* @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
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;
{ "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 },
* 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, };
"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");
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)
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"))'
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