repo: Make ostree_repo_create() nonfatal on existing repos
In general we want to support "idempotentcy" or "state synchronization" across interruption. If a repo is only partially created due to a crash or whatever, it's hard for a user to know that. Let's just make `ostree_repo_create()` idempotent. Since all we're doing is a set of `mkdirat()` invocations, it's quite simple. This also involved porting to fd-relative, which IMO makes the code a lot clearer. Closes: #422 Approved by: 14rcole
This commit is contained in:
parent
a312d8fd8c
commit
5334758ba7
|
|
@ -1842,8 +1842,15 @@ ostree_repo_mode_from_string (const char *mode,
|
||||||
* @cancellable: Cancellable
|
* @cancellable: Cancellable
|
||||||
* @error: Error
|
* @error: Error
|
||||||
*
|
*
|
||||||
* Create the underlying structure on disk for the
|
* Create the underlying structure on disk for the repository, and call
|
||||||
* repository.
|
* ostree_repo_open() on the result, preparing it for use.
|
||||||
|
|
||||||
|
* Since version 2016.8, this function will succeed on an existing
|
||||||
|
* repository, and finish creating any necessary files in a partially
|
||||||
|
* created repository. However, this function cannot change the mode
|
||||||
|
* of an existing repository, and will silently ignore an attempt to
|
||||||
|
* do so.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
ostree_repo_create (OstreeRepo *self,
|
ostree_repo_create (OstreeRepo *self,
|
||||||
|
|
@ -1851,76 +1858,65 @@ ostree_repo_create (OstreeRepo *self,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
const char *repopath = gs_file_get_path_cached (self->repodir);
|
||||||
GString *config_data = NULL;
|
glnx_fd_close int dfd = -1;
|
||||||
g_autoptr(GFile) child = NULL;
|
struct stat stbuf;
|
||||||
g_autoptr(GFile) grandchild = NULL;
|
const char *state_dirs[] = { "objects", "tmp", "extensions", "state",
|
||||||
const char *mode_str;
|
"refs", "refs/heads", "refs/remotes" };
|
||||||
|
|
||||||
if (!ostree_repo_mode_to_string (mode, &mode_str, error))
|
if (mkdir (repopath, 0755) != 0)
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (mkdir (gs_file_get_path_cached (self->repodir), 0755) != 0)
|
|
||||||
{
|
{
|
||||||
if (errno != EEXIST)
|
if (G_UNLIKELY (errno != EEXIST))
|
||||||
{
|
{
|
||||||
glnx_set_error_from_errno (error);
|
glnx_set_error_from_errno (error);
|
||||||
goto out;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config_data = g_string_new (DEFAULT_CONFIG_CONTENTS);
|
if (!glnx_opendirat (AT_FDCWD, repopath, TRUE, &dfd, error))
|
||||||
g_string_append_printf (config_data, "mode=%s\n", mode_str);
|
return FALSE;
|
||||||
|
|
||||||
if (!g_file_replace_contents (self->config_file,
|
if (fstatat (dfd, "config", &stbuf, 0) < 0)
|
||||||
config_data->str,
|
{
|
||||||
config_data->len,
|
if (errno == ENOENT)
|
||||||
NULL, FALSE, 0, NULL,
|
{
|
||||||
cancellable, error))
|
const char *mode_str;
|
||||||
goto out;
|
g_autoptr(GString) config_data = g_string_new (DEFAULT_CONFIG_CONTENTS);
|
||||||
|
|
||||||
if (!g_file_make_directory (self->objects_dir, cancellable, error))
|
if (!ostree_repo_mode_to_string (mode, &mode_str, error))
|
||||||
goto out;
|
return FALSE;
|
||||||
|
|
||||||
if (!g_file_make_directory (self->tmp_dir, cancellable, error))
|
g_string_append_printf (config_data, "mode=%s\n", mode_str);
|
||||||
goto out;
|
|
||||||
|
|
||||||
{
|
if (!glnx_file_replace_contents_at (dfd, "config",
|
||||||
g_autoptr(GFile) extensions_dir =
|
(guint8*)config_data->str, config_data->len,
|
||||||
g_file_resolve_relative_path (self->repodir, "extensions");
|
0, cancellable, error))
|
||||||
if (!g_file_make_directory (extensions_dir, cancellable, error))
|
return FALSE;
|
||||||
goto out;
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
glnx_set_error_from_errno (error);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
g_clear_object (&child);
|
for (guint i = 0; i < G_N_ELEMENTS (state_dirs); i++)
|
||||||
child = g_file_get_child (self->repodir, "refs");
|
{
|
||||||
if (!g_file_make_directory (child, cancellable, error))
|
const char *elt = state_dirs[i];
|
||||||
goto out;
|
if (mkdirat (dfd, elt, 0755) == -1)
|
||||||
|
{
|
||||||
g_clear_object (&grandchild);
|
if (G_UNLIKELY (errno != EEXIST))
|
||||||
grandchild = g_file_get_child (child, "heads");
|
{
|
||||||
if (!g_file_make_directory (grandchild, cancellable, error))
|
glnx_set_error_from_errno (error);
|
||||||
goto out;
|
return FALSE;
|
||||||
|
}
|
||||||
g_clear_object (&grandchild);
|
}
|
||||||
grandchild = g_file_get_child (child, "remotes");
|
}
|
||||||
if (!g_file_make_directory (grandchild, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
g_clear_object (&child);
|
|
||||||
child = g_file_get_child (self->repodir, "state");
|
|
||||||
if (!g_file_make_directory (child, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (!ostree_repo_open (self, cancellable, error))
|
if (!ostree_repo_open (self, cancellable, error))
|
||||||
goto out;
|
return FALSE;
|
||||||
|
|
||||||
ret = TRUE;
|
return TRUE;
|
||||||
|
|
||||||
out:
|
|
||||||
if (config_data)
|
|
||||||
g_string_free (config_data, TRUE);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
echo "1..57"
|
echo "1..58"
|
||||||
|
|
||||||
$OSTREE checkout test2 checkout-test2
|
$OSTREE checkout test2 checkout-test2
|
||||||
echo "ok checkout"
|
echo "ok checkout"
|
||||||
|
|
@ -41,6 +41,12 @@ echo "ok shortened checksum"
|
||||||
(cd repo && ${CMD_PREFIX} ostree rev-parse test2)
|
(cd repo && ${CMD_PREFIX} ostree rev-parse test2)
|
||||||
echo "ok repo-in-cwd"
|
echo "ok repo-in-cwd"
|
||||||
|
|
||||||
|
rm test-repo -rf
|
||||||
|
$OSTREE --repo=test-repo init --mode=bare-user
|
||||||
|
$OSTREE --repo=test-repo init --mode=bare-user
|
||||||
|
rm test-repo -rf
|
||||||
|
echo "ok repo-init on existing repo"
|
||||||
|
|
||||||
cd checkout-test2
|
cd checkout-test2
|
||||||
assert_has_file firstfile
|
assert_has_file firstfile
|
||||||
assert_has_file baz/cow
|
assert_has_file baz/cow
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue