Skip to content

Commit

Permalink
util gc: allow specifying prune time
Browse files Browse the repository at this point in the history
This only affects pruning of the operation log for now, and only
supports the string "now" for now.
  • Loading branch information
jonathantanmy committed Jan 22, 2024
1 parent 25f9727 commit 9825317
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 4 deletions.
24 changes: 20 additions & 4 deletions cli/src/commands/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,18 @@ pub(crate) struct UtilCompletionArgs {

/// Run backend-dependent garbage collection.
#[derive(clap::Args, Clone, Debug)]
pub(crate) struct UtilGcArgs {}
pub(crate) struct UtilGcArgs {
/// Time threshold
///
/// By default, only obsolete objects and operations older than 2 weeks are
/// pruned.
///
/// Only the string "now" can be passed to this parameter. Support for
/// arbitrary absolute and relative timestamps will come in a subsequent
/// release.
#[arg(long)]
prune: Option<String>,
}

/// Print a ROFF (manpage)
#[derive(clap::Args, Clone, Debug)]
Expand Down Expand Up @@ -108,16 +119,21 @@ fn cmd_util_completion(
fn cmd_util_gc(
ui: &mut Ui,
command: &CommandHelper,
_args: &UtilGcArgs,
args: &UtilGcArgs,
) -> Result<(), CommandError> {
if command.global_args().at_operation != "@" {
return Err(user_error(
"Cannot garbage collect from a non-head operation",
));
}
let keep_newer = SystemTime::now()
- match args.prune.as_deref() {
None => Duration::from_secs(14 * 86400),
Some("now") => Duration::ZERO,
_ => return Err(user_error("--prune only accepts 'now'")),
};
let workspace_command = command.workspace_helper(ui)?;
// TODO: add command argument to specify the expiration time?
let keep_newer = SystemTime::now() - Duration::from_secs(14 * 86400);

let repo = workspace_command.repo();
repo.op_store()
.gc(slice::from_ref(repo.op_id()), keep_newer)?;
Expand Down
38 changes: 38 additions & 0 deletions cli/tests/test_util_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,42 @@ fn test_gc_args() {
insta::assert_snapshot!(stderr, @r###"
Error: Cannot garbage collect from a non-head operation
"###);

let stderr = test_env.jj_cmd_failure(&repo_path, &["util", "gc", "--prune=foobar"]);
insta::assert_snapshot!(stderr, @r###"
Error: --prune only accepts 'now'
"###);
}

#[test]
fn test_gc_operation_log() {
let test_env = TestEnvironment::default();
// Use the local backend because GitBackend::gc() depends on the git CLI.
test_env.jj_cmd_ok(
test_env.env_root(),
&["init", "repo", "--config-toml=ui.allow-init-native=true"],
);
let repo_path = test_env.env_root().join("repo");

// Create an operation.
std::fs::write(repo_path.join("file"), "a change\n").unwrap();
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "a change"]);
let op_to_remove = test_env.current_operation_id(&repo_path);

// Make another operation the head.
std::fs::write(repo_path.join("file"), "another change\n").unwrap();
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "another change"]);

// This works before the operation is removed.
test_env.jj_cmd_ok(&repo_path, &["debug", "operation", &op_to_remove]);

// Remove some operations.
test_env.jj_cmd_ok(&repo_path, &["operation", "abandon", "..@-"]);
test_env.jj_cmd_ok(&repo_path, &["util", "gc", "--prune=now"]);

// Now this doesn't work.
let stderr = test_env.jj_cmd_failure(&repo_path, &["debug", "operation", &op_to_remove]);
insta::assert_snapshot!(stderr, @r###"
Error: No operation ID matching "35688918195690874cbf1f282140cda33c882e48a84dbb0f92c262b52ace4a5753777432b18e9de01bc23121b23261eb2c828622836b9ec7ded7c0ca3c7c1670"
"###);
}

0 comments on commit 9825317

Please sign in to comment.