core: Support committing multiple tarballs in the same transaction
ostbuild will generate two artifacts: foo-runtime.tar.gz and foo-devel.tar.gz in the general case. When committing to the devel tree, it'd be lame (i.e. slower and not atomic) to have to commit twice.
This commit is contained in:
parent
d444ee917d
commit
bdfde03b61
|
|
@ -1773,24 +1773,19 @@ file_tree_import_recurse (OstreeRepo *self,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
import_libarchive (OstreeRepo *self,
|
stage_libarchive_into_root (OstreeRepo *self,
|
||||||
GFile *archive_f,
|
FileTree *root,
|
||||||
OstreeRepoCommitModifier *modifier,
|
GFile *archive_f,
|
||||||
char **out_contents_checksum,
|
OstreeRepoCommitModifier *modifier,
|
||||||
char **out_metadata_checksum,
|
GCancellable *cancellable,
|
||||||
GCancellable *cancellable,
|
GError **error)
|
||||||
GError **error)
|
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
int r;
|
int r;
|
||||||
char *ret_contents_checksum = NULL;
|
|
||||||
char *ret_metadata_checksum = NULL;
|
|
||||||
struct archive *a;
|
struct archive *a;
|
||||||
struct archive_entry *entry;
|
struct archive_entry *entry;
|
||||||
GFileInfo *file_info = NULL;
|
GFileInfo *file_info = NULL;
|
||||||
FileTree *root = NULL;
|
|
||||||
GChecksum *tmp_checksum = NULL;
|
GChecksum *tmp_checksum = NULL;
|
||||||
GPtrArray *split_path = NULL;
|
GPtrArray *split_path = NULL;
|
||||||
GPtrArray *hardlink_split_path = NULL;
|
GPtrArray *hardlink_split_path = NULL;
|
||||||
|
|
@ -1804,8 +1799,6 @@ import_libarchive (OstreeRepo *self,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
root = file_tree_new ();
|
|
||||||
|
|
||||||
while (TRUE)
|
while (TRUE)
|
||||||
{
|
{
|
||||||
const char *pathname;
|
const char *pathname;
|
||||||
|
|
@ -1922,31 +1915,24 @@ import_libarchive (OstreeRepo *self,
|
||||||
if (parent == NULL)
|
if (parent == NULL)
|
||||||
{
|
{
|
||||||
dir = root;
|
dir = root;
|
||||||
if (root->metadata_checksum)
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"Directory exists: %s", pathname);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (g_hash_table_lookup (parent->subdirs, basename))
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"Directory exists: %s", pathname);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (g_hash_table_lookup (parent->file_checksums, basename))
|
if (g_hash_table_lookup (parent->file_checksums, basename))
|
||||||
{
|
{
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
"Can't replace file with directory: %s", pathname);
|
"Can't replace file with directory: %s", pathname);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
dir = file_tree_new ();
|
/* Allow duplicate directories */
|
||||||
g_assert (basename);
|
if (!g_hash_table_lookup (parent->subdirs, basename))
|
||||||
g_hash_table_insert (parent->subdirs, g_strdup (basename), dir);
|
{
|
||||||
|
dir = file_tree_new ();
|
||||||
|
g_assert (basename);
|
||||||
|
g_hash_table_replace (parent->subdirs, g_strdup (basename), dir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
g_free (dir->metadata_checksum);
|
||||||
dir->metadata_checksum = g_strdup (g_checksum_get_string (tmp_checksum));
|
dir->metadata_checksum = g_strdup (g_checksum_get_string (tmp_checksum));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -1979,44 +1965,35 @@ import_libarchive (OstreeRepo *self,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!file_tree_import_recurse (self, root, &ret_contents_checksum, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
ret_metadata_checksum = g_strdup (root->metadata_checksum);
|
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
ot_transfer_out_value(out_contents_checksum, &ret_contents_checksum);
|
|
||||||
ot_transfer_out_value(out_metadata_checksum, &ret_metadata_checksum);
|
|
||||||
out:
|
out:
|
||||||
if (root)
|
|
||||||
file_tree_free (root);
|
|
||||||
g_clear_object (&file_info);
|
g_clear_object (&file_info);
|
||||||
g_free (ret_contents_checksum);
|
|
||||||
g_free (ret_metadata_checksum);
|
|
||||||
ot_clear_checksum (&tmp_checksum);
|
ot_clear_checksum (&tmp_checksum);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
ostree_repo_commit_tarfile (OstreeRepo *self,
|
ostree_repo_commit_tarfiles (OstreeRepo *self,
|
||||||
const char *branch,
|
const char *branch,
|
||||||
const char *parent,
|
const char *parent,
|
||||||
const char *subject,
|
const char *subject,
|
||||||
const char *body,
|
const char *body,
|
||||||
GVariant *metadata,
|
GVariant *metadata,
|
||||||
GFile *path,
|
GPtrArray *tarfiles,
|
||||||
OstreeRepoCommitModifier *modifier,
|
OstreeRepoCommitModifier *modifier,
|
||||||
GChecksum **out_commit,
|
GChecksum **out_commit,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_LIBARCHIVE
|
#ifdef HAVE_LIBARCHIVE
|
||||||
OstreeRepoPrivate *priv = GET_PRIVATE (self);
|
OstreeRepoPrivate *priv = GET_PRIVATE (self);
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
GChecksum *ret_commit_checksum = NULL;
|
GChecksum *ret_commit_checksum = NULL;
|
||||||
|
FileTree *root = NULL;
|
||||||
char *root_contents_checksum = NULL;
|
char *root_contents_checksum = NULL;
|
||||||
char *root_metadata_checksum = NULL;
|
|
||||||
char *current_head = NULL;
|
char *current_head = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||||
g_return_val_if_fail (priv->inited, FALSE);
|
g_return_val_if_fail (priv->inited, FALSE);
|
||||||
|
|
@ -2033,11 +2010,21 @@ ostree_repo_commit_tarfile (OstreeRepo *self,
|
||||||
if (!ostree_repo_resolve_rev (self, parent, TRUE, ¤t_head, error))
|
if (!ostree_repo_resolve_rev (self, parent, TRUE, ¤t_head, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!import_libarchive (self, path, modifier, &root_contents_checksum, &root_metadata_checksum, cancellable, error))
|
root = file_tree_new ();
|
||||||
|
|
||||||
|
for (i = 0; i < tarfiles->len; i++)
|
||||||
|
{
|
||||||
|
GFile *archive_f = tarfiles->pdata[i];
|
||||||
|
|
||||||
|
if (!stage_libarchive_into_root (self, root, archive_f, modifier, cancellable, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file_tree_import_recurse (self, root, &root_contents_checksum, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!do_commit_write_ref (self, branch, current_head, subject, body, metadata,
|
if (!do_commit_write_ref (self, branch, current_head, subject, body, metadata,
|
||||||
root_contents_checksum, root_metadata_checksum, &ret_commit_checksum,
|
root_contents_checksum, root->metadata_checksum, &ret_commit_checksum,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
@ -2047,8 +2034,9 @@ ostree_repo_commit_tarfile (OstreeRepo *self,
|
||||||
out:
|
out:
|
||||||
ot_clear_checksum (&ret_commit_checksum);
|
ot_clear_checksum (&ret_commit_checksum);
|
||||||
g_free (current_head);
|
g_free (current_head);
|
||||||
g_free (root_metadata_checksum);
|
|
||||||
g_free (root_contents_checksum);
|
g_free (root_contents_checksum);
|
||||||
|
if (root)
|
||||||
|
file_tree_free (root);
|
||||||
return ret;
|
return ret;
|
||||||
#else
|
#else
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||||
|
|
|
||||||
|
|
@ -154,17 +154,17 @@ gboolean ostree_repo_commit_directory (OstreeRepo *self,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
gboolean ostree_repo_commit_tarfile (OstreeRepo *self,
|
gboolean ostree_repo_commit_tarfiles (OstreeRepo *self,
|
||||||
const char *branch,
|
const char *branch,
|
||||||
const char *parent,
|
const char *parent,
|
||||||
const char *subject,
|
const char *subject,
|
||||||
const char *body,
|
const char *body,
|
||||||
GVariant *metadata,
|
GVariant *metadata,
|
||||||
GFile *base,
|
GPtrArray *tarfiles,
|
||||||
OstreeRepoCommitModifier *modifier,
|
OstreeRepoCommitModifier *modifier,
|
||||||
GChecksum **out_commit,
|
GChecksum **out_commit,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
OSTREE_REPO_CHECKOUT_MODE_NONE,
|
OSTREE_REPO_CHECKOUT_MODE_NONE,
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ static GOptionEntry options[] = {
|
||||||
{ "metadata-variant", 0, 0, G_OPTION_ARG_FILENAME, &metadata_bin_path, "File containing serialized variant, in host endianness", "path" },
|
{ "metadata-variant", 0, 0, G_OPTION_ARG_FILENAME, &metadata_bin_path, "File containing serialized variant, in host endianness", "path" },
|
||||||
{ "branch", 'b', 0, G_OPTION_ARG_STRING, &branch, "Branch", "branch" },
|
{ "branch", 'b', 0, G_OPTION_ARG_STRING, &branch, "Branch", "branch" },
|
||||||
{ "parent", 'p', 0, G_OPTION_ARG_STRING, &parent, "Parent commit", "commit" },
|
{ "parent", 'p', 0, G_OPTION_ARG_STRING, &parent, "Parent commit", "commit" },
|
||||||
{ "tar", 0, 0, G_OPTION_ARG_NONE, &tar, "Given argument is a tar file", NULL },
|
{ "tar", 0, 0, G_OPTION_ARG_NONE, &tar, "Given arguments are tar files", NULL },
|
||||||
{ "owner-uid", 0, 0, G_OPTION_ARG_INT, &owner_uid, "Set file ownership user id", "UID" },
|
{ "owner-uid", 0, 0, G_OPTION_ARG_INT, &owner_uid, "Set file ownership user id", "UID" },
|
||||||
{ "owner-gid", 0, 0, G_OPTION_ARG_INT, &owner_gid, "Set file ownership group id", "GID" },
|
{ "owner-gid", 0, 0, G_OPTION_ARG_INT, &owner_gid, "Set file ownership group id", "GID" },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
|
|
@ -60,11 +60,13 @@ ostree_builtin_commit (int argc, char **argv, const char *repo_path, GError **er
|
||||||
OstreeRepo *repo = NULL;
|
OstreeRepo *repo = NULL;
|
||||||
char *argpath = NULL;
|
char *argpath = NULL;
|
||||||
GFile *arg = NULL;
|
GFile *arg = NULL;
|
||||||
|
GPtrArray *tar_files = NULL;
|
||||||
GChecksum *commit_checksum = NULL;
|
GChecksum *commit_checksum = NULL;
|
||||||
GVariant *metadata = NULL;
|
GVariant *metadata = NULL;
|
||||||
GMappedFile *metadata_mappedf = NULL;
|
GMappedFile *metadata_mappedf = NULL;
|
||||||
GFile *metadata_f = NULL;
|
GFile *metadata_f = NULL;
|
||||||
OstreeRepoCommitModifier *modifier = NULL;
|
OstreeRepoCommitModifier *modifier = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
context = g_option_context_new ("[ARG] - Commit a new revision");
|
context = g_option_context_new ("[ARG] - Commit a new revision");
|
||||||
g_option_context_add_main_entries (context, options, NULL);
|
g_option_context_add_main_entries (context, options, NULL);
|
||||||
|
|
@ -146,8 +148,13 @@ ostree_builtin_commit (int argc, char **argv, const char *repo_path, GError **er
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!ostree_repo_commit_tarfile (repo, branch, parent, subject, body, metadata,
|
tar_files = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
|
||||||
arg, modifier, &commit_checksum, NULL, error))
|
g_ptr_array_add (tar_files, g_object_ref (arg));
|
||||||
|
for (i = 2; i < argc; i++)
|
||||||
|
g_ptr_array_add (tar_files, ot_gfile_new_for_path (argv[i]));
|
||||||
|
|
||||||
|
if (!ostree_repo_commit_tarfiles (repo, branch, parent, subject, body, metadata,
|
||||||
|
tar_files, modifier, &commit_checksum, NULL, error))
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,6 +163,8 @@ ostree_builtin_commit (int argc, char **argv, const char *repo_path, GError **er
|
||||||
out:
|
out:
|
||||||
g_free (argpath);
|
g_free (argpath);
|
||||||
g_clear_object (&arg);
|
g_clear_object (&arg);
|
||||||
|
if (tar_files)
|
||||||
|
g_ptr_array_unref (tar_files);
|
||||||
if (metadata_mappedf)
|
if (metadata_mappedf)
|
||||||
g_mapped_file_unref (metadata_mappedf);
|
g_mapped_file_unref (metadata_mappedf);
|
||||||
if (context)
|
if (context)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
echo "1..4"
|
echo "1..6"
|
||||||
|
|
||||||
. libtest.sh
|
. libtest.sh
|
||||||
|
|
||||||
|
|
@ -72,3 +72,31 @@ cd test-hardlinks-checkout
|
||||||
assert_file_has_content foo foo1
|
assert_file_has_content foo foo1
|
||||||
assert_file_has_content bar foo1
|
assert_file_has_content bar foo1
|
||||||
echo "ok hardlink contents"
|
echo "ok hardlink contents"
|
||||||
|
|
||||||
|
cd ${test_tmpdir}
|
||||||
|
mkdir multicommit-files
|
||||||
|
cd multicommit-files
|
||||||
|
mkdir -p files1/subdir files2/subdir
|
||||||
|
echo "to be overwritten file" > files1/testfile
|
||||||
|
echo "not overwritten" > files1/otherfile
|
||||||
|
echo "overwriting file" > files2/testfile
|
||||||
|
ln -s "to-be-overwritten-symlink" files1/testsymlink
|
||||||
|
ln -s "overwriting-symlink" files2/testsymlink
|
||||||
|
ln -s "not overwriting symlink" files2/ohersymlink
|
||||||
|
echo "original" > files1/subdir/original
|
||||||
|
echo "new" > files2/subdir/new
|
||||||
|
|
||||||
|
tar -c -C files1 -z -f files1.tar.gz .
|
||||||
|
tar -c -C files2 -z -f files2.tar.gz .
|
||||||
|
|
||||||
|
$OSTREE commit -s 'multi tar' -b multicommit --tar files1.tar.gz files2.tar.gz
|
||||||
|
echo "ok tar multicommit"
|
||||||
|
|
||||||
|
cd ${test_tmpdir}
|
||||||
|
$OSTREE checkout multicommit multicommit-checkout
|
||||||
|
cd multicommit-checkout
|
||||||
|
assert_file_has_content testfile "overwriting file"
|
||||||
|
assert_file_has_content otherfile "not overwritten"
|
||||||
|
assert_file_has_content subdir/original "original"
|
||||||
|
assert_file_has_content subdir/new "new"
|
||||||
|
echo "ok tar multicommit contents"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue