checkout: add an extra checkout_overwrite mode
authorRuixin <peter.bao@mail.utoronto.ca>
Thu, 31 Aug 2017 15:44:35 +0000 (15:44 +0000)
committerAtomic Bot <atomic-devel@projectatomic.io>
Fri, 1 Sep 2017 15:42:50 +0000 (15:42 +0000)
This is for issue projectatomic/rpm-ostree#365,
an extra option of overwrite mode is added to the checkout command
so that when there is "non-directory" file already exist
during checkout, the error will be handled.

Some tests are added for regression

Closes: #1116
Approved by: cgwalters

bash/ostree
man/ostree-checkout.xml
src/libostree/ostree-repo-checkout.c
src/libostree/ostree-repo.h
src/ostree/ot-builtin-checkout.c
tests/basic-test.sh

index f12d88b7d30e15e45275d5eaf4956296eb34e88d..4ebe22c3d2e340edf21508ea23592da58d487236 100644 (file)
@@ -696,6 +696,7 @@ _ostree_checkout() {
         --require-hardlinks -H
         --union
         --union-add
+        --disjoint-union
         --user-mode -U
         --whiteouts
     "
index c8585878daf0f160e29b8ab9844e912a651ddf51..07d44b3457fd5d5a69a6c22041bab2dee6f54d07 100644 (file)
@@ -97,6 +97,14 @@ Boston, MA 02111-1307, USA.
                 </para></listitem>
             </varlistentry>
 
+            <varlistentry>
+                <term><option>--disjoint-union</option></term>
+
+                <listitem><para>
+                    When layering checkouts, error out if a file would be replaced, but add new files and directories
+                </para></listitem>
+            </varlistentry>
+
             <varlistentry>
                 <term><option>--allow-noent</option></term>
 
index 3deaa297d739895e25a63c64d7d200cfb4a77219..4fbbee7dc0e0a08ee6ad495f892cd67893129d82 100644 (file)
@@ -654,7 +654,8 @@ checkout_tree_at_recurse (OstreeRepo                        *self,
       {
         if (errno == EEXIST &&
             (options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES
-             || options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES))
+             || options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES
+             || options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_DISJOINT_UNION_FILES))
           did_exist = TRUE;
         else
           return glnx_throw_errno (error);
index ab0370206812ca0b489560351baf0262429c0d1f..58b1a1dc27abd918cc789fbfb1de36cc64c9d6ac 100644 (file)
@@ -832,11 +832,13 @@ typedef enum {
  * @OSTREE_REPO_CHECKOUT_OVERWRITE_NONE: No special options
  * @OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: When layering checkouts, unlink() and replace existing files, but do not modify existing directories
  * @OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES: Only add new files/directories
+ * @OSTREE_REPO_CHECKOUT_OVERWRITE_DISJOINT_UNION_FILES: When layering checkouts, error out if a file would be replaced, but add new files and directories
  */
 typedef enum {
   OSTREE_REPO_CHECKOUT_OVERWRITE_NONE = 0,
   OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES = 1,
   OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES = 2, /* Since: 2017.3 */
+  OSTREE_REPO_CHECKOUT_OVERWRITE_DISJOINT_UNION_FILES = 3 /* Since: 2017.11 */
 } OstreeRepoCheckoutOverwriteMode;
 
 _OSTREE_PUBLIC
index a31d36852080bf330b9f63a03a55c29bafc66285..a3494ae3abc935dfa2f5aca05174deefd841fc45 100644 (file)
@@ -37,6 +37,7 @@ static gboolean opt_disable_cache;
 static char *opt_subpath;
 static gboolean opt_union;
 static gboolean opt_union_add;
+static gboolean opt_disjoint_union;
 static gboolean opt_whiteouts;
 static gboolean opt_from_stdin;
 static char *opt_from_file;
@@ -72,6 +73,7 @@ static GOptionEntry options[] = {
   { "subpath", 0, 0, G_OPTION_ARG_FILENAME, &opt_subpath, "Checkout sub-directory PATH", "PATH" },
   { "union", 0, 0, G_OPTION_ARG_NONE, &opt_union, "Keep existing directories, overwrite existing files", NULL },
   { "union-add", 0, 0, G_OPTION_ARG_NONE, &opt_union_add, "Keep existing files/directories, only add new", NULL },
+  { "disjoint-union", 0, 0, G_OPTION_ARG_NONE, &opt_disjoint_union, "When layering checkouts, error out if a file would be replaced, but add new files and directories", NULL },
   { "whiteouts", 0, 0, G_OPTION_ARG_NONE, &opt_whiteouts, "Process 'whiteout' (Docker style) entries", NULL },
   { "allow-noent", 0, 0, G_OPTION_ARG_NONE, &opt_allow_noent, "Do nothing if specified path does not exist", NULL },
   { "from-stdin", 0, 0, G_OPTION_ARG_NONE, &opt_from_stdin, "Process many checkouts from standard input", NULL },
@@ -99,7 +101,7 @@ process_one_checkout (OstreeRepo           *repo,
    * convenient infrastructure for testing C APIs with data.
    */
   if (opt_disable_cache || opt_whiteouts || opt_require_hardlinks ||
-      opt_union_add || opt_force_copy || opt_bareuseronly_dirs)
+      opt_union_add || opt_force_copy || opt_bareuseronly_dirs || opt_disjoint_union)
     {
       OstreeRepoCheckoutAtOptions options = { 0, };
 
@@ -112,6 +114,18 @@ process_one_checkout (OstreeRepo           *repo,
                        "Cannot specify both --union and --union-add");
           goto out;
         }
+      if (opt_union && opt_disjoint_union)
+        {
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                       "Cannot specify both --union and --disjoint-union");
+          goto out;
+        }
+      if (opt_union_add && opt_disjoint_union)
+        {
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                       "Cannot specify both --union-add and --disjoint-union ");
+          goto out;
+        }
       if (opt_require_hardlinks && opt_force_copy)
         {
           glnx_throw (error, "Cannot specify both --require-hardlinks and --force-copy");
@@ -121,6 +135,8 @@ process_one_checkout (OstreeRepo           *repo,
         options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES;
       else if (opt_union_add)
         options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES;
+      else if (opt_disjoint_union)
+        options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_DISJOINT_UNION_FILES;
       if (opt_whiteouts)
         options.process_whiteouts = TRUE;
       if (subpath)
index de4bd445c52d4222f6f31e6340b183147f48a21f..6b43ca907e4bf0639db16b08644217c022429c3c 100644 (file)
@@ -19,7 +19,7 @@
 
 set -euo pipefail
 
-echo "1..$((70 + ${extra_basic_tests:-0}))"
+echo "1..$((72 + ${extra_basic_tests:-0}))"
 
 $CMD_PREFIX ostree --version > version.yaml
 python -c 'import yaml; yaml.safe_load(open("version.yaml"))'
@@ -469,6 +469,32 @@ assert_file_has_content checkout-test-union-add/union-add-test 'existing file fo
 assert_file_has_content checkout-test-union-add/union-add-test2 'another file for union add testing'
 echo "ok checkout union add"
 
+# Create some new files for testing
+cd ${test_tmpdir}
+mkdir disjoint-union-test
+mkdir disjoint-union-test/test_one
+chmod a+w disjoint-union-test/test_one
+echo 'file for add dirs testing' > disjoint-union-test/test_one/test_file
+$OSTREE commit ${COMMIT_ARGS} -b test-disjoint-union --tree=dir=disjoint-union-test
+$OSTREE checkout --disjoint-union test-disjoint-union checkout-test-disjoint-union
+echo "ok adding new directories and new file"
+# Make a new file, and try the checkout again
+echo 'second test file' >  disjoint-union-test/test_one/test_second_file
+$OSTREE commit ${COMMIT_ARGS} -b test-disjoint-union --tree=dir=disjoint-union-test
+# Check out the latest commit, should fail due to presence of existing files
+if $OSTREE checkout --disjoint-union test-disjoint-union checkout-test-disjoint-union 2> err.txt; then
+    assert_not_reached "checking out files unexpectedly succeeded!"
+fi
+assert_file_has_content err.txt 'File exists'
+# Verify that Union mode still functions properly
+rm checkout-test-disjoint-union/test_one/test_file
+echo 'file for testing union mode alongwith disjoint-union mode' > checkout-test-disjoint-union/test_one/test_file
+$OSTREE checkout --union test-disjoint-union checkout-test-disjoint-union
+assert_has_file checkout-test-disjoint-union/test_one/test_second_file
+# This shows the file with same name has been successfully overwriten
+assert_file_has_content checkout-test-disjoint-union/test_one/test_file 'file for add dirs testing'
+echo "ok checkout disjoint union"
+
 cd ${test_tmpdir}
 rm files -rf && mkdir files
 mkdir files/worldwritable-dir