[ostree/wip/libsysroot: 1/2] wip



commit a7c26b032d4cd0e0259a5032f8c6e6a4b0644ca3
Author: Colin Walters <walters verbum org>
Date:   Mon Sep 16 22:37:00 2013 -0400

    wip

 src/libostree/ostree-sysroot-cleanup.c |   13 +-
 src/libostree/ostree-sysroot-deploy.c  |  406 +++++++++++---------------------
 src/libostree/ostree-sysroot-private.h |    6 +
 src/libostree/ostree-sysroot.c         |    4 +
 src/libostree/ostree-sysroot.h         |    1 -
 src/ostree/ot-admin-builtin-deploy.c   |   11 +-
 src/ostree/ot-admin-builtin-upgrade.c  |    7 +-
 src/ostree/ot-admin-functions.c        |   47 ++++
 src/ostree/ot-admin-functions.h        |    9 +
 9 files changed, 222 insertions(+), 282 deletions(-)
---
diff --git a/src/libostree/ostree-sysroot-cleanup.c b/src/libostree/ostree-sysroot-cleanup.c
index 186c6cb..29ff995 100644
--- a/src/libostree/ostree-sysroot-cleanup.c
+++ b/src/libostree/ostree-sysroot-cleanup.c
@@ -25,11 +25,11 @@
 
 #include "ostree-sysroot-private.h"
 
-static gboolean
-list_deployment_dirs_for_os (GFile               *osdir,
-                             GPtrArray           *inout_deployments,
-                             GCancellable        *cancellable,
-                             GError             **error)
+gboolean
+_ostree_sysroot_list_deployment_dirs_for_os (GFile               *osdir,
+                                             GPtrArray           *inout_deployments,
+                                             GCancellable        *cancellable,
+                                             GError             **error)
 {
   gboolean ret = FALSE;
   const char *osname = gs_file_get_basename_cached (osdir);
@@ -136,7 +136,8 @@ list_all_deployment_directories (OstreeSysroot       *self,
       if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
         continue;
       
-      if (!list_deployment_dirs_for_os (child, ret_deployments, cancellable, error))
+      if (!_ostree_sysroot_list_deployment_dirs_for_os (child, ret_deployments,
+                                                        cancellable, error))
         goto out;
     }
   
diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c
index 14136d2..2b32cf0 100644
--- a/src/libostree/ostree-sysroot-deploy.c
+++ b/src/libostree/ostree-sysroot-deploy.c
@@ -459,224 +459,6 @@ checksum_from_kernel_src (GFile        *src,
   return TRUE;
 }
 
-static int
-sort_by_bootserial (gconstpointer ap, gconstpointer bp)
-{
-  OstreeDeployment **a_loc = (OstreeDeployment**)ap;
-  OstreeDeployment *a = *a_loc;
-  OstreeDeployment **b_loc = (OstreeDeployment**)bp;
-  OstreeDeployment *b = *b_loc;
-
-  if (ostree_deployment_get_bootserial (a) == ostree_deployment_get_bootserial (b))
-    return 0;
-  else if (ostree_deployment_get_bootserial (a) < ostree_deployment_get_bootserial (b))
-    return -1;
-  return 1;
-}
-
-static GPtrArray *
-filter_deployments_by_bootcsum (GPtrArray    *deployments,
-                                const char   *osname,
-                                const char   *bootcsum)
-{
-  GPtrArray *ret = g_ptr_array_new ();
-  guint i;
-
-  for (i = 0; i < deployments->len; i++)
-    {
-      OstreeDeployment *deployment = deployments->pdata[i];
-      
-      if (strcmp (ostree_deployment_get_osname (deployment), osname) != 0)
-        continue;
-      if (strcmp (ostree_deployment_get_bootcsum (deployment), bootcsum) != 0)
-        continue;
-      
-      g_ptr_array_add (ret, deployment);
-    }
-  g_ptr_array_sort (ret, sort_by_bootserial);
-
-  return ret;
-}
-
-static void
-compute_new_deployment_list (int           current_bootversion,
-                             GPtrArray    *current_deployments,
-                             const char   *osname,
-                             OstreeDeployment *booted_deployment,
-                             OstreeDeployment *merge_deployment,
-                             gboolean      retain,
-                             const char   *revision,
-                             const char   *bootcsum,
-                             GPtrArray   **out_new_deployments)
-{
-  guint i;
-  int new_index;
-  guint new_deployserial = 0;
-  int new_bootserial = 0;
-  gs_unref_object OstreeDeployment *new_deployment = NULL;
-  gs_unref_ptrarray GPtrArray *matching_deployments_by_bootserial = NULL;
-  OstreeDeployment *deployment_to_delete = NULL;
-  gs_unref_ptrarray GPtrArray *ret_new_deployments = NULL;
-
-  /* First, compute the serial for this deployment; we look
-   * for other ones in this os with the same checksum.
-   */
-  for (i = 0; i < current_deployments->len; i++)
-    {
-      OstreeDeployment *deployment = current_deployments->pdata[i];
-      
-      if (strcmp (ostree_deployment_get_osname (deployment), osname) != 0)
-        continue;
-      if (strcmp (ostree_deployment_get_csum (deployment), revision) != 0)
-        continue;
-
-      new_deployserial = MAX(new_deployserial, ostree_deployment_get_deployserial (deployment)+1);
-    }
-
-  /* We retain by default (well, hardcoded now) one previous
-   * deployment for this OS, plus the booted deployment.  Usually, we
-   * have one previous, one into which we're booted, and we're
-   * deploying a new one.  So the old previous will get swapped out,
-   * and booted becomes previous.
-   *
-   * But if the user then upgrades again, we will end up pruning the
-   * front of the deployment list.  We never delete the running
-   * deployment.
-   */
-  if (!retain)
-    {
-      for (i = 0; i < current_deployments->len; i++)
-        {
-          OstreeDeployment *deployment = current_deployments->pdata[i];
-      
-          if (strcmp (ostree_deployment_get_osname (deployment), osname) != 0)
-            continue;
-
-          // Keep both the booted and merge deployments
-          if (ostree_deployment_equal (deployment, booted_deployment) || 
-              ostree_deployment_equal (deployment, merge_deployment))
-            continue;
-
-          deployment_to_delete = deployment;
-        }
-    }
-
-  ret_new_deployments = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
-
-  new_deployment = ostree_deployment_new (0, osname, revision, new_deployserial,
-                                      bootcsum, new_bootserial);
-  g_ptr_array_add (ret_new_deployments, g_object_ref (new_deployment));
-  new_index = 1;
-  for (i = 0; i < current_deployments->len; i++)
-    {
-      OstreeDeployment *orig_deployment = current_deployments->pdata[i];
-      gs_unref_object OstreeDeployment *deployment_clone = NULL;
-
-      if (orig_deployment == deployment_to_delete)
-        continue;
-
-      deployment_clone = ostree_deployment_clone (orig_deployment);
-      ostree_deployment_set_index (deployment_clone, new_index);
-      new_index++;
-      g_ptr_array_add (ret_new_deployments, g_object_ref (deployment_clone));
-    }
-
-  /* Just renumber the deployments for the OS we're adding; we don't
-   * handle anything else at the moment.
-   */
-  matching_deployments_by_bootserial = filter_deployments_by_bootcsum (ret_new_deployments,
-                                                                       osname, bootcsum);
-  for (i = 0; i < matching_deployments_by_bootserial->len; i++)
-    {
-      OstreeDeployment *deployment = matching_deployments_by_bootserial->pdata[i];
-      ostree_deployment_set_bootserial (deployment, i);
-    }
-
-  *out_new_deployments = ret_new_deployments;
-  ret_new_deployments = NULL;
-}
-
-static GHashTable *
-object_array_to_set (GPtrArray   *objlist,
-                     GHashFunc    hashfunc,
-                     GEqualFunc   equalfunc)
-{
-  GHashTable *ret = g_hash_table_new_full (hashfunc, equalfunc, g_object_unref, NULL);
-  guint i;
-
-  for (i = 0; i < objlist->len; i++)
-    {
-      GObject *obj = g_object_ref (objlist->pdata[i]);
-      g_hash_table_insert (ret, obj, obj);
-    }
-  
-  return ret;
-}
-
-static GHashTable *
-object_set_subtract (GHashTable *a, GHashTable *b)
-{
-  GHashTable *ret = g_hash_table_new_full (NULL, NULL, g_object_unref, NULL);
-  GHashTableIter hashiter;
-  gpointer hashkey, hashvalue;
-  
-  g_hash_table_iter_init (&hashiter, a);
-  while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue))
-    {
-      if (!g_hash_table_contains (b, hashkey))
-        {
-          GObject *o = g_object_ref (hashkey);
-          g_hash_table_insert (ret, o, o);
-        }
-    }
-
-  return ret;
-}
-
-static void
-print_deployment_set (gboolean    for_removal,
-                      GHashTable *set)
-{
-  GHashTableIter hashiter;
-  gpointer hashkey, hashvalue;
-
-  if (g_hash_table_size (set) == 0)
-    return;
-
-  g_print ("%s\n", for_removal ? "removed:" : "added: ");
-
-  g_hash_table_iter_init (&hashiter, set);
-  while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue))
-    {
-      OstreeDeployment *deployment = hashkey;
-
-      g_print ("  %c %s %s.%d",
-               for_removal ? '-' : '+', ostree_deployment_get_osname (deployment),
-               ostree_deployment_get_csum (deployment),
-               ostree_deployment_get_deployserial (deployment));
-
-      if (!for_removal)
-        g_print (" index=%d", ostree_deployment_get_index (deployment));
-      g_print ("\n");
-    }
-}
-
-static void
-print_deployment_diff (GPtrArray   *current_deployments,
-                       GPtrArray   *new_deployments)
-{
-  gs_unref_hashtable GHashTable *curset = object_array_to_set (current_deployments, ostree_deployment_hash, 
ostree_deployment_equal);
-  gs_unref_hashtable GHashTable *newset = object_array_to_set (new_deployments, ostree_deployment_hash, 
ostree_deployment_equal);
-  gs_unref_hashtable GHashTable *removed = NULL;
-  gs_unref_hashtable GHashTable *added = NULL;
-
-  removed = object_set_subtract (curset, newset);
-  added = object_set_subtract (newset, curset);
-
-  print_deployment_set (TRUE, removed);
-  print_deployment_set (FALSE, added);
-}
-
 /* FIXME: We should really do individual fdatasync() on files/dirs,
  * since this causes us to block on unrelated I/O.  However, it's just
  * safer for now.
@@ -970,7 +752,8 @@ swap_bootloader (OstreeSysroot  *sysroot,
 }
 
 static GHashTable *
-bootcsum_counts_for_deployment_list (GPtrArray   *deployments)
+bootcsum_counts_for_deployment_list (GPtrArray   *deployments,
+                                     gboolean     set_bootserial)
 {
   guint i;
   GHashTable *ret = 
@@ -984,7 +767,52 @@ bootcsum_counts_for_deployment_list (GPtrArray   *deployments)
 
       count = GPOINTER_TO_UINT (g_hash_table_lookup (ret, bootcsum));
       g_hash_table_replace (ret, (char*)bootcsum, GUINT_TO_POINTER (count + 1));
+
+      if (set_bootserial)
+        ostree_deployment_set_bootserial (deployment, count);
+    }
+  return ret;
+}
+
+/* TEMPORARY HACK: Add a "current" symbolic link that's easy to
+ * follow inside the gnome-ostree build scripts.  This isn't atomic,
+ * but that doesn't matter because it's only used by deployments
+ * done from the host.
+ */
+static gboolean
+create_current_symlinks (OstreeSysroot         *self,
+                         GCancellable          *cancellable,
+                         GError               **error)
+{
+  gboolean ret = FALSE;
+  guint i;
+  gs_unref_hashtable GHashTable *created_current_for_osname =
+    g_hash_table_new (g_str_hash, g_str_equal);
+
+  for (i = 0; i < self->deployments->len; i++)
+    {
+      OstreeDeployment *deployment = self->deployments->pdata[i];
+      const char *osname = ostree_deployment_get_osname (deployment);
+
+      if (!g_hash_table_lookup (created_current_for_osname, osname))
+        {
+          gs_unref_object GFile *osdir = ot_gfile_resolve_path_printf (self->path, "ostree/deploy/%s", 
osname);
+          gs_unref_object GFile *os_current_path = g_file_get_child (osdir, "current");
+          gs_unref_object GFile *deployment_path = ostree_sysroot_get_deployment_directory (self, 
deployment);
+          gs_free char *target = g_file_get_relative_path (osdir, deployment_path);
+          
+          g_assert (target != NULL);
+          
+          if (!ot_gfile_atomic_symlink_swap (os_current_path, target,
+                                             cancellable, error))
+            goto out;
+
+          g_hash_table_insert (created_current_for_osname, (char*)osname, GUINT_TO_POINTER (1));
+        }
     }
+
+  ret = TRUE;
+ out:
   return ret;
 }
 
@@ -1007,9 +835,16 @@ ostree_sysroot_write_deployments (OstreeSysroot     *self,
   gboolean ret = FALSE;
   guint i;
   gboolean requires_new_bootversion = FALSE;
+  gboolean found_booted_deployment = FALSE;
+  gs_unref_hashtable GHashTable *new_bootcsum_to_count = NULL;
 
   g_assert (self->loaded);
 
+  /* Calculate the total number of deployments per bootcsums; while we
+   * are doing this, assign a bootserial to each new deployment.
+   */
+  new_bootcsum_to_count = bootcsum_counts_for_deployment_list (new_deployments, TRUE);
+
   /* 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
@@ -1022,9 +857,7 @@ ostree_sysroot_write_deployments (OstreeSysroot     *self,
       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);
+        = bootcsum_counts_for_deployment_list (self->deployments, FALSE);
 
       g_hash_table_iter_init (&hashiter, orig_bootcsum_to_count);
       while (g_hash_table_iter_next (&hashiter, &hkey, &hvalue))
@@ -1041,6 +874,22 @@ ostree_sysroot_write_deployments (OstreeSysroot     *self,
         }
     }
 
+  for (i = 0; i < new_deployments->len; i++)
+    {
+      OstreeDeployment *deployment = new_deployments->pdata[i];
+      
+      if (deployment == self->booted_deployment)
+        found_booted_deployment = TRUE;
+
+      ostree_deployment_set_index (deployment, 0);
+    }
+
+  if (self->booted_deployment && !found_booted_deployment)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Attempting to remove booted deployment");
+      goto out;
+    }
+
   if (!requires_new_bootversion)
     {
       if (!full_system_sync (cancellable, error))
@@ -1108,6 +957,16 @@ ostree_sysroot_write_deployments (OstreeSysroot     *self,
         }
     }
 
+  g_print ("Transaction complete, performing cleanup\n");
+
+  /* And finally, cleanup of any leftover data.
+   */
+  if (!ostree_sysroot_cleanup (self, cancellable, error))
+    {
+      g_prefix_error (error, "Performing final cleanup: ");
+      goto out;
+    }
+
   /* Now reload from disk */
   if (!ostree_sysroot_load (self, cancellable, error))
     {
@@ -1115,10 +974,52 @@ ostree_sysroot_write_deployments (OstreeSysroot     *self,
       goto out;
     }
 
+  if (!create_current_symlinks (self, cancellable, error))
+    goto out;
+
   ret = TRUE;
  out:
   return ret;
 }
+
+static gboolean
+allocate_deployserial (OstreeSysroot           *self,
+                       const char              *osname,
+                       const char              *revision,
+                       int                     *out_deployserial,
+                       GCancellable            *cancellable,
+                       GError                 **error)
+{
+  gboolean ret = FALSE;
+  guint i;
+  int new_deployserial = 0;
+  gs_unref_object GFile *osdir = NULL;
+  gs_unref_ptrarray GPtrArray *tmp_current_deployments =
+    g_ptr_array_new_with_free_func (g_object_unref);
+
+  osdir = ot_gfile_get_child_build_path (self->path, "ostree/deploy", osname, NULL);
+  
+  if (!_ostree_sysroot_list_deployment_dirs_for_os (osdir, tmp_current_deployments,
+                                                    cancellable, error))
+    goto out;
+
+  for (i = 0; i < tmp_current_deployments->len; i++)
+    {
+      OstreeDeployment *deployment = tmp_current_deployments->pdata[i];
+      
+      if (strcmp (ostree_deployment_get_osname (deployment), osname) != 0)
+        continue;
+      if (strcmp (ostree_deployment_get_csum (deployment), revision) != 0)
+        continue;
+
+      new_deployserial = MAX(new_deployserial, ostree_deployment_get_deployserial (deployment)+1);
+    }
+
+  ret = TRUE;
+  *out_deployserial = new_deployserial;
+ out:
+  return ret;
+}
                             
 /**
  * ostree_sysroot_deploy_one_tree:
@@ -1127,14 +1028,13 @@ ostree_sysroot_write_deployments (OstreeSysroot     *self,
  * @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
  * @provided_merge_deployment: (allow-none): Use this deployment for merge path
  * @out_new_deployment: (out): The new deployment path
  * @cancellable: Cancellable
  * @error: Error
  *
- * Add a new deployment with revision @revision; if @retain is %FALSE,
- * then an earlier deployment will be garbage collected.
+ * Check out deployment tree with revision @revision, performing a 3
+ * way merge with @provided_merge_deployment for configuration.
  */
 gboolean
 ostree_sysroot_deploy_one_tree (OstreeSysroot     *self,
@@ -1142,14 +1042,14 @@ ostree_sysroot_deploy_one_tree (OstreeSysroot     *self,
                                 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;
+  gint new_deployserial;
+  gs_unref_object OstreeDeployment *new_deployment = NULL;
   gs_unref_object OstreeDeployment *merge_deployment = NULL;
   gs_unref_object OstreeRepo *repo = NULL;
   gs_unref_object GFile *commit_root = NULL;
@@ -1158,7 +1058,6 @@ ostree_sysroot_deploy_one_tree (OstreeSysroot     *self,
   gs_unref_object GFile *new_deployment_path = NULL;
   gs_free char *new_bootcsum = NULL;
   gs_unref_object OstreeBootconfigParser *bootconfig = NULL;
-  gs_unref_ptrarray GPtrArray *new_deployments = NULL;
 
   g_return_val_if_fail (osname != NULL || self->booted_deployment != NULL, FALSE);
 
@@ -1199,25 +1098,16 @@ ostree_sysroot_deploy_one_tree (OstreeSysroot     *self,
         goto out;
     }
 
-  /* If we're booted into the OS into which we're deploying, then
-   * merge the currently *booted* configuration, rather than the most
-   * recently deployed.
-   */
   if (provided_merge_deployment != NULL)
     merge_deployment = g_object_ref (provided_merge_deployment);
-  else
-    merge_deployment = ostree_sysroot_get_merge_deployment (self, osname);
-
-  compute_new_deployment_list (self->bootversion,
-                               self->deployments, osname,
-                               self->booted_deployment, merge_deployment,
-                               retain,
-                               revision, new_bootcsum,
-                               &new_deployments);
-  new_deployment = g_object_ref (new_deployments->pdata[0]);
-  ostree_deployment_set_origin (new_deployment, origin);
 
-  print_deployment_diff (self->deployments, new_deployments);
+  if (!allocate_deployserial (self, osname, revision, &new_deployserial,
+                              cancellable, error))
+    goto out;
+
+  new_deployment = ostree_deployment_new (0, osname, revision, new_deployserial,
+                                          new_bootcsum, 0);
+  ostree_deployment_set_origin (new_deployment, origin);
 
   /* Check out the userspace tree onto the filesystem */
   if (!checkout_deployment_tree (self, repo, new_deployment, &new_deployment_path,
@@ -1274,34 +1164,6 @@ ostree_sysroot_deploy_one_tree (OstreeSysroot     *self,
       ostree_bootconfig_parser_set (bootconfig, "options", new_options);
     }
 
-  if (!ostree_sysroot_write_deployments (self, new_deployments, cancellable, error))
-    goto out;
-
-  g_print ("Transaction complete, performing cleanup\n");
-
-  /* TEMPORARY HACK: Add a "current" symbolic link that's easy to
-   * follow inside the gnome-ostree build scripts.  This isn't atomic,
-   * but that doesn't matter because it's only used by deployments
-   * done from the host.
-   */
-  {
-    gs_unref_object GFile *osdir = ot_gfile_resolve_path_printf (self->path, "ostree/deploy/%s", 
ostree_deployment_get_osname (new_deployment));
-    gs_unref_object GFile *os_current_path = g_file_get_child (osdir, "current");
-    gs_free char *target = g_file_get_relative_path (osdir, new_deployment_path);
-    g_assert (target != NULL);
-    if (!ot_gfile_atomic_symlink_swap (os_current_path, target,
-                                       cancellable, error))
-      goto out;
-  }
-
-  /* And finally, cleanup of any leftover data.
-   */
-  if (!ostree_sysroot_cleanup (self, cancellable, error))
-    {
-      g_prefix_error (error, "Performing final cleanup: ");
-      goto out;
-    }
-
   ret = TRUE;
   ot_transfer_out_value (out_new_deployment, &new_deployment);
  out:
diff --git a/src/libostree/ostree-sysroot-private.h b/src/libostree/ostree-sysroot-private.h
index 864d3cd..ce79fb8 100644
--- a/src/libostree/ostree-sysroot-private.h
+++ b/src/libostree/ostree-sysroot-private.h
@@ -61,6 +61,12 @@ _ostree_sysroot_parse_deploy_path_name (const char *name,
                                         GError    **error);
 
 gboolean
+_ostree_sysroot_list_deployment_dirs_for_os (GFile               *osdir,
+                                             GPtrArray           *inout_deployments,
+                                             GCancellable        *cancellable,
+                                             GError             **error);
+
+gboolean
 _ostree_sysroot_get_devino (GFile         *path,
                             guint32       *out_device,
                             guint64       *out_inode,
diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c
index bf064d5..92d7b03 100644
--- a/src/libostree/ostree-sysroot.c
+++ b/src/libostree/ostree-sysroot.c
@@ -1070,6 +1070,10 @@ ostree_sysroot_get_merge_deployment (OstreeSysroot     *self,
   if (osname == NULL)
     osname = ostree_deployment_get_osname (self->booted_deployment);
 
+  /* If we're booted into the OS into which we're deploying, then
+   * merge the currently *booted* configuration, rather than the most
+   * recently deployed.
+   */
   if (self->booted_deployment &&
       g_strcmp0 (ostree_deployment_get_osname (self->booted_deployment), osname) == 0)
     {
diff --git a/src/libostree/ostree-sysroot.h b/src/libostree/ostree-sysroot.h
index d8959c4..a61f491 100644
--- a/src/libostree/ostree-sysroot.h
+++ b/src/libostree/ostree-sysroot.h
@@ -76,7 +76,6 @@ gboolean ostree_sysroot_deploy_one_tree (OstreeSysroot     *self,
                                          const char        *revision,
                                          GKeyFile          *origin,
                                          char             **add_kernel_argv,
-                                         gboolean           retain,
                                          OstreeDeployment  *provided_merge_deployment,
                                          OstreeDeployment **out_new_deployment,
                                          GCancellable      *cancellable,
diff --git a/src/ostree/ot-admin-builtin-deploy.c b/src/ostree/ot-admin-builtin-deploy.c
index 9761f86..efe543b 100644
--- a/src/ostree/ot-admin-builtin-deploy.c
+++ b/src/ostree/ot-admin-builtin-deploy.c
@@ -54,6 +54,7 @@ ot_admin_builtin_deploy (int argc, char **argv, OstreeSysroot *sysroot, GCancell
   gs_unref_object OstreeRepo *repo = NULL;
   gs_unref_ptrarray GPtrArray *new_deployments = NULL;
   gs_unref_object OstreeDeployment *new_deployment = NULL;
+  gs_unref_object OstreeDeployment *merge_deployment = NULL;
   gs_free char *revision = NULL;
 
   context = g_option_context_new ("REFSPEC - Checkout revision REFSPEC as the new default deployment");
@@ -102,14 +103,20 @@ ot_admin_builtin_deploy (int argc, char **argv, OstreeSysroot *sysroot, GCancell
   if (!ostree_repo_resolve_rev (repo, refspec, FALSE, &revision, error))
     goto out;
 
+  merge_deployment = ostree_sysroot_get_merge_deployment (sysroot, opt_osname);
+
   if (!ostree_sysroot_deploy_one_tree (sysroot,
                                        opt_osname, revision, origin,
-                                       opt_kernel_argv, opt_retain,
-                                       NULL,
+                                       opt_kernel_argv, merge_deployment,
                                        &new_deployment,
                                        cancellable, error))
     goto out;
 
+  if (!ot_admin_complete_deploy_one (sysroot, opt_osname,
+                                     new_deployment, merge_deployment, opt_retain,
+                                     cancellable, error))
+    goto out;
+
   ret = TRUE;
  out:
   if (origin)
diff --git a/src/ostree/ot-admin-builtin-upgrade.c b/src/ostree/ot-admin-builtin-upgrade.c
index 73b1bf5..8654e65 100644
--- a/src/ostree/ot-admin-builtin-upgrade.c
+++ b/src/ostree/ot-admin-builtin-upgrade.c
@@ -127,12 +127,17 @@ ot_admin_builtin_upgrade (int argc, char **argv, OstreeSysroot *sysroot, GCancel
       gs_unref_object GFile *real_sysroot = g_file_new_for_path ("/");
       if (!ostree_sysroot_deploy_one_tree (sysroot,
                                            opt_osname, new_revision, origin,
-                                           NULL, FALSE,
+                                           NULL,
                                            merge_deployment,
                                            &new_deployment,
                                            cancellable, error))
         goto out;
 
+      if (!ot_admin_complete_deploy_one (sysroot, opt_osname,
+                                         new_deployment, merge_deployment, FALSE,
+                                         cancellable, error))
+        goto out;
+
       if (opt_reboot && g_file_equal (ostree_sysroot_get_path (sysroot), real_sysroot))
         {
           gs_subprocess_simple_run_sync (NULL, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT,
diff --git a/src/ostree/ot-admin-functions.c b/src/ostree/ot-admin-functions.c
index 90f3a4e..bf9364d 100644
--- a/src/ostree/ot-admin-functions.c
+++ b/src/ostree/ot-admin-functions.c
@@ -56,3 +56,50 @@ ot_admin_require_booted_deployment_or_osname (OstreeSysroot       *sysroot,
  out:
   return ret;
 }
+
+gboolean
+ot_admin_complete_deploy_one (OstreeSysroot      *sysroot,
+                              const char         *osname,
+                              OstreeDeployment   *new_deployment,
+                              OstreeDeployment   *merge_deployment,
+                              gboolean            opt_retain,
+                              GCancellable       *cancellable,
+                              GError            **error)
+{
+  gboolean ret = FALSE;
+  guint i;
+  OstreeDeployment *booted_deployment = NULL;
+  gs_unref_ptrarray GPtrArray *deployments = NULL;
+  gs_unref_ptrarray GPtrArray *new_deployments = g_ptr_array_new_with_free_func (g_object_unref);
+
+  deployments = ostree_sysroot_get_deployments (sysroot);
+  booted_deployment = ostree_sysroot_get_booted_deployment (sysroot);
+
+  g_ptr_array_add (new_deployments, g_object_ref (new_deployment));
+
+  for (i = 0; i < deployments->len; i++)
+    {
+      OstreeDeployment *deployment = deployments->pdata[i];
+      
+      /* Keep deployments with different osnames, as well as the
+       * booted and merge deployments
+       */
+      if (opt_retain ||
+          strcmp (ostree_deployment_get_osname (deployment), osname) != 0 ||
+          ostree_deployment_equal (deployment, booted_deployment) ||
+          ostree_deployment_equal (deployment, merge_deployment))
+        {
+          g_ptr_array_add (new_deployments, g_object_ref (deployment));
+        }
+    }
+
+  if (!ostree_sysroot_write_deployments (sysroot, new_deployments, cancellable, error))
+    goto out;
+
+  if (!ostree_sysroot_cleanup (sysroot, cancellable, error))
+    goto out;
+
+  ret = TRUE;
+ out:
+  return ret;
+}
diff --git a/src/ostree/ot-admin-functions.h b/src/ostree/ot-admin-functions.h
index 8b9758d..e0a824d 100644
--- a/src/ostree/ot-admin-functions.h
+++ b/src/ostree/ot-admin-functions.h
@@ -35,5 +35,14 @@ ot_admin_require_booted_deployment_or_osname (OstreeSysroot       *sysroot,
                                               GCancellable        *cancellable,
                                               GError             **error);
 
+gboolean
+ot_admin_complete_deploy_one (OstreeSysroot      *sysroot,
+                              const char         *osname,
+                              OstreeDeployment   *new_deployment,
+                              OstreeDeployment   *merge_deployment,
+                              gboolean            opt_retain,
+                              GCancellable        *cancellable,
+                              GError             **error);
+
 G_END_DECLS
 


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