Skip to content

Commit

Permalink
checkout: Support a "pure addition" mode
Browse files Browse the repository at this point in the history
I plan to use this for `rpm-ostree livefs`.
coreos/rpm-ostree#639
  • Loading branch information
cgwalters committed Mar 6, 2017
1 parent d87c367 commit adf6bb2
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 9 deletions.
8 changes: 8 additions & 0 deletions man/ostree-checkout.xml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@ Boston, MA 02111-1307, USA.
</para></listitem>
</varlistentry>

<varlistentry>
<term><option>--union-add</option></term>

<listitem><para>
Keep existing directories and files.
</para></listitem>
</varlistentry>

<varlistentry>
<term><option>--allow-noent</option></term>

Expand Down
28 changes: 25 additions & 3 deletions src/libostree/ostree-repo-checkout.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,16 @@ checkout_file_from_input_at (OstreeRepo *self,
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (res == -1)
{
glnx_set_error_from_errno (error);
goto out;
if (errno == EEXIST && options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES)
{
ret = TRUE;
goto out;
}
else
{
glnx_set_error_from_errno (error);
goto out;
}
}

if (options->mode != OSTREE_REPO_CHECKOUT_MODE_USER)
Expand Down Expand Up @@ -240,6 +248,11 @@ checkout_file_from_input_at (OstreeRepo *self,
while (G_UNLIKELY (fd == -1 && errno == EINTR));
if (fd == -1)
{
if (errno == EEXIST && options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES)
{
ret = TRUE;
goto out;
}
glnx_set_error_from_errno (error);
goto out;
}
Expand Down Expand Up @@ -362,6 +375,12 @@ checkout_file_hardlink (OstreeRepo *self,
{
ret_was_supported = FALSE;
}
else if (errno == EEXIST && options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES)
{
/* In this mode, we keep existing content. Still need to mark the hardlink as supported.
*/
ret_was_supported = TRUE;
}
else if (errno == EEXIST && options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES)
{
/* Idiocy, from man rename(2)
Expand Down Expand Up @@ -573,6 +592,7 @@ checkout_one_file_at (OstreeRepo *repo,
/* Fall back to copy if we couldn't hardlink */
if (need_copy)
{
g_assert (!options->no_copy_fallback);
if (!ostree_repo_load_file (repo, checksum, &input, NULL, &xattrs,
cancellable, error))
goto out;
Expand Down Expand Up @@ -655,7 +675,9 @@ checkout_tree_at (OstreeRepo *self,
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (res == -1)
{
if (errno == EEXIST && options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES)
if (errno == EEXIST &&
(options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES
|| options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES))
did_exist = TRUE;
else
{
Expand Down
6 changes: 4 additions & 2 deletions src/libostree/ostree-repo.h
Original file line number Diff line number Diff line change
Expand Up @@ -722,11 +722,13 @@ typedef enum {
/**
* OstreeRepoCheckoutOverwriteMode:
* @OSTREE_REPO_CHECKOUT_OVERWRITE_NONE: No special options
* @OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: When layering checkouts, overwrite earlier files, but keep earlier directories
* @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
*/
typedef enum {
OSTREE_REPO_CHECKOUT_OVERWRITE_NONE = 0,
OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES = 1
OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES = 1,
OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES = 2, /* Since: 2017.3 */
} OstreeRepoCheckoutOverwriteMode;

_OSTREE_PUBLIC
Expand Down
17 changes: 14 additions & 3 deletions src/ostree/ot-builtin-checkout.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ static gboolean opt_allow_noent;
static gboolean opt_disable_cache;
static char *opt_subpath;
static gboolean opt_union;
static gboolean opt_union_add;
static gboolean opt_whiteouts;
static gboolean opt_from_stdin;
static char *opt_from_file;
Expand Down Expand Up @@ -63,6 +64,7 @@ static GOptionEntry options[] = {
{ "disable-cache", 0, 0, G_OPTION_ARG_NONE, &opt_disable_cache, "Do not update or use the internal repository uncompressed object cache", NULL },
{ "subpath", 0, 0, G_OPTION_ARG_STRING, &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 },
{ "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 },
Expand All @@ -87,14 +89,23 @@ process_one_checkout (OstreeRepo *repo,
* `ostree_repo_checkout_at` until such time as we have a more
* convenient infrastructure for testing C APIs with data.
*/
if (opt_disable_cache || opt_whiteouts || opt_require_hardlinks)
if (opt_disable_cache || opt_whiteouts || opt_require_hardlinks || opt_union_add)
{
OstreeRepoCheckoutAtOptions options = { 0, };

if (opt_user_mode)
options.mode = OSTREE_REPO_CHECKOUT_MODE_USER;
if (opt_union)
/* Can't union these */
if (opt_union && opt_union_add)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Cannot specify both --union and --union-add");
goto out;
}
else if (opt_union)
options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES;
else if (opt_union_add)
options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES;
if (opt_whiteouts)
options.process_whiteouts = TRUE;
if (subpath)
Expand Down
20 changes: 19 additions & 1 deletion tests/basic-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

set -euo pipefail

echo "1..62"
echo "1..63"

$CMD_PREFIX ostree --version > version.yaml
python -c 'import yaml; yaml.safe_load(open("version.yaml"))'
Expand Down Expand Up @@ -279,6 +279,24 @@ cd checkout-test2-union
assert_file_has_content ./yet/another/tree/green "leaf"
echo "ok checkout union 1"

cd ${test_tmpdir}
$OSTREE commit -b test-union-add --tree=ref=test2
$OSTREE checkout test-union-add checkout-test-union-add
echo 'file for union add testing' > checkout-test-union-add/union-add-test
echo 'another file for union add testing' > checkout-test-union-add/union-add-test2
$OSTREE commit -b test-union-add --tree=dir=checkout-test-union-add
rm checkout-test-union-add -rf
# Check out previous
$OSTREE checkout test-union-add^ checkout-test-union-add
assert_not_has_file checkout-test-union-add/union-add-test
assert_not_has_file checkout-test-union-add/union-add-test2
# Now create a file we don't want overwritten
echo 'existing file for union add' > checkout-test-union-add/union-add-test
$OSTREE checkout --union-add test-union-add checkout-test-union-add
assert_file_has_content checkout-test-union-add/union-add-test 'existing file for union add'
assert_file_has_content checkout-test-union-add/union-add-test2 'another file for union add testing'
echo "ok checkout union add"

cd ${test_tmpdir}
rm -rf shadow-repo
mkdir shadow-repo
Expand Down

0 comments on commit adf6bb2

Please sign in to comment.