[ostree] core: Support committing multiple tarballs in the same transaction



commit bdfde03b61a0df53e0a6d2e45d9e0632528f28b7
Author: Colin Walters <walters verbum org>
Date:   Tue Dec 20 17:21:15 2011 -0500

    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.

 src/libostree/ostree-repo.c    |   94 +++++++++++++++++----------------------
 src/libostree/ostree-repo.h    |   22 +++++-----
 src/ostree/ot-builtin-commit.c |   15 +++++-
 tests/t0006-libarchive.sh      |   30 ++++++++++++-
 4 files changed, 93 insertions(+), 68 deletions(-)
---
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index 575c0e7..dffc162 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -1773,24 +1773,19 @@ file_tree_import_recurse (OstreeRepo           *self,
   return ret;
 }
                           
-
 static gboolean
-import_libarchive (OstreeRepo           *self,
-                   GFile                *archive_f,
-                   OstreeRepoCommitModifier *modifier,
-                   char                **out_contents_checksum,
-                   char                **out_metadata_checksum,
-                   GCancellable         *cancellable,
-                   GError              **error)
+stage_libarchive_into_root (OstreeRepo           *self,
+                            FileTree             *root,
+                            GFile                *archive_f,
+                            OstreeRepoCommitModifier *modifier,
+                            GCancellable         *cancellable,
+                            GError              **error)
 {
   gboolean ret = FALSE;
   int r;
-  char *ret_contents_checksum = NULL;
-  char *ret_metadata_checksum = NULL;
   struct archive *a;
   struct archive_entry *entry;
   GFileInfo *file_info = NULL;
-  FileTree *root = NULL;
   GChecksum *tmp_checksum = NULL;
   GPtrArray *split_path = NULL;
   GPtrArray *hardlink_split_path = NULL;
@@ -1804,8 +1799,6 @@ import_libarchive (OstreeRepo           *self,
       goto out;
     }
 
-  root = file_tree_new ();
-
   while (TRUE)
     {
       const char *pathname;
@@ -1922,31 +1915,24 @@ import_libarchive (OstreeRepo           *self,
           if (parent == NULL)
             {
               dir = root;
-              if (root->metadata_checksum)
-                {
-                  g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                               "Directory exists: %s", pathname);
-                  goto out;
-                }
             }
           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))
                 {
                   g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                                "Can't replace file with directory: %s", pathname);
                   goto out;
                 }
-              dir = file_tree_new ();
-              g_assert (basename);
-              g_hash_table_insert (parent->subdirs, g_strdup (basename), dir);
+              /* Allow duplicate directories */
+              if (!g_hash_table_lookup (parent->subdirs, basename))
+                {
+                  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));
         }
       else 
@@ -1979,44 +1965,35 @@ import_libarchive (OstreeRepo           *self,
       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;
-  ot_transfer_out_value(out_contents_checksum, &ret_contents_checksum);
-  ot_transfer_out_value(out_metadata_checksum, &ret_metadata_checksum);
  out:
-  if (root)
-    file_tree_free (root);
   g_clear_object (&file_info);
-  g_free (ret_contents_checksum);
-  g_free (ret_metadata_checksum);
   ot_clear_checksum (&tmp_checksum);
   return ret;
 }
 #endif
   
 gboolean      
-ostree_repo_commit_tarfile (OstreeRepo *self,
-                            const char   *branch,
-                            const char   *parent,
-                            const char   *subject,
-                            const char   *body,
-                            GVariant     *metadata,
-                            GFile        *path,
-                            OstreeRepoCommitModifier *modifier,
-                            GChecksum   **out_commit,
-                            GCancellable *cancellable,
-                            GError      **error)
+ostree_repo_commit_tarfiles (OstreeRepo *self,
+                             const char   *branch,
+                             const char   *parent,
+                             const char   *subject,
+                             const char   *body,
+                             GVariant     *metadata,
+                             GPtrArray    *tarfiles,
+                             OstreeRepoCommitModifier *modifier,
+                             GChecksum   **out_commit,
+                             GCancellable *cancellable,
+                             GError      **error)
 {
 #ifdef HAVE_LIBARCHIVE
   OstreeRepoPrivate *priv = GET_PRIVATE (self);
   gboolean ret = FALSE;
   GChecksum *ret_commit_checksum = NULL;
+  FileTree *root = NULL;
   char *root_contents_checksum = NULL;
-  char *root_metadata_checksum = NULL;
   char *current_head = NULL;
+  int i;
 
   g_return_val_if_fail (error == NULL || *error == NULL, 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, &current_head, error))
     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;
 
   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))
     goto out;
   
@@ -2047,8 +2034,9 @@ ostree_repo_commit_tarfile (OstreeRepo *self,
  out:
   ot_clear_checksum (&ret_commit_checksum);
   g_free (current_head);
-  g_free (root_metadata_checksum);
   g_free (root_contents_checksum);
+  if (root)
+    file_tree_free (root);
   return ret;
 #else
   g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h
index 0222a62..c87aa7b 100644
--- a/src/libostree/ostree-repo.h
+++ b/src/libostree/ostree-repo.h
@@ -154,17 +154,17 @@ gboolean      ostree_repo_commit_directory (OstreeRepo   *self,
                                             GCancellable *cancellable,
                                             GError      **error);
 
-gboolean      ostree_repo_commit_tarfile (OstreeRepo   *self,
-                                          const char   *branch,
-                                          const char   *parent,
-                                          const char   *subject,
-                                          const char   *body,
-                                          GVariant     *metadata,
-                                          GFile        *base,
-                                          OstreeRepoCommitModifier *modifier,
-                                          GChecksum   **out_commit,
-                                          GCancellable *cancellable,
-                                          GError      **error);
+gboolean      ostree_repo_commit_tarfiles (OstreeRepo   *self,
+                                           const char   *branch,
+                                           const char   *parent,
+                                           const char   *subject,
+                                           const char   *body,
+                                           GVariant     *metadata,
+                                           GPtrArray    *tarfiles,
+                                           OstreeRepoCommitModifier *modifier,
+                                           GChecksum   **out_commit,
+                                           GCancellable *cancellable,
+                                           GError      **error);
 
 typedef enum {
   OSTREE_REPO_CHECKOUT_MODE_NONE,
diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c
index 61f62c6..0147eb0 100644
--- a/src/ostree/ot-builtin-commit.c
+++ b/src/ostree/ot-builtin-commit.c
@@ -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 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-gid", 0, 0, G_OPTION_ARG_INT, &owner_gid, "Set file ownership group id", "GID" },
   { NULL }
@@ -60,11 +60,13 @@ ostree_builtin_commit (int argc, char **argv, const char *repo_path, GError **er
   OstreeRepo *repo = NULL;
   char *argpath = NULL;
   GFile *arg = NULL;
+  GPtrArray *tar_files = NULL;
   GChecksum *commit_checksum = NULL;
   GVariant *metadata = NULL;
   GMappedFile *metadata_mappedf = NULL;
   GFile *metadata_f = NULL;
   OstreeRepoCommitModifier *modifier = NULL;
+  int i;
 
   context = g_option_context_new ("[ARG] - Commit a new revision");
   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
     {
-      if (!ostree_repo_commit_tarfile (repo, branch, parent, subject, body, metadata,
-                                       arg, modifier, &commit_checksum, NULL, error))
+      tar_files = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
+      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;
     }
 
@@ -156,6 +163,8 @@ ostree_builtin_commit (int argc, char **argv, const char *repo_path, GError **er
  out:
   g_free (argpath);
   g_clear_object (&arg);
+  if (tar_files)
+    g_ptr_array_unref (tar_files);
   if (metadata_mappedf)
     g_mapped_file_unref (metadata_mappedf);
   if (context)
diff --git a/tests/t0006-libarchive.sh b/tests/t0006-libarchive.sh
index 76bcd88..7094c22 100755
--- a/tests/t0006-libarchive.sh
+++ b/tests/t0006-libarchive.sh
@@ -19,7 +19,7 @@
 
 set -e
 
-echo "1..4"
+echo "1..6"
 
 . libtest.sh
 
@@ -72,3 +72,31 @@ cd test-hardlinks-checkout
 assert_file_has_content foo foo1
 assert_file_has_content bar foo1
 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"



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