build: Move sources into src/ again
This is necessary if we want to build when srcdir == builddir, otherwise we blow up because "ostree" is a source directory and a binary.
This commit is contained in:
1 parent
9dc6ddce08
commit
18f0b537a4
47 files changed
+5284
-42
No files matched your search
@@ -0,0 +1,362 @@
|
||||
/* -*- 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 "ostree.h"
|
||||
#include "otutil.h"
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
|
||||
PROP_REPO,
|
||||
PROP_PATH
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (OstreeCheckout, ostree_checkout, G_TYPE_OBJECT)
|
||||
|
||||
#define GET_PRIVATE(o) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((o), OSTREE_TYPE_CHECKOUT, OstreeCheckoutPrivate))
|
||||
|
||||
typedef struct _OstreeCheckoutPrivate OstreeCheckoutPrivate;
|
||||
|
||||
struct _OstreeCheckoutPrivate {
|
||||
OstreeRepo *repo;
|
||||
char *path;
|
||||
};
|
||||
|
||||
static void
|
||||
ostree_checkout_finalize (GObject *object)
|
||||
{
|
||||
OstreeCheckout *self = OSTREE_CHECKOUT (object);
|
||||
OstreeCheckoutPrivate *priv = GET_PRIVATE (self);
|
||||
|
||||
g_free (priv->path);
|
||||
g_clear_object (&priv->repo);
|
||||
|
||||
G_OBJECT_CLASS (ostree_checkout_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
ostree_checkout_set_property(GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
OstreeCheckout *self = OSTREE_CHECKOUT (object);
|
||||
OstreeCheckoutPrivate *priv = GET_PRIVATE (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PATH:
|
||||
priv->path = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_REPO:
|
||||
priv->repo = g_value_dup_object (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ostree_checkout_get_property(GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
OstreeCheckout *self = OSTREE_CHECKOUT (object);
|
||||
OstreeCheckoutPrivate *priv = GET_PRIVATE (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PATH:
|
||||
g_value_set_string (value, priv->path);
|
||||
break;
|
||||
case PROP_REPO:
|
||||
g_value_set_object (value, priv->repo);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static GObject *
|
||||
ostree_checkout_constructor (GType gtype,
|
||||
guint n_properties,
|
||||
GObjectConstructParam *properties)
|
||||
{
|
||||
GObject *object;
|
||||
GObjectClass *parent_class;
|
||||
OstreeCheckoutPrivate *priv;
|
||||
|
||||
parent_class = G_OBJECT_CLASS (ostree_checkout_parent_class);
|
||||
object = parent_class->constructor (gtype, n_properties, properties);
|
||||
|
||||
priv = GET_PRIVATE (object);
|
||||
|
||||
g_assert (priv->path != NULL);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
static void
|
||||
ostree_checkout_class_init (OstreeCheckoutClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (OstreeCheckoutPrivate));
|
||||
|
||||
object_class->constructor = ostree_checkout_constructor;
|
||||
object_class->get_property = ostree_checkout_get_property;
|
||||
object_class->set_property = ostree_checkout_set_property;
|
||||
object_class->finalize = ostree_checkout_finalize;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_PATH,
|
||||
g_param_spec_string ("path", "", "",
|
||||
NULL,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_REPO,
|
||||
g_param_spec_object ("repo", "", "",
|
||||
OSTREE_TYPE_REPO,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||||
}
|
||||
|
||||
static void
|
||||
ostree_checkout_init (OstreeCheckout *self)
|
||||
{
|
||||
}
|
||||
|
||||
OstreeCheckout*
|
||||
ostree_checkout_new (OstreeRepo *repo,
|
||||
const char *path)
|
||||
{
|
||||
return g_object_new (OSTREE_TYPE_CHECKOUT, "repo", repo, "path", path, NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
executable_exists_in_checkout (const char *path,
|
||||
const char *executable)
|
||||
{
|
||||
int i;
|
||||
const char *subdirs[] = {"bin", "sbin", "usr/bin", "usr/sbin"};
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (subdirs); i++)
|
||||
{
|
||||
char *possible_path = g_build_filename (path, subdirs[i], executable, NULL);
|
||||
gboolean exists;
|
||||
|
||||
exists = g_file_test (possible_path, G_FILE_TEST_EXISTS);
|
||||
g_free (possible_path);
|
||||
|
||||
if (exists)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
run_trigger (OstreeCheckout *self,
|
||||
GFile *trigger,
|
||||
gboolean requires_chroot,
|
||||
GError **error)
|
||||
{
|
||||
OstreeCheckoutPrivate *priv = GET_PRIVATE (self);
|
||||
gboolean ret = FALSE;
|
||||
char *path = NULL;
|
||||
char *temp_path = NULL;
|
||||
char *rel_temp_path = NULL;
|
||||
GFile *temp_copy = NULL;
|
||||
char *basename = NULL;
|
||||
GPtrArray *args = NULL;
|
||||
int estatus;
|
||||
|
||||
path = g_file_get_path (trigger);
|
||||
basename = g_path_get_basename (path);
|
||||
|
||||
args = g_ptr_array_new ();
|
||||
|
||||
if (requires_chroot)
|
||||
{
|
||||
temp_path = g_build_filename (priv->path, basename, NULL);
|
||||
rel_temp_path = g_strconcat ("./", basename, NULL);
|
||||
temp_copy = ot_util_new_file_for_path (temp_path);
|
||||
|
||||
if (!g_file_copy (trigger, temp_copy, 0, NULL, NULL, NULL, error))
|
||||
goto out;
|
||||
|
||||
g_ptr_array_add (args, "chroot");
|
||||
g_ptr_array_add (args, ".");
|
||||
g_ptr_array_add (args, rel_temp_path);
|
||||
g_ptr_array_add (args, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_ptr_array_add (args, path);
|
||||
g_ptr_array_add (args, NULL);
|
||||
}
|
||||
|
||||
g_print ("Running trigger: %s\n", path);
|
||||
if (!g_spawn_sync (priv->path,
|
||||
(char**)args->pdata,
|
||||
NULL,
|
||||
G_SPAWN_SEARCH_PATH,
|
||||
NULL, NULL, NULL, NULL,
|
||||
&estatus,
|
||||
error))
|
||||
{
|
||||
g_prefix_error (error, "Failed to run trigger %s: ", basename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (requires_chroot && temp_path)
|
||||
(void)unlink (temp_path);
|
||||
|
||||
g_free (path);
|
||||
g_free (basename);
|
||||
g_free (temp_path);
|
||||
g_free (rel_temp_path);
|
||||
g_clear_object (&temp_copy);
|
||||
if (args)
|
||||
g_ptr_array_free (args, TRUE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
check_trigger (OstreeCheckout *self,
|
||||
GFile *trigger,
|
||||
GError **error)
|
||||
{
|
||||
OstreeCheckoutPrivate *priv = GET_PRIVATE (self);
|
||||
gboolean ret = FALSE;
|
||||
GInputStream *instream = NULL;
|
||||
GDataInputStream *datain = NULL;
|
||||
GError *temp_error = NULL;
|
||||
char *line;
|
||||
gsize len;
|
||||
gboolean requires_chroot = TRUE;
|
||||
gboolean matches = FALSE;
|
||||
|
||||
instream = (GInputStream*)g_file_read (trigger, NULL, error);
|
||||
if (!instream)
|
||||
goto out;
|
||||
datain = g_data_input_stream_new (instream);
|
||||
|
||||
while ((line = g_data_input_stream_read_line (datain, &len, NULL, &temp_error)) != NULL)
|
||||
{
|
||||
if (g_str_has_prefix (line, "# IfExecutable: "))
|
||||
{
|
||||
char *executable = g_strdup (line + strlen ("# IfExecutable: "));
|
||||
g_strchomp (executable);
|
||||
matches = executable_exists_in_checkout (priv->path, executable);
|
||||
g_free (executable);
|
||||
}
|
||||
|
||||
g_free (line);
|
||||
}
|
||||
if (line == NULL && temp_error != NULL)
|
||||
{
|
||||
g_propagate_error (error, temp_error);
|
||||
goto out;
|
||||
}
|
||||
if (matches)
|
||||
{
|
||||
if (!run_trigger (self, trigger, requires_chroot, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
g_clear_object (&instream);
|
||||
g_clear_object (&datain);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
ostree_checkout_run_triggers (OstreeCheckout *self,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GError *temp_error = NULL;
|
||||
char *triggerdir_path = NULL;
|
||||
GFile *triggerdir = NULL;
|
||||
GFileInfo *file_info = NULL;
|
||||
GFileEnumerator *enumerator = NULL;
|
||||
|
||||
triggerdir_path = g_build_filename (LIBEXECDIR, "ostree", "triggers.d", NULL);
|
||||
triggerdir = ot_util_new_file_for_path (triggerdir_path);
|
||||
|
||||
enumerator = g_file_enumerate_children (triggerdir, OSTREE_GIO_FAST_QUERYINFO,
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
NULL,
|
||||
error);
|
||||
if (!enumerator)
|
||||
goto out;
|
||||
|
||||
while ((file_info = g_file_enumerator_next_file (enumerator, NULL, &temp_error)) != NULL)
|
||||
{
|
||||
const char *name;
|
||||
guint32 type;
|
||||
char *child_path = NULL;
|
||||
GFile *child = NULL;
|
||||
gboolean success;
|
||||
|
||||
name = g_file_info_get_attribute_byte_string (file_info, "standard::name");
|
||||
type = g_file_info_get_attribute_uint32 (file_info, "standard::type");
|
||||
|
||||
if (type == G_FILE_TYPE_REGULAR && g_str_has_suffix (name, ".trigger"))
|
||||
{
|
||||
child_path = g_build_filename (triggerdir_path, name, NULL);
|
||||
child = ot_util_new_file_for_path (child_path);
|
||||
|
||||
success = check_trigger (self, child, error);
|
||||
}
|
||||
else
|
||||
success = TRUE;
|
||||
|
||||
g_object_unref (file_info);
|
||||
g_free (child_path);
|
||||
g_clear_object (&child);
|
||||
if (!success)
|
||||
goto out;
|
||||
}
|
||||
if (file_info == NULL && temp_error != NULL)
|
||||
{
|
||||
g_propagate_error (error, temp_error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
g_free (triggerdir_path);
|
||||
g_clear_object (&triggerdir);
|
||||
g_clear_object (&enumerator);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/* -*- 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>
|
||||
*/
|
||||
|
||||
#ifndef _OSTREE_CHECKOUT
|
||||
#define _OSTREE_CHECKOUT
|
||||
|
||||
#include <ostree-repo.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define OSTREE_TYPE_CHECKOUT ostree_checkout_get_type()
|
||||
#define OSTREE_CHECKOUT(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST ((obj), OSTREE_TYPE_CHECKOUT, OstreeCheckout))
|
||||
#define OSTREE_CHECKOUT_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST ((klass), OSTREE_TYPE_CHECKOUT, OstreeCheckoutClass))
|
||||
#define OSTREE_IS_CHECKOUT(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), OSTREE_TYPE_CHECKOUT))
|
||||
#define OSTREE_IS_CHECKOUT_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE ((klass), OSTREE_TYPE_CHECKOUT))
|
||||
#define OSTREE_CHECKOUT_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS ((obj), OSTREE_TYPE_CHECKOUT, OstreeCheckoutClass))
|
||||
|
||||
typedef struct {
|
||||
GObject parent;
|
||||
} OstreeCheckout;
|
||||
|
||||
typedef struct {
|
||||
GObjectClass parent_class;
|
||||
} OstreeCheckoutClass;
|
||||
|
||||
GType ostree_checkout_get_type (void);
|
||||
|
||||
OstreeCheckout* ostree_checkout_new (OstreeRepo *repo,
|
||||
const char *path);
|
||||
|
||||
gboolean ostree_checkout_run_triggers (OstreeCheckout *checkout,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* _OSTREE_CHECKOUT */
|
||||
@@ -0,0 +1,856 @@
|
||||
/* -*- 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 "ostree.h"
|
||||
#include "otutil.h"
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ostree_checksum_update_stat (GChecksum *checksum, guint32 uid, guint32 gid, guint32 mode)
|
||||
{
|
||||
guint32 perms = (mode & ~S_IFMT);
|
||||
g_checksum_update (checksum, (guint8*) &uid, 4);
|
||||
g_checksum_update (checksum, (guint8*) &gid, 4);
|
||||
g_checksum_update (checksum, (guint8*) &perms, 4);
|
||||
}
|
||||
|
||||
static char *
|
||||
canonicalize_xattrs (char *xattr_string, size_t len)
|
||||
{
|
||||
char *p;
|
||||
GSList *xattrs = NULL;
|
||||
GSList *iter;
|
||||
GString *result;
|
||||
|
||||
result = g_string_new (0);
|
||||
|
||||
p = xattr_string;
|
||||
while (p < xattr_string+len)
|
||||
{
|
||||
xattrs = g_slist_prepend (xattrs, p);
|
||||
p += strlen (p) + 1;
|
||||
}
|
||||
|
||||
xattrs = g_slist_sort (xattrs, (GCompareFunc) strcmp);
|
||||
for (iter = xattrs; iter; iter = iter->next)
|
||||
g_string_append (result, iter->data);
|
||||
|
||||
g_slist_free (xattrs);
|
||||
return g_string_free (result, FALSE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
read_xattr_name_array (const char *path,
|
||||
const char *xattrs,
|
||||
size_t len,
|
||||
GVariantBuilder *builder,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
const char *p;
|
||||
|
||||
p = xattrs;
|
||||
while (p < xattrs+len)
|
||||
{
|
||||
ssize_t bytes_read;
|
||||
char *buf;
|
||||
|
||||
bytes_read = lgetxattr (path, p, NULL, 0);
|
||||
if (bytes_read < 0)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
goto out;
|
||||
}
|
||||
if (bytes_read == 0)
|
||||
continue;
|
||||
|
||||
buf = g_malloc (bytes_read);
|
||||
if (lgetxattr (path, p, buf, bytes_read) < 0)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
g_free (buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
g_variant_builder_add (builder, "(@ay@ay)",
|
||||
g_variant_new_bytestring (p),
|
||||
g_variant_new_from_data (G_VARIANT_TYPE ("ay"),
|
||||
buf, bytes_read, FALSE, g_free, buf));
|
||||
|
||||
p = p + strlen (p) + 1;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
GVariant *
|
||||
ostree_get_xattrs_for_path (const char *path,
|
||||
GError **error)
|
||||
{
|
||||
GVariant *ret = NULL;
|
||||
GVariantBuilder builder;
|
||||
char *xattr_names = NULL;
|
||||
char *xattr_names_canonical = NULL;
|
||||
ssize_t bytes_read;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayay)"));
|
||||
|
||||
bytes_read = llistxattr (path, NULL, 0);
|
||||
|
||||
if (bytes_read < 0)
|
||||
{
|
||||
if (errno != ENOTSUP)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else if (bytes_read > 0)
|
||||
{
|
||||
xattr_names = g_malloc (bytes_read);
|
||||
if (llistxattr (path, xattr_names, bytes_read) < 0)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
goto out;
|
||||
}
|
||||
xattr_names_canonical = canonicalize_xattrs (xattr_names, bytes_read);
|
||||
|
||||
if (!read_xattr_name_array (path, xattr_names_canonical, bytes_read, &builder, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = g_variant_builder_end (&builder);
|
||||
g_variant_ref_sink (ret);
|
||||
out:
|
||||
if (!ret)
|
||||
g_variant_builder_clear (&builder);
|
||||
g_free (xattr_names);
|
||||
g_free (xattr_names_canonical);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
ostree_stat_and_checksum_file (int dir_fd, const char *path,
|
||||
OstreeObjectType objtype,
|
||||
GChecksum **out_checksum,
|
||||
struct stat *out_stbuf,
|
||||
GError **error)
|
||||
{
|
||||
GChecksum *content_sha256 = NULL;
|
||||
GChecksum *content_and_meta_sha256 = NULL;
|
||||
char *stat_string = NULL;
|
||||
ssize_t bytes_read;
|
||||
GVariant *xattrs = NULL;
|
||||
int fd = -1;
|
||||
DIR *temp_dir = NULL;
|
||||
char *basename = NULL;
|
||||
gboolean ret = FALSE;
|
||||
char *symlink_target = NULL;
|
||||
char *device_id = NULL;
|
||||
struct stat stbuf;
|
||||
|
||||
basename = g_path_get_basename (path);
|
||||
|
||||
if (dir_fd == -1)
|
||||
{
|
||||
char *dirname = g_path_get_dirname (path);
|
||||
temp_dir = opendir (dirname);
|
||||
if (temp_dir == NULL)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
g_free (dirname);
|
||||
}
|
||||
g_free (dirname);
|
||||
dir_fd = dirfd (temp_dir);
|
||||
}
|
||||
|
||||
if (fstatat (dir_fd, basename, &stbuf, AT_SYMLINK_NOFOLLOW) < 0)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (S_ISREG(stbuf.st_mode))
|
||||
{
|
||||
fd = ot_util_open_file_read_at (dir_fd, basename, error);
|
||||
if (fd < 0)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (objtype == OSTREE_OBJECT_TYPE_FILE)
|
||||
{
|
||||
xattrs = ostree_get_xattrs_for_path (path, error);
|
||||
if (!xattrs)
|
||||
goto out;
|
||||
}
|
||||
|
||||
content_sha256 = g_checksum_new (G_CHECKSUM_SHA256);
|
||||
|
||||
if (S_ISREG(stbuf.st_mode))
|
||||
{
|
||||
guint8 buf[8192];
|
||||
|
||||
while ((bytes_read = read (fd, buf, sizeof (buf))) > 0)
|
||||
g_checksum_update (content_sha256, buf, bytes_read);
|
||||
if (bytes_read < 0)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else if (S_ISLNK(stbuf.st_mode))
|
||||
{
|
||||
symlink_target = g_malloc (PATH_MAX);
|
||||
|
||||
g_assert (objtype == OSTREE_OBJECT_TYPE_FILE);
|
||||
|
||||
bytes_read = readlinkat (dir_fd, basename, symlink_target, PATH_MAX);
|
||||
if (bytes_read < 0)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
goto out;
|
||||
}
|
||||
g_checksum_update (content_sha256, (guint8*)symlink_target, bytes_read);
|
||||
}
|
||||
else if (S_ISCHR(stbuf.st_mode) || S_ISBLK(stbuf.st_mode))
|
||||
{
|
||||
g_assert (objtype == OSTREE_OBJECT_TYPE_FILE);
|
||||
device_id = g_strdup_printf ("%u", (guint)stbuf.st_rdev);
|
||||
g_checksum_update (content_sha256, (guint8*)device_id, strlen (device_id));
|
||||
}
|
||||
else if (S_ISFIFO(stbuf.st_mode))
|
||||
{
|
||||
g_assert (objtype == OSTREE_OBJECT_TYPE_FILE);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"Unsupported file '%s' (must be regular, symbolic link, fifo, or character/block device)",
|
||||
path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
content_and_meta_sha256 = g_checksum_copy (content_sha256);
|
||||
|
||||
if (objtype == OSTREE_OBJECT_TYPE_FILE)
|
||||
{
|
||||
ostree_checksum_update_stat (content_and_meta_sha256, stbuf.st_uid,
|
||||
stbuf.st_gid, stbuf.st_mode);
|
||||
g_checksum_update (content_and_meta_sha256, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
|
||||
}
|
||||
|
||||
*out_stbuf = stbuf;
|
||||
*out_checksum = content_and_meta_sha256;
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (fd >= 0)
|
||||
close (fd);
|
||||
if (temp_dir != NULL)
|
||||
closedir (temp_dir);
|
||||
g_free (symlink_target);
|
||||
g_free (basename);
|
||||
g_free (stat_string);
|
||||
if (xattrs)
|
||||
g_variant_unref (xattrs);
|
||||
if (content_sha256)
|
||||
g_checksum_free (content_sha256);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
ostree_set_xattrs (const char *path, GVariant *xattrs, GCancellable *cancellable, GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
int i, n;
|
||||
|
||||
n = g_variant_n_children (xattrs);
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
const guint8* name;
|
||||
GVariant *value;
|
||||
const guint8* value_data;
|
||||
gsize value_len;
|
||||
gboolean loop_err;
|
||||
|
||||
g_variant_get_child (xattrs, i, "(^&ay@ay)",
|
||||
&name, &value);
|
||||
value_data = g_variant_get_fixed_array (value, &value_len, 1);
|
||||
|
||||
loop_err = lsetxattr (path, (char*)name, (char*)value_data, value_len, XATTR_REPLACE) < 0;
|
||||
|
||||
g_variant_unref (value);
|
||||
if (loop_err)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
ostree_parse_metadata_file (const char *path,
|
||||
OstreeSerializedVariantType *out_type,
|
||||
GVariant **out_variant,
|
||||
GError **error)
|
||||
{
|
||||
GFile *pathf = NULL;
|
||||
gboolean ret = FALSE;
|
||||
GVariant *ret_variant = NULL;
|
||||
GVariant *container = NULL;
|
||||
guint32 ret_type;
|
||||
|
||||
pathf = ot_util_new_file_for_path (path);
|
||||
if (!ot_util_variant_map (pathf, G_VARIANT_TYPE (OSTREE_SERIALIZED_VARIANT_FORMAT),
|
||||
&container, error))
|
||||
goto out;
|
||||
|
||||
g_variant_get (container, "(uv)",
|
||||
&ret_type, &ret_variant);
|
||||
ret_type = GUINT32_FROM_BE (ret_type);
|
||||
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;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
*out_type = ret_type;
|
||||
*out_variant = ot_util_variant_take_ref (ret_variant);
|
||||
ret_variant = NULL;
|
||||
out:
|
||||
if (ret_variant)
|
||||
g_variant_unref (ret_variant);
|
||||
if (container != NULL)
|
||||
g_variant_unref (container);
|
||||
g_clear_object (&pathf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *
|
||||
ostree_get_relative_object_path (const char *checksum,
|
||||
OstreeObjectType type,
|
||||
gboolean archive)
|
||||
{
|
||||
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:
|
||||
if (archive)
|
||||
type_string = ".packfile";
|
||||
else
|
||||
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);
|
||||
}
|
||||
|
||||
gboolean
|
||||
ostree_pack_object (GOutputStream *output,
|
||||
GFile *file,
|
||||
OstreeObjectType objtype,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
char *path = NULL;
|
||||
GFileInfo *finfo = NULL;
|
||||
GFileInputStream *instream = NULL;
|
||||
gboolean pack_builder_initialized = FALSE;
|
||||
GVariantBuilder pack_builder;
|
||||
GVariant *pack_variant = NULL;
|
||||
GVariant *xattrs = NULL;
|
||||
gsize bytes_written;
|
||||
|
||||
path = g_file_get_path (file);
|
||||
|
||||
finfo = g_file_query_info (file, "standard::type,standard::size,standard::is-symlink,standard::symlink-target,unix::*",
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error);
|
||||
if (!finfo)
|
||||
goto out;
|
||||
|
||||
if (objtype == OSTREE_OBJECT_TYPE_META)
|
||||
{
|
||||
guint64 object_size_be = GUINT64_TO_BE ((guint64)g_file_info_get_size (finfo));
|
||||
if (!g_output_stream_write_all (output, &object_size_be, 8, &bytes_written, cancellable, error))
|
||||
goto out;
|
||||
|
||||
instream = g_file_read (file, NULL, error);
|
||||
if (!instream)
|
||||
goto out;
|
||||
|
||||
if (g_output_stream_splice (output, (GInputStream*)instream, 0, cancellable, error) < 0)
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
guint32 uid, gid, mode;
|
||||
guint32 device = 0;
|
||||
guint32 metadata_size_be;
|
||||
const char *target = NULL;
|
||||
guint64 object_size;
|
||||
|
||||
uid = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_UID);
|
||||
gid = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_GID);
|
||||
mode = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_MODE);
|
||||
|
||||
g_variant_builder_init (&pack_builder, G_VARIANT_TYPE (OSTREE_PACK_FILE_VARIANT_FORMAT));
|
||||
pack_builder_initialized = TRUE;
|
||||
g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (0));
|
||||
g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (uid));
|
||||
g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (gid));
|
||||
g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (mode));
|
||||
|
||||
xattrs = ostree_get_xattrs_for_path (path, error);
|
||||
if (!xattrs)
|
||||
goto out;
|
||||
g_variant_builder_add (&pack_builder, "@a(ayay)", xattrs);
|
||||
|
||||
if (S_ISREG (mode))
|
||||
{
|
||||
object_size = (guint64)g_file_info_get_size (finfo);
|
||||
}
|
||||
else if (S_ISLNK (mode))
|
||||
{
|
||||
target = g_file_info_get_attribute_byte_string (finfo, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET);
|
||||
object_size = strlen (target);
|
||||
}
|
||||
else if (S_ISBLK (mode) || S_ISCHR (mode))
|
||||
{
|
||||
device = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_DEVICE);
|
||||
object_size = 4;
|
||||
}
|
||||
else if (S_ISFIFO (mode))
|
||||
{
|
||||
object_size = 0;
|
||||
}
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
|
||||
g_variant_builder_add (&pack_builder, "t", GUINT64_TO_BE (object_size));
|
||||
pack_variant = g_variant_builder_end (&pack_builder);
|
||||
pack_builder_initialized = FALSE;
|
||||
|
||||
metadata_size_be = GUINT32_TO_BE (g_variant_get_size (pack_variant));
|
||||
|
||||
if (!g_output_stream_write_all (output, &metadata_size_be, 4,
|
||||
&bytes_written, cancellable, error))
|
||||
goto out;
|
||||
g_assert (bytes_written == 4);
|
||||
|
||||
if (!g_output_stream_write_all (output, g_variant_get_data (pack_variant), g_variant_get_size (pack_variant),
|
||||
&bytes_written, cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (S_ISREG (mode))
|
||||
{
|
||||
instream = g_file_read (file, NULL, error);
|
||||
if (!instream)
|
||||
goto out;
|
||||
bytes_written = g_output_stream_splice (output, (GInputStream*)instream, 0, cancellable, error);
|
||||
if (bytes_written < 0)
|
||||
goto out;
|
||||
if (bytes_written != object_size)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"File size changed unexpectedly");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else if (S_ISLNK (mode))
|
||||
{
|
||||
if (!g_output_stream_write_all (output, target, object_size,
|
||||
&bytes_written, cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
else if (S_ISBLK (mode) || S_ISCHR (mode))
|
||||
{
|
||||
guint32 device_be = GUINT32_TO_BE (device);
|
||||
g_assert (object_size == 4);
|
||||
if (!g_output_stream_write_all (output, &device_be, object_size,
|
||||
&bytes_written, cancellable, error))
|
||||
goto out;
|
||||
g_assert (bytes_written == 4);
|
||||
}
|
||||
else if (S_ISFIFO (mode))
|
||||
{
|
||||
}
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
g_free (path);
|
||||
g_clear_object (&finfo);
|
||||
g_clear_object (&instream);
|
||||
if (xattrs)
|
||||
g_variant_unref (xattrs);
|
||||
if (pack_builder_initialized)
|
||||
g_variant_builder_clear (&pack_builder);
|
||||
if (pack_variant)
|
||||
g_variant_unref (pack_variant);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
splice_and_checksum (GOutputStream *out,
|
||||
GInputStream *in,
|
||||
GChecksum *checksum,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
|
||||
if (checksum != NULL)
|
||||
{
|
||||
gsize bytes_read, bytes_written;
|
||||
char buf[4096];
|
||||
do
|
||||
{
|
||||
if (!g_input_stream_read_all (in, buf, sizeof(buf), &bytes_read, cancellable, error))
|
||||
goto out;
|
||||
if (checksum)
|
||||
g_checksum_update (checksum, (guint8*)buf, bytes_read);
|
||||
if (!g_output_stream_write_all (out, buf, bytes_read, &bytes_written, cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
while (bytes_read > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g_output_stream_splice (out, in, 0, cancellable, error) < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
unpack_meta (const char *path,
|
||||
const char *dest_path,
|
||||
GChecksum **out_checksum,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GFile *file = NULL;
|
||||
GFile *dest_file = NULL;
|
||||
GFileInputStream *in = NULL;
|
||||
GChecksum *ret_checksum = NULL;
|
||||
GFileOutputStream *out = NULL;
|
||||
|
||||
file = ot_util_new_file_for_path (path);
|
||||
dest_file = ot_util_new_file_for_path (dest_path);
|
||||
|
||||
if (out_checksum)
|
||||
ret_checksum = g_checksum_new (G_CHECKSUM_SHA256);
|
||||
|
||||
in = g_file_read (file, NULL, error);
|
||||
if (!in)
|
||||
goto out;
|
||||
|
||||
out = g_file_replace (dest_file, NULL, FALSE, 0, NULL, error);
|
||||
if (!out)
|
||||
goto out;
|
||||
|
||||
if (!splice_and_checksum ((GOutputStream*)out, (GInputStream*)in, ret_checksum, NULL, error))
|
||||
goto out;
|
||||
|
||||
if (!g_output_stream_close ((GOutputStream*)out, NULL, error))
|
||||
goto out;
|
||||
|
||||
ret = TRUE;
|
||||
if (out_checksum)
|
||||
*out_checksum = ret_checksum;
|
||||
ret_checksum = NULL;
|
||||
out:
|
||||
if (!ret)
|
||||
(void) unlink (dest_path);
|
||||
if (ret_checksum)
|
||||
g_checksum_free (ret_checksum);
|
||||
g_clear_object (&file);
|
||||
g_clear_object (&dest_file);
|
||||
g_clear_object (&in);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
ostree_parse_packed_file (GFile *file,
|
||||
GVariant **out_metadata,
|
||||
GInputStream **out_content,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
char *metadata_buf = NULL;
|
||||
GVariant *ret_metadata = NULL;
|
||||
GFileInputStream *in = NULL;
|
||||
guint32 metadata_len;
|
||||
gsize bytes_read;
|
||||
|
||||
in = g_file_read (file, NULL, error);
|
||||
if (!in)
|
||||
goto out;
|
||||
|
||||
if (!g_input_stream_read_all ((GInputStream*)in, &metadata_len, 4, &bytes_read, NULL, error))
|
||||
goto out;
|
||||
if (bytes_read != 4)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Corrupted packfile; too short while reading metadata length");
|
||||
goto out;
|
||||
}
|
||||
|
||||
metadata_len = GUINT32_FROM_BE (metadata_len);
|
||||
if (metadata_len > OSTREE_MAX_METADATA_SIZE)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Corrupted packfile; metadata length %u is larger than maximum %u",
|
||||
metadata_len, OSTREE_MAX_METADATA_SIZE);
|
||||
goto out;
|
||||
}
|
||||
metadata_buf = g_malloc (metadata_len);
|
||||
|
||||
if (!g_input_stream_read_all ((GInputStream*)in, metadata_buf, metadata_len, &bytes_read, NULL, error))
|
||||
goto out;
|
||||
if (bytes_read != metadata_len)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Corrupted packfile; too short while reading metadata");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret_metadata = g_variant_new_from_data (G_VARIANT_TYPE (OSTREE_PACK_FILE_VARIANT_FORMAT),
|
||||
metadata_buf, metadata_len, FALSE,
|
||||
(GDestroyNotify)g_free,
|
||||
metadata_buf);
|
||||
metadata_buf = NULL;
|
||||
|
||||
ret = TRUE;
|
||||
*out_metadata = ret_metadata;
|
||||
ret_metadata = NULL;
|
||||
*out_content = (GInputStream*)in;
|
||||
in = NULL;
|
||||
out:
|
||||
g_clear_object (&in);
|
||||
if (ret_metadata)
|
||||
g_variant_unref (ret_metadata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
unpack_file (const char *path,
|
||||
const char *dest_path,
|
||||
GChecksum **out_checksum,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GFile *file = NULL;
|
||||
GFile *dest_file = NULL;
|
||||
GVariant *metadata = NULL;
|
||||
GVariant *xattrs = NULL;
|
||||
GInputStream *in = NULL;
|
||||
GFileOutputStream *out = NULL;
|
||||
GChecksum *ret_checksum = NULL;
|
||||
guint32 version, uid, gid, mode;
|
||||
guint64 content_len;
|
||||
gsize bytes_read;
|
||||
|
||||
file = ot_util_new_file_for_path (path);
|
||||
|
||||
if (!ostree_parse_packed_file (file, &metadata, &in, NULL, error))
|
||||
goto out;
|
||||
|
||||
g_variant_get (metadata, "(uuuu@a(ayay)t)",
|
||||
&version, &uid, &gid, &mode,
|
||||
&xattrs, &content_len);
|
||||
uid = GUINT32_FROM_BE (uid);
|
||||
gid = GUINT32_FROM_BE (gid);
|
||||
mode = GUINT32_FROM_BE (mode);
|
||||
content_len = GUINT64_FROM_BE (content_len);
|
||||
|
||||
dest_file = ot_util_new_file_for_path (dest_path);
|
||||
|
||||
if (out_checksum)
|
||||
ret_checksum = g_checksum_new (G_CHECKSUM_SHA256);
|
||||
|
||||
if (S_ISREG (mode))
|
||||
{
|
||||
out = g_file_replace (dest_file, NULL, FALSE, 0, NULL, error);
|
||||
if (!out)
|
||||
goto out;
|
||||
|
||||
if (!splice_and_checksum ((GOutputStream*)out, in, ret_checksum, NULL, error))
|
||||
goto out;
|
||||
|
||||
if (!g_output_stream_close ((GOutputStream*)out, NULL, error))
|
||||
goto out;
|
||||
}
|
||||
else if (S_ISLNK (mode))
|
||||
{
|
||||
char target[PATH_MAX+1];
|
||||
|
||||
if (!g_input_stream_read_all (in, target, sizeof(target)-1, &bytes_read, NULL, error))
|
||||
goto out;
|
||||
target[bytes_read] = '\0';
|
||||
if (ret_checksum)
|
||||
g_checksum_update (ret_checksum, (guint8*)target, bytes_read);
|
||||
if (symlink (target, dest_path) < 0)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else if (S_ISCHR (mode) || S_ISBLK (mode))
|
||||
{
|
||||
guint32 dev;
|
||||
|
||||
if (!g_input_stream_read_all (in, &dev, 4, &bytes_read, NULL, error))
|
||||
goto out;
|
||||
if (bytes_read != 4)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Corrupted packfile; too short while reading device id");
|
||||
goto out;
|
||||
}
|
||||
dev = GUINT32_FROM_BE (dev);
|
||||
if (ret_checksum)
|
||||
g_checksum_update (ret_checksum, (guint8*)&dev, 4);
|
||||
if (mknod (dest_path, mode, dev) < 0)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else if (S_ISFIFO (mode))
|
||||
{
|
||||
if (mkfifo (dest_path, mode) < 0)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Corrupted packfile; invalid mode %u", mode);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!S_ISLNK (mode))
|
||||
{
|
||||
if (chmod (dest_path, mode) < 0)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ostree_set_xattrs (dest_path, xattrs, NULL, error))
|
||||
goto out;
|
||||
|
||||
if (ret_checksum)
|
||||
{
|
||||
ostree_checksum_update_stat (ret_checksum, uid, gid, mode);
|
||||
g_checksum_update (ret_checksum, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
if (out_checksum)
|
||||
*out_checksum = ret_checksum;
|
||||
ret_checksum = NULL;
|
||||
out:
|
||||
if (!ret)
|
||||
(void) unlink (dest_path);
|
||||
if (ret_checksum)
|
||||
g_checksum_free (ret_checksum);
|
||||
g_clear_object (&file);
|
||||
g_clear_object (&dest_file);
|
||||
g_clear_object (&in);
|
||||
g_clear_object (&out);
|
||||
if (metadata)
|
||||
g_variant_unref (metadata);
|
||||
if (xattrs)
|
||||
g_variant_unref (xattrs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
ostree_unpack_object (const char *path,
|
||||
OstreeObjectType objtype,
|
||||
const char *dest_path,
|
||||
GChecksum **out_checksum,
|
||||
GError **error)
|
||||
{
|
||||
if (objtype == OSTREE_OBJECT_TYPE_META)
|
||||
return unpack_meta (path, dest_path, out_checksum, error);
|
||||
else
|
||||
return unpack_file (path, dest_path, out_checksum, error);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
/* -*- 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>
|
||||
*/
|
||||
|
||||
#ifndef _OSTREE_CORE
|
||||
#define _OSTREE_CORE
|
||||
|
||||
#include <otutil.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define OSTREE_MAX_METADATA_SIZE (1 << 26)
|
||||
|
||||
#define OSTREE_GIO_FAST_QUERYINFO "standard::name,standard::type,standard::is-symlink,standard::symlink-target,standard::is-hidden,unix::*"
|
||||
|
||||
#define OSTREE_EMPTY_STRING_SHA256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
|
||||
|
||||
typedef enum {
|
||||
OSTREE_OBJECT_TYPE_FILE = 1,
|
||||
OSTREE_OBJECT_TYPE_META = 2,
|
||||
} OstreeObjectType;
|
||||
|
||||
typedef enum {
|
||||
OSTREE_SERIALIZED_TREE_VARIANT = 1,
|
||||
OSTREE_SERIALIZED_COMMIT_VARIANT = 2,
|
||||
OSTREE_SERIALIZED_DIRMETA_VARIANT = 3,
|
||||
OSTREE_SERIALIZED_XATTR_VARIANT = 4
|
||||
} OstreeSerializedVariantType;
|
||||
#define OSTREE_SERIALIZED_VARIANT_LAST 4
|
||||
|
||||
#define OSTREE_SERIALIZED_VARIANT_FORMAT "(uv)"
|
||||
|
||||
/*
|
||||
* xattr objects:
|
||||
* a(ayay) - array of (name, value) pairs, both binary data, though name is a bytestring
|
||||
*/
|
||||
#define OSTREE_XATTR_GVARIANT_FORMAT "a(ayay)"
|
||||
|
||||
#define OSTREE_DIR_META_VERSION 0
|
||||
/*
|
||||
* dirmeta objects:
|
||||
* u - Version
|
||||
* u - uid
|
||||
* u - gid
|
||||
* u - mode
|
||||
* a(ayay) - xattrs
|
||||
*/
|
||||
#define OSTREE_DIRMETA_GVARIANT_FORMAT "(uuuua(ayay))"
|
||||
|
||||
#define OSTREE_TREE_VERSION 0
|
||||
/*
|
||||
* Tree objects:
|
||||
* u - Version
|
||||
* a{sv} - Metadata
|
||||
* a(ss) - array of (filename, checksum) for files
|
||||
* a(sss) - array of (dirname, tree_checksum, meta_checksum) for directories
|
||||
*/
|
||||
#define OSTREE_TREE_GVARIANT_FORMAT "(ua{sv}a(ss)a(sss)"
|
||||
|
||||
#define OSTREE_COMMIT_VERSION 0
|
||||
/*
|
||||
* Commit objects:
|
||||
* u - Version
|
||||
* a{sv} - Metadata
|
||||
* s - parent checksum (empty string for initial)
|
||||
* s - subject
|
||||
* s - body
|
||||
* t - Timestamp in seconds since the epoch (UTC)
|
||||
* s - Root tree contents
|
||||
* s - Root tree metadata
|
||||
*/
|
||||
#define OSTREE_COMMIT_GVARIANT_FORMAT "(ua{sv}ssstss)"
|
||||
|
||||
gboolean ostree_validate_checksum_string (const char *sha256,
|
||||
GError **error);
|
||||
|
||||
char *ostree_get_relative_object_path (const char *checksum,
|
||||
OstreeObjectType type,
|
||||
gboolean archive);
|
||||
|
||||
GVariant *ostree_get_xattrs_for_path (const char *path,
|
||||
GError **error);
|
||||
|
||||
gboolean ostree_set_xattrs (const char *path, GVariant *xattrs,
|
||||
GCancellable *cancellable, 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,
|
||||
OstreeObjectType type,
|
||||
GChecksum **out_checksum,
|
||||
struct stat *out_stbuf,
|
||||
GError **error);
|
||||
|
||||
/* Packed files:
|
||||
*
|
||||
* guint32 metadata_length [metadata gvariant] [content]
|
||||
*
|
||||
* metadata variant:
|
||||
* u - Version
|
||||
* u - uid
|
||||
* u - gid
|
||||
* u - mode
|
||||
* a(ayay) - xattrs
|
||||
* t - content length
|
||||
*
|
||||
* And then following the end of the variant is the content. If
|
||||
* symlink, then this is the target; if device, then device ID as
|
||||
* network byte order uint32.
|
||||
*/
|
||||
#define OSTREE_PACK_FILE_VARIANT_FORMAT "(uuuua(ayay)t)"
|
||||
|
||||
gboolean ostree_pack_object (GOutputStream *output,
|
||||
GFile *file,
|
||||
OstreeObjectType objtype,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean ostree_parse_packed_file (GFile *file,
|
||||
GVariant **out_metadata,
|
||||
GInputStream **out_content,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean ostree_unpack_object (const char *path,
|
||||
OstreeObjectType objtype,
|
||||
const char *dest_path,
|
||||
GChecksum **out_checksum,
|
||||
GError **error);
|
||||
|
||||
void ostree_checksum_update_stat (GChecksum *checksum, guint32 uid, guint32 gid, guint32 mode);
|
||||
|
||||
|
||||
#endif /* _OSTREE_REPO */
|
||||
@@ -0,0 +1,143 @@
|
||||
/* -*- 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 "ostree-repo-file-enumerator.h"
|
||||
#include <string.h>
|
||||
|
||||
struct _OstreeRepoFileEnumerator
|
||||
{
|
||||
GFileEnumerator parent;
|
||||
|
||||
OstreeRepoFile *dir;
|
||||
char *attributes;
|
||||
GFileQueryInfoFlags flags;
|
||||
|
||||
int index;
|
||||
};
|
||||
|
||||
#define ostree_repo_file_enumerator_get_type _ostree_repo_file_enumerator_get_type
|
||||
G_DEFINE_TYPE (OstreeRepoFileEnumerator, ostree_repo_file_enumerator, G_TYPE_FILE_ENUMERATOR);
|
||||
|
||||
static GFileInfo *ostree_repo_file_enumerator_next_file (GFileEnumerator *enumerator,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
static gboolean ostree_repo_file_enumerator_close (GFileEnumerator *enumerator,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
|
||||
static void
|
||||
ostree_repo_file_enumerator_dispose (GObject *object)
|
||||
{
|
||||
OstreeRepoFileEnumerator *self;
|
||||
|
||||
self = OSTREE_REPO_FILE_ENUMERATOR (object);
|
||||
|
||||
g_clear_object (&self->dir);
|
||||
g_free (self->attributes);
|
||||
|
||||
if (G_OBJECT_CLASS (ostree_repo_file_enumerator_parent_class)->dispose)
|
||||
G_OBJECT_CLASS (ostree_repo_file_enumerator_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
ostree_repo_file_enumerator_finalize (GObject *object)
|
||||
{
|
||||
OstreeRepoFileEnumerator *self;
|
||||
|
||||
self = OSTREE_REPO_FILE_ENUMERATOR (object);
|
||||
(void)self;
|
||||
|
||||
G_OBJECT_CLASS (ostree_repo_file_enumerator_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ostree_repo_file_enumerator_class_init (OstreeRepoFileEnumeratorClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GFileEnumeratorClass *enumerator_class = G_FILE_ENUMERATOR_CLASS (klass);
|
||||
|
||||
gobject_class->finalize = ostree_repo_file_enumerator_finalize;
|
||||
gobject_class->dispose = ostree_repo_file_enumerator_dispose;
|
||||
|
||||
enumerator_class->next_file = ostree_repo_file_enumerator_next_file;
|
||||
enumerator_class->close_fn = ostree_repo_file_enumerator_close;
|
||||
}
|
||||
|
||||
static void
|
||||
ostree_repo_file_enumerator_init (OstreeRepoFileEnumerator *self)
|
||||
{
|
||||
}
|
||||
|
||||
GFileEnumerator *
|
||||
_ostree_repo_file_enumerator_new (OstreeRepoFile *dir,
|
||||
const char *attributes,
|
||||
GFileQueryInfoFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
OstreeRepoFileEnumerator *self;
|
||||
|
||||
self = g_object_new (OSTREE_TYPE_REPO_FILE_ENUMERATOR,
|
||||
"container", dir,
|
||||
NULL);
|
||||
|
||||
self->dir = g_object_ref (dir);
|
||||
self->attributes = g_strdup (attributes);
|
||||
self->flags = flags;
|
||||
|
||||
return G_FILE_ENUMERATOR (self);
|
||||
}
|
||||
|
||||
static GFileInfo *
|
||||
ostree_repo_file_enumerator_next_file (GFileEnumerator *enumerator,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
OstreeRepoFileEnumerator *self = OSTREE_REPO_FILE_ENUMERATOR (enumerator);
|
||||
gboolean ret = FALSE;
|
||||
GFileInfo *info = NULL;
|
||||
|
||||
if (!_ostree_repo_file_tree_query_child (self->dir, self->index,
|
||||
self->attributes, self->flags,
|
||||
&info, cancellable, error))
|
||||
goto out;
|
||||
|
||||
self->index++;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (!ret)
|
||||
g_clear_object (&info);
|
||||
return info;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ostree_repo_file_enumerator_close (GFileEnumerator *enumerator,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/* -*- 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>
|
||||
*/
|
||||
|
||||
#ifndef _OSTREE_REPO_FILE_ENUMERATOR
|
||||
#define _OSTREE_REPO_FILE_ENUMERATOR
|
||||
|
||||
#include "ostree-repo-file.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define OSTREE_TYPE_REPO_FILE_ENUMERATOR (_ostree_repo_file_enumerator_get_type ())
|
||||
#define OSTREE_REPO_FILE_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_REPO_FILE_ENUMERATOR, OstreeRepoFileEnumerator))
|
||||
#define OSTREE_REPO_FILE_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_REPO_FILE_ENUMERATOR, OstreeRepoFileEnumeratorClass))
|
||||
#define OSTREE_IS_REPO_FILE_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_REPO_FILE_ENUMERATOR))
|
||||
#define OSTREE_IS_REPO_FILE_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_REPO_FILE_ENUMERATOR))
|
||||
#define OSTREE_REPO_FILE_ENUMERATOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_REPO_FILE_ENUMERATOR, OstreeRepoFileEnumeratorClass))
|
||||
|
||||
typedef struct _OstreeRepoFileEnumerator OstreeRepoFileEnumerator;
|
||||
typedef struct _OstreeRepoFileEnumeratorClass OstreeRepoFileEnumeratorClass;
|
||||
|
||||
struct _OstreeRepoFileEnumeratorClass
|
||||
{
|
||||
GFileEnumeratorClass parent_class;
|
||||
};
|
||||
|
||||
GType _ostree_repo_file_enumerator_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GFileEnumerator * _ostree_repo_file_enumerator_new (OstreeRepoFile *dir,
|
||||
const char *attributes,
|
||||
GFileQueryInfoFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,115 @@
|
||||
/* -*- 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>
|
||||
*/
|
||||
|
||||
#ifndef _OSTREE_REPO_FILE
|
||||
#define _OSTREE_REPO_FILE
|
||||
|
||||
#include "ostree-repo.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define OSTREE_TYPE_REPO_FILE (_ostree_repo_file_get_type ())
|
||||
#define OSTREE_REPO_FILE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_REPO_FILE, OstreeRepoFile))
|
||||
#define OSTREE_REPO_FILE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_REPO_FILE, OstreeRepoFileClass))
|
||||
#define OSTREE_IS_LOCAL_FILE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_REPO_FILE))
|
||||
#define OSTREE_IS_LOCAL_FILE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_REPO_FILE))
|
||||
#define OSTREE_REPO_FILE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_REPO_FILE, OstreeRepoFileClass))
|
||||
|
||||
typedef struct _OstreeRepoFile OstreeRepoFile;
|
||||
typedef struct _OstreeRepoFileClass OstreeRepoFileClass;
|
||||
|
||||
struct _OstreeRepoFileClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
GType _ostree_repo_file_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GFile * _ostree_repo_file_new_root (OstreeRepo *repo,
|
||||
const char *commit);
|
||||
|
||||
OstreeRepoFile * _ostree_repo_file_new_empty_tree (OstreeRepo *repo);
|
||||
|
||||
GFile * _ostree_repo_file_new_child (OstreeRepoFile *parent,
|
||||
const char *name);
|
||||
|
||||
gboolean _ostree_repo_file_ensure_resolved (OstreeRepoFile *self,
|
||||
GError **error);
|
||||
|
||||
gboolean _ostree_repo_file_get_xattrs (OstreeRepoFile *self,
|
||||
GVariant **out_xattrs,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
OstreeRepo * _ostree_repo_file_get_repo (OstreeRepoFile *self);
|
||||
OstreeRepoFile * _ostree_repo_file_get_root (OstreeRepoFile *self);
|
||||
|
||||
void _ostree_repo_file_make_empty_tree (OstreeRepoFile *self);
|
||||
|
||||
void _ostree_repo_file_tree_set_metadata (OstreeRepoFile *self,
|
||||
const char *checksum,
|
||||
GVariant *metadata);
|
||||
|
||||
void _ostree_repo_file_tree_set_content_checksum (OstreeRepoFile *self,
|
||||
const char *checksum);
|
||||
const char *_ostree_repo_file_tree_get_content_checksum (OstreeRepoFile *self);
|
||||
|
||||
gboolean _ostree_repo_file_is_tree (OstreeRepoFile *self);
|
||||
|
||||
const char * _ostree_repo_file_nontree_get_checksum (OstreeRepoFile *self);
|
||||
|
||||
GFile *_ostree_repo_file_nontree_get_local (OstreeRepoFile *self);
|
||||
|
||||
void _ostree_repo_file_tree_remove_child (OstreeRepoFile *self,
|
||||
const char *name);
|
||||
|
||||
void _ostree_repo_file_tree_add_file (OstreeRepoFile *self,
|
||||
const char *name,
|
||||
const char *checksum);
|
||||
|
||||
void _ostree_repo_file_tree_add_dir (OstreeRepoFile *self,
|
||||
const char *name,
|
||||
const char *content_checksum,
|
||||
const char *metadata_checksum);
|
||||
|
||||
int _ostree_repo_file_tree_find_child (OstreeRepoFile *self,
|
||||
const char *name,
|
||||
gboolean *is_dir,
|
||||
GVariant **out_container);
|
||||
|
||||
const char *_ostree_repo_file_tree_get_child_checksum (OstreeRepoFile *self,
|
||||
int n);
|
||||
|
||||
gboolean _ostree_repo_file_tree_query_child (OstreeRepoFile *self,
|
||||
int n,
|
||||
const char *attributes,
|
||||
GFileQueryInfoFlags flags,
|
||||
GFileInfo **out_info,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
GVariant *_ostree_repo_file_tree_get_contents (OstreeRepoFile *self);
|
||||
GVariant *_ostree_repo_file_tree_get_metadata (OstreeRepoFile *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,162 @@
|
||||
/* -*- 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>
|
||||
*/
|
||||
|
||||
#ifndef _OSTREE_REPO
|
||||
#define _OSTREE_REPO
|
||||
|
||||
#include "ostree-core.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define OSTREE_TYPE_REPO ostree_repo_get_type()
|
||||
#define OSTREE_REPO(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST ((obj), OSTREE_TYPE_REPO, OstreeRepo))
|
||||
#define OSTREE_REPO_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST ((klass), OSTREE_TYPE_REPO, OstreeRepoClass))
|
||||
#define OSTREE_IS_REPO(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), OSTREE_TYPE_REPO))
|
||||
#define OSTREE_IS_REPO_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE ((klass), OSTREE_TYPE_REPO))
|
||||
#define OSTREE_REPO_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS ((obj), OSTREE_TYPE_REPO, OstreeRepoClass))
|
||||
|
||||
typedef struct {
|
||||
GObject parent;
|
||||
} OstreeRepo;
|
||||
|
||||
typedef struct {
|
||||
GObjectClass parent_class;
|
||||
} OstreeRepoClass;
|
||||
|
||||
GType ostree_repo_get_type (void);
|
||||
|
||||
OstreeRepo* ostree_repo_new (const char *path);
|
||||
|
||||
gboolean ostree_repo_check (OstreeRepo *self, GError **error);
|
||||
|
||||
const char * ostree_repo_get_path (OstreeRepo *self);
|
||||
|
||||
gboolean ostree_repo_is_archive (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);
|
||||
|
||||
char * ostree_repo_get_object_path (OstreeRepo *self,
|
||||
const char *object,
|
||||
OstreeObjectType type);
|
||||
|
||||
gboolean ostree_repo_store_packfile (OstreeRepo *self,
|
||||
const char *expected_checksum,
|
||||
const char *path,
|
||||
OstreeObjectType objtype,
|
||||
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,
|
||||
GVariant **out_variant,
|
||||
GError **error);
|
||||
|
||||
gboolean ostree_repo_load_variant_checked (OstreeRepo *self,
|
||||
OstreeSerializedVariantType expected_type,
|
||||
const char *sha256,
|
||||
GVariant **out_variant,
|
||||
GError **error);
|
||||
|
||||
gboolean ostree_repo_commit_from_filelist_fd (OstreeRepo *self,
|
||||
const char *branch,
|
||||
const char *parent,
|
||||
const char *subject,
|
||||
const char *body,
|
||||
GVariant *metadata,
|
||||
const char *base,
|
||||
int fd,
|
||||
char separator,
|
||||
GChecksum **out_commit,
|
||||
GError **error);
|
||||
|
||||
gboolean ostree_repo_checkout (OstreeRepo *self,
|
||||
const char *ref,
|
||||
const char *destination,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
typedef struct {
|
||||
guint content_differs : 1;
|
||||
guint xattrs_differs : 1;
|
||||
guint unused : 30;
|
||||
|
||||
GFileInfo *src_info;
|
||||
GFileInfo *target_info;
|
||||
|
||||
char *src_file_checksum;
|
||||
char *target_file_checksum;
|
||||
|
||||
GVariant *src_xattrs;
|
||||
GVariant *target_xattrs;
|
||||
} OstreeRepoDiffItem;
|
||||
|
||||
gboolean ostree_repo_diff (OstreeRepo *self,
|
||||
const char *ref,
|
||||
GFile *target,
|
||||
GPtrArray **out_modified, /* OstreeRepoDiffItem */
|
||||
GPtrArray **out_removed, /* OstreeRepoDiffItem */
|
||||
GPtrArray **out_added, /* OstreeRepoDiffItem */
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
typedef void (*OstreeRepoObjectIter) (OstreeRepo *self, const char *path,
|
||||
GFileInfo *fileinfo, gpointer user_data);
|
||||
|
||||
gboolean ostree_repo_iter_objects (OstreeRepo *self,
|
||||
OstreeRepoObjectIter callback,
|
||||
gpointer user_data,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* _OSTREE_REPO */
|
||||
@@ -0,0 +1,29 @@
|
||||
/* -*- 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>
|
||||
*/
|
||||
|
||||
#ifndef __OSTREE_H__
|
||||
|
||||
#include <ostree-core.h>
|
||||
#include <ostree-repo.h>
|
||||
#include <ostree-checkout.h>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,178 @@
|
||||
/* -*- 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 <gio/gio.h>
|
||||
#include <gio/gunixinputstream.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "otutil.h"
|
||||
|
||||
gboolean
|
||||
ot_util_ensure_directory (const char *path, gboolean with_parents, GError **error)
|
||||
{
|
||||
GFile *dir;
|
||||
GError *temp_error = NULL;
|
||||
gboolean ret = FALSE;
|
||||
|
||||
dir = g_file_new_for_path (path);
|
||||
if (with_parents)
|
||||
ret = g_file_make_directory_with_parents (dir, NULL, &temp_error);
|
||||
else
|
||||
ret = g_file_make_directory (dir, NULL, &temp_error);
|
||||
if (!ret)
|
||||
{
|
||||
if (!g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_EXISTS))
|
||||
{
|
||||
g_propagate_error (error, temp_error);
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
g_clear_error (&temp_error);
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
g_clear_object (&dir);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
ot_util_get_file_contents_utf8 (const char *path,
|
||||
GError **error)
|
||||
{
|
||||
GFile *file = NULL;
|
||||
char *ret = NULL;
|
||||
|
||||
file = ot_util_new_file_for_path (path);
|
||||
if (!ot_util_gfile_load_contents_utf8 (file, NULL, &ret, NULL, error))
|
||||
goto out;
|
||||
|
||||
out:
|
||||
g_clear_object (&file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
ot_util_gfile_load_contents_utf8 (GFile *file,
|
||||
GCancellable *cancellable,
|
||||
char **contents_out,
|
||||
char **etag_out,
|
||||
GError **error)
|
||||
{
|
||||
char *ret_contents = NULL;
|
||||
char *ret_etag = NULL;
|
||||
gsize len;
|
||||
gboolean ret = FALSE;
|
||||
|
||||
if (!g_file_load_contents (file, cancellable, &ret_contents, &len, &ret_etag, error))
|
||||
goto out;
|
||||
if (!g_utf8_validate (ret_contents, len, NULL))
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_DATA,
|
||||
"Invalid UTF-8");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (contents_out)
|
||||
*contents_out = ret_contents;
|
||||
else
|
||||
g_free (ret_contents);
|
||||
ret_contents = NULL;
|
||||
if (etag_out)
|
||||
*etag_out = ret_etag;
|
||||
else
|
||||
g_free (ret_etag);
|
||||
ret_etag = NULL;
|
||||
ret = TRUE;
|
||||
out:
|
||||
g_free (ret_contents);
|
||||
g_free (ret_etag);
|
||||
return ret;
|
||||
}
|
||||
|
||||
GInputStream *
|
||||
ot_util_read_file_noatime (GFile *file, GCancellable *cancellable, GError **error)
|
||||
{
|
||||
GInputStream *ret = NULL;
|
||||
int fd;
|
||||
int flags = O_RDONLY;
|
||||
char *path = NULL;
|
||||
|
||||
path = g_file_get_path (file);
|
||||
#ifdef O_NOATIME
|
||||
flags |= O_NOATIME;
|
||||
#endif
|
||||
fd = open (path, flags);
|
||||
if (fd < 0)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = (GInputStream*)g_unix_input_stream_new (fd, TRUE);
|
||||
|
||||
out:
|
||||
g_free (path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Like g_file_new_for_path, but only do local stuff, not GVFS */
|
||||
GFile *
|
||||
ot_util_new_file_for_path (const char *path)
|
||||
{
|
||||
return g_vfs_get_file_for_path (g_vfs_get_local (), path);
|
||||
}
|
||||
|
||||
const char *
|
||||
ot_gfile_get_path_cached (GFile *file)
|
||||
{
|
||||
const char *path;
|
||||
|
||||
path = g_object_get_data ((GObject*)file, "ostree-file-path");
|
||||
if (!path)
|
||||
{
|
||||
path = g_file_get_path (file);
|
||||
g_object_set_data_full ((GObject*)file, "ostree-file-path", (char*)path, (GDestroyNotify)g_free);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
ot_gfile_get_basename_cached (GFile *file)
|
||||
{
|
||||
const char *name;
|
||||
|
||||
name = g_object_get_data ((GObject*)file, "ostree-file-name");
|
||||
if (!name)
|
||||
{
|
||||
name = g_file_get_basename (file);
|
||||
g_object_set_data_full ((GObject*)file, "ostree-file-name", (char*)name, (GDestroyNotify)g_free);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/* -*- 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>
|
||||
*/
|
||||
|
||||
#ifndef __OSTREE_GIO_UTILS_H__
|
||||
#define __OSTREE_GIO_UTILS_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GFile *ot_util_new_file_for_path (const char *path);
|
||||
|
||||
const char *ot_gfile_get_path_cached (GFile *file);
|
||||
|
||||
const char *ot_gfile_get_basename_cached (GFile *file);
|
||||
|
||||
gboolean ot_util_ensure_directory (const char *path, gboolean with_parents, GError **error);
|
||||
|
||||
char * ot_util_get_file_contents_utf8 (const char *path, GError **error);
|
||||
|
||||
gboolean ot_util_gfile_load_contents_utf8 (GFile *file,
|
||||
GCancellable *cancellable,
|
||||
char **contents_out,
|
||||
char **etag_out,
|
||||
GError **error);
|
||||
|
||||
GInputStream *ot_util_read_file_noatime (GFile *file, GCancellable *cancellable, GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,160 @@
|
||||
/* -*- 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 <gio/gio.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "otutil.h"
|
||||
|
||||
#if GLIB_CHECK_VERSION(2,32,0)
|
||||
/* nothing */
|
||||
#else
|
||||
/* Code copied from glib/glib/genviron.c */
|
||||
/* GLIB - Library of useful routines for C programming
|
||||
* Copyright (C) 1995-1998 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the GLib Team and others 1997-2000. See the AUTHORS
|
||||
* file for a list of people on the GLib Team. See the ChangeLog
|
||||
* files for a list of changes. These files are distributed with
|
||||
* GLib at ftp://ftp.gtk.org/pub/gtk/.
|
||||
*/
|
||||
|
||||
static gint
|
||||
ot_g_environ_find (gchar **envp,
|
||||
const gchar *variable)
|
||||
{
|
||||
gint len, i;
|
||||
|
||||
len = strlen (variable);
|
||||
|
||||
for (i = 0; envp[i]; i++)
|
||||
{
|
||||
if (strncmp (envp[i], variable, len) == 0 &&
|
||||
envp[i][len] == '=')
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
ot_g_environ_getenv (gchar **envp,
|
||||
const gchar *variable)
|
||||
{
|
||||
gint index;
|
||||
|
||||
g_return_val_if_fail (envp != NULL, NULL);
|
||||
g_return_val_if_fail (variable != NULL, NULL);
|
||||
|
||||
index = ot_g_environ_find (envp, variable);
|
||||
if (index != -1)
|
||||
return envp[index] + strlen (variable) + 1;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gchar **
|
||||
ot_g_environ_setenv (gchar **envp,
|
||||
const gchar *variable,
|
||||
const gchar *value,
|
||||
gboolean overwrite)
|
||||
{
|
||||
gint index;
|
||||
|
||||
g_return_val_if_fail (envp != NULL, NULL);
|
||||
g_return_val_if_fail (variable != NULL, NULL);
|
||||
g_return_val_if_fail (strchr (variable, '=') == NULL, NULL);
|
||||
|
||||
index = ot_g_environ_find (envp, variable);
|
||||
if (index != -1)
|
||||
{
|
||||
if (overwrite)
|
||||
{
|
||||
g_free (envp[index]);
|
||||
envp[index] = g_strdup_printf ("%s=%s", variable, value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint length;
|
||||
|
||||
length = g_strv_length (envp);
|
||||
envp = g_renew (gchar *, envp, length + 2);
|
||||
envp[length] = g_strdup_printf ("%s=%s", variable, value);
|
||||
envp[length + 1] = NULL;
|
||||
}
|
||||
|
||||
return envp;
|
||||
}
|
||||
|
||||
gchar **
|
||||
ot_g_environ_unsetenv (gchar **envp,
|
||||
const gchar *variable)
|
||||
{
|
||||
gint len;
|
||||
gchar **e, **f;
|
||||
|
||||
g_return_val_if_fail (envp != NULL, NULL);
|
||||
g_return_val_if_fail (variable != NULL, NULL);
|
||||
g_return_val_if_fail (strchr (variable, '=') == NULL, NULL);
|
||||
|
||||
len = strlen (variable);
|
||||
|
||||
/* Note that we remove *all* environment entries for
|
||||
* the variable name, not just the first.
|
||||
*/
|
||||
e = f = envp;
|
||||
while (*e != NULL)
|
||||
{
|
||||
if (strncmp (*e, variable, len) != 0 || (*e)[len] != '=')
|
||||
{
|
||||
*f = *e;
|
||||
f++;
|
||||
}
|
||||
e++;
|
||||
}
|
||||
*f = NULL;
|
||||
|
||||
return envp;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
/* -*- 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>
|
||||
*/
|
||||
|
||||
#ifndef __OSTREE_GLIB_COMPAT_H__
|
||||
#define __OSTREE_GLIB_COMPAT_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#if GLIB_CHECK_VERSION(2,32,0)
|
||||
#define ot_g_environ_getenv g_environ_getenv
|
||||
#define ot_g_environ_setenv g_environ_setenv
|
||||
#define ot_g_environ_unsetenv g_environ_unsetenv
|
||||
#else
|
||||
const gchar *
|
||||
ot_g_environ_getenv (gchar **envp,
|
||||
const gchar *variable);
|
||||
|
||||
gchar **
|
||||
ot_g_environ_setenv (gchar **envp,
|
||||
const gchar *variable,
|
||||
const gchar *value,
|
||||
gboolean overwrite);
|
||||
|
||||
gchar **
|
||||
ot_g_environ_unsetenv (gchar **envp,
|
||||
const gchar *variable);
|
||||
#endif
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
/* -*- 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 <gio/gio.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "otutil.h"
|
||||
|
||||
void
|
||||
ot_util_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);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/* -*- 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>
|
||||
*/
|
||||
|
||||
#ifndef __OSTREE_OPT_UTILS_H__
|
||||
#define __OSTREE_OPT_UTILS_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void ot_util_usage_error (GOptionContext *context, const char *message, GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,273 @@
|
||||
/* -*- 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-unix-utils.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gio/gunixoutputstream.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
|
||||
gboolean
|
||||
ot_util_spawn_pager (GOutputStream **out_stream,
|
||||
GError **error)
|
||||
{
|
||||
const char *pager;
|
||||
char *argv[2];
|
||||
int stdin_fd;
|
||||
pid_t pid;
|
||||
gboolean ret = FALSE;
|
||||
GOutputStream *ret_stream = NULL;
|
||||
|
||||
if (!isatty (1))
|
||||
{
|
||||
ret_stream = (GOutputStream*)g_unix_output_stream_new (1, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
pager = g_getenv ("GIT_PAGER");
|
||||
if (pager == NULL)
|
||||
pager = "less";
|
||||
|
||||
argv[0] = (char*)pager;
|
||||
argv[1] = NULL;
|
||||
|
||||
if (!g_spawn_async_with_pipes (NULL, argv, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
|
||||
NULL, NULL, &pid, &stdin_fd, NULL, NULL, error))
|
||||
{
|
||||
g_prefix_error (error, "%s", "Failed to spawn pager: ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret_stream = (GOutputStream*)g_unix_output_stream_new (stdin_fd, TRUE);
|
||||
}
|
||||
|
||||
*out_stream = ret_stream;
|
||||
ret_stream = NULL;
|
||||
ret = TRUE;
|
||||
out:
|
||||
g_clear_object (&ret_stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
compare_filenames_by_component_length (const char *a,
|
||||
const char *b)
|
||||
{
|
||||
char *a_slash, *b_slash;
|
||||
|
||||
a_slash = strchr (a, '/');
|
||||
b_slash = strchr (b, '/');
|
||||
while (a_slash && b_slash)
|
||||
{
|
||||
a = a_slash + 1;
|
||||
b = b_slash + 1;
|
||||
a_slash = strchr (a, '/');
|
||||
b_slash = strchr (b, '/');
|
||||
}
|
||||
if (a_slash)
|
||||
return -1;
|
||||
else if (b_slash)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
GPtrArray *
|
||||
ot_util_sort_filenames_by_component_length (GPtrArray *files)
|
||||
{
|
||||
GPtrArray *array = g_ptr_array_sized_new (files->len);
|
||||
memcpy (array->pdata, files->pdata, sizeof (gpointer) * files->len);
|
||||
g_ptr_array_sort (array, (GCompareFunc) compare_filenames_by_component_length);
|
||||
return array;
|
||||
}
|
||||
|
||||
int
|
||||
ot_util_count_filename_components (const char *path)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (path)
|
||||
{
|
||||
i++;
|
||||
path = strchr (path, '/');
|
||||
if (path)
|
||||
path++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
gboolean
|
||||
ot_util_filename_has_dotdot (const char *path)
|
||||
{
|
||||
char *p;
|
||||
char last;
|
||||
|
||||
if (strcmp (path, "..") == 0)
|
||||
return TRUE;
|
||||
if (g_str_has_prefix (path, "../"))
|
||||
return TRUE;
|
||||
p = strstr (path, "/..");
|
||||
if (!p)
|
||||
return FALSE;
|
||||
last = *(p + 1);
|
||||
return last == '\0' || last == '/';
|
||||
}
|
||||
|
||||
GPtrArray *
|
||||
ot_util_path_split (const char *path)
|
||||
{
|
||||
GPtrArray *ret = NULL;
|
||||
const char *p;
|
||||
const char *slash;
|
||||
int i;
|
||||
|
||||
g_return_val_if_fail (path[0] != '/', NULL);
|
||||
|
||||
ret = g_ptr_array_new ();
|
||||
g_ptr_array_set_free_func (ret, g_free);
|
||||
|
||||
p = path;
|
||||
do {
|
||||
slash = strchr (p, '/');
|
||||
if (!slash)
|
||||
{
|
||||
g_ptr_array_add (ret, g_strdup (p));
|
||||
p = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_ptr_array_add (ret, g_strndup (p, slash - p));
|
||||
p = slash + 1;
|
||||
}
|
||||
} while (p && *p);
|
||||
|
||||
/* Canonicalize by removing duplicate '.' */
|
||||
for (i = ret->len-1; i >= 0; i--)
|
||||
{
|
||||
if (strcmp (ret->pdata[i], ".") == 0)
|
||||
g_ptr_array_remove_index (ret, i);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *
|
||||
ot_util_path_join_n (const char *base, GPtrArray *components, int n)
|
||||
{
|
||||
int max = MIN(n+1, components->len);
|
||||
GPtrArray *subcomponents;
|
||||
char *path;
|
||||
int i;
|
||||
|
||||
subcomponents = g_ptr_array_new ();
|
||||
|
||||
if (base != NULL)
|
||||
g_ptr_array_add (subcomponents, (char*)base);
|
||||
|
||||
for (i = 0; i < max; i++)
|
||||
{
|
||||
g_ptr_array_add (subcomponents, components->pdata[i]);
|
||||
}
|
||||
g_ptr_array_add (subcomponents, NULL);
|
||||
|
||||
path = g_build_filenamev ((char**)subcomponents->pdata);
|
||||
g_ptr_array_free (subcomponents, TRUE);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
void
|
||||
ot_util_set_error_from_errno (GError **error,
|
||||
gint saved_errno)
|
||||
{
|
||||
g_set_error_literal (error,
|
||||
G_IO_ERROR,
|
||||
0,
|
||||
g_strerror (saved_errno));
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
int
|
||||
ot_util_open_file_read (const char *path, GError **error)
|
||||
{
|
||||
char *dirname = NULL;
|
||||
char *basename = NULL;
|
||||
DIR *dir = NULL;
|
||||
int fd = -1;
|
||||
|
||||
dirname = g_path_get_dirname (path);
|
||||
basename = g_path_get_basename (path);
|
||||
dir = opendir (dirname);
|
||||
if (dir == NULL)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
fd = ot_util_open_file_read_at (dirfd (dir), basename, error);
|
||||
|
||||
out:
|
||||
g_free (basename);
|
||||
g_free (dirname);
|
||||
if (dir != NULL)
|
||||
closedir (dir);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int
|
||||
ot_util_open_file_read_at (int dirfd, const char *name, GError **error)
|
||||
{
|
||||
int fd;
|
||||
int flags = O_RDONLY;
|
||||
|
||||
#ifdef O_CLOEXEC
|
||||
flags |= O_CLOEXEC;
|
||||
#endif
|
||||
#ifdef O_NOATIME
|
||||
flags |= O_NOATIME;
|
||||
#endif
|
||||
fd = openat (dirfd, name, flags);
|
||||
if (fd < 0)
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
return fd;
|
||||
}
|
||||
|
||||
void
|
||||
ot_util_fatal_literal (const char *msg)
|
||||
{
|
||||
g_printerr ("%s\n", msg);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
void
|
||||
ot_util_fatal_gerror (GError *error)
|
||||
{
|
||||
g_assert (error != NULL);
|
||||
ot_util_fatal_literal (error->message);
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/* -*- 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>
|
||||
*/
|
||||
|
||||
#ifndef __OSTREE_UNIX_UTILS_H__
|
||||
#define __OSTREE_UNIX_UTILS_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
/* I just put all this shit here. Sue me. */
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
gboolean ot_util_spawn_pager (GOutputStream **out_stream, GError **error);
|
||||
|
||||
void ot_util_fatal_literal (const char *msg) G_GNUC_NORETURN;
|
||||
|
||||
void ot_util_fatal_gerror (GError *error) G_GNUC_NORETURN;
|
||||
|
||||
gboolean ot_util_filename_has_dotdot (const char *path);
|
||||
|
||||
GPtrArray *ot_util_sort_filenames_by_component_length (GPtrArray *files);
|
||||
|
||||
GPtrArray* ot_util_path_split (const char *path);
|
||||
|
||||
char *ot_util_path_join_n (const char *base, GPtrArray *components, int n);
|
||||
|
||||
int ot_util_count_filename_components (const char *path);
|
||||
|
||||
int ot_util_open_file_read (const char *path, GError **error);
|
||||
|
||||
int ot_util_open_file_read_at (int dirfd, const char *name, GError **error);
|
||||
|
||||
void ot_util_set_error_from_errno (GError **error, gint saved_errno);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,126 @@
|
||||
/* -*- 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 <gio/gio.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "otutil.h"
|
||||
|
||||
GHashTable *
|
||||
ot_util_variant_asv_to_hash_table (GVariant *variant)
|
||||
{
|
||||
GHashTable *ret;
|
||||
GVariantIter *viter;
|
||||
char *key;
|
||||
GVariant *value;
|
||||
|
||||
ret = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref);
|
||||
viter = g_variant_iter_new (variant);
|
||||
while (g_variant_iter_next (viter, "{s@v}", &key, &value))
|
||||
g_hash_table_replace (ret, key, g_variant_ref_sink (value));
|
||||
|
||||
g_variant_iter_free (viter);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
ot_util_variant_save (GFile *dest,
|
||||
GVariant *variant,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GOutputStream *out = NULL;
|
||||
gsize bytes_written;
|
||||
|
||||
out = (GOutputStream*)g_file_replace (dest, NULL, 0, FALSE, cancellable, error);
|
||||
if (!out)
|
||||
goto out;
|
||||
|
||||
if (!g_output_stream_write_all (out,
|
||||
g_variant_get_data (variant),
|
||||
g_variant_get_size (variant),
|
||||
&bytes_written,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
if (!g_output_stream_close (out, cancellable, error))
|
||||
goto out;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
g_clear_object (&out);
|
||||
return ret;
|
||||
}
|
||||
|
||||
GVariant *
|
||||
ot_util_variant_take_ref (GVariant *variant)
|
||||
{
|
||||
#if GLIB_CHECK_VERSION(2,32,0)
|
||||
return g_variant_take_ref (variant);
|
||||
#else
|
||||
if (g_variant_is_floating (variant))
|
||||
return g_variant_ref_sink (variant);
|
||||
return variant;
|
||||
#endif
|
||||
}
|
||||
|
||||
gboolean
|
||||
ot_util_variant_map (GFile *src,
|
||||
const GVariantType *type,
|
||||
GVariant **out_variant,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GMappedFile *mfile = NULL;
|
||||
char *path = NULL;
|
||||
GVariant *ret_variant = NULL;
|
||||
|
||||
path = g_file_get_path (src);
|
||||
mfile = g_mapped_file_new (path, FALSE, error);
|
||||
if (!mfile)
|
||||
goto out;
|
||||
|
||||
ret_variant = g_variant_new_from_data (type,
|
||||
g_mapped_file_get_contents (mfile),
|
||||
g_mapped_file_get_length (mfile),
|
||||
FALSE,
|
||||
(GDestroyNotify) g_mapped_file_unref,
|
||||
mfile);
|
||||
mfile = NULL;
|
||||
g_variant_ref_sink (ret_variant);
|
||||
|
||||
ret = TRUE;
|
||||
*out_variant = ret_variant;
|
||||
ret_variant = NULL;
|
||||
out:
|
||||
if (ret_variant)
|
||||
g_variant_unref (ret_variant);
|
||||
if (mfile)
|
||||
g_mapped_file_unref (mfile);
|
||||
g_free (path);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/* -*- 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>
|
||||
*/
|
||||
|
||||
#ifndef __OSTREE_VARIANT_UTILS_H__
|
||||
#define __OSTREE_VARIANT_UTILS_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GHashTable *ot_util_variant_asv_to_hash_table (GVariant *variant);
|
||||
|
||||
GVariant * ot_util_variant_take_ref (GVariant *variant);
|
||||
|
||||
gboolean ot_util_variant_save (GFile *dest,
|
||||
GVariant *variant,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean ot_util_variant_map (GFile *src,
|
||||
const GVariantType *type,
|
||||
GVariant **out_variant,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
/* -*- 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>
|
||||
*/
|
||||
|
||||
#ifndef __OSTREE_UTIL_H__
|
||||
|
||||
#include <ot-gio-utils.h>
|
||||
#include <ot-glib-compat.h>
|
||||
#include <ot-opt-utils.h>
|
||||
#include <ot-unix-utils.h>
|
||||
#include <ot-variant-utils.h>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,108 @@
|
||||
/* -*- 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 <gio/gio.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "ob-builtins.h"
|
||||
|
||||
static OsbuildBuiltin builtins[] = {
|
||||
{ "buildone", osbuild_builtin_buildone, 0 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static int
|
||||
usage (char **argv, gboolean is_error)
|
||||
{
|
||||
OsbuildBuiltin *builtin = builtins;
|
||||
void (*print_func) (const gchar *format, ...);
|
||||
|
||||
if (is_error)
|
||||
print_func = g_printerr;
|
||||
else
|
||||
print_func = g_print;
|
||||
|
||||
print_func ("usage: %s COMMAND [options]\n",
|
||||
argv[0]);
|
||||
print_func ("Builtin commands:\n");
|
||||
|
||||
while (builtin->name)
|
||||
{
|
||||
print_func (" %s\n", builtin->name);
|
||||
builtin++;
|
||||
}
|
||||
return (is_error ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
OsbuildBuiltin *builtin;
|
||||
const char *cmd;
|
||||
|
||||
g_type_init ();
|
||||
|
||||
g_set_prgname (argv[0]);
|
||||
|
||||
builtin = builtins;
|
||||
|
||||
if (argc < 2)
|
||||
return usage (argv, 1);
|
||||
|
||||
cmd = argv[1];
|
||||
|
||||
while (builtin->name)
|
||||
{
|
||||
GError *error = NULL;
|
||||
if (strcmp (cmd, builtin->name) == 0)
|
||||
{
|
||||
int i;
|
||||
int tmp_argc;
|
||||
char **tmp_argv;
|
||||
|
||||
tmp_argc = argc - 1;
|
||||
tmp_argv = g_new0 (char *, tmp_argc + 1);
|
||||
|
||||
tmp_argv[0] = (char*)builtin->name;
|
||||
for (i = 0; i < tmp_argc; i++)
|
||||
tmp_argv[i+1] = argv[i+2];
|
||||
if (!builtin->fn (tmp_argc, tmp_argv, NULL, &error))
|
||||
{
|
||||
g_free (tmp_argv);
|
||||
g_printerr ("%s\n", error->message);
|
||||
g_clear_error (&error);
|
||||
return 1;
|
||||
}
|
||||
g_free (tmp_argv);
|
||||
return 0;
|
||||
}
|
||||
builtin++;
|
||||
}
|
||||
|
||||
g_printerr ("Unknown command '%s'\n", cmd);
|
||||
return usage (argv, 1);
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/* -*- 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 "otutil.h"
|
||||
#include "ob-builtins.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static char *repo_path;
|
||||
static char *ref;
|
||||
static char *name;
|
||||
static char *generator;
|
||||
static char *resultdir;
|
||||
static gboolean raw;
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{ "repo", 0, 0, G_OPTION_ARG_FILENAME, &repo_path, "Repository path", "repo" },
|
||||
{ "rev", 'r', 0, G_OPTION_ARG_STRING, &ref, "Build using this tree", "rev" },
|
||||
{ "name", 0, 0, G_OPTION_ARG_STRING, &name, "Name of the source", "source" },
|
||||
{ "generator", 0, 0, G_OPTION_ARG_FILENAME, &generator, "Script to run on installed tree", "script" },
|
||||
{ "raw", 0, 0, G_OPTION_ARG_NONE, &raw, "Do not instantiate a tree, use current", NULL },
|
||||
{ "resultdir", 0, 0, G_OPTION_ARG_FILENAME, &resultdir, "Directory for output artifacts", "dir" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static char *
|
||||
get_tmpdir (void) G_GNUC_UNUSED;
|
||||
|
||||
static char *
|
||||
get_tmpdir (void)
|
||||
{
|
||||
char *tmp_prefix = g_strdup (g_getenv ("XDG_RUNTIME_DIR"));
|
||||
char *ret;
|
||||
|
||||
if (tmp_prefix)
|
||||
{
|
||||
ret = g_strdup_printf ("%s/osbuild", tmp_prefix);
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp_prefix = g_strdup_printf ("/tmp/osbuild-%d", getuid ());
|
||||
if (!g_file_test (tmp_prefix, G_FILE_TEST_IS_DIR))
|
||||
{
|
||||
if (!mkdir (tmp_prefix, 0755))
|
||||
{
|
||||
g_printerr ("Failed to make logging directory %s\n", tmp_prefix);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
ret = tmp_prefix;
|
||||
tmp_prefix = NULL;
|
||||
}
|
||||
g_free (tmp_prefix);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
open_log (const char *name,
|
||||
GOutputStream **out_log,
|
||||
GError **error) G_GNUC_UNUSED;
|
||||
|
||||
static gboolean
|
||||
open_log (const char *name,
|
||||
GOutputStream **out_log,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
char *tmpdir = NULL;
|
||||
char *path = NULL;
|
||||
GFile *logf = NULL;
|
||||
GFileOutputStream *ret_log = NULL;
|
||||
|
||||
path = g_strdup_printf ("%s/%s.log", tmpdir, name);
|
||||
logf = ot_util_new_file_for_path (path);
|
||||
|
||||
ret_log = g_file_replace (logf, NULL, FALSE, 0, NULL, error);
|
||||
if (!ret_log)
|
||||
goto out;
|
||||
|
||||
ret = TRUE;
|
||||
*out_log = (GOutputStream*)ret_log;
|
||||
ret_log = NULL;
|
||||
out:
|
||||
g_free (path);
|
||||
g_free (tmpdir);
|
||||
g_clear_object (&logf);
|
||||
g_clear_object (&ret_log);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
osbuild_builtin_buildone (int argc, char **argv, const char *prefix, GError **error)
|
||||
{
|
||||
GOptionContext *context;
|
||||
gboolean ret = FALSE;
|
||||
|
||||
context = g_option_context_new ("- Build current directory");
|
||||
g_option_context_add_main_entries (context, options, NULL);
|
||||
|
||||
if (!g_option_context_parse (context, &argc, &argv, error))
|
||||
goto out;
|
||||
|
||||
if (!raw && !repo_path)
|
||||
{
|
||||
ot_util_usage_error (context, "A result directory must be specified with --resultdir", error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!generator)
|
||||
generator = g_build_filename (LIBEXECDIR, "ostree", "generators", "default", NULL);
|
||||
|
||||
|
||||
|
||||
out:
|
||||
if (context)
|
||||
g_option_context_free (context);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/* -*- 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>
|
||||
*/
|
||||
|
||||
#ifndef __OSBUILD_BUILTINS__
|
||||
#define __OSBUILD_BUILTINS__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
OSBUILD_BUILTIN_FLAG_NONE = 0,
|
||||
} OsbuildBuiltinFlags;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
gboolean (*fn) (int argc, char **argv, const char *prefix, GError **error);
|
||||
int flags; /* OsbuildBuiltinFlags */
|
||||
} OsbuildBuiltin;
|
||||
|
||||
gboolean osbuild_builtin_buildone (int argc, char **argv, const char *prefix, GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,188 @@
|
||||
/* -*- 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 <gio/gio.h>
|
||||
|
||||
#include "otutil.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static const char *
|
||||
find_first_file (GFileTest test, const char *name, ...) G_GNUC_NULL_TERMINATED;
|
||||
|
||||
static const char *
|
||||
find_first_file (GFileTest test, const char *name, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start (args, name);
|
||||
|
||||
do
|
||||
{
|
||||
if (g_file_test (name, test))
|
||||
break;
|
||||
name = va_arg (args, const char *);
|
||||
}
|
||||
while (name != NULL);
|
||||
|
||||
va_end (args);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static void
|
||||
split_configure_make_args (int argc,
|
||||
char **argv,
|
||||
GPtrArray **out_configure_args,
|
||||
GPtrArray **out_make_args,
|
||||
GPtrArray **out_makeinstall_args)
|
||||
{
|
||||
int i;
|
||||
|
||||
*out_configure_args = g_ptr_array_new ();
|
||||
*out_make_args = g_ptr_array_new ();
|
||||
*out_makeinstall_args = g_ptr_array_new ();
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (g_str_has_prefix (argv[i], "--"))
|
||||
g_ptr_array_add (*out_configure_args, argv[i]);
|
||||
else if (g_str_has_prefix (argv[i], "DESTDIR="))
|
||||
g_ptr_array_add (*out_makeinstall_args, argv[i]);
|
||||
else
|
||||
g_ptr_array_add (*out_make_args, argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
spawn_sync_or_fatal (char **args, char **env, GSpawnFlags flags)
|
||||
{
|
||||
GError *error = NULL;
|
||||
int estatus;
|
||||
char **iter;
|
||||
|
||||
g_print ("osbuild: running: ");
|
||||
for (iter = args; *iter; iter++)
|
||||
g_print ("%s ", *iter);
|
||||
g_print ("\n");
|
||||
if (g_spawn_sync (NULL, args, env, flags, NULL, NULL, NULL, NULL, &estatus, &error))
|
||||
{
|
||||
if (WIFEXITED (estatus) && WEXITSTATUS (estatus) == 0)
|
||||
{
|
||||
g_message ("Subprocess %s exited successfully\n", args[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (WIFEXITED (estatus))
|
||||
g_error ("Subprocess %s exited with code %d\n", args[0], WEXITSTATUS (estatus));
|
||||
else if (WIFSIGNALED (estatus))
|
||||
g_error ("Subprocess %s killed by signal %d\n", args[0], WTERMSIG (estatus));
|
||||
else
|
||||
g_error ("Subprocess %s terminated with status %d\n", args[0], estatus);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_error ("Failed to execute %s: %s\n", args[0], error->message);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ptr_array_extend (GPtrArray *dest, GPtrArray *to_append)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < to_append->len; i++)
|
||||
g_ptr_array_add (dest, to_append->pdata[i]);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
GPtrArray *config_args;
|
||||
GPtrArray *make_args;
|
||||
GPtrArray *makeinstall_args;
|
||||
GPtrArray *args;
|
||||
char **subprocess_env;
|
||||
|
||||
g_type_init ();
|
||||
|
||||
g_set_prgname (argv[0]);
|
||||
|
||||
args = g_ptr_array_new ();
|
||||
|
||||
subprocess_env = g_get_environ ();
|
||||
ot_g_environ_setenv (subprocess_env, "LANG", "C", TRUE);
|
||||
ot_g_environ_unsetenv (subprocess_env, "LC_ALL");
|
||||
|
||||
split_configure_make_args (argc, argv, &config_args, &make_args, &makeinstall_args);
|
||||
|
||||
if (!g_file_test ("./configure", G_FILE_TEST_IS_EXECUTABLE))
|
||||
{
|
||||
const char *autogen;
|
||||
char **autogen_env;
|
||||
|
||||
autogen = find_first_file (G_FILE_TEST_IS_EXECUTABLE, "./autogen", "./autogen.sh", NULL);
|
||||
if (!autogen)
|
||||
ot_util_fatal_literal ("No executable configure or autogen script found");
|
||||
|
||||
autogen_env = g_strdupv (subprocess_env);
|
||||
ot_g_environ_setenv (autogen_env, "NOCONFIGURE", "1", TRUE);
|
||||
|
||||
g_ptr_array_set_size (args, 0);
|
||||
g_ptr_array_add (args, (char*) autogen);
|
||||
g_ptr_array_add (args, NULL);
|
||||
spawn_sync_or_fatal ((char**)args->pdata, autogen_env, 0);
|
||||
}
|
||||
|
||||
if (!g_file_test ("./configure", G_FILE_TEST_IS_EXECUTABLE))
|
||||
ot_util_fatal_literal ("autogen script failed to generate a configure script");
|
||||
|
||||
g_ptr_array_set_size (args, 0);
|
||||
g_ptr_array_add (args, "./configure");
|
||||
ptr_array_extend (args, config_args);
|
||||
g_ptr_array_add (args, NULL);
|
||||
spawn_sync_or_fatal ((char**)args->pdata, subprocess_env, 0);
|
||||
|
||||
g_ptr_array_set_size (args, 0);
|
||||
g_ptr_array_add (args, "make");
|
||||
ptr_array_extend (args, make_args);
|
||||
g_ptr_array_add (args, NULL);
|
||||
spawn_sync_or_fatal ((char**)args->pdata, subprocess_env, G_SPAWN_SEARCH_PATH);
|
||||
|
||||
g_ptr_array_set_size (args, 0);
|
||||
g_ptr_array_add (args, "make");
|
||||
g_ptr_array_add (args, "install");
|
||||
ptr_array_extend (args, makeinstall_args);
|
||||
g_ptr_array_add (args, NULL);
|
||||
spawn_sync_or_fatal ((char**)args->pdata, subprocess_env, G_SPAWN_SEARCH_PATH);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,304 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# ostree-buildone:
|
||||
# Copyright 2010, 2011 Colin Walters <walters@verbum.org>
|
||||
# Licensed under the new-BSD license (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
# The build output is automatically logged to $TMPDIR/build-$(PWD).log.
|
||||
# For example, invoking metabuild in a directory named "foo" will log
|
||||
# to /tmp/build-foo.log
|
||||
#
|
||||
# You can pass arguments to metabuild; if they start with '--', they're
|
||||
# given to configure. Otherwise, they're passed to make.
|
||||
#
|
||||
# $ metabuild --enable-libfoo # passed to configure
|
||||
# $ metabuild -j 1 # passed to make
|
||||
|
||||
import os,sys,subprocess,tempfile,re
|
||||
import select,time,stat,fcntl
|
||||
|
||||
subprocess_nice_args = []
|
||||
|
||||
# In the future we should test for this better; possibly implement a
|
||||
# custom fork handler
|
||||
try:
|
||||
chrt_args = ['chrt', '--idle', '0']
|
||||
proc = subprocess.Popen(chrt_args + ['true'])
|
||||
if proc.wait() == 0:
|
||||
subprocess_nice_args.extend(chrt_args)
|
||||
except OSError, e:
|
||||
pass
|
||||
|
||||
try:
|
||||
ionice_args = ['ionice', '-c', '3', '-t']
|
||||
proc = subprocess.Popen(ionice_args + ['true'])
|
||||
if proc.wait() == 0:
|
||||
subprocess_nice_args.extend(ionice_args)
|
||||
except OSError, e:
|
||||
pass
|
||||
|
||||
warning_re = re.compile(r'(: ((warning)|(error)|(fatal error)): )|(make(\[[0-9]+\])?: \*\*\*)')
|
||||
output_whitelist_re = re.compile(r'^(make(\[[0-9]+\])?: Entering directory)|(ostree-build )')
|
||||
|
||||
_bold_sequence = None
|
||||
_normal_sequence = None
|
||||
if os.isatty(1):
|
||||
_bold_sequence = subprocess.Popen(['tput', 'bold'], stdout=subprocess.PIPE, stderr=open('/dev/null', 'w')).communicate()[0]
|
||||
_normal_sequence = subprocess.Popen(['tput', 'sgr0'], stdout=subprocess.PIPE, stderr=open('/dev/null', 'w')).communicate()[0]
|
||||
def _bold(text):
|
||||
if _bold_sequence is not None:
|
||||
return '%s%s%s' % (_bold_sequence, text, _normal_sequence)
|
||||
else:
|
||||
return text
|
||||
|
||||
class Mainloop(object):
|
||||
DEFAULT = None
|
||||
def __init__(self):
|
||||
self._running = True
|
||||
self.poll = select.poll()
|
||||
self._timeouts = []
|
||||
self._pid_watches = {}
|
||||
self._fd_callbacks = {}
|
||||
|
||||
@classmethod
|
||||
def get(cls, context):
|
||||
if context is None:
|
||||
if cls.DEFAULT is None:
|
||||
cls.DEFAULT = cls()
|
||||
return cls.DEFAULT
|
||||
raise NotImplementedError("Unknown context %r" % (context, ))
|
||||
|
||||
def watch_fd(self, fd, callback):
|
||||
self.poll.register(fd)
|
||||
self._fd_callbacks[fd] = callback
|
||||
|
||||
def unwatch_fd(self, fd):
|
||||
self.poll.unregister(fd)
|
||||
del self._fd_callbacks[fd]
|
||||
|
||||
def watch_pid(self, pid, callback):
|
||||
self._pid_watches[pid] = callback
|
||||
|
||||
def timeout_add(self, ms, callback):
|
||||
self._timeouts.append((ms, callback))
|
||||
|
||||
def quit(self):
|
||||
self._running = False
|
||||
|
||||
def run_once(self):
|
||||
min_timeout = None
|
||||
if len(self._pid_watches) > 0:
|
||||
min_timeout = 500
|
||||
for (ms, callback) in self._timeouts:
|
||||
if (min_timeout is None) or (ms < min_timeout):
|
||||
min_timeout = ms
|
||||
origtime = time.time() * 1000
|
||||
fds = self.poll.poll(min_timeout)
|
||||
for fd in fds:
|
||||
self._fd_callbacks[fd]()
|
||||
for pid in self._pid_watches:
|
||||
(opid, status) = os.waitpid(pid, os.WNOHANG)
|
||||
if opid != 0:
|
||||
self._pid_watches[pid](opid, status)
|
||||
del self._pid_watches[pid]
|
||||
newtime = time.time() * 1000
|
||||
diff = int(newtime - origtime)
|
||||
if diff < 0: diff = 0
|
||||
for i,(ms, callback) in enumerate(self._timeouts):
|
||||
remaining_ms = ms - diff
|
||||
if remaining_ms <= 0:
|
||||
callback()
|
||||
else:
|
||||
self._timeouts[i] = (remaining_ms, callback)
|
||||
|
||||
def run(self):
|
||||
while self._running:
|
||||
self.run_once()
|
||||
|
||||
class FileMonitor(object):
|
||||
def __init__(self):
|
||||
self._paths = {}
|
||||
self._path_modtimes = {}
|
||||
self._timeout = 1000
|
||||
self._timeout_installed = False
|
||||
self._loop = Mainloop.get(None)
|
||||
|
||||
def _stat(self, path):
|
||||
try:
|
||||
st = os.stat(path)
|
||||
return st[stat.ST_MTIME]
|
||||
except OSError, e:
|
||||
return None
|
||||
|
||||
def add(self, path, callback):
|
||||
if path not in self._paths:
|
||||
self._paths[path] = []
|
||||
self._path_modtimes[path] = self._stat(path)
|
||||
self._paths[path].append(callback)
|
||||
if not self._timeout_installed:
|
||||
self._timeout_installed = True
|
||||
self._loop.timeout_add(self._timeout, self._check_files)
|
||||
|
||||
def _check_files(self):
|
||||
for (path,callbacks) in self._paths.iteritems():
|
||||
mtime = self._stat(path)
|
||||
orig_mtime = self._path_modtimes[path]
|
||||
if (mtime is not None) and (orig_mtime is None or (mtime > orig_mtime)):
|
||||
self._path_modtimes[path] = mtime
|
||||
for cb in callbacks:
|
||||
cb()
|
||||
|
||||
_filemon = FileMonitor()
|
||||
|
||||
class OutputFilter(object):
|
||||
def __init__(self, filename, output):
|
||||
self.filename = filename
|
||||
self.output = output
|
||||
|
||||
# inherit globals
|
||||
self._warning_re = warning_re
|
||||
self._nonfilter_re = output_whitelist_re
|
||||
|
||||
self._buf = ''
|
||||
self._warning_count = 0
|
||||
self._filtered_line_count = 0
|
||||
_filemon.add(filename, self._on_changed)
|
||||
self._fd = os.open(filename, os.O_RDONLY)
|
||||
fcntl.fcntl(self._fd, fcntl.F_SETFL, os.O_NONBLOCK)
|
||||
|
||||
def _do_read(self):
|
||||
while True:
|
||||
buf = os.read(self._fd, 4096)
|
||||
if buf == '':
|
||||
break
|
||||
self._buf += buf
|
||||
self._flush()
|
||||
|
||||
def _write_last_log_lines(self):
|
||||
_last_line_limit = 100
|
||||
f = open(logfile_path)
|
||||
lines = []
|
||||
for line in f:
|
||||
if line.startswith('ostree-build '):
|
||||
continue
|
||||
lines.append(line)
|
||||
if len(lines) > _last_line_limit:
|
||||
lines.pop(0)
|
||||
f.close()
|
||||
for line in lines:
|
||||
self.output.write('| ')
|
||||
self.output.write(line)
|
||||
|
||||
def _flush(self):
|
||||
while True:
|
||||
p = self._buf.find('\n')
|
||||
if p < 0:
|
||||
break
|
||||
line = self._buf[0:p]
|
||||
self._buf = self._buf[p+1:]
|
||||
match = self._warning_re.search(line)
|
||||
if match:
|
||||
self._warning_count += 1
|
||||
self.output.write(line + '\n')
|
||||
else:
|
||||
match = self._nonfilter_re.search(line)
|
||||
if match:
|
||||
self.output.write(line + '\n')
|
||||
else:
|
||||
self._filtered_line_count += 1
|
||||
|
||||
def _on_changed(self):
|
||||
self._do_read()
|
||||
|
||||
def start(self):
|
||||
self._do_read()
|
||||
|
||||
def finish(self, successful):
|
||||
self._do_read()
|
||||
if not successful:
|
||||
self._write_last_log_lines()
|
||||
pass
|
||||
self.output.write("ostree-build %s: %d warnings\n" % ('success' if successful else _bold('failed'),
|
||||
self._warning_count, ))
|
||||
self.output.write("ostree-build: full log path: %s\n" % (logfile_path, ))
|
||||
|
||||
if successful:
|
||||
for f in os.listdir('_build'):
|
||||
path = os.path.join('_build', f)
|
||||
if f.startswith('artifact-'):
|
||||
self.output.write("ostree-build: created artifact: %s\n" % (f, ))
|
||||
sys.exit(0 if successful else 1)
|
||||
|
||||
def _on_makeinstall_exit(pid, estatus):
|
||||
_output_filter.finish(estatus == 0)
|
||||
|
||||
def _on_make_exit(pid, estatus):
|
||||
if estatus == 0:
|
||||
args = list(subprocess_nice_args)
|
||||
args.append('ostree-buildone-makeinstall-split-artifacts')
|
||||
_logfile_f.write("Running: %r\n" % (args, ))
|
||||
_logfile_f.flush()
|
||||
proc = subprocess.Popen(args, stdin=devnull, stdout=logfile_write_fd, stderr=logfile_write_fd)
|
||||
_loop.watch_pid(proc.pid, _on_makeinstall_exit)
|
||||
else:
|
||||
_output_filter.finish(False)
|
||||
|
||||
def _get_version():
|
||||
if not os.path.isdir('.git'):
|
||||
sys.stderr.write("ostree-buildone: error: Couldn't find .git directory")
|
||||
sys.exit(1)
|
||||
|
||||
proc = subprocess.Popen(['git', 'describe'], stdout=subprocess.PIPE)
|
||||
output = proc.communicate()[0].strip()
|
||||
if proc.wait() != 0:
|
||||
proc = subprocess.Popen(['git', 'rev-parse', 'HEAD'], stdout=subprocess.PIPE)
|
||||
if proc.wait() != 0:
|
||||
sys.stderr.write("ostree-buildone: error: git rev-parse HEAD failed")
|
||||
sys.exit(1)
|
||||
output = proc.communicate()[0].strip()
|
||||
return output
|
||||
|
||||
if __name__ == '__main__':
|
||||
user_tmpdir = os.environ.get('XDG_RUNTIME_DIR')
|
||||
if user_tmpdir is None:
|
||||
user_tmpdir = os.path.join(os.environ.get('TMPDIR', '/tmp'), 'metabuild-%s' % (os.getuid(), ))
|
||||
else:
|
||||
user_tmpdir = os.path.join(user_tmpdir, 'ostree-build')
|
||||
|
||||
os.environ['OSBUILD_VERSION'] = _get_version()
|
||||
|
||||
if os.path.isdir('_build'):
|
||||
for filename in os.listdir('_build'):
|
||||
path = os.path.join('_build', filename)
|
||||
if filename.startswith('artifact-'):
|
||||
os.unlink(path)
|
||||
|
||||
if not os.path.isdir(user_tmpdir):
|
||||
os.makedirs(user_tmpdir)
|
||||
logfile_path = os.path.join(user_tmpdir, '%s.log' % (os.path.basename(os.getcwd()), ))
|
||||
try:
|
||||
os.unlink(logfile_path)
|
||||
except OSError, e:
|
||||
pass
|
||||
logfile_write_fd = os.open(logfile_path, os.O_WRONLY | os.O_CREAT | os.O_EXCL)
|
||||
global _logfile_f
|
||||
_logfile_f = os.fdopen(logfile_write_fd, "w")
|
||||
sys.stdout.write('ostree-build: logging to %r\n' % (logfile_path, ))
|
||||
sys.stdout.flush()
|
||||
|
||||
global _output_filter
|
||||
_output_filter = OutputFilter(logfile_path, sys.stdout)
|
||||
_output_filter.start()
|
||||
|
||||
args = list(subprocess_nice_args)
|
||||
args.append('ostree-buildone-make')
|
||||
args.extend(sys.argv[1:])
|
||||
devnull=open('/dev/null')
|
||||
_logfile_f.write("Running: %r\n" % (args, ))
|
||||
_logfile_f.flush()
|
||||
proc = subprocess.Popen(args, stdin=devnull, stdout=logfile_write_fd, stderr=logfile_write_fd)
|
||||
|
||||
global _loop
|
||||
_loop = Mainloop.get(None)
|
||||
_loop.watch_pid(proc.pid, _on_make_exit)
|
||||
_loop.run()
|
||||
@@ -0,0 +1,205 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# ostree-buildone-raw: Generic build system wrapper
|
||||
# Copyright 2010, 2011 Colin Walters <walters@verbum.org>
|
||||
# Licensed under the new-BSD license (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
# ostree-buildone-raw wraps systems that implement the GNOME build API:
|
||||
# http://people.gnome.org/~walters/docs/build-api.txt
|
||||
|
||||
import os,sys,subprocess,tempfile,re
|
||||
from multiprocessing import cpu_count
|
||||
import select,time
|
||||
|
||||
root = None
|
||||
|
||||
prefix = '/usr'
|
||||
|
||||
# libdir detection
|
||||
if os.path.isdir('/lib64'):
|
||||
libdir=os.path.join(prefix, 'lib64')
|
||||
else:
|
||||
libdir=os.path.join(prefix, 'lib')
|
||||
|
||||
default_buildapi_jobs = ['-j', '%d' % (cpu_count() * 2, )]
|
||||
configargs = ['--prefix=' + prefix,
|
||||
'--libdir=' + libdir,
|
||||
'--sysconfdir=/etc',
|
||||
'--localstatedir=/var',
|
||||
'--bindir=' + os.path.join(prefix, 'bin'),
|
||||
'--sbindir=' + os.path.join(prefix, 'sbin'),
|
||||
'--datadir=' + os.path.join(prefix, 'share'),
|
||||
'--includedir=' + os.path.join(prefix, 'include'),
|
||||
'--libexecdir=' + os.path.join(prefix, 'libexec'),
|
||||
'--mandir=' + os.path.join(prefix, 'share', 'man'),
|
||||
'--infodir=' + os.path.join(prefix, 'share', 'info')]
|
||||
makeargs = ['make']
|
||||
|
||||
top_srcdir=os.getcwd()
|
||||
|
||||
for arg in sys.argv[1:]:
|
||||
if arg.startswith('--'):
|
||||
configargs.append(arg)
|
||||
else:
|
||||
makeargs.append(arg)
|
||||
|
||||
def log(msg):
|
||||
fullmsg = 'ostree-buildone: ' + msg + '\n'
|
||||
sys.stdout.write(fullmsg)
|
||||
sys.stdout.flush()
|
||||
|
||||
def fatal(msg):
|
||||
log(msg)
|
||||
sys.exit(1)
|
||||
|
||||
def run_sync(args, env=None):
|
||||
log("Running: %r" % (args, ))
|
||||
f = open('/dev/null', 'r')
|
||||
proc = subprocess.Popen(args, stdin=f, stdout=sys.stdout, stderr=sys.stderr,
|
||||
close_fds=True, env=env)
|
||||
f.close()
|
||||
returncode = proc.wait()
|
||||
log("pid %d exited with code %d" % (proc.pid, returncode))
|
||||
if returncode != 0:
|
||||
sys.exit(1)
|
||||
|
||||
class BuildSystemScanner(object):
|
||||
@classmethod
|
||||
def _find_file(cls, names):
|
||||
for name in names:
|
||||
if os.path.exists(name):
|
||||
return name
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def get_configure_source_script(cls):
|
||||
return cls._find_file(('./configure.ac', './configure.in'))
|
||||
|
||||
@classmethod
|
||||
def get_configure_script(cls):
|
||||
return cls._find_file(('./configure', ))
|
||||
|
||||
@classmethod
|
||||
def get_bootstrap_script(cls):
|
||||
return cls._find_file(('./autogen.sh', ))
|
||||
|
||||
@classmethod
|
||||
def get_silent_rules(cls):
|
||||
src = cls.get_configure_source_script()
|
||||
if not src:
|
||||
return False
|
||||
f = open(src)
|
||||
for line in f:
|
||||
if line.find('AM_SILENT_RULES') >= 0:
|
||||
f.close()
|
||||
return True
|
||||
f.close()
|
||||
return False
|
||||
|
||||
def _search_file(filename, pattern):
|
||||
f = open(filename)
|
||||
for line in f:
|
||||
if line.startswith(pattern):
|
||||
f.close()
|
||||
return line
|
||||
f.close()
|
||||
return None
|
||||
|
||||
def _find_buildapi_makevariable(name):
|
||||
var = '.%s:' % (name, )
|
||||
line = None
|
||||
if os.path.exists('Makefile.in'):
|
||||
line = _search_file('Makefile.in', var)
|
||||
if not line and os.path.exists('Makefile'):
|
||||
line = _search_file('Makefile', var)
|
||||
return line is not None
|
||||
|
||||
def phase_bootstrap():
|
||||
have_configure = BuildSystemScanner.get_configure_script()
|
||||
have_configure_source = BuildSystemScanner.get_configure_source_script()
|
||||
if not (have_configure or have_configure_source):
|
||||
fatal("No configure or bootstrap script detected; unknown buildsystem")
|
||||
return
|
||||
|
||||
need_v1 = BuildSystemScanner.get_silent_rules()
|
||||
if need_v1:
|
||||
log("Detected AM_SILENT_RULES, adding --disable-silent-rules to configure")
|
||||
configargs.append('--disable-silent-rules')
|
||||
|
||||
if have_configure:
|
||||
phase_configure()
|
||||
else:
|
||||
bootstrap = BuildSystemScanner.get_bootstrap_script()
|
||||
if bootstrap:
|
||||
log("Detected bootstrap script: %s, using it" % (bootstrap, ))
|
||||
args = [bootstrap]
|
||||
args.extend(configargs)
|
||||
# Add NOCONFIGURE; GNOME style scripts use this
|
||||
env = dict(os.environ)
|
||||
env['NOCONFIGURE'] = '1'
|
||||
run_sync(args, env=env)
|
||||
else:
|
||||
log("No bootstrap script found; using generic autoreconf")
|
||||
run_sync(['autoreconf', '-f', '-i'])
|
||||
phase_configure()
|
||||
|
||||
def phase_configure():
|
||||
use_builddir = True
|
||||
doesnot_support_builddir = _find_buildapi_makevariable('buildapi-no-builddir')
|
||||
if doesnot_support_builddir:
|
||||
log("Found .buildapi-no-builddir; copying source tree to _build")
|
||||
shutil.rmtree('_build')
|
||||
os.mkdir('_build')
|
||||
shutil.copytree('.', '_build', symlinks=True,
|
||||
ignore=shutil.ignore_patterns('_build'))
|
||||
use_builddir = False
|
||||
builddir = '.'
|
||||
else:
|
||||
builddir = '_build'
|
||||
|
||||
if not use_builddir:
|
||||
configdir = './'
|
||||
else:
|
||||
configdir = os.getcwd()
|
||||
builddir = builddir
|
||||
log("Using build directory %r" % (builddir, ))
|
||||
if not os.path.isdir(builddir):
|
||||
os.mkdir(builddir)
|
||||
os.chdir(builddir)
|
||||
|
||||
configstatus = 'config.status'
|
||||
if not os.path.exists(configstatus):
|
||||
args = [os.path.join(configdir, 'configure')]
|
||||
args.extend(configargs)
|
||||
run_sync(args)
|
||||
else:
|
||||
log("Found %s, skipping configure" % (configstatus, ))
|
||||
phase_build()
|
||||
|
||||
build_status = False
|
||||
|
||||
def phase_build():
|
||||
if not os.path.exists('Makefile'):
|
||||
log("No Makefile found")
|
||||
sys.exit(1)
|
||||
args = makeargs
|
||||
user_specified_jobs = False
|
||||
for arg in args:
|
||||
if arg == '-j':
|
||||
user_specified_jobs = True
|
||||
|
||||
if not user_specified_jobs:
|
||||
notparallel = _find_buildapi_makevariable('NOTPARALLEL')
|
||||
if not notparallel:
|
||||
log("Didn't find NOTPARALLEL, using parallel make by default")
|
||||
args.extend(default_buildapi_jobs)
|
||||
|
||||
run_sync(args)
|
||||
|
||||
def phase_complete():
|
||||
sys.exit(0)
|
||||
|
||||
log("invocation arguments: %r" % (sys.argv, ))
|
||||
|
||||
# Start off the process
|
||||
phase_bootstrap()
|
||||
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# ostree-buildone-raw: Generic build system wrapper
|
||||
# Copyright 2010, 2011 Colin Walters <walters@verbum.org>
|
||||
# Licensed under the new-BSD license (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
import os,sys,re,subprocess
|
||||
import tempfile,shutil
|
||||
|
||||
_devel_regexps = map(re.compile,
|
||||
[r'/usr/include/',
|
||||
r'/usr/share/pkgconfig/',
|
||||
r'/.*lib(?:|(?:32)|(?:64))/pkgconfig/.*\.pc',
|
||||
r'/.*lib(?:|(?:32)|(?:64))/.*\.so$'])
|
||||
|
||||
def log(msg):
|
||||
fullmsg = 'ostree-buildone: ' + msg + '\n'
|
||||
sys.stdout.write(fullmsg)
|
||||
sys.stdout.flush()
|
||||
|
||||
tempfiles = []
|
||||
|
||||
def do_exit(code):
|
||||
for tmpname in tempfiles:
|
||||
if os.path.isdir(tmpname):
|
||||
shutil.rmtree(tmpname)
|
||||
else:
|
||||
try:
|
||||
os.unlink(tmpname)
|
||||
pass
|
||||
except OSError, e:
|
||||
pass
|
||||
sys.exit(code)
|
||||
|
||||
def fatal(msg):
|
||||
log(msg)
|
||||
do_exit(1)
|
||||
|
||||
def run_sync(args, env=None):
|
||||
log("Running: %r" % (args, ))
|
||||
f = open('/dev/null', 'r')
|
||||
proc = subprocess.Popen(args, stdin=f, stdout=sys.stdout, stderr=sys.stderr,
|
||||
close_fds=True, env=env)
|
||||
f.close()
|
||||
returncode = proc.wait()
|
||||
if returncode == 0:
|
||||
func = log
|
||||
else:
|
||||
func = fatal
|
||||
func("pid %d exited with code %d" % (proc.pid, returncode))
|
||||
|
||||
basename=os.path.basename(os.getcwd())
|
||||
artifact_prefix='artifact-%s,%s' % (basename, os.environ['OSBUILD_VERSION'])
|
||||
origdir=os.getcwd()
|
||||
os.chdir('_build')
|
||||
|
||||
if not os.path.exists('Makefile'):
|
||||
log("No Makefile found")
|
||||
do_exit(1)
|
||||
|
||||
(fd,fakeroot_temp)=tempfile.mkstemp(prefix='ostree-fakeroot-%s-' % (basename,))
|
||||
os.close(fd)
|
||||
tempfiles.append(fakeroot_temp)
|
||||
tempdir = tempfile.mkdtemp(prefix='ostree-build-%s-' % (basename,))
|
||||
tempfiles.append(tempdir)
|
||||
args = ['fakeroot', '-s', fakeroot_temp, 'make', 'install', 'DESTDIR=' + tempdir]
|
||||
run_sync(args)
|
||||
|
||||
devel_files = set()
|
||||
runtime_files = set()
|
||||
|
||||
oldpwd=os.getcwd()
|
||||
os.chdir(tempdir)
|
||||
for root, dirs, files in os.walk('.'):
|
||||
for filename in files:
|
||||
path = os.path.join(root, filename)
|
||||
matched = False
|
||||
for r in _devel_regexps:
|
||||
if r.match(path[1:]):
|
||||
devel_files.add(path)
|
||||
matched = True
|
||||
break
|
||||
if not matched:
|
||||
runtime_files.add(path)
|
||||
os.chdir(oldpwd)
|
||||
|
||||
def make_artifact(name, from_files):
|
||||
artifact_target = '%s-%s.tar.gz' % (artifact_prefix, name)
|
||||
(fd,filelist_temp)=tempfile.mkstemp(prefix='ostree-filelist-%s-%s' % (basename, name))
|
||||
os.close(fd)
|
||||
tempfiles.append(filelist_temp)
|
||||
f = open(filelist_temp, 'w')
|
||||
for filename in from_files:
|
||||
f.write(filename)
|
||||
f.write('\n')
|
||||
f.close()
|
||||
args = ['fakeroot', '-i', fakeroot_temp, 'tar', '-c', '-z', '-C', tempdir, '-f', artifact_target, '-T', filelist_temp]
|
||||
run_sync(args)
|
||||
|
||||
if devel_files:
|
||||
make_artifact('devel', devel_files)
|
||||
make_artifact('runtime', runtime_files)
|
||||
|
||||
do_exit(0)
|
||||
@@ -0,0 +1,127 @@
|
||||
/* -*- 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 <gio/gio.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "ot-builtins.h"
|
||||
|
||||
static OstreeBuiltin builtins[] = {
|
||||
{ "checkout", ostree_builtin_checkout, 0 },
|
||||
{ "diff", ostree_builtin_diff, 0 },
|
||||
{ "init", ostree_builtin_init, 0 },
|
||||
{ "commit", ostree_builtin_commit, 0 },
|
||||
{ "compose", ostree_builtin_compose, 0 },
|
||||
{ "log", ostree_builtin_log, 0 },
|
||||
#ifdef HAVE_LIBSOUP_GNOME
|
||||
{ "pull", ostree_builtin_pull, 0 },
|
||||
#endif
|
||||
{ "fsck", ostree_builtin_fsck, 0 },
|
||||
{ "remote", ostree_builtin_remote, 0 },
|
||||
{ "rev-parse", ostree_builtin_rev_parse, 0 },
|
||||
{ "remote", ostree_builtin_remote, 0 },
|
||||
{ "run-triggers", ostree_builtin_run_triggers, 0 },
|
||||
{ "show", ostree_builtin_show, 0 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static int
|
||||
usage (char **argv, gboolean is_error)
|
||||
{
|
||||
OstreeBuiltin *builtin = builtins;
|
||||
void (*print_func) (const gchar *format, ...);
|
||||
|
||||
if (is_error)
|
||||
print_func = g_printerr;
|
||||
else
|
||||
print_func = g_print;
|
||||
|
||||
print_func ("usage: %s --repo=PATH COMMAND [options]\n",
|
||||
argv[0]);
|
||||
print_func ("Builtin commands:\n");
|
||||
|
||||
while (builtin->name)
|
||||
{
|
||||
print_func (" %s\n", builtin->name);
|
||||
builtin++;
|
||||
}
|
||||
return (is_error ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
OstreeBuiltin *builtin;
|
||||
const char *cmd;
|
||||
const char *repo;
|
||||
|
||||
g_type_init ();
|
||||
|
||||
g_set_prgname (argv[0]);
|
||||
|
||||
builtin = builtins;
|
||||
|
||||
if (argc < 3)
|
||||
return usage (argv, 1);
|
||||
|
||||
if (!g_str_has_prefix (argv[1], "--repo="))
|
||||
return usage (argv, 1);
|
||||
repo = argv[1] + strlen ("--repo=");
|
||||
|
||||
cmd = argv[2];
|
||||
|
||||
while (builtin->name)
|
||||
{
|
||||
GError *error = NULL;
|
||||
if (strcmp (cmd, builtin->name) == 0)
|
||||
{
|
||||
int i;
|
||||
int tmp_argc;
|
||||
char **tmp_argv;
|
||||
|
||||
tmp_argc = argc - 2;
|
||||
tmp_argv = g_new0 (char *, tmp_argc + 1);
|
||||
|
||||
tmp_argv[0] = (char*)builtin->name;
|
||||
for (i = 0; i < tmp_argc; i++)
|
||||
tmp_argv[i+1] = argv[i+3];
|
||||
if (!builtin->fn (tmp_argc, tmp_argv, repo, &error))
|
||||
{
|
||||
g_free (tmp_argv);
|
||||
g_printerr ("%s\n", error->message);
|
||||
g_clear_error (&error);
|
||||
return 1;
|
||||
}
|
||||
g_free (tmp_argv);
|
||||
return 0;
|
||||
}
|
||||
builtin++;
|
||||
}
|
||||
|
||||
g_printerr ("Unknown command '%s'\n", cmd);
|
||||
return usage (argv, 1);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/* -*- 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 }
|
||||
};
|
||||
|
||||
gboolean
|
||||
ostree_builtin_checkout (int argc, char **argv, const char *repo_path, GError **error)
|
||||
{
|
||||
GOptionContext *context;
|
||||
gboolean ret = FALSE;
|
||||
OstreeRepo *repo = NULL;
|
||||
OstreeCheckout *checkout = NULL;
|
||||
const char *commit;
|
||||
const char *destination;
|
||||
GFile *destf = NULL;
|
||||
|
||||
context = g_option_context_new ("COMMIT DESTINATION - Check out a commit into a filesystem tree");
|
||||
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 < 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, NULL, 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;
|
||||
}
|
||||
@@ -0,0 +1,335 @@
|
||||
/* -*- 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 <gio/gunixoutputstream.h>
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
static gboolean separator_null;
|
||||
static int from_fd = -1;
|
||||
static gboolean from_stdin;
|
||||
static char *from_file;
|
||||
static char *metadata_text_path;
|
||||
static char *metadata_bin_path;
|
||||
static char *subject;
|
||||
static char *body;
|
||||
static char *parent;
|
||||
static char *branch;
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{ "subject", 's', 0, G_OPTION_ARG_STRING, &subject, "One line subject", "subject" },
|
||||
{ "body", 'm', 0, G_OPTION_ARG_STRING, &body, "Full description", "body" },
|
||||
{ "metadata-variant-text", 0, 0, G_OPTION_ARG_FILENAME, &metadata_text_path, "File containing g_variant_print() output", "path" },
|
||||
{ "metadata-variant", 0, 0, G_OPTION_ARG_FILENAME, &metadata_bin_path, "File containing serialized variant, in host endianness", "path" },
|
||||
{ "branch", 'b', 0, G_OPTION_ARG_STRING, &branch, "Branch", "branch" },
|
||||
{ "parent", 'p', 0, G_OPTION_ARG_STRING, &parent, "Parent commit", "commit" },
|
||||
{ "from-fd", 0, 0, G_OPTION_ARG_INT, &from_fd, "Read new tree files from fd", "file descriptor" },
|
||||
{ "from-stdin", 0, 0, G_OPTION_ARG_NONE, &from_stdin, "Read new tree files from stdin", "file descriptor" },
|
||||
{ "from-file", 0, 0, G_OPTION_ARG_FILENAME, &from_file, "Read new tree files from another file", "path" },
|
||||
{ "separator-null", 0, 0, G_OPTION_ARG_NONE, &separator_null, "", "Use '\\0' as filename separator, as with find -print0" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
GFile *dir;
|
||||
char separator;
|
||||
GOutputStream *out;
|
||||
GCancellable *cancellable;
|
||||
} FindThreadData;
|
||||
|
||||
static gboolean
|
||||
find (const char *basepath,
|
||||
GFile *dir,
|
||||
char separator,
|
||||
GOutputStream *out,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
static gboolean
|
||||
find_write_child (const char *basepath,
|
||||
GFile *dir,
|
||||
char separator,
|
||||
GOutputStream *out,
|
||||
GFileInfo *finfo,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
guint32 type;
|
||||
const char *name;
|
||||
char buf[1];
|
||||
char *child_path = NULL;
|
||||
GString *child_trimmed_path = NULL;
|
||||
GFile *child = NULL;
|
||||
gsize bytes_written;
|
||||
|
||||
type = g_file_info_get_attribute_uint32 (finfo, "standard::type");
|
||||
name = g_file_info_get_attribute_byte_string (finfo, "standard::name");
|
||||
|
||||
child = g_file_get_child (dir, name);
|
||||
|
||||
if (type == G_FILE_TYPE_DIRECTORY)
|
||||
{
|
||||
if (!find (basepath, child, separator, out, cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
child_path = g_file_get_path (child);
|
||||
child_trimmed_path = g_string_new (child_path + strlen (basepath));
|
||||
if (!*(child_trimmed_path->str))
|
||||
{
|
||||
/* do nothing - we implicitly add the root . */
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert (*(child_trimmed_path->str) == '/');
|
||||
g_string_insert_c (child_trimmed_path, 0, '.');
|
||||
|
||||
if (!g_output_stream_write_all (out, child_trimmed_path->str, child_trimmed_path->len,
|
||||
&bytes_written, cancellable, error))
|
||||
goto out;
|
||||
buf[0] = separator;
|
||||
if (!g_output_stream_write_all (out, buf, 1, &bytes_written,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
g_string_free (child_trimmed_path, TRUE);
|
||||
child_trimmed_path = NULL;
|
||||
g_free (child_path);
|
||||
child_path = NULL;
|
||||
g_clear_object (&child);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
find (const char *basepath,
|
||||
GFile *dir,
|
||||
char separator,
|
||||
GOutputStream *out,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GError *temp_error = NULL;
|
||||
GFileEnumerator *enumerator = NULL;
|
||||
GFileInfo *finfo = NULL;
|
||||
|
||||
enumerator = g_file_enumerate_children (dir, "standard::type,standard::name",
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
cancellable, error);
|
||||
if (!enumerator)
|
||||
goto out;
|
||||
|
||||
while ((finfo = g_file_enumerator_next_file (enumerator, cancellable, error)) != NULL)
|
||||
{
|
||||
if (!find_write_child (basepath, dir, separator, out, finfo, cancellable, error))
|
||||
goto out;
|
||||
g_clear_object (&finfo);
|
||||
}
|
||||
if (temp_error)
|
||||
{
|
||||
g_propagate_error (error, temp_error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
g_clear_object (&finfo);
|
||||
g_clear_object (&enumerator);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
find_thread (gpointer data)
|
||||
{
|
||||
FindThreadData *tdata = data;
|
||||
GError *error = NULL;
|
||||
char *path;
|
||||
|
||||
path = g_file_get_path (tdata->dir);
|
||||
if (!find (path, tdata->dir, tdata->separator, tdata->out,
|
||||
tdata->cancellable, &error))
|
||||
{
|
||||
g_printerr ("%s", error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
g_free (path);
|
||||
g_clear_object (&(tdata->dir));
|
||||
g_clear_object (&(tdata->out));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
ostree_builtin_commit (int argc, char **argv, const char *repo_path, GError **error)
|
||||
{
|
||||
GOptionContext *context;
|
||||
gboolean ret = FALSE;
|
||||
OstreeRepo *repo = NULL;
|
||||
char *dir = NULL;
|
||||
GChecksum *commit_checksum = NULL;
|
||||
char separator;
|
||||
GVariant *metadata = NULL;
|
||||
GMappedFile *metadata_mappedf = NULL;
|
||||
GFile *metadata_f = NULL;
|
||||
gboolean temp_fd = -1;
|
||||
int pipefd[2] = { -1, -1 };
|
||||
GOutputStream *out = NULL;
|
||||
FindThreadData fdata;
|
||||
|
||||
context = g_option_context_new ("[DIR] - Commit a new revision");
|
||||
g_option_context_add_main_entries (context, options, NULL);
|
||||
|
||||
if (!g_option_context_parse (context, &argc, &argv, error))
|
||||
goto out;
|
||||
|
||||
if (argc > 1)
|
||||
dir = g_strdup (argv[1]);
|
||||
else
|
||||
dir = g_get_current_dir ();
|
||||
|
||||
if (g_str_has_suffix (dir, "/"))
|
||||
dir[strlen (dir) - 1] = '\0';
|
||||
|
||||
separator = separator_null ? '\0' : '\n';
|
||||
|
||||
if (!*dir)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Invalid empty directory");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (metadata_text_path || metadata_bin_path)
|
||||
{
|
||||
metadata_mappedf = g_mapped_file_new (metadata_text_path ? metadata_text_path : metadata_bin_path, FALSE, error);
|
||||
if (!metadata_mappedf)
|
||||
goto out;
|
||||
if (metadata_text_path)
|
||||
{
|
||||
metadata = g_variant_parse (G_VARIANT_TYPE ("a{sv}"),
|
||||
g_mapped_file_get_contents (metadata_mappedf),
|
||||
g_mapped_file_get_contents (metadata_mappedf) + g_mapped_file_get_length (metadata_mappedf),
|
||||
NULL, error);
|
||||
if (!metadata)
|
||||
goto out;
|
||||
}
|
||||
else if (metadata_bin_path)
|
||||
{
|
||||
metadata_f = ot_util_new_file_for_path (metadata_bin_path);
|
||||
if (!ot_util_variant_map (metadata_f, G_VARIANT_TYPE ("a{sv}"), &metadata, error))
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
repo = ostree_repo_new (repo_path);
|
||||
if (!ostree_repo_check (repo, error))
|
||||
goto out;
|
||||
|
||||
if (!branch)
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"A branch must be specified with --branch");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!subject)
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"A subject must be specified with --subject");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(from_file || from_fd >= 0 || from_stdin))
|
||||
{
|
||||
/* We're using the current directory */
|
||||
|
||||
}
|
||||
|
||||
if (from_stdin)
|
||||
from_fd = 0;
|
||||
else if (from_file)
|
||||
{
|
||||
temp_fd = ot_util_open_file_read (from_file, error);
|
||||
if (temp_fd < 0)
|
||||
{
|
||||
g_prefix_error (error, "Failed to open '%s': ", from_file);
|
||||
goto out;
|
||||
}
|
||||
from_fd = temp_fd;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pipe (pipefd) < 0)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out = (GOutputStream*)g_unix_output_stream_new (pipefd[1], TRUE);
|
||||
from_fd = pipefd[0];
|
||||
|
||||
fdata.dir = ot_util_new_file_for_path (dir);
|
||||
fdata.separator = separator;
|
||||
fdata.out = out;
|
||||
fdata.cancellable = NULL;
|
||||
|
||||
if (g_thread_create_full (find_thread, &fdata, 0, FALSE, FALSE, G_THREAD_PRIORITY_NORMAL, error) == NULL)
|
||||
goto out;
|
||||
|
||||
out = NULL;
|
||||
}
|
||||
|
||||
if (!ostree_repo_commit_from_filelist_fd (repo, branch, parent, subject, body, metadata,
|
||||
dir, from_fd, separator,
|
||||
&commit_checksum, error))
|
||||
goto out;
|
||||
|
||||
ret = TRUE;
|
||||
g_print ("%s\n", g_checksum_get_string (commit_checksum));
|
||||
out:
|
||||
g_clear_object (&out);
|
||||
if (temp_fd >= 0)
|
||||
(void)close (temp_fd);
|
||||
if (pipefd[0] > 0)
|
||||
(void) close (pipefd[0]);
|
||||
if (pipefd[1] > 0)
|
||||
(void) close (pipefd[1]);
|
||||
g_free (dir);
|
||||
if (metadata_mappedf)
|
||||
g_mapped_file_unref (metadata_mappedf);
|
||||
if (context)
|
||||
g_option_context_free (context);
|
||||
g_clear_object (&repo);
|
||||
if (commit_checksum)
|
||||
g_checksum_free (commit_checksum);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,307 @@
|
||||
/* -*- 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 char *compose_metadata_path;
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{ "out-metadata", 0, 0, G_OPTION_ARG_FILENAME, &compose_metadata_path, "Output a file containing serialized metadata about the compose, in host endianness", "path" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
rm_rf (GFile *path)
|
||||
{
|
||||
GFileInfo *finfo = NULL;
|
||||
GFileEnumerator *path_enum = NULL;
|
||||
guint32 type;
|
||||
|
||||
finfo = g_file_query_info (path, OSTREE_GIO_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, OSTREE_GIO_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, OSTREE_GIO_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, OSTREE_GIO_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;
|
||||
}
|
||||
|
||||
g_clear_object (&dest_subfile);
|
||||
g_clear_object (&src_subfile);
|
||||
}
|
||||
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,
|
||||
GVariantBuilder *metadata_builder,
|
||||
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, NULL, error))
|
||||
goto out;
|
||||
g_print ("...done\n");
|
||||
g_print ("Merging over destination...\n");
|
||||
if (!merge_dir (destination, branchf, error))
|
||||
goto out;
|
||||
|
||||
if (metadata_builder)
|
||||
g_variant_builder_add (metadata_builder, "(ss)", branch, branchrev);
|
||||
|
||||
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 *repo_path, GError **error)
|
||||
{
|
||||
GOptionContext *context;
|
||||
gboolean ret = FALSE;
|
||||
OstreeRepo *repo = NULL;
|
||||
OstreeCheckout *checkout = NULL;
|
||||
const char *destination;
|
||||
GFile *destf = NULL;
|
||||
gboolean compose_metadata_builder_initialized = FALSE;
|
||||
GVariantBuilder compose_metadata_builder;
|
||||
gboolean commit_metadata_builder_initialized = FALSE;
|
||||
GVariantBuilder commit_metadata_builder;
|
||||
GVariant *commit_metadata = NULL;
|
||||
GFile *metadata_f = 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;
|
||||
|
||||
repo = ostree_repo_new (repo_path);
|
||||
if (!ostree_repo_check (repo, error))
|
||||
goto out;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
destination = argv[1];
|
||||
destf = ot_util_new_file_for_path (destination);
|
||||
|
||||
if (compose_metadata_path)
|
||||
{
|
||||
compose_metadata_builder_initialized = TRUE;
|
||||
g_variant_builder_init (&compose_metadata_builder, G_VARIANT_TYPE ("a(ss)"));
|
||||
}
|
||||
|
||||
for (i = 2; i < argc; i++)
|
||||
{
|
||||
const char *branch = argv[i];
|
||||
|
||||
if (!compose_branch_on_dir (repo, destf, branch, compose_metadata_builder_initialized ? &compose_metadata_builder : NULL, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (compose_metadata_path)
|
||||
{
|
||||
commit_metadata_builder_initialized = TRUE;
|
||||
g_variant_builder_init (&commit_metadata_builder, G_VARIANT_TYPE ("a{sv}"));
|
||||
|
||||
g_variant_builder_add (&commit_metadata_builder, "{sv}",
|
||||
"ostree-compose", g_variant_builder_end (&compose_metadata_builder));
|
||||
compose_metadata_builder_initialized = FALSE;
|
||||
|
||||
metadata_f = ot_util_new_file_for_path (compose_metadata_path);
|
||||
|
||||
commit_metadata = g_variant_builder_end (&commit_metadata_builder);
|
||||
if (!ot_util_variant_save (metadata_f, commit_metadata, NULL, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (compose_metadata_builder_initialized)
|
||||
g_variant_builder_clear (&compose_metadata_builder);
|
||||
if (commit_metadata_builder_initialized)
|
||||
g_variant_builder_clear (&commit_metadata_builder);
|
||||
if (context)
|
||||
g_option_context_free (context);
|
||||
if (commit_metadata)
|
||||
g_variant_unref (commit_metadata);
|
||||
g_clear_object (&repo);
|
||||
g_clear_object (&checkout);
|
||||
g_clear_object (&destf);
|
||||
g_clear_object (&metadata_f);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/* -*- 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 }
|
||||
};
|
||||
|
||||
gboolean
|
||||
ostree_builtin_diff (int argc, char **argv, const char *repo_path, GError **error)
|
||||
{
|
||||
GOptionContext *context;
|
||||
gboolean ret = FALSE;
|
||||
OstreeRepo *repo = NULL;
|
||||
const char *target;
|
||||
const char *rev;
|
||||
GFile *targetf = NULL;
|
||||
GPtrArray *modified = NULL;
|
||||
GPtrArray *removed = NULL;
|
||||
GPtrArray *added = NULL;
|
||||
|
||||
context = g_option_context_new ("REV TARGETDIR - Compare directory TARGETDIR against revision REV");
|
||||
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 < 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,
|
||||
"REV and TARGETDIR must be specified");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rev = argv[1];
|
||||
target = argv[2];
|
||||
targetf = ot_util_new_file_for_path (target);
|
||||
|
||||
if (!ostree_repo_diff (repo, rev, targetf, &modified, &removed, &added, NULL, error))
|
||||
goto out;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
g_clear_object (&repo);
|
||||
g_clear_object (&targetf);
|
||||
if (modified)
|
||||
g_ptr_array_free (modified, TRUE);
|
||||
if (removed)
|
||||
g_ptr_array_free (removed, TRUE);
|
||||
if (added)
|
||||
g_ptr_array_free (added, TRUE);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
/* -*- 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 gboolean quiet;
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{ "quiet", 'q', 0, G_OPTION_ARG_NONE, &quiet, "Don't display informational messages", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
guint n_objects;
|
||||
gboolean had_error;
|
||||
} OtFsckData;
|
||||
|
||||
static gboolean
|
||||
checksum_packed_file (OtFsckData *data,
|
||||
const char *path,
|
||||
GChecksum **out_checksum,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GChecksum *ret_checksum = NULL;
|
||||
GFile *file = NULL;
|
||||
char *metadata_buf = NULL;
|
||||
GVariant *metadata = NULL;
|
||||
GVariant *xattrs = NULL;
|
||||
GFileInputStream *in = NULL;
|
||||
guint32 metadata_len;
|
||||
guint32 version, uid, gid, mode;
|
||||
guint64 content_len;
|
||||
gsize bytes_read;
|
||||
char buf[8192];
|
||||
|
||||
file = ot_util_new_file_for_path (path);
|
||||
|
||||
in = g_file_read (file, NULL, error);
|
||||
if (!in)
|
||||
goto out;
|
||||
|
||||
if (!g_input_stream_read_all ((GInputStream*)in, &metadata_len, 4, &bytes_read, NULL, error))
|
||||
goto out;
|
||||
|
||||
metadata_len = GUINT32_FROM_BE (metadata_len);
|
||||
|
||||
metadata_buf = g_malloc (metadata_len);
|
||||
|
||||
if (!g_input_stream_read_all ((GInputStream*)in, metadata_buf, metadata_len, &bytes_read, NULL, error))
|
||||
goto out;
|
||||
|
||||
metadata = g_variant_new_from_data (G_VARIANT_TYPE (OSTREE_PACK_FILE_VARIANT_FORMAT),
|
||||
metadata_buf, metadata_len, FALSE, NULL, NULL);
|
||||
|
||||
g_variant_get (metadata, "(uuuu@a(ayay)t)",
|
||||
&version, &uid, &gid, &mode,
|
||||
&xattrs, &content_len);
|
||||
uid = GUINT32_FROM_BE (uid);
|
||||
gid = GUINT32_FROM_BE (gid);
|
||||
mode = GUINT32_FROM_BE (mode);
|
||||
content_len = GUINT64_FROM_BE (content_len);
|
||||
|
||||
ret_checksum = g_checksum_new (G_CHECKSUM_SHA256);
|
||||
|
||||
do
|
||||
{
|
||||
if (!g_input_stream_read_all ((GInputStream*)in, buf, sizeof(buf), &bytes_read, NULL, error))
|
||||
goto out;
|
||||
g_checksum_update (ret_checksum, (guint8*)buf, bytes_read);
|
||||
}
|
||||
while (bytes_read > 0);
|
||||
|
||||
ostree_checksum_update_stat (ret_checksum, uid, gid, mode);
|
||||
g_checksum_update (ret_checksum, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
|
||||
|
||||
ret = TRUE;
|
||||
*out_checksum = ret_checksum;
|
||||
ret_checksum = NULL;
|
||||
out:
|
||||
if (ret_checksum)
|
||||
g_checksum_free (ret_checksum);
|
||||
g_free (metadata_buf);
|
||||
g_clear_object (&file);
|
||||
g_clear_object (&in);
|
||||
if (metadata)
|
||||
g_variant_unref (metadata);
|
||||
if (xattrs)
|
||||
g_variant_unref (xattrs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
object_iter_callback (OstreeRepo *repo,
|
||||
const char *path,
|
||||
GFileInfo *file_info,
|
||||
gpointer user_data)
|
||||
{
|
||||
OtFsckData *data = user_data;
|
||||
struct stat stbuf;
|
||||
GChecksum *checksum = NULL;
|
||||
GError *error = NULL;
|
||||
char *dirname = NULL;
|
||||
char *checksum_prefix = NULL;
|
||||
char *checksum_string = NULL;
|
||||
char *filename_checksum = NULL;
|
||||
gboolean packed = FALSE;
|
||||
OstreeObjectType objtype;
|
||||
char *dot;
|
||||
|
||||
/* nlinks = g_file_info_get_attribute_uint32 (file_info, "unix::nlink");
|
||||
if (nlinks < 2 && !quiet)
|
||||
g_printerr ("note: floating object: %s\n", path); */
|
||||
|
||||
if (g_str_has_suffix (path, ".meta"))
|
||||
objtype = OSTREE_OBJECT_TYPE_META;
|
||||
else if (g_str_has_suffix (path, ".file"))
|
||||
objtype = OSTREE_OBJECT_TYPE_FILE;
|
||||
else if (g_str_has_suffix (path, ".packfile"))
|
||||
{
|
||||
objtype = OSTREE_OBJECT_TYPE_FILE;
|
||||
packed = TRUE;
|
||||
}
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
|
||||
if (packed && objtype == OSTREE_OBJECT_TYPE_FILE)
|
||||
{
|
||||
if (!checksum_packed_file (data, path, &checksum, &error))
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ostree_stat_and_checksum_file (-1, path, objtype, &checksum, &stbuf, &error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
filename_checksum = g_strdup (g_file_info_get_name (file_info));
|
||||
dot = strrchr (filename_checksum, '.');
|
||||
g_assert (dot != NULL);
|
||||
*dot = '\0';
|
||||
|
||||
dirname = g_path_get_dirname (path);
|
||||
checksum_prefix = g_path_get_basename (dirname);
|
||||
checksum_string = g_strconcat (checksum_prefix, filename_checksum, NULL);
|
||||
|
||||
if (strcmp (checksum_string, g_checksum_get_string (checksum)) != 0)
|
||||
{
|
||||
data->had_error = TRUE;
|
||||
g_printerr ("ERROR: corrupted object '%s' expected checksum: %s\n",
|
||||
path, g_checksum_get_string (checksum));
|
||||
}
|
||||
|
||||
data->n_objects++;
|
||||
|
||||
out:
|
||||
if (checksum != NULL)
|
||||
g_checksum_free (checksum);
|
||||
g_free (dirname);
|
||||
g_free (checksum_prefix);
|
||||
g_free (checksum_string);
|
||||
g_free (filename_checksum);
|
||||
if (error != NULL)
|
||||
{
|
||||
g_printerr ("%s\n", error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
ostree_builtin_fsck (int argc, char **argv, const char *repo_path, GError **error)
|
||||
{
|
||||
GOptionContext *context;
|
||||
OtFsckData data;
|
||||
gboolean ret = FALSE;
|
||||
OstreeRepo *repo = NULL;
|
||||
|
||||
context = g_option_context_new ("- Check the repository for consistency");
|
||||
g_option_context_add_main_entries (context, options, NULL);
|
||||
|
||||
if (!g_option_context_parse (context, &argc, &argv, error))
|
||||
goto out;
|
||||
|
||||
data.n_objects = 0;
|
||||
data.had_error = FALSE;
|
||||
|
||||
repo = ostree_repo_new (repo_path);
|
||||
if (!ostree_repo_check (repo, error))
|
||||
goto out;
|
||||
|
||||
if (!ostree_repo_iter_objects (repo, object_iter_callback, &data, error))
|
||||
goto out;
|
||||
|
||||
if (data.had_error)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Encountered filesystem consistency errors");
|
||||
goto out;
|
||||
}
|
||||
if (!quiet)
|
||||
g_printerr ("Total Objects: %u\n", data.n_objects);
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (context)
|
||||
g_option_context_free (context);
|
||||
g_clear_object (&repo);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/* -*- 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 gboolean archive;
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{ "archive", 0, 0, G_OPTION_ARG_NONE, &archive, "Initialize repository as archive", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
#define DEFAULT_CONFIG_CONTENTS ("[core]\n" \
|
||||
"repo_version=0\n")
|
||||
|
||||
|
||||
gboolean
|
||||
ostree_builtin_init (int argc, char **argv, const char *repo_path, GError **error)
|
||||
{
|
||||
GOptionContext *context = NULL;
|
||||
gboolean ret = FALSE;
|
||||
GFile *repodir = NULL;
|
||||
GFile *child = NULL;
|
||||
GFile *grandchild = NULL;
|
||||
GString *config_data = NULL;
|
||||
|
||||
context = g_option_context_new ("- Initialize a new empty repository");
|
||||
g_option_context_add_main_entries (context, options, NULL);
|
||||
|
||||
if (!g_option_context_parse (context, &argc, &argv, error))
|
||||
goto out;
|
||||
|
||||
repodir = ot_util_new_file_for_path (repo_path);
|
||||
|
||||
child = g_file_get_child (repodir, "config");
|
||||
|
||||
config_data = g_string_new (DEFAULT_CONFIG_CONTENTS);
|
||||
g_string_append_printf (config_data, "archive=%s\n", archive ? "true" : "false");
|
||||
if (!g_file_replace_contents (child,
|
||||
config_data->str,
|
||||
config_data->len,
|
||||
NULL, FALSE, 0, NULL,
|
||||
NULL, error))
|
||||
goto out;
|
||||
g_clear_object (&child);
|
||||
|
||||
child = g_file_get_child (repodir, "objects");
|
||||
if (!g_file_make_directory (child, NULL, error))
|
||||
goto out;
|
||||
g_clear_object (&child);
|
||||
|
||||
child = g_file_get_child (repodir, "tmp");
|
||||
if (!g_file_make_directory (child, NULL, error))
|
||||
goto out;
|
||||
g_clear_object (&child);
|
||||
|
||||
child = g_file_get_child (repodir, "refs");
|
||||
if (!g_file_make_directory (child, NULL, error))
|
||||
goto out;
|
||||
|
||||
grandchild = g_file_get_child (child, "heads");
|
||||
if (!g_file_make_directory (grandchild, NULL, error))
|
||||
goto out;
|
||||
g_clear_object (&grandchild);
|
||||
|
||||
grandchild = g_file_get_child (child, "remotes");
|
||||
if (!g_file_make_directory (grandchild, NULL, error))
|
||||
goto out;
|
||||
g_clear_object (&grandchild);
|
||||
|
||||
g_clear_object (&child);
|
||||
|
||||
child = g_file_get_child (repodir, "tags");
|
||||
if (!g_file_make_directory (child, NULL, error))
|
||||
goto out;
|
||||
g_clear_object (&child);
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (context)
|
||||
g_option_context_free (context);
|
||||
if (config_data)
|
||||
g_string_free (config_data, TRUE);
|
||||
g_clear_object (&repodir);
|
||||
g_clear_object (&child);
|
||||
g_clear_object (&grandchild);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/* -*- 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 }
|
||||
};
|
||||
|
||||
gboolean
|
||||
ostree_builtin_log (int argc, char **argv, const char *repo_path, GError **error)
|
||||
{
|
||||
GOptionContext *context;
|
||||
gboolean ret = FALSE;
|
||||
OstreeRepo *repo = NULL;
|
||||
GOutputStream *pager = NULL;
|
||||
const char *rev;
|
||||
GVariant *commit = NULL;
|
||||
char *resolved_rev = NULL;
|
||||
|
||||
context = g_option_context_new ("- Show revision log");
|
||||
g_option_context_add_main_entries (context, options, NULL);
|
||||
|
||||
if (!g_option_context_parse (context, &argc, &argv, error))
|
||||
goto out;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"A revision must be specified");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rev = argv[1];
|
||||
|
||||
repo = ostree_repo_new (repo_path);
|
||||
if (!ostree_repo_check (repo, error))
|
||||
goto out;
|
||||
|
||||
if (!ot_util_spawn_pager (&pager, error))
|
||||
goto out;
|
||||
|
||||
if (!ostree_repo_resolve_rev (repo, rev, &resolved_rev, error))
|
||||
goto out;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
OstreeSerializedVariantType type;
|
||||
char *formatted = NULL;
|
||||
guint32 version;
|
||||
const char *parent;
|
||||
const char *subject;
|
||||
const char *body;
|
||||
guint64 timestamp;
|
||||
const char *contents;
|
||||
const char *root_metadata;
|
||||
GDateTime *time_obj = NULL;
|
||||
char *formatted_date = NULL;
|
||||
const char *body_newline;
|
||||
gsize bytes_written;
|
||||
GVariant *commit_metadata = NULL;
|
||||
char *formatted_metadata = NULL;
|
||||
|
||||
if (commit)
|
||||
g_variant_unref (commit);
|
||||
if (!ostree_repo_load_variant (repo, resolved_rev, &type, &commit, error))
|
||||
goto out;
|
||||
|
||||
/* Ignore commit metadata for now */
|
||||
g_variant_get (commit, "(u@a{sv}&s&s&st&s&s)",
|
||||
&version, &commit_metadata, &parent, &subject, &body,
|
||||
×tamp, &contents, &root_metadata);
|
||||
version = GUINT32_FROM_BE (version);
|
||||
timestamp = GUINT64_FROM_BE (timestamp);
|
||||
time_obj = g_date_time_new_from_unix_utc (timestamp);
|
||||
formatted_date = g_date_time_format (time_obj, "%a %b %d %H:%M:%S %Y %z");
|
||||
g_date_time_unref (time_obj);
|
||||
time_obj = NULL;
|
||||
|
||||
formatted_metadata = g_variant_print (commit_metadata, TRUE);
|
||||
g_variant_unref (commit_metadata);
|
||||
formatted = g_strdup_printf ("commit %s\nSubject: %s\nDate: %s\nMetadata: %s\n\n",
|
||||
resolved_rev, subject, formatted_date, formatted_metadata);
|
||||
g_free (formatted_metadata);
|
||||
g_free (formatted_date);
|
||||
formatted_date = NULL;
|
||||
|
||||
if (!g_output_stream_write_all (pager, formatted, strlen (formatted), &bytes_written, NULL, error))
|
||||
{
|
||||
g_free (formatted);
|
||||
goto out;
|
||||
}
|
||||
g_free (formatted);
|
||||
|
||||
body_newline = strchr (body, '\n');
|
||||
do {
|
||||
gsize len;
|
||||
if (!g_output_stream_write_all (pager, " ", 4, &bytes_written, NULL, error))
|
||||
goto out;
|
||||
len = body_newline ? body_newline - body : strlen (body);
|
||||
if (!g_output_stream_write_all (pager, body, len, &bytes_written, NULL, error))
|
||||
goto out;
|
||||
if (!g_output_stream_write_all (pager, "\n\n", 2, &bytes_written, NULL, error))
|
||||
goto out;
|
||||
body_newline = strchr (body, '\n');
|
||||
if (!body_newline)
|
||||
break;
|
||||
else
|
||||
body_newline += 1;
|
||||
} while (*body_newline);
|
||||
|
||||
if (strcmp (parent, "") == 0)
|
||||
break;
|
||||
g_free (resolved_rev);
|
||||
resolved_rev = g_strdup (parent);
|
||||
}
|
||||
|
||||
if (!g_output_stream_close (pager, NULL, error))
|
||||
goto out;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
g_free (resolved_rev);
|
||||
if (context)
|
||||
g_option_context_free (context);
|
||||
if (commit)
|
||||
g_variant_unref (commit);
|
||||
g_clear_object (&repo);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,351 @@
|
||||
/* -*- 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>
|
||||
|
||||
#include <libsoup/soup-gnome.h>
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
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 = ot_util_new_file_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;
|
||||
|
||||
objpath = ostree_get_relative_object_path (object, objtype, TRUE);
|
||||
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, obj_uri, &filename, error))
|
||||
goto out;
|
||||
|
||||
if (!ostree_repo_store_packfile (repo, object, filename, objtype, error))
|
||||
goto out;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (obj_uri)
|
||||
soup_uri_free (obj_uri);
|
||||
if (filename)
|
||||
(void) unlink (filename);
|
||||
g_free (filename);
|
||||
g_free (objpath);
|
||||
g_free (relpath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
store_tree_recurse (OstreeRepo *repo,
|
||||
SoupSession *soup,
|
||||
SoupURI *base_uri,
|
||||
const char *rev,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GVariant *tree = NULL;
|
||||
GVariant *files_variant = NULL;
|
||||
GVariant *dirs_variant = NULL;
|
||||
OstreeSerializedVariantType metatype;
|
||||
gboolean did_exist;
|
||||
int i, n;
|
||||
|
||||
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 (tree, 2, "@a(ss)", &files_variant);
|
||||
g_variant_get_child (tree, 3, "@a(sss)", &dirs_variant);
|
||||
|
||||
n = g_variant_n_children (files_variant);
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
const char *filename;
|
||||
const char *checksum;
|
||||
|
||||
g_variant_get_child (files_variant, i, "(ss)", &filename, &checksum);
|
||||
|
||||
if (!store_object (repo, soup, base_uri, checksum, OSTREE_OBJECT_TYPE_FILE, &did_exist, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
n = g_variant_n_children (dirs_variant);
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
const char *dirname;
|
||||
const char *tree_checksum;
|
||||
const char *meta_checksum;
|
||||
|
||||
g_variant_get_child (dirs_variant, i, "(sss)",
|
||||
&dirname, &tree_checksum, &meta_checksum);
|
||||
|
||||
if (!store_tree_recurse (repo, soup, base_uri, tree_checksum, error))
|
||||
goto out;
|
||||
|
||||
if (!store_object (repo, soup, base_uri, meta_checksum, OSTREE_OBJECT_TYPE_META, &did_exist, error))
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (tree)
|
||||
g_variant_unref (tree);
|
||||
if (files_variant)
|
||||
g_variant_unref (files_variant);
|
||||
if (dirs_variant)
|
||||
g_variant_unref (dirs_variant);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
store_commit_recurse (OstreeRepo *repo,
|
||||
SoupSession *soup,
|
||||
SoupURI *base_uri,
|
||||
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",
|
||||
rev, 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, soup, base_uri, tree_meta_checksum, OSTREE_OBJECT_TYPE_META, &did_exist, error))
|
||||
goto out;
|
||||
|
||||
if (!store_tree_recurse (repo, soup, base_uri, 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 *repo_path, GError **error)
|
||||
{
|
||||
GOptionContext *context;
|
||||
gboolean ret = FALSE;
|
||||
OstreeRepo *repo = 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;
|
||||
|
||||
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;
|
||||
|
||||
repo = ostree_repo_new (repo_path);
|
||||
if (!ostree_repo_check (repo, error))
|
||||
goto out;
|
||||
|
||||
if (argc < 3)
|
||||
{
|
||||
ot_util_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;
|
||||
|
||||
rev = ot_util_get_file_contents_utf8 (temppath, error);
|
||||
if (!rev)
|
||||
goto out;
|
||||
g_strchomp (rev);
|
||||
|
||||
if (!ostree_validate_checksum_string (rev, error))
|
||||
goto out;
|
||||
|
||||
if (!store_commit_recurse (repo, soup, base_uri, rev, error))
|
||||
goto out;
|
||||
|
||||
if (!ostree_repo_write_ref (repo, FALSE, branch, rev, error))
|
||||
goto out;
|
||||
|
||||
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);
|
||||
g_clear_object (&repo);
|
||||
g_clear_object (&soup);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/* -*- 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 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);
|
||||
}
|
||||
|
||||
gboolean
|
||||
ostree_builtin_remote (int argc, char **argv, const char *repo_path, GError **error)
|
||||
{
|
||||
GOptionContext *context;
|
||||
gboolean ret = FALSE;
|
||||
OstreeRepo *repo = NULL;
|
||||
OstreeCheckout *checkout = NULL;
|
||||
const char *op;
|
||||
GKeyFile *config = NULL;
|
||||
|
||||
context = g_option_context_new ("OPERATION [args] - Control remote repository configuration");
|
||||
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)
|
||||
{
|
||||
usage_error (context, "OPERATION must be specified", error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
op = argv[1];
|
||||
|
||||
config = ostree_repo_copy_config (repo);
|
||||
|
||||
if (!strcmp (op, "add"))
|
||||
{
|
||||
char *key;
|
||||
if (argc < 4)
|
||||
{
|
||||
usage_error (context, "NAME and URL must be specified", error);
|
||||
goto out;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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_free (config);
|
||||
g_clear_object (&repo);
|
||||
g_clear_object (&checkout);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/* -*- 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 }
|
||||
};
|
||||
|
||||
gboolean
|
||||
ostree_builtin_rev_parse (int argc, char **argv, const char *repo_path, GError **error)
|
||||
{
|
||||
GOptionContext *context;
|
||||
gboolean ret = FALSE;
|
||||
OstreeRepo *repo = NULL;
|
||||
const char *rev = "master";
|
||||
char *resolved_rev = NULL;
|
||||
GVariant *variant = NULL;
|
||||
char *formatted_variant = NULL;
|
||||
|
||||
context = g_option_context_new ("REV - Output the target of a rev");
|
||||
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, "REV must be specified", error);
|
||||
goto out;
|
||||
}
|
||||
rev = argv[1];
|
||||
|
||||
if (!ostree_repo_resolve_rev (repo, rev, &resolved_rev, error))
|
||||
goto out;
|
||||
|
||||
g_print ("%s\n", resolved_rev);
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
g_free (resolved_rev);
|
||||
if (context)
|
||||
g_option_context_free (context);
|
||||
g_clear_object (&repo);
|
||||
if (variant)
|
||||
g_variant_unref (variant);
|
||||
g_free (formatted_variant);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/* -*- 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 gboolean quiet;
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{ "quiet", 'q', 0, G_OPTION_ARG_NONE, &quiet, "Don't display informational messages", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
gboolean
|
||||
ostree_builtin_run_triggers (int argc, char **argv, const char *repo_path, GError **error)
|
||||
{
|
||||
GOptionContext *context;
|
||||
gboolean ret = FALSE;
|
||||
OstreeRepo *repo = NULL;
|
||||
OstreeCheckout *checkout = NULL;
|
||||
const char *dir;
|
||||
|
||||
context = g_option_context_new ("DIR - Run trigger scripts for directory");
|
||||
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 < 1)
|
||||
{
|
||||
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,
|
||||
"DIR must be specified");
|
||||
goto out;
|
||||
}
|
||||
|
||||
dir = argv[1];
|
||||
|
||||
checkout = ostree_checkout_new (repo, dir);
|
||||
if (!ostree_checkout_run_triggers (checkout, error))
|
||||
goto out;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (context)
|
||||
g_option_context_free (context);
|
||||
g_clear_object (&repo);
|
||||
g_clear_object (&checkout);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
/* -*- 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 gboolean print_compose;
|
||||
static char* print_variant_type;
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{ "print-compose", 0, 0, G_OPTION_ARG_NONE, &print_compose, "If given, show the branches which make up the given compose commit", NULL },
|
||||
{ "print-variant-type", 0, 0, G_OPTION_ARG_STRING, &print_variant_type, "If given, argument should be a filename and it will be interpreted as this type", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
print_variant (GVariant *variant)
|
||||
{
|
||||
char *formatted_variant = NULL;
|
||||
|
||||
formatted_variant = g_variant_print (variant, TRUE);
|
||||
g_print ("%s\n", formatted_variant);
|
||||
|
||||
g_free (formatted_variant);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
do_print_variant_generic (const GVariantType *type,
|
||||
const char *filename,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GFile *f = NULL;
|
||||
GVariant *variant = NULL;
|
||||
|
||||
f = ot_util_new_file_for_path (filename);
|
||||
|
||||
if (!ot_util_variant_map (f, type, &variant, error))
|
||||
goto out;
|
||||
|
||||
print_variant (variant);
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (variant)
|
||||
g_variant_unref (variant);
|
||||
g_clear_object (&f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
show_repo_meta (OstreeRepo *repo,
|
||||
const char *rev,
|
||||
const char *resolved_rev,
|
||||
GError **error)
|
||||
{
|
||||
OstreeSerializedVariantType type;
|
||||
gboolean ret = FALSE;
|
||||
GVariant *variant = NULL;
|
||||
|
||||
if (!ostree_repo_load_variant (repo, resolved_rev, &type, &variant, error))
|
||||
goto out;
|
||||
g_print ("Object: %s\nType: %d\n", resolved_rev, type);
|
||||
print_variant (variant);
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (variant)
|
||||
g_variant_unref (variant);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
do_print_compose (OstreeRepo *repo,
|
||||
const char *rev,
|
||||
const char *resolved_rev,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GVariant *variant = NULL;
|
||||
GVariant *metadata = NULL;
|
||||
GVariant *compose_contents = NULL;
|
||||
GVariantIter *viter = NULL;
|
||||
GHashTable *metadata_hash = NULL;
|
||||
const char *branch;
|
||||
const char *branchrev;
|
||||
|
||||
if (!ostree_repo_load_variant_checked (repo, OSTREE_SERIALIZED_COMMIT_VARIANT,
|
||||
resolved_rev, &variant, error))
|
||||
goto out;
|
||||
|
||||
/* PARSE OSTREE_SERIALIZED_COMMIT_VARIANT */
|
||||
metadata = g_variant_get_child_value (variant, 1);
|
||||
metadata_hash = ot_util_variant_asv_to_hash_table (metadata);
|
||||
|
||||
compose_contents = g_hash_table_lookup (metadata_hash, "ostree-compose");
|
||||
if (!compose_contents)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Commit %s does not have compose metadata key \"ostree-compose\"", resolved_rev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
g_variant_get_child (compose_contents, 0, "a(ss)", &viter);
|
||||
while (g_variant_iter_next (viter, "(&s&s)", &branch, &branchrev))
|
||||
{
|
||||
g_print ("%s %s\n", branch, branchrev);
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (variant)
|
||||
g_variant_unref (variant);
|
||||
if (viter)
|
||||
g_variant_iter_free (viter);
|
||||
if (metadata)
|
||||
g_variant_unref (metadata);
|
||||
if (metadata_hash)
|
||||
g_hash_table_destroy (metadata_hash);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
ostree_builtin_show (int argc, char **argv, const char *repo_path, GError **error)
|
||||
{
|
||||
GOptionContext *context;
|
||||
gboolean ret = FALSE;
|
||||
OstreeRepo *repo = NULL;
|
||||
const char *rev = "master";
|
||||
char *resolved_rev = NULL;
|
||||
|
||||
context = g_option_context_new ("- Output a metadata object");
|
||||
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 > 1)
|
||||
rev = argv[1];
|
||||
|
||||
if (print_compose)
|
||||
{
|
||||
if (!ostree_repo_resolve_rev (repo, rev, &resolved_rev, error))
|
||||
goto out;
|
||||
|
||||
if (!do_print_compose (repo, rev, resolved_rev, error))
|
||||
goto out;
|
||||
}
|
||||
else if (print_variant_type)
|
||||
{
|
||||
if (!do_print_variant_generic (G_VARIANT_TYPE (print_variant_type), rev, error))
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ostree_repo_resolve_rev (repo, rev, &resolved_rev, error))
|
||||
goto out;
|
||||
|
||||
if (!show_repo_meta (repo, rev, resolved_rev, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
g_free (resolved_rev);
|
||||
if (context)
|
||||
g_option_context_free (context);
|
||||
g_clear_object (&repo);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/* -*- 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>
|
||||
*/
|
||||
|
||||
#ifndef __OSTREE_BUILTINS__
|
||||
#define __OSTREE_BUILTINS__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
OSTREE_BUILTIN_FLAG_NONE = 0,
|
||||
} OstreeBuiltinFlags;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
gboolean (*fn) (int argc, char **argv, const char *repo, GError **error);
|
||||
int flags; /* OstreeBuiltinFlags */
|
||||
} OstreeBuiltin;
|
||||
|
||||
gboolean ostree_builtin_checkout (int argc, char **argv, const char *repo, GError **error);
|
||||
gboolean ostree_builtin_commit (int argc, char **argv, const char *repo, GError **error);
|
||||
gboolean ostree_builtin_compose (int argc, char **argv, const char *repo, GError **error);
|
||||
gboolean ostree_builtin_diff (int argc, char **argv, const char *repo, GError **error);
|
||||
gboolean ostree_builtin_init (int argc, char **argv, const char *repo, GError **error);
|
||||
gboolean ostree_builtin_log (int argc, char **argv, const char *repo, GError **error);
|
||||
gboolean ostree_builtin_pull (int argc, char **argv, const char *repo, GError **error);
|
||||
gboolean ostree_builtin_run_triggers (int argc, char **argv, const char *repo, GError **error);
|
||||
gboolean ostree_builtin_fsck (int argc, char **argv, const char *repo, GError **error);
|
||||
gboolean ostree_builtin_show (int argc, char **argv, const char *repo, GError **error);
|
||||
gboolean ostree_builtin_rev_parse (int argc, char **argv, const char *repo, GError **error);
|
||||
gboolean ostree_builtin_remote (int argc, char **argv, const char *repo, GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user