[ostree] core: Add ability for repositories to have a "parent"



commit 5947b5b1453e2514e4c483b836e872c585cb816c
Author: Colin Walters <walters verbum org>
Date:   Mon Apr 16 21:21:50 2012 -0400

    core: Add ability for repositories to have a "parent"
    
    This will be useful for ostbuild; a user can create their own archive
    mode repository which transparently inherits objects from the
    root-owned one in /ostree.

 Makefile-ostree.am             |    1 +
 src/libostree/ostree-repo.c    |  205 +++++++++++++++++++++++++++++++++------
 src/libostree/ostree-repo.h    |   14 +--
 src/ostree/main.c              |    1 +
 src/ostree/ostree-pull.c       |    9 +--
 src/ostree/ot-builtin-config.c |  144 ++++++++++++++++++++++++++++
 src/ostree/ot-builtins.h       |    1 +
 tests/t0000-basic.sh           |   12 ++-
 8 files changed, 339 insertions(+), 48 deletions(-)
---
diff --git a/Makefile-ostree.am b/Makefile-ostree.am
index a1d2e5a..27ace0d 100644
--- a/Makefile-ostree.am
+++ b/Makefile-ostree.am
@@ -22,6 +22,7 @@ bin_PROGRAMS += ostree
 ostree_SOURCES = src/ostree/main.c \
 	src/ostree/ot-builtins.h \
 	src/ostree/ot-builtin-cat.c \
+	src/ostree/ot-builtin-config.c \
 	src/ostree/ot-builtin-checkout.c \
 	src/ostree/ot-builtin-checksum.c \
 	src/ostree/ot-builtin-commit.c \
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index a871498..3aad785 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -40,6 +40,16 @@
 #include "ostree-libarchive-input-stream.h"
 #endif
 
+static gboolean      
+repo_find_object (OstreeRepo           *self,
+                  OstreeObjectType      objtype,
+                  const char           *checksum,
+                  GFile               **out_stored_path,
+                  char                **out_pack_checksum,
+                  guint64              *out_pack_offset,
+                  GCancellable         *cancellable,
+                  GError             **error);
+
 enum {
   PROP_0,
 
@@ -73,6 +83,8 @@ struct _OstreeRepoPrivate {
   GKeyFile *config;
   OstreeRepoMode mode;
 
+  OstreeRepo *parent_repo;
+
   GHashTable *pack_index_mappings;
   GHashTable *pack_data_mappings;
 };
@@ -83,6 +95,8 @@ ostree_repo_finalize (GObject *object)
   OstreeRepo *self = OSTREE_REPO (object);
   OstreeRepoPrivate *priv = GET_PRIVATE (self);
 
+  g_clear_object (&priv->parent_repo);
+
   g_clear_object (&priv->repodir);
   g_clear_object (&priv->tmp_dir);
   g_clear_object (&priv->pending_dir);
@@ -397,7 +411,14 @@ ostree_repo_resolve_rev (OstreeRepo     *self,
               
               if (child == NULL)
                 {
-                  if (!allow_noent)
+                  if (priv->parent_repo)
+                    {
+                      if (!ostree_repo_resolve_rev (priv->parent_repo, rev,
+                                                    allow_noent, &ret_rev,
+                                                    error))
+                        goto out;
+                    }
+                  else if (!allow_noent)
                     {
                       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                                    "Rev '%s' not found", rev);
@@ -641,8 +662,9 @@ ostree_repo_check (OstreeRepo *self, GError **error)
   gboolean ret = FALSE;
   OstreeRepoPrivate *priv = GET_PRIVATE (self);
   gboolean is_archive;
-  ot_lfree char *version = NULL;;
-  ot_lfree char *mode = NULL;;
+  ot_lfree char *version = NULL;
+  ot_lfree char *mode = NULL;
+  ot_lfree char *parent_repo_path = NULL;
 
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
@@ -702,6 +724,24 @@ ostree_repo_check (OstreeRepo *self, GError **error)
         }
     }
 
+  if (!keyfile_get_value_with_default (priv->config, "core", "parent",
+                                       NULL, &parent_repo_path, error))
+    goto out;
+
+  if (parent_repo_path && parent_repo_path[0])
+    {
+      ot_lobj GFile *parent_repo_f = ot_gfile_new_for_path (parent_repo_path);
+
+      priv->parent_repo = ostree_repo_new (parent_repo_f);
+
+      if (!ostree_repo_check (priv->parent_repo, error))
+        {
+          g_prefix_error (error, "While checking parent repository '%s': ",
+                          ot_gfile_get_path_cached (parent_repo_f));
+          goto out;
+        }
+    }
+
   priv->inited = TRUE;
   
   ret = TRUE;
@@ -793,6 +833,7 @@ impl_stage_archive_file_object (OstreeRepo         *self,
                                 GFileInfo          *file_info,
                                 GVariant           *xattrs,
                                 GInputStream       *input,
+                                gboolean            store_if_packed,
                                 const char         *expected_checksum,
                                 guchar            **out_csum,
                                 GCancellable       *cancellable,
@@ -801,6 +842,8 @@ impl_stage_archive_file_object (OstreeRepo         *self,
   gboolean ret = FALSE;
   OstreeRepoPrivate *priv = GET_PRIVATE (self);
   const char *actual_checksum;
+  gboolean have_obj;
+  gboolean do_commit;
   ot_lvariant GVariant *archive_metadata = NULL;
   ot_lobj GFileInfo *temp_info = NULL;
   ot_lobj GFile *temp_file = NULL;
@@ -850,9 +893,25 @@ impl_stage_archive_file_object (OstreeRepo         *self,
   else
     actual_checksum = g_checksum_get_string (checksum);
 
-  if (!commit_tmpfile_trusted (self, actual_checksum, OSTREE_OBJECT_TYPE_FILE,
-                               temp_file, cancellable, error))
-    goto out;
+  if (!store_if_packed)
+    {
+      if (!ostree_repo_has_object (self, OSTREE_OBJECT_TYPE_FILE, actual_checksum, &have_obj,
+                                   cancellable, error))
+        goto out;
+      
+      do_commit = !have_obj;
+    }
+  else
+    do_commit = TRUE;
+
+  if (do_commit)
+    {
+      if (!commit_tmpfile_trusted (self, actual_checksum, OSTREE_OBJECT_TYPE_FILE, 
+                                   temp_file, cancellable, error))
+        goto out;
+
+      g_clear_object (&temp_file);
+    }
 
   if (checksum)
     ret_csum = ot_csum_from_gchecksum (checksum);
@@ -860,6 +919,8 @@ impl_stage_archive_file_object (OstreeRepo         *self,
   ret = TRUE;
   ot_transfer_out_value (out_csum, &ret_csum);
  out:
+  if (temp_file)
+    (void) unlink (ot_gfile_get_path_cached (temp_file));
   ot_clear_checksum (&checksum);
   return ret;
 }
@@ -880,6 +941,7 @@ stage_object_impl (OstreeRepo         *self,
   OstreeRepoPrivate *priv = GET_PRIVATE (self);
   guint64 pack_offset;
   const char *actual_checksum;
+  gboolean do_commit;
   ot_lobj GFileInfo *temp_info = NULL;
   ot_lobj GFile *temp_file = NULL;
   ot_lobj GFile *stored_path = NULL;
@@ -900,16 +962,16 @@ stage_object_impl (OstreeRepo         *self,
     {
       if (!store_if_packed)
         {
-          if (!ostree_repo_find_object (self, objtype, expected_checksum,
-                                        &stored_path, &pack_checksum, &pack_offset,
-                                        cancellable, error))
+          if (!repo_find_object (self, objtype, expected_checksum,
+                                 &stored_path, &pack_checksum, &pack_offset,
+                                 cancellable, error))
             goto out;
         }
       else
         {
-          if (!ostree_repo_find_object (self, objtype, expected_checksum,
-                                        &stored_path, NULL, NULL,
-                                        cancellable, error))
+          if (!repo_find_object (self, objtype, expected_checksum,
+                                 &stored_path, NULL, NULL,
+                                 cancellable, error))
             goto out;
         }
     }
@@ -933,6 +995,7 @@ stage_object_impl (OstreeRepo         *self,
       if (objtype == OSTREE_OBJECT_TYPE_FILE && priv->mode == OSTREE_REPO_MODE_ARCHIVE)
         {
           if (!impl_stage_archive_file_object (self, file_info, xattrs, input,
+                                               store_if_packed,
                                                expected_checksum,
                                                out_csum ? &ret_csum : NULL,
                                                cancellable, error))
@@ -977,12 +1040,29 @@ stage_object_impl (OstreeRepo         *self,
                                expected_checksum, actual_checksum);
                   goto out;
                 }
+
             }
           
-          if (!commit_tmpfile_trusted (self, actual_checksum, objtype, 
-                                       temp_file, cancellable, error))
-            goto out;
-          g_clear_object (&temp_file);
+          if (!store_if_packed)
+            {
+              gboolean have_obj;
+
+              if (!ostree_repo_has_object (self, objtype, actual_checksum, &have_obj,
+                                           cancellable, error))
+                goto out;
+
+              do_commit = !have_obj;
+            }
+          else
+            do_commit = TRUE;
+
+          if (do_commit)
+            {
+              if (!commit_tmpfile_trusted (self, actual_checksum, objtype, 
+                                           temp_file, cancellable, error))
+                goto out;
+              g_clear_object (&temp_file);
+            }
 
           if (checksum)
             ret_csum = ot_csum_from_gchecksum (checksum);
@@ -3140,6 +3220,7 @@ ostree_repo_load_file (OstreeRepo         *self,
                        GError            **error)
 {
   gboolean ret = FALSE;
+  OstreeRepoPrivate *priv = GET_PRIVATE (self);
   guchar *pack_data;
   guint64 pack_len;
   guint64 pack_offset;
@@ -3154,10 +3235,10 @@ ostree_repo_load_file (OstreeRepo         *self,
   ot_lobj GFileInfo *ret_file_info = NULL;
   ot_lvariant GVariant *ret_xattrs = NULL;
 
-  if (!ostree_repo_find_object (self, OSTREE_OBJECT_TYPE_FILE,
-                                checksum, &loose_path,
-                                &pack_checksum, &pack_offset,
-                                cancellable, error))
+  if (!repo_find_object (self, OSTREE_OBJECT_TYPE_FILE,
+                         checksum, &loose_path,
+                         &pack_checksum, &pack_offset,
+                         cancellable, error))
     goto out;
 
   if (loose_path)
@@ -3212,6 +3293,15 @@ ostree_repo_load_file (OstreeRepo         *self,
                                          cancellable, error))
         goto out;
     }
+  else if (priv->parent_repo)
+    {
+      if (!ostree_repo_load_file (priv->parent_repo, checksum, 
+                                  out_input ? &ret_input : NULL,
+                                  out_file_info ? &ret_file_info : NULL,
+                                  out_xattrs ? &ret_xattrs : NULL,
+                                  cancellable, error))
+        goto out;
+    }
   else
     {
       g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
@@ -3399,15 +3489,15 @@ find_object_in_packs (OstreeRepo        *self,
   return ret;
 }
 
-gboolean      
-ostree_repo_find_object (OstreeRepo           *self,
-                         OstreeObjectType      objtype,
-                         const char           *checksum,
-                         GFile               **out_stored_path,
-                         char                **out_pack_checksum,
-                         guint64              *out_pack_offset,
-                         GCancellable         *cancellable,
-                         GError             **error)
+static gboolean      
+repo_find_object (OstreeRepo           *self,
+                  OstreeObjectType      objtype,
+                  const char           *checksum,
+                  GFile               **out_stored_path,
+                  char                **out_pack_checksum,
+                  guint64              *out_pack_offset,
+                  GCancellable         *cancellable,
+                  GError             **error)
 {
   gboolean ret = FALSE;
   guint64 ret_pack_offset = 0;
@@ -3446,6 +3536,41 @@ out:
 }
 
 gboolean
+ostree_repo_has_object (OstreeRepo           *self,
+                        OstreeObjectType      objtype,
+                        const char           *checksum,
+                        gboolean             *out_have_object,
+                        GCancellable         *cancellable,
+                        GError              **error)
+{
+  gboolean ret = FALSE;
+  OstreeRepoPrivate *priv = GET_PRIVATE (self);
+  gboolean ret_have_object;
+  ot_lobj GFile *loose_path = NULL;
+  ot_lfree char *pack_checksum = NULL;
+
+  if (!repo_find_object (self, objtype, checksum, &loose_path,
+                         &pack_checksum, NULL,
+                         cancellable, error))
+    goto out;
+
+  ret_have_object = (loose_path != NULL) || (pack_checksum != NULL);
+
+  if (!ret_have_object && priv->parent_repo)
+    {
+      if (!ostree_repo_has_object (priv->parent_repo, objtype, checksum,
+                                   &ret_have_object, cancellable, error))
+        goto out;
+    }
+                                
+  ret = TRUE;
+  if (out_have_object)
+    *out_have_object = ret_have_object;
+ out:
+  return ret;
+}
+
+gboolean
 ostree_repo_load_variant_c (OstreeRepo          *self,
                             OstreeObjectType     objtype,
                             const guchar        *csum, 
@@ -3473,6 +3598,7 @@ ostree_repo_load_variant (OstreeRepo  *self,
                           GError       **error)
 {
   gboolean ret = FALSE;
+  OstreeRepoPrivate *priv = GET_PRIVATE (self);
   guchar *pack_data;
   guint64 pack_len;
   guint64 object_offset;
@@ -3484,9 +3610,9 @@ ostree_repo_load_variant (OstreeRepo  *self,
 
   g_return_val_if_fail (OSTREE_OBJECT_TYPE_IS_META (objtype), FALSE);
 
-  if (!ostree_repo_find_object (self, objtype, sha256, &object_path,
-                                &pack_checksum, &object_offset,
-                                cancellable, error))
+  if (!repo_find_object (self, objtype, sha256, &object_path,
+                         &pack_checksum, &object_offset,
+                         cancellable, error))
     goto out;
 
   /* Prefer loose metadata for now */
@@ -3508,6 +3634,11 @@ ostree_repo_load_variant (OstreeRepo  *self,
 
       g_variant_get_child (packed_object, 2, "v", &ret_variant);
     }
+  else if (priv->parent_repo)
+    {
+      if (!ostree_repo_load_variant (priv->parent_repo, objtype, sha256, &ret_variant, error))
+        goto out;
+    }
   else
     {
       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
@@ -3562,12 +3693,22 @@ ostree_repo_list_objects (OstreeRepo                  *self,
     {
       if (!list_loose_objects (self, ret_objects, cancellable, error))
         goto out;
+      if (priv->parent_repo)
+        {
+          if (!list_loose_objects (priv->parent_repo, ret_objects, cancellable, error))
+            goto out;
+        }
     }
 
   if (flags & OSTREE_REPO_LIST_OBJECTS_PACKED)
     {
       if (!list_packed_objects (self, ret_objects, cancellable, error))
         goto out;
+      if (priv->parent_repo)
+        {
+          if (!list_packed_objects (priv->parent_repo, ret_objects, cancellable, error))
+            goto out;
+        }
     }
 
   ret = TRUE;
diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h
index 9d7e56f..2896f5f 100644
--- a/src/libostree/ostree-repo.h
+++ b/src/libostree/ostree-repo.h
@@ -92,14 +92,12 @@ gboolean      ostree_repo_abort_transaction (OstreeRepo     *self,
                                              GCancellable   *cancellable,
                                              GError        **error);
 
-gboolean      ostree_repo_find_object (OstreeRepo           *self,
-                                       OstreeObjectType      objtype,
-                                       const char           *checksum,
-                                       GFile               **out_stored_path,
-                                       char                **out_pack_checksum,
-                                       guint64              *out_pack_offset,
-                                       GCancellable         *cancellable,
-                                       GError              **error);
+gboolean      ostree_repo_has_object (OstreeRepo           *self,
+                                      OstreeObjectType      objtype,
+                                      const char           *checksum,
+                                      gboolean             *out_have_object,
+                                      GCancellable         *cancellable,
+                                      GError              **error);
 
 gboolean      ostree_repo_stage_object (OstreeRepo       *self,
                                         OstreeObjectType  objtype,
diff --git a/src/ostree/main.c b/src/ostree/main.c
index 95a81b2..aa5daa4 100644
--- a/src/ostree/main.c
+++ b/src/ostree/main.c
@@ -31,6 +31,7 @@
 
 static OstreeBuiltin builtins[] = {
   { "cat", ostree_builtin_cat, 0 },
+  { "config", ostree_builtin_config, 0 },
   { "checkout", ostree_builtin_checkout, 0 },
   { "checksum", ostree_builtin_checksum, OSTREE_BUILTIN_FLAG_NO_REPO },
   { "diff", ostree_builtin_diff, 0 },
diff --git a/src/ostree/ostree-pull.c b/src/ostree/ostree-pull.c
index 84d43ec..5fab1b7 100644
--- a/src/ostree/ostree-pull.c
+++ b/src/ostree/ostree-pull.c
@@ -514,17 +514,12 @@ find_object_ensure_indexes (OtPullData            *pull_data,
 {
   gboolean ret = FALSE;
   gboolean ret_is_stored;
-  ot_lobj GFile *stored_path = NULL;
-  ot_lfree char *local_pack_checksum = NULL;
   ot_lfree char *ret_remote_pack_checksum = NULL;
 
-  if (!ostree_repo_find_object (pull_data->repo, objtype, checksum,
-                                &stored_path, &local_pack_checksum, NULL,
-                                cancellable, error))
+  if (!ostree_repo_has_object (pull_data->repo, objtype, checksum, &ret_is_stored,
+                               cancellable, error))
     goto out;
 
-  ret_is_stored = (stored_path != NULL || local_pack_checksum != NULL);
-
   if (!ret_is_stored)
     {
       if (!pull_data->fetched_packs)
diff --git a/src/ostree/ot-builtin-config.c b/src/ostree/ot-builtin-config.c
new file mode 100644
index 0000000..8ad6a17
--- /dev/null
+++ b/src/ostree/ot-builtin-config.c
@@ -0,0 +1,144 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2011 Colin Walters <walters verbum org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters verbum org>
+ */
+
+#include "config.h"
+
+#include "ot-builtins.h"
+#include "ostree.h"
+
+#include <glib/gi18n.h>
+
+static GOptionEntry options[] = {
+  { NULL }
+};
+
+static gboolean
+split_key_string (const char   *k,
+                  char       **out_section,
+                  char       **out_value,
+                  GError     **error)
+{
+  const char *dot = strchr (k, '.');
+  
+  if (!dot)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Key must be of the form \"sectionname.keyname\"");
+      return FALSE;
+    }
+
+  *out_section = g_strndup (k, dot - k);
+  *out_value = g_strdup (dot + 1);
+
+  return TRUE;
+}
+
+gboolean
+ostree_builtin_config (int argc, char **argv, GFile *repo_path, GError **error)
+{
+  GOptionContext *context = NULL;
+  gboolean ret = FALSE;
+  const char *op;
+  const char *section_key;
+  const char *value;
+  ot_lobj OstreeRepo *repo = NULL;
+  ot_lfree char *section = NULL;
+  ot_lfree char *key = NULL;
+  GKeyFile *config = NULL;
+
+  context = g_option_context_new ("- Change configuration settings");
+  g_option_context_add_main_entries (context, options, NULL);
+
+  if (!g_option_context_parse (context, &argc, &argv, error))
+    goto out;
+
+  repo = ostree_repo_new (repo_path);
+  if (!ostree_repo_check (repo, error))
+    goto out;
+
+  if (argc < 2)
+    {
+      ot_util_usage_error (context, "OPERATION must be specified", error);
+      goto out;
+    }
+
+  op = argv[1];
+
+  if (!strcmp (op, "set"))
+    {
+      if (argc < 4)
+        {
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                       "KEY and VALUE must be specified");
+          goto out;
+        }
+
+      section_key = argv[2];
+      value = argv[3];
+
+      if (!split_key_string (section_key, &section, &key, error))
+        goto out;
+
+      config = ostree_repo_copy_config (repo);
+      g_key_file_set_string (config, section, key, value);
+
+      if (!ostree_repo_write_config (repo, config, error))
+        goto out;
+    }
+  else if (!strcmp (op, "set"))
+    {
+      ot_lfree char *value = NULL;
+      if (argc < 3)
+        {
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                       "KEY must be specified");
+          goto out;
+        }
+
+      section_key = argv[2];
+
+      if (!split_key_string (section_key, &section, &key, error))
+        goto out;
+
+      config = g_key_file_ref (ostree_repo_get_config (repo));
+
+      value = g_key_file_get_string (config, section, key, error);
+      if (value == NULL)
+        goto out;
+
+      g_print ("%s\n", value);
+    }
+  else
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Unknown operation %s", op);
+      goto out;
+    }
+  
+  ret = TRUE;
+ out:
+  if (config)
+    g_key_file_free (config);
+  if (context)
+    g_option_context_free (context);
+  return ret;
+}
diff --git a/src/ostree/ot-builtins.h b/src/ostree/ot-builtins.h
index 4cb675c..a0e5dd8 100644
--- a/src/ostree/ot-builtins.h
+++ b/src/ostree/ot-builtins.h
@@ -28,6 +28,7 @@
 G_BEGIN_DECLS
 
 gboolean ostree_builtin_cat (int argc, char **argv, GFile *repo_path, GError **error);
+gboolean ostree_builtin_config (int argc, char **argv, GFile *repo_path, GError **error);
 gboolean ostree_builtin_checkout (int argc, char **argv, GFile *repo_path, GError **error);
 gboolean ostree_builtin_checksum (int argc, char **argv, GFile *repo_path, GError **error);
 gboolean ostree_builtin_commit (int argc, char **argv, GFile *repo_path, GError **error);
diff --git a/tests/t0000-basic.sh b/tests/t0000-basic.sh
index 253421f..03a657c 100755
--- a/tests/t0000-basic.sh
+++ b/tests/t0000-basic.sh
@@ -19,7 +19,7 @@
 
 set -e
 
-echo "1..30"
+echo "1..31"
 
 . libtest.sh
 
@@ -219,3 +219,13 @@ $OSTREE checkout --link-cache=linkcache test2 test2-checkout-from-link-cache
 cd test2-checkout-from-link-cache
 assert_file_has_content ./yet/another/tree/green "leaf"
 echo "ok checkout link cache"
+
+cd ${test_tmpdir}
+rm -rf shadow-repo
+mkdir shadow-repo
+ostree --repo=shadow-repo init
+ostree --repo=shadow-repo config set core.parent $(pwd)/repo
+rm -rf test2-checkout
+parent_rev_test2=$(ostree --repo=repo rev-parse test2)
+ostree --repo=shadow-repo checkout "${parent_rev_test2}" test2-checkout
+echo "ok checkout from shadow repo"



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