mirror of
https://github.com/ostreedev/ostree.git
synced 2025-01-11 09:18:20 +03:00
core: Allow specifying a previous commit tree as a basis for a new commit
It's pretty trivial to map a previously existing commit tree into a mutable tree too. While we're here change the command line arguments for commit so that we can now properly overlay any combination of directory, commit, or tarfile.
This commit is contained in:
parent
c8377c7c5c
commit
add55849ab
@ -28,6 +28,7 @@ struct _OstreeMutableTree
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
char *contents_checksum;
|
||||
char *metadata_checksum;
|
||||
|
||||
GHashTable *files;
|
||||
@ -43,6 +44,7 @@ ostree_mutable_tree_finalize (GObject *object)
|
||||
|
||||
self = OSTREE_MUTABLE_TREE (object);
|
||||
|
||||
g_free (self->contents_checksum);
|
||||
g_free (self->metadata_checksum);
|
||||
|
||||
g_hash_table_destroy (self->files);
|
||||
@ -82,6 +84,20 @@ ostree_mutable_tree_get_metadata_checksum (OstreeMutableTree *self)
|
||||
return self->metadata_checksum;
|
||||
}
|
||||
|
||||
void
|
||||
ostree_mutable_tree_set_contents_checksum (OstreeMutableTree *self,
|
||||
const char *checksum)
|
||||
{
|
||||
g_free (self->contents_checksum);
|
||||
self->contents_checksum = g_strdup (checksum);
|
||||
}
|
||||
|
||||
const char *
|
||||
ostree_mutable_tree_get_contents_checksum (OstreeMutableTree *self)
|
||||
{
|
||||
return self->contents_checksum;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
set_error_noent (GError **error, const char *path)
|
||||
{
|
||||
|
@ -56,6 +56,11 @@ void ostree_mutable_tree_set_metadata_checksum (OstreeMutableTree *self,
|
||||
|
||||
const char *ostree_mutable_tree_get_metadata_checksum (OstreeMutableTree *self);
|
||||
|
||||
void ostree_mutable_tree_set_contents_checksum (OstreeMutableTree *self,
|
||||
const char *checksum);
|
||||
|
||||
const char *ostree_mutable_tree_get_contents_checksum (OstreeMutableTree *self);
|
||||
|
||||
gboolean ostree_mutable_tree_replace_file (OstreeMutableTree *self,
|
||||
const char *name,
|
||||
const char *checksum,
|
||||
|
@ -1370,6 +1370,7 @@ ostree_repo_stage_directory_to_mtree (OstreeRepo *self,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
OstreeRepoFile *repo_dir = NULL;
|
||||
GError *temp_error = NULL;
|
||||
GFileInfo *child_info = NULL;
|
||||
OstreeMutableTree *child_mtree = NULL;
|
||||
@ -1380,26 +1381,38 @@ ostree_repo_stage_directory_to_mtree (OstreeRepo *self,
|
||||
GVariant *xattrs = NULL;
|
||||
GInputStream *file_input = NULL;
|
||||
|
||||
child_info = g_file_query_info (dir, OSTREE_GIO_FAST_QUERYINFO,
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
cancellable, error);
|
||||
if (!child_info)
|
||||
goto out;
|
||||
/* We can only reuse checksums directly if there's no modifier */
|
||||
if (OSTREE_IS_REPO_FILE (dir) && modifier == NULL)
|
||||
repo_dir = (OstreeRepoFile*)dir;
|
||||
|
||||
modified_info = create_modified_file_info (child_info, modifier);
|
||||
if (repo_dir)
|
||||
{
|
||||
ostree_mutable_tree_set_metadata_checksum (mtree, ostree_repo_file_get_checksum (repo_dir));
|
||||
ostree_mutable_tree_set_contents_checksum (mtree, ostree_repo_file_tree_get_content_checksum (repo_dir));
|
||||
}
|
||||
else
|
||||
{
|
||||
child_info = g_file_query_info (dir, OSTREE_GIO_FAST_QUERYINFO,
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
cancellable, error);
|
||||
if (!child_info)
|
||||
goto out;
|
||||
|
||||
modified_info = create_modified_file_info (child_info, modifier);
|
||||
|
||||
xattrs = ostree_get_xattrs_for_file (dir, error);
|
||||
if (!xattrs)
|
||||
goto out;
|
||||
|
||||
if (!stage_directory_meta (self, modified_info, xattrs, &child_file_checksum,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
ostree_mutable_tree_set_metadata_checksum (mtree, g_checksum_get_string (child_file_checksum));
|
||||
|
||||
xattrs = ostree_get_xattrs_for_file (dir, error);
|
||||
if (!xattrs)
|
||||
goto out;
|
||||
|
||||
if (!stage_directory_meta (self, modified_info, xattrs, &child_file_checksum,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
ostree_mutable_tree_set_metadata_checksum (mtree, g_checksum_get_string (child_file_checksum));
|
||||
|
||||
g_clear_object (&child_info);
|
||||
g_clear_object (&modified_info);
|
||||
g_clear_object (&child_info);
|
||||
g_clear_object (&modified_info);
|
||||
}
|
||||
|
||||
dir_enum = g_file_enumerate_children ((GFile*)dir, OSTREE_GIO_FAST_QUERYINFO,
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
@ -1428,6 +1441,13 @@ ostree_repo_stage_directory_to_mtree (OstreeRepo *self,
|
||||
modifier, cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
else if (repo_dir)
|
||||
{
|
||||
if (!ostree_mutable_tree_replace_file (mtree, name,
|
||||
ostree_repo_file_get_checksum ((OstreeRepoFile*) child),
|
||||
error))
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
ot_clear_checksum (&child_file_checksum);
|
||||
@ -1568,43 +1588,50 @@ ostree_repo_stage_mtree (OstreeRepo *self,
|
||||
gboolean ret = FALSE;
|
||||
GChecksum *ret_contents_checksum_obj = NULL;
|
||||
char *ret_contents_checksum = NULL;
|
||||
GHashTable *dir_metadata_checksums;
|
||||
GHashTable *dir_contents_checksums;
|
||||
GHashTable *dir_metadata_checksums = NULL;
|
||||
GHashTable *dir_contents_checksums = NULL;
|
||||
GVariant *serialized_tree = NULL;
|
||||
GHashTableIter hash_iter;
|
||||
gpointer key, value;
|
||||
|
||||
dir_contents_checksums = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
(GDestroyNotify)g_free, (GDestroyNotify)g_free);
|
||||
dir_metadata_checksums = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
(GDestroyNotify)g_free, (GDestroyNotify)g_free);
|
||||
|
||||
g_hash_table_iter_init (&hash_iter, ostree_mutable_tree_get_subdirs (mtree));
|
||||
while (g_hash_table_iter_next (&hash_iter, &key, &value))
|
||||
if (ostree_mutable_tree_get_contents_checksum (mtree))
|
||||
{
|
||||
const char *name = key;
|
||||
OstreeMutableTree *child_dir = value;
|
||||
char *child_dir_contents_checksum;
|
||||
|
||||
if (!ostree_repo_stage_mtree (self, child_dir, &child_dir_contents_checksum,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
g_hash_table_replace (dir_contents_checksums, g_strdup (name),
|
||||
child_dir_contents_checksum); /* Transfer ownership */
|
||||
g_hash_table_replace (dir_metadata_checksums, g_strdup (name),
|
||||
g_strdup (ostree_mutable_tree_get_metadata_checksum (child_dir)));
|
||||
ret_contents_checksum = g_strdup (ostree_mutable_tree_get_contents_checksum (mtree));
|
||||
}
|
||||
|
||||
serialized_tree = create_tree_variant_from_hashes (ostree_mutable_tree_get_files (mtree),
|
||||
dir_contents_checksums,
|
||||
dir_metadata_checksums);
|
||||
else
|
||||
{
|
||||
dir_contents_checksums = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
(GDestroyNotify)g_free, (GDestroyNotify)g_free);
|
||||
dir_metadata_checksums = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
(GDestroyNotify)g_free, (GDestroyNotify)g_free);
|
||||
|
||||
if (!stage_gvariant_object (self, OSTREE_OBJECT_TYPE_DIR_TREE,
|
||||
serialized_tree, &ret_contents_checksum_obj,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
ret_contents_checksum = g_strdup (g_checksum_get_string (ret_contents_checksum_obj));
|
||||
g_hash_table_iter_init (&hash_iter, ostree_mutable_tree_get_subdirs (mtree));
|
||||
while (g_hash_table_iter_next (&hash_iter, &key, &value))
|
||||
{
|
||||
const char *name = key;
|
||||
OstreeMutableTree *child_dir = value;
|
||||
char *child_dir_contents_checksum;
|
||||
|
||||
if (!ostree_repo_stage_mtree (self, child_dir, &child_dir_contents_checksum,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
g_hash_table_replace (dir_contents_checksums, g_strdup (name),
|
||||
child_dir_contents_checksum); /* Transfer ownership */
|
||||
g_hash_table_replace (dir_metadata_checksums, g_strdup (name),
|
||||
g_strdup (ostree_mutable_tree_get_metadata_checksum (child_dir)));
|
||||
}
|
||||
|
||||
serialized_tree = create_tree_variant_from_hashes (ostree_mutable_tree_get_files (mtree),
|
||||
dir_contents_checksums,
|
||||
dir_metadata_checksums);
|
||||
|
||||
if (!stage_gvariant_object (self, OSTREE_OBJECT_TYPE_DIR_TREE,
|
||||
serialized_tree, &ret_contents_checksum_obj,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
ret_contents_checksum = g_strdup (g_checksum_get_string (ret_contents_checksum_obj));
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
ot_transfer_out_value(out_contents_checksum, &ret_contents_checksum);
|
||||
|
@ -35,7 +35,7 @@ static char *subject;
|
||||
static char *body;
|
||||
static char *parent;
|
||||
static char *branch;
|
||||
static gboolean tar;
|
||||
static char **trees;
|
||||
static gint owner_uid = -1;
|
||||
static gint owner_gid = -1;
|
||||
|
||||
@ -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" },
|
||||
{ "branch", 'b', 0, G_OPTION_ARG_STRING, &branch, "Branch", "branch" },
|
||||
{ "parent", 'p', 0, G_OPTION_ARG_STRING, &parent, "Parent commit", "commit" },
|
||||
{ "tar", 0, 0, G_OPTION_ARG_NONE, &tar, "Given arguments are tar files", NULL },
|
||||
{ "tree", 0, 0, G_OPTION_ARG_STRING_ARRAY, &trees, "Overlay the given argument as a tree", "NAME" },
|
||||
{ "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" },
|
||||
{ NULL }
|
||||
@ -68,7 +68,7 @@ ostree_builtin_commit (int argc, char **argv, const char *repo_path, GError **er
|
||||
char *contents_checksum = NULL;
|
||||
GCancellable *cancellable = NULL;
|
||||
OstreeMutableTree *mtree = NULL;
|
||||
int i;
|
||||
char *tree_type = NULL;
|
||||
|
||||
context = g_option_context_new ("[ARG] - Commit a new revision");
|
||||
g_option_context_add_main_entries (context, options, NULL);
|
||||
@ -133,7 +133,7 @@ ostree_builtin_commit (int argc, char **argv, const char *repo_path, GError **er
|
||||
|
||||
mtree = ostree_mutable_tree_new ();
|
||||
|
||||
if (argc == 1)
|
||||
if (argc == 1 && (trees == NULL || trees[0] == NULL))
|
||||
{
|
||||
char *current_dir = g_get_current_dir ();
|
||||
arg = ot_gfile_new_for_path (current_dir);
|
||||
@ -145,22 +145,55 @@ ostree_builtin_commit (int argc, char **argv, const char *repo_path, GError **er
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 1; i < argc; i++)
|
||||
const char *const*tree_iter;
|
||||
const char *tree;
|
||||
const char *eq;
|
||||
|
||||
for (tree_iter = (const char *const*)trees; *tree_iter; tree_iter++)
|
||||
{
|
||||
g_clear_object (&arg);
|
||||
arg = ot_gfile_new_for_path (argv[i]);
|
||||
if (tar)
|
||||
tree = *tree_iter;
|
||||
|
||||
eq = strchr (tree, '=');
|
||||
if (!eq)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Missing type in tree specification '%s'", tree);
|
||||
goto out;
|
||||
}
|
||||
g_free (tree_type);
|
||||
tree_type = g_strndup (tree, eq - tree);
|
||||
tree = eq + 1;
|
||||
|
||||
g_clear_object (&arg);
|
||||
if (strcmp (tree_type, "dir") == 0)
|
||||
{
|
||||
arg = ot_gfile_new_for_path (tree);
|
||||
if (!ostree_repo_stage_directory_to_mtree (repo, arg, mtree, modifier,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
else if (strcmp (tree_type, "tar") == 0)
|
||||
{
|
||||
arg = ot_gfile_new_for_path (tree);
|
||||
if (!ostree_repo_stage_archive_to_mtree (repo, arg, mtree, modifier,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
else if (strcmp (tree_type, "ref") == 0)
|
||||
{
|
||||
if (!ostree_repo_read_commit (repo, tree, &arg, cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (!ostree_repo_stage_directory_to_mtree (repo, arg, mtree, modifier,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Invalid tree type specification '%s'", tree_type);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,6 +218,7 @@ ostree_builtin_commit (int argc, char **argv, const char *repo_path, GError **er
|
||||
g_clear_object (&mtree);
|
||||
g_free (contents_checksum);
|
||||
g_free (parent);
|
||||
g_free (tree_type);
|
||||
if (metadata_mappedf)
|
||||
g_mapped_file_unref (metadata_mappedf);
|
||||
if (context)
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
set -e
|
||||
|
||||
echo "1..18"
|
||||
echo "1..19"
|
||||
|
||||
. libtest.sh
|
||||
|
||||
@ -151,3 +151,6 @@ echo "ok local clone checkout"
|
||||
|
||||
$OSTREE checkout -U test2 checkout-user-test2
|
||||
echo "ok user checkout"
|
||||
|
||||
$OSTREE commit -b test2 -s "Another commit" --tree=ref=test2
|
||||
echo "ok commit from ref"
|
||||
|
@ -39,7 +39,7 @@ echo not > subdir/2/notempty
|
||||
|
||||
tar -c -z -f ../foo.tar.gz .
|
||||
cd ..
|
||||
$OSTREE commit -s "from tar" -b test-tar --tar foo.tar.gz
|
||||
$OSTREE commit -s "from tar" -b test-tar --tree=tar=foo.tar.gz
|
||||
echo "ok tar commit"
|
||||
|
||||
cd ${test_tmpdir}
|
||||
@ -62,7 +62,7 @@ echo foo1 > foo
|
||||
ln foo bar
|
||||
tar czf ${test_tmpdir}/hardlinktest.tar.gz .
|
||||
cd ${test_tmpdir}
|
||||
$OSTREE commit -s 'hardlinks' -b test-hardlinks --tar hardlinktest.tar.gz
|
||||
$OSTREE commit -s 'hardlinks' -b test-hardlinks --tree=tar=hardlinktest.tar.gz
|
||||
rm -rf hardlinktest
|
||||
echo "ok hardlink commit"
|
||||
|
||||
@ -89,7 +89,7 @@ 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
|
||||
$OSTREE commit -s 'multi tar' -b multicommit --tree=tar=files1.tar.gz --tree=tar=files2.tar.gz
|
||||
echo "ok tar multicommit"
|
||||
|
||||
cd ${test_tmpdir}
|
||||
|
Loading…
Reference in New Issue
Block a user