From 448da392ac095ee2832509b62998c4cae81d5180 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Sun, 8 Feb 2026 12:49:34 +0700 Subject: [PATCH 1/2] Accurate push with deps, separate tree command --- mk/repo.mk | 36 ++++++++++++++++++--- src/bin/repo.rs | 81 ++++++++++++++++++++++++++++++------------------ src/cook/tree.rs | 23 +++++++++----- 3 files changed, 97 insertions(+), 43 deletions(-) diff --git a/mk/repo.mk b/mk/repo.mk index 646e9d9c9..1e45dfe84 100644 --- a/mk/repo.mk +++ b/mk/repo.mk @@ -13,12 +13,20 @@ endif comma := , -# List all recipes in a tree fashion specified by the filesystem config -tree: $(FSTOOLS_TAG) $(CONTAINER_TAG) +# List all recipes in a cook-tree fashion specified by the filesystem config +repo-tree: $(FSTOOLS_TAG) $(CONTAINER_TAG) ifeq ($(PODMAN_BUILD),1) $(PODMAN_RUN) make $@ else - @./target/release/repo tree $(COOKBOOK_OPTS) --with-package-deps + @./target/release/repo cook-tree $(COOKBOOK_OPTS) --with-package-deps +endif + +# List all recipes in a push-tree fashion specified by the filesystem config +image-tree: $(FSTOOLS_TAG) $(CONTAINER_TAG) +ifeq ($(PODMAN_BUILD),1) + $(PODMAN_RUN) make $@ +else + @./target/release/repo push-tree $(COOKBOOK_OPTS) --with-package-deps endif # Fetch all recipes source or binary from filesystem config @@ -67,7 +75,7 @@ else ./target/release/repo fetch $(foreach f,$(subst $(comma), ,$*),$(f)) $(COOKBOOK_OPTS) endif -# Invoke repo.sh for one or more targets separated by comma +# Invoke cook for one or more targets separated by comma r.%: prefix $(FSTOOLS_TAG) FORCE ifeq ($(PODMAN_BUILD),1) $(PODMAN_RUN) make $@ @@ -77,6 +85,14 @@ else ./target/release/repo cook $(foreach f,$(subst $(comma), ,$*),$(f)) $(COOKBOOK_OPTS) endif +# Show what to cook +rt.%: prefix $(FSTOOLS_TAG) FORCE +ifeq ($(PODMAN_BUILD),1) + $(PODMAN_RUN) make $@ +else + ./target/release/repo cook-tree $(foreach f,$(subst $(comma), ,$*),$(f)) $(COOKBOOK_OPTS) +endif + MOUNTED_TAG=$(MOUNT_DIR)~ # Push compiled package into existing image @@ -105,6 +121,18 @@ endif pp.%: $(FSTOOLS_TAG) FORCE $(MAKE) p.$*,--with-package-deps +# Show what to push +pt.%: prefix $(FSTOOLS_TAG) FORCE +ifeq ($(PODMAN_BUILD),1) + $(PODMAN_RUN) make $@ +else + ./target/release/repo push-tree $(foreach f,$(subst $(comma), ,$*),$(f)) $(COOKBOOK_OPTS) +endif + +# Show what to push (with deps) +ppt.%: prefix $(FSTOOLS_TAG) FORCE + $(MAKE) pt.$*,--with-package-deps + # Push all recipes specified by the filesystem config push: $(FSTOOLS_TAG) FORCE ifeq ($(ALLOW_FSTOOLS),1) diff --git a/src/bin/repo.rs b/src/bin/repo.rs index b51755e03..1fc91fdbc 100644 --- a/src/bin/repo.rs +++ b/src/bin/repo.rs @@ -48,7 +48,8 @@ const REPO_HELP_STR: &str = r#" clean delete recipe artifacts push extract package into sysroot find find path of recipe packages - tree show tree of recipe packages + cook-tree show tree of recipe build + push-tree show tree of recipe packages common flags: --cookbook= the "recipes" folder, default to $PWD/recipes @@ -90,22 +91,23 @@ struct CliConfig { enum CliCommand { Fetch, Cook, + CookTree, Unfetch, Clean, Push, - Tree, + PushTree, Find, } impl CliCommand { pub fn is_informational(&self) -> bool { - *self == CliCommand::Tree || *self == CliCommand::Find + *self == CliCommand::PushTree || *self == CliCommand::CookTree || *self == CliCommand::Find } pub fn is_building(&self) -> bool { - *self == CliCommand::Fetch || *self == CliCommand::Cook + *self == CliCommand::Fetch || *self == CliCommand::Cook || *self == CliCommand::CookTree } pub fn is_pushing(&self) -> bool { - *self == CliCommand::Push || *self == CliCommand::Tree + *self == CliCommand::Push || *self == CliCommand::PushTree } pub fn is_cleaning(&self) -> bool { *self == CliCommand::Clean || *self == CliCommand::Unfetch @@ -122,7 +124,8 @@ impl FromStr for CliCommand { "unfetch" => Ok(CliCommand::Unfetch), "clean" => Ok(CliCommand::Clean), "push" => Ok(CliCommand::Push), - "tree" => Ok(CliCommand::Tree), + "push-tree" => Ok(CliCommand::PushTree), + "cook-tree" => Ok(CliCommand::CookTree), "find" => Ok(CliCommand::Find), _ => Err(anyhow!("Unknown command '{}'\n{}\n", s, REPO_HELP_STR)), } @@ -137,7 +140,8 @@ impl ToString for CliCommand { CliCommand::Unfetch => "unfetch".to_string(), CliCommand::Clean => "clean".to_string(), CliCommand::Push => "push".to_string(), - CliCommand::Tree => "tree".to_string(), + CliCommand::PushTree => "push-tree".to_string(), + CliCommand::CookTree => "cook-tree".to_string(), CliCommand::Find => "find".to_string(), } } @@ -186,12 +190,12 @@ fn main_inner() -> anyhow::Result<()> { process::exit(1); } - let (config, command, recipe_names) = parse_args(args)?; + let (config, command, recipes) = parse_args(args)?; if command.is_building() { ident::init_ident(); } if command == CliCommand::Cook && config.cook.tui { - if let Some((name, e)) = run_tui_cook(config.clone(), recipe_names.clone())? { + if let Some((name, e)) = run_tui_cook(config.clone(), recipes.clone())? { let _ = stderr().write(e.as_bytes()); let _ = stderr().write(b"\n\n"); print_failed(&command, &name); @@ -199,17 +203,20 @@ fn main_inner() -> anyhow::Result<()> { } else { print_success(&command, None); } - return publish_packages(&recipe_names, &config.repo_dir); + return publish_packages(&recipes, &config.repo_dir); } - if command == CliCommand::Tree { - return handle_tree(&recipe_names, &config); + if command == CliCommand::PushTree { + return handle_tree(&recipes, false, &config); + } + if command == CliCommand::CookTree { + return handle_tree(&recipes, true, &config); } if command == CliCommand::Push { - return handle_push(&recipe_names, &config); + return handle_push(&recipes, &config); } let verbose = config.cook.verbose; - for recipe in &recipe_names { + for recipe in &recipes { match repo_inner(&config, &command, recipe) { Ok(_) => { if !command.is_informational() { @@ -234,14 +241,14 @@ fn main_inner() -> anyhow::Result<()> { } if command == CliCommand::Cook { - return publish_packages(&recipe_names, &config.repo_dir); + return publish_packages(&recipes, &config.repo_dir); } - if verbose && recipe_names.len() > 1 { + if verbose && recipes.len() > 1 { println!( "\nCommand '{}' completed for {} recipes.", command.to_string(), - recipe_names.len() + recipes.len() ); } Ok(()) @@ -348,7 +355,8 @@ fn repo_inner( CliCommand::Unfetch => handle_clean(recipe, config, true, true)?, CliCommand::Clean => handle_clean(recipe, config, false, true)?, CliCommand::Push => unreachable!(), - CliCommand::Tree => unreachable!(), + CliCommand::PushTree => unreachable!(), + CliCommand::CookTree => unreachable!(), CliCommand::Find => println!("{}", recipe.dir.display()), }) } @@ -564,17 +572,21 @@ fn parse_args(args: Vec) -> anyhow::Result<(CliConfig, CliCommand, Vec) -> anyhow::Result<(CliConfig, CliCommand, Vec, config: &CliConfig) -> anyhow::Result< &recipe_map, "", i == num_roots - 1, + false, &mut visited, &mut total_size, handle_push_inner, @@ -803,7 +817,11 @@ fn handle_push(recipes: &Vec, config: &CliConfig) -> anyhow::Result< Ok(()) } -fn handle_tree(recipes: &Vec, _config: &CliConfig) -> anyhow::Result<()> { +fn handle_tree( + recipes: &Vec, + is_build_tree: bool, + _config: &CliConfig, +) -> anyhow::Result<()> { let recipe_map: HashMap<&PackageName, &CookRecipe> = recipes.iter().map(|r| (&r.name, r)).collect(); let mut total_size: u64 = 0; @@ -816,6 +834,7 @@ fn handle_tree(recipes: &Vec, _config: &CliConfig) -> anyhow::Result &recipe_map, "", i == num_roots - 1, + is_build_tree, &mut visited, &mut total_size, )?; diff --git a/src/cook/tree.rs b/src/cook/tree.rs index 9bb51281e..cf6eec5c2 100644 --- a/src/cook/tree.rs +++ b/src/cook/tree.rs @@ -21,6 +21,7 @@ pub fn display_tree_entry( recipe_map: &HashMap<&PackageName, &CookRecipe>, prefix: &str, is_last: bool, + is_build_tree: bool, visited: &mut HashSet, total_size: &mut u64, ) -> anyhow::Result<()> { @@ -29,6 +30,7 @@ pub fn display_tree_entry( recipe_map, prefix, is_last, + is_build_tree, visited, total_size, display_pkg_fn, @@ -40,6 +42,7 @@ pub fn walk_tree_entry( recipe_map: &HashMap<&PackageName, &CookRecipe>, prefix: &str, is_last: bool, + is_build_tree: bool, visited: &mut HashSet, total_size: &mut u64, op: fn(&PackageName, &str, bool, &WalkTreeEntry) -> anyhow::Result<()>, @@ -47,7 +50,7 @@ pub fn walk_tree_entry( let cook_recipe = match recipe_map.get(package_name) { Some(r) => r, None => { - // TODO: This is a dependency, but it's not in recipe list + // Data not provided, will not be processed by the build system op(package_name, prefix, is_last, &WalkTreeEntry::Missing)?; return Ok(()); } @@ -75,13 +78,16 @@ pub fn walk_tree_entry( let pkg_meta: Package; let mut all_deps_set: HashSet<&PackageName> = HashSet::new(); - if let Ok(pkg_toml_str) = read_to_string(&pkg_toml) { - // more accurate with auto deps - pkg_meta = toml::from_str(&pkg_toml_str) - .context(format!("Unable to parse {}", pkg_toml.display()))?; - all_deps_set.extend(pkg_meta.depends.iter()); - } else { + if is_build_tree { + all_deps_set.extend(cook_recipe.recipe.build.dependencies.iter()); all_deps_set.extend(cook_recipe.recipe.package.dependencies.iter()); + } else { + if let Ok(pkg_toml_str) = read_to_string(&pkg_toml) { + // more accurate with auto deps + pkg_meta = toml::from_str(&pkg_toml_str) + .context(format!("Unable to parse {}", pkg_toml.display()))?; + all_deps_set.extend(pkg_meta.depends.iter()); + } } if all_deps_set.is_empty() { @@ -97,6 +103,7 @@ pub fn walk_tree_entry( recipe_map, &format!("{}{}", prefix, child_prefix), i == deps_count - 1, + is_build_tree, visited, total_size, op, @@ -116,7 +123,7 @@ pub fn display_pkg_fn( WalkTreeEntry::Built(_path_buf, size) => format!("[{}]", format_size(*size)), WalkTreeEntry::NotBuilt => "(not built)".to_string(), WalkTreeEntry::Deduped => "".to_string(), - WalkTreeEntry::Missing => "(dependency info missing)".to_string(), + WalkTreeEntry::Missing => "(omitted)".to_string(), }; let line_prefix = if is_last { "└── " } else { "├── " }; println!("{}{}{} {}", prefix, line_prefix, package_name, size_str); From 81837d01982a41cd75e474f9b2aeaa863bf8ea05 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Sun, 8 Feb 2026 13:19:08 +0700 Subject: [PATCH 2/2] Make build stats count missing build --- src/bin/repo.rs | 34 ++++++++++++++++++++++++---------- src/cook/tree.rs | 10 ++++++++-- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/bin/repo.rs b/src/bin/repo.rs index 1fc91fdbc..6b406cd1f 100644 --- a/src/bin/repo.rs +++ b/src/bin/repo.rs @@ -841,16 +841,30 @@ fn handle_tree( } println!(""); - println!( - "Estimated image size: {} of {} {}", - tree::format_size(total_size), - visited.len(), - if visited.len() == 1 { - "package" - } else { - "packages" - }, - ); + if is_build_tree { + println!( + "Build summary: {} need build, {} may rebuild, with total of {} {}", + total_size, + roots.len(), + visited.len(), + if visited.len() == 1 { + "recipe" + } else { + "recipes" + }, + ); + } else { + println!( + "Estimated image size: {} of {} {}", + tree::format_size(total_size), + visited.len(), + if visited.len() == 1 { + "package" + } else { + "packages" + }, + ); + } Ok(()) } diff --git a/src/cook/tree.rs b/src/cook/tree.rs index cf6eec5c2..f4bb935d7 100644 --- a/src/cook/tree.rs +++ b/src/cook/tree.rs @@ -72,8 +72,14 @@ pub fn walk_tree_entry( } visited.insert(package_name.clone()); - if let WalkTreeEntry::Built(_p, pkg_size) = &entry { - *total_size += pkg_size; + if is_build_tree { + if matches!(entry, WalkTreeEntry::NotBuilt) { + *total_size += 1; + } + } else { + if let WalkTreeEntry::Built(_p, pkg_size) = &entry { + *total_size += pkg_size; + } } let pkg_meta: Package;