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:
Colin Walters 2011-12-21 20:10:10 -05:00
parent c8377c7c5c
commit add55849ab
6 changed files with 146 additions and 61 deletions

View File

@ -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)
{

View File

@ -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,

View File

@ -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);

View File

@ -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)

View File

@ -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"

View File

@ -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}