repo: Add a "force copy" flag to checkout
This is intended to be used for copying `/usr/etc` → `/etc` for deployments. A TODO here is to use `glnx_file_copy_at()` if the repo mode allows it - then we'd use reflinks if available. Closes: #804 Approved by: jlebon
This commit is contained in:
parent
3f1bcab27f
commit
6060abbb4b
|
|
@ -403,7 +403,7 @@ checkout_one_file_at (OstreeRepo *repo,
|
||||||
|
|
||||||
need_copy = FALSE;
|
need_copy = FALSE;
|
||||||
}
|
}
|
||||||
else
|
else if (!options->force_copy)
|
||||||
{
|
{
|
||||||
HardlinkResult hardlink_res = HARDLINK_RESULT_NOT_SUPPORTED;
|
HardlinkResult hardlink_res = HARDLINK_RESULT_NOT_SUPPORTED;
|
||||||
/* Try to do a hardlink first, if it's a regular file. This also
|
/* Try to do a hardlink first, if it's a regular file. This also
|
||||||
|
|
@ -895,6 +895,8 @@ ostree_repo_checkout_at (OstreeRepo *self,
|
||||||
if (ostree_repo_get_mode (self) == OSTREE_REPO_MODE_BARE_USER_ONLY)
|
if (ostree_repo_get_mode (self) == OSTREE_REPO_MODE_BARE_USER_ONLY)
|
||||||
options->mode = OSTREE_REPO_CHECKOUT_MODE_USER;
|
options->mode = OSTREE_REPO_CHECKOUT_MODE_USER;
|
||||||
|
|
||||||
|
g_return_val_if_fail (!(options->force_copy && options->no_copy_fallback), FALSE);
|
||||||
|
|
||||||
g_autoptr(GFile) commit_root = (GFile*) _ostree_repo_file_new_for_commit (self, commit, error);
|
g_autoptr(GFile) commit_root = (GFile*) _ostree_repo_file_new_for_commit (self, commit, error);
|
||||||
if (!commit_root)
|
if (!commit_root)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
|
||||||
|
|
@ -767,7 +767,8 @@ typedef struct {
|
||||||
gboolean enable_fsync; /* Deprecated */
|
gboolean enable_fsync; /* Deprecated */
|
||||||
gboolean process_whiteouts;
|
gboolean process_whiteouts;
|
||||||
gboolean no_copy_fallback;
|
gboolean no_copy_fallback;
|
||||||
gboolean unused_bools[7];
|
gboolean force_copy; /* Since: 2017.6 */
|
||||||
|
gboolean unused_bools[6];
|
||||||
|
|
||||||
const char *subpath;
|
const char *subpath;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ static gboolean opt_from_stdin;
|
||||||
static char *opt_from_file;
|
static char *opt_from_file;
|
||||||
static gboolean opt_disable_fsync;
|
static gboolean opt_disable_fsync;
|
||||||
static gboolean opt_require_hardlinks;
|
static gboolean opt_require_hardlinks;
|
||||||
|
static gboolean opt_force_copy;
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
parse_fsync_cb (const char *option_name,
|
parse_fsync_cb (const char *option_name,
|
||||||
|
|
@ -71,6 +72,7 @@ static GOptionEntry options[] = {
|
||||||
{ "from-file", 0, 0, G_OPTION_ARG_STRING, &opt_from_file, "Process many checkouts from input file", "FILE" },
|
{ "from-file", 0, 0, G_OPTION_ARG_STRING, &opt_from_file, "Process many checkouts from input file", "FILE" },
|
||||||
{ "fsync", 0, 0, G_OPTION_ARG_CALLBACK, parse_fsync_cb, "Specify how to invoke fsync()", "POLICY" },
|
{ "fsync", 0, 0, G_OPTION_ARG_CALLBACK, parse_fsync_cb, "Specify how to invoke fsync()", "POLICY" },
|
||||||
{ "require-hardlinks", 'H', 0, G_OPTION_ARG_NONE, &opt_require_hardlinks, "Do not fall back to full copies if hardlinking fails", NULL },
|
{ "require-hardlinks", 'H', 0, G_OPTION_ARG_NONE, &opt_require_hardlinks, "Do not fall back to full copies if hardlinking fails", NULL },
|
||||||
|
{ "force-copy", 'C', 0, G_OPTION_ARG_NONE, &opt_force_copy, "Never hardlink (but may reflink if available)", NULL },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -89,7 +91,7 @@ process_one_checkout (OstreeRepo *repo,
|
||||||
* `ostree_repo_checkout_at` until such time as we have a more
|
* `ostree_repo_checkout_at` until such time as we have a more
|
||||||
* convenient infrastructure for testing C APIs with data.
|
* convenient infrastructure for testing C APIs with data.
|
||||||
*/
|
*/
|
||||||
if (opt_disable_cache || opt_whiteouts || opt_require_hardlinks || opt_union_add)
|
if (opt_disable_cache || opt_whiteouts || opt_require_hardlinks || opt_union_add || opt_force_copy)
|
||||||
{
|
{
|
||||||
OstreeRepoCheckoutAtOptions options = { 0, };
|
OstreeRepoCheckoutAtOptions options = { 0, };
|
||||||
|
|
||||||
|
|
@ -102,6 +104,11 @@ process_one_checkout (OstreeRepo *repo,
|
||||||
"Cannot specify both --union and --union-add");
|
"Cannot specify both --union and --union-add");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
if (opt_require_hardlinks && opt_force_copy)
|
||||||
|
{
|
||||||
|
glnx_throw (error, "Cannot specify both --require-hardlinks and --force-copy");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
else if (opt_union)
|
else if (opt_union)
|
||||||
options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES;
|
options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES;
|
||||||
else if (opt_union_add)
|
else if (opt_union_add)
|
||||||
|
|
@ -111,6 +118,7 @@ process_one_checkout (OstreeRepo *repo,
|
||||||
if (subpath)
|
if (subpath)
|
||||||
options.subpath = subpath;
|
options.subpath = subpath;
|
||||||
options.no_copy_fallback = opt_require_hardlinks;
|
options.no_copy_fallback = opt_require_hardlinks;
|
||||||
|
options.force_copy = opt_force_copy;
|
||||||
|
|
||||||
if (!ostree_repo_checkout_at (repo, &options,
|
if (!ostree_repo_checkout_at (repo, &options,
|
||||||
AT_FDCWD, destination,
|
AT_FDCWD, destination,
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
echo "1..65"
|
echo "1..66"
|
||||||
|
|
||||||
$CMD_PREFIX ostree --version > version.yaml
|
$CMD_PREFIX ostree --version > version.yaml
|
||||||
python -c 'import yaml; yaml.safe_load(open("version.yaml"))'
|
python -c 'import yaml; yaml.safe_load(open("version.yaml"))'
|
||||||
|
|
@ -28,7 +28,7 @@ echo "ok yaml version"
|
||||||
CHECKOUT_U_ARG=""
|
CHECKOUT_U_ARG=""
|
||||||
COMMIT_ARGS=""
|
COMMIT_ARGS=""
|
||||||
DIFF_ARGS=""
|
DIFF_ARGS=""
|
||||||
if grep bare-user-only repo/config; then
|
if grep -q bare-user-only repo/config; then
|
||||||
# In bare-user-only repos we can only represent files with uid/gid 0, no
|
# In bare-user-only repos we can only represent files with uid/gid 0, no
|
||||||
# xattrs and canonical permissions, so we need to commit them as such, or
|
# xattrs and canonical permissions, so we need to commit them as such, or
|
||||||
# we end up with repos that don't pass fsck
|
# we end up with repos that don't pass fsck
|
||||||
|
|
@ -50,11 +50,14 @@ validate_checkout_basic() {
|
||||||
|
|
||||||
$OSTREE checkout test2 checkout-test2
|
$OSTREE checkout test2 checkout-test2
|
||||||
validate_checkout_basic checkout-test2
|
validate_checkout_basic checkout-test2
|
||||||
|
if grep -q 'mode=bare$' repo/config; then
|
||||||
|
assert_not_streq $(stat -c '%h' checkout-test2/firstfile) 1
|
||||||
|
fi
|
||||||
echo "ok checkout"
|
echo "ok checkout"
|
||||||
|
|
||||||
# Note this tests bare-user *and* bare-user-only
|
# Note this tests bare-user *and* bare-user-only
|
||||||
rm checkout-test2 -rf
|
rm checkout-test2 -rf
|
||||||
if grep bare-user repo/config; then
|
if grep -q bare-user repo/config; then
|
||||||
$OSTREE checkout -U -H test2 checkout-test2
|
$OSTREE checkout -U -H test2 checkout-test2
|
||||||
else
|
else
|
||||||
$OSTREE checkout -H test2 checkout-test2
|
$OSTREE checkout -H test2 checkout-test2
|
||||||
|
|
@ -78,6 +81,14 @@ fi
|
||||||
fi
|
fi
|
||||||
echo "ok checkout -H"
|
echo "ok checkout -H"
|
||||||
|
|
||||||
|
rm checkout-test2 -rf
|
||||||
|
$OSTREE checkout -C test2 checkout-test2
|
||||||
|
for file in firstfile baz/cow baz/alink; do
|
||||||
|
assert_streq $(stat -c '%h' checkout-test2/$file) 1
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "ok checkout -C"
|
||||||
|
|
||||||
$OSTREE rev-parse test2
|
$OSTREE rev-parse test2
|
||||||
$OSTREE rev-parse 'test2^'
|
$OSTREE rev-parse 'test2^'
|
||||||
$OSTREE rev-parse 'test2^^' 2>/dev/null && fatal "rev-parse test2^^ unexpectedly succeeded!"
|
$OSTREE rev-parse 'test2^^' 2>/dev/null && fatal "rev-parse test2^^ unexpectedly succeeded!"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue