[ostree] sysroot: Clean up API



commit 8f1ea1b50aad70f671b8a2902f4b68771cce8682
Author: Colin Walters <walters verbum org>
Date:   Mon Sep 16 09:13:58 2013 -0400

    sysroot: Clean up API
    
    Now that we have a real GObject for the sysroot, we have a convenient
    place to keep track of 4 pieces of state:
    
    * The current deployment list
    * The current bootversion
    * The current subbootversion
    * The current booted deployment (if any)
    
    Avoid requiring callers to pass all of this around and load it
    piecemeal; instead the new thing is ostree_sysroot_load().

 doc/ostree-sections.txt                |   11 +-
 src/libostree/ostree-sysroot-cleanup.c |   36 ++----
 src/libostree/ostree-sysroot-deploy.c  |  190 +++++++++++++++++-----------
 src/libostree/ostree-sysroot-private.h |   14 ++
 src/libostree/ostree-sysroot.c         |  217 +++++++++++++++++---------------
 src/libostree/ostree-sysroot.h         |   68 +++-------
 src/ostree/ot-admin-builtin-cleanup.c  |    3 +
 src/ostree/ot-admin-builtin-deploy.c   |   32 ++---
 src/ostree/ot-admin-builtin-diff.c     |   33 ++---
 src/ostree/ot-admin-builtin-status.c   |   24 +---
 src/ostree/ot-admin-builtin-undeploy.c |   21 +---
 src/ostree/ot-admin-builtin-upgrade.c  |   38 ++----
 src/ostree/ot-admin-functions.c        |   22 ++++
 src/ostree/ot-admin-functions.h        |    6 +
 14 files changed, 360 insertions(+), 355 deletions(-)
---
diff --git a/doc/ostree-sections.txt b/doc/ostree-sections.txt
index 9bcedce..aaecbb4 100644
--- a/doc/ostree-sections.txt
+++ b/doc/ostree-sections.txt
@@ -140,16 +140,17 @@ ostree_sysroot_get_type
 ostree_sysroot_new
 ostree_sysroot_new_default
 ostree_sysroot_get_path
+ostree_sysroot_load
 ostree_sysroot_ensure_initialized
-ostree_sysroot_read_current_subbootversion
-ostree_sysroot_list_deployments
+ostree_sysroot_get_bootversion
+ostree_sysroot_get_subbootversion
+ostree_sysroot_get_deployments
+ostree_sysroot_get_booted_deployment
 ostree_sysroot_get_deployment_directory
 ostree_sysroot_get_deployment_origin_path
 ostree_sysroot_cleanup
 ostree_sysroot_get_repo
-ostree_sysroot_find_booted_deployment
-ostree_sysroot_require_deployment_or_osname
 ostree_sysroot_write_deployments
-ostree_sysroot_deploy
+ostree_sysroot_deploy_one_tree
 ostree_sysroot_get_merge_deployment
 </SECTION>
diff --git a/src/libostree/ostree-sysroot-cleanup.c b/src/libostree/ostree-sysroot-cleanup.c
index fbad0b2..186c6cb 100644
--- a/src/libostree/ostree-sysroot-cleanup.c
+++ b/src/libostree/ostree-sysroot-cleanup.c
@@ -242,8 +242,6 @@ list_all_boot_directories (OstreeSysroot       *self,
 
 static gboolean
 cleanup_other_bootversions (OstreeSysroot       *self,
-                            int                  bootversion,
-                            int                  subbootversion,
                             GCancellable        *cancellable,
                             GError             **error)
 {
@@ -252,8 +250,8 @@ cleanup_other_bootversions (OstreeSysroot       *self,
   int cleanup_subbootversion;
   gs_unref_object GFile *cleanup_boot_dir = NULL;
 
-  cleanup_bootversion = bootversion == 0 ? 1 : 0;
-  cleanup_subbootversion = subbootversion == 0 ? 1 : 0;
+  cleanup_bootversion = self->bootversion == 0 ? 1 : 0;
+  cleanup_subbootversion = self->subbootversion == 0 ? 1 : 0;
 
   cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "boot/loader.%d", cleanup_bootversion);
   if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
@@ -275,7 +273,7 @@ cleanup_other_bootversions (OstreeSysroot       *self,
     goto out;
   g_clear_object (&cleanup_boot_dir);
 
-  cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.%d", bootversion,
+  cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.%d", self->bootversion,
                                                    cleanup_subbootversion);
   if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
     goto out;
@@ -288,7 +286,6 @@ cleanup_other_bootversions (OstreeSysroot       *self,
 
 static gboolean
 cleanup_old_deployments (OstreeSysroot       *self,
-                         GPtrArray           *deployments,
                          GCancellable        *cancellable,
                          GError             **error)
 {
@@ -309,9 +306,9 @@ cleanup_old_deployments (OstreeSysroot       *self,
   active_deployment_dirs = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, NULL, 
g_object_unref);
   active_boot_checksums = g_hash_table_new_full (g_str_hash, (GEqualFunc)g_str_equal, g_free, NULL);
 
-  for (i = 0; i < deployments->len; i++)
+  for (i = 0; i < self->deployments->len; i++)
     {
-      OstreeDeployment *deployment = deployments->pdata[i];
+      OstreeDeployment *deployment = self->deployments->pdata[i];
       GFile *deployment_path = ostree_sysroot_get_deployment_directory (self, deployment);
       char *bootcsum = g_strdup (ostree_deployment_get_bootcsum (deployment));
       /* Transfer ownership */
@@ -494,34 +491,23 @@ ostree_sysroot_cleanup (OstreeSysroot       *self,
                         GError             **error)
 {
   gboolean ret = FALSE;
-  gs_unref_ptrarray GPtrArray *deployments = NULL;
   gs_unref_object OstreeRepo *repo = NULL;
-  int bootversion;
-  int subbootversion;
 
-  if (!ostree_sysroot_list_deployments (self, &bootversion, &deployments,
-                                        cancellable, error))
-    goto out;
+  g_return_val_if_fail (self->loaded, FALSE);
 
-  if (!ostree_sysroot_read_current_subbootversion (self, bootversion, &subbootversion,
-                                                   cancellable, error))
-    goto out;
-
-  if (!cleanup_other_bootversions (self, bootversion, subbootversion,
-                                   cancellable, error))
+  if (!cleanup_other_bootversions (self, cancellable, error))
     goto out;
 
-  if (!cleanup_old_deployments (self, deployments,
-                                cancellable, error))
+  if (!cleanup_old_deployments (self, cancellable, error))
     goto out;
 
-  if (deployments->len > 0)
+  if (self->deployments->len > 0)
     {
       if (!ostree_sysroot_get_repo (self, &repo, cancellable, error))
         goto out;
 
-      if (!generate_deployment_refs_and_prune (self, repo, bootversion,
-                                               subbootversion, deployments,
+      if (!generate_deployment_refs_and_prune (self, repo, self->bootversion,
+                                               self->subbootversion, self->deployments,
                                                cancellable, error))
         goto out;
     }
diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c
index c295beb..cc8f542 100644
--- a/src/libostree/ostree-sysroot-deploy.c
+++ b/src/libostree/ostree-sysroot-deploy.c
@@ -507,8 +507,7 @@ compute_new_deployment_list (int           current_bootversion,
                              gboolean      retain,
                              const char   *revision,
                              const char   *bootcsum,
-                             GPtrArray   **out_new_deployments,
-                             int          *out_new_bootversion)
+                             GPtrArray   **out_new_deployments)
 {
   guint i;
   int new_index;
@@ -518,10 +517,6 @@ compute_new_deployment_list (int           current_bootversion,
   gs_unref_ptrarray GPtrArray *matching_deployments_by_bootserial = NULL;
   OstreeDeployment *deployment_to_delete = NULL;
   gs_unref_ptrarray GPtrArray *ret_new_deployments = NULL;
-  gboolean requires_new_bootversion;
-
-  if (osname == NULL)
-    osname = ostree_deployment_get_osname (booted_deployment);
 
   /* First, compute the serial for this deployment; we look
    * for other ones in this os with the same checksum.
@@ -566,13 +561,6 @@ compute_new_deployment_list (int           current_bootversion,
         }
     }
 
-  /* We need to update the bootloader only if the deployment we're
-   * removing uses a different kernel.
-   */
-  requires_new_bootversion =
-    (deployment_to_delete == NULL) ||
-    (strcmp (ostree_deployment_get_bootcsum (deployment_to_delete), bootcsum) != 0);
-
   ret_new_deployments = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
 
   new_deployment = ostree_deployment_new (0, osname, revision, new_deployserial,
@@ -606,11 +594,6 @@ compute_new_deployment_list (int           current_bootversion,
 
   *out_new_deployments = ret_new_deployments;
   ret_new_deployments = NULL;
-  g_assert (current_bootversion == 0 || current_bootversion == 1);
-  if (requires_new_bootversion)
-    *out_new_bootversion = (current_bootversion == 0) ? 1 : 0;
-  else
-    *out_new_bootversion = current_bootversion;
 }
 
 static GHashTable *
@@ -707,29 +690,34 @@ full_system_sync (GCancellable      *cancellable,
 }
 
 static gboolean
-swap_bootlinks (OstreeSysroot *sysroot,
-                int           current_bootversion,
+swap_bootlinks (OstreeSysroot *self,
+                int            bootversion,
                 GPtrArray    *new_deployments,
                 GCancellable *cancellable,
                 GError      **error)
 {
   gboolean ret = FALSE;
   guint i;
-  int old_subbootversion, new_subbootversion;
-  gs_unref_object GFile *ostree_dir = g_file_get_child (ostree_sysroot_get_path (sysroot), "ostree");
-  gs_free char *ostree_bootdir_name = g_strdup_printf ("boot.%d", current_bootversion);
+  int old_subbootversion;
+  int new_subbootversion;
+  gs_unref_object GFile *ostree_dir = g_file_get_child (self->path, "ostree");
+  gs_free char *ostree_bootdir_name = g_strdup_printf ("boot.%d", bootversion);
   gs_unref_object GFile *ostree_bootdir = g_file_resolve_relative_path (ostree_dir, ostree_bootdir_name);
   gs_free char *ostree_subbootdir_name = NULL;
   gs_unref_object GFile *ostree_subbootdir = NULL;
 
-  if (!ostree_sysroot_read_current_subbootversion (sysroot, current_bootversion,
-                                                   &old_subbootversion,
-                                                   cancellable, error))
-    goto out;
+  if (bootversion != self->bootversion)
+    {
+      if (!_ostree_sysroot_read_current_subbootversion (self, bootversion, &old_subbootversion,
+                                                        cancellable, error))
+        goto out;
+    }
+  else
+    old_subbootversion = self->subbootversion;
 
   new_subbootversion = old_subbootversion == 0 ? 1 : 0;
 
-  ostree_subbootdir_name = g_strdup_printf ("boot.%d.%d", current_bootversion, new_subbootversion);
+  ostree_subbootdir_name = g_strdup_printf ("boot.%d.%d", bootversion, new_subbootversion);
   ostree_subbootdir = g_file_resolve_relative_path (ostree_dir, ostree_subbootdir_name);
 
   if (!gs_file_ensure_directory (ostree_subbootdir, TRUE, cancellable, error))
@@ -982,38 +970,91 @@ swap_bootloader (OstreeSysroot  *sysroot,
   return ret;
 }
 
+static GHashTable *
+bootcsum_counts_for_deployment_list (GPtrArray   *deployments)
+{
+  guint i;
+  GHashTable *ret = 
+    g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
+
+  for (i = 0; i < deployments->len; i++)
+    {
+      OstreeDeployment *deployment = deployments->pdata[i];
+      const char *bootcsum = ostree_deployment_get_bootcsum (deployment);
+      gpointer orig_key;
+      gpointer countp;
+
+      if (!g_hash_table_lookup_extended (ret, bootcsum, &orig_key, &countp))
+        {
+          g_hash_table_insert (ret, (char*)bootcsum, GUINT_TO_POINTER (0));
+        }
+      else
+        {
+          guint count = GPOINTER_TO_UINT (countp);
+          g_hash_table_replace (ret, (char*)bootcsum, GUINT_TO_POINTER (count + 1));
+        }
+    }
+  return ret;
+}
+
 /**
  * ostree_sysroot_write_deployments:
  * @self: Sysroot
- * @current_bootversion: 0 or 1 for active boot version
- * @new_bootversion: 0 or 1 for new bootversion
  * @new_deployments: (element-type OstreeDeployment): List of new deployments
  * @cancellable: Cancellable
  * @error: Error
  *
- * Complete the deployment of @new_deployments by updating either the
- * bootloader configuration (if @current_bootversion and the new
- * version @new_bootversion differ), or swapping the bootlinks if
- * they're the same.
+ * Assuming @new_deployments have already been deployed in place on
+ * disk, atomically update bootloader configuration.
  */
 gboolean
 ostree_sysroot_write_deployments (OstreeSysroot     *self,
-                                  int                current_bootversion,
-                                  int                new_bootversion,
                                   GPtrArray         *new_deployments,
                                   GCancellable      *cancellable,
                                   GError           **error)
 {
   gboolean ret = FALSE;
   guint i;
+  gboolean requires_new_bootversion = FALSE;
   gs_unref_object OstreeBootloader *bootloader = _ostree_sysroot_query_bootloader (self);
 
+  /* Determine whether or not we need to touch the bootloader
+   * configuration.  If we have an equal number of deployments and
+   * more strongly an equal number of deployments per bootcsum, then
+   * we can just swap the subbootversion bootlinks.
+   */
+  if (new_deployments->len != self->deployments->len)
+    requires_new_bootversion = TRUE;
+  else
+    {
+      GHashTableIter hashiter;
+      gpointer hkey, hvalue;
+      gs_unref_hashtable GHashTable *orig_bootcsum_to_count
+        = bootcsum_counts_for_deployment_list (self->deployments);
+      gs_unref_hashtable GHashTable *new_bootcsum_to_count
+        = bootcsum_counts_for_deployment_list (new_deployments);
+
+      g_hash_table_iter_init (&hashiter, orig_bootcsum_to_count);
+      while (g_hash_table_iter_next (&hashiter, &hkey, &hvalue))
+        {
+          guint orig_count = GPOINTER_TO_UINT (hvalue);
+          gpointer new_countp = g_hash_table_lookup (new_bootcsum_to_count, hkey);
+          guint new_count = GPOINTER_TO_UINT (new_countp);
+
+          if (orig_count != new_count)
+            {
+              requires_new_bootversion = TRUE;
+              break;
+            }
+        }
+    }
+
   if (bootloader)
     g_print ("Detected bootloader: %s\n", _ostree_bootloader_get_name (bootloader));
   else
     g_print ("Detected bootloader: (unknown)\n");
 
-  if (current_bootversion == new_bootversion)
+  if (!requires_new_bootversion)
     {
       if (!full_system_sync (cancellable, error))
         {
@@ -1021,7 +1062,7 @@ ostree_sysroot_write_deployments (OstreeSysroot     *self,
           goto out;
         }
 
-      if (!swap_bootlinks (self, current_bootversion,
+      if (!swap_bootlinks (self, self->bootversion,
                            new_deployments,
                            cancellable, error))
         {
@@ -1031,6 +1072,7 @@ ostree_sysroot_write_deployments (OstreeSysroot     *self,
     }
   else
     {
+      int new_bootversion = self->bootversion ? 0 : 1;
       for (i = 0; i < new_deployments->len; i++)
         {
           OstreeDeployment *deployment = new_deployments->pdata[i];
@@ -1059,12 +1101,12 @@ ostree_sysroot_write_deployments (OstreeSysroot     *self,
 
       if (bootloader && !_ostree_bootloader_write_config (bootloader, new_bootversion,
                                                           cancellable, error))
-          {
-            g_prefix_error (error, "Bootloader write config: ");
-            goto out;
-          }
+        {
+          g_prefix_error (error, "Bootloader write config: ");
+          goto out;
+        }
 
-      if (!swap_bootloader (self, current_bootversion, new_bootversion,
+      if (!swap_bootloader (self, self->bootversion, new_bootversion,
                             cancellable, error))
         {
           g_prefix_error (error, "Final bootloader swap: ");
@@ -1072,25 +1114,25 @@ ostree_sysroot_write_deployments (OstreeSysroot     *self,
         }
     }
 
+  /* Now reload from disk */
+  if (!ostree_sysroot_load (self, cancellable, error))
+    goto out;
+
   ret = TRUE;
  out:
   return ret;
 }
                             
 /**
- * ostree_sysroot_deploy:
- * @current_bootversion: Active bootversion
- * @current_deployments: (element-type OstreeDeployment): Active deployments
+ * ostree_sysroot_deploy_one_tree:
+ * @self: Sysroot
  * @osname: (allow-none): osname to use for merge deployment
  * @revision: Checksum to add
  * @origin: (allow-none): Origin to use for upgrades
  * @add_kernel_argv: (allow-none): Append these arguments to kernel configuration
  * @retain: If %TRUE, then do not delete earlier deployment
- * @booted_deployment: (allow-none): Retain this deployment
  * @provided_merge_deployment: (allow-none): Use this deployment for merge path
  * @out_new_deployment: (out): The new deployment path
- * @out_new_bootversion: (out): The new bootversion
- * @out_new_deployments: (out) (element-type OstreeDeployment): Full list of new deployments
  * @cancellable: Cancellable
  * @error: Error
  *
@@ -1098,21 +1140,16 @@ ostree_sysroot_write_deployments (OstreeSysroot     *self,
  * then an earlier deployment will be garbage collected.
  */
 gboolean
-ostree_sysroot_deploy (OstreeSysroot     *self,
-                       int                current_bootversion,
-                       GPtrArray         *current_deployments,
-                       const char        *osname,
-                       const char        *revision,
-                       GKeyFile          *origin,
-                       char             **add_kernel_argv,
-                       gboolean           retain,
-                       OstreeDeployment  *booted_deployment,
-                       OstreeDeployment  *provided_merge_deployment,
-                       OstreeDeployment **out_new_deployment,
-                       int               *out_new_bootversion,
-                       GPtrArray        **out_new_deployments,
-                       GCancellable      *cancellable,
-                       GError           **error)
+ostree_sysroot_deploy_one_tree (OstreeSysroot     *self,
+                                const char        *osname,
+                                const char        *revision,
+                                GKeyFile          *origin,
+                                char             **add_kernel_argv,
+                                gboolean           retain,
+                                OstreeDeployment  *provided_merge_deployment,
+                                OstreeDeployment **out_new_deployment,
+                                GCancellable      *cancellable,
+                                GError           **error)
 {
   gboolean ret = FALSE;
   OstreeDeployment *new_deployment;
@@ -1125,7 +1162,11 @@ ostree_sysroot_deploy (OstreeSysroot     *self,
   gs_free char *new_bootcsum = NULL;
   gs_unref_object OstreeBootconfigParser *bootconfig = NULL;
   gs_unref_ptrarray GPtrArray *new_deployments = NULL;
-  int new_bootversion;
+
+  g_return_val_if_fail (osname != NULL || self->booted_deployment != NULL, FALSE);
+
+  if (osname == NULL)
+    osname = ostree_deployment_get_osname (self->booted_deployment);
 
   if (!ostree_sysroot_get_repo (self, &repo, cancellable, error))
     goto out;
@@ -1168,20 +1209,18 @@ ostree_sysroot_deploy (OstreeSysroot     *self,
   if (provided_merge_deployment != NULL)
     merge_deployment = g_object_ref (provided_merge_deployment);
   else
-    merge_deployment = ostree_sysroot_get_merge_deployment (current_deployments, osname,
-                                                            booted_deployment); 
+    merge_deployment = ostree_sysroot_get_merge_deployment (self, osname);
 
-  compute_new_deployment_list (current_bootversion,
-                               current_deployments, osname,
-                               booted_deployment, merge_deployment,
+  compute_new_deployment_list (self->bootversion,
+                               self->deployments, osname,
+                               self->booted_deployment, merge_deployment,
                                retain,
                                revision, new_bootcsum,
-                               &new_deployments,
-                               &new_bootversion);
+                               &new_deployments);
   new_deployment = g_object_ref (new_deployments->pdata[0]);
   ostree_deployment_set_origin (new_deployment, origin);
 
-  print_deployment_diff (current_deployments, new_deployments);
+  print_deployment_diff (self->deployments, new_deployments);
 
   /* Check out the userspace tree onto the filesystem */
   if (!checkout_deployment_tree (self, repo, new_deployment, &new_deployment_path,
@@ -1238,8 +1277,7 @@ ostree_sysroot_deploy (OstreeSysroot     *self,
       ostree_bootconfig_parser_set (bootconfig, "options", new_options);
     }
 
-  if (!ostree_sysroot_write_deployments (self, current_bootversion, new_bootversion,
-                                         new_deployments, cancellable, error))
+  if (!ostree_sysroot_write_deployments (self, new_deployments, cancellable, error))
     goto out;
 
   g_print ("Transaction complete, performing cleanup\n");
@@ -1269,8 +1307,6 @@ ostree_sysroot_deploy (OstreeSysroot     *self,
 
   ret = TRUE;
   ot_transfer_out_value (out_new_deployment, &new_deployment);
-  *out_new_bootversion = new_bootversion;
-  ot_transfer_out_value (out_new_deployments, &new_deployments)
  out:
   return ret;
 }
diff --git a/src/libostree/ostree-sysroot-private.h b/src/libostree/ostree-sysroot-private.h
index f51b2bb..682c389 100644
--- a/src/libostree/ostree-sysroot-private.h
+++ b/src/libostree/ostree-sysroot-private.h
@@ -30,6 +30,13 @@ struct OstreeSysroot {
 
   GFile *path;
   int sysroot_fd;
+
+  gboolean loaded;
+  
+  GPtrArray *deployments;
+  int bootversion;
+  int subbootversion;
+  OstreeDeployment *booted_deployment;
 };
 
 gboolean
@@ -40,6 +47,13 @@ _ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self,
                                           GError       **error);
 
 gboolean
+_ostree_sysroot_read_current_subbootversion (OstreeSysroot *self,
+                                             int            bootversion,
+                                             int           *out_subbootversion,
+                                             GCancellable  *cancellable,
+                                             GError       **error);
+
+gboolean
 _ostree_sysroot_parse_deploy_path_name (const char *name,
                                         char      **out_csum,
                                         int        *out_serial,
diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c
index e7bc34f..01d1617 100644
--- a/src/libostree/ostree-sysroot.c
+++ b/src/libostree/ostree-sysroot.c
@@ -27,6 +27,12 @@
 #include "ostree-bootloader-uboot.h"
 #include "ostree-bootloader-syslinux.h"
 
+static gboolean
+find_booted_deployment (OstreeSysroot       *self,
+                        OstreeDeployment   **out_deployment,
+                        GCancellable        *cancellable,
+                        GError             **error);
+
 /**
  * SECTION:libostree-sysroot
  * @title: Root partition mount point
@@ -193,7 +199,9 @@ _ostree_sysroot_get_devino (GFile         *path,
 
 /**
  * ostree_sysroot_ensure_initialized:
- * @self:
+ * @self: Sysroot
+ * @cancellable: Cancellable
+ * @error: Error
  *
  * Ensure that @self is set up as a valid rootfs, by creating
  * /ostree/repo, among other things.
@@ -275,23 +283,12 @@ _ostree_sysroot_parse_deploy_path_name (const char *name,
   return ret;
 }
 
-
-/**
- * ostree_sysroot_read_current_subbootversion:
- * @self: Sysroot
- * @bootversion: Current boot version
- * @out_subbootversion: (out): The active subbootversion
- * @cancellable: Cancellable
- * @error: Error
- *
- * Determine the active subbootversion.
- */
 gboolean
-ostree_sysroot_read_current_subbootversion (OstreeSysroot *self,
-                                            int            bootversion,
-                                            int           *out_subbootversion,
-                                            GCancellable  *cancellable,
-                                            GError       **error)
+_ostree_sysroot_read_current_subbootversion (OstreeSysroot *self,
+                                             int            bootversion,
+                                             int           *out_subbootversion,
+                                             GCancellable  *cancellable,
+                                             GError       **error)
 {
   gboolean ret = FALSE;
   gs_unref_object GFile *ostree_dir = g_file_get_child (self->path, "ostree");
@@ -664,62 +661,117 @@ compare_deployments_by_boot_loader_version_reversed (gconstpointer     a_pp,
   else
     return 1;
 }
+
 /**
- * ostree_sysroot_list_deployments:
- * @sysroot: Sysroot
- * @out_current_bootversion: (out): Current bootversion
- * @out_deployments: (out) (element-type OstreeDeployment): Deployment list
+ * ostree_sysroot_load:
+ * @self: Sysroot
  * @cancellable: Cancellable
  * @error: Error
  *
- * Enumerate all deployments, in the boot order.  Also returns the
- * active bootversion.
+ * Load deployment list, bootversion, and subbootversion from the
+ * rootfs @self.
  */
 gboolean
-ostree_sysroot_list_deployments (OstreeSysroot       *self,
-                                 int                 *out_current_bootversion,
-                                 GPtrArray          **out_deployments,
-                                 GCancellable        *cancellable,
-                                 GError             **error)
+ostree_sysroot_load (OstreeSysroot  *self,
+                     GCancellable   *cancellable,
+                     GError        **error)
 {
   gboolean ret = FALSE;
-  gs_unref_ptrarray GPtrArray *boot_loader_configs = NULL;
-  gs_unref_ptrarray GPtrArray *ret_deployments = NULL;
   guint i;
-  int bootversion = -1;
+  int bootversion;
+  int subbootversion;
+  gs_unref_ptrarray GPtrArray *boot_loader_configs = NULL;
+  gs_unref_ptrarray GPtrArray *deployments = NULL;
+
+  g_clear_pointer (&self->deployments, g_ptr_array_unref);
+  g_clear_pointer (&self->booted_deployment, g_object_unref);
+  self->bootversion = -1;
+  self->subbootversion = -1;
 
   if (!read_current_bootversion (self, &bootversion, cancellable, error))
     goto out;
 
+  if (!_ostree_sysroot_read_current_subbootversion (self, bootversion, &subbootversion,
+                                                    cancellable, error))
+    goto out;
+
   if (!_ostree_sysroot_read_boot_loader_configs (self, bootversion, &boot_loader_configs,
                                                  cancellable, error))
     goto out;
 
-  ret_deployments = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
+  deployments = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
 
   for (i = 0; i < boot_loader_configs->len; i++)
     {
       OstreeBootconfigParser *config = boot_loader_configs->pdata[i];
 
-      if (!list_deployments_process_one_boot_entry (self, config, ret_deployments,
+      if (!list_deployments_process_one_boot_entry (self, config, deployments,
                                                     cancellable, error))
         goto out;
     }
 
-  g_ptr_array_sort (ret_deployments, compare_deployments_by_boot_loader_version_reversed);
-  for (i = 0; i < ret_deployments->len; i++)
+  g_ptr_array_sort (deployments, compare_deployments_by_boot_loader_version_reversed);
+  for (i = 0; i < deployments->len; i++)
     {
-      OstreeDeployment *deployment = ret_deployments->pdata[i];
+      OstreeDeployment *deployment = deployments->pdata[i];
       ostree_deployment_set_index (deployment, i);
     }
 
+  if (!find_booted_deployment (self, &self->booted_deployment,
+                               cancellable, error))
+    goto out;
+
+  self->bootversion = bootversion;
+  self->subbootversion = subbootversion;
+  self->deployments = deployments;
+  deployments = NULL; /* Transfer ownership */
+  self->loaded = TRUE;
+
   ret = TRUE;
-  *out_current_bootversion = bootversion;
-  gs_transfer_out_value (out_deployments, &ret_deployments);
  out:
   return ret;
 }
 
+int
+ostree_sysroot_get_bootversion (OstreeSysroot   *self)
+{
+  return self->bootversion;
+}
+
+int
+ostree_sysroot_get_subbootversion (OstreeSysroot   *self)
+{
+  return self->subbootversion;
+}
+
+/**
+ * ostree_sysroot_get_booted_deployment:
+ * @self: Sysroot
+ * 
+ * Returns: (transfer none): The currently booted deployment, or %NULL if none
+ */
+OstreeDeployment *
+ostree_sysroot_get_booted_deployment (OstreeSysroot       *self)
+{
+  return self->booted_deployment;
+}
+
+/**
+ * ostree_sysroot_get_deployments:
+ * @self: Sysroot
+ *
+ * Returns: (element-type OstreeDeployment) (transfer full): Ordered list of deployments
+ */
+GPtrArray *
+ostree_sysroot_get_deployments (OstreeSysroot  *self)
+{
+  GPtrArray *copy = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
+  guint i;
+  for (i = 0; i < self->deployments->len; i++)
+    g_ptr_array_add (copy, g_object_ref (self->deployments->pdata[i]));
+  return copy;
+}
+
 /**
  * ostree_sysroot_get_deployment_directory:
  * @self: Sysroot
@@ -740,8 +792,7 @@ ostree_sysroot_get_deployment_directory (OstreeSysroot    *self,
 
 /**
  * ostree_sysroot_get_deployment_origin_path:
- * @self: Sysroot
- * @deployment: A deployment
+ * @deployment_path: A deployment path
  *
  * Returns: (transfer full): Path to deployment origin file
  */
@@ -754,7 +805,6 @@ ostree_sysroot_get_deployment_origin_path (GFile   *deployment_path)
                                        gs_file_get_path_cached (deployment_path));
 }
 
-
 /**
  * ostree_sysroot_get_repo:
  * @self: Sysroot
@@ -784,7 +834,6 @@ ostree_sysroot_get_repo (OstreeSysroot         *self,
   return ret;
 }
 
-
 /**
  * ostree_sysroot_query_bootloader:
  * @sysroot: Sysroot
@@ -852,32 +901,19 @@ parse_kernel_commandline (OstreeOrderedHash  **out_args,
   return ret;
 }
 
-/**
- * ostree_sysroot_find_booted_deployment:
- * @target_sysroot: Root directory
- * @deployments: (element-type OstreeDeployment): Loaded deployments
- * @out_deployment: (out): The currently booted deployment
- * @cancellable:
- * @error: 
- * 
- * If the system is currently booted into a deployment in
- * @deployments, set @out_deployment.  Note that if @target_sysroot is
- * not equal to "/", @out_deployment will always be set to %NULL.
- */
-gboolean
-ostree_sysroot_find_booted_deployment (OstreeSysroot       *self,
-                                       GPtrArray           *deployments,
-                                       OstreeDeployment   **out_deployment,
-                                       GCancellable        *cancellable,
-                                       GError             **error)
+static gboolean
+find_booted_deployment (OstreeSysroot       *self,
+                        OstreeDeployment   **out_deployment,
+                        GCancellable        *cancellable,
+                        GError             **error)
 {
   gboolean ret = FALSE;
   gs_unref_object GFile *active_root = g_file_new_for_path ("/");
-  gs_unref_object OstreeSysroot *active_deployment_root = ostree_sysroot_new_default ();
   gs_unref_object OstreeDeployment *ret_deployment = NULL;
 
   if (g_file_equal (active_root, self->path))
     { 
+      gs_unref_object OstreeSysroot *active_deployment_root = ostree_sysroot_new_default ();
       guint i;
       const char *bootlink_arg;
       __attribute__((cleanup(_ostree_ordered_hash_cleanup))) OstreeOrderedHash *kernel_args = NULL;
@@ -894,9 +930,9 @@ ostree_sysroot_find_booted_deployment (OstreeSysroot       *self,
       bootlink_arg = g_hash_table_lookup (kernel_args->table, "ostree");
       if (bootlink_arg)
         {
-          for (i = 0; i < deployments->len; i++)
+          for (i = 0; i < self->deployments->len; i++)
             {
-              OstreeDeployment *deployment = deployments->pdata[i];
+              OstreeDeployment *deployment = self->deployments->pdata[i];
               gs_unref_object GFile *deployment_path = ostree_sysroot_get_deployment_directory 
(active_deployment_root, deployment);
               guint32 device;
               guint64 inode;
@@ -930,34 +966,6 @@ ostree_sysroot_find_booted_deployment (OstreeSysroot       *self,
   return ret;
 }
 
-gboolean
-ostree_sysroot_require_deployment_or_osname (OstreeSysroot       *sysroot,
-                                             GPtrArray           *deployments,
-                                             const char          *osname,
-                                             OstreeDeployment   **out_deployment,
-                                             GCancellable        *cancellable,
-                                             GError             **error)
-{
-  gboolean ret = FALSE;
-  gs_unref_object OstreeDeployment *ret_deployment = NULL;
-
-  if (!ostree_sysroot_find_booted_deployment (sysroot, deployments, &ret_deployment,
-                                              cancellable, error))
-    goto out;
-
-  if (ret_deployment == NULL && osname == NULL)
-    {
-      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                           "Not currently booted into an OSTree system and no --os= argument given");
-      goto out;
-    }
-  
-  ret = TRUE;
-  ot_transfer_out_value (out_deployment, &ret_deployment);
- out:
-  return ret;
-}
-
 OstreeOrderedHash *
 _ostree_sysroot_parse_kernel_args (const char *options)
 {
@@ -1040,27 +1048,34 @@ _ostree_sysroot_kernel_arg_string_serialize (OstreeOrderedHash *ohash)
   return g_string_free (buf, FALSE);
 }
 
+/**
+ * ostree_sysroot_get_merge_deployment:
+ * @self: Sysroot
+ * @osname: (allow-none): Operating system group
+ *
+ * Find the deployment to use as a configuration merge source; this is
+ * the first one in the current deployment list which matches osname.
+ */
 OstreeDeployment *
-ostree_sysroot_get_merge_deployment (GPtrArray         *deployments,
-                                     const char        *osname,
-                                     OstreeDeployment  *booted_deployment)
+ostree_sysroot_get_merge_deployment (OstreeSysroot     *self,
+                                     const char        *osname)
 {
-  g_return_val_if_fail (osname != NULL || booted_deployment != NULL, NULL);
+  g_return_val_if_fail (osname != NULL || self->booted_deployment != NULL, NULL);
 
   if (osname == NULL)
-    osname = ostree_deployment_get_osname (booted_deployment);
+    osname = ostree_deployment_get_osname (self->booted_deployment);
 
-  if (booted_deployment &&
-      g_strcmp0 (ostree_deployment_get_osname (booted_deployment), osname) == 0)
+  if (self->booted_deployment &&
+      g_strcmp0 (ostree_deployment_get_osname (self->booted_deployment), osname) == 0)
     {
-      return g_object_ref (booted_deployment);
+      return g_object_ref (self->booted_deployment);
     }
   else
     {
       guint i;
-      for (i = 0; i < deployments->len; i++)
+      for (i = 0; i < self->deployments->len; i++)
         {
-          OstreeDeployment *deployment = deployments->pdata[i];
+          OstreeDeployment *deployment = self->deployments->pdata[i];
 
           if (strcmp (ostree_deployment_get_osname (deployment), osname) != 0)
             continue;
diff --git a/src/libostree/ostree-sysroot.h b/src/libostree/ostree-sysroot.h
index 9ae1fe8..8ff9cfd 100644
--- a/src/libostree/ostree-sysroot.h
+++ b/src/libostree/ostree-sysroot.h
@@ -40,21 +40,18 @@ OstreeSysroot* ostree_sysroot_new_default (void);
 
 GFile *ostree_sysroot_get_path (OstreeSysroot *self);
 
+gboolean ostree_sysroot_load (OstreeSysroot  *self,
+                              GCancellable   *cancellable,
+                              GError        **error);
+
 gboolean ostree_sysroot_ensure_initialized (OstreeSysroot  *self,
                                             GCancellable   *cancellable,
                                             GError        **error);
 
-gboolean ostree_sysroot_read_current_subbootversion (OstreeSysroot *self,
-                                                     int            bootversion,
-                                                     int           *out_subbootversion,
-                                                     GCancellable  *cancellable,
-                                                     GError       **error);
-
-gboolean ostree_sysroot_list_deployments (OstreeSysroot       *self,
-                                          int                 *out_bootversion,
-                                          GPtrArray          **out_deployments,
-                                          GCancellable        *cancellable,
-                                          GError             **error);
+int ostree_sysroot_get_bootversion (OstreeSysroot   *self);
+int ostree_sysroot_get_subbootversion (OstreeSysroot   *self);
+GPtrArray *ostree_sysroot_get_deployments (OstreeSysroot  *self);
+OstreeDeployment *ostree_sysroot_get_booted_deployment (OstreeSysroot *self);
 
 GFile *ostree_sysroot_get_deployment_directory (OstreeSysroot    *self,
                                                 OstreeDeployment *deployment);
@@ -70,47 +67,24 @@ gboolean ostree_sysroot_get_repo (OstreeSysroot         *self,
                                   GCancellable          *cancellable,
                                   GError               **error);
 
-
-gboolean ostree_sysroot_find_booted_deployment (OstreeSysroot       *sysroot,
-                                                GPtrArray           *deployments,
-                                                OstreeDeployment   **out_deployment,
-                                                GCancellable        *cancellable,
-                                                GError             **error);
-
-gboolean ostree_sysroot_require_deployment_or_osname (OstreeSysroot       *sysroot,
-                                                      GPtrArray           *deployment_list,
-                                                      const char          *osname,
-                                                      OstreeDeployment   **out_deployment,
-                                                      GCancellable        *cancellable,
-                                                      GError             **error);
-
 gboolean ostree_sysroot_write_deployments (OstreeSysroot     *self,
-                                           int                current_bootversion,
-                                           int                new_bootversion,
                                            GPtrArray         *new_deployments,
                                            GCancellable      *cancellable,
                                            GError           **error);
 
-gboolean ostree_sysroot_deploy (OstreeSysroot     *self,
-                                int                current_bootversion,
-                                GPtrArray         *current_deployments,
-                                const char        *osname,
-                                const char        *revision,
-                                GKeyFile          *origin,
-                                char             **add_kernel_argv,
-                                gboolean           retain,
-                                OstreeDeployment  *booted_deployment,
-                                OstreeDeployment  *merge_deployment,
-                                OstreeDeployment **out_new_deployment,
-                                int               *out_new_bootversion,
-                                GPtrArray        **out_new_deployments,
-                                GCancellable      *cancellable,
-                                GError           **error);
-
-
-OstreeDeployment *ostree_sysroot_get_merge_deployment (GPtrArray         *deployment_list,
-                                                       const char        *osname,
-                                                       OstreeDeployment  *booted_deployment);
+gboolean ostree_sysroot_deploy_one_tree (OstreeSysroot     *self,
+                                         const char        *osname,
+                                         const char        *revision,
+                                         GKeyFile          *origin,
+                                         char             **add_kernel_argv,
+                                         gboolean           retain,
+                                         OstreeDeployment  *provided_merge_deployment,
+                                         OstreeDeployment **out_new_deployment,
+                                         GCancellable      *cancellable,
+                                         GError           **error);
+
+OstreeDeployment *ostree_sysroot_get_merge_deployment (OstreeSysroot     *self,
+                                                       const char        *osname);
 
 G_END_DECLS
 
diff --git a/src/ostree/ot-admin-builtin-cleanup.c b/src/ostree/ot-admin-builtin-cleanup.c
index db9c667..015dfe7 100644
--- a/src/ostree/ot-admin-builtin-cleanup.c
+++ b/src/ostree/ot-admin-builtin-cleanup.c
@@ -46,6 +46,9 @@ ot_admin_builtin_cleanup (int argc, char **argv, OstreeSysroot *sysroot, GCancel
   if (!g_option_context_parse (context, &argc, &argv, error))
     goto out;
 
+  if (!ostree_sysroot_load (sysroot, cancellable, error))
+    goto out;
+
   if (!ostree_sysroot_cleanup (sysroot, cancellable, error))
     goto out;
 
diff --git a/src/ostree/ot-admin-builtin-deploy.c b/src/ostree/ot-admin-builtin-deploy.c
index 6e5cc60..9761f86 100644
--- a/src/ostree/ot-admin-builtin-deploy.c
+++ b/src/ostree/ot-admin-builtin-deploy.c
@@ -51,13 +51,9 @@ ot_admin_builtin_deploy (int argc, char **argv, OstreeSysroot *sysroot, GCancell
   const char *refspec;
   GOptionContext *context;
   GKeyFile *origin = NULL;
-  int current_bootversion;
-  int new_bootversion;
   gs_unref_object OstreeRepo *repo = NULL;
-  gs_unref_ptrarray GPtrArray *current_deployments = NULL;
   gs_unref_ptrarray GPtrArray *new_deployments = NULL;
   gs_unref_object OstreeDeployment *new_deployment = NULL;
-  gs_unref_object OstreeDeployment *booted_deployment = NULL;
   gs_free char *revision = NULL;
 
   context = g_option_context_new ("REFSPEC - Checkout revision REFSPEC as the new default deployment");
@@ -75,23 +71,17 @@ ot_admin_builtin_deploy (int argc, char **argv, OstreeSysroot *sysroot, GCancell
 
   refspec = argv[1];
 
-  if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
+  if (!ostree_sysroot_load (sysroot, cancellable, error))
     goto out;
 
-  if (!ostree_sysroot_list_deployments (sysroot, &current_bootversion, &current_deployments,
-                                        cancellable, error))
-    {
-      g_prefix_error (error, "While listing deployments: ");
-      goto out;
-    }
+  if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
+    goto out;
 
   /* Find the currently booted deployment, if any; we will ensure it
    * is present in the new deployment list.
    */
-  if (!ostree_sysroot_require_deployment_or_osname (sysroot, current_deployments,
-                                                    opt_osname,
-                                                    &booted_deployment,
-                                                    cancellable, error))
+  if (!ot_admin_require_booted_deployment_or_osname (sysroot, opt_osname,
+                                                     cancellable, error))
     {
       g_prefix_error (error, "Looking for booted deployment: ");
       goto out;
@@ -112,12 +102,12 @@ ot_admin_builtin_deploy (int argc, char **argv, OstreeSysroot *sysroot, GCancell
   if (!ostree_repo_resolve_rev (repo, refspec, FALSE, &revision, error))
     goto out;
 
-  if (!ostree_sysroot_deploy (sysroot, current_bootversion, current_deployments,
-                              opt_osname, revision, origin,
-                              opt_kernel_argv, opt_retain,
-                              booted_deployment, NULL,
-                              &new_deployment, &new_bootversion, &new_deployments,
-                              cancellable, error))
+  if (!ostree_sysroot_deploy_one_tree (sysroot,
+                                       opt_osname, revision, origin,
+                                       opt_kernel_argv, opt_retain,
+                                       NULL,
+                                       &new_deployment,
+                                       cancellable, error))
     goto out;
 
   ret = TRUE;
diff --git a/src/ostree/ot-admin-builtin-diff.c b/src/ostree/ot-admin-builtin-diff.c
index 8c54392..7497e1a 100644
--- a/src/ostree/ot-admin-builtin-diff.c
+++ b/src/ostree/ot-admin-builtin-diff.c
@@ -46,10 +46,8 @@ ot_admin_builtin_diff (int argc, char **argv, OstreeSysroot *sysroot, GCancellab
   gs_unref_ptrarray GPtrArray *modified = NULL;
   gs_unref_ptrarray GPtrArray *removed = NULL;
   gs_unref_ptrarray GPtrArray *added = NULL;
-  gs_unref_ptrarray GPtrArray *deployments = NULL;
   gs_unref_object GFile *orig_etc_path = NULL;
   gs_unref_object GFile *new_etc_path = NULL;
-  int bootversion;
 
   context = g_option_context_new ("Diff current /etc configuration versus default");
 
@@ -58,27 +56,24 @@ ot_admin_builtin_diff (int argc, char **argv, OstreeSysroot *sysroot, GCancellab
   if (!g_option_context_parse (context, &argc, &argv, error))
     goto out;
   
-  if (!ostree_sysroot_list_deployments (sysroot, &bootversion, &deployments,
-                                        cancellable, error))
-    {
-      g_prefix_error (error, "While listing deployments: ");
-      goto out;
-    }
+  if (!ostree_sysroot_load (sysroot, cancellable, error))
+    goto out;
 
-  if (!ostree_sysroot_require_deployment_or_osname (sysroot, deployments,
-                                                    opt_osname, &deployment,
-                                                    cancellable, error))
+  if (!ot_admin_require_booted_deployment_or_osname (sysroot, opt_osname,
+                                                     cancellable, error))
     goto out;
-  if (deployment != NULL)
-    opt_osname = (char*)ostree_deployment_get_osname (deployment);
-  if (deployment == NULL)
-    deployment = ostree_sysroot_get_merge_deployment (deployments, opt_osname, deployment);
-  if (deployment == NULL)
+  if (opt_osname != NULL)
     {
-      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
-                   "No deployment for OS '%s'", opt_osname);
-      goto out;
+      deployment = ostree_sysroot_get_merge_deployment (sysroot, opt_osname);
+      if (deployment == NULL)
+        {
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+                       "No deployment for OS '%s'", opt_osname);
+          goto out;
+        }
     }
+  else
+    deployment = g_object_ref (ostree_sysroot_get_booted_deployment (sysroot));
 
   deployment_dir = ostree_sysroot_get_deployment_directory (sysroot, deployment);
 
diff --git a/src/ostree/ot-admin-builtin-status.c b/src/ostree/ot-admin-builtin-status.c
index c561eaf..1f7801f 100644
--- a/src/ostree/ot-admin-builtin-status.c
+++ b/src/ostree/ot-admin-builtin-status.c
@@ -38,8 +38,7 @@ ot_admin_builtin_status (int argc, char **argv, OstreeSysroot *sysroot, GCancell
 {
   GOptionContext *context;
   gboolean ret = FALSE;
-  int bootversion;
-  gs_unref_object OstreeDeployment *booted_deployment = NULL;
+  OstreeDeployment *booted_deployment = NULL;
   gs_unref_ptrarray GPtrArray *deployments = NULL;
   guint i;
 
@@ -50,31 +49,18 @@ ot_admin_builtin_status (int argc, char **argv, OstreeSysroot *sysroot, GCancell
   if (!g_option_context_parse (context, &argc, &argv, error))
     goto out;
 
-  if (!ostree_sysroot_list_deployments (sysroot, &bootversion, &deployments,
-                                        cancellable, error))
-    {
-      g_prefix_error (error, "While listing deployments: ");
-      goto out;
-    }
-
-  if (!ostree_sysroot_find_booted_deployment (sysroot, deployments,
-                                              &booted_deployment,
-                                              cancellable, error))
+  if (!ostree_sysroot_load (sysroot, cancellable, error))
     goto out;
 
+  deployments = ostree_sysroot_get_deployments (sysroot);
+  booted_deployment = ostree_sysroot_get_booted_deployment (sysroot);
+
   if (deployments->len == 0)
     {
       g_print ("No deployments.\n");
     }
   else
     {
-      int subbootversion;
-
-      if (!ostree_sysroot_read_current_subbootversion (sysroot, bootversion,
-                                                 &subbootversion,
-                                                 cancellable, error))
-        goto out;
-
       for (i = 0; i < deployments->len; i++)
         {
           OstreeDeployment *deployment = deployments->pdata[i];
diff --git a/src/ostree/ot-admin-builtin-undeploy.c b/src/ostree/ot-admin-builtin-undeploy.c
index 1de2a6c..055209d 100644
--- a/src/ostree/ot-admin-builtin-undeploy.c
+++ b/src/ostree/ot-admin-builtin-undeploy.c
@@ -38,7 +38,6 @@ ot_admin_builtin_undeploy (int argc, char **argv, OstreeSysroot *sysroot, GCance
   GOptionContext *context;
   const char *deploy_index_str;
   int deploy_index;
-  int current_bootversion;
   gs_unref_ptrarray GPtrArray *current_deployments = NULL;
   gs_unref_object OstreeDeployment *booted_deployment = NULL;
   gs_unref_object OstreeDeployment *target_deployment = NULL;
@@ -56,20 +55,13 @@ ot_admin_builtin_undeploy (int argc, char **argv, OstreeSysroot *sysroot, GCance
       goto out;
     }
 
+  if (!ostree_sysroot_load (sysroot, cancellable, error))
+    goto out;
+  current_deployments = ostree_sysroot_get_deployments (sysroot);
+
   deploy_index_str = argv[1];
   deploy_index = atoi (deploy_index_str);
 
-  if (!ostree_sysroot_list_deployments (sysroot, &current_bootversion, &current_deployments,
-                                        cancellable, error))
-    {
-      g_prefix_error (error, "While listing deployments: ");
-      goto out;
-    }
-
-  if (!ostree_sysroot_find_booted_deployment (sysroot, current_deployments, &booted_deployment,
-                                              cancellable, error))
-    goto out;
-
   if (deploy_index < 0)
     {
       g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
@@ -84,7 +76,7 @@ ot_admin_builtin_undeploy (int argc, char **argv, OstreeSysroot *sysroot, GCance
     }
   
   target_deployment = g_object_ref (current_deployments->pdata[deploy_index]);
-  if (target_deployment == booted_deployment)
+  if (target_deployment == ostree_sysroot_get_booted_deployment (sysroot))
     {
       g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
                    "Cannot undeploy currently booted deployment %i", deploy_index);
@@ -93,8 +85,7 @@ ot_admin_builtin_undeploy (int argc, char **argv, OstreeSysroot *sysroot, GCance
   
   g_ptr_array_remove_index (current_deployments, deploy_index);
 
-  if (!ostree_sysroot_write_deployments (sysroot, current_bootversion,
-                                         current_bootversion ? 0 : 1, current_deployments,
+  if (!ostree_sysroot_write_deployments (sysroot, current_deployments,
                                          cancellable, error))
     goto out;
 
diff --git a/src/ostree/ot-admin-builtin-upgrade.c b/src/ostree/ot-admin-builtin-upgrade.c
index 563b14b..045d132 100644
--- a/src/ostree/ot-admin-builtin-upgrade.c
+++ b/src/ostree/ot-admin-builtin-upgrade.c
@@ -53,13 +53,8 @@ ot_admin_builtin_upgrade (int argc, char **argv, OstreeSysroot *sysroot, GCancel
   gs_free char *new_revision = NULL;
   gs_unref_object GFile *deployment_path = NULL;
   gs_unref_object GFile *deployment_origin_path = NULL;
-  gs_unref_object OstreeDeployment *booted_deployment = NULL;
   gs_unref_object OstreeDeployment *merge_deployment = NULL;
-  gs_unref_ptrarray GPtrArray *current_deployments = NULL;
-  gs_unref_ptrarray GPtrArray *new_deployments = NULL;
   gs_unref_object OstreeDeployment *new_deployment = NULL;
-  int current_bootversion;
-  int new_bootversion;
   GKeyFile *origin;
 
   context = g_option_context_new ("Construct new tree from current origin and deploy it, if it changed");
@@ -68,23 +63,15 @@ ot_admin_builtin_upgrade (int argc, char **argv, OstreeSysroot *sysroot, GCancel
   if (!g_option_context_parse (context, &argc, &argv, error))
     goto out;
 
-  if (!ostree_sysroot_list_deployments (sysroot, &current_bootversion,
-                                        &current_deployments,
-                                        cancellable, error))
-    {
-      g_prefix_error (error, "While listing deployments: ");
-      goto out;
-    }
+  if (!ostree_sysroot_load (sysroot, cancellable, error))
+    goto out;
 
-  if (!ostree_sysroot_require_deployment_or_osname (sysroot, current_deployments,
-                                                    opt_osname,
-                                                    &booted_deployment,
-                                                    cancellable, error))
+  if (!ot_admin_require_booted_deployment_or_osname (sysroot, opt_osname,
+                                                     cancellable, error))
     goto out;
   if (!opt_osname)
-    opt_osname = (char*)ostree_deployment_get_osname (booted_deployment);
-  merge_deployment = ostree_sysroot_get_merge_deployment (current_deployments, opt_osname,
-                                                          booted_deployment);
+    opt_osname = (char*)ostree_deployment_get_osname (ostree_sysroot_get_booted_deployment (sysroot));
+  merge_deployment = ostree_sysroot_get_merge_deployment (sysroot, opt_osname); 
 
   deployment_path = ostree_sysroot_get_deployment_directory (sysroot, merge_deployment);
   deployment_origin_path = ostree_sysroot_get_deployment_origin_path (deployment_path);
@@ -131,13 +118,12 @@ ot_admin_builtin_upgrade (int argc, char **argv, OstreeSysroot *sysroot, GCancel
   else
     {
       gs_unref_object GFile *real_sysroot = g_file_new_for_path ("/");
-      if (!ostree_sysroot_deploy (sysroot,
-                                  current_bootversion, current_deployments,
-                                  opt_osname, new_revision, origin,
-                                  NULL, FALSE,
-                                  booted_deployment, merge_deployment,
-                                  &new_deployment, &new_bootversion, &new_deployments,
-                                  cancellable, error))
+      if (!ostree_sysroot_deploy_one_tree (sysroot,
+                                           opt_osname, new_revision, origin,
+                                           NULL, FALSE,
+                                           merge_deployment,
+                                           &new_deployment,
+                                           cancellable, error))
         goto out;
 
       if (opt_reboot && g_file_equal (ostree_sysroot_get_path (sysroot), real_sysroot))
diff --git a/src/ostree/ot-admin-functions.c b/src/ostree/ot-admin-functions.c
index c72c15b..90f3a4e 100644
--- a/src/ostree/ot-admin-functions.c
+++ b/src/ostree/ot-admin-functions.c
@@ -34,3 +34,25 @@ ot_origin_new_from_refspec (const char *refspec)
   g_key_file_set_string (ret, "origin", "refspec", refspec);
   return ret;
 }
+
+gboolean
+ot_admin_require_booted_deployment_or_osname (OstreeSysroot       *sysroot,
+                                              const char          *osname,
+                                              GCancellable        *cancellable,
+                                              GError             **error)
+{
+  gboolean ret = FALSE;
+  OstreeDeployment *booted_deployment =
+    ostree_sysroot_get_booted_deployment (sysroot);
+
+  if (booted_deployment == NULL && osname == NULL)
+    {
+      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                           "Not currently booted into an OSTree system and no --os= argument given");
+      goto out;
+    }
+
+  ret = TRUE;
+ out:
+  return ret;
+}
diff --git a/src/ostree/ot-admin-functions.h b/src/ostree/ot-admin-functions.h
index 189974f..8b9758d 100644
--- a/src/ostree/ot-admin-functions.h
+++ b/src/ostree/ot-admin-functions.h
@@ -29,5 +29,11 @@ G_BEGIN_DECLS
 
 GKeyFile *ot_origin_new_from_refspec (const char *refspec);
 
+gboolean
+ot_admin_require_booted_deployment_or_osname (OstreeSysroot       *sysroot,
+                                              const char          *osname,
+                                              GCancellable        *cancellable,
+                                              GError             **error);
+
 G_END_DECLS
 


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