[ostree] core: Make compose its own builtin



commit 69f104c558ac7519cd601fb93514003ba1955db1
Author: Colin Walters <walters verbum org>
Date:   Thu Nov 3 22:32:06 2011 -0400

    core: Make compose its own builtin
    
    This will allow more flexibility down the line.

 Makefile-ostree.am                                 |    1 +
 ostree/main.c                                      |    1 +
 ostree/ot-builtin-checkout.c                       |  235 +----------------
 ostree/ot-builtin-compose.c                        |  270 ++++++++++++++++++++
 ostree/ot-builtins.h                               |    1 +
 ...{t0005-checkout-compose.sh => t0005-compose.sh} |    4 +-
 6 files changed, 288 insertions(+), 224 deletions(-)
---
diff --git a/Makefile-ostree.am b/Makefile-ostree.am
index ef26c81..a0a97f5 100644
--- a/Makefile-ostree.am
+++ b/Makefile-ostree.am
@@ -24,6 +24,7 @@ ostree_SOURCES = ostree/main.c \
 	ostree/ot-builtins.h \
 	ostree/ot-builtin-checkout.c \
 	ostree/ot-builtin-commit.c \
+	ostree/ot-builtin-compose.c \
 	ostree/ot-builtin-fsck.c \
 	ostree/ot-builtin-init.c \
 	ostree/ot-builtin-link-file.c \
diff --git a/ostree/main.c b/ostree/main.c
index ad5dfd8..3359227 100644
--- a/ostree/main.c
+++ b/ostree/main.c
@@ -31,6 +31,7 @@ static OstreeBuiltin builtins[] = {
   { "checkout", ostree_builtin_checkout, 0 },
   { "init", ostree_builtin_init, 0 },
   { "commit", ostree_builtin_commit, 0 },
+  { "compose", ostree_builtin_compose, 0 },
   { "link-file", ostree_builtin_link_file, 0 },
   { "log", ostree_builtin_log, 0 },
   { "pull", ostree_builtin_pull, 0 },
diff --git a/ostree/ot-builtin-checkout.c b/ostree/ot-builtin-checkout.c
index 00aaa79..5734257 100644
--- a/ostree/ot-builtin-checkout.c
+++ b/ostree/ot-builtin-checkout.c
@@ -27,194 +27,12 @@
 #include <glib/gi18n.h>
 
 static char *repo_path;
-static gboolean compose;
-
-#define FAST_QUERYINFO "standard::name,standard::type,standard::is-symlink,standard::symlink-target,unix::*"
 
 static GOptionEntry options[] = {
   { "repo", 0, 0, G_OPTION_ARG_FILENAME, &repo_path, "Repository path", "repo" },
-  { "compose", 0, 0, G_OPTION_ARG_NONE, &compose, "Extra arguments are branches to compose, in order", NULL },
   { NULL }
 };
 
-static void
-rm_rf (GFile *path)
-{
-  GFileInfo *finfo = NULL;
-  GFileEnumerator *path_enum = NULL;
-  guint32 type;
-  
-  finfo = g_file_query_info (path, FAST_QUERYINFO,
-                             G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
-                             NULL, NULL);
-  if (!finfo)
-    goto out;
-
-  type = g_file_info_get_attribute_uint32 (finfo, "standard::type");
-  if (type == G_FILE_TYPE_DIRECTORY)
-    {
-      path_enum = g_file_enumerate_children (path, FAST_QUERYINFO, 
-                                             G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
-                                             NULL, NULL);
-      if (!path_enum)
-        goto out;
-
-      
-      g_clear_object (&finfo);
-      while ((finfo = g_file_enumerator_next_file (path_enum, NULL, NULL)) != NULL)
-        {
-          GFile *child = g_file_get_child (path, g_file_info_get_attribute_byte_string (finfo, "standard::name"));
-          rm_rf (child);
-          g_clear_object (&child);
-          g_clear_object (&finfo);
-        }
-    }
-
-  (void) g_file_delete (path, NULL, NULL);
-
- out:
-  g_clear_object (&finfo);
-  g_clear_object (&path_enum);
-}
-
-static gboolean
-merge_dir (GFile    *destination,
-           GFile    *src,
-           GError  **error)
-{
-  gboolean ret = FALSE;
-  char *dest_path = NULL;
-  char *src_path = NULL;
-  GError *temp_error = NULL;
-  GFileInfo *src_fileinfo = NULL;
-  GFileInfo *dest_fileinfo = NULL;
-  GFileEnumerator *src_enum = NULL;
-  GFile *dest_subfile = NULL;
-  GFile *src_subfile = NULL;
-  const char *name;
-  guint32 type;
-
-  dest_path = g_file_get_path (destination);
-  src_path = g_file_get_path (src);
-
-  dest_fileinfo = g_file_query_info (destination, FAST_QUERYINFO,
-                                     G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
-                                     NULL, &temp_error);
-  if (dest_fileinfo)
-    {
-      type = g_file_info_get_attribute_uint32 (dest_fileinfo, "standard::type");
-      if (type != G_FILE_TYPE_DIRECTORY)
-        {
-          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                       "Attempting to replace non-directory %s with directory %s",
-                       dest_path, src_path);
-          goto out;
-        }
-
-      src_enum = g_file_enumerate_children (src, FAST_QUERYINFO, 
-                                            G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
-                                            NULL, error);
-      if (!src_enum)
-        goto out;
-
-      while ((src_fileinfo = g_file_enumerator_next_file (src_enum, NULL, &temp_error)) != NULL)
-        {
-          type = g_file_info_get_attribute_uint32 (src_fileinfo, "standard::type");
-          name = g_file_info_get_attribute_byte_string (src_fileinfo, "standard::name");
-      
-          dest_subfile = g_file_get_child (destination, name);
-          src_subfile = g_file_get_child (src, name);
-
-          if (type == G_FILE_TYPE_DIRECTORY)
-            {
-              if (!merge_dir (dest_subfile, src_subfile, error))
-                goto out;
-            }
-          else
-            {
-              if (!g_file_delete (dest_subfile, NULL, &temp_error))
-                {
-                  if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
-                    g_clear_error (&temp_error);
-                  else
-                    {
-                      g_propagate_error (error, temp_error);
-                      goto out;
-                    }
-                }
-              if (!g_file_move (src_subfile, dest_subfile, 0, NULL, NULL, NULL, error))
-                goto out;
-            }
-        }
-      if (temp_error)
-        {
-          g_propagate_error (error, temp_error);
-          goto out;
-        }
-    }
-  else if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
-    {
-      g_clear_error (&temp_error);
-      if (!g_file_move (src, destination, 0, NULL, NULL, NULL, error))
-        goto out;
-    }
-  else
-    goto out;
-
-  ret = TRUE;
- out:
-  g_free (dest_path);
-  g_free (src_path);
-  g_clear_object (&src_fileinfo);
-  g_clear_object (&dest_fileinfo);
-  g_clear_object (&src_enum);
-  g_clear_object (&dest_subfile);
-  g_clear_object (&src_subfile);
-  return ret;
-}
-
-static gboolean
-compose_branch_on_dir (OstreeRepo *repo,
-                       GFile *destination,
-                       const char *branch,
-                       GError **error)
-{
-  char *destpath = NULL;
-  char *branchpath = NULL;
-  GFile *branchf = NULL;
-  GFileEnumerator *enumerator = NULL;
-  gboolean ret = FALSE;
-  char *branchrev = NULL;
-
-  if (!ostree_repo_resolve_rev (repo, branch, &branchrev, error))
-    goto out;
-  
-  destpath = g_file_get_path (destination);
-  if (g_str_has_suffix (destpath, "/"))
-    destpath[strlen (destpath) - 1] = '\0';
-  branchpath = g_strconcat (destpath, "-tmp-checkout-", branchrev, NULL);
-  branchf = ot_util_new_file_for_path (branchpath);
-
-  g_print ("Checking out %s (commit %s)...\n", branch, branchrev);
-  if (!ostree_repo_checkout (repo, branchrev, branchpath, error))
-    goto out;
-  g_print ("...done\n", branch);
-  g_print ("Merging over destination...\n", branch, branchrev);
-  if (!merge_dir (destination, branchf, error))
-    goto out;
-
-  ret = TRUE;
- out:
-  if (branchf)
-    rm_rf (branchf);
-  g_clear_object (&enumerator);
-  g_clear_object (&branchf);
-  g_free (branchrev);
-  g_free (destpath);
-  g_free (branchpath);
-  return ret;
-}
-
 gboolean
 ostree_builtin_checkout (int argc, char **argv, const char *prefix, GError **error)
 {
@@ -240,48 +58,21 @@ ostree_builtin_checkout (int argc, char **argv, const char *prefix, GError **err
   if (!ostree_repo_check (repo, error))
     goto out;
 
-  if (!compose)
-    { 
-      if (argc < 3)
-        {
-          gchar *help = g_option_context_get_help (context, TRUE, NULL);
-          g_printerr ("%s\n", help);
-          g_free (help);
-          g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                               "COMMIT and DESTINATION must be specified");
-          goto out;
-        }
-      
-      commit = argv[1];
-      destination = argv[2];
-
-      if (!ostree_repo_checkout (repo, commit, destination, error))
-        goto out;
-    }
-  else
+  if (argc < 3)
     {
-      destination = argv[1];
-
-      destf = ot_util_new_file_for_path (destination);
-
-      if (argc < 3)
-        {
-          gchar *help = g_option_context_get_help (context, TRUE, NULL);
-          g_printerr ("%s\n", help);
-          g_free (help);
-          g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                               "DESTINATION and at least one COMMIT must be specified");
-          goto out;
-        }
-
-      for (i = 2; i < argc; i++)
-        {
-          const char *branch = argv[i];
-
-          if (!compose_branch_on_dir (repo, destf, branch, error))
-            goto out;
-        }
+      gchar *help = g_option_context_get_help (context, TRUE, NULL);
+      g_printerr ("%s\n", help);
+      g_free (help);
+      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                           "COMMIT and DESTINATION must be specified");
+      goto out;
     }
+  
+  commit = argv[1];
+  destination = argv[2];
+  
+  if (!ostree_repo_checkout (repo, commit, destination, error))
+    goto out;
 
   ret = TRUE;
  out:
diff --git a/ostree/ot-builtin-compose.c b/ostree/ot-builtin-compose.c
new file mode 100644
index 0000000..571eefd
--- /dev/null
+++ b/ostree/ot-builtin-compose.c
@@ -0,0 +1,270 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2011 Colin Walters <walters verbum org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; 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>
+ */
+
+#include "config.h"
+
+#include "ot-builtins.h"
+#include "ostree.h"
+
+#include <glib/gi18n.h>
+
+static char *repo_path;
+
+#define FAST_QUERYINFO "standard::name,standard::type,standard::is-symlink,standard::symlink-target,unix::*"
+
+static GOptionEntry options[] = {
+  { "repo", 0, 0, G_OPTION_ARG_FILENAME, &repo_path, "Repository path", "repo" },
+  { NULL }
+};
+
+static void
+rm_rf (GFile *path)
+{
+  GFileInfo *finfo = NULL;
+  GFileEnumerator *path_enum = NULL;
+  guint32 type;
+  
+  finfo = g_file_query_info (path, FAST_QUERYINFO,
+                             G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+                             NULL, NULL);
+  if (!finfo)
+    goto out;
+
+  type = g_file_info_get_attribute_uint32 (finfo, "standard::type");
+  if (type == G_FILE_TYPE_DIRECTORY)
+    {
+      path_enum = g_file_enumerate_children (path, FAST_QUERYINFO, 
+                                             G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+                                             NULL, NULL);
+      if (!path_enum)
+        goto out;
+
+      
+      g_clear_object (&finfo);
+      while ((finfo = g_file_enumerator_next_file (path_enum, NULL, NULL)) != NULL)
+        {
+          GFile *child = g_file_get_child (path, g_file_info_get_attribute_byte_string (finfo, "standard::name"));
+          rm_rf (child);
+          g_clear_object (&child);
+          g_clear_object (&finfo);
+        }
+    }
+
+  (void) g_file_delete (path, NULL, NULL);
+
+ out:
+  g_clear_object (&finfo);
+  g_clear_object (&path_enum);
+}
+
+static gboolean
+merge_dir (GFile    *destination,
+           GFile    *src,
+           GError  **error)
+{
+  gboolean ret = FALSE;
+  char *dest_path = NULL;
+  char *src_path = NULL;
+  GError *temp_error = NULL;
+  GFileInfo *src_fileinfo = NULL;
+  GFileInfo *dest_fileinfo = NULL;
+  GFileEnumerator *src_enum = NULL;
+  GFile *dest_subfile = NULL;
+  GFile *src_subfile = NULL;
+  const char *name;
+  guint32 type;
+
+  dest_path = g_file_get_path (destination);
+  src_path = g_file_get_path (src);
+
+  dest_fileinfo = g_file_query_info (destination, FAST_QUERYINFO,
+                                     G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+                                     NULL, &temp_error);
+  if (dest_fileinfo)
+    {
+      type = g_file_info_get_attribute_uint32 (dest_fileinfo, "standard::type");
+      if (type != G_FILE_TYPE_DIRECTORY)
+        {
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                       "Attempting to replace non-directory %s with directory %s",
+                       dest_path, src_path);
+          goto out;
+        }
+
+      src_enum = g_file_enumerate_children (src, FAST_QUERYINFO, 
+                                            G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+                                            NULL, error);
+      if (!src_enum)
+        goto out;
+
+      while ((src_fileinfo = g_file_enumerator_next_file (src_enum, NULL, &temp_error)) != NULL)
+        {
+          type = g_file_info_get_attribute_uint32 (src_fileinfo, "standard::type");
+          name = g_file_info_get_attribute_byte_string (src_fileinfo, "standard::name");
+      
+          dest_subfile = g_file_get_child (destination, name);
+          src_subfile = g_file_get_child (src, name);
+
+          if (type == G_FILE_TYPE_DIRECTORY)
+            {
+              if (!merge_dir (dest_subfile, src_subfile, error))
+                goto out;
+            }
+          else
+            {
+              if (!g_file_delete (dest_subfile, NULL, &temp_error))
+                {
+                  if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+                    g_clear_error (&temp_error);
+                  else
+                    {
+                      g_propagate_error (error, temp_error);
+                      goto out;
+                    }
+                }
+              if (!g_file_move (src_subfile, dest_subfile, 0, NULL, NULL, NULL, error))
+                goto out;
+            }
+        }
+      if (temp_error)
+        {
+          g_propagate_error (error, temp_error);
+          goto out;
+        }
+    }
+  else if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+    {
+      g_clear_error (&temp_error);
+      if (!g_file_move (src, destination, 0, NULL, NULL, NULL, error))
+        goto out;
+    }
+  else
+    goto out;
+
+  ret = TRUE;
+ out:
+  g_free (dest_path);
+  g_free (src_path);
+  g_clear_object (&src_fileinfo);
+  g_clear_object (&dest_fileinfo);
+  g_clear_object (&src_enum);
+  g_clear_object (&dest_subfile);
+  g_clear_object (&src_subfile);
+  return ret;
+}
+
+static gboolean
+compose_branch_on_dir (OstreeRepo *repo,
+                       GFile *destination,
+                       const char *branch,
+                       GError **error)
+{
+  char *destpath = NULL;
+  char *branchpath = NULL;
+  GFile *branchf = NULL;
+  GFileEnumerator *enumerator = NULL;
+  gboolean ret = FALSE;
+  char *branchrev = NULL;
+
+  if (!ostree_repo_resolve_rev (repo, branch, &branchrev, error))
+    goto out;
+  
+  destpath = g_file_get_path (destination);
+  if (g_str_has_suffix (destpath, "/"))
+    destpath[strlen (destpath) - 1] = '\0';
+  branchpath = g_strconcat (destpath, "-tmp-checkout-", branchrev, NULL);
+  branchf = ot_util_new_file_for_path (branchpath);
+
+  g_print ("Checking out %s (commit %s)...\n", branch, branchrev);
+  if (!ostree_repo_checkout (repo, branchrev, branchpath, error))
+    goto out;
+  g_print ("...done\n", branch);
+  g_print ("Merging over destination...\n", branch, branchrev);
+  if (!merge_dir (destination, branchf, error))
+    goto out;
+
+  ret = TRUE;
+ out:
+  if (branchf)
+    rm_rf (branchf);
+  g_clear_object (&enumerator);
+  g_clear_object (&branchf);
+  g_free (branchrev);
+  g_free (destpath);
+  g_free (branchpath);
+  return ret;
+}
+
+gboolean
+ostree_builtin_compose (int argc, char **argv, const char *prefix, GError **error)
+{
+  GOptionContext *context;
+  gboolean ret = FALSE;
+  OstreeRepo *repo = NULL;
+  OstreeCheckout *checkout = NULL;
+  const char *destination;
+  GFile *destf = NULL;
+  int i;
+
+  context = g_option_context_new ("DESTINATION BRANCH1 BRANCH2 ... - Merge multiple commits into a single filesystem tree");
+  g_option_context_add_main_entries (context, options, NULL);
+
+  if (!g_option_context_parse (context, &argc, &argv, error))
+    goto out;
+
+  if (repo_path == NULL)
+    repo_path = ".";
+
+  repo = ostree_repo_new (repo_path);
+  if (!ostree_repo_check (repo, error))
+    goto out;
+
+  destination = argv[1];
+  
+  destf = ot_util_new_file_for_path (destination);
+  
+  if (argc < 3)
+    {
+      gchar *help = g_option_context_get_help (context, TRUE, NULL);
+      g_printerr ("%s\n", help);
+      g_free (help);
+      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                               "DESTINATION and at least one COMMIT must be specified");
+      goto out;
+    }
+  
+  for (i = 2; i < argc; i++)
+    {
+      const char *branch = argv[i];
+      
+      if (!compose_branch_on_dir (repo, destf, branch, error))
+        goto out;
+    }
+
+  ret = TRUE;
+ out:
+  if (context)
+    g_option_context_free (context);
+  g_clear_object (&repo);
+  g_clear_object (&checkout);
+  g_clear_object (&destf);
+  return ret;
+}
diff --git a/ostree/ot-builtins.h b/ostree/ot-builtins.h
index 1373f60..68e471c 100644
--- a/ostree/ot-builtins.h
+++ b/ostree/ot-builtins.h
@@ -38,6 +38,7 @@ typedef struct {
 
 gboolean ostree_builtin_checkout (int argc, char **argv, const char *prefix, GError **error);
 gboolean ostree_builtin_commit (int argc, char **argv, const char *prefix, GError **error);
+gboolean ostree_builtin_compose (int argc, char **argv, const char *prefix, GError **error);
 gboolean ostree_builtin_init (int argc, char **argv, const char *prefix, GError **error);
 gboolean ostree_builtin_log (int argc, char **argv, const char *prefix, GError **error);
 gboolean ostree_builtin_link_file (int argc, char **argv, const char *prefix, GError **error);
diff --git a/tests/t0005-checkout-compose.sh b/tests/t0005-compose.sh
similarity index 93%
rename from tests/t0005-checkout-compose.sh
rename to tests/t0005-compose.sh
index 22c0b2f..4621d64 100755
--- a/tests/t0005-checkout-compose.sh
+++ b/tests/t0005-compose.sh
@@ -20,7 +20,7 @@
 
 set -e
 
-echo "1..8"
+echo "1..2"
 
 . libtest.sh
 
@@ -59,5 +59,5 @@ find | grep -v '^\.$' | ostree commit $ot_repo -b artifact-barapp -s 'Build 42 o
 echo 'ok artifacts committed'
 
 cd "${test_tmpdir}"
-ostree checkout $ot_repo --compose some-compose artifact-libfoo-runtime artifact-libfoo-devel artifact-barapp
+ostree compose $ot_repo some-compose artifact-libfoo-runtime artifact-libfoo-devel artifact-barapp
 echo 'ok compose command'



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