diff --git a/man/ostree-commit.xml b/man/ostree-commit.xml index b0c5b3355d..7d96a2472e 100644 --- a/man/ostree-commit.xml +++ b/man/ostree-commit.xml @@ -99,10 +99,13 @@ Boston, MA 02111-1307, USA. - ="dir=PATH" or "tar=TARFILE" or "ref=COMMIT" + ="dir=PATH" or "tar=TARFILE" or "ref=COMMIT" or "prefix=PATH" - Overlay the given argument as a tree. When committing an archive, the TARFILE can be specified as - to read the archive from standard input. + Overlay the given argument as a tree. When committing an archive, the TARFILE + can be specified as - to read the archive from standard + input. prefix is a little different - --tree=prefix=PATH affects where in the + tree the later --tree=ref/tar/dir are merged. diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c index 20409fc213..65714736da 100644 --- a/src/ostree/ot-builtin-commit.c +++ b/src/ostree/ot-builtin-commit.c @@ -104,7 +104,7 @@ static GOptionEntry options[] = { { "no-bindings", 0, 0, G_OPTION_ARG_NONE, &opt_no_bindings, "Do not write any ref bindings", NULL }, { "bind-ref", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_bind_refs, "Add a ref to ref binding commit metadata", "BRANCH" }, { "base", 0, 0, G_OPTION_ARG_STRING, &opt_base, "Start from the given commit as a base (no modifiers apply)", "REF" }, - { "tree", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_trees, "Overlay the given argument as a tree", "dir=PATH or tar=TARFILE or ref=COMMIT" }, + { "tree", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_trees, "Overlay the given argument as a tree", "dir=PATH or tar=TARFILE or ref=COMMIT or prefix=PATH" }, { "add-metadata-string", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata_strings, "Add a key/value pair to metadata", "KEY=VALUE" }, { "add-metadata", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata_variants, "Add a key/value pair to metadata, where the KEY is a string, an VALUE is g_variant_parse() formatted", "KEY=VALUE" }, { "keep-metadata", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata_keep, "Keep metadata KEY and its associated VALUE from parent", "KEY" }, @@ -636,7 +636,7 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio { mtree = ostree_mutable_tree_new (); } - + g_autoptr(OstreeMutableTree) target_mtree = g_object_ref (mtree); /* Convert implicit . or explicit path via argv into * --tree=dir= so that we only have one primary code path below. @@ -691,7 +691,7 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio goto out; ostree_repo_commit_modifier_set_sepolicy (modifier, policy); } - if (!ostree_repo_write_dfd_to_mtree (repo, AT_FDCWD, tree, mtree, modifier, + if (!ostree_repo_write_dfd_to_mtree (repo, AT_FDCWD, tree, target_mtree, modifier, cancellable, error)) goto out; } @@ -706,7 +706,7 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio { if (strcmp (tree, "-") == 0) { - if (!ostree_repo_write_archive_to_mtree_from_fd (repo, STDIN_FILENO, mtree, modifier, + if (!ostree_repo_write_archive_to_mtree_from_fd (repo, STDIN_FILENO, target_mtree, modifier, opt_tar_autocreate_parents, cancellable, error)) goto out; @@ -715,7 +715,7 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio { object_to_commit = g_file_new_for_path (tree); - if (!ostree_repo_write_archive_to_mtree (repo, object_to_commit, mtree, modifier, + if (!ostree_repo_write_archive_to_mtree (repo, object_to_commit, target_mtree, modifier, opt_tar_autocreate_parents, cancellable, error)) goto out; @@ -754,7 +754,7 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio if (!archive) goto out; - if (!ostree_repo_import_archive_to_mtree (repo, &opts, archive, mtree, + if (!ostree_repo_import_archive_to_mtree (repo, &opts, archive, target_mtree, modifier, cancellable, error)) goto out; #else @@ -775,10 +775,31 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio if (!ostree_repo_read_commit (repo, tree, &object_to_commit, NULL, cancellable, error)) goto out; - if (!ostree_repo_write_directory_to_mtree (repo, object_to_commit, mtree, modifier, + if (!ostree_repo_write_directory_to_mtree (repo, object_to_commit, target_mtree, modifier, cancellable, error)) goto out; } + else if (strcmp (tree_type, "prefix") == 0) + { + if (!tree || g_strcmp0(tree, "") == 0 || g_strcmp0(tree, "/") == 0) + g_set_object (&target_mtree, mtree); + else + { + const char dirmeta_0755_0_0[] = "446a0ef11b7cc167f3b603e585c7eeeeb675faa412d5ec73f62988eb0b6c5488"; + g_autoptr(GPtrArray) split_path = NULL; + if (!ot_util_path_split_validate (tree, &split_path, error)) + goto out; + + /* ensure_parent_dirs makes a directory for a file, so we have + * to give a dummy filename: */ + g_ptr_array_add (split_path, g_strdup ("dummy")); + + g_clear_object (&target_mtree); + if (!ostree_mutable_tree_ensure_parent_dirs (mtree, + split_path, dirmeta_0755_0_0, &target_mtree, error)) + goto out; + } + } else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, diff --git a/tests/basic-test.sh b/tests/basic-test.sh index fc193f4f96..efa03c8f97 100644 --- a/tests/basic-test.sh +++ b/tests/basic-test.sh @@ -21,7 +21,7 @@ set -euo pipefail -echo "1..$((86 + ${extra_basic_tests:-0}))" +echo "1..$((87 + ${extra_basic_tests:-0}))" CHECKOUT_U_ARG="" CHECKOUT_H_ARGS="-H" @@ -456,6 +456,33 @@ cd ${test_tmpdir}/checkout-test2-4 $OSTREE commit ${COMMIT_ARGS} -b test2 -s "no xattrs" --no-xattrs echo "ok commit with no xattrs" +assert_trees_identical() { + $OSTREE diff "$1" "$2" > "diff-$1-$2" + cat "diff-$1-$2" 1>&2 + assert_file_empty "diff-$1-$2" + rm "diff-$1-$2" +} + +mkdir -p prefix1 prefix-expected/usr/bin +$OSTREE commit ${COMMIT_ARGS} -b empty_usr_bin --tree=dir=prefix-expected +echo bish-bosh >prefix1/bash +echo bish-bosh >prefix-expected/usr/bin/bash +echo ing >touch + +$OSTREE commit ${COMMIT_ARGS} -b prefix-expected-root --owner-uid 0 --owner-gid 0 --tree=dir=prefix-expected +$OSTREE commit ${COMMIT_ARGS} -b prefix1a --owner-uid 0 --owner-gid 0 --tree=prefix=/usr/bin --tree=dir=prefix1 + +assert_trees_identical prefix1a prefix-expected-root + +# --prefix refers to trees after the --tree=prefix= option, but it does mkdir +# the given directories +mkdir -p prefix2/usr/bin +$OSTREE commit ${COMMIT_ARGS} -b prefix-none --owner-uid 0 --owner-gid 0 --tree=dir=prefix2 --tree=dir=prefix1 +$OSTREE commit ${COMMIT_ARGS} -b prefix-none-a --owner-uid 0 --owner-gid 0 --tree=dir=prefix1 --tree=prefix=/usr/bin +assert_trees_identical prefix-none prefix-none-a + +echo "ok commit with prefix" + mkdir tree-A tree-B touch tree-A/file-a tree-B/file-b @@ -488,13 +515,6 @@ $OSTREE commit ${COMMIT_ARGS} -b test3-dir-ref --tree=dir=tree-C --tree=ref=test $OSTREE commit ${COMMIT_ARGS} -b test3-ref-dir --tree=ref=test3-C1 --tree=dir=tree-D $OSTREE commit ${COMMIT_ARGS} -b test3-dir-dir --tree=dir=tree-C --tree=dir=tree-D -assert_trees_identical() { - $OSTREE diff "$1" "$2" > "diff-$1-$2" - cat "diff-$1-$2" 1>&2 - assert_file_empty "diff-$1-$2" - rm "diff-$1-$2" -} - for x in ref dir do for y in ref dir