mirror of
https://gitlab.redox-os.org/redox-os/redox.git
synced 2026-06-21 12:24:17 +08:00
Merge branch 'build-cache-hint' into 'master'
Implement hints to cached build See merge request redox-os/redox!2013
This commit is contained in:
commit
290cabe8fc
@ -227,9 +227,13 @@ fn main_inner() -> anyhow::Result<()> {
|
||||
let verbose = config.cook.verbose;
|
||||
for recipe in &recipes {
|
||||
match repo_inner(&config, &command, recipe) {
|
||||
Ok(_) => {
|
||||
Ok(cached) => {
|
||||
if !command.is_informational() {
|
||||
print_success(&command, Some(&recipe.name));
|
||||
if cached {
|
||||
print_cached(&command, Some(&recipe.name));
|
||||
} else {
|
||||
print_success(&command, Some(&recipe.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
@ -298,20 +302,44 @@ fn print_success(command: &CliCommand, recipe: Option<&PackageName>) {
|
||||
}
|
||||
}
|
||||
|
||||
fn print_cached(command: &CliCommand, recipe: Option<&PackageName>) {
|
||||
if let Some(recipe) = recipe {
|
||||
eprintln!(
|
||||
"{}{}{} {} - cached{}{}",
|
||||
style::Bold,
|
||||
color::Fg(color::AnsiValue(45)),
|
||||
command.to_string(),
|
||||
recipe.as_str(),
|
||||
color::Fg(color::Reset),
|
||||
style::Reset,
|
||||
);
|
||||
} else {
|
||||
eprintln!(
|
||||
"{}{}{} - cached{}{}",
|
||||
style::Bold,
|
||||
color::Fg(color::AnsiValue(45)),
|
||||
command.to_string(),
|
||||
color::Fg(color::Reset),
|
||||
style::Reset,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn repo_inner(
|
||||
config: &CliConfig,
|
||||
command: &CliCommand,
|
||||
recipe: &CookRecipe,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
) -> Result<bool, anyhow::Error> {
|
||||
Ok(match *command {
|
||||
CliCommand::Fetch | CliCommand::Cook => {
|
||||
let repo_inner_fn = move |logger: &PtyOut| -> Result<(), anyhow::Error> {
|
||||
let repo_inner_fn = move |logger: &PtyOut| -> Result<bool, anyhow::Error> {
|
||||
let is_cook = *command == CliCommand::Cook;
|
||||
let mut cached = false;
|
||||
let source_dir = handle_fetch(recipe, config, is_cook, logger)?;
|
||||
if is_cook {
|
||||
handle_cook(recipe, config, source_dir, logger)?;
|
||||
cached = handle_cook(recipe, config, source_dir, logger)?;
|
||||
}
|
||||
Ok(())
|
||||
Ok(cached)
|
||||
};
|
||||
let Some(log_path) = &config.logs_dir else {
|
||||
return repo_inner_fn(&None);
|
||||
@ -359,7 +387,7 @@ fn repo_inner(
|
||||
.send(StatusUpdate::CookThreadFinished)
|
||||
.unwrap_or_default();
|
||||
let _ = th.join();
|
||||
result?;
|
||||
result?
|
||||
}
|
||||
CliCommand::Unfetch | CliCommand::Clean | CliCommand::CleanTarget => {
|
||||
handle_clean(recipe, config, command)?
|
||||
@ -367,7 +395,10 @@ fn repo_inner(
|
||||
CliCommand::Push => unreachable!(),
|
||||
CliCommand::PushTree => unreachable!(),
|
||||
CliCommand::CookTree => unreachable!(),
|
||||
CliCommand::Find => println!("{}", recipe.dir.display()),
|
||||
CliCommand::Find => {
|
||||
println!("{}", recipe.dir.display());
|
||||
false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -690,10 +721,10 @@ fn handle_cook(
|
||||
config: &CliConfig,
|
||||
source_dir: PathBuf,
|
||||
logger: &PtyOut,
|
||||
) -> anyhow::Result<()> {
|
||||
) -> anyhow::Result<bool> {
|
||||
let recipe_dir = &recipe.dir;
|
||||
let target_dir = create_target_dir(recipe_dir, recipe.target).map_err(|e| anyhow!(e))?;
|
||||
let (stage_dirs, auto_deps) = build(
|
||||
let build_result = build(
|
||||
recipe_dir,
|
||||
&source_dir,
|
||||
&target_dir,
|
||||
@ -703,12 +734,11 @@ fn handle_cook(
|
||||
)
|
||||
.map_err(|err| anyhow!("failed to build: {:?}", err))?;
|
||||
|
||||
package(&recipe, &stage_dirs, &auto_deps, &config.cook, logger)
|
||||
package(&recipe, &build_result, &config.cook, logger)
|
||||
.map_err(|err| anyhow!("failed to package: {:?}", err))?;
|
||||
|
||||
if config.cook.clean_target || config.cook.write_filetree {
|
||||
let stage_dirs = get_stage_dirs(&recipe.recipe.optional_packages, &target_dir);
|
||||
for stage_dir in stage_dirs {
|
||||
for stage_dir in &build_result.stage_dirs {
|
||||
if stage_dir.is_dir() {
|
||||
if config.cook.write_filetree {
|
||||
let mut stage_files_buf = String::new();
|
||||
@ -723,7 +753,7 @@ fn handle_cook(
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
Ok(build_result.cached)
|
||||
}
|
||||
|
||||
/// delete stage artifacts upon nonstop failure to let repo_builder know
|
||||
@ -741,19 +771,22 @@ fn handle_clean(
|
||||
recipe: &CookRecipe,
|
||||
_config: &CliConfig,
|
||||
command: &CliCommand,
|
||||
) -> anyhow::Result<()> {
|
||||
) -> anyhow::Result<bool> {
|
||||
let mut dir = recipe.dir.join("target");
|
||||
let mut cached = true;
|
||||
if matches!(*command, CliCommand::CleanTarget) {
|
||||
dir = dir.join(redoxer::target())
|
||||
}
|
||||
if dir.exists() {
|
||||
fs::remove_dir_all(&dir).context(format!("failed to delete {}", dir.display()))?;
|
||||
cached = false;
|
||||
}
|
||||
let dir = recipe.dir.join("source");
|
||||
if dir.exists() && matches!(*command, CliCommand::Unfetch) {
|
||||
fs::remove_dir_all(&dir).context(format!("failed to delete {}", dir.display()))?;
|
||||
cached = false;
|
||||
}
|
||||
Ok(())
|
||||
Ok(cached)
|
||||
}
|
||||
|
||||
static PUSH_SYSROOT_DIR: OnceLock<PathBuf> = OnceLock::new();
|
||||
@ -918,6 +951,7 @@ enum RecipeStatus {
|
||||
Fetching,
|
||||
Fetched,
|
||||
Cooking,
|
||||
Cached,
|
||||
Done,
|
||||
Failed(String),
|
||||
}
|
||||
@ -928,7 +962,7 @@ enum StatusUpdate {
|
||||
Fetched(CookRecipe),
|
||||
FailFetch(CookRecipe, String),
|
||||
StartCook(PackageName),
|
||||
Cooked(CookRecipe),
|
||||
Cooked(CookRecipe, bool),
|
||||
FailCook(CookRecipe, String),
|
||||
PushLog(PackageName, Vec<u8>),
|
||||
FlushLog(PackageName, PathBuf),
|
||||
@ -1104,12 +1138,19 @@ impl TuiApp {
|
||||
let _ = self.write_log(&name, &path);
|
||||
return;
|
||||
}
|
||||
StatusUpdate::Cooked(recipe) => {
|
||||
StatusUpdate::Cooked(recipe, cached) => {
|
||||
if self.active_cook.as_ref() == Some(&recipe.name) {
|
||||
self.active_cook = None;
|
||||
}
|
||||
self.auto_scroll = true;
|
||||
(recipe.name.clone(), RecipeStatus::Done)
|
||||
(
|
||||
recipe.name.clone(),
|
||||
if cached {
|
||||
RecipeStatus::Cached
|
||||
} else {
|
||||
RecipeStatus::Done
|
||||
},
|
||||
)
|
||||
}
|
||||
StatusUpdate::FailCook(recipe, err) => {
|
||||
self.prompt = Some(FailurePrompt::new(recipe.clone(), err.clone()));
|
||||
@ -1146,7 +1187,7 @@ impl TuiApp {
|
||||
self.done = self
|
||||
.recipes
|
||||
.iter()
|
||||
.filter(|(_, s)| *s == RecipeStatus::Done)
|
||||
.filter(|(_, s)| *s == RecipeStatus::Done || *s == RecipeStatus::Cached)
|
||||
.map(|(r, _)| r.name.clone())
|
||||
.collect();
|
||||
}
|
||||
@ -1189,9 +1230,9 @@ fn run_tui_cook(
|
||||
.unwrap_or_default();
|
||||
}
|
||||
match handler {
|
||||
Ok(()) => {
|
||||
Ok(cached) => {
|
||||
cooker_status_tx
|
||||
.send(StatusUpdate::Cooked(recipe))
|
||||
.send(StatusUpdate::Cooked(recipe, cached))
|
||||
.unwrap_or_default();
|
||||
if cooker_config.cook.nonstop
|
||||
&& cooker_prompting.load(Ordering::SeqCst) == 4
|
||||
@ -1414,20 +1455,23 @@ fn run_tui_cook(
|
||||
*s == RecipeStatus::Fetched
|
||||
|| *s == RecipeStatus::Cooking
|
||||
|| *s == RecipeStatus::Done
|
||||
|| *s == RecipeStatus::Cached
|
||||
|| matches!(s, RecipeStatus::Failed(_))
|
||||
})
|
||||
.map(|(r, s)| {
|
||||
let style = match s {
|
||||
RecipeStatus::Fetched => Style::default().fg(Color::Cyan),
|
||||
RecipeStatus::Fetched => Style::default(),
|
||||
RecipeStatus::Cooking => Style::default().fg(Color::Yellow),
|
||||
RecipeStatus::Done => Style::default().fg(Color::Green),
|
||||
RecipeStatus::Cached => Style::default().fg(Color::Cyan),
|
||||
RecipeStatus::Failed(_) => Style::default().fg(Color::Red),
|
||||
_ => Style::default(),
|
||||
};
|
||||
let icon = match s {
|
||||
RecipeStatus::Fetched => ' ',
|
||||
RecipeStatus::Cooking => spin,
|
||||
RecipeStatus::Done => ' ',
|
||||
RecipeStatus::Done => '+',
|
||||
RecipeStatus::Cached => ' ',
|
||||
RecipeStatus::Failed(_) => 'X',
|
||||
_ => '?',
|
||||
};
|
||||
|
||||
@ -167,6 +167,30 @@ fn auto_deps_from_static_package_deps(
|
||||
Ok(pkgs.into_iter().collect())
|
||||
}
|
||||
|
||||
pub struct BuildResult {
|
||||
pub stage_dirs: Vec<PathBuf>,
|
||||
pub auto_deps: BTreeSet<PackageName>,
|
||||
pub cached: bool,
|
||||
}
|
||||
|
||||
impl BuildResult {
|
||||
pub fn new(stage_dirs: Vec<PathBuf>, auto_deps: BTreeSet<PackageName>) -> Self {
|
||||
BuildResult {
|
||||
stage_dirs,
|
||||
auto_deps,
|
||||
cached: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cached(stage_dirs: Vec<PathBuf>, auto_deps: BTreeSet<PackageName>) -> Self {
|
||||
BuildResult {
|
||||
stage_dirs,
|
||||
auto_deps,
|
||||
cached: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(
|
||||
recipe_dir: &Path,
|
||||
source_dir: &Path,
|
||||
@ -174,7 +198,7 @@ pub fn build(
|
||||
cook_recipe: &CookRecipe,
|
||||
cook_config: &CookConfig,
|
||||
logger: &PtyOut,
|
||||
) -> Result<(Vec<PathBuf>, BTreeSet<PackageName>), String> {
|
||||
) -> Result<BuildResult, String> {
|
||||
let recipe = &cook_recipe.recipe;
|
||||
let name = &cook_recipe.name;
|
||||
let check_source = !cook_recipe.is_deps;
|
||||
@ -189,7 +213,7 @@ pub fn build(
|
||||
let cli_jobs = cook_config.jobs;
|
||||
if recipe.build.kind == BuildKind::None {
|
||||
// metapackages don't need to do anything here
|
||||
return Ok((stage_dirs, BTreeSet::new()));
|
||||
return Ok(BuildResult::new(stage_dirs, BTreeSet::new()));
|
||||
}
|
||||
|
||||
let mut dep_pkgars = BTreeSet::new();
|
||||
@ -234,7 +258,7 @@ pub fn build(
|
||||
log_to_pty!(logger, "DEBUG: using cached build, not checking source");
|
||||
}
|
||||
let auto_deps = make_auto_deps!()?;
|
||||
return Ok((stage_dirs, auto_deps));
|
||||
return Ok(BuildResult::cached(stage_dirs, auto_deps));
|
||||
}
|
||||
}
|
||||
|
||||
@ -276,7 +300,7 @@ pub fn build(
|
||||
if cook_config.clean_target {
|
||||
// stop early otherwise we'll end up rebuilding
|
||||
let auto_deps = make_auto_deps!()?;
|
||||
return Ok((stage_dirs, auto_deps));
|
||||
return Ok(BuildResult::cached(stage_dirs, auto_deps));
|
||||
}
|
||||
}
|
||||
|
||||
@ -493,7 +517,7 @@ pub fn build(
|
||||
}
|
||||
|
||||
let auto_deps = make_auto_deps!()?;
|
||||
Ok((stage_dirs, auto_deps))
|
||||
Ok(BuildResult::new(stage_dirs, auto_deps))
|
||||
}
|
||||
|
||||
pub fn remove_stage_dir(stage_dir: &PathBuf) -> Result<(), String> {
|
||||
@ -661,7 +685,7 @@ pub fn build_remote(
|
||||
recipe: &Recipe,
|
||||
target_dir: &Path,
|
||||
cook_config: &CookConfig,
|
||||
) -> Result<(Vec<PathBuf>, BTreeSet<PackageName>), String> {
|
||||
) -> Result<BuildResult, String> {
|
||||
let source_toml = target_dir.join("source.toml");
|
||||
let source_pubkey = "build/remotes/pub_key_static.redox-os.org.toml";
|
||||
|
||||
@ -714,7 +738,7 @@ pub fn build_remote(
|
||||
serialize_and_write(&auto_deps_path, &wrapper)?;
|
||||
wrapper.packages
|
||||
};
|
||||
Ok((stage_dirs, auto_deps))
|
||||
Ok(BuildResult::new(stage_dirs, auto_deps))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@ -10,20 +10,20 @@ use pkgar_core::HeaderFlags;
|
||||
use crate::{
|
||||
blake3::hash_to_hex,
|
||||
config::CookConfig,
|
||||
cook::{fetch, fs::*, pty::PtyOut},
|
||||
cook::{cook_build::BuildResult, fetch, fs::*, pty::PtyOut},
|
||||
log_to_pty,
|
||||
recipe::{BuildKind, CookRecipe, OptionalPackageRecipe},
|
||||
};
|
||||
|
||||
pub fn package(
|
||||
recipe: &CookRecipe,
|
||||
stage_dirs: &Vec<PathBuf>,
|
||||
auto_deps: &BTreeSet<PackageName>,
|
||||
build_result: &BuildResult,
|
||||
cook_config: &CookConfig,
|
||||
logger: &PtyOut,
|
||||
) -> Result<(), String> {
|
||||
let name = &recipe.name;
|
||||
let target_dir = &recipe.target_dir();
|
||||
let auto_deps = &build_result.auto_deps;
|
||||
if recipe.recipe.build.kind == BuildKind::None {
|
||||
// metapackages don't have stage dir and optional packages
|
||||
package_toml(
|
||||
@ -51,21 +51,12 @@ pub fn package(
|
||||
.map_err(|err| format!("failed to save pkgar secret key: {:?}", err))?;
|
||||
}
|
||||
|
||||
let Ok(stage_modified) = modified_all(stage_dirs, modified_dir) else {
|
||||
// stage dirs doesn't exist, assume safe only when clean_target = true
|
||||
if !crate::config::get_config().cook.clean_target {
|
||||
return Err("Stage directory is not present at packaging step".into());
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
let packages = recipe.recipe.get_packages_list();
|
||||
|
||||
for package in packages {
|
||||
let (stage_dir, package_file, package_meta) = package_stage_paths(package, target_dir);
|
||||
// Rebuild package if stage is newer
|
||||
if package_file.is_file() && modified(&package_file)? < stage_modified {
|
||||
if package_file.is_file() && !build_result.cached {
|
||||
log_to_pty!(logger, "DEBUG: updating '{}'", package_file.display());
|
||||
remove_all(&package_file)?;
|
||||
if package_meta.is_file() {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user