More stuff, didn't test
This commit is contained in:
+129
-22
@@ -49,8 +49,9 @@ impl Builder {
|
||||
rebuild: bool,
|
||||
dry_run: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
let requested = filter_skipped(recipes, requested);
|
||||
let plan = TaskPlanner::new(&self.root, &self.config.arch, recipes)
|
||||
.build_plan(requested, rebuild)?;
|
||||
.build_plan(&requested, rebuild)?;
|
||||
self.print_plan(&plan);
|
||||
if dry_run {
|
||||
return Ok(());
|
||||
@@ -64,8 +65,9 @@ impl Builder {
|
||||
requested: &[String],
|
||||
dry_run: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
let requested = filter_skipped(recipes, requested);
|
||||
let plan =
|
||||
TaskPlanner::new(&self.root, &self.config.arch, recipes).fetch_plan(requested)?;
|
||||
TaskPlanner::new(&self.root, &self.config.arch, recipes).fetch_plan(&requested)?;
|
||||
self.print_plan(&plan);
|
||||
if dry_run {
|
||||
return Ok(());
|
||||
@@ -424,11 +426,7 @@ impl Builder {
|
||||
) -> anyhow::Result<()> {
|
||||
log::step("configure", &recipe.key());
|
||||
if let Some(func) = recipe.phases().configure() {
|
||||
let ctx = PhaseContext::new(
|
||||
source_dir_for(recipe),
|
||||
prefix_for(recipe.kind()),
|
||||
default_jobs(),
|
||||
);
|
||||
let ctx = phase_context_for(recipe);
|
||||
self.invoke_with_runtime(active, &[PhaseArg::Ctx(ctx)], func)?;
|
||||
}
|
||||
self.write_recipe_stamp(layout, recipe, "configure")
|
||||
@@ -441,11 +439,7 @@ impl Builder {
|
||||
active: &ActiveContainer,
|
||||
) -> anyhow::Result<()> {
|
||||
log::step("build", &recipe.key());
|
||||
let ctx = PhaseContext::new(
|
||||
source_dir_for(recipe),
|
||||
prefix_for(recipe.kind()),
|
||||
default_jobs(),
|
||||
);
|
||||
let ctx = phase_context_for(recipe);
|
||||
self.invoke_with_runtime(active, &[PhaseArg::Ctx(ctx)], recipe.phases().build())?;
|
||||
self.write_recipe_stamp(layout, recipe, "build")
|
||||
}
|
||||
@@ -464,11 +458,7 @@ impl Builder {
|
||||
&base_env(&active.base_path),
|
||||
"/",
|
||||
)?;
|
||||
let ctx = PhaseContext::new(
|
||||
source_dir_for(recipe),
|
||||
prefix_for(recipe.kind()),
|
||||
default_jobs(),
|
||||
);
|
||||
let ctx = phase_context_for(recipe);
|
||||
let pkg = PackageContext::new(dest);
|
||||
self.invoke_with_runtime(
|
||||
active,
|
||||
@@ -491,11 +481,7 @@ impl Builder {
|
||||
&base_env(&active.base_path),
|
||||
"/",
|
||||
)?;
|
||||
let ctx = PhaseContext::new(
|
||||
source_dir_for(recipe),
|
||||
prefix_for(recipe.kind()),
|
||||
default_jobs(),
|
||||
);
|
||||
let ctx = phase_context_for(recipe);
|
||||
let pkg = PackageContext::new(dest.clone());
|
||||
self.invoke_with_runtime(
|
||||
active,
|
||||
@@ -595,6 +581,61 @@ impl Builder {
|
||||
phase::invoke_phase(func, args)
|
||||
}
|
||||
|
||||
fn populate_sysroot(
|
||||
&self,
|
||||
layout: &Layout<'_>,
|
||||
recipes: &RecipeSet,
|
||||
recipe: &Recipe,
|
||||
active: &ActiveContainer,
|
||||
deps: &[String],
|
||||
) -> anyhow::Result<()> {
|
||||
if deps.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let env = base_env(&active.base_path);
|
||||
for dep in deps {
|
||||
let output = recipes.output(dep)?;
|
||||
let owning = recipes.recipe(output.recipe())?;
|
||||
let apk_host = layout.apk_path(owning, output);
|
||||
if !apk_host.exists() {
|
||||
bail!(
|
||||
"missing apk for target dependency `{dep}` at {}; \
|
||||
rebuild it first (e.g. `distro build -r {dep}`)",
|
||||
apk_host.display()
|
||||
);
|
||||
}
|
||||
let file_name = apk_host
|
||||
.file_name()
|
||||
.and_then(|n| n.to_str())
|
||||
.ok_or_else(|| {
|
||||
anyhow::anyhow!("apk path {} has no UTF-8 file name", apk_host.display())
|
||||
})?;
|
||||
active.container.borrow().exec(
|
||||
&[
|
||||
"apk".to_owned(),
|
||||
"extract".to_owned(),
|
||||
"--allow-untrusted".to_owned(),
|
||||
"--destination".to_owned(),
|
||||
"/sysroot".to_owned(),
|
||||
format!("/pkgs/{file_name}"),
|
||||
],
|
||||
&env,
|
||||
"/",
|
||||
)?;
|
||||
}
|
||||
|
||||
log::info(
|
||||
"sysroot",
|
||||
&format!(
|
||||
"{}: extracted /sysroot from {} target apk(s)",
|
||||
recipe.key(),
|
||||
deps.len()
|
||||
),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn start_recipe_container(
|
||||
&self,
|
||||
recipes: &RecipeSet,
|
||||
@@ -609,8 +650,10 @@ impl Builder {
|
||||
fs::create_dir_all(&build_dir)?;
|
||||
|
||||
let host_deps = transitive_host_deps(recipes, recipe)?;
|
||||
let target_deps = transitive_target_deps(recipes, recipe)?;
|
||||
let pkgs_dir = self.root.join("build/pkgs").join(&self.config.arch);
|
||||
fs::create_dir_all(&pkgs_dir)?;
|
||||
|
||||
let mut mounts = vec![
|
||||
Mount {
|
||||
host: source_dir,
|
||||
@@ -628,6 +671,15 @@ impl Builder {
|
||||
read_only: false,
|
||||
},
|
||||
];
|
||||
|
||||
if let Some(files_dir) = recipe.files_dir() {
|
||||
mounts.push(Mount {
|
||||
host: files_dir,
|
||||
container: "/files".to_owned(),
|
||||
read_only: true,
|
||||
});
|
||||
}
|
||||
|
||||
let mut tools_bins: Vec<String> = Vec::new();
|
||||
for dep_key in &host_deps {
|
||||
let dep_recipe = recipes.recipe(dep_key)?;
|
||||
@@ -674,6 +726,8 @@ impl Builder {
|
||||
base_path,
|
||||
};
|
||||
|
||||
self.populate_sysroot(&layout, recipes, recipe, &active, &target_deps)?;
|
||||
|
||||
Ok(active)
|
||||
}
|
||||
|
||||
@@ -817,6 +871,21 @@ struct ActiveContainer {
|
||||
base_path: String,
|
||||
}
|
||||
|
||||
fn filter_skipped(recipes: &RecipeSet, requested: &[String]) -> Vec<String> {
|
||||
requested
|
||||
.iter()
|
||||
.filter(|key| {
|
||||
if recipes.is_skipped(key) {
|
||||
log::skip("skip", &format!("{key} (build_if returned false)"));
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn task_needs_container(task: &TaskId) -> bool {
|
||||
matches!(
|
||||
task,
|
||||
@@ -835,6 +904,16 @@ fn prefix_for(kind: RecipeKind) -> &'static str {
|
||||
}
|
||||
}
|
||||
|
||||
fn phase_context_for(recipe: &Recipe) -> PhaseContext {
|
||||
let files = recipe.files_dir().map(|_| "/files".to_owned());
|
||||
PhaseContext::new(
|
||||
source_dir_for(recipe),
|
||||
prefix_for(recipe.kind()),
|
||||
default_jobs(),
|
||||
files,
|
||||
)
|
||||
}
|
||||
|
||||
fn source_dir_for(recipe: &Recipe) -> SourceDir {
|
||||
let entries = recipe.sources().entries();
|
||||
let named: Vec<(&str, &crate::recipe::Source)> = entries
|
||||
@@ -896,6 +975,34 @@ fn transitive_host_deps(recipes: &RecipeSet, recipe: &Recipe) -> anyhow::Result<
|
||||
Ok(order)
|
||||
}
|
||||
|
||||
/// Compute the transitive closure of a recipe's target package dependencies.
|
||||
/// The recipe's own `build_deps` and `deps` seed the queue; for each visited
|
||||
/// dependency we follow its `deps` (runtime+build-needed) recursively, but
|
||||
/// not its `build_deps` (build-time-only relative to *that* package, hence
|
||||
/// not propagated outward).
|
||||
fn transitive_target_deps(recipes: &RecipeSet, recipe: &Recipe) -> anyhow::Result<Vec<String>> {
|
||||
let mut order: Vec<String> = Vec::new();
|
||||
let mut seen: BTreeSet<String> = BTreeSet::new();
|
||||
let mut queue: VecDeque<String> = recipe
|
||||
.build_deps()
|
||||
.iter()
|
||||
.chain(recipe.deps().iter())
|
||||
.cloned()
|
||||
.collect();
|
||||
while let Some(dep) = queue.pop_front() {
|
||||
if !seen.insert(dep.clone()) {
|
||||
continue;
|
||||
}
|
||||
let output = recipes.output(&dep)?;
|
||||
let owning = recipes.recipe(output.recipe())?;
|
||||
for sub in owning.deps() {
|
||||
queue.push_back(sub.clone());
|
||||
}
|
||||
order.push(dep);
|
||||
}
|
||||
Ok(order)
|
||||
}
|
||||
|
||||
fn random_suffix() -> u64 {
|
||||
let nanos = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
|
||||
Reference in New Issue
Block a user