From ca7e4737da2d192d935dc637fcd2114f4c6cea53 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Sat, 9 May 2026 18:32:32 +0700 Subject: [PATCH] Implement git rollback --- src/bin/repo.rs | 25 ++++++++++++++++++------- src/cook/fs.rs | 24 ++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/bin/repo.rs b/src/bin/repo.rs index 51dcb625..898a11f9 100644 --- a/src/bin/repo.rs +++ b/src/bin/repo.rs @@ -3,7 +3,8 @@ use cookbook::config::{CookConfig, CookLockOpt, get_config, init_config}; use cookbook::cook::cook_build::{build, get_stage_dirs, remove_stage_dir}; use cookbook::cook::fetch::{FetchResult, fetch, fetch_offline}; use cookbook::cook::fs::{ - create_dir, create_target_dir, get_git_commit_date, get_git_head_rev, remove_all, run_command, + create_dir, create_target_dir, get_git_commit_date, get_git_head_rev, get_git_rev_before_date, + remove_all, run_command, }; use cookbook::cook::package::{package, package_handle_push}; use cookbook::cook::pty::{PtyOut, UnixSlavePty, flush_pty, setup_pty, write_to_pty}; @@ -972,7 +973,7 @@ fn handle_change_rule( command: &CliCommand, ) -> Result<()> { let mut lock = get_config().recipe_lock.clone(); - let _cookbook_date = get_git_commit_date(&PathBuf::from("."))?; + let cookbook_date = get_git_commit_date(&PathBuf::from("."))?; let is_change_rule = matches!(command, CliCommand::ChangeRule); let is_capture_rev = matches!(command, CliCommand::CaptureRev); for recipe in recipes { @@ -1002,12 +1003,22 @@ fn handle_change_rule( if config.unset { recipe_lock.gitrev.take().is_none() } else { - if config.with_rollback { - todo!(); + let source_dir = recipe.dir.join("source"); + let rev = if config.with_rollback { + get_git_rev_before_date(&source_dir, &cookbook_date) + } else { + get_git_head_rev(&source_dir).map(|r| r.0) + }; + match rev { + Ok(rev) => { + let old_rev = recipe_lock.gitrev.replace(rev.clone()); + old_rev == Some(rev) + } + Err(e) => { + eprintln!("Skipped: {e}"); + continue; + } } - let (rev, _) = get_git_head_rev(&recipe.dir.join("source"))?; - let old_rev = recipe_lock.gitrev.replace(rev.clone()); - old_rev == Some(rev) } } else { unreachable!() diff --git a/src/cook/fs.rs b/src/cook/fs.rs index c24efa2a..87f9a344 100644 --- a/src/cook/fs.rs +++ b/src/cook/fs.rs @@ -485,6 +485,26 @@ pub fn get_git_commit_date(dir: &PathBuf) -> Result { git.stdout(Stdio::piped()); git.output() - .map_err(wrap_io_err!("Executing git")) - .map(|s| String::from_utf8_lossy(&s.stdout).to_string()) + .map_err(wrap_io_err!("Executing git log")) + .map(|s| String::from_utf8_lossy(&s.stdout).trim().to_string()) +} + +pub fn get_git_rev_before_date(dir: &PathBuf, date: &str) -> Result { + let mut git = process::Command::new("git"); + git.args(["rev-list", "-n", "1", &format!("--before={}", date), "HEAD"]); + git.current_dir(dir); + git.stdout(Stdio::piped()); + + let output = git + .output() + .map_err(wrap_io_err!("Executing git rev-list"))?; + let rev = String::from_utf8_lossy(&output.stdout).trim().to_string(); + + if rev.is_empty() { + return Err(Error::from(format!( + "No commit found before {} in {:?}", + date, dir + ))); + } + Ok(rev) }