[ostree] Add OstreeAsyncProgress, use it for ostree_repo_pull



commit c65923e64241ddeffbbfe48555150fd4d0ec1a8c
Author: Colin Walters <walters verbum org>
Date:   Thu Oct 24 09:10:34 2013 -0400

    Add OstreeAsyncProgress, use it for ostree_repo_pull
    
    Several APIs in libostree were moved there from the commandline code,
    and have hardcoded g_print() for progress and notifications.  This
    isn't useful for people who want to write PackageKit backends, custom
    GUIs and the like.
    
    From what I can tell, there isn't really a winning precedent in GLib
    for progress notifications.
    
    PackageKit has the model where the source has GObject properties that
    change as async ops execute, which isn't bad...but I'd like something
    a bit more general where say you can have multiple outstanding async
    ops and sensibly track their state.
    
    So, OstreeAsyncProgress is basically a threadsafe property bag with a
    change notification signal.
    
    Use this new API to move the GSConsole usage (i.e. g_print()) out from
    libostree/ and into ostree/.

 Makefile-libostree-defines.am         |    1 +
 Makefile-libostree.am                 |    1 +
 Makefile-ostree.am                    |    2 +
 src/libostree/ostree-async-progress.c |  272 +++++++++++++++++++++++++++++++++
 src/libostree/ostree-async-progress.h |   68 ++++++++
 src/libostree/ostree-repo-pull.c      |   71 ++++------
 src/libostree/ostree-repo.c           |    2 +
 src/libostree/ostree-repo.h           |    2 +
 src/libostree/ostree.h                |    5 +-
 src/ostree/ot-admin-builtin-upgrade.c |    9 +-
 src/ostree/ot-builtin-pull.c          |   12 ++-
 src/ostree/ot-builtins-common.c       |   75 +++++++++
 src/ostree/ot-builtins-common.h       |   27 ++++
 tests/test-sysroot.js                 |    6 +-
 14 files changed, 501 insertions(+), 52 deletions(-)
---
diff --git a/Makefile-libostree-defines.am b/Makefile-libostree-defines.am
index 4be0eec..6b07d0e 100644
--- a/Makefile-libostree-defines.am
+++ b/Makefile-libostree-defines.am
@@ -20,6 +20,7 @@
 
 libostree_public_headers = \
        src/libostree/ostree.h \
+       src/libostree/ostree-async-progress.h \
        src/libostree/ostree-core.h \
        src/libostree/ostree-mutable-tree.h \
        src/libostree/ostree-repo.h \
diff --git a/Makefile-libostree.am b/Makefile-libostree.am
index 9a3fe2b..b2b90bb 100644
--- a/Makefile-libostree.am
+++ b/Makefile-libostree.am
@@ -25,6 +25,7 @@ libostreeincludedir = $(includedir)/ostree-1
 libostreeinclude_HEADERS = $(libostree_public_headers)
 
 libostree_1_la_SOURCES = \
+       src/libostree/ostree-async-progress.c \
        src/libostree/ostree-core-private.h \
        src/libostree/ostree-core.c \
        src/libostree/ostree-checksum-input-stream.c \
diff --git a/Makefile-ostree.am b/Makefile-ostree.am
index f2a3615..86b6be0 100644
--- a/Makefile-ostree.am
+++ b/Makefile-ostree.am
@@ -20,6 +20,8 @@
 bin_PROGRAMS += ostree
 
 ostree_SOURCES = src/ostree/main.c \
+       src/ostree/ot-builtins-common.h \
+       src/ostree/ot-builtins-common.c \
        src/ostree/ot-builtin-admin.c \
        src/ostree/ot-builtins.h \
        src/ostree/ot-builtin-cat.c \
diff --git a/src/libostree/ostree-async-progress.c b/src/libostree/ostree-async-progress.c
new file mode 100644
index 0000000..fa7e60b
--- /dev/null
+++ b/src/libostree/ostree-async-progress.c
@@ -0,0 +1,272 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2013 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "ostree-async-progress.h"
+#include "libgsystem.h"
+
+/**
+ * SECTION:libostree-async-progress
+ * @title: Progress notification system for asynchronous operations
+ * @short_description: Values representing progress
+ *
+ * For many asynchronous operations, it's desirable for callers to be
+ * able to watch their status as they progress.  For example, an user
+ * interface calling an asynchronous download operation will want to
+ * be able to see the total number of bytes downloaded.
+ *
+ * This class provides a mechanism for callees of asynchronous
+ * operations to communicate back with callers.  It transparently
+ * handles thread safety, ensuring that the progress change
+ * notification occurs in the thread-default context of the calling
+ * operation.
+ */
+
+#if GLIB_SIZEOF_VOID_P == 8
+#define _OSTREE_HAVE_LP64 1
+#else
+#define _OSTREE_HAVE_LP64 0
+#endif
+
+enum {
+  CHANGED,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+struct OstreeAsyncProgress
+{
+  GObject parent_instance;
+
+  GMutex lock;
+  GMainContext *maincontext;
+  GSource *idle_source;
+  GHashTable *uint_values;
+  GHashTable *uint64_values;
+
+  char *status;
+};
+
+G_DEFINE_TYPE (OstreeAsyncProgress, ostree_async_progress, G_TYPE_OBJECT)
+
+static void
+ostree_async_progress_finalize (GObject *object)
+{
+  OstreeAsyncProgress *self;
+
+  self = OSTREE_ASYNC_PROGRESS (object);
+
+  g_mutex_clear (&self->lock);
+  g_clear_pointer (&self->maincontext, g_main_context_unref);
+  g_clear_pointer (&self->idle_source, g_source_unref);
+  g_hash_table_unref (self->uint_values);
+  g_hash_table_unref (self->uint64_values);
+  g_free (self->status);
+
+  G_OBJECT_CLASS (ostree_async_progress_parent_class)->finalize (object);
+}
+
+static void
+ostree_async_progress_class_init (OstreeAsyncProgressClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = ostree_async_progress_finalize;
+
+  /**
+   * OstreeAsyncProgress::changed:
+   * @self: Self
+   *
+   * Emitted when @self has been changed.
+   **/
+  signals[CHANGED] =
+    g_signal_new ("changed",
+                 OSTREE_TYPE_ASYNC_PROGRESS,
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (OstreeAsyncProgressClass, changed),
+                 NULL, NULL,
+                 NULL,
+                 G_TYPE_NONE, 0);
+}
+
+static void
+ostree_async_progress_init (OstreeAsyncProgress *self)
+{
+  g_mutex_init (&self->lock);
+  self->maincontext = g_main_context_ref_thread_default ();
+  self->uint_values = g_hash_table_new (NULL, NULL);
+#if _OSTREE_HAVE_LP64
+  self->uint64_values = g_hash_table_new (NULL, NULL);
+#else
+  self->uint64_values = g_hash_table_new_full (NULL, NULL,
+                                               NULL, g_free);
+#endif
+}
+
+guint
+ostree_async_progress_get_uint (OstreeAsyncProgress       *self,
+                                const char                *key)
+{
+  guint rval;
+  g_mutex_lock (&self->lock);
+  rval = GPOINTER_TO_UINT (g_hash_table_lookup (self->uint_values,
+                                                GUINT_TO_POINTER (g_quark_from_string (key))));
+  g_mutex_unlock (&self->lock);
+  return rval;
+}
+
+guint64
+ostree_async_progress_get_uint64 (OstreeAsyncProgress       *self,
+                                  const char                *key)
+{
+#if _OSTREE_HAVE_LP64
+  guint64 rval;
+  g_mutex_lock (&self->lock);
+  rval = (guint64) g_hash_table_lookup (self->uint64_values, GUINT_TO_POINTER (g_quark_from_string (key)));
+  g_mutex_unlock (&self->lock);
+  return rval;
+#else
+  guint64 *rval;
+  g_mutex_lock (&self->lock);
+  rval = g_hash_table_lookup (self->uint64_values, (gpointer)g_quark_from_string (key));
+  g_mutex_unlock (&self->lock);
+  if (rval)
+    return *rval;
+  return 0;
+#endif
+}
+
+static gboolean
+idle_invoke_async_progress (gpointer user_data)
+{
+  OstreeAsyncProgress *self = user_data;
+
+  g_mutex_lock (&self->lock);
+  self->idle_source = NULL;
+  g_mutex_unlock (&self->lock);
+
+  g_signal_emit (self, signals[CHANGED], 0);
+
+  return FALSE;
+}
+
+static void
+ensure_callback_locked (OstreeAsyncProgress *self)
+{
+  if (self->idle_source)
+    return;
+  self->idle_source = g_idle_source_new ();
+  g_source_set_callback (self->idle_source, idle_invoke_async_progress, self, NULL);
+  g_source_attach (self->idle_source, self->maincontext);
+}
+
+void
+ostree_async_progress_set_status (OstreeAsyncProgress       *self,
+                                  const char                *status)
+{
+  g_mutex_lock (&self->lock);
+  g_free (self->status);
+  self->status = g_strdup (status);
+  ensure_callback_locked (self);
+  g_mutex_unlock (&self->lock);
+}
+
+char *
+ostree_async_progress_get_status (OstreeAsyncProgress       *self)
+{
+  char *ret;
+  g_mutex_lock (&self->lock);
+  ret = g_strdup (self->status);
+  g_mutex_unlock (&self->lock);
+  return ret;
+}
+
+static void
+update_key (OstreeAsyncProgress   *self,
+            GHashTable            *hash,
+            const char            *key,
+            gpointer               value)
+{
+  gpointer orig_value;
+  gpointer qkey = GUINT_TO_POINTER (g_quark_from_string (key));
+
+  g_mutex_lock (&self->lock);
+
+  if (g_hash_table_lookup_extended (hash, qkey, NULL, &orig_value))
+    {
+      if (orig_value == value)
+        goto out;
+    }
+  g_hash_table_replace (hash, qkey, value);
+  ensure_callback_locked (self);
+
+ out:
+  g_mutex_unlock (&self->lock);
+}
+
+void
+ostree_async_progress_set_uint (OstreeAsyncProgress       *self,
+                                const char                *key,
+                                guint                      value)
+{
+  update_key (self, self->uint_values, key, GUINT_TO_POINTER (value));
+}
+
+void
+ostree_async_progress_set_uint64 (OstreeAsyncProgress       *self,
+                                  const char                *key,
+                                  guint64                    value)
+{
+  gpointer valuep;
+
+#if _OSTREE_HAVE_LP64
+  valuep = (gpointer)value;
+#else
+  {
+    guint64 *boxed = g_malloc (sizeof (guint64));
+    *boxed = value;
+    valuep = boxed;
+  }
+#endif
+  update_key (self, self->uint64_values, key, valuep);
+}
+
+/**
+ * ostree_async_progress_new:
+ *
+ * Returns: (transfer full): A new progress object
+ */
+OstreeAsyncProgress *
+ostree_async_progress_new (void)
+{
+  return (OstreeAsyncProgress*)g_object_new (OSTREE_TYPE_ASYNC_PROGRESS, NULL);
+}
+
+
+OstreeAsyncProgress *
+ostree_async_progress_new_and_connect (void (*changed) (OstreeAsyncProgress *self, gpointer user_data),
+                                       gpointer user_data)
+{
+  OstreeAsyncProgress *ret = ostree_async_progress_new ();
+  g_signal_connect (ret, "changed", G_CALLBACK (changed), user_data);
+  return ret;
+}
diff --git a/src/libostree/ostree-async-progress.h b/src/libostree/ostree-async-progress.h
new file mode 100644
index 0000000..71b2fba
--- /dev/null
+++ b/src/libostree/ostree-async-progress.h
@@ -0,0 +1,68 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2013 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#pragma once
+
+#include "ostree-types.h"
+
+G_BEGIN_DECLS
+
+#define OSTREE_TYPE_ASYNC_PROGRESS         (ostree_async_progress_get_type ())
+#define OSTREE_ASYNC_PROGRESS(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_ASYNC_PROGRESS, 
OstreeAsyncProgress))
+#define OSTREE_ASYNC_PROGRESS_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_ASYNC_PROGRESS, 
OstreeAsyncProgressClass))
+#define OSTREE_IS_ASYNC_PROGRESS(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_ASYNC_PROGRESS))
+#define OSTREE_IS_ASYNC_PROGRESS_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_ASYNC_PROGRESS))
+#define OSTREE_ASYNC_PROGRESS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_ASYNC_PROGRESS, 
OstreeAsyncProgressClass))
+
+typedef struct OstreeAsyncProgress   OstreeAsyncProgress;
+typedef struct OstreeAsyncProgressClass   OstreeAsyncProgressClass;
+
+struct OstreeAsyncProgressClass
+{
+  GObjectClass parent_class;
+
+  void (*changed) (OstreeAsyncProgress *self, gpointer user_data);
+};
+
+GType   ostree_async_progress_get_type (void) G_GNUC_CONST;
+
+OstreeAsyncProgress *ostree_async_progress_new (void);
+
+OstreeAsyncProgress *ostree_async_progress_new_and_connect (void (*changed) (OstreeAsyncProgress *self, 
gpointer user_data), gpointer user_data);
+
+char *ostree_async_progress_get_status (OstreeAsyncProgress       *self);
+
+guint ostree_async_progress_get_uint (OstreeAsyncProgress       *self,
+                                      const char                *key);
+guint64 ostree_async_progress_get_uint64 (OstreeAsyncProgress       *self,
+                                          const char                *key);
+
+void ostree_async_progress_set_status (OstreeAsyncProgress       *self,
+                                       const char                *status);
+
+void ostree_async_progress_set_uint (OstreeAsyncProgress       *self,
+                                     const char                *key,
+                                     guint                      value);
+void ostree_async_progress_set_uint64 (OstreeAsyncProgress       *self,
+                                       const char                *key,
+                                       guint64                    value);
+
+G_END_DECLS
+
diff --git a/src/libostree/ostree-repo-pull.c b/src/libostree/ostree-repo-pull.c
index 58cef3f..ce1af2a 100644
--- a/src/libostree/ostree-repo-pull.c
+++ b/src/libostree/ostree-repo-pull.c
@@ -87,6 +87,7 @@ typedef struct {
   GMainContext    *main_context;
   GMainLoop    *loop;
   GCancellable *cancellable;
+  OstreeAsyncProgress *progress;
 
   gboolean      transaction_resuming;
   volatile gint n_scanned_metadata;
@@ -179,47 +180,35 @@ suburi_new (SoupURI   *base,
 }
 
 static gboolean
-uri_fetch_update_status (gpointer user_data)
+update_progress (gpointer user_data)
 {
   OtPullData *pull_data = user_data;
-  GString *status;
-  guint outstanding_writes;
-  guint outstanding_fetches;
+  guint outstanding_writes = pull_data->n_outstanding_content_write_requests +
+    pull_data->n_outstanding_metadata_write_requests;
+  guint outstanding_fetches = pull_data->n_outstanding_content_fetches +
+    pull_data->n_outstanding_metadata_fetches;
+  guint64 bytes_transferred = ostree_fetcher_bytes_transferred (pull_data->fetcher);
+  guint fetched = pull_data->n_fetched_metadata + pull_data->n_fetched_content;
+  guint requested = pull_data->n_requested_metadata + pull_data->n_requested_content;
+  guint n_scanned_metadata = g_atomic_int_get (&pull_data->n_scanned_metadata);
  
-  status = g_string_new ("");
+  g_assert (pull_data->progress);
 
-  outstanding_fetches = pull_data->n_outstanding_content_fetches + pull_data->n_outstanding_metadata_fetches;
-  outstanding_writes = pull_data->n_outstanding_content_write_requests + 
pull_data->n_outstanding_metadata_write_requests;
+  ostree_async_progress_set_uint (pull_data->progress, "outstanding-fetches", outstanding_fetches);
+  ostree_async_progress_set_uint (pull_data->progress, "outstanding-writes", outstanding_writes);
+  ostree_async_progress_set_uint (pull_data->progress, "fetched", fetched);
+  ostree_async_progress_set_uint (pull_data->progress, "requested", requested);
+  ostree_async_progress_set_uint (pull_data->progress, "scanned-metadata", n_scanned_metadata);
+  ostree_async_progress_set_uint64 (pull_data->progress, "bytes-transferred", bytes_transferred);
 
   if (pull_data->fetching_sync_uri)
     {
       gs_free char *uri_string = soup_uri_to_string (pull_data->fetching_sync_uri, TRUE);
-      g_string_append_printf (status, "Requesting %s", uri_string);
+      gs_free char *status_string = g_strconcat ("Requesting %s", uri_string, NULL);
+      ostree_async_progress_set_status (pull_data->progress, status_string);
     }
-  else if (outstanding_fetches)
-    {
-      guint64 bytes_transferred = ostree_fetcher_bytes_transferred (pull_data->fetcher);
-      guint fetched = pull_data->n_fetched_metadata + pull_data->n_fetched_content;
-      guint requested = pull_data->n_requested_metadata + pull_data->n_requested_content;
-      gs_free char *formatted_bytes_transferred = NULL;
-
-      formatted_bytes_transferred = g_format_size_full (bytes_transferred, 0);
-
-      g_string_append_printf (status, "Receiving objects: %u%% (%u/%u) %s",
-                              (guint)((((double)fetched) / requested) * 100),
-                              fetched, requested, formatted_bytes_transferred);
-    }
-  else if (outstanding_writes > 0)
-    g_string_append_printf (status, "Writing objects: %u", outstanding_writes);
-  else if (!pull_data->metadata_scan_idle)
-    g_string_append_printf (status, "Scanning metadata: %u",
-                            g_atomic_int_get (&pull_data->n_scanned_metadata));
   else
-    g_string_append_printf (status, "Idle");
-
-  gs_console_begin_status_line (gs_console_get (), status->str, NULL, NULL);
-
-  g_string_free (status, TRUE);
+    ostree_async_progress_set_status (pull_data->progress, NULL);
 
   return TRUE;
 }
@@ -303,31 +292,23 @@ static gboolean
 run_mainloop_monitor_fetcher (OtPullData   *pull_data)
 {
   GSource *update_timeout = NULL;
-  GSConsole *console;
   GSource *idle_src;
 
-  console = gs_console_get ();
-
-  if (console)
+  if (pull_data->progress)
     {
-      gs_console_begin_status_line (console, "", NULL, NULL);
-
       update_timeout = g_timeout_source_new_seconds (1);
-      g_source_set_callback (update_timeout, uri_fetch_update_status, pull_data, NULL);
+      g_source_set_callback (update_timeout, update_progress, pull_data, NULL);
       g_source_attach (update_timeout, g_main_loop_get_context (pull_data->loop));
       g_source_unref (update_timeout);
     }
-  
+
   idle_src = g_idle_source_new ();
   g_source_set_callback (idle_src, idle_check_outstanding_requests, pull_data, NULL);
   g_source_attach (idle_src, pull_data->main_context);
   g_main_loop_run (pull_data->loop);
 
-  if (console)
-    {
-      gs_console_end_status_line (console, NULL, NULL);
-      g_source_destroy (update_timeout);
-    }
+  if (update_timeout)
+    g_source_destroy (update_timeout);
 
   return !pull_data->caught_error;
 }
@@ -1198,6 +1179,7 @@ ostree_repo_pull (OstreeRepo               *self,
                   const char               *remote_name,
                   char                    **refs_to_fetch,
                   OstreeRepoPullFlags       flags,
+                  OstreeAsyncProgress      *progress,
                   GCancellable             *cancellable,
                   GError                  **error)
 {
@@ -1231,6 +1213,7 @@ ostree_repo_pull (OstreeRepo               *self,
   pull_data->flags = flags;
 
   pull_data->repo = self;
+  pull_data->progress = progress;
 
   pull_data->scanned_metadata = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal,
                                                        (GDestroyNotify)g_variant_unref, NULL);
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index e7a26bc..b13a245 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -1454,6 +1454,7 @@ ostree_repo_read_commit (OstreeRepo   *self,
  * @remote_name: Name of remote
  * @refs_to_fetch: (array zero-terminated=1) (element-type utf8) (allow-none): Optional list of refs; if 
%NULL, fetch all configured refs
  * @flags: Options controlling fetch behavior
+ * @progress: (allow-none): Progress
  * @cancellable: Cancellable
  * @error: Error
  *
@@ -1467,6 +1468,7 @@ ostree_repo_pull (OstreeRepo               *self,
                   const char               *remote_name,
                   char                    **refs_to_fetch,
                   OstreeRepoPullFlags       flags,
+                  OstreeAsyncProgress      *progress,
                   GCancellable             *cancellable,
                   GError                  **error)
 {
diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h
index 4f3e9d6..6a97f6b 100644
--- a/src/libostree/ostree-repo.h
+++ b/src/libostree/ostree-repo.h
@@ -24,6 +24,7 @@
 
 #include "ostree-core.h"
 #include "ostree-types.h"
+#include "ostree-async-progress.h"
 
 G_BEGIN_DECLS
 
@@ -461,6 +462,7 @@ gboolean ostree_repo_pull (OstreeRepo             *self,
                            const char             *remote_name,
                            char                  **refs_to_fetch,
                            OstreeRepoPullFlags     flags,
+                           OstreeAsyncProgress    *progress,
                            GCancellable           *cancellable,
                            GError                **error);
 
diff --git a/src/libostree/ostree.h b/src/libostree/ostree.h
index 730b616..f1e7450 100644
--- a/src/libostree/ostree.h
+++ b/src/libostree/ostree.h
@@ -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,2013 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
@@ -16,12 +16,11 @@
  * License along with this library; if not, write to the
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters verbum org>
  */
 
 #pragma once
 
+#include <ostree-async-progress.h>
 #include <ostree-core.h>
 #include <ostree-repo.h>
 #include <ostree-mutable-tree.h>
diff --git a/src/ostree/ot-admin-builtin-upgrade.c b/src/ostree/ot-admin-builtin-upgrade.c
index 3beb7c9..3eeb18a 100644
--- a/src/ostree/ot-admin-builtin-upgrade.c
+++ b/src/ostree/ot-admin-builtin-upgrade.c
@@ -24,6 +24,7 @@
 
 #include "ot-admin-builtins.h"
 #include "ot-admin-functions.h"
+#include "ot-builtins-common.h"
 #include "ostree.h"
 #include "otutil.h"
 #include "libgsystem.h"
@@ -106,10 +107,16 @@ ot_admin_builtin_upgrade (int argc, char **argv, OstreeSysroot *sysroot, GCancel
     {
       OstreeRepoPullFlags pullflags = 0;
       char *refs_to_fetch[] = { origin_ref, NULL };
+      GSConsole *console;
+      gs_unref_object OstreeAsyncProgress *progress = NULL;
+
+      console = gs_console_get ();
+      if (console)
+        progress = ostree_async_progress_new_and_connect (ot_common_pull_progress, console);
 
       g_print ("Fetching remote %s ref %s\n", origin_remote, origin_ref);
 
-      if (!ostree_repo_pull (repo, origin_remote, refs_to_fetch, pullflags,
+      if (!ostree_repo_pull (repo, origin_remote, refs_to_fetch, pullflags, progress,
                              cancellable, error))
         goto out;
     }
diff --git a/src/ostree/ot-builtin-pull.c b/src/ostree/ot-builtin-pull.c
index 630301e..67305fd 100644
--- a/src/ostree/ot-builtin-pull.c
+++ b/src/ostree/ot-builtin-pull.c
@@ -23,6 +23,7 @@
 #include "config.h"
 
 #include "ot-builtins.h"
+#include "ot-builtins-common.h"
 #include "ostree.h"
 #include "otutil.h"
 
@@ -37,7 +38,9 @@ ostree_builtin_pull (int argc, char **argv, OstreeRepo *repo, GCancellable *canc
   gboolean ret = FALSE;
   const char *remote;
   OstreeRepoPullFlags pullflags = 0;
+  GSConsole *console = NULL;
   gs_unref_ptrarray GPtrArray *refs_to_fetch = NULL;
+  gs_unref_object OstreeAsyncProgress *progress = NULL;
 
   context = g_option_context_new ("REMOTE [BRANCH...] - Download data from remote repository");
   g_option_context_add_main_entries (context, options, NULL);
@@ -61,9 +64,16 @@ ostree_builtin_pull (int argc, char **argv, OstreeRepo *repo, GCancellable *canc
       g_ptr_array_add (refs_to_fetch, NULL);
     }
 
+  console = gs_console_get ();
+  if (console)
+    progress = ostree_async_progress_new_and_connect (ot_common_pull_progress, console);
+
   if (!ostree_repo_pull (repo, remote, refs_to_fetch ? (char**)refs_to_fetch->pdata : NULL,
-                    pullflags, cancellable, error))
+                         pullflags, progress, cancellable, error))
     goto out;
+
+  if (console)
+    gs_console_end_status_line (console, NULL, NULL);
  
   ret = TRUE;
  out:
diff --git a/src/ostree/ot-builtins-common.c b/src/ostree/ot-builtins-common.c
new file mode 100644
index 0000000..8de6b60
--- /dev/null
+++ b/src/ostree/ot-builtins-common.c
@@ -0,0 +1,75 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2013 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "ot-builtins-common.h"
+#include "otutil.h"
+
+void
+ot_common_pull_progress (OstreeAsyncProgress       *progress,
+                         gpointer                   user_data)
+{
+  GSConsole *console = user_data;
+  GString *buf;
+  gs_free char *status = NULL;
+  guint outstanding_fetches;
+  guint outstanding_writes;
+  guint n_scanned_metadata;
+
+  if (!console)
+    return;
+
+  buf = g_string_new ("");
+
+  status = ostree_async_progress_get_status (progress);
+  outstanding_fetches = ostree_async_progress_get_uint (progress, "outstanding-fetches");
+  outstanding_writes = ostree_async_progress_get_uint (progress, "outstanding-writes");
+  n_scanned_metadata = ostree_async_progress_get_uint (progress, "scanned-metadata");
+  if (status)
+    {
+      g_string_append (buf, status);
+    }
+  else if (outstanding_fetches)
+    {
+      guint64 bytes_transferred = ostree_async_progress_get_uint64 (progress, "bytes-transferred");
+      guint fetched = ostree_async_progress_get_uint (progress, "fetched");
+      guint requested = ostree_async_progress_get_uint (progress, "requested");
+      gs_free char *formatted_bytes_transferred =
+        g_format_size_full (bytes_transferred, 0);
+
+      g_string_append_printf (buf, "Receiving objects: %u%% (%u/%u) %s",
+                              (guint)((((double)fetched) / requested) * 100),
+                              fetched, requested, formatted_bytes_transferred);
+    }
+  else if (outstanding_writes)
+    {
+      g_string_append_printf (buf, "Writing objects: %u", outstanding_writes);
+    }
+  else
+    {
+      g_string_append_printf (buf, "Scanning metadata: %u", n_scanned_metadata);
+    }
+
+  gs_console_begin_status_line (console, buf->str, NULL, NULL);
+  
+  g_string_free (buf, TRUE);
+  
+}
diff --git a/src/ostree/ot-builtins-common.h b/src/ostree/ot-builtins-common.h
new file mode 100644
index 0000000..deb599a
--- /dev/null
+++ b/src/ostree/ot-builtins-common.h
@@ -0,0 +1,27 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2013 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#pragma once
+
+#include <ostree.h>
+
+void
+ot_common_pull_progress (OstreeAsyncProgress       *progress,
+                         gpointer                   user_data);
diff --git a/tests/test-sysroot.js b/tests/test-sysroot.js
index 0271126..03ce2e4 100644
--- a/tests/test-sysroot.js
+++ b/tests/test-sysroot.js
@@ -68,7 +68,7 @@ sysrootRepoConfig.set_string(testosRefSection, 'url', 'file://' + upstreamRepo.g
 sysrootRepoConfig.set_boolean(testosRefSection, 'gpg-verify', false);
 sysrootRepoConfig.set_string_list(testosRefSection, 'branches', [runtimeRef]);
 
-sysrootRepo.pull('testos', null, 0, null);
+sysrootRepo.pull('testos', null, 0, null, null);
 
 //// TEST: We can deploy one tree
 
@@ -111,7 +111,7 @@ sysroot.write_deployments(newDeployments, null);
 
 libtestExec('os_repository_new_commit');
 
-sysrootRepo.pull('testos', null, 0, null);
+sysrootRepo.pull('testos', null, 0, null, null);
 
 let [,newRev] = upstreamRepo.resolve_rev(runtimeRef, false);
 
@@ -137,7 +137,7 @@ print("OK two deployments");
 
 libtestExec('os_repository_new_commit 0 1');
 
-sysrootRepo.pull('testos', null, 0, null);
+sysrootRepo.pull('testos', null, 0, null, null);
 
 let [,thirdRev] = sysrootRepo.resolve_rev(runtimeRef, false);
 assertNotEquals(newRev, thirdRev);


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