203 lines
5.5 KiB
Rust
203 lines
5.5 KiB
Rust
use std::cell::Cell;
|
|
|
|
use allocative::Allocative;
|
|
use starlark::{
|
|
environment::{GlobalsBuilder, Methods, MethodsBuilder, MethodsStatic},
|
|
eval::Evaluator,
|
|
starlark_module, starlark_simple_value,
|
|
typing::Ty,
|
|
values::{
|
|
Heap, StarlarkValue, UnpackValue, Value, ValueLike, none::NoneType, tuple::UnpackTuple,
|
|
type_repr::StarlarkTypeRepr,
|
|
},
|
|
};
|
|
use starlark_derive::{NoSerialize, ProvidesStaticType, starlark_value};
|
|
|
|
use crate::{
|
|
container::{Container, ContainerManager},
|
|
eval::{Path, UnpackCloned},
|
|
log,
|
|
recipe::Source,
|
|
};
|
|
|
|
#[derive(Debug, Clone, Allocative, NoSerialize, ProvidesStaticType)]
|
|
pub struct TarballSource {
|
|
url: String,
|
|
sha256: String,
|
|
strip_components: u32,
|
|
}
|
|
|
|
impl std::fmt::Display for TarballSource {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "tarball")
|
|
}
|
|
}
|
|
|
|
starlark_simple_value!(TarballSource);
|
|
|
|
#[starlark_value(type = "tarball")]
|
|
impl<'v> StarlarkValue<'v> for TarballSource {}
|
|
|
|
impl UnpackCloned for TarballSource {
|
|
fn unpack_cloned(value: Value<'_>) -> Option<Self> {
|
|
value.downcast_ref().cloned()
|
|
}
|
|
}
|
|
|
|
impl Source for TarballSource {}
|
|
|
|
#[derive(Debug, Clone, Allocative, NoSerialize, ProvidesStaticType)]
|
|
pub struct Metadata {
|
|
maintainer: Option<String>,
|
|
description: Option<String>,
|
|
license: Option<String>,
|
|
website: Option<String>,
|
|
}
|
|
|
|
impl std::fmt::Display for Metadata {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "metadata")
|
|
}
|
|
}
|
|
|
|
starlark_simple_value!(Metadata);
|
|
|
|
#[starlark_value(type = "metadata")]
|
|
impl<'v> StarlarkValue<'v> for Metadata {}
|
|
|
|
impl UnpackCloned for Metadata {
|
|
fn unpack_cloned(value: Value<'_>) -> Option<Self> {
|
|
value.downcast_ref().cloned()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Allocative, NoSerialize, ProvidesStaticType)]
|
|
pub struct Context {
|
|
pub source_dir: Path,
|
|
pub build_dir: Path,
|
|
pub jobs: i32,
|
|
}
|
|
|
|
impl std::fmt::Display for Context {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "context")
|
|
}
|
|
}
|
|
|
|
starlark_simple_value!(Context);
|
|
|
|
#[derive(Debug)]
|
|
struct RunArg(pub String);
|
|
|
|
impl UnpackValue<'_> for RunArg {
|
|
type Error = anyhow::Error;
|
|
|
|
fn unpack_value_impl(value: Value) -> anyhow::Result<Option<Self>> {
|
|
Ok(if let Some(str) = value.unpack_str() {
|
|
Some(RunArg(str.to_owned()))
|
|
} else if let Some(int) = value.unpack_i32() {
|
|
Some(RunArg(int.to_string()))
|
|
} else if let Some(path) = value.downcast_ref::<Path>() {
|
|
Some(RunArg(path.path().to_str().unwrap_or("").to_string()))
|
|
} else {
|
|
None
|
|
})
|
|
}
|
|
}
|
|
|
|
impl StarlarkTypeRepr for RunArg {
|
|
type Canonical = Self;
|
|
|
|
fn starlark_type_repr() -> starlark::typing::Ty {
|
|
Ty::string()
|
|
}
|
|
}
|
|
|
|
#[derive(ProvidesStaticType)]
|
|
pub struct ContainerManagerWrapper<'a>(pub &'a ContainerManager);
|
|
|
|
#[starlark_module]
|
|
fn context_methods(b: &mut MethodsBuilder) {
|
|
fn run(
|
|
#[starlark(this)] this: &Context,
|
|
#[starlark(args)] args: UnpackTuple<RunArg>,
|
|
eval: &mut Evaluator,
|
|
) -> anyhow::Result<NoneType> {
|
|
let ContainerManagerWrapper(container_manager) = eval
|
|
.extra
|
|
.and_then(|extra| extra.downcast_ref())
|
|
.ok_or_else(|| anyhow::anyhow!("`config` called outside of config.star"))?;
|
|
|
|
let argv = args.items.iter().map(|x| x.0.as_str()).collect::<Vec<_>>();
|
|
|
|
log!("run", "Running command: {argv:?}");
|
|
|
|
container_manager
|
|
.container("changeme")? // TODO
|
|
.exec(argv, [], std::path::Path::new("/"))?;
|
|
|
|
Ok(NoneType)
|
|
}
|
|
}
|
|
|
|
#[starlark_value(type = "context")]
|
|
impl<'v> StarlarkValue<'v> for Context {
|
|
fn get_methods() -> Option<&'static Methods> {
|
|
static RES: MethodsStatic = MethodsStatic::new();
|
|
RES.methods(context_methods)
|
|
}
|
|
|
|
fn has_attr(&self, attr: &str, _heap: &Heap) -> bool {
|
|
match attr {
|
|
"source_dir" => true,
|
|
"build_dir" => true,
|
|
"jobs" => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
fn get_attr(&self, attr: &str, heap: &'v Heap) -> Option<Value<'v>> {
|
|
match attr {
|
|
"source_dir" => Some(heap.alloc(self.source_dir.clone())),
|
|
"build_dir" => Some(heap.alloc(self.build_dir.clone())),
|
|
"jobs" => Some(heap.alloc(self.jobs)),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl UnpackCloned for Context {
|
|
fn unpack_cloned(value: Value<'_>) -> Option<Self> {
|
|
value.downcast_ref().cloned()
|
|
}
|
|
}
|
|
|
|
#[starlark_module]
|
|
pub fn recipe_globals(b: &mut GlobalsBuilder) {
|
|
fn tarball(
|
|
#[starlark(require = named)] url: &str,
|
|
#[starlark(require = named)] sha256: &str,
|
|
#[starlark(require = named, default = 0)] strip_components: u32,
|
|
) -> anyhow::Result<TarballSource> {
|
|
Ok(TarballSource {
|
|
url: url.to_string(),
|
|
sha256: sha256.to_string(),
|
|
strip_components,
|
|
})
|
|
}
|
|
|
|
fn meta(
|
|
#[starlark(require = named)] maintainer: Option<&str>,
|
|
#[starlark(require = named)] description: Option<&str>,
|
|
#[starlark(require = named)] license: Option<&str>,
|
|
#[starlark(require = named)] website: Option<&str>,
|
|
) -> anyhow::Result<Metadata> {
|
|
Ok(Metadata {
|
|
maintainer: maintainer.map(|x| x.to_string()),
|
|
description: description.map(|x| x.to_string()),
|
|
license: license.map(|x| x.to_string()),
|
|
website: website.map(|x| x.to_string()),
|
|
})
|
|
}
|
|
}
|