Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prune only branch #1127

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 44 additions & 1 deletion src/ostree/ot-builtin-prune.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ static gboolean opt_refs_only;
static char *opt_delete_commit;
static char *opt_keep_younger_than;
static char **opt_retain_branch_depth;
static char **opt_only_branches;

/* ATTENTION:
* Please remember to update the bash-completion script (bash/ostree) and
Expand All @@ -49,6 +50,7 @@ static GOptionEntry options[] = {
{ "keep-younger-than", 0, 0, G_OPTION_ARG_STRING, &opt_keep_younger_than, "Prune all commits older than the specified date", "DATE" },
{ "static-deltas-only", 0, 0, G_OPTION_ARG_NONE, &opt_static_deltas_only, "Change the behavior of delete-commit and keep-younger-than to prune only static deltas" },
{ "retain-branch-depth", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_retain_branch_depth, "Additionally retain BRANCH=DEPTH commits", "BRANCH=DEPTH" },
{ "only-branch", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_only_branches, "Only prune BRANCH (may be specified multiple times)", "BRANCH" },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you thought about making these positional args, e.g. just ostree prune foo bar? Seems more natural.

Hmm, although git prune foo bar has the opposite meaning:

<head>...
    In addition to objects reachable from any of our references, keep objects reachable from listed <head>s.

which I find odd, but if in case people are used to that, I'm fine with leaving it as a switch!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmm...not sure about promoting this to the toplevel quite yet.

{ NULL }
};

Expand Down Expand Up @@ -185,7 +187,7 @@ ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError *
gint n_objects_total;
gint n_objects_pruned;
guint64 objsize_total;
if (!(opt_retain_branch_depth || opt_keep_younger_than))
if (!(opt_retain_branch_depth || opt_keep_younger_than || opt_only_branches))
{
if (!ostree_repo_prune (repo, pruneflags, opt_depth,
&n_objects_total, &n_objects_pruned, &objsize_total,
Expand All @@ -210,6 +212,7 @@ ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError *
return glnx_throw (error, "Could not parse '%s'", opt_keep_younger_than);
}

/* Process --retain-branch-depth */
for (char **iter = opt_retain_branch_depth; iter && *iter; iter++)
{
/* bd should look like BRANCH=DEPTH where DEPTH is an int */
Expand Down Expand Up @@ -239,6 +242,45 @@ ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError *
cancellable, error))
return FALSE;

/* Process --only-branch. Note this combines with --retain-branch-depth; one
* could do e.g.:
* * --only-branch exampleos/x86_64/foo
* * --only-branch exampleos/x86_64/bar
* * --retain-branch-depth exampleos/x86_64/foo=0
* * --depth 5
* to prune exampleos/x86_64/foo to just the latest commit, and
* exampleos/x86_64/bar to a depth of 5.
*/
if (opt_only_branches)
{
/* Turn --only-branch into a set */
g_autoptr(GHashTable) only_branches_set = g_hash_table_new (g_str_hash, g_str_equal);
for (char **iter = opt_only_branches; iter && *iter; iter++)
{
const char *ref = *iter;
/* Ensure the specified branch exists */
if (!ostree_repo_resolve_rev (repo, ref, FALSE, NULL, error))
return FALSE;
g_hash_table_add (only_branches_set, (char*)ref);
}

/* Iterate over all refs, add equivalent of --retain-branch-depth=$ref=-1
* if the ref isn't in --only-branch set and there wasn't already a
* --retain-branch-depth specified for it.
*/
GLNX_HASH_TABLE_FOREACH (all_refs, const char *, ref)
{
if (!g_hash_table_contains (only_branches_set, ref) &&
!g_hash_table_contains (retain_branch_depth, ref))
{
g_hash_table_insert (retain_branch_depth, g_strdup (ref), GINT_TO_POINTER ((int)-1));
}
}
}

/* Traverse each ref, and gather all objects pointed to by it up to a
* specific depth (if configured).
*/
g_hash_table_iter_init (&hash_iter, all_refs);
while (g_hash_table_iter_next (&hash_iter, &key, &value))
{
Expand Down Expand Up @@ -275,6 +317,7 @@ ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError *
return FALSE;
}

/* We've gathered the reachable set; start the prune ✀ */
{ OstreeRepoPruneOptions opts = { pruneflags, reachable };
if (!ostree_repo_prune_from_reachable (repo, &opts,
&n_objects_total,
Expand Down
101 changes: 72 additions & 29 deletions tests/test-prune.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ skip_without_user_xattrs

setup_fake_remote_repo1 "archive"

echo '1..5'
echo '1..12'

cd ${test_tmpdir}
mkdir repo
Expand All @@ -44,16 +44,20 @@ done

${CMD_PREFIX} ostree --repo=repo pull --depth=-1 origin test

assert_repo_has_n_commits() {
repo=$1
count=$2
assert_streq "$(find ${repo}/objects -name '*.commit' | wc -l)" "${count}"
}

${CMD_PREFIX} ostree prune --repo=repo --refs-only --depth=2 -v
find repo | grep \.commit$ | wc -l > commitcount
assert_file_has_content commitcount "^3$"
assert_repo_has_n_commits repo 3
find repo/objects -name '*.tombstone-commit' | wc -l > tombstonecommitcount
assert_file_has_content tombstonecommitcount "^0$"
$OSTREE fsck

${CMD_PREFIX} ostree prune --repo=repo --refs-only --depth=1 -v
find repo | grep \.commit$ | wc -l > commitcount
assert_file_has_content commitcount "^2$"
assert_repo_has_n_commits repo 2
find repo/objects -name '*.tombstone-commit' | wc -l > tombstonecommitcount
assert_file_has_content tombstonecommitcount "^0$"

Expand All @@ -70,8 +74,7 @@ find repo/objects -name '*.tombstone-commit' | wc -l > tombstonecommitcount
assert_file_has_content tombstonecommitcount "^0$"

${CMD_PREFIX} ostree prune --repo=repo --refs-only --depth=0 -v
find repo/objects -name '*.commit' | wc -l > commitcount
assert_file_has_content commitcount "^1$"
assert_repo_has_n_commits repo 1
find repo/objects -name '*.tombstone-commit' | wc -l > tombstonecommitcount
assert_not_file_has_content tombstonecommitcount "^0$"
$OSTREE fsck
Expand All @@ -88,28 +91,22 @@ assert_file_has_content tombstonecommitcount "^1$"
$OSTREE fsck

${CMD_PREFIX} ostree prune --repo=repo --refs-only --depth=0 -v
find repo/objects -name '*.commit' | wc -l > commitcount
assert_file_has_content commitcount "^1$"
assert_repo_has_n_commits repo 1
${CMD_PREFIX} ostree --repo=repo commit --branch=test -m test -s test tree --timestamp="2005-10-29 12:43:29 +0000"
${CMD_PREFIX} ostree --repo=repo commit --branch=test -m test -s test tree --timestamp="2010-10-29 12:43:29 +0000"
find repo/objects -name '*.commit' | wc -l > commitcount
assert_file_has_content commitcount "^3$"
assert_repo_has_n_commits repo 3
${CMD_PREFIX} ostree --repo=repo prune --keep-younger-than="2015-10-29 12:43:29 +0000"
find repo/objects -name '*.commit' | wc -l > commitcount
assert_file_has_content commitcount "^2$"
assert_repo_has_n_commits repo 2
$OSTREE fsck


${CMD_PREFIX} ostree prune --repo=repo --refs-only --depth=0 -v
find repo/objects -name '*.commit' | wc -l > commitcount
assert_file_has_content commitcount "^2$"
assert_repo_has_n_commits repo 2
${CMD_PREFIX} ostree --repo=repo commit --branch=test -m test -s test tree --timestamp="October 25 1985"
${CMD_PREFIX} ostree --repo=repo commit --branch=test -m test -s test tree --timestamp="October 21 2015"
find repo/objects -name '*.commit' | wc -l > commitcount
assert_file_has_content commitcount "^4$"
assert_repo_has_n_commits repo 4
${CMD_PREFIX} ostree --repo=repo prune --keep-younger-than="1 week ago"
find repo/objects -name '*.commit' | wc -l > commitcount
assert_file_has_content commitcount "^2$"
assert_repo_has_n_commits repo 2

${CMD_PREFIX} ostree --repo=repo commit --branch=oldcommit tree --timestamp="2005-10-29 12:43:29 +0000"
oldcommit_rev=$($OSTREE --repo=repo rev-parse oldcommit)
Expand Down Expand Up @@ -200,8 +197,7 @@ for x in $(seq 3); do
${CMD_PREFIX} ostree --repo=datetest-snapshot-repo commit --branch=stable -m test -s "new stable build $x" tree
${CMD_PREFIX} ostree --repo=datetest-snapshot-repo commit --branch=dev -m test -s "new dev build $x" tree
done
find datetest-snapshot-repo/objects -name '*.commit' | wc -l > commitcount
assert_file_has_content commitcount "^16$"
assert_repo_has_n_commits datetest-snapshot-repo 16

# Snapshot the above
reinitialize_datesnap_repo() {
Expand All @@ -219,27 +215,74 @@ if ${CMD_PREFIX} ostree --repo=repo prune --keep-younger-than="1 week ago" --ret
fi
assert_file_has_content err.txt 'Invalid depth BACON'
${CMD_PREFIX} ostree --repo=repo prune --keep-younger-than="1 week ago" --retain-branch-depth=stable=-1
find repo/objects -name '*.commit' | wc -l > commitcount
assert_file_has_content commitcount "^11$"
assert_repo_has_n_commits repo 11
# Double check our backup is unchanged
find datetest-snapshot-repo/objects -name '*.commit' | wc -l > commitcount
assert_file_has_content commitcount "^16$"
assert_repo_has_n_commits datetest-snapshot-repo 16
$OSTREE fsck

# Again but this time only retain 6 (5+1) commits on stable. This should drop
# out 8 - 6 = 2 commits (so the 11 above minus 2 = 9)
${CMD_PREFIX} ostree --repo=repo prune --keep-younger-than="1 week ago" --retain-branch-depth=stable=5
find repo/objects -name '*.commit' | wc -l > commitcount
assert_file_has_content commitcount "^9$"
assert_repo_has_n_commits repo 9
$OSTREE fsck
echo "ok retain branch depth and keep-younger-than"

# Just stable branch ref, we should prune everything except the tip of dev,
# so 8 stable + 1 dev = 9
reinitialize_datesnap_repo
${CMD_PREFIX} ostree --repo=repo prune --depth=0 --retain-branch-depth=stable=-1
find repo/objects -name '*.commit' | wc -l > commitcount
assert_file_has_content commitcount "^9$"
assert_repo_has_n_commits repo 9
$OSTREE fsck

echo "ok retain branch depth (alone)"

# Test --only-branch with --depth=0; this should be exactly identical to the
# above with a result of 9.
reinitialize_datesnap_repo
${CMD_PREFIX} ostree --repo=repo prune --only-branch=dev --depth=0
assert_repo_has_n_commits repo 9
$OSTREE fsck
echo "ok --only-branch --depth=0"

# Test --only-branch with --depth=1; should just add 1 to the above, for 10.
reinitialize_datesnap_repo
${CMD_PREFIX} ostree --repo=repo prune --only-branch=dev --depth=1
assert_repo_has_n_commits repo 10
echo "ok --only-branch --depth=1"

# Test --only-branch with all branches
reinitialize_datesnap_repo
${CMD_PREFIX} ostree --repo=repo prune --only-branch=dev --only-branch=stable --depth=0
assert_repo_has_n_commits repo 2
reinitialize_datesnap_repo
${CMD_PREFIX} ostree --repo=repo prune --only-branch=dev --only-branch=stable --depth=1
assert_repo_has_n_commits repo 4
echo "ok --only-branch (all) --depth=1"

# Test --only-branch and --retain-branch-depth overlap
reinitialize_datesnap_repo
${CMD_PREFIX} ostree --repo=repo prune --only-branch=dev --only-branch=stable --depth=0 \
--retain-branch-depth=stable=2
assert_repo_has_n_commits repo 4
echo "ok --only-branch and --retain-branch-depth overlap"

# Test --only-branch and --retain-branch-depth together
reinitialize_datesnap_repo
${CMD_PREFIX} ostree --repo=repo prune --only-branch=dev --depth=0 --retain-branch-depth=stable=2
assert_repo_has_n_commits repo 4
echo "ok --only-branch and --retain-branch-depth together"

# Test --only-branch with --keep-younger-than; this should be identical to the test
# above for --retain-branch-depth=stable=-1
reinitialize_datesnap_repo
${CMD_PREFIX} ostree --repo=repo prune --only-branch=stable --keep-younger-than="1 week ago"
assert_repo_has_n_commits repo 11
echo "ok --only-branch --keep-younger-than"

# Test --only-branch with a nonexistent ref
reinitialize_datesnap_repo
if ${CMD_PREFIX} ostree --repo=repo prune --only-branch=BACON 2>err.txt; then
fatal "we pruned BACON?"
fi
assert_file_has_content err.txt "Refspec.*BACON.*not found"
echo "ok --only-branch=BACON"