[ostree/wip/pull: 3/5] work on pull
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [ostree/wip/pull: 3/5] work on pull
- Date: Sun, 30 Oct 2011 00:15:03 +0000 (UTC)
commit fa2415f94c8821c70ec6fcf51312e0596b84dc0a
Author: Colin Walters <walters verbum org>
Date: Sat Oct 29 12:01:31 2011 -0400
work on pull
Makefile-src.am | 9 +-
configure.ac | 1 +
src/libostree/ostree-core.c | 93 ++++++++++++
src/libostree/ostree-core.h | 22 ++-
src/libostree/ostree-repo.c | 246 +++++++++++++++++++------------
src/libostree/ostree-repo.h | 25 +++
src/main.c | 1 +
src/ot-builtin-pull.c | 348 +++++++++++++++++++++++++++++++++++++++++++
src/ot-builtin-remote.c | 18 +--
src/ot-builtins.h | 1 +
tests/Makefile | 5 +-
tests/libtest.sh | 27 ++++
tests/ostree-http-server.c | 5 +-
tests/t0012-pull.sh | 33 ++++
14 files changed, 714 insertions(+), 120 deletions(-)
---
diff --git a/Makefile-src.am b/Makefile-src.am
index 9990ecd..30b5af8 100644
--- a/Makefile-src.am
+++ b/Makefile-src.am
@@ -40,8 +40,8 @@ libostree_la_SOURCES = src/libostree/ostree.h \
src/libostree/ostree-checkout.c \
src/libostree/ostree-checkout.h \
$(NULL)
-libostree_la_CFLAGS = -I$(srcdir)/src/libostree -I$(srcdir)/src/libotutil -DLOCALEDIR=\"$(datadir)/locale\" $(GIO_UNIX_CFLAGS)
-libostree_la_LIBADD = libotutil.la $(GIO_UNIX_LIBS)
+libostree_la_CFLAGS = -I$(srcdir)/src/libostree -I$(srcdir)/src/libotutil -DLOCALEDIR=\"$(datadir)/locale\" $(OT_COREBIN_DEP_CFLAGS)
+libostree_la_LIBADD = libotutil.la $(OT_COREBIN_DEP_LIBS)
bin_PROGRAMS += ostree
@@ -53,10 +53,11 @@ ostree_SOURCES = src/main.c \
src/ot-builtin-init.c \
src/ot-builtin-link-file.c \
src/ot-builtin-log.c \
+ src/ot-builtin-pull.c \
src/ot-builtin-run-triggers.c \
src/ot-builtin-remote.c \
src/ot-builtin-rev-parse.c \
src/ot-builtin-show.c \
$(NULL)
-ostree_CFLAGS = -I$(srcdir)/src -I$(srcdir)/src/libostree -I$(srcdir)/src/libotutil -DLOCALEDIR=\"$(datadir)/locale\" $(GIO_UNIX_CFLAGS)
-ostree_LDADD = libotutil.la libostree.la $(GIO_UNIX_LIBS)
+ostree_CFLAGS = -I$(srcdir)/src -I$(srcdir)/src/libostree -I$(srcdir)/src/libotutil -DLOCALEDIR=\"$(datadir)/locale\" $(OT_COREBIN_DEP_CFLAGS)
+ostree_LDADD = libotutil.la libostree.la $(OT_COREBIN_DEP_LIBS)
diff --git a/configure.ac b/configure.ac
index be78b1f..92c06d5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -32,6 +32,7 @@ LT_INIT
PKG_PROG_PKG_CONFIG
PKG_CHECK_MODULES(GIO_UNIX, [gio-unix-2.0 >= 2.28])
+PKG_CHECK_MODULES(OT_COREBIN_DEP, [libsoup-gnome-2.4 >= 2.34.0 gio-unix-2.0 >= 2.28])
AM_PATH_PYTHON
diff --git a/src/libostree/ostree-core.c b/src/libostree/ostree-core.c
index d92681b..c0b8e74 100644
--- a/src/libostree/ostree-core.c
+++ b/src/libostree/ostree-core.c
@@ -27,6 +27,20 @@
#include <sys/types.h>
#include <attr/xattr.h>
+gboolean
+ostree_validate_checksum_string (const char *sha256,
+ GError **error)
+{
+ if (strlen (sha256) != 64)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Invalid rev '%s'", sha256);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
static char *
stat_to_string (struct stat *stbuf)
{
@@ -270,3 +284,82 @@ ostree_stat_and_checksum_file (int dir_fd, const char *path,
return ret;
}
+
+gboolean
+ostree_parse_metadata_file (const char *path,
+ OstreeSerializedVariantType *out_type,
+ GVariant **out_variant,
+ GError **error)
+{
+ GMappedFile *mfile = NULL;
+ gboolean ret = FALSE;
+ GVariant *ret_variant = NULL;
+ GVariant *container = NULL;
+ guint32 ret_type;
+
+ mfile = g_mapped_file_new (path, FALSE, error);
+ if (mfile == NULL)
+ {
+ goto out;
+ }
+ else
+ {
+ container = g_variant_new_from_data (G_VARIANT_TYPE (OSTREE_SERIALIZED_VARIANT_FORMAT),
+ g_mapped_file_get_contents (mfile),
+ g_mapped_file_get_length (mfile),
+ FALSE,
+ (GDestroyNotify) g_mapped_file_unref,
+ mfile);
+ g_variant_get (container, "(uv)",
+ &ret_type, &ret_variant);
+ if (ret_type <= 0 || ret_type > OSTREE_SERIALIZED_VARIANT_LAST)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Corrupted metadata object '%s'; invalid type %d", path, ret_type);
+ goto out;
+ }
+ mfile = NULL;
+ }
+
+ ret = TRUE;
+ *out_type = ret_type;
+ *out_variant = ret_variant;
+ ret_variant = NULL;
+ out:
+ if (ret_variant)
+ g_variant_unref (ret_variant);
+ if (container != NULL)
+ g_variant_unref (container);
+ if (mfile != NULL)
+ g_mapped_file_unref (mfile);
+ return ret;
+}
+
+char *
+ostree_get_relative_object_path (const char *checksum,
+ OstreeObjectType type)
+{
+ GString *path;
+ const char *type_string;
+
+ g_assert (strlen (checksum) == 64);
+
+ path = g_string_new ("objects/");
+
+ g_string_append_len (path, checksum, 2);
+ g_string_append_c (path, '/');
+ g_string_append (path, checksum + 2);
+ switch (type)
+ {
+ case OSTREE_OBJECT_TYPE_FILE:
+ type_string = ".file";
+ break;
+ case OSTREE_OBJECT_TYPE_META:
+ type_string = ".meta";
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ g_string_append (path, type_string);
+ return g_string_free (path, FALSE);
+}
diff --git a/src/libostree/ostree-core.h b/src/libostree/ostree-core.h
index 6d80941..03d8375 100644
--- a/src/libostree/ostree-core.h
+++ b/src/libostree/ostree-core.h
@@ -39,6 +39,7 @@ typedef enum {
OSTREE_SERIALIZED_DIRMETA_VARIANT = 3,
OSTREE_SERIALIZED_XATTR_VARIANT = 4
} OstreeSerializedVariantType;
+#define OSTREE_SERIALIZED_VARIANT_LAST 4
#define OSTREE_SERIALIZED_VARIANT_FORMAT "(uv)"
@@ -83,13 +84,24 @@ typedef enum {
*/
#define OSTREE_COMMIT_GVARIANT_FORMAT "(ua{sv}ssstss)"
-GVariant *ostree_get_xattrs_for_path (const char *path,
- GError **error);
+gboolean ostree_validate_checksum_string (const char *sha256,
+ GError **error);
+
+char *ostree_get_relative_object_path (const char *checksum,
+ OstreeObjectType type);
+
+GVariant *ostree_get_xattrs_for_path (const char *path,
+ GError **error);
+
+gboolean ostree_parse_metadata_file (const char *path,
+ OstreeSerializedVariantType *out_type,
+ GVariant **out_variant,
+ GError **error);
gboolean ostree_stat_and_checksum_file (int dirfd, const char *path,
- GChecksum **out_checksum,
- struct stat *out_stbuf,
- GError **error);
+ GChecksum **out_checksum,
+ struct stat *out_stbuf,
+ GError **error);
#endif /* _OSTREE_REPO */
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index 964ce69..f22e60c 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -57,6 +57,7 @@ struct _OstreeRepoPrivate {
char *path;
GFile *repo_file;
GFile *local_heads_dir;
+ GFile *remote_heads_dir;
char *objects_path;
char *config_path;
@@ -74,6 +75,7 @@ ostree_repo_finalize (GObject *object)
g_free (priv->path);
g_clear_object (&priv->repo_file);
g_clear_object (&priv->local_heads_dir);
+ g_clear_object (&priv->remote_heads_dir);
g_free (priv->objects_path);
g_free (priv->config_path);
if (priv->config)
@@ -140,6 +142,7 @@ ostree_repo_constructor (GType gtype,
priv->repo_file = ot_util_new_file_for_path (priv->path);
priv->local_heads_dir = g_file_resolve_relative_path (priv->repo_file, "refs/heads");
+ priv->remote_heads_dir = g_file_resolve_relative_path (priv->repo_file, "refs/remotes");
priv->objects_path = g_build_filename (priv->path, "objects", NULL);
priv->config_path = g_build_filename (priv->path, "config", NULL);
@@ -180,19 +183,6 @@ ostree_repo_new (const char *path)
}
static gboolean
-validate_checksum_string (const char *sha256,
- GError **error)
-{
- if (strlen (sha256) != 64)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Invalid rev '%s'", sha256);
- return FALSE;
- }
- return TRUE;
-}
-
-static gboolean
parse_rev_file (OstreeRepo *self,
const char *path,
char **sha256,
@@ -252,7 +242,7 @@ parse_rev_file (OstreeRepo *self,
}
else
{
- if (!validate_checksum_string (rev, error))
+ if (!ostree_validate_checksum_string (rev, error))
goto out;
}
@@ -304,7 +294,7 @@ resolve_rev (OstreeRepo *self,
{
g_strchomp (ret_rev);
- if (!validate_checksum_string (ret_rev, error))
+ if (!ostree_validate_checksum_string (ret_rev, error))
goto out;
}
}
@@ -357,6 +347,81 @@ write_checksum_file (GFile *parentdir,
return ret;
}
+/**
+ * ostree_repo_get_config:
+ * @self:
+ *
+ * Returns: (transfer none): The repository configuration; do not modify
+ */
+GKeyFile *
+ostree_repo_get_config (OstreeRepo *self)
+{
+ OstreeRepoPrivate *priv = GET_PRIVATE (self);
+
+ g_return_val_if_fail (priv->inited, NULL);
+
+ return priv->config;
+}
+
+/**
+ * ostree_repo_copy_config:
+ * @self:
+ *
+ * Returns: (transfer full): A newly-allocated copy of the repository config
+ */
+GKeyFile *
+ostree_repo_copy_config (OstreeRepo *self)
+{
+ OstreeRepoPrivate *priv = GET_PRIVATE (self);
+ GKeyFile *copy;
+ char *data;
+ gsize len;
+
+ g_return_val_if_fail (priv->inited, NULL);
+
+ copy = g_key_file_new ();
+ data = g_key_file_to_data (priv->config, &len, NULL);
+ if (!g_key_file_load_from_data (copy, data, len, 0, NULL))
+ g_assert_not_reached ();
+ g_free (data);
+ return copy;
+}
+
+/**
+ * ostree_repo_write_config:
+ * @self:
+ * @new_config: Overwrite the config file with this data. Do not change later!
+ * @error: a #GError
+ *
+ * Save @new_config in place of this repository's config file. Note
+ * that @new_config should not be modified after - this function
+ * simply adds a reference.
+ */
+gboolean
+ostree_repo_write_config (OstreeRepo *self,
+ GKeyFile *new_config,
+ GError **error)
+{
+ OstreeRepoPrivate *priv = GET_PRIVATE (self);
+ char *data = NULL;
+ gsize len;
+ gboolean ret = FALSE;
+
+ g_return_val_if_fail (priv->inited, FALSE);
+
+ data = g_key_file_to_data (new_config, &len, error);
+ if (!g_file_set_contents (priv->config_path, data, len, error))
+ goto out;
+
+ g_key_file_unref (priv->config);
+ priv->config = g_key_file_ref (new_config);
+
+ ret = TRUE;
+ out:
+ g_free (data);
+ return ret;
+}
+
gboolean
ostree_repo_check (OstreeRepo *self, GError **error)
{
@@ -402,6 +467,13 @@ ostree_repo_check (OstreeRepo *self, GError **error)
return ret;
}
+const char *
+ostree_repo_get_path (OstreeRepo *self)
+{
+ OstreeRepoPrivate *priv = GET_PRIVATE (self);
+ return priv->path;
+}
+
static gboolean
import_gvariant_object (OstreeRepo *self,
OstreeSerializedVariantType type,
@@ -463,54 +535,13 @@ load_gvariant_object_unknown (OstreeRepo *self,
GVariant **out_variant,
GError **error)
{
- GMappedFile *mfile = NULL;
gboolean ret = FALSE;
- GVariant *ret_variant = NULL;
- GVariant *container = NULL;
char *path = NULL;
- guint32 ret_type;
path = get_object_path (self, sha256, OSTREE_OBJECT_TYPE_META);
-
- mfile = g_mapped_file_new (path, FALSE, error);
- if (mfile == NULL)
- goto out;
- else
- {
- container = g_variant_new_from_data (G_VARIANT_TYPE (OSTREE_SERIALIZED_VARIANT_FORMAT),
- g_mapped_file_get_contents (mfile),
- g_mapped_file_get_length (mfile),
- FALSE,
- (GDestroyNotify) g_mapped_file_unref,
- mfile);
- if (!g_variant_is_of_type (container, G_VARIANT_TYPE (OSTREE_SERIALIZED_VARIANT_FORMAT)))
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Corrupted metadata object '%s'", sha256);
- goto out;
- }
- g_variant_get (container, "(uv)",
- &ret_type, &ret_variant);
- mfile = NULL;
- }
-
- ret = TRUE;
- out:
- if (!ret)
- {
- if (ret_variant)
- g_variant_unref (ret_variant);
- }
- else
- {
- *out_type = ret_type;
- *out_variant = ret_variant;
- }
- if (container != NULL)
- g_variant_unref (container);
+ ret = ostree_parse_metadata_file (path, out_type, out_variant, error);
g_free (path);
- if (mfile != NULL)
- g_mapped_file_unref (mfile);
+
return ret;
}
@@ -534,7 +565,6 @@ load_gvariant_object (OstreeRepo *self,
"Corrupted metadata object '%s'; found type %u, expected %u", sha256,
type, (guint32)expected_type);
goto out;
-
}
ret = TRUE;
@@ -616,41 +646,25 @@ get_object_path (OstreeRepo *self,
OstreeObjectType type)
{
OstreeRepoPrivate *priv = GET_PRIVATE (self);
- char *checksum_prefix;
- char *base_path;
- char *ret;
- const char *type_string;
-
- checksum_prefix = g_strndup (checksum, 2);
- base_path = g_build_filename (priv->objects_path, checksum_prefix, checksum + 2, NULL);
- switch (type)
- {
- case OSTREE_OBJECT_TYPE_FILE:
- type_string = ".file";
- break;
- case OSTREE_OBJECT_TYPE_META:
- type_string = ".meta";
- break;
- default:
- g_assert_not_reached ();
- }
- ret = g_strconcat (base_path, type_string, NULL);
- g_free (base_path);
- g_free (checksum_prefix);
+ char *relpath;
+
+ relpath = ostree_get_relative_object_path (checksum, type);
+ ret = g_build_filename (priv->path, relpath, NULL);
+ g_free (relpath);
return ret;
}
static char *
prepare_dir_for_checksum_get_object_path (OstreeRepo *self,
- GChecksum *checksum,
+ const char *checksum,
OstreeObjectType type,
GError **error)
{
char *checksum_dir = NULL;
char *object_path = NULL;
- object_path = get_object_path (self, g_checksum_get_string (checksum), type);
+ object_path = get_object_path (self, checksum, type);
checksum_dir = g_path_get_dirname (object_path);
if (!ot_util_ensure_directory (checksum_dir, FALSE, error))
@@ -661,18 +675,21 @@ prepare_dir_for_checksum_get_object_path (OstreeRepo *self,
return object_path;
}
-static gboolean
-link_one_file (OstreeRepo *self, const char *path, OstreeObjectType type,
- gboolean ignore_exists, gboolean force,
- GChecksum **out_checksum,
- GError **error)
+gboolean
+ostree_repo_store_object_trusted (OstreeRepo *self,
+ const char *path,
+ const char *checksum,
+ OstreeObjectType objtype,
+ gboolean ignore_exists,
+ gboolean force,
+ gboolean *did_exist,
+ GError **error)
{
char *src_basename = NULL;
char *src_dirname = NULL;
char *dest_basename = NULL;
char *tmp_dest_basename = NULL;
char *dest_dirname = NULL;
- GChecksum *id = NULL;
DIR *src_dir = NULL;
DIR *dest_dir = NULL;
gboolean ret = FALSE;
@@ -689,9 +706,7 @@ link_one_file (OstreeRepo *self, const char *path, OstreeObjectType type,
goto out;
}
- if (!ostree_stat_and_checksum_file (dirfd (src_dir), path, &id, &stbuf, error))
- goto out;
- dest_path = prepare_dir_for_checksum_get_object_path (self, id, type, error);
+ dest_path = prepare_dir_for_checksum_get_object_path (self, checksum, type, error);
if (!dest_path)
goto out;
@@ -719,7 +734,11 @@ link_one_file (OstreeRepo *self, const char *path, OstreeObjectType type,
ot_util_set_error_from_errno (error, errno);
goto out;
}
+ else
+ *did_exist = TRUE;
}
+ else
+ *did_exist = FALSE;
if (force)
{
@@ -732,12 +751,8 @@ link_one_file (OstreeRepo *self, const char *path, OstreeObjectType type,
(void) unlinkat (dirfd (dest_dir), tmp_dest_basename, 0);
}
- *out_checksum = id;
- id = NULL;
ret = TRUE;
out:
- if (id != NULL)
- g_checksum_free (id);
if (src_dir != NULL)
closedir (src_dir);
if (dest_dir != NULL)
@@ -750,6 +765,31 @@ link_one_file (OstreeRepo *self, const char *path, OstreeObjectType type,
return ret;
}
+static gboolean
+link_one_file (OstreeRepo *self, const char *path, OstreeObjectType type,
+ gboolean ignore_exists, gboolean force,
+ GChecksum **out_checksum,
+ GError **error)
+{
+ struct stat stbuf;
+ GChecksum *id = NULL;
+ gboolean did_exist;
+
+ if (!ostree_stat_and_checksum_file (dirfd (src_dir), path, &id, &stbuf, error))
+ goto out;
+
+ if (!ostree_repo_store_object_trusted (self, path, g_checksum_get_string (id), type,
+ ignore_exists, force, &did_exist, error))
+ goto out;
+
+ *out_checksum = id;
+ id = NULL;
+ ret = TRUE;
+ out:
+ if (id != NULL)
+ g_checksum_free (id);
+}
+
gboolean
ostree_repo_link_file (OstreeRepo *self,
const char *path,
@@ -839,6 +879,7 @@ parse_tree (OstreeRepo *self,
sha256, &tree_variant, error))
goto out;
+ /* PARSE OSTREE_SERIALIZED_TREE_VARIANT */
g_variant_get (tree_variant, "(u a{sv}@a(ss)@a(sss))",
&version, &meta_variant, &files_variant, &dirs_variant);
@@ -922,6 +963,7 @@ load_commit_and_trees (OstreeRepo *self,
commit_sha256, &ret_commit, error))
goto out;
+ /* PARSE OSTREE_SERIALIZED_COMMIT_VARIANT */
g_variant_get_child (ret_commit, 6, "&s", &tree_contents_checksum);
g_variant_get_child (ret_commit, 7, "&s", &tree_meta_checksum);
@@ -1366,6 +1408,17 @@ add_files_to_tree_and_import (OstreeRepo *self,
return ret;
}
+gboolean
+ostree_repo_write_ref (OstreeRepo *self,
+ gboolean is_local,
+ const char *name,
+ const char *rev,
+ GError **error)
+{
+ return write_checksum_file (is_local ? priv->local_heads_dir : priv->remote_heads_dir,
+ name, rev, error))
+}
+
static gboolean
commit_parsed_tree (OstreeRepo *self,
const char *branch,
@@ -1403,7 +1456,7 @@ commit_parsed_tree (OstreeRepo *self,
commit, &ret_commit, error))
goto out;
- if (!write_checksum_file (priv->local_heads_dir, branch, g_checksum_get_string (ret_commit), error))
+ if (!ostree_repo_write_ref (self, TRUE, branch, g_checksum_get_string (ret_commit), error))
goto out;
ret = TRUE;
@@ -1789,6 +1842,7 @@ checkout_one_directory (OstreeRepo *self,
dest_path = g_build_filename (destination, dirname, NULL);
+ /* PARSE OSTREE_SERIALIZED_DIRMETA_VARIANT */
g_variant_get (dir->meta_data, "(uuuu a(ayay))",
&version, &uid, &gid, &mode,
&xattr_variant);
diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h
index c0159ea..36149ef 100644
--- a/src/libostree/ostree-repo.h
+++ b/src/libostree/ostree-repo.h
@@ -53,17 +53,42 @@ OstreeRepo* ostree_repo_new (const char *path);
gboolean ostree_repo_check (OstreeRepo *self, GError **error);
+const char * ostree_repo_get_path (OstreeRepo *self);
+
+GKeyFile * ostree_repo_get_config (OstreeRepo *self);
+
+GKeyFile * ostree_repo_copy_config (OstreeRepo *self);
+
+gboolean ostree_repo_write_config (OstreeRepo *self,
+ GKeyFile *new_config,
+ GError **error);
+
gboolean ostree_repo_link_file (OstreeRepo *self,
const char *path,
gboolean ignore_exists,
gboolean force,
GError **error);
+gboolean ostree_repo_store_object_trusted (OstreeRepo *self,
+ const char *path,
+ const char *checksum,
+ OstreeObjectType objtype,
+ gboolean ignore_exists,
+ gboolean force,
+ gboolean *did_exist,
+ GError **error);
+
gboolean ostree_repo_resolve_rev (OstreeRepo *self,
const char *rev,
char **out_resolved,
GError **error);
+gboolean ostree_repo_write_ref (OstreeRepo *self,
+ gboolean is_local,
+ const char *name,
+ const char *rev,
+ GError **error);
+
gboolean ostree_repo_load_variant (OstreeRepo *self,
const char *sha256,
OstreeSerializedVariantType *out_type,
diff --git a/src/main.c b/src/main.c
index f32e741..ad5dfd8 100644
--- a/src/main.c
+++ b/src/main.c
@@ -33,6 +33,7 @@ static OstreeBuiltin builtins[] = {
{ "commit", ostree_builtin_commit, 0 },
{ "link-file", ostree_builtin_link_file, 0 },
{ "log", ostree_builtin_log, 0 },
+ { "pull", ostree_builtin_pull, 0 },
{ "fsck", ostree_builtin_fsck, 0 },
{ "remote", ostree_builtin_remote, 0 },
{ "rev-parse", ostree_builtin_rev_parse, 0 },
diff --git a/src/ot-builtin-pull.c b/src/ot-builtin-pull.c
new file mode 100644
index 0000000..db13cb9
--- /dev/null
+++ b/src/ot-builtin-pull.c
@@ -0,0 +1,348 @@
+/* -*- 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>
+
+#include <libsoup/soup-gnome.h>
+
+static char *repo_path;
+
+static GOptionEntry options[] = {
+ { "repo", 0, 0, G_OPTION_ARG_FILENAME, &repo_path, "Repository path", "repo" },
+ { NULL }
+};
+
+static void
+usage_error (GOptionContext *context, const char *message, GError **error)
+{
+ 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,
+ message);
+}
+
+static gboolean
+fetch_uri (OstreeRepo *repo,
+ SoupSession *soup,
+ SoupURI *uri,
+ char **temp_filename,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ SoupMessage *msg = NULL;
+ guint response;
+ char *template = NULL;
+ int fd;
+ SoupBuffer *buf = NULL;
+ GFile *tempf = NULL;
+
+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri);
+
+ response = soup_session_send_message (soup, msg);
+ if (response != 200)
+ {
+ char *uri_string = soup_uri_to_string (uri, FALSE);
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Failed to retrieve '%s': %d %s",
+ uri_string, response, msg->reason_phrase);
+ g_free (uri_string);
+ goto out;
+ }
+
+ template = g_strdup_printf ("%s/tmp-fetchXXXXXX", ostree_repo_get_path (repo));
+
+ fd = g_mkstemp (template);
+ if (fd < 0)
+ {
+ ot_util_set_error_from_errno (error, errno);
+ goto out;
+ }
+ close (fd);
+ tempf = g_file_new_for_path (template);
+
+ buf = soup_message_body_flatten (msg->response_body);
+
+ if (!g_file_replace_contents (tempf, buf->data, buf->length, NULL, FALSE, 0, NULL, NULL, error))
+ goto out;
+
+ *temp_filename = template;
+ template = NULL;
+
+ ret = TRUE;
+ out:
+ g_free (template);
+ g_clear_object (&msg);
+ g_clear_object (&tempf);
+ return ret;
+}
+
+static gboolean
+store_object (OstreeRepo *repo,
+ SoupSession *soup,
+ SoupURI *baseuri,
+ const char *object,
+ OstreeObjectType objtype,
+ gboolean *did_exist,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ char *filename = NULL;
+ char *objpath = NULL;
+ char *relpath = NULL;
+ SoupURI *obj_uri = NULL;
+ GChecksum *checksum = NULL;
+
+ objpath = ostree_get_relative_object_path (rev, objtype);
+ obj_uri = soup_uri_copy (baseuri);
+ relpath = g_build_filename (soup_uri_get_path (obj_uri), objpath, NULL);
+ soup_uri_set_path (obj_uri, relpath);
+
+ if (!fetch_uri (repo, soup, relpath, &filename, error))
+ goto out;
+
+ if (!ostree_stat_and_checksum_file (-1, filename, &checksum,
+ &stbuf, error))
+ goto out;
+
+ if (strcmp (g_checksum_get_string (checksum), object) != 0)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Corrupted object %s (actual checksum is %s)",
+ object, g_checksum_get_string (checksum));
+ goto out;
+ }
+
+ if (!ostree_repo_store_object_trusted (repo, filename, object, TRUE, FALSE, did_exist, error))
+ goto out;
+
+ ret = TRUE;
+ *temp_filename = ret_filename;
+ ret_filename = NULL;
+ out:
+ if (checksum)
+ g_checksum_free (checksum);
+ if (obj_uri)
+ soup_uri_free (obj_uri);
+ g_free (ret_filename);
+ g_free (objpath);
+ return ret;
+}
+
+static gboolean
+store_tree_recurse (OstreeRepo *repo,
+ SoupSession *session,
+ SoupURI *baseuri,
+ const char *rev,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ GVariant *tree = NULL;
+ OstreeSerializedVariantType metatype;
+ gboolean did_exist;
+
+ if (!store_object (repo, soup, base_uri, rev, OSTREE_OBJECT_TYPE_META, &did_exist, error))
+ goto out;
+
+ if (!did_exist)
+ {
+ if (!ostree_repo_load_variant (repo, rev, &metatype, &tree, error))
+ goto out;
+
+ if (metatype != OSTREE_SERIALIZED_TREE_VARIANT)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Tree metadata '%s' has wrong type %d, expected %d",
+ rev, metatype, OSTREE_SERIALIZED_TREE_VARIANT);
+ goto out;
+ }
+
+ /* PARSE OSTREE_SERIALIZED_TREE_VARIANT */
+ g_variant_get_child (commit, 2, "@a(ss)", &files_variant);
+ g_variant_get_child (commit, 3, "@a(sss)", &dirs_variant);
+
+ store files_variant
+ store dirs_variant
+ }
+
+ ret = TRUE;
+ out:
+ if (commit)
+ g_variant_unref (commit);
+ return ret;
+}
+
+static gboolean
+store_commit_recurse (OstreeRepo *repo,
+ SoupSession *session,
+ SoupURI *baseuri,
+ const char *rev,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ GVariant *commit = NULL;
+ OstreeSerializedVariantType metatype;
+ const char *tree_contents_checksum;
+ const char *tree_meta_checksum;
+ gboolean did_exist;
+
+ if (!store_object (repo, soup, base_uri, rev, OSTREE_OBJECT_TYPE_META, &did_exist, error))
+ goto out;
+
+ if (!did_exist)
+ {
+ if (!ostree_repo_load_variant (repo, rev, &metatype, &commit, error))
+ goto out;
+
+ if (metatype != OSTREE_SERIALIZED_COMMIT_VARIANT)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Commit '%s' has wrong type %d, expected %d",
+ branch, metatype, OSTREE_SERIALIZED_COMMIT_VARIANT);
+ goto out;
+ }
+
+ /* PARSE OSTREE_SERIALIZED_COMMIT_VARIANT */
+ g_variant_get_child (commit, 6, "&s", &tree_contents_checksum);
+ g_variant_get_child (commit, 7, "&s", &tree_meta_checksum);
+
+ if (!store_object (repo, session, baseuri, tree_meta_checksum, error))
+ goto out;
+
+ if (!store_tree_recurse (repo, session, baseuri, tree_contents_checksum, error))
+ goto out;
+ }
+
+ ret = TRUE;
+ out:
+ if (commit)
+ g_variant_unref (commit);
+ return ret;
+}
+
+gboolean
+ostree_builtin_pull (int argc, char **argv, const char *prefix, GError **error)
+{
+ GOptionContext *context;
+ gboolean ret = FALSE;
+ OstreeRepo *repo = NULL;
+ OstreeCheckout *checkout = NULL;
+ const char *remote;
+ const char *branch;
+ char *remote_branch_ref_path = NULL;
+ char *key = NULL;
+ char *baseurl = NULL;
+ char *refpath = NULL;
+ char *temppath = NULL;
+ GKeyFile *config = NULL;
+ SoupURI *base_uri = NULL;
+ SoupURI *target_uri = NULL;
+ SoupSession *soup = NULL;
+ char *rev = NULL;
+ gsize len;
+
+ context = g_option_context_new ("REMOTE BRANCH - Download data from remote repository");
+ 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;
+
+ if (argc < 3)
+ {
+ usage_error (context, "REMOTE and BRANCH must be specified", error);
+ goto out;
+ }
+
+ remote = argv[1];
+ branch = argv[2];
+
+ config = ostree_repo_get_config (repo);
+
+ key = g_strdup_printf ("remote \"%s\"", remote);
+ baseurl = g_key_file_get_string (config, key, "url", error);
+ if (!baseurl)
+ goto out;
+ base_uri = soup_uri_new (baseurl);
+ if (!base_uri)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Failed to parse url '%s'", baseurl);
+ goto out;
+ }
+ target_uri = soup_uri_copy (base_uri);
+ g_free (refpath);
+ refpath = g_build_filename (soup_uri_get_path (target_uri), "refs", "heads", branch, NULL);
+ soup_uri_set_path (target_uri, refpath);
+
+ soup = soup_session_sync_new_with_options (SOUP_SESSION_USER_AGENT, "ostree ",
+ SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_GNOME_FEATURES_2_26,
+ SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_CONTENT_DECODER,
+ SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_COOKIE_JAR,
+ NULL);
+ if (!fetch_uri (repo, soup, target_uri, &temppath, error))
+ goto out;
+
+ if (!ot_util_get_file_contents_utf8 (temppath, &rev, error))
+ goto out;
+
+ if (!ostree_validate_checksum_string (rev, error))
+ goto out;
+
+ if (!store_commit_recurse (repo, soup, base_uri, rev, error))
+ goto out;
+
+ if (!g_file_
+
+ ret = TRUE;
+ out:
+ if (context)
+ g_option_context_free (context);
+ if (temppath)
+ (void) unlink (temppath);
+ g_free (temppath);
+ g_free (key);
+ g_free (rev);
+ g_free (baseurl);
+ g_free (refpath);
+ g_free (remote_branch_ref_path);
+ g_clear_object (&soup);
+ if (base_uri)
+ soup_uri_free (base_uri);
+ if (target_uri)
+ soup_uri_free (target_uri);
+ if (commit)
+ g_variant_unref (commit);
+ g_clear_object (&repo);
+ g_clear_object (&checkout);
+ return ret;
+}
diff --git a/src/ot-builtin-remote.c b/src/ot-builtin-remote.c
index f26d683..40f7c29 100644
--- a/src/ot-builtin-remote.c
+++ b/src/ot-builtin-remote.c
@@ -51,9 +51,6 @@ ostree_builtin_remote (int argc, char **argv, const char *prefix, GError **error
OstreeRepo *repo = NULL;
OstreeCheckout *checkout = NULL;
const char *op;
- gsize len;
- char *config_path = NULL;
- char *data = NULL;
GKeyFile *config = NULL;
context = g_option_context_new ("OPERATION [args] - Control remote repository configuration");
@@ -77,10 +74,7 @@ ostree_builtin_remote (int argc, char **argv, const char *prefix, GError **error
op = argv[1];
- config = g_key_file_new ();
- config_path = g_build_filename (repo_path, "config", NULL);
- if (!g_key_file_load_from_file (config, config_path, 0, error))
- goto out;
+ config = ostree_repo_copy_config (repo);
if (!strcmp (op, "add"))
{
@@ -92,25 +86,23 @@ ostree_builtin_remote (int argc, char **argv, const char *prefix, GError **error
}
key = g_strdup_printf ("remote \"%s\"", argv[2]);
g_key_file_set_string (config, key, "url", argv[3]);
+ g_free (key);
}
else
{
usage_error (context, "Unknown operation", error);
goto out;
}
-
- data = g_key_file_to_data (config, &len, error);
- if (!g_file_set_contents (config_path, data, len, error))
- goto out;
+ if (!ostree_repo_write_config (repo, config, error))
+ goto out;
+
ret = TRUE;
out:
if (context)
g_option_context_free (context);
if (config)
g_key_file_unref (config);
- g_free (data);
- g_free (config_path);
g_clear_object (&repo);
g_clear_object (&checkout);
return ret;
diff --git a/src/ot-builtins.h b/src/ot-builtins.h
index 1da3db9..1373f60 100644
--- a/src/ot-builtins.h
+++ b/src/ot-builtins.h
@@ -41,6 +41,7 @@ gboolean ostree_builtin_commit (int argc, char **argv, const char *prefix, GErro
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);
+gboolean ostree_builtin_pull (int argc, char **argv, const char *prefix, GError **error);
gboolean ostree_builtin_run_triggers (int argc, char **argv, const char *prefix, GError **error);
gboolean ostree_builtin_fsck (int argc, char **argv, const char *prefix, GError **error);
gboolean ostree_builtin_show (int argc, char **argv, const char *prefix, GError **error);
diff --git a/tests/Makefile b/tests/Makefile
index c24db2c..e35744b 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -20,7 +20,10 @@
TESTS = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)
-all:
+all: ostree-http-server
+
+ostree-http-server: ostree-http-server.c Makefile
+ gcc $(CFLAGS) `pkg-config --cflags --libs libsoup-gnome-2.4` -o ostree-http-server $<
check:
@for test in $(TESTS); do \
diff --git a/tests/libtest.sh b/tests/libtest.sh
index cedf537..9e50e4d 100644
--- a/tests/libtest.sh
+++ b/tests/libtest.sh
@@ -18,6 +18,9 @@
#
# Author: Colin Walters <walters verbum org>
+cd `dirname $0`
+SRCDIR=`pwd`
+cd -
TMPDIR=${TMPDIR:-/tmp}
export TMPDIR
test_tmpdir=`mktemp -d "$TMPDIR/ostree-tests.XXXXXXXXXX"`
@@ -91,4 +94,28 @@ setup_test_repository2 () {
ostree fsck -q $ot_repo
}
+setup_fake_remote_repo1() {
+ oldpwd=`pwd`
+ mkdir remote
+ ostree init --repo=remote
+ mkdir remote-files
+ cd remote-files
+ echo first > firstfile
+ mkdir baz
+ echo moo > baz/cow
+ echo alien > baz/saucer
+ find | grep -v '^\.$' | ostree commit --repo=${test_tmpdir}/remote -b main -s "A remote commit" -m "Some Commit body" --from-stdin
+ mkdir baz/deeper
+ ostree commit --repo=${test_tmpdir}/remote -b main -s "Add deeper" --add=baz/deeper
+ echo hi > baz/deeper/ohyeah
+ mkdir baz/another/
+ echo x > baz/another/y
+ find | grep -v '^\.$' | ostree commit --repo=${test_tmpdir}/remote -b main -s "The rest" --from-stdin
+ cd ..
+ rm -rf remote-files
+
+ ${SRCDIR}/ostree-http-server > ${test_tmpdir}/remote-address &
+ cd ${oldpwd}
+}
+
trap 'die' EXIT
diff --git a/tests/ostree-http-server.c b/tests/ostree-http-server.c
index 63edda5..a6c0279 100644
--- a/tests/ostree-http-server.c
+++ b/tests/ostree-http-server.c
@@ -39,7 +39,10 @@ request_callback (SoupServer *server, SoupMessage *msg,
file = g_file_new_for_path (path + 1);
if (g_file_load_contents (file, NULL, &content, &len, NULL, NULL))
- soup_message_set_response (msg, "application/octet-stream", SOUP_MEMORY_TAKE, content, len);
+ {
+ soup_message_set_response (msg, "application/octet-stream", SOUP_MEMORY_TAKE, content, len);
+ soup_message_set_status (msg, SOUP_STATUS_OK);
+ }
else
soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND);
}
diff --git a/tests/t0012-pull.sh b/tests/t0012-pull.sh
new file mode 100755
index 0000000..a98466e
--- /dev/null
+++ b/tests/t0012-pull.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+#
+# 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>
+
+set -e
+
+. libtest.sh
+
+echo '1..1'
+
+setup_fake_remote_repo1
+cd ${test_tmpdir}
+mkdir repo
+ostree init --repo=repo
+ostree remote --repo=repo add origin $(cat remote-address)/remote
+ostree pull --repo=repo origin main
+echo "ok pull"
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]