[ostree/wip/packfile-rebase2: 6/11] core: Expose API to query all object status at once



commit 63f3a7afe0c7f7de202dddda82f374a0e1965824
Author: Colin Walters <walters verbum org>
Date:   Mon Mar 19 19:04:53 2012 -0400

    core: Expose API to query all object status at once
    
    This is more efficient in the end than an iteration API, and helps us
    allow differentiatiation between packed/loose objects.

 src/libostree/ostree-core.c         |   17 ++++
 src/libostree/ostree-core.h         |    7 ++
 src/libostree/ostree-repo.c         |  156 +++++++++++++++++++++++++----------
 src/libostree/ostree-repo.h         |   32 +++++---
 src/ostree/ot-builtin-fsck.c        |   64 ++++++++++-----
 src/ostree/ot-builtin-local-clone.c |   71 +++++++++++-----
 src/ostree/ot-builtin-prune.c       |   60 +++++++++++---
 src/ostree/ot-builtin-repack.c      |  154 +++++++++++++++++-----------------
 8 files changed, 376 insertions(+), 185 deletions(-)
---
diff --git a/src/libostree/ostree-core.c b/src/libostree/ostree-core.c
index 263988c..852adcb 100644
--- a/src/libostree/ostree-core.c
+++ b/src/libostree/ostree-core.c
@@ -584,6 +584,23 @@ ostree_object_from_string (const char *str,
   *out_objtype = ostree_object_type_from_string (dot + 1);
 }
 
+GVariant *
+ostree_object_name_serialize (const char *checksum,
+                              OstreeObjectType objtype)
+{
+  return g_variant_new ("(su)", checksum, (guint32)objtype);
+}
+
+void
+ostree_object_name_deserialize (GVariant         *variant,
+                                const char      **out_checksum,
+                                OstreeObjectType *out_objtype)
+{
+  guint32 objtype_u32;
+  g_variant_get (variant, "(&su)", out_checksum, &objtype_u32);
+  *out_objtype = (OstreeObjectType)objtype_u32;
+}
+
 char *
 ostree_get_relative_object_path (const char *checksum,
                                  OstreeObjectType type)
diff --git a/src/libostree/ostree-core.h b/src/libostree/ostree-core.h
index db4b6cd..398c4aa 100644
--- a/src/libostree/ostree-core.h
+++ b/src/libostree/ostree-core.h
@@ -144,6 +144,13 @@ const char * ostree_object_type_to_string (OstreeObjectType objtype);
 
 OstreeObjectType ostree_object_type_from_string (const char *str);
 
+GVariant *ostree_object_name_serialize (const char *checksum,
+                                        OstreeObjectType objtype);
+
+void ostree_object_name_deserialize (GVariant         *variant,
+                                     const char      **out_checksum,
+                                     OstreeObjectType *out_objtype);
+
 char * ostree_object_to_string (const char *checksum,
                                 OstreeObjectType objtype);
 
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index 4c99d88..83489e7 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -2294,43 +2294,54 @@ ostree_repo_commit_modifier_unref (OstreeRepoCommitModifier *modifier)
   return;
 }
 
+static guint
+hash_list_object_key (gconstpointer a)
+{
+  GVariant *variant = (gpointer)a;
+  const char *checksum;
+  OstreeObjectType objtype;
+  gint objtype_int;
+  
+  ostree_object_name_deserialize (variant, &checksum, &objtype);
+  objtype_int = (gint) objtype;
+  return g_str_hash (checksum) + g_int_hash (&objtype_int);
+}
 
 static gboolean
-iter_object_dir (OstreeRepo             *self,
-                 GFile                  *dir,
-                 OstreeRepoObjectIter    callback,
-                 gpointer                user_data,
-                 GError                **error)
+list_loose_object_dir (OstreeRepo             *self,
+                       GFile                  *dir,
+                       GHashTable             *inout_objects,
+                       GCancellable           *cancellable,
+                       GError                **error)
 {
   gboolean ret = FALSE;
   GError *temp_error = NULL;
   GFileEnumerator *enumerator = NULL;
   GFileInfo *file_info = NULL;
   const char *dirname = NULL;
+  char *dot = NULL;
+  GString *checksum = NULL;
 
   dirname = ot_gfile_get_basename_cached (dir);
 
   enumerator = g_file_enumerate_children (dir, OSTREE_GIO_FAST_QUERYINFO, 
                                           G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
-                                          NULL, 
+                                          cancellable, 
                                           error);
   if (!enumerator)
     goto out;
   
-  while ((file_info = g_file_enumerator_next_file (enumerator, NULL, &temp_error)) != NULL)
+  while ((file_info = g_file_enumerator_next_file (enumerator, cancellable, &temp_error)) != NULL)
     {
       const char *name;
       guint32 type;
-      char *dot = NULL;
-      GFile *child = NULL;
-      GString *checksum = NULL;
       OstreeObjectType objtype;
 
       name = g_file_info_get_attribute_byte_string (file_info, "standard::name"); 
       type = g_file_info_get_attribute_uint32 (file_info, "standard::type");
 
       if (type == G_FILE_TYPE_DIRECTORY)
-        goto loop_out;
+        goto loop_next;
       
       if (g_str_has_suffix (name, ".file"))
         objtype = OSTREE_OBJECT_TYPE_RAW_FILE;
@@ -2345,25 +2356,33 @@ iter_object_dir (OstreeRepo             *self,
       else if (g_str_has_suffix (name, ".commit"))
         objtype = OSTREE_OBJECT_TYPE_COMMIT;
       else
-        goto loop_out;
+        goto loop_next;
           
       dot = strrchr (name, '.');
       g_assert (dot);
 
-      if ((dot - name) != 62)
-        goto loop_out;
-      
-      checksum = g_string_new (dirname);
-      g_string_append_len (checksum, name, 62);
-      
-      child = g_file_get_child (dir, name);
-      callback (self, checksum->str, objtype, child, file_info, user_data);
-      
-    loop_out:
-      if (checksum)
-        g_string_free (checksum, TRUE);
+      if ((dot - name) == 62)
+        {
+          GVariant *key, *value;
+
+          if (checksum)
+            g_string_free (checksum, TRUE);
+          checksum = g_string_new (dirname);
+          g_string_append_len (checksum, name, 62);
+          
+          key = ostree_object_name_serialize (checksum->str, objtype);
+          value = g_variant_new ("(b astt)",
+                                 TRUE, g_variant_new_strv (NULL, 0),
+                                 g_file_info_get_attribute_uint64 (file_info,
+                                                                   G_FILE_ATTRIBUTE_TIME_CHANGED),
+                                 g_file_info_get_attribute_uint64 (file_info,
+                                                                   G_FILE_ATTRIBUTE_STANDARD_SIZE));
+          /* transfer ownership */
+          g_hash_table_replace (inout_objects, g_variant_ref_sink (key),
+                                g_variant_ref_sink (value));
+        }
+    loop_next:
       g_clear_object (&file_info);
-      g_clear_object (&child);
     }
   if (temp_error != NULL)
     {
@@ -2376,32 +2395,33 @@ iter_object_dir (OstreeRepo             *self,
   ret = TRUE;
  out:
   g_clear_object (&file_info);
+  g_clear_object (&enumerator);
+  if (checksum)
+    g_string_free (checksum, TRUE);
   return ret;
 }
 
-gboolean
-ostree_repo_iter_objects (OstreeRepo  *self,
-                          OstreeRepoObjectIter callback,
-                          gpointer       user_data,
-                          GError        **error)
+static gboolean
+list_loose_objects (OstreeRepo                     *self,
+                    GHashTable                     *inout_objects,
+                    GCancellable                   *cancellable,
+                    GError                        **error)
 {
+  gboolean ret = FALSE;
   OstreeRepoPrivate *priv = GET_PRIVATE (self);
   GFileEnumerator *enumerator = NULL;
-  gboolean ret = FALSE;
   GFileInfo *file_info = NULL;
   GError *temp_error = NULL;
-
-  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-  g_return_val_if_fail (priv->inited, FALSE);
+  GFile *objdir = NULL;
 
   enumerator = g_file_enumerate_children (priv->objects_dir, OSTREE_GIO_FAST_QUERYINFO, 
                                           G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
-                                          NULL, 
+                                          cancellable, 
                                           error);
   if (!enumerator)
     goto out;
 
-  while ((file_info = g_file_enumerator_next_file (enumerator, NULL, &temp_error)) != NULL)
+  while ((file_info = g_file_enumerator_next_file (enumerator, cancellable, &temp_error)) != NULL)
     {
       const char *name;
       guint32 type;
@@ -2411,31 +2431,77 @@ ostree_repo_iter_objects (OstreeRepo  *self,
       
       if (strlen (name) == 2 && type == G_FILE_TYPE_DIRECTORY)
         {
-          GFile *objdir = g_file_get_child (priv->objects_dir, name);
-          if (!iter_object_dir (self, objdir, callback, user_data, error))
-            {
-              g_object_unref (objdir);
-              goto out;
-            }
-          g_object_unref (objdir);
+          g_clear_object (&objdir);
+          objdir = g_file_get_child (priv->objects_dir, name);
+          if (!list_loose_object_dir (self, objdir, inout_objects, cancellable, error))
+            goto out;
         }
-      g_object_unref (file_info);
+      g_clear_object (&file_info);
     }
   if (file_info == NULL && temp_error != NULL)
     {
       g_propagate_error (error, temp_error);
       goto out;
     }
-  if (!g_file_enumerator_close (enumerator, NULL, error))
+  if (!g_file_enumerator_close (enumerator, cancellable, error))
     goto out;
 
   ret = TRUE;
  out:
+  g_clear_object (&objdir);
   g_clear_object (&file_info);
   g_clear_object (&enumerator);
   return ret;
 }
 
+/**
+ * ostree_repo_list_objects:
+ * @self:
+ * @flags:
+ * @out_objects: (out): Map of serialized object name to variant data
+ * @cancellable:
+ * @error:
+ *
+ * This function synchronously enumerates all objects in the
+ * repository, returning data in @out_objects.  @out_objects
+ * maps from keys returned by ostree_object_name_serialize()
+ * to #GVariant values of type %OSTREE_REPO_LIST_OBJECTS_VARIANT_TYPE.
+ *
+ * Returns: %TRUE on success, %FALSE on error, and @error will be set
+ */ 
+gboolean
+ostree_repo_list_objects (OstreeRepo                  *self,
+                          OstreeRepoListObjectsFlags   flags,
+                          GHashTable                 **out_objects,
+                          GCancellable                *cancellable,
+                          GError                     **error)
+{
+  gboolean ret = FALSE;
+  OstreeRepoPrivate *priv = GET_PRIVATE (self);
+  GHashTable *ret_objects = NULL;
+
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+  g_return_val_if_fail (priv->inited, FALSE);
+  
+  ret_objects = g_hash_table_new_full (hash_list_object_key, g_variant_equal, (GDestroyNotify) g_variant_unref, (GDestroyNotify) g_variant_unref);
+
+  if (flags & OSTREE_REPO_LIST_OBJECTS_ALL)
+    flags |= (OSTREE_REPO_LIST_OBJECTS_LOOSE | OSTREE_REPO_LIST_OBJECTS_PACKED);
+
+  if (flags & OSTREE_REPO_LIST_OBJECTS_LOOSE)
+    {
+      if (!list_loose_objects (self, ret_objects, cancellable, error))
+        goto out;
+    }
+
+  ret = TRUE;
+  ot_transfer_out_value (out_objects, &ret_objects);
+ out:
+  if (ret_objects)
+    g_hash_table_unref (ret_objects);
+  return ret;
+}
+
 static gboolean
 checkout_file_from_input (GFile          *file,
                           OstreeRepoCheckoutMode mode,
diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h
index 25ef09e..0d3ae1b 100644
--- a/src/libostree/ostree-repo.h
+++ b/src/libostree/ostree-repo.h
@@ -226,17 +226,27 @@ gboolean       ostree_repo_read_commit (OstreeRepo *self,
                                         GCancellable *cancellable,
                                         GError  **error);
 
-typedef void (*OstreeRepoObjectIter) (OstreeRepo *self, 
-                                      const char *checksum,
-                                      OstreeObjectType type,
-                                      GFile      *path,
-                                      GFileInfo  *fileinfo,
-                                      gpointer user_data);
-
-gboolean     ostree_repo_iter_objects (OstreeRepo  *self,
-                                       OstreeRepoObjectIter callback,
-                                       gpointer       user_data,
-                                       GError        **error);
+typedef enum {
+  OSTREE_REPO_LIST_OBJECTS_LOOSE = (1 << 0),
+  OSTREE_REPO_LIST_OBJECTS_PACKED = (1 << 1),
+  OSTREE_REPO_LIST_OBJECTS_ALL = (1 << 2)
+} OstreeRepoListObjectsFlags;
+
+/**
+ * OSTREE_REPO_LIST_OBJECTS_VARIANT_TYPE:
+ *
+ * b - %TRUE if object is available "loose"
+ * as - List of pack file checksums in which this object appears
+ * t - For loose objects, Unix ctime (seconds)
+ * t - object size
+ */
+#define OSTREE_REPO_LIST_OBJECTS_VARIANT_TYPE (G_VARIANT_TYPE ("(bastt)")
+
+gboolean ostree_repo_list_objects (OstreeRepo                  *self,
+                                   OstreeRepoListObjectsFlags   flags,
+                                   GHashTable                 **out_objects,
+                                   GCancellable                *cancellable,
+                                   GError                     **error);
 
 G_END_DECLS
 
diff --git a/src/ostree/ot-builtin-fsck.c b/src/ostree/ot-builtin-fsck.c
index 9671ffa..6e5de25 100644
--- a/src/ostree/ot-builtin-fsck.c
+++ b/src/ostree/ot-builtin-fsck.c
@@ -123,39 +123,36 @@ checksum_archived_file (OtFsckData   *data,
   return ret;
 }
 
-static void
-object_iter_callback (OstreeRepo    *repo,
-                      const char    *exp_checksum,
-                      OstreeObjectType objtype,
-                      GFile         *objf,
-                      GFileInfo     *file_info,
-                      gpointer       user_data)
+static gboolean
+fsck_loose_object (OtFsckData    *data,
+                   const char    *exp_checksum,
+                   OstreeObjectType objtype,
+                   GCancellable   *cancellable,
+                   GError        **error)
 {
-  OtFsckData *data = user_data;
+  gboolean ret = FALSE;
+  GFile *objf = NULL;
   GChecksum *real_checksum = NULL;
-  GError *error = NULL;
 
-  /* nlinks = g_file_info_get_attribute_uint32 (file_info, "unix::nlink");
-     if (nlinks < 2 && !quiet)
-     g_printerr ("note: floating object: %s\n", path); */
+  objf = ostree_repo_get_object_path (data->repo, exp_checksum, objtype);
 
   if (objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META)
     {
       if (!g_str_has_suffix (ot_gfile_get_path_cached (objf), ".archive-meta"))
         {
-          g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                        "Invalid archive filename '%s'",
                        ot_gfile_get_path_cached (objf));
           goto out;
         }
-      if (!checksum_archived_file (data, exp_checksum, objf, &real_checksum, &error))
+      if (!checksum_archived_file (data, exp_checksum, objf, &real_checksum, error))
         goto out;
     }
   else if (objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT)
     ; /* Handled above */
   else
     {
-      if (!ostree_checksum_file (objf, objtype, &real_checksum, NULL, &error))
+      if (!ostree_checksum_file (objf, objtype, &real_checksum, NULL, error))
         goto out;
     }
 
@@ -170,13 +167,10 @@ object_iter_callback (OstreeRepo    *repo,
 
   data->n_objects++;
 
+  ret = TRUE;
  out:
   ot_clear_checksum (&real_checksum);
-  if (error != NULL)
-    {
-      g_printerr ("%s\n", error->message);
-      g_clear_error (&error);
-    }
+  return ret;
 }
 
 gboolean
@@ -186,6 +180,10 @@ ostree_builtin_fsck (int argc, char **argv, GFile *repo_path, GError **error)
   OtFsckData data;
   gboolean ret = FALSE;
   OstreeRepo *repo = NULL;
+  GHashTable *objects = NULL;
+  GCancellable *cancellable = NULL;
+  GHashTableIter hash_iter;
+  gpointer key, value;
 
   context = g_option_context_new ("- Check the repository for consistency");
   g_option_context_add_main_entries (context, options, NULL);
@@ -201,8 +199,30 @@ ostree_builtin_fsck (int argc, char **argv, GFile *repo_path, GError **error)
   data.n_objects = 0;
   data.had_error = FALSE;
 
-  if (!ostree_repo_iter_objects (repo, object_iter_callback, &data, error))
+  if (!ostree_repo_list_objects (repo, OSTREE_REPO_LIST_OBJECTS_ALL,
+                                 &objects, cancellable, error))
     goto out;
+  
+  g_hash_table_iter_init (&hash_iter, objects);
+
+  while (g_hash_table_iter_next (&hash_iter, &key, &value))
+    {
+      GVariant *serialized_key = key;
+      GVariant *objdata = value;
+      const char *checksum;
+      OstreeObjectType objtype;
+      gboolean is_loose;
+
+      ostree_object_name_deserialize (serialized_key, &checksum, &objtype);
+
+      g_variant_get_child (objdata, 0, "b", &is_loose);
+
+      if (is_loose)
+        {
+          if (!fsck_loose_object (&data, checksum, objtype, cancellable, error))
+            goto out;
+        }
+    }
 
   if (data.had_error)
     {
@@ -218,5 +238,7 @@ ostree_builtin_fsck (int argc, char **argv, GFile *repo_path, GError **error)
   if (context)
     g_option_context_free (context);
   g_clear_object (&repo);
+  if (objects)
+    g_hash_table_unref (objects);
   return ret;
 }
diff --git a/src/ostree/ot-builtin-local-clone.c b/src/ostree/ot-builtin-local-clone.c
index 87b0151..840bf9d 100644
--- a/src/ostree/ot-builtin-local-clone.c
+++ b/src/ostree/ot-builtin-local-clone.c
@@ -97,23 +97,29 @@ copy_dir_contents_recurse (GFile  *src,
   return ret;
 }
 
-static void
-object_iter_callback (OstreeRepo   *repo,
-                      const char   *checksum,
-                      OstreeObjectType objtype,
-                      GFile        *objfile,
-                      GFileInfo    *file_info,
-                      gpointer      user_data)
+static gboolean
+import_loose_object (OtLocalCloneData *data,
+                     const char   *checksum,
+                     OstreeObjectType objtype,
+                     GCancellable  *cancellable,
+                     GError        **error)
 {
-  OtLocalCloneData *data = user_data;
-  GError *real_error = NULL;
-  GError **error = &real_error;
+  gboolean ret = FALSE;
+  GFile *objfile = NULL;
+  GFileInfo *file_info = NULL;
   GFile *content_path = NULL;
   GFileInfo *archive_info = NULL;
   GVariant *archive_metadata = NULL;
   GVariant *xattrs = NULL;
   GInputStream *input = NULL;
 
+  objfile = ostree_repo_get_object_path (data->src_repo, checksum, objtype);
+  file_info = g_file_query_info (objfile, OSTREE_GIO_FAST_QUERYINFO,
+                                 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error);
+
+  if (file_info == NULL)
+    goto out;
+
   if (objtype == OSTREE_OBJECT_TYPE_RAW_FILE)
     xattrs = ostree_get_xattrs_for_file (objfile, error);
   
@@ -121,13 +127,13 @@ object_iter_callback (OstreeRepo   *repo,
     ;
   else if (objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META)
     {
-      if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META, checksum, &archive_metadata, error))
+      if (!ostree_repo_load_variant (data->src_repo, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META, checksum, &archive_metadata, error))
         goto out;
 
       if (!ostree_parse_archived_file_meta (archive_metadata, &archive_info, &xattrs, error))
         goto out;
 
-      content_path = ostree_repo_get_object_path (repo, checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT);
+      content_path = ostree_repo_get_object_path (data->src_repo, checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT);
 
       if (g_file_info_get_file_type (archive_info) == G_FILE_TYPE_REGULAR)
         {
@@ -156,18 +162,16 @@ object_iter_callback (OstreeRepo   *repo,
         goto out;
     }
 
+  ret = TRUE;
  out:
   ot_clear_gvariant (&archive_metadata);
   ot_clear_gvariant (&xattrs);
   g_clear_object (&archive_info);
   g_clear_object (&input);
   g_clear_object (&content_path);
-  if (real_error != NULL)
-    {
-      g_printerr ("%s\n", real_error->message);
-      g_clear_error (error);
-      exit (1);
-    }
+  g_clear_object (&file_info);
+  g_clear_object (&objfile);
+  return ret;
 }
 
 static gboolean
@@ -209,6 +213,7 @@ ostree_builtin_local_clone (int argc, char **argv, GFile *repo_path, GError **er
 {
   gboolean ret = FALSE;
   GCancellable *cancellable = NULL;
+  GHashTable *objects = NULL;
   GOptionContext *context;
   const char *destination;
   GFile *dest_f = NULL;
@@ -220,6 +225,8 @@ ostree_builtin_local_clone (int argc, char **argv, GFile *repo_path, GError **er
   GFile *src_dir = NULL;
   GFile *dest_dir = NULL;
   int i;
+  GHashTableIter hash_iter;
+  gpointer key, value;
 
   context = g_option_context_new ("DEST ... - Create new repository DEST");
   g_option_context_add_main_entries (context, options, NULL);
@@ -266,11 +273,33 @@ ostree_builtin_local_clone (int argc, char **argv, GFile *repo_path, GError **er
 
   data.uids_differ = g_file_info_get_attribute_uint32 (src_info, "unix::uid") != g_file_info_get_attribute_uint32 (dest_info, "unix::uid");
 
-  if (!ostree_repo_prepare_transaction (data.dest_repo, NULL, error))
+  if (!ostree_repo_list_objects (data.src_repo, OSTREE_REPO_LIST_OBJECTS_ALL,
+                                 &objects, cancellable, error))
     goto out;
 
-  if (!ostree_repo_iter_objects (data.src_repo, object_iter_callback, &data, error))
+  if (!ostree_repo_prepare_transaction (data.dest_repo, NULL, error))
     goto out;
+  
+  g_hash_table_iter_init (&hash_iter, objects);
+
+  while (g_hash_table_iter_next (&hash_iter, &key, &value))
+    {
+      GVariant *serialized_key = key;
+      GVariant *objdata = value;
+      const char *checksum;
+      OstreeObjectType objtype;
+      gboolean is_loose;
+
+      ostree_object_name_deserialize (serialized_key, &checksum, &objtype);
+
+      g_variant_get_child (objdata, 0, "b", &is_loose);
+
+      if (is_loose)
+        {
+          if (!import_loose_object (&data, checksum, objtype, cancellable, error))
+            goto out;
+        }
+    }
 
   if (!ostree_repo_commit_transaction (data.dest_repo, NULL, error))
     goto out;
@@ -311,5 +340,7 @@ ostree_builtin_local_clone (int argc, char **argv, GFile *repo_path, GError **er
   g_clear_object (&dest_dir);
   g_clear_object (&data.src_repo);
   g_clear_object (&data.dest_repo);
+  if (objects)
+    g_hash_table_unref (objects);
   return ret;
 }
diff --git a/src/ostree/ot-builtin-prune.c b/src/ostree/ot-builtin-prune.c
index 5090036..2c50f51 100644
--- a/src/ostree/ot-builtin-prune.c
+++ b/src/ostree/ot-builtin-prune.c
@@ -187,24 +187,27 @@ compute_reachable_objects_from_commit (OstreeRepo      *repo,
   return ret;
 }
 
-static void
-object_iter_callback (OstreeRepo    *repo,
-                      const char    *checksum,
-                      OstreeObjectType objtype,
-                      GFile         *objf,
-                      GFileInfo     *file_info,
-                      gpointer       user_data)
+static gboolean
+prune_loose_object (OtPruneData    *data,
+                    const char    *checksum,
+                    OstreeObjectType objtype,
+                    GCancellable    *cancellable,
+                    GError         **error)
 {
-  OtPruneData *data = user_data;
+  gboolean ret = FALSE;
   char *key;
+  GFile *objf = NULL;
 
   key = ostree_object_to_string (checksum, objtype);
 
+  objf = ostree_repo_get_object_path (data->repo, checksum, objtype);
+
   if (!g_hash_table_lookup_extended (data->reachable, key, NULL, NULL))
     {
       if (delete)
         {
-          (void) unlink (ot_gfile_get_path_cached (objf));
+          if (!g_file_delete (objf, cancellable, error))
+            goto out;
           g_print ("Deleted: %s\n", key);
         }
       else
@@ -216,16 +219,21 @@ object_iter_callback (OstreeRepo    *repo,
   else
     data->n_reachable++;
 
+  ret = TRUE;
+ out:
+  g_clear_object (&objf);
   g_free (key);
+  return ret;
 }
 
 
 gboolean
 ostree_builtin_prune (int argc, char **argv, GFile *repo_path, GError **error)
 {
+  gboolean ret = FALSE;
   GOptionContext *context;
   OtPruneData data;
-  gboolean ret = FALSE;
+  GHashTable *objects = NULL;
   OstreeRepo *repo = NULL;
   GHashTable *all_refs = NULL;
   GHashTableIter hash_iter;
@@ -266,10 +274,36 @@ ostree_builtin_prune (int argc, char **argv, GFile *repo_path, GError **error)
         goto out;
     }
 
-  g_hash_table_iter_init (&hash_iter, data.reachable);
+  if (!ostree_repo_list_objects (repo, OSTREE_REPO_LIST_OBJECTS_ALL, &objects, cancellable, error))
+    goto out;
+
+  g_hash_table_iter_init (&hash_iter, objects);
+
 
-  if (!ostree_repo_iter_objects (repo, object_iter_callback, &data, error))
+  if (!ostree_repo_list_objects (repo, OSTREE_REPO_LIST_OBJECTS_ALL,
+                                 &objects, cancellable, error))
     goto out;
+  
+  g_hash_table_iter_init (&hash_iter, objects);
+
+  while (g_hash_table_iter_next (&hash_iter, &key, &value))
+    {
+      GVariant *serialized_key = key;
+      GVariant *objdata = value;
+      const char *checksum;
+      OstreeObjectType objtype;
+      gboolean is_loose;
+
+      ostree_object_name_deserialize (serialized_key, &checksum, &objtype);
+
+      g_variant_get_child (objdata, 0, "b", &is_loose);
+
+      if (is_loose)
+        {
+          if (!prune_loose_object (&data, checksum, objtype, cancellable, error))
+            goto out;
+        }
+    }
 
   if (data.had_error)
     goto out;
@@ -286,5 +320,7 @@ ostree_builtin_prune (int argc, char **argv, GFile *repo_path, GError **error)
   if (context)
     g_option_context_free (context);
   g_clear_object (&repo);
+  if (objects)
+    g_hash_table_unref (objects);
   return ret;
 }
diff --git a/src/ostree/ot-builtin-repack.c b/src/ostree/ot-builtin-repack.c
index 4bee9f3..cbf92ff 100644
--- a/src/ostree/ot-builtin-repack.c
+++ b/src/ostree/ot-builtin-repack.c
@@ -64,7 +64,6 @@ typedef struct {
   guint n_dirmeta;
   guint n_dirtree;
   guint n_files;
-  GPtrArray *objects;
   gboolean had_error;
   GError **error;
 } OtRepackData;
@@ -133,56 +132,6 @@ create_compressor_subprocess (OtBuildRepackFile *self,
   return ret;
 }
 
-static void
-object_iter_callback (OstreeRepo    *repo,
-                      const char    *checksum,
-                      OstreeObjectType objtype,
-                      GFile         *objf,
-                      GFileInfo     *file_info,
-                      gpointer       user_data)
-{
-  gboolean ret = FALSE;
-  OtRepackData *data = user_data;
-  guint64 objsize;
-  GVariant *objdata = NULL;
-
-  switch (objtype)
-    {
-    case OSTREE_OBJECT_TYPE_COMMIT:
-      data->n_commits++;
-      break;
-    case OSTREE_OBJECT_TYPE_DIR_TREE:
-      data->n_dirtree++;
-      break;
-    case OSTREE_OBJECT_TYPE_DIR_META:
-      data->n_dirmeta++;
-      break;
-    case OSTREE_OBJECT_TYPE_RAW_FILE:
-    case OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT:
-      data->n_files++;
-      break;
-    case OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META:
-      /* Counted under files */
-      break;
-    }
-
-  /* For archived content, only count regular files */
-  if (!(objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT
-        && g_file_info_get_file_type (file_info) != G_FILE_TYPE_REGULAR))
-    {
-      objsize = g_file_info_get_size (file_info);
-
-      objdata = g_variant_new ("(tsu)", objsize, checksum, (guint32)objtype);
-      g_ptr_array_add (data->objects, g_variant_ref_sink (objdata));
-      objdata = NULL; /* Transfer ownership */
-    }
-
-  ret = TRUE;
-  /* out: */
-  ot_clear_gvariant (&objdata);
-  data->had_error = !ret;
-}
-
 static gint
 compare_object_data_by_size (gconstpointer    ap,
                              gconstpointer    bp)
@@ -192,8 +141,8 @@ compare_object_data_by_size (gconstpointer    ap,
   guint64 a_size;
   guint64 b_size;
 
-  g_variant_get_child (a, 0, "t", &a_size);
-  g_variant_get_child (b, 0, "t", &b_size);
+  g_variant_get_child (a, 2, "t", &a_size);
+  g_variant_get_child (b, 2, "t", &b_size);
   if (a == b)
     return 0;
   else if (a > b)
@@ -315,7 +264,7 @@ create_pack_file (OtRepackData        *data,
       GOutputStream *write_pack_out;
       guchar entry_flags;
 
-      g_variant_get (object_data, "(t&su)", &objsize, &checksum, &objtype_u32);
+      g_variant_get (object_data, "(&sut)", &checksum, &objtype_u32, &objsize);
                      
       objtype = (OstreeObjectType) objtype_u32;
 
@@ -489,26 +438,49 @@ create_pack_file (OtRepackData        *data,
  * Returns: [Array of [Array of object data]].  Free with g_ptr_array_unref().
  */
 static GPtrArray *
-cluster_objects_stupidly (OtRepackData      *data)
+cluster_objects_stupidly (OtRepackData      *data,
+                          GHashTable        *objects)
 {
   GPtrArray *ret = NULL;
-  GPtrArray *objects = data->objects;
+  GPtrArray *object_list = NULL;
   guint i;
   guint64 current_size;
   guint current_offset;
+  GHashTableIter hash_iter;
+  gpointer key, value;
+
+  object_list = g_ptr_array_new_with_free_func ((GDestroyNotify)g_variant_unref);
 
-  g_ptr_array_sort (data->objects, compare_object_data_by_size);
+  g_hash_table_iter_init (&hash_iter, objects);
+
+  while (g_hash_table_iter_next (&hash_iter, &key, &value))
+    {
+      GVariant *serialized_key = key;
+      GVariant *objdata = value;
+      const char *checksum;
+      OstreeObjectType objtype;
+      guint64 size;
+
+      ostree_object_name_deserialize (serialized_key, &checksum, &objtype);
+
+      g_variant_get_child (objdata, 3, "t", &size);
+
+      g_ptr_array_add (object_list,
+                       g_variant_new ("(sut)", checksum, objtype, size));
+    }
+
+  g_ptr_array_sort (object_list, compare_object_data_by_size);
 
   ret = g_ptr_array_new ();
 
   current_size = 0;
   current_offset = 0;
-  for (i = 0; i < objects->len; i++)
+  for (i = 0; i < object_list->len; i++)
     { 
-      GVariant *objdata = objects->pdata[i];
+      GVariant *objdata = object_list->pdata[i];
       guint64 objsize;
 
-      g_variant_get_child (objdata, 0, "t", &objsize);
+      g_variant_get_child (objdata, 2, "t", &objsize);
 
       if (current_size + objsize > data->pack_size)
         {
@@ -516,7 +488,7 @@ cluster_objects_stupidly (OtRepackData      *data)
           GPtrArray *current = g_ptr_array_new ();
           for (j = current_offset; j < i; j++)
             {
-              g_ptr_array_add (current, objects->pdata[j]);
+              g_ptr_array_add (current, object_list->pdata[j]);
             }
           g_ptr_array_add (ret, current);
           current_size = objsize;
@@ -532,6 +504,8 @@ cluster_objects_stupidly (OtRepackData      *data)
         }
     }
 
+  if (object_list)
+    g_ptr_array_unref (object_list);
   return ret;
 }
 
@@ -622,14 +596,17 @@ parse_compression_string (const char *compstr,
 gboolean
 ostree_builtin_repack (int argc, char **argv, GFile *repo_path, GError **error)
 {
+  gboolean ret = FALSE;
   GOptionContext *context;
   OtRepackData data;
-  gboolean ret = FALSE;
   OstreeRepo *repo = NULL;
+  GHashTable *objects = NULL;
   GCancellable *cancellable = NULL;
   guint i;
   guint64 total_size;
   GPtrArray *clusters = NULL;
+  GHashTableIter hash_iter;
+  gpointer key, value;
 
   memset (&data, 0, sizeof (data));
 
@@ -645,7 +622,6 @@ ostree_builtin_repack (int argc, char **argv, GFile *repo_path, GError **error)
 
   data.repo = repo;
   data.error = error;
-  data.objects = g_ptr_array_new_with_free_func ((GDestroyNotify)g_variant_unref);
 
   if (!parse_size_spec_with_suffix (opt_pack_size, OT_DEFAULT_PACK_SIZE_BYTES, &data.pack_size, error))
     goto out;
@@ -655,33 +631,57 @@ ostree_builtin_repack (int argc, char **argv, GFile *repo_path, GError **error)
   if (!parse_compression_string (opt_ext_compression, &data.ext_compression, error))
     goto out;
 
-  if (!ostree_repo_iter_objects (repo, object_iter_callback, &data, error))
+  if (!ostree_repo_list_objects (repo, OSTREE_REPO_LIST_OBJECTS_LOOSE, &objects, cancellable, error))
     goto out;
 
-  if (data.had_error)
-    goto out;
-
-  g_print ("Commits: %u\n", data.n_commits);
-  g_print ("Tree contents: %u\n", data.n_dirtree);
-  g_print ("Tree meta: %u\n", data.n_dirmeta);
-  g_print ("Files: %u\n", data.n_files);
+  g_hash_table_iter_init (&hash_iter, objects);
 
   total_size = 0;
-  for (i = 0; i < data.objects->len; i++)
+  while (g_hash_table_iter_next (&hash_iter, &key, &value))
     {
-      GVariant *objdata = data.objects->pdata[i];
+      GVariant *serialized_key = key;
+      GVariant *objdata = value;
+      const char *checksum;
+      OstreeObjectType objtype;
       guint64 size;
-      
-      g_variant_get_child (objdata, 0, "t", &size);
+
+      ostree_object_name_deserialize (serialized_key, &checksum, &objtype);
+
+      switch (objtype)
+        {
+        case OSTREE_OBJECT_TYPE_COMMIT:
+          data.n_commits++;
+          break;
+        case OSTREE_OBJECT_TYPE_DIR_TREE:
+          data.n_dirtree++;
+          break;
+        case OSTREE_OBJECT_TYPE_DIR_META:
+          data.n_dirmeta++;
+          break;
+        case OSTREE_OBJECT_TYPE_RAW_FILE:
+        case OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT:
+          data.n_files++;
+          break;
+        case OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META:
+          /* Counted under files */
+          break;
+        }
+
+      g_variant_get_child (objdata, 3, "t", &size);
       
       total_size += size;
     }
+
+  g_print ("Commits: %u\n", data.n_commits);
+  g_print ("Tree contents: %u\n", data.n_dirtree);
+  g_print ("Tree meta: %u\n", data.n_dirmeta);
+  g_print ("Files: %u\n", data.n_files);
   g_print ("Total size: %" G_GUINT64_FORMAT "\n", total_size);
 
   g_print ("\n");
   g_print ("Using pack size: %" G_GUINT64_FORMAT "\n", data.pack_size);
 
-  clusters = cluster_objects_stupidly (&data);
+  clusters = cluster_objects_stupidly (&data, objects);
 
   g_print ("Going to create %u packfiles\n", clusters->len);
 
@@ -705,5 +705,7 @@ ostree_builtin_repack (int argc, char **argv, GFile *repo_path, GError **error)
   g_clear_object (&repo);
   if (clusters)
     g_ptr_array_unref (clusters);
+  if (objects)
+    g_hash_table_unref (objects);
   return ret;
 }



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