[ostree] core: Allow specifying a previous commit tree as a basis for a new commit



commit add55849abf4f9f18442beebe0067aa50b55aa7f
Author: Colin Walters <walters verbum org>
Date:   Wed Dec 21 20:10:10 2011 -0500

    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.

 src/libostree/ostree-mutable-tree.c |   16 +++++
 src/libostree/ostree-mutable-tree.h |    5 ++
 src/libostree/ostree-repo.c         |  119 +++++++++++++++++++++-------------
 src/ostree/ot-builtin-commit.c      |   50 ++++++++++++---
 tests/t0000-basic.sh                |    5 +-
 tests/t0006-libarchive.sh           |    6 +-
 6 files changed, 143 insertions(+), 58 deletions(-)
---
diff --git a/src/libostree/ostree-mutable-tree.c b/src/libostree/ostree-mutable-tree.c
index 943ef31..1c698b9 100644
--- a/src/libostree/ostree-mutable-tree.c
+++ b/src/libostree/ostree-mutable-tree.c
@@ -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)
 {
diff --git a/src/libostree/ostree-mutable-tree.h b/src/libostree/ostree-mutable-tree.h
index 42e9e77..413da02 100644
--- a/src/libostree/ostree-mutable-tree.h
+++ b/src/libostree/ostree-mutable-tree.h
@@ -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,
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index 9070cd0..493c7bc 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -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;
-
-  modified_info = create_modified_file_info (child_info, modifier);
-
-  xattrs = ostree_get_xattrs_for_file (dir, error);
-  if (!xattrs)
-    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;
 
-  if (!stage_directory_meta (self, modified_info, xattrs, &child_file_checksum,
-                             cancellable, error))
-    goto out;
+  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));
 
-  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;
+      ret_contents_checksum = g_strdup (ostree_mutable_tree_get_contents_checksum (mtree));
+    }
+  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);
+      
+      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;
+          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)));
-    }
+          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);
+      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));
+      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);
diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c
index cdaf10b..d84a77a 100644
--- a/src/ostree/ot-builtin-commit.c
+++ b/src/ostree/ot-builtin-commit.c
@@ -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++)
         {
+          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);
-          arg = ot_gfile_new_for_path (argv[i]);
-          if (tar)
+          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)
diff --git a/tests/t0000-basic.sh b/tests/t0000-basic.sh
index e73631b..3ef89d2 100755
--- a/tests/t0000-basic.sh
+++ b/tests/t0000-basic.sh
@@ -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"
diff --git a/tests/t0006-libarchive.sh b/tests/t0006-libarchive.sh
index 7094c22..4173c97 100755
--- a/tests/t0006-libarchive.sh
+++ b/tests/t0006-libarchive.sh
@@ -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}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]