[ostree] pull: Add ability to fetch refs/summary if no ref specified



commit 24403389687b1d6aed475711d22c092a39736a83
Author: Colin Walters <walters verbum org>
Date:   Mon Feb 27 08:37:51 2012 -0500

    pull: Add ability to fetch refs/summary if no ref specified
    
    This allows us to fetch all refs, which is useful for ostbuild where
    we do want the buildroot/ refs.

 src/ostree/ostree-pull.c |  336 ++++++++++++++++++++++++++++++++++++----------
 1 files changed, 265 insertions(+), 71 deletions(-)
---
diff --git a/src/ostree/ostree-pull.c b/src/ostree/ostree-pull.c
index ec0adda..ad108eb 100644
--- a/src/ostree/ostree-pull.c
+++ b/src/ostree/ostree-pull.c
@@ -1,6 +1,6 @@
 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
  *
- * Copyright (C) 2011 Colin Walters <walters verbum org>
+ * Copyright (C) 2011,2012 Colin Walters <walters verbum org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -83,6 +83,7 @@ fetch_uri (OstreeRepo  *repo,
            SoupURI     *uri,
            const char  *tmp_prefix,
            GFile      **out_temp_filename,
+           GCancellable  *cancellable,
            GError     **error)
 {
   gboolean ret = FALSE;
@@ -137,12 +138,50 @@ fetch_uri (OstreeRepo  *repo,
 }
 
 static gboolean
+fetch_uri_contents_utf8 (OstreeRepo  *repo,
+                         SoupSession *soup,
+                         SoupURI     *uri,
+                         char       **out_contents,
+                         GCancellable  *cancellable,
+                         GError     **error)
+{
+  gboolean ret = FALSE;
+  GFile *tmpf = NULL;
+  char *ret_contents = NULL;
+  gsize len;
+
+  if (!fetch_uri (repo, soup, uri, "tmp-", &tmpf, cancellable, error))
+    goto out;
+
+  if (!g_file_load_contents (tmpf, cancellable, &ret_contents, &len, NULL, error))
+    goto out;
+
+  if (!g_utf8_validate (ret_contents, -1, NULL))
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Invalid UTF-8");
+      goto out;
+    }
+
+  ret = TRUE;
+  ot_transfer_out_value (out_contents, &ret_contents);
+ out:
+  if (tmpf)
+    (void) unlink (ot_gfile_get_path_cached (tmpf));
+  g_clear_object (&tmpf);
+  g_free (ret_contents);
+  return ret;
+}
+
+
+static gboolean
 fetch_object (OstreeRepo  *repo,
               SoupSession *soup,
               SoupURI     *baseuri,
               const char  *checksum,
               OstreeObjectType objtype,
               GFile           **out_temp_path,
+              GCancellable *cancellable,
               GError     **error)
 {
   gboolean ret = FALSE;
@@ -156,7 +195,8 @@ fetch_object (OstreeRepo  *repo,
   relpath = g_build_filename (soup_uri_get_path (obj_uri), objpath, NULL);
   soup_uri_set_path (obj_uri, relpath);
   
-  if (!fetch_uri (repo, soup, obj_uri, ostree_object_type_to_string (objtype), &ret_temp_path, error))
+  if (!fetch_uri (repo, soup, obj_uri, ostree_object_type_to_string (objtype), &ret_temp_path,
+                  cancellable, error))
     goto out;
 
   ret = TRUE;
@@ -178,6 +218,7 @@ fetch_and_store_object (OstreeRepo  *repo,
                         OstreeObjectType objtype,
                         gboolean         *out_is_pending,
                         GVariant        **out_metadata,
+                        GCancellable *cancellable,
                         GError     **error)
 {
   gboolean ret = FALSE;
@@ -197,25 +238,25 @@ fetch_and_store_object (OstreeRepo  *repo,
       
   if (!(stored_path || pending_path))
     {
-      if (!fetch_object (repo, soup, baseuri, checksum, objtype, &temp_path, error))
+      if (!fetch_object (repo, soup, baseuri, checksum, objtype, &temp_path, cancellable, error))
         goto out;
     }
 
   if (temp_path)
     {
       file_info = g_file_query_info (temp_path, OSTREE_GIO_FAST_QUERYINFO,
-                                     G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, error);
+                                     G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error);
       if (!file_info)
         goto out;
       
-      input = (GInputStream*)g_file_read (temp_path, NULL, error);
+      input = (GInputStream*)g_file_read (temp_path, cancellable, error);
       if (!input)
         goto out;
     }
   
   if (pending_path || temp_path)
     {
-      if (!ostree_repo_stage_object (repo, objtype, checksum, file_info, NULL, input, NULL, error))
+      if (!ostree_repo_stage_object (repo, objtype, checksum, file_info, NULL, input, cancellable, error))
         goto out;
 
       log_verbose ("Staged object: %s.%s", checksum, ostree_object_type_to_string (objtype));
@@ -253,6 +294,7 @@ fetch_and_store_tree_recurse (OstreeRepo   *repo,
                               SoupSession  *soup,
                               SoupURI      *base_uri,
                               const char   *rev,
+                              GCancellable *cancellable,
                               GError      **error)
 {
   gboolean ret = FALSE;
@@ -270,7 +312,8 @@ fetch_and_store_tree_recurse (OstreeRepo   *repo,
   GFile *pending_path = NULL;
   GInputStream *input = NULL;
 
-  if (!fetch_and_store_object (repo, soup, base_uri, rev, OSTREE_OBJECT_TYPE_DIR_TREE, &is_pending, &tree, error))
+  if (!fetch_and_store_object (repo, soup, base_uri, rev, OSTREE_OBJECT_TYPE_DIR_TREE,
+                               &is_pending, &tree, cancellable, error))
     goto out;
 
   if (!is_pending)
@@ -302,13 +345,13 @@ fetch_and_store_tree_recurse (OstreeRepo   *repo,
           if (ostree_repo_get_mode (repo) == OSTREE_REPO_MODE_BARE)
             {
               if (!ostree_repo_find_object (repo, OSTREE_OBJECT_TYPE_RAW_FILE, checksum,
-                                            &stored_path, &pending_path, NULL, error))
+                                            &stored_path, &pending_path, cancellable, error))
                 goto out;
             }
           else
             {
               if (!ostree_repo_find_object (repo, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT, checksum,
-                                            &stored_path, &pending_path, NULL, error))
+                                            &stored_path, &pending_path, cancellable, error))
                 goto out;
             }
 
@@ -321,6 +364,7 @@ fetch_and_store_tree_recurse (OstreeRepo   *repo,
               if (!fetch_object (repo, soup, base_uri, checksum,
                                  OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META,
                                  &meta_temp_path,
+                                 cancellable,
                                  error))
                 goto out;
 
@@ -337,10 +381,11 @@ fetch_and_store_tree_recurse (OstreeRepo   *repo,
                   if (!fetch_object (repo, soup, base_uri, checksum,
                                      OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT,
                                      &content_temp_path,
+                                     cancellable,
                                      error))
                     goto out;
                   
-                  input = (GInputStream*)g_file_read (content_temp_path, NULL, error);
+                  input = (GInputStream*)g_file_read (content_temp_path, cancellable, error);
                   if (!input)
                     goto out;
                 }
@@ -353,7 +398,7 @@ fetch_and_store_tree_recurse (OstreeRepo   *repo,
               if (!ostree_repo_stage_object (repo, OSTREE_OBJECT_TYPE_RAW_FILE,
                                              checksum,
                                              archive_file_info, archive_xattrs, input,
-                                             NULL, error))
+                                             cancellable, error))
                 goto out;
             }
               
@@ -386,10 +431,11 @@ fetch_and_store_tree_recurse (OstreeRepo   *repo,
           if (!ostree_validate_checksum_string (meta_checksum, error))
             goto out;
 
-          if (!fetch_and_store_object (repo, soup, base_uri, meta_checksum, OSTREE_OBJECT_TYPE_DIR_META, NULL, NULL, error))
+          if (!fetch_and_store_object (repo, soup, base_uri, meta_checksum, OSTREE_OBJECT_TYPE_DIR_META,
+                                       NULL, NULL, cancellable, error))
             goto out;
 
-          if (!fetch_and_store_tree_recurse (repo, soup, base_uri, tree_checksum, error))
+          if (!fetch_and_store_tree_recurse (repo, soup, base_uri, tree_checksum, cancellable, error))
             goto out;
         }
     }
@@ -423,6 +469,7 @@ fetch_and_store_commit_recurse (OstreeRepo   *repo,
                                 SoupSession  *soup,
                                 SoupURI      *base_uri,
                                 const char   *rev,
+                                GCancellable *cancellable,
                                 GError      **error)
 {
   gboolean ret = FALSE;
@@ -431,7 +478,8 @@ fetch_and_store_commit_recurse (OstreeRepo   *repo,
   const char *tree_meta_checksum;
   gboolean is_pending;
 
-  if (!fetch_and_store_object (repo, soup, base_uri, rev, OSTREE_OBJECT_TYPE_COMMIT, &is_pending, &commit, error))
+  if (!fetch_and_store_object (repo, soup, base_uri, rev, OSTREE_OBJECT_TYPE_COMMIT,
+                               &is_pending, &commit, cancellable, error))
     goto out;
 
   if (!is_pending)
@@ -442,10 +490,12 @@ fetch_and_store_commit_recurse (OstreeRepo   *repo,
       g_variant_get_child (commit, 6, "&s", &tree_contents_checksum);
       g_variant_get_child (commit, 7, "&s", &tree_meta_checksum);
       
-      if (!fetch_and_store_object (repo, soup, base_uri, tree_meta_checksum, OSTREE_OBJECT_TYPE_DIR_META, NULL, NULL, error))
+      if (!fetch_and_store_object (repo, soup, base_uri, tree_meta_checksum, OSTREE_OBJECT_TYPE_DIR_META,
+                                   NULL, NULL, cancellable, error))
         goto out;
       
-      if (!fetch_and_store_tree_recurse (repo, soup, base_uri, tree_contents_checksum, error))
+      if (!fetch_and_store_tree_recurse (repo, soup, base_uri, tree_contents_checksum,
+                                         cancellable, error))
         goto out;
     }
 
@@ -454,6 +504,152 @@ fetch_and_store_commit_recurse (OstreeRepo   *repo,
   ot_clear_gvariant (&commit);
   return ret;
 }
+
+static gboolean
+fetch_ref_contents (OstreeRepo    *repo,
+                    SoupSession   *soup,
+                    SoupURI       *base_uri,
+                    const char    *ref,
+                    char         **out_contents,
+                    GCancellable  *cancellable,
+                    GError       **error)
+{
+  gboolean ret = FALSE;
+  char *ret_contents = NULL;
+  char *refpath = NULL;
+  SoupURI *target_uri = NULL;
+
+  target_uri = soup_uri_copy (base_uri);
+  refpath = g_build_filename (soup_uri_get_path (target_uri), "refs", "heads", ref, NULL);
+  soup_uri_set_path (target_uri, refpath);
+  
+  if (!fetch_uri_contents_utf8 (repo, soup, target_uri, &ret_contents, cancellable, error))
+    goto out;
+
+  g_strchomp (ret_contents);
+
+  if (!ostree_validate_checksum_string (ret_contents, error))
+    goto out;
+
+  ret = TRUE;
+  ot_transfer_out_value (out_contents, &ret_contents);
+ out:
+  g_free (refpath);
+  g_free (ret_contents);
+  if (target_uri)
+    soup_uri_free (target_uri);
+  return ret;
+}
+
+static gboolean
+pull_one_commit (OstreeRepo       *repo,
+                 const char       *remote,
+                 const char       *branch,
+                 const char       *rev,
+                 SoupSession      *soup,
+                 SoupURI          *base_uri,
+                 GCancellable     *cancellable,
+                 GError          **error)
+{
+  gboolean ret = FALSE;
+  char *key = NULL;
+  char *remote_ref = NULL;
+  char *baseurl = NULL;
+  char *original_rev = NULL;
+
+  remote_ref = g_strdup_printf ("%s/%s", remote, branch);
+
+  if (!ostree_repo_resolve_rev (repo, remote_ref, TRUE, &original_rev, error))
+    goto out;
+
+  if (original_rev && strcmp (rev, original_rev) == 0)
+    {
+      g_print ("No changes in %s\n", remote_ref);
+    }
+  else
+    {
+      if (!ostree_validate_checksum_string (rev, error))
+        goto out;
+
+      if (!ostree_repo_prepare_transaction (repo, NULL, error))
+        goto out;
+      
+      if (!fetch_and_store_commit_recurse (repo, soup, base_uri, rev, cancellable, error))
+        goto out;
+
+      if (!ostree_repo_commit_transaction (repo, cancellable, error))
+        goto out;
+      
+      if (!ostree_repo_write_ref (repo, remote, branch, rev, error))
+        goto out;
+      
+      g_print ("remote %s is now %s\n", remote_ref, rev);
+    }
+
+  ret = TRUE;
+ out:
+  g_free (key);
+  g_free (remote_ref);
+  g_free (baseurl);
+  g_free (original_rev);
+  return ret;
+}
+
+static gboolean
+parse_ref_summary (const char    *contents,
+                   GHashTable   **out_refs,
+                   GError       **error)
+{
+  gboolean ret = FALSE;
+  GHashTable *ret_refs = NULL;
+  char **lines = NULL;
+  char **iter = NULL;
+  char *ref = NULL;
+  char *sha256 = NULL;
+
+  ret_refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+  lines = g_strsplit_set (contents, "\n", -1);
+  for (iter = lines; *iter; iter++)
+    {
+      const char *line = *iter;
+      const char *spc;
+
+      if (!*line)
+        continue;
+
+      spc = strchr (line, ' ');
+      if (!spc)
+        {
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                       "Invalid ref summary file; missing ' ' in line");
+          goto out;
+        }
+
+      g_free (ref);
+      ref = g_strdup (spc + 1);
+      if (!ostree_validate_rev (ref, error))
+        goto out;
+      
+      g_free (sha256);
+      sha256 = g_strndup (line, spc - line);
+      if (!ostree_validate_checksum_string (sha256, error))
+        goto out;
+
+      g_hash_table_replace (ret_refs, ref, sha256);
+      /* Transfer ownership */
+      ref = NULL;
+      sha256 = NULL;
+    }
+
+  ret = TRUE;
+  ot_transfer_out_value (out_refs, &ret_refs);
+ out:
+  if (ret_refs)
+    g_hash_table_unref (ret_refs);
+  g_strfreev (lines);
+  return ret;
+}
                       
 static gboolean
 ostree_builtin_pull (int argc, char **argv, GFile *repo_path, GError **error)
@@ -463,19 +659,20 @@ ostree_builtin_pull (int argc, char **argv, GFile *repo_path, GError **error)
   OstreeRepo *repo = NULL;
   const char *remote;
   const char *branch;
-  char *key = NULL;
+  SoupSession *soup = NULL;
+  char *path = NULL;
   char *baseurl = NULL;
-  char *refpath = NULL;
-  GFile *tempf = NULL;
-  char *remote_ref = NULL;
-  char *original_rev = NULL;
-  GKeyFile *config = NULL;
+  char *summary_data = NULL;
   SoupURI *base_uri = NULL;
-  SoupURI *target_uri = NULL;
-  SoupSession *soup = NULL;
-  char *rev = NULL;
+  SoupURI *summary_uri = NULL;
+  GKeyFile *config = NULL;
+  GCancellable *cancellable = NULL;
+  GHashTable *refs_to_fetch = NULL;
+  GHashTableIter hash_iter;
+  gpointer key, value;
+  char *branch_rev = NULL;
 
-  context = g_option_context_new ("REMOTE BRANCH - Download data from remote repository");
+  context = g_option_context_new ("REMOTE [BRANCH] - Download data from remote repository");
   g_option_context_add_main_entries (context, options, NULL);
 
   if (!g_option_context_parse (context, &argc, &argv, error))
@@ -485,19 +682,21 @@ ostree_builtin_pull (int argc, char **argv, GFile *repo_path, GError **error)
   if (!ostree_repo_check (repo, error))
     goto out;
 
-  if (argc < 3)
+  if (argc < 2)
     {
-      ot_util_usage_error (context, "REMOTE and BRANCH must be specified", error);
+      ot_util_usage_error (context, "REMOTE must be specified", error);
       goto out;
     }
 
   remote = argv[1];
-  branch = argv[2];
-
-  remote_ref = g_strdup_printf ("%s/%s", remote, branch);
+  if (argc == 2)
+    branch = NULL;
+  else
+    branch = argv[2];
 
-  if (!ostree_repo_resolve_rev (repo, remote_ref, TRUE, &original_rev, error))
-    goto out;
+  soup = soup_session_sync_new_with_options (SOUP_SESSION_USER_AGENT, "ostree ",
+                                             SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_COOKIE_JAR,
+                                             NULL);
 
   config = ostree_repo_get_config (repo);
 
@@ -506,69 +705,64 @@ ostree_builtin_pull (int argc, char **argv, GFile *repo_path, GError **error)
   if (!baseurl)
     goto out;
   base_uri = soup_uri_new (baseurl);
+
   if (!base_uri)
     {
       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                    "Failed to parse url '%s'", baseurl);
       goto out;
     }
-  target_uri = soup_uri_copy (base_uri);
-  g_free (refpath);
-  refpath = g_build_filename (soup_uri_get_path (target_uri), "refs", "heads", branch, NULL);
-  soup_uri_set_path (target_uri, refpath);
-  
-  soup = soup_session_sync_new_with_options (SOUP_SESSION_USER_AGENT, "ostree ",
-                                             SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_COOKIE_JAR,
-                                             NULL);
-  if (!fetch_uri (repo, soup, target_uri, "ref-", &tempf, error))
-    goto out;
 
-  if (!ot_gfile_load_contents_utf8 (tempf, &rev, NULL, NULL, error))
-    goto out;
-  g_strchomp (rev);
-
-  if (original_rev && strcmp (rev, original_rev) == 0)
+  if (branch != NULL)
     {
-      g_print ("No changes in %s\n", remote_ref);
+      char *contents;
+
+      if (!fetch_ref_contents (repo, soup, base_uri, branch, &contents, cancellable, error))
+        goto out;
+      
+      /* Transfer ownership of contents */
+      refs_to_fetch = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+      g_hash_table_insert (refs_to_fetch, g_strdup (branch), contents);
     }
   else
     {
-      if (!ostree_validate_checksum_string (rev, error))
-        goto out;
+      summary_uri = soup_uri_copy (base_uri);
+      path = g_build_filename (soup_uri_get_path (summary_uri), "refs", "summary", NULL);
+      soup_uri_set_path (summary_uri, path);
 
-      if (!ostree_repo_prepare_transaction (repo, NULL, error))
-        goto out;
-      
-      if (!fetch_and_store_commit_recurse (repo, soup, base_uri, rev, error))
+      if (!fetch_uri_contents_utf8 (repo, soup, summary_uri, &summary_data, cancellable, error))
         goto out;
 
-      if (!ostree_repo_commit_transaction (repo, NULL, error))
+      if (!parse_ref_summary (summary_data, &refs_to_fetch, error))
         goto out;
+    }
+
+  g_hash_table_iter_init (&hash_iter, refs_to_fetch);
+
+  while (g_hash_table_iter_next (&hash_iter, &key, &value))
+    {
+      const char *ref = key;
+      const char *sha256 = value;
       
-      if (!ostree_repo_write_ref (repo, remote, branch, rev, error))
+      if (!pull_one_commit (repo, remote, ref, sha256, soup, base_uri, cancellable, error))
         goto out;
-      
-      g_print ("remote %s is now %s\n", remote_ref, rev);
     }
- 
+
   ret = TRUE;
  out:
+  if (refs_to_fetch)
+    g_hash_table_unref (refs_to_fetch);
+  g_free (path);
+  g_free (baseurl);
+  g_free (summary_data);
+  g_free (branch_rev);
   if (context)
     g_option_context_free (context);
-  if (tempf)
-    (void) unlink (ot_gfile_get_path_cached (tempf));
-  g_clear_object (&tempf);
-  g_free (key);
-  g_free (rev);
-  g_free (remote_ref);
-  g_free (original_rev);
-  g_free (baseurl);
-  g_free (refpath);
   g_clear_object (&soup);
   if (base_uri)
     soup_uri_free (base_uri);
-  if (target_uri)
-    soup_uri_free (target_uri);
+  if (summary_uri)
+    soup_uri_free (summary_uri);
   g_clear_object (&repo);
   g_clear_object (&soup);
   return ret;



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