[ostree] ostree-repo-resolve-rev: Add function to accept a partial checksum



commit fd56952d6ba96056cf2c77e8d6031b42711849f5
Author: Anne LoVerso <aelv13 gmail com>
Date:   Fri Jul 11 14:00:45 2014 -0400

    ostree-repo-resolve-rev: Add function to accept a partial checksum
    
    This patch adds a function that will parse a partial checksum when
    resolving a refspec.  If the inputted refspec matches a truncated
    existing checksum, it will return that checksum to be parsed.  If
    multiple truncated checksums match the partial refspec, it is not
    unique and will return false.  This addition is inspired by the same
    functionality in Docker, which allows a user to reference a specific
    commit without typing the entire checksum.
    
    partial checksums: Add function to abstract comparison
    
    This modifies the list_objects and list_objects_at functions
    to take an additional argument for the string that a commit starts
    with.  If this string arg is not null, it will only list commit
    objects beginning with that string.  This allows for a new function
    ostree_repo_list_commit_objects_starting_with to pass a partial string
    and return a list of all matching commits.  This improves on the
    previous strategy of listing refs because it will list all commit objects,
    even ones in past history.  This update also includes bugfixes on
    error handling and string comparison, and changes the output structure
    of resolve_partial_checksum. The new strcuture will no longer return FALSE
    without error.  Also, the hashtable foreach now uses iter.  Also
    includes modified test file

 src/libostree/ostree-repo-refs.c |   78 ++++++++++++++++++++++++++++++-
 src/libostree/ostree-repo.c      |   95 +++++++++++++++++++++++++++++++------
 src/libostree/ostree-repo.h      |    6 ++
 tests/test-basic.sh              |    9 ++++
 4 files changed, 171 insertions(+), 17 deletions(-)
---
diff --git a/src/libostree/ostree-repo-refs.c b/src/libostree/ostree-repo-refs.c
index 2b05e6f..a7909fb 100644
--- a/src/libostree/ostree-repo-refs.c
+++ b/src/libostree/ostree-repo-refs.c
@@ -348,6 +348,75 @@ resolve_refspec (OstreeRepo     *self,
 }
 
 /**
+ * ostree_repo_resolve_partial_checksum:
+ * @self: Repo
+ * @refspec: A refspec
+ * @full_checksum (out) (transfer full): A full checksum corresponding to the truncated ref given
+ * @error: Error
+ *
+ * Look up the existing refspec checksums.  If the given ref is a unique truncated beginning
+ * of a valid checksum it will return that checksum in the parameter @full_checksum
+ */
+static gboolean
+ostree_repo_resolve_partial_checksum (OstreeRepo   *self,
+                                      const char   *refspec,
+                                      char        **full_checksum,
+                                      GError      **error)
+{
+  gboolean ret = FALSE;
+  s_unref_hashtable GHashTable *ref_list = NULL;
+  gs_free char *ret_rev = NULL;
+  guint length;
+  const char *checksum = NULL;
+  OstreeObjectType objtype;
+  GHashTableIter hashiter;
+  gpointer key, value;
+  GVariant *first_commit;
+
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  /* this looks through all objects and adds them to the ref_list if:
+     a) they are a commit object AND
+     b) the obj checksum starts with the partual checksum defined by "refspec" */
+  if (!ostree_repo_list_commit_objects_starting_with (self, refspec, &ref_list, NULL, error))
+    goto out;
+
+  length = g_hash_table_size (ref_list);
+
+  g_hash_table_iter_init (&hashiter, ref_list);
+  if (g_hash_table_iter_next (&hashiter, &key, &value))
+    first_commit = (GVariant*) key;
+  else
+    first_commit = NULL;
+
+  if (first_commit) 
+    ostree_object_name_deserialize (first_commit, &checksum, &objtype);
+
+  /* length more than one - multiple commits match partial refspec: is not unique */
+  if (length > 1)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Refspec %s not unique", refspec);
+      goto out;
+    }
+    
+  /* length is 1 - a single matching commit gives us our revision */
+  else if (length == 1)
+    {
+      ret_rev = g_strdup (checksum);
+    }
+
+  /* Note: if length is 0, then code will return TRUE
+     because there is no error, but it will return full_checksum = NULL
+     to signal to continue parsing */
+
+  ret = TRUE;
+  ot_transfer_out_value (full_checksum, &ret_rev);
+ out:
+  return ret;
+}
+
+/**
  * ostree_repo_resolve_rev:
  * @self: Repo
  * @refspec: A refspec
@@ -374,8 +443,15 @@ ostree_repo_resolve_rev (OstreeRepo     *self,
     {
       ret_rev = g_strdup (refspec);
     }
-  else
+
+  else if (!ostree_repo_resolve_partial_checksum (self, refspec, &ret_rev, error))
+    goto out;
+
+  if (!ret_rev)
     {
+      if (error != NULL && *error != NULL)
+        goto out;
+
       if (g_str_has_suffix (refspec, "^"))
         {
           gs_free char *parent_refspec = NULL;
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index 5676664..70e1e9a 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -990,12 +990,14 @@ list_loose_objects_at (OstreeRepo             *self,
                        GHashTable             *inout_objects,
                        const char             *prefix,
                        int                     dfd,
+                       const char             *commit_starting_with,
                        GCancellable           *cancellable,
                        GError                **error)
 {
   gboolean ret = FALSE;
   DIR *d = NULL;
   struct dirent *dent;
+  GVariant *key, *value;
 
   d = fdopendir (dfd);
   if (!d)
@@ -1030,21 +1032,33 @@ list_loose_objects_at (OstreeRepo             *self,
       else
         continue;
 
-      if ((dot - name) == 62)
+      if ((dot - name) != 62)
+        continue;
+
+      memcpy (buf, prefix, 2);
+      memcpy (buf + 2, name, 62);
+      buf[sizeof(buf)-1] = '\0';
+
+      /* if we passed in a "starting with" argument, then
+         we only want to return .commit objects with a checksum
+         that matches the commit_starting_with argument */
+      if (commit_starting_with)
         {
-          GVariant *key, *value;
-
-          memcpy (buf, prefix, 2);
-          memcpy (buf + 2, name, 62);
-          buf[sizeof(buf)-1] = '\0';
-
-          key = ostree_object_name_serialize (buf, objtype);
-          value = g_variant_new ("(b as)",
-                                 TRUE, g_variant_new_strv (NULL, 0));
-          /* transfer ownership */
-          g_hash_table_replace (inout_objects, key,
-                                g_variant_ref_sink (value));
+          /* object is not a commit, do not add to array */
+          if (objtype != OSTREE_OBJECT_TYPE_COMMIT)
+              continue;
+
+          /* commit checksum does not match "starting with", do not add to array */     
+          if (!g_str_has_prefix (buf, commit_starting_with))
+            continue;
         }
+
+        key = ostree_object_name_serialize (buf, objtype);
+        value = g_variant_new ("(b as)",
+                               TRUE, g_variant_new_strv (NULL, 0));
+        /* transfer ownership */
+        g_hash_table_replace (inout_objects, key,
+                              g_variant_ref_sink (value));
     }
 
   ret = TRUE;
@@ -1057,6 +1071,7 @@ list_loose_objects_at (OstreeRepo             *self,
 static gboolean
 list_loose_objects (OstreeRepo                     *self,
                     GHashTable                     *inout_objects,
+                    const char                     *commit_starting_with,
                     GCancellable                   *cancellable,
                     GError                        **error)
 {
@@ -1084,7 +1099,8 @@ list_loose_objects (OstreeRepo                     *self,
         }
       /* Takes ownership of dfd */
       if (!list_loose_objects_at (self, inout_objects, buf, dfd,
-                                  cancellable, error))
+                                       commit_starting_with,
+                                       cancellable, error))
         goto out;
     }
 
@@ -1702,11 +1718,11 @@ ostree_repo_list_objects (OstreeRepo                  *self,
 
   if (flags & OSTREE_REPO_LIST_OBJECTS_LOOSE)
     {
-      if (!list_loose_objects (self, ret_objects, cancellable, error))
+      if (!list_loose_objects (self, ret_objects, NULL, cancellable, error))
         goto out;
       if (self->parent_repo)
         {
-          if (!list_loose_objects (self->parent_repo, ret_objects, cancellable, error))
+          if (!list_loose_objects (self->parent_repo, ret_objects, NULL, cancellable, error))
             goto out;
         }
     }
@@ -1723,6 +1739,53 @@ ostree_repo_list_objects (OstreeRepo                  *self,
 }
 
 /**
+ * ostree_repo_list_commit_objects_starting_with:
+ * @self: Repo
+ * @start: List commits starting with this checksum
+ * @out_commits: Array of GVariants
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * This function synchronously enumerates all commit objects starting
+ * with @start, returning data in @out_commits.
+ *
+ * Returns: %TRUE on success, %FALSE on error, and @error will be set
+ */
+gboolean
+ostree_repo_list_commit_objects_starting_with (OstreeRepo                  *self,
+                                               const char                  *start,
+                                               GHashTable                 **out_commits,
+                                               GCancellable                *cancellable,
+                                               GError                     **error)
+{
+  gboolean ret = FALSE;
+  gs_unref_hashtable GHashTable *ret_commits = NULL;
+
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+  g_return_val_if_fail (self->inited, FALSE);
+
+  ret_commits = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal,
+                                       (GDestroyNotify) g_variant_unref,
+                                       (GDestroyNotify) g_variant_unref);
+
+  if (!list_loose_objects (self, ret_commits, start, cancellable, error))
+        goto out;
+
+
+  if (self->parent_repo)
+    {
+      if (!list_loose_objects (self->parent_repo, ret_commits, start,
+                               cancellable, error))
+        goto out;
+    }
+
+  ret = TRUE;
+  ot_transfer_out_value (out_commits, &ret_commits);
+ out:
+  return ret;
+}
+
+/**
  * ostree_repo_read_commit:
  * @self: Repo
  * @ref: Ref or ASCII checksum
diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h
index 7a57d33..26fd6cc 100644
--- a/src/libostree/ostree-repo.h
+++ b/src/libostree/ostree-repo.h
@@ -446,6 +446,12 @@ gboolean ostree_repo_list_objects (OstreeRepo                  *self,
                                    GCancellable                *cancellable,
                                    GError                     **error);
 
+gboolean ostree_repo_list_commit_objects_starting_with ( OstreeRepo                  *self,
+                                                         const char                  *start,
+                                                         GHashTable                 **out_commits,
+                                                         GCancellable                *cancellable,
+                                                         GError                     **error);
+
 gboolean ostree_repo_list_static_delta_names (OstreeRepo                  *self,
                                               GPtrArray                  **out_deltas,
                                               GCancellable                *cancellable,
diff --git a/tests/test-basic.sh b/tests/test-basic.sh
index e0e7132..dfad255 100755
--- a/tests/test-basic.sh
+++ b/tests/test-basic.sh
@@ -34,6 +34,15 @@ $OSTREE rev-parse 'test2^'
 $OSTREE rev-parse 'test2^^' 2>/dev/null && (echo 1>&2 "rev-parse test2^^ unexpectedly succeeded!"; exit 1)
 echo "ok rev-parse"
 
+checksum=$($OSTREE rev-parse test2)
+partial=${checksum:0:6} 
+echo "partial:" $partial
+echo "corresponds to:" $checksum
+$OSTREE rev-parse test2 > checksum
+$OSTREE rev-parse $partial > partial-results
+assert_file_has_content checksum $(cat partial-results)
+echo "ok shortened checksum"
+
 (cd repo && ostree rev-parse test2)
 echo "ok repo-in-cwd"
 


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