From 4779209ef390627ac1c9801bc05d002859bbbb9a Mon Sep 17 00:00:00 2001 From: William Manley Date: Tue, 26 Jun 2018 19:49:12 +0100 Subject: [PATCH] ostree commit: Add option `--tree=prefix=PREFIX` This enhances `ostree commit`'s ability to compose trees. You can now run ostree commit -b rootfs \ --tree=ref=rootfs \ --tree=prefix=/usr/lib/machines/container --tree=ref=container and that will "mount" the container ref under usr/lib/machines/container in rootfs. It is much faster than checking the tree out and checking it back in again. This is useful for our buildsystem where we ship containers in the rootfs image. --- man/ostree-commit.xml | 7 +++++-- src/ostree/ot-builtin-commit.c | 35 ++++++++++++++++++++++++++------- tests/basic-test.sh | 36 ++++++++++++++++++++++++++-------- 3 files changed, 61 insertions(+), 17 deletions(-) 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