forked from Mirrors/flatpak-builder
Add xdg-app-builder
This is a tool that makes it easy to build applications and their dependecies by automating the configure && make && make install steps.tingping/wmclass
parent
7e1a645f99
commit
b2790349d6
|
@ -29,6 +29,7 @@ xdg-app
|
|||
xdg-app-helper
|
||||
xdg-app-session-helper
|
||||
xdg-document-portal
|
||||
xdg-app-builder
|
||||
testdb
|
||||
doc/*.1
|
||||
*~
|
||||
|
|
|
@ -47,6 +47,7 @@ include libglnx/Makefile-libglnx.am.inc
|
|||
include lib/Makefile.am.inc
|
||||
include data/Makefile.am.inc
|
||||
include app/Makefile.am.inc
|
||||
include builder/Makefile.am.inc
|
||||
include session-helper/Makefile.am.inc
|
||||
include dbus-proxy/Makefile.am.inc
|
||||
include document-portal/Makefile.am.inc
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
bin_PROGRAMS += \
|
||||
xdg-app-builder \
|
||||
$(NULL)
|
||||
|
||||
xdg_app_builder_SOURCES = \
|
||||
builder/xdg-app-builder-main.c \
|
||||
builder/builder-manifest.c \
|
||||
builder/builder-manifest.h \
|
||||
builder/builder-options.c \
|
||||
builder/builder-options.h \
|
||||
builder/builder-module.c \
|
||||
builder/builder-module.h \
|
||||
builder/builder-source.c \
|
||||
builder/builder-source.h \
|
||||
builder/builder-source-archive.c \
|
||||
builder/builder-source-archive.h \
|
||||
builder/builder-source-git.c \
|
||||
builder/builder-source-git.h \
|
||||
builder/builder-source-bzr.c \
|
||||
builder/builder-source-bzr.h \
|
||||
builder/builder-source-file.c \
|
||||
builder/builder-source-file.h \
|
||||
builder/builder-source-patch.c \
|
||||
builder/builder-source-patch.h \
|
||||
builder/builder-context.c \
|
||||
builder/builder-context.h \
|
||||
builder/builder-cache.c \
|
||||
builder/builder-cache.h \
|
||||
builder/builder-utils.c \
|
||||
builder/builder-utils.h \
|
||||
$(NULL)
|
||||
|
||||
xdg_app_builder_LDADD = $(BASE_LIBS) $(OSTREE_LIBS) $(JSON_LIBS) $(SOUP_LIBS) $(LIBARCHIVE_LIBS) libglnx.la libxdgapp.la
|
||||
xdg_app_builder_CFLAGS = $(BASE_CFLAGS) $(OSTREE_CFLAGS) $(JSON_CFLAGS) $(SOUP_CFLAGS) $(LIBARCHIVE_CFLAGS)
|
||||
|
|
@ -0,0 +1,499 @@
|
|||
/* builder-cache.c
|
||||
*
|
||||
* Copyright (C) 2015 Red Hat, Inc
|
||||
*
|
||||
* This file 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 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This file 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 General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/statfs.h>
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <ostree.h>
|
||||
#include "libglnx/libglnx.h"
|
||||
#include "libgsystem.h"
|
||||
|
||||
#include "xdg-app-utils.h"
|
||||
#include "builder-utils.h"
|
||||
#include "builder-cache.h"
|
||||
|
||||
struct BuilderCache {
|
||||
GObject parent;
|
||||
GChecksum *checksum;
|
||||
GFile *cache_dir;
|
||||
GFile *app_dir;
|
||||
char *branch;
|
||||
char *last_parent;
|
||||
OstreeRepo *repo;
|
||||
gboolean disabled;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
GObjectClass parent_class;
|
||||
} BuilderCacheClass;
|
||||
|
||||
G_DEFINE_TYPE (BuilderCache, builder_cache, G_TYPE_OBJECT);
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_CACHE_DIR,
|
||||
PROP_APP_DIR,
|
||||
PROP_BRANCH,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
#define OSTREE_GIO_FAST_QUERYINFO ("standard::name,standard::type,standard::size,standard::is-symlink,standard::symlink-target," \
|
||||
"unix::device,unix::inode,unix::mode,unix::uid,unix::gid,unix::rdev")
|
||||
|
||||
static void
|
||||
builder_cache_finalize (GObject *object)
|
||||
{
|
||||
BuilderCache *self = (BuilderCache *)object;
|
||||
|
||||
g_clear_object (&self->cache_dir);
|
||||
g_clear_object (&self->app_dir);
|
||||
g_checksum_free (self->checksum);
|
||||
g_free (self->branch);
|
||||
g_free (self->last_parent);
|
||||
|
||||
G_OBJECT_CLASS (builder_cache_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
builder_cache_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BuilderCache *self = BUILDER_CACHE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CACHE_DIR:
|
||||
g_value_set_object (value, self->cache_dir);
|
||||
break;
|
||||
|
||||
case PROP_APP_DIR:
|
||||
g_value_set_object (value, self->app_dir);
|
||||
break;
|
||||
|
||||
case PROP_BRANCH:
|
||||
g_value_set_string (value, self->branch);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
builder_cache_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BuilderCache *self = BUILDER_CACHE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_BRANCH:
|
||||
g_free (self->branch);
|
||||
self->branch = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
case PROP_CACHE_DIR:
|
||||
g_set_object (&self->cache_dir, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_APP_DIR:
|
||||
g_set_object (&self->app_dir, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
builder_cache_class_init (BuilderCacheClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = builder_cache_finalize;
|
||||
object_class->get_property = builder_cache_get_property;
|
||||
object_class->set_property = builder_cache_set_property;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_CACHE_DIR,
|
||||
g_param_spec_object ("cache-dir",
|
||||
"",
|
||||
"",
|
||||
G_TYPE_FILE,
|
||||
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_APP_DIR,
|
||||
g_param_spec_object ("app-dir",
|
||||
"",
|
||||
"",
|
||||
G_TYPE_FILE,
|
||||
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_BRANCH,
|
||||
g_param_spec_string ("branch",
|
||||
"",
|
||||
"",
|
||||
NULL,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
builder_cache_init (BuilderCache *self)
|
||||
{
|
||||
self->checksum = g_checksum_new (G_CHECKSUM_SHA256);
|
||||
}
|
||||
|
||||
BuilderCache *
|
||||
builder_cache_new (GFile *cache_dir,
|
||||
GFile *app_dir,
|
||||
const char *branch)
|
||||
{
|
||||
return g_object_new (BUILDER_TYPE_CACHE,
|
||||
"cache-dir", cache_dir,
|
||||
"app-dir", app_dir,
|
||||
"branch", branch,
|
||||
NULL);
|
||||
}
|
||||
|
||||
GChecksum *
|
||||
builder_cache_get_checksum (BuilderCache *self)
|
||||
{
|
||||
return self->checksum;
|
||||
}
|
||||
|
||||
gboolean
|
||||
builder_cache_open (BuilderCache *self,
|
||||
GError **error)
|
||||
{
|
||||
self->repo = ostree_repo_new (self->cache_dir);
|
||||
|
||||
if (!g_file_query_exists (self->cache_dir, NULL))
|
||||
{
|
||||
if (!ostree_repo_create (self->repo, OSTREE_REPO_MODE_BARE, NULL, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!ostree_repo_open (self->repo, NULL, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static char *
|
||||
builder_cache_get_current (BuilderCache *self)
|
||||
{
|
||||
g_autoptr(GChecksum) copy = g_checksum_copy (self->checksum);
|
||||
|
||||
return g_strdup (g_checksum_get_string (copy));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
builder_cache_checkout (BuilderCache *self, const char *commit)
|
||||
{
|
||||
g_autoptr(GFile) root = NULL;
|
||||
g_autoptr(GFileInfo) file_info = NULL;
|
||||
|
||||
if (!ostree_repo_read_commit (self->repo, commit, &root, NULL, NULL, NULL))
|
||||
return FALSE;
|
||||
|
||||
file_info = g_file_query_info (root, OSTREE_GIO_FAST_QUERYINFO,
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
NULL, NULL);
|
||||
if (file_info == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (!ostree_repo_checkout_tree (self->repo,
|
||||
OSTREE_REPO_CHECKOUT_MODE_NONE,
|
||||
OSTREE_REPO_CHECKOUT_OVERWRITE_NONE,
|
||||
self->app_dir,
|
||||
OSTREE_REPO_FILE (root), file_info,
|
||||
NULL, NULL))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
builder_cache_ensure_checkout (BuilderCache *self)
|
||||
{
|
||||
if (self->disabled)
|
||||
return;
|
||||
|
||||
if (self->last_parent)
|
||||
{
|
||||
g_print ("Everything cached, checking out from cache\n");
|
||||
|
||||
if (!builder_cache_checkout (self, self->last_parent))
|
||||
g_error ("Failed to check out cache");
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
builder_cache_lookup (BuilderCache *self)
|
||||
{
|
||||
g_autofree char *current = NULL;
|
||||
g_autofree char *commit = NULL;
|
||||
|
||||
if (self->disabled)
|
||||
return FALSE;
|
||||
|
||||
if (!ostree_repo_resolve_rev (self->repo, self->branch, TRUE, &commit, NULL))
|
||||
goto checkout;
|
||||
|
||||
current = builder_cache_get_current (self);
|
||||
|
||||
while (commit != NULL)
|
||||
{
|
||||
g_autoptr(GVariant) variant = NULL;
|
||||
const gchar *subject;
|
||||
|
||||
if (!ostree_repo_load_variant (self->repo, OSTREE_OBJECT_TYPE_COMMIT, commit,
|
||||
&variant, NULL))
|
||||
goto checkout;
|
||||
|
||||
g_variant_get (variant, "(a{sv}aya(say)&s&stayay)", NULL, NULL, NULL,
|
||||
&subject, NULL, NULL, NULL, NULL);
|
||||
|
||||
if (strcmp (subject, current) == 0)
|
||||
{
|
||||
g_free (self->last_parent);
|
||||
self->last_parent = g_steal_pointer (&commit);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_free (commit);
|
||||
commit = ostree_commit_get_parent (variant);
|
||||
}
|
||||
|
||||
checkout:
|
||||
if (self->last_parent)
|
||||
{
|
||||
g_print ("Cache miss, checking out last cache hit\n");
|
||||
|
||||
if (!builder_cache_checkout (self, self->last_parent))
|
||||
g_error ("Failed to check out cache");
|
||||
}
|
||||
|
||||
self->disabled = TRUE; /* Don't use cache any more after first miss */
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
builder_cache_commit (BuilderCache *self,
|
||||
const char *body,
|
||||
GError **error)
|
||||
{
|
||||
g_autofree char *current = NULL;
|
||||
OstreeRepoCommitModifier *modifier = NULL;
|
||||
g_autoptr(OstreeMutableTree) mtree = NULL;
|
||||
g_autoptr(GFile) root = NULL;
|
||||
g_autofree char *commit_checksum = NULL;
|
||||
gboolean res = FALSE;
|
||||
|
||||
if (!ostree_repo_prepare_transaction (self->repo, NULL, NULL, error))
|
||||
return FALSE;
|
||||
|
||||
mtree = ostree_mutable_tree_new ();
|
||||
|
||||
modifier = ostree_repo_commit_modifier_new (OSTREE_REPO_COMMIT_MODIFIER_FLAGS_SKIP_XATTRS,
|
||||
NULL, NULL, NULL);
|
||||
if (!ostree_repo_write_directory_to_mtree (self->repo, self->app_dir,
|
||||
mtree, modifier, NULL, error))
|
||||
goto out;
|
||||
|
||||
if (!ostree_repo_write_mtree (self->repo, mtree, &root, NULL, error))
|
||||
goto out;
|
||||
|
||||
current = builder_cache_get_current (self);
|
||||
|
||||
if (!ostree_repo_write_commit (self->repo, self->last_parent, current, body, NULL,
|
||||
OSTREE_REPO_FILE (root),
|
||||
&commit_checksum, NULL, error))
|
||||
goto out;
|
||||
|
||||
ostree_repo_transaction_set_ref (self->repo, NULL, self->branch, commit_checksum);
|
||||
|
||||
if (!ostree_repo_commit_transaction (self->repo, NULL, NULL, error))
|
||||
goto out;
|
||||
|
||||
g_free (self->last_parent);
|
||||
self->last_parent = g_steal_pointer (&commit_checksum);
|
||||
|
||||
res = TRUE;
|
||||
|
||||
out:
|
||||
if (!res)
|
||||
{
|
||||
if (!ostree_repo_abort_transaction (self->repo, NULL, NULL))
|
||||
g_warning ("failed to abort transaction");
|
||||
}
|
||||
if (modifier)
|
||||
ostree_repo_commit_modifier_unref (modifier);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
GPtrArray *
|
||||
builder_cache_get_changes (BuilderCache *self,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GPtrArray) added = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
g_autoptr(GPtrArray) modified = g_ptr_array_new_with_free_func ((GDestroyNotify)ostree_diff_item_unref);
|
||||
g_autoptr(GPtrArray) removed = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
g_autoptr(GPtrArray) added_paths = g_ptr_array_new_with_free_func (g_free);
|
||||
g_autoptr(GFile) current_root = NULL;
|
||||
g_autoptr(GFile) current_files = NULL;
|
||||
g_autoptr(GFile) parent_root = NULL;
|
||||
g_autoptr(GFile) parent_files = NULL;
|
||||
g_autoptr(GVariant) variant = NULL;
|
||||
g_autoptr(GHashTable) owned = NULL;
|
||||
g_autofree char *parent_commit = NULL;
|
||||
int i;
|
||||
|
||||
if (!ostree_repo_read_commit (self->repo, self->last_parent, ¤t_root, NULL, NULL, error))
|
||||
return NULL;
|
||||
|
||||
current_files = g_file_get_child (current_root, "files");
|
||||
|
||||
if (!ostree_repo_load_variant (self->repo, OSTREE_OBJECT_TYPE_COMMIT, self->last_parent,
|
||||
&variant, NULL))
|
||||
return NULL;
|
||||
|
||||
parent_commit = ostree_commit_get_parent (variant);
|
||||
if (parent_commit != NULL)
|
||||
{
|
||||
if (!ostree_repo_read_commit (self->repo, parent_commit, &parent_root, NULL, NULL, error))
|
||||
return FALSE;
|
||||
parent_files = g_file_get_child (parent_root, "files");
|
||||
}
|
||||
|
||||
if (!ostree_diff_dirs (OSTREE_DIFF_FLAGS_NONE,
|
||||
parent_files,
|
||||
current_files,
|
||||
modified,
|
||||
removed,
|
||||
added,
|
||||
NULL, error))
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < added->len; i++)
|
||||
{
|
||||
char *path = g_file_get_relative_path (current_files, g_ptr_array_index (added, i));
|
||||
g_ptr_array_add (added_paths, path);
|
||||
}
|
||||
|
||||
return g_steal_pointer (&added_paths);
|
||||
}
|
||||
|
||||
void
|
||||
builder_cache_disable_lookups (BuilderCache *self)
|
||||
{
|
||||
self->disabled = TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
builder_gc (BuilderCache *self,
|
||||
GError **error)
|
||||
{
|
||||
gint objects_total;
|
||||
gint objects_pruned;
|
||||
guint64 pruned_object_size_total;
|
||||
|
||||
return ostree_repo_prune (self->repo,
|
||||
OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY, -1,
|
||||
&objects_total,
|
||||
&objects_pruned,
|
||||
&pruned_object_size_total,
|
||||
NULL, error);
|
||||
}
|
||||
|
||||
void
|
||||
builder_cache_checksum_str (BuilderCache *self,
|
||||
const char *str)
|
||||
{
|
||||
/* We include the terminating zero so that we make
|
||||
* a difference between NULL and "". */
|
||||
|
||||
if (str)
|
||||
g_checksum_update (self->checksum, (const guchar *)str, strlen (str) + 1);
|
||||
else
|
||||
/* Always add something so we can't be fooled by a sequence like
|
||||
NULL, "a" turning into "a", NULL. */
|
||||
g_checksum_update (self->checksum, (const guchar *)"\1", 1);
|
||||
}
|
||||
|
||||
void
|
||||
builder_cache_checksum_strv (BuilderCache *self,
|
||||
char **strv)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (strv)
|
||||
{
|
||||
g_checksum_update (self->checksum, (const guchar *)"\1", 1);
|
||||
for (i = 0; strv[i] != NULL; i++)
|
||||
builder_cache_checksum_str (self, strv[i]);
|
||||
}
|
||||
else
|
||||
g_checksum_update (self->checksum, (const guchar *)"\2", 1);
|
||||
}
|
||||
|
||||
void
|
||||
builder_cache_checksum_boolean (BuilderCache *self,
|
||||
gboolean val)
|
||||
{
|
||||
if (val)
|
||||
g_checksum_update (self->checksum, (const guchar *)"\1", 1);
|
||||
else
|
||||
g_checksum_update (self->checksum, (const guchar *)"\0", 1);
|
||||
}
|
||||
|
||||
void
|
||||
builder_cache_checksum_uint32 (BuilderCache *self,
|
||||
guint32 val)
|
||||
{
|
||||
guchar v[4];
|
||||
v[0] = (val >> 0) & 0xff;
|
||||
v[1] = (val >> 8) & 0xff;
|
||||
v[2] = (val >> 16) & 0xff;
|
||||
v[3] = (val >> 24) & 0xff;
|
||||
g_checksum_update (self->checksum, v, 4);
|
||||
}
|
||||
|
||||
void
|
||||
builder_cache_checksum_data (BuilderCache *self,
|
||||
guint8 *data,
|
||||
gsize len)
|
||||
{
|
||||
g_checksum_update (self->checksum, data, len);
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright © 2015 Red Hat, Inc
|
||||
*
|
||||
* This program 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __BUILDER_CACHE_H__
|
||||
#define __BUILDER_CACHE_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct BuilderCache BuilderCache;
|
||||
|
||||
#define BUILDER_TYPE_CACHE (builder_cache_get_type())
|
||||
#define BUILDER_CACHE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BUILDER_TYPE_CACHE, BuilderCache))
|
||||
#define BUILDER_IS_CACHE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BUILDER_TYPE_CACHE))
|
||||
|
||||
GType builder_cache_get_type (void);
|
||||
|
||||
BuilderCache *builder_cache_new (GFile *cache_dir,
|
||||
GFile *app_dir,
|
||||
const char *branch);
|
||||
void builder_cache_disable_lookups (BuilderCache *self);
|
||||
gboolean builder_cache_open (BuilderCache *self,
|
||||
GError **error);
|
||||
GChecksum * builder_cache_get_checksum (BuilderCache *self);
|
||||
gboolean builder_cache_lookup (BuilderCache *self);
|
||||
void builder_cache_ensure_checkout (BuilderCache *self);
|
||||
gboolean builder_cache_commit (BuilderCache *self,
|
||||
const char *body,
|
||||
GError **error);
|
||||
GPtrArray *builder_cache_get_changes (BuilderCache *self,
|
||||
GError **error);
|
||||
gboolean builder_gc (BuilderCache *self,
|
||||
GError **error);
|
||||
|
||||
void builder_cache_checksum_str (BuilderCache *self,
|
||||
const char *str);
|
||||
void builder_cache_checksum_strv (BuilderCache *self,
|
||||
char **strv);
|
||||
void builder_cache_checksum_boolean (BuilderCache *self,
|
||||
gboolean val);
|
||||
void builder_cache_checksum_uint32 (BuilderCache *self,
|
||||
guint32 val);
|
||||
void builder_cache_checksum_data (BuilderCache *self,
|
||||
guint8 *data,
|
||||
gsize len);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(BuilderCache, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __BUILDER_CACHE_H__ */
|
|
@ -0,0 +1,264 @@
|
|||
/* builder-context.c
|
||||
*
|
||||
* Copyright (C) 2015 Red Hat, Inc
|
||||
*
|
||||
* This file 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 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This file 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 General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/statfs.h>
|
||||
|
||||
#include "builder-context.h"
|
||||
#include "xdg-app-utils.h"
|
||||
|
||||
struct BuilderContext {
|
||||
GObject parent;
|
||||
|
||||
GFile *app_dir;
|
||||
GFile *base_dir;
|
||||
SoupSession *soup_session;
|
||||
char *arch;
|
||||
|
||||
GFile *download_dir;
|
||||
GFile *state_dir;
|
||||
GFile *cache_dir;
|
||||
|
||||
BuilderOptions *options;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
GObjectClass parent_class;
|
||||
} BuilderContextClass;
|
||||
|
||||
G_DEFINE_TYPE (BuilderContext, builder_context, G_TYPE_OBJECT);
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_APP_DIR,
|
||||
PROP_BASE_DIR,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
builder_context_finalize (GObject *object)
|
||||
{
|
||||
BuilderContext *self = (BuilderContext *)object;
|
||||
|
||||
g_clear_object (&self->app_dir);
|
||||
g_clear_object (&self->base_dir);
|
||||
g_clear_object (&self->soup_session);
|
||||
g_clear_object (&self->options);
|
||||
g_free (self->arch);
|
||||
|
||||
G_OBJECT_CLASS (builder_context_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
builder_context_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BuilderContext *self = BUILDER_CONTEXT (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_BASE_DIR:
|
||||
g_value_set_object (value, self->base_dir);
|
||||
break;
|
||||
|
||||
case PROP_APP_DIR:
|
||||
g_value_set_object (value, self->app_dir);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
builder_context_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BuilderContext *self = BUILDER_CONTEXT (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_BASE_DIR:
|
||||
g_set_object (&self->base_dir, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_APP_DIR:
|
||||
g_set_object (&self->app_dir, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
builder_context_constructed (GObject *object)
|
||||
{
|
||||
BuilderContext *self = BUILDER_CONTEXT (object);
|
||||
|
||||
self->state_dir = g_file_get_child (self->base_dir, ".xdg-app-builder");
|
||||
self->download_dir = g_file_get_child (self->state_dir, "downloads");
|
||||
self->cache_dir = g_file_get_child (self->state_dir, "cache");
|
||||
}
|
||||
|
||||
static void
|
||||
builder_context_class_init (BuilderContextClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->constructed = builder_context_constructed;
|
||||
object_class->finalize = builder_context_finalize;
|
||||
object_class->get_property = builder_context_get_property;
|
||||
object_class->set_property = builder_context_set_property;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_APP_DIR,
|
||||
g_param_spec_object ("app-dir",
|
||||
"",
|
||||
"",
|
||||
G_TYPE_FILE,
|
||||
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_BASE_DIR,
|
||||
g_param_spec_object ("base-dir",
|
||||
"",
|
||||
"",
|
||||
G_TYPE_FILE,
|
||||
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
|
||||
}
|
||||
|
||||
static void
|
||||
builder_context_init (BuilderContext *self)
|
||||
{
|
||||
}
|
||||
|
||||
GFile *
|
||||
builder_context_get_base_dir (BuilderContext *self)
|
||||
{
|
||||
return self->base_dir;
|
||||
}
|
||||
|
||||
GFile *
|
||||
builder_context_get_state_dir (BuilderContext *self)
|
||||
{
|
||||
return self->state_dir;
|
||||
}
|
||||
|
||||
GFile *
|
||||
builder_context_get_app_dir (BuilderContext *self)
|
||||
{
|
||||
return self->app_dir;
|
||||
}
|
||||
|
||||
GFile *
|
||||
builder_context_get_download_dir (BuilderContext *self)
|
||||
{
|
||||
return self->download_dir;
|
||||
}
|
||||
|
||||
GFile *
|
||||
builder_context_get_cache_dir (BuilderContext *self)
|
||||
{
|
||||
return self->cache_dir;
|
||||
}
|
||||
|
||||
SoupSession *
|
||||
builder_context_get_soup_session (BuilderContext *self)
|
||||
{
|
||||
if (self->soup_session == NULL)
|
||||
{
|
||||
const char *http_proxy;
|
||||
|
||||
self->soup_session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT, "xdg-app-builder ",
|
||||
SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE,
|
||||
SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
|
||||
SOUP_SESSION_TIMEOUT, 60,
|
||||
SOUP_SESSION_IDLE_TIMEOUT, 60,
|
||||
NULL);
|
||||
http_proxy = g_getenv ("http_proxy");
|
||||
if (http_proxy)
|
||||
{
|
||||
g_autoptr(SoupURI) proxy_uri = soup_uri_new (http_proxy);
|
||||
if (!proxy_uri)
|
||||
g_warning ("Invalid proxy URI '%s'", http_proxy);
|
||||
else
|
||||
g_object_set (self->soup_session, SOUP_SESSION_PROXY_URI, proxy_uri, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return self->soup_session;
|
||||
}
|
||||
|
||||
const char *
|
||||
builder_context_get_arch (BuilderContext *self)
|
||||
{
|
||||
if (self->arch == NULL)
|
||||
self->arch = g_strdup (xdg_app_get_arch ());
|
||||
|
||||
return (const char *)self->arch;
|
||||
}
|
||||
|
||||
void
|
||||
builder_context_set_arch (BuilderContext *self,
|
||||
const char *arch)
|
||||
{
|
||||
g_free (self->arch);
|
||||
self->arch = g_strdup (arch);
|
||||
}
|
||||
|
||||
BuilderOptions *
|
||||
builder_context_get_options (BuilderContext *self)
|
||||
{
|
||||
return self->options;
|
||||
}
|
||||
|
||||
void
|
||||
builder_context_set_options (BuilderContext *self,
|
||||
BuilderOptions *option)
|
||||
{
|
||||
g_set_object (&self->options, option);
|
||||
}
|
||||
|
||||
int
|
||||
builder_context_get_n_cpu (BuilderContext *self)
|
||||
{
|
||||
return (int)sysconf (_SC_NPROCESSORS_ONLN);
|
||||
}
|
||||
|
||||
BuilderContext *
|
||||
builder_context_new (GFile *base_dir,
|
||||
GFile *app_dir)
|
||||
{
|
||||
return g_object_new (BUILDER_TYPE_CONTEXT,
|
||||
"base-dir", base_dir,
|
||||
"app-dir", app_dir,
|
||||
NULL);
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright © 2015 Red Hat, Inc
|
||||
*
|
||||
* This program 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __BUILDER_CONTEXT_H__
|
||||
#define __BUILDER_CONTEXT_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <libsoup/soup.h>
|
||||
#include "builder-options.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* BuilderContext defined in builder-options.h to fix include loop */
|
||||
|
||||
#define BUILDER_TYPE_CONTEXT (builder_context_get_type())
|
||||
#define BUILDER_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BUILDER_TYPE_CONTEXT, BuilderContext))
|
||||
#define BUILDER_IS_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BUILDER_TYPE_CONTEXT))
|
||||
|
||||
GType builder_context_get_type (void);
|
||||
|
||||
GFile * builder_context_get_app_dir (BuilderContext *self);
|
||||
GFile * builder_context_get_base_dir (BuilderContext *self);
|
||||
GFile * builder_context_get_state_dir (BuilderContext *self);
|
||||
GFile * builder_context_get_cache_dir (BuilderContext *self);
|
||||
GFile * builder_context_get_download_dir (BuilderContext *self);
|
||||
SoupSession * builder_context_get_soup_session (BuilderContext *self);
|
||||
const char * builder_context_get_arch (BuilderContext *self);
|
||||
void builder_context_set_arch (BuilderContext *self,
|
||||
const char *arch);
|
||||
int builder_context_get_n_cpu (BuilderContext *self);
|
||||
BuilderOptions *builder_context_get_options (BuilderContext *self);
|
||||
void builder_context_set_options (BuilderContext *self,
|
||||
BuilderOptions *option);
|
||||
|
||||
BuilderContext *builder_context_new (GFile *base_dir,
|
||||
GFile *app_dir);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(BuilderContext, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __BUILDER_CONTEXT_H__ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright © 2015 Red Hat, Inc
|
||||
*
|
||||
* This program 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __BUILDER_MANIFEST_H__
|
||||
#define __BUILDER_MANIFEST_H__
|
||||
|
||||
#include <json-glib/json-glib.h>
|
||||
|
||||
#include "builder-options.h"
|
||||
#include "builder-module.h"
|
||||
#include "builder-cache.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct BuilderManifest BuilderManifest;
|
||||
|
||||
#define BUILDER_TYPE_MANIFEST (builder_manifest_get_type())
|
||||
#define BUILDER_MANIFEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BUILDER_TYPE_MANIFEST, BuilderManifest))
|
||||
#define BUILDER_IS_MANIFEST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BUILDER_TYPE_MANIFEST))
|
||||
|
||||
/* Bump this if format changes in incompatible ways to force rebuild */
|
||||
#define BUILDER_MANIFEST_CHECKSUM_VERSION "1"
|
||||
|
||||
GType builder_manifest_get_type (void);
|
||||
|
||||
const char * builder_manifest_get_app_id (BuilderManifest *self);
|
||||
BuilderOptions *builder_manifest_get_build_options (BuilderManifest *self);
|
||||
GList * builder_manifest_get_modules (BuilderManifest *self);
|
||||
|
||||
gboolean builder_manifest_init_app_dir (BuilderManifest *self,
|
||||
BuilderContext *context,
|
||||
GError **error);
|
||||
gboolean builder_manifest_download (BuilderManifest *self,
|
||||
BuilderContext *context,
|
||||
GError **error);
|
||||
gboolean builder_manifest_build (BuilderManifest *self,
|
||||
BuilderCache *cache,
|
||||
BuilderContext *context,
|
||||
GError **error);
|
||||
void builder_manifest_checksum (BuilderManifest *self,
|
||||
BuilderCache *cache,
|
||||
BuilderContext *context);
|
||||
gboolean builder_manifest_cleanup (BuilderManifest *self,
|
||||
BuilderCache *cache,
|
||||
BuilderContext *context,
|
||||
GError **error);
|
||||
gboolean builder_manifest_finish (BuilderManifest *self,
|
||||
BuilderCache *cache,
|
||||
BuilderContext *context,
|
||||
GError **error);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(BuilderManifest, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __BUILDER_MANIFEST_H__ */
|
|
@ -0,0 +1,784 @@
|
|||
/* builder-module.c
|
||||
*
|
||||
* Copyright (C) 2015 Red Hat, Inc
|
||||
*
|
||||
* This file 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 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This file 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 General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/statfs.h>
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include "libglnx/libglnx.h"
|
||||
#include "libgsystem.h"
|
||||
|
||||
#include "builder-utils.h"
|
||||
#include "builder-module.h"
|
||||
|
||||
struct BuilderModule {
|
||||
GObject parent;
|
||||
|
||||
char *name;
|
||||
char **config_opts;
|
||||
char **make_args;
|
||||
char **make_install_args;
|
||||
gboolean rm_configure;
|
||||
gboolean no_autogen;
|
||||
BuilderOptions *build_options;
|
||||
GPtrArray *changes;
|
||||
char **cleanup;
|
||||
GList *sources;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
GObjectClass parent_class;
|
||||
} BuilderModuleClass;
|
||||
|
||||
static void serializable_iface_init (JsonSerializableIface *serializable_iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (BuilderModule, builder_module, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (JSON_TYPE_SERIALIZABLE, serializable_iface_init));
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_NAME,
|
||||
PROP_RM_CONFIGURE,
|
||||
PROP_NO_AUTOGEN,
|
||||
PROP_CONFIG_OPTS,
|
||||
PROP_MAKE_ARGS,
|
||||
PROP_MAKE_INSTALL_ARGS,
|
||||
PROP_SOURCES,
|
||||
PROP_BUILD_OPTIONS,
|
||||
PROP_CLEANUP,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
builder_module_finalize (GObject *object)
|
||||
{
|
||||
BuilderModule *self = (BuilderModule *)object;
|
||||
|
||||
g_free (self->name);
|
||||
g_strfreev (self->config_opts);
|
||||
g_strfreev (self->make_args);
|
||||
g_strfreev (self->make_install_args);
|
||||
g_clear_object (&self->build_options);
|
||||
g_list_free_full (self->sources, g_object_unref);
|
||||
g_strfreev (self->cleanup);
|
||||
|
||||
if (self->changes)
|
||||
g_ptr_array_unref (self->changes);
|
||||
|
||||
G_OBJECT_CLASS (builder_module_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
builder_module_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BuilderModule *self = BUILDER_MODULE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_NAME:
|
||||
g_value_set_string (value, self->name);
|
||||
break;
|
||||
|
||||
case PROP_RM_CONFIGURE:
|
||||
g_value_set_boolean (value, self->rm_configure);
|
||||
break;
|
||||
|
||||
case PROP_NO_AUTOGEN:
|
||||
g_value_set_boolean (value, self->no_autogen);
|
||||
break;
|
||||
|
||||
case PROP_CONFIG_OPTS:
|
||||
g_value_set_boxed (value, self->config_opts);
|
||||
break;
|
||||
|
||||
case PROP_MAKE_ARGS:
|
||||
g_value_set_boxed (value, self->make_args);
|
||||
break;
|
||||
|
||||
case PROP_MAKE_INSTALL_ARGS:
|
||||
g_value_set_boxed (value, self->make_install_args);
|
||||
break;
|
||||
|
||||
case PROP_BUILD_OPTIONS:
|
||||
g_value_set_object (value, self->build_options);
|
||||
break;
|
||||
|
||||
case PROP_SOURCES:
|
||||
g_value_set_pointer (value, self->sources);
|
||||
break;
|
||||
|
||||
case PROP_CLEANUP:
|
||||
g_value_set_boxed (value, self->cleanup);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
builder_module_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BuilderModule *self = BUILDER_MODULE (object);
|
||||
gchar **tmp;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_NAME:
|
||||
g_clear_pointer (&self->name, g_free);
|
||||
self->name = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
case PROP_RM_CONFIGURE:
|
||||
self->rm_configure = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
case PROP_NO_AUTOGEN:
|
||||
self->no_autogen = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
case PROP_CONFIG_OPTS:
|
||||
tmp = self->config_opts;
|
||||
self->config_opts = g_strdupv (g_value_get_boxed (value));
|
||||
g_strfreev (tmp);
|
||||
break;
|
||||
|
||||
case PROP_MAKE_ARGS:
|
||||
tmp = self->make_args;
|
||||
self->make_args = g_strdupv (g_value_get_boxed (value));
|
||||
g_strfreev (tmp);
|
||||
break;
|
||||
|
||||
case PROP_MAKE_INSTALL_ARGS:
|
||||
tmp = self->make_install_args;
|
||||
self->make_install_args = g_strdupv (g_value_get_boxed (value));
|
||||
g_strfreev (tmp);
|
||||
break;
|
||||
|
||||
case PROP_BUILD_OPTIONS:
|
||||
g_set_object (&self->build_options, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_SOURCES:
|
||||
g_list_free_full (self->sources, g_object_unref);
|
||||
/* NOTE: This takes ownership of the list! */
|
||||
self->sources = g_value_get_pointer (value);
|
||||
break;
|
||||
|
||||
case PROP_CLEANUP:
|
||||
tmp = self->cleanup;
|
||||
self->cleanup = g_strdupv (g_value_get_boxed (value));
|
||||
g_strfreev (tmp);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
builder_module_class_init (BuilderModuleClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = builder_module_finalize;
|
||||
object_class->get_property = builder_module_get_property;
|
||||
object_class->set_property = builder_module_set_property;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_NAME,
|
||||
g_param_spec_string ("name",
|
||||
"",
|
||||
"",
|
||||
NULL,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_RM_CONFIGURE,
|
||||
g_param_spec_boolean ("rm-configure",
|
||||
"",
|
||||
"",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_NO_AUTOGEN,
|
||||
g_param_spec_boolean ("no-autogen",
|
||||
"",
|
||||
"",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_SOURCES,
|
||||
g_param_spec_pointer ("sources",
|
||||
"",
|
||||
"",
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_CONFIG_OPTS,
|
||||
g_param_spec_boxed ("config-opts",
|
||||
"",
|
||||
"",
|
||||
G_TYPE_STRV,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_MAKE_ARGS,
|
||||
g_param_spec_boxed ("make-args",
|
||||
"",
|
||||
"",
|
||||
G_TYPE_STRV,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_MAKE_INSTALL_ARGS,
|
||||
g_param_spec_boxed ("make-install-args",
|
||||
"",
|
||||
"",
|
||||
G_TYPE_STRV,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_BUILD_OPTIONS,
|
||||
g_param_spec_object ("build-options",
|
||||
"",
|
||||
"",
|
||||
BUILDER_TYPE_OPTIONS,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_CLEANUP,
|
||||
g_param_spec_boxed ("cleanup",
|
||||
"",
|
||||
"",
|
||||
G_TYPE_STRV,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
builder_module_init (BuilderModule *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
builder_module_deserialize_property (JsonSerializable *serializable,
|
||||
const gchar *property_name,
|
||||
GValue *value,
|
||||
GParamSpec *pspec,
|
||||
JsonNode *property_node)
|
||||
{
|
||||
if (strcmp (property_name, "sources") == 0)
|
||||
{
|
||||
if (JSON_NODE_TYPE (property_node) == JSON_NODE_NULL)
|
||||
{
|
||||
g_value_set_pointer (value, NULL);
|
||||
return TRUE;
|
||||
}
|
||||
else if (JSON_NODE_TYPE (property_node) == JSON_NODE_ARRAY)
|
||||
{
|
||||
JsonArray *array = json_node_get_array (property_node);
|
||||
guint i, array_len = json_array_get_length (array);
|
||||
GList *sources = NULL;
|
||||
BuilderSource *source;
|
||||
|
||||
for (i = 0; i < array_len; i++)
|
||||
{
|
||||
JsonNode *element_node = json_array_get_element (array, i);
|
||||
|
||||
if (JSON_NODE_TYPE (element_node) != JSON_NODE_OBJECT)
|
||||
{
|
||||
g_list_free_full (sources, g_object_unref);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
source = builder_source_from_json (element_node);
|
||||
if (source == NULL)
|
||||
{
|
||||
g_list_free_full (sources, g_object_unref);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sources = g_list_prepend (sources, source);
|
||||
}
|
||||
|
||||
g_value_set_pointer (value, g_list_reverse (sources));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
return json_serializable_default_deserialize_property (serializable,
|
||||
property_name,
|
||||
value,
|
||||
pspec, property_node);
|
||||
}
|
||||
|
||||
static void
|
||||
serializable_iface_init (JsonSerializableIface *serializable_iface)
|
||||
{
|
||||
serializable_iface->deserialize_property = builder_module_deserialize_property;
|
||||
}
|
||||
|
||||
const char *
|
||||
builder_module_get_name (BuilderModule *self)
|
||||
{
|
||||
return self->name;
|
||||
}
|
||||
|
||||
GList *
|
||||
builder_module_get_sources (BuilderModule *self)
|
||||
{
|
||||
return self->sources;
|
||||
}
|
||||
|
||||
gboolean
|
||||
builder_module_download_sources (BuilderModule *self,
|
||||
BuilderContext *context,
|
||||
GError **error)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = self->sources; l != NULL; l = l->next)
|
||||
{
|
||||
BuilderSource *source = l->data;
|
||||
|
||||
if (!builder_source_download (source, context, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
builder_module_extract_sources (BuilderModule *self,
|
||||
GFile *dest,
|
||||
BuilderContext *context,
|
||||
GError **error)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
if (!g_file_query_exists (dest, NULL) &&
|
||||
!g_file_make_directory_with_parents (dest, NULL, error))
|
||||
return FALSE;
|
||||
|
||||
for (l = self->sources; l != NULL; l = l->next)
|
||||
{
|
||||
BuilderSource *source = l->data;
|
||||
|
||||
if (!builder_source_extract (source, dest, context, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static const char skip_arg[] = "skip";
|
||||
static const char strv_arg[] = "strv";
|
||||
|
||||
static gboolean
|
||||
build (GFile *app_dir,
|
||||
GFile *source_dir,
|
||||
GFile *cwd_dir,
|
||||
char **xdg_app_opts,
|
||||
char **env_vars,
|
||||
GError **error,
|
||||
const gchar *argv1,
|
||||
...)
|
||||
{
|
||||
g_autoptr(GSubprocessLauncher) launcher = NULL;
|
||||
g_autoptr(GSubprocess) subp = NULL;
|
||||
g_autoptr(GPtrArray) args = NULL;
|
||||
const gchar *arg;
|
||||
const gchar **argv;
|
||||
g_autofree char *commandline = NULL;
|
||||
g_autofree char *source_dir_path = g_file_get_path (source_dir);
|
||||
g_autofree char *source_dir_path_canonical = NULL;
|
||||
g_autofree char *cwd_dir_path = NULL;
|
||||
g_autofree char *cwd_dir_path_canonical = NULL;
|
||||
va_list ap;
|
||||
int i;
|
||||
|
||||
args = g_ptr_array_new_with_free_func (g_free);
|
||||
g_ptr_array_add (args, g_strdup ("xdg-app"));
|
||||
g_ptr_array_add (args, g_strdup ("build"));
|
||||
|
||||
source_dir_path_canonical = canonicalize_file_name (source_dir_path);
|
||||
|
||||
g_ptr_array_add (args, g_strdup ("--nofilesystem=host"));
|
||||
g_ptr_array_add (args, g_strdup_printf ("--filesystem=%s", source_dir_path_canonical));
|
||||
|
||||
if (xdg_app_opts)
|
||||
{
|
||||
for (i = 0; xdg_app_opts[i] != NULL; i++)
|
||||
g_ptr_array_add (args, g_strdup (xdg_app_opts[i]));
|
||||
}
|
||||
|
||||
if (env_vars)
|
||||
{
|
||||
for (i = 0; env_vars[i] != NULL; i++)
|
||||
g_ptr_array_add (args, g_strdup_printf ("--env=%s", env_vars[i]));
|
||||
}
|
||||
g_ptr_array_add (args, g_file_get_path (app_dir));
|
||||
va_start (ap, argv1);
|
||||
g_ptr_array_add (args, g_strdup (argv1));
|
||||
while ((arg = va_arg (ap, const gchar *)))
|
||||
{
|
||||
if (arg == strv_arg)
|
||||
{
|
||||
argv = va_arg (ap, const gchar **);
|
||||
if (argv != NULL)
|
||||
{
|
||||
for (i = 0; argv[i] != NULL; i++)
|
||||
g_ptr_array_add (args, g_strdup (argv[i]));
|
||||
}
|
||||
}
|
||||
else if (arg != skip_arg)
|
||||
g_ptr_array_add (args, g_strdup (arg));
|
||||
}
|
||||
g_ptr_array_add (args, NULL);
|
||||
va_end (ap);
|
||||
|
||||
commandline = g_strjoinv (" ", (char **) args->pdata);
|
||||
g_print ("Running: %s\n", commandline);
|
||||
|
||||
launcher = g_subprocess_launcher_new (0);
|
||||
|
||||
if (cwd_dir)
|
||||
{
|
||||
cwd_dir_path = g_file_get_path (cwd_dir);
|
||||
cwd_dir_path_canonical = canonicalize_file_name (cwd_dir_path);
|
||||
g_subprocess_launcher_set_cwd (launcher, cwd_dir_path_canonical);
|
||||
}
|
||||
else
|
||||
g_subprocess_launcher_set_cwd (launcher, source_dir_path_canonical);
|
||||
|
||||
subp = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
|
||||
g_ptr_array_free (args, TRUE);
|
||||
|
||||
if (subp == NULL ||
|
||||
!g_subprocess_wait_check (subp, NULL, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
builder_module_build (BuilderModule *self,
|
||||
BuilderContext *context,
|
||||
GError **error)
|
||||
{
|
||||
GFile *app_dir = builder_context_get_app_dir (context);
|
||||
g_autofree char *make_j = NULL;
|
||||
g_autofree char *make_l = NULL;
|
||||
g_autofree char *makefile_content = NULL;
|
||||
g_autoptr(GFile) configure_file = NULL;
|
||||
const char *makefile_names[] = {"Makefile", "makefile", "GNUmakefile", NULL};
|
||||
g_autoptr(GFile) build_dir = NULL;
|
||||
gboolean has_configure;
|
||||
gboolean var_require_builddir;
|
||||
gboolean has_notparallel;
|
||||
gboolean use_builddir;
|
||||
int i;
|
||||
g_auto(GStrv) env = NULL;
|
||||
g_auto(GStrv) build_args = NULL;
|
||||
const char *cflags, *cxxflags;
|
||||
g_autofree char *buildname = NULL;
|
||||
g_autoptr(GFile) source_dir = NULL;
|
||||
g_autoptr(GFile) source_dir_template = NULL;
|
||||
g_autofree char *source_dir_path = NULL;
|
||||
|
||||
buildname = g_strdup_printf ("build-%s-XXXXXX", self->name);
|
||||
|
||||
source_dir_template = g_file_get_child (builder_context_get_state_dir (context),
|
||||
buildname);
|
||||
source_dir_path = g_file_get_path (source_dir_template);;
|
||||
|
||||
if (g_mkdtemp (source_dir_path) == NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Can't create build directory");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
source_dir = g_file_new_for_path (source_dir_path);
|
||||
|
||||
g_print ("Building module %s in %s\n", self->name, source_dir_path);
|
||||
|
||||
if (!builder_module_extract_sources (self, source_dir, context, error))
|
||||
return FALSE;
|
||||
|
||||
env = builder_options_get_env (self->build_options, context);
|
||||
build_args = builder_options_get_build_args (self->build_options, context);
|
||||
|
||||
cflags = builder_options_get_cflags (self->build_options, context);
|
||||
if (cflags)
|
||||
env = g_environ_setenv (env, "CFLAGS", cflags, TRUE);
|
||||
|
||||
cxxflags = builder_options_get_cxxflags (self->build_options, context);
|
||||
if (cxxflags)
|
||||
env = g_environ_setenv (env, "CXXFLAGS", cxxflags, TRUE);
|
||||
|
||||
configure_file = g_file_get_child (source_dir, "configure");
|
||||
|
||||
if (self->rm_configure)
|
||||
{
|
||||
if (!g_file_delete (configure_file, NULL, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
has_configure = g_file_query_exists (configure_file, NULL);
|
||||
|
||||
if (!has_configure && !self->no_autogen)
|
||||
{
|
||||
const char *autogen_names[] = {"autogen", "autogen.sh", "bootstrap", NULL};
|
||||
g_autofree char *autogen_cmd = NULL;
|
||||
g_auto(GStrv) env_with_noconfigure = NULL;
|
||||
|
||||
for (i = 0; autogen_names[i] != NULL; i++)
|
||||
{
|
||||
g_autoptr(GFile) autogen_file = g_file_get_child (source_dir, autogen_names[i]);
|
||||
if (g_file_query_exists (autogen_file, NULL))
|
||||
{
|
||||
autogen_cmd = g_strdup_printf ("./%s", autogen_names[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (autogen_cmd == NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Can't find autogen, autogen.sh or bootstrap");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
env_with_noconfigure = g_environ_setenv (g_strdupv (env), "NOCONFIGURE", "1", TRUE);
|
||||
if (!build (app_dir, source_dir, NULL, build_args, env_with_noconfigure, error,
|
||||
autogen_cmd, NULL))
|
||||
return FALSE;
|
||||
|
||||
if (!g_file_query_exists (configure_file, NULL))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "autogen did not create configure");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
has_configure = TRUE;
|
||||
}
|
||||
|
||||
if (has_configure)
|
||||
{
|
||||
const char *configure_cmd;
|
||||
g_autofree char *configure_content = NULL;
|
||||
|
||||
if (!g_file_load_contents (configure_file, NULL, &configure_content, NULL, NULL, error))
|
||||
return FALSE;
|
||||
|
||||
var_require_builddir = strstr (configure_content, "buildapi-variable-require-builddir") != NULL;
|
||||
use_builddir = var_require_builddir;
|
||||
|
||||
if (use_builddir)
|
||||
{
|
||||
build_dir = g_file_get_child (source_dir, "_build");
|
||||
configure_cmd = "../configure";
|
||||
}
|
||||
else
|
||||
{
|
||||
build_dir = g_object_ref (source_dir);
|
||||
configure_cmd = "./configure";
|
||||
}
|
||||
|
||||
if (!build (app_dir, source_dir, build_dir, build_args, env, error,
|
||||
configure_cmd, "--prefix=/app", strv_arg, self->config_opts, NULL))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
build_dir = g_object_ref (source_dir);
|
||||
|
||||
for (i = 0; makefile_names[i] != NULL; i++)
|
||||
{
|
||||
g_autoptr(GFile) makefile_file = g_file_get_child (build_dir, makefile_names[i]);
|
||||
if (g_file_query_exists (makefile_file, NULL))
|
||||
{
|
||||
if (!g_file_load_contents (makefile_file, NULL, &makefile_content, NULL, NULL, error))
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (makefile_content == NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Can't find makefile");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
has_notparallel =
|
||||
g_str_has_prefix (makefile_content, ".NOTPARALLEL") ||
|
||||
(strstr (makefile_content, "\n.NOTPARALLEL") != NULL);
|
||||
|
||||
if (!has_notparallel)
|
||||
{
|
||||
make_j = g_strdup_printf ("-j%d", builder_context_get_n_cpu (context));
|
||||
make_l = g_strdup_printf ("-l%d", 2*builder_context_get_n_cpu (context));
|
||||
}
|
||||
|
||||
if (!build (app_dir, source_dir, build_dir, build_args, env, error,
|
||||
"make", "all", make_j?make_j:skip_arg, make_l?make_l:skip_arg, strv_arg, self->make_args, NULL))
|
||||
return FALSE;
|
||||
|
||||
if (!build (app_dir, source_dir, build_dir, build_args, env, error,
|
||||
"make", "install", strv_arg, self->make_install_args, NULL))
|
||||
return FALSE;
|
||||
|
||||
if (!gs_shutil_rm_rf (source_dir, NULL, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
builder_module_checksum (BuilderModule *self,
|
||||
BuilderCache *cache,
|
||||
BuilderContext *context)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
builder_cache_checksum_str (cache, BUILDER_MODULE_CHECKSUM_VERSION);
|
||||
builder_cache_checksum_str (cache, self->name);
|
||||
builder_cache_checksum_strv (cache, self->config_opts);
|
||||
builder_cache_checksum_strv (cache, self->make_args);
|
||||
builder_cache_checksum_strv (cache, self->make_install_args);
|
||||
builder_cache_checksum_boolean (cache, self->rm_configure);
|
||||
builder_cache_checksum_boolean (cache, self->no_autogen);
|
||||
|
||||
for (l = self->sources; l != NULL; l = l->next)
|
||||
{
|
||||
BuilderSource *source = l->data;
|
||||
|
||||
builder_source_checksum (source, cache, context);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
builder_module_checksum_for_cleanup (BuilderModule *self,
|
||||
BuilderCache *cache,
|
||||
BuilderContext *context)
|
||||
{
|
||||
builder_cache_checksum_str (cache, BUILDER_MODULE_CHECKSUM_VERSION);
|
||||
builder_cache_checksum_str (cache, self->name);
|
||||
builder_cache_checksum_strv (cache, self->cleanup);
|
||||
}
|
||||
|
||||
GPtrArray *
|
||||
builder_module_get_changes (BuilderModule *self)
|
||||
{
|
||||
return self->changes;
|
||||
}
|
||||
|
||||
void
|
||||
builder_module_set_changes (BuilderModule *self,
|
||||
GPtrArray *changes)
|
||||
{
|
||||
if (self->changes != changes)
|
||||
{
|
||||
if (self->changes)
|
||||
g_ptr_array_unref (self->changes);
|
||||
self->changes = g_ptr_array_ref (changes);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
collect_for_pattern (BuilderModule *self,
|
||||
const char *pattern,
|
||||
const char *path,
|
||||
GHashTable *to_remove_ht)
|
||||
{
|
||||
const char *rest;
|
||||
const char *last_slash;
|
||||
g_autofree char *dir = NULL;
|
||||
|
||||
if (pattern[0] == '/')
|
||||
{
|
||||
/* Absolute path match */
|
||||
rest = path_prefix_match (pattern+1, path);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Basename match */
|
||||
last_slash = strrchr (path, '/');
|
||||
if (last_slash)
|
||||
{
|
||||
dir = g_strndup (path, last_slash - path);
|
||||
path = last_slash + 1;
|
||||
}
|
||||
rest = path_prefix_match (pattern, path);
|
||||
}
|
||||
|
||||
while (rest != NULL)
|
||||
{
|
||||
const char *slash;
|
||||
g_autofree char *prefix = g_strndup (path, rest-path);
|
||||
g_autofree char *to_remove = NULL;
|
||||
if (dir)
|
||||
to_remove = g_strconcat (dir, "/", prefix, NULL);
|
||||
else
|
||||
to_remove = g_strdup (prefix);
|
||||
g_hash_table_insert (to_remove_ht, g_steal_pointer (&to_remove), GINT_TO_POINTER (1));
|
||||
while (*rest == '/')
|
||||
rest++;
|
||||
if (*rest == 0)
|
||||
break;
|
||||
slash = strchr (rest, '/');
|
||||
rest = slash ? slash : rest + strlen (rest);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
builder_module_cleanup_collect (BuilderModule *self,
|
||||
char **global_patterns,
|
||||
GHashTable *to_remove_ht)
|
||||
{
|
||||
GPtrArray *changed_files;
|
||||
int i, j;
|
||||
|
||||
changed_files = self->changes;
|
||||
for (i = 0; i < changed_files->len; i++)
|
||||
{
|
||||
const char *path = g_ptr_array_index (changed_files, i);
|
||||
|
||||
if (global_patterns)
|
||||
{
|
||||
for (j = 0; global_patterns[j] != NULL; j++)
|
||||
collect_for_pattern (self, global_patterns[j], path, to_remove_ht);
|
||||
}
|
||||
|
||||
if (self->cleanup)
|
||||
{
|
||||
for (j = 0; self->cleanup[j] != NULL; j++)
|
||||
collect_for_pattern (self, self->cleanup[j], path, to_remove_ht);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright © 2015 Red Hat, Inc
|
||||
*
|
||||
* This program 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __BUILDER_MODULE_H__
|
||||
#define __BUILDER_MODULE_H__
|
||||
|
||||
#include <json-glib/json-glib.h>
|
||||
|
||||
#include "builder-source.h"
|
||||
#include "builder-options.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct BuilderModule BuilderModule;
|
||||
|
||||
#define BUILDER_TYPE_MODULE (builder_module_get_type())
|
||||
#define BUILDER_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BUILDER_TYPE_MODULE, BuilderModule))
|
||||
#define BUILDER_IS_MODULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BUILDER_TYPE_MODULE))
|
||||
|
||||
/* Bump this if format changes in incompatible ways to force rebuild */
|
||||
#define BUILDER_MODULE_CHECKSUM_VERSION "1"
|
||||
|
||||
GType builder_module_get_type (void);
|
||||
|
||||
const char * builder_module_get_name (BuilderModule *self);
|
||||
GList * builder_module_get_sources (BuilderModule *self);
|
||||
GPtrArray * builder_module_get_changes (BuilderModule *self);
|
||||
void builder_module_set_changes (BuilderModule *self,
|
||||
GPtrArray *changes);
|
||||
|
||||
gboolean builder_module_download_sources (BuilderModule *self,
|
||||
BuilderContext *context,
|
||||
GError **error);
|
||||
gboolean builder_module_extract_sources (BuilderModule *self,
|
||||
GFile *dest,
|
||||
BuilderContext *context,
|
||||
GError **error);
|
||||
gboolean builder_module_build (BuilderModule *self,
|
||||
BuilderContext *context,
|
||||
GError **error);
|
||||
|
||||
void builder_module_checksum (BuilderModule *self,
|
||||
BuilderCache *cache,
|
||||
BuilderContext *context);
|
||||
void builder_module_checksum_for_cleanup (BuilderModule *self,
|
||||
BuilderCache *cache,
|
||||
BuilderContext *context);
|
||||
void builder_module_cleanup_collect (BuilderModule *self,
|
||||
char **global_patterns,
|
||||
GHashTable *to_remove_ht);
|
||||
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(BuilderModule, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __BUILDER_MODULE_H__ */
|
|
@ -0,0 +1,445 @@
|
|||
/* builder-options.c
|
||||
*
|
||||
* Copyright (C) 2015 Red Hat, Inc
|
||||
*
|
||||
* This file 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 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This file 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 General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/statfs.h>
|
||||
|
||||
#include "builder-options.h"
|
||||
#include "builder-context.h"
|
||||
#include "builder-utils.h"
|
||||
|
||||
struct BuilderOptions {
|
||||
GObject parent;
|
||||
|
||||
char *cflags;
|
||||
char *cxxflags;
|
||||
char **env;
|
||||
char **build_args;
|
||||
GHashTable *arch;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
GObjectClass parent_class;
|
||||
} BuilderOptionsClass;
|
||||
|
||||
static void serializable_iface_init (JsonSerializableIface *serializable_iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (BuilderOptions, builder_options, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (JSON_TYPE_SERIALIZABLE, serializable_iface_init));
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_CFLAGS,
|
||||
PROP_CXXFLAGS,
|
||||
PROP_ENV,
|
||||
PROP_ARCH,
|
||||
PROP_BUILD_ARGS,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
builder_options_finalize (GObject *object)
|
||||
{
|
||||
BuilderOptions *self = (BuilderOptions *)object;
|
||||
|
||||
g_free (self->cflags);
|
||||
g_free (self->cxxflags);
|
||||
g_strfreev (self->env);
|
||||
g_strfreev (self->build_args);
|
||||
|
||||
G_OBJECT_CLASS (builder_options_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
builder_options_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BuilderOptions *self = BUILDER_OPTIONS (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CFLAGS:
|
||||
g_value_set_string (value, self->cflags);
|
||||
break;
|
||||
|
||||
case PROP_CXXFLAGS:
|
||||
g_value_set_string (value, self->cxxflags);
|
||||
break;
|
||||
|
||||
case PROP_ENV:
|
||||
g_value_set_boxed (value, self->env);
|
||||
break;
|
||||
|
||||
case PROP_ARCH:
|
||||
g_value_set_boxed (value, self->arch);
|
||||
break;
|
||||
|
||||
case PROP_BUILD_ARGS:
|
||||
g_value_set_boxed (value, self->build_args);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
builder_options_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BuilderOptions *self = BUILDER_OPTIONS (object);
|
||||
gchar **tmp;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CFLAGS:
|
||||
g_clear_pointer (&self->cflags, g_free);
|
||||
self->cflags = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
case PROP_CXXFLAGS:
|
||||
g_clear_pointer (&self->cxxflags, g_free);
|
||||
self->cxxflags = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
case PROP_ENV:
|
||||
tmp = self->env;
|
||||
self->env = g_strdupv (g_value_get_boxed (value));
|
||||
g_strfreev (tmp);
|
||||
break;
|
||||
|
||||
case PROP_ARCH:
|
||||
g_hash_table_destroy (self->arch);
|
||||
/* NOTE: This takes ownership of the hash table! */
|
||||
self->arch = g_value_dup_boxed (value);
|
||||
break;
|
||||
|
||||
case PROP_BUILD_ARGS:
|
||||
tmp = self->build_args;
|
||||
self->build_args = g_strdupv (g_value_get_boxed (value));
|
||||
g_strfreev (tmp);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
builder_options_class_init (BuilderOptionsClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = builder_options_finalize;
|
||||
object_class->get_property = builder_options_get_property;
|
||||
object_class->set_property = builder_options_set_property;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_CFLAGS,
|
||||
g_param_spec_string ("cflags",
|
||||
"",
|
||||
"",
|
||||
NULL,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_CXXFLAGS,
|
||||
g_param_spec_string ("cxxflags",
|
||||
"",
|
||||
"",
|
||||
NULL,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_ENV,
|
||||
g_param_spec_boxed ("env",
|
||||
"",
|
||||
"",
|
||||
G_TYPE_STRV,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_ARCH,
|
||||
g_param_spec_boxed ("arch",
|
||||
"",
|
||||
"",
|
||||
G_TYPE_HASH_TABLE,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_BUILD_ARGS,
|
||||
g_param_spec_boxed ("build-args",
|
||||
"",
|
||||
"",
|
||||
G_TYPE_STRV,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
builder_options_init (BuilderOptions *self)
|
||||
{
|
||||
self->arch = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
builder_options_deserialize_property (JsonSerializable *serializable,
|
||||
const gchar *property_name,
|
||||
GValue *value,
|
||||
GParamSpec *pspec,
|
||||
JsonNode *property_node)
|
||||
{
|
||||
if (strcmp (property_name, "arch") == 0)
|
||||
{
|
||||
if (JSON_NODE_TYPE (property_node) == JSON_NODE_NULL)
|
||||
{
|
||||
g_value_set_boxed (value, NULL);
|
||||
return TRUE;
|
||||
}
|
||||
else if (JSON_NODE_TYPE (property_node) == JSON_NODE_OBJECT)
|
||||
{
|
||||
JsonObject *object = json_node_get_object (property_node);
|
||||
g_autoptr(GPtrArray) env = g_ptr_array_new_with_free_func (g_free);
|
||||
g_autoptr(GHashTable) hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
|
||||
g_autoptr(GList) members = NULL;
|
||||
GList *l;
|
||||
|
||||
members = json_object_get_members (object);
|
||||
for (l = members; l != NULL; l = l->next)
|
||||
{
|
||||
const char *member_name = l->data;
|
||||
JsonNode *val;
|
||||
GObject *option;
|
||||
|
||||
val = json_object_get_member (object, member_name);
|
||||
option = json_gobject_deserialize (BUILDER_TYPE_OPTIONS, val);
|
||||
if (option == NULL)
|
||||
return FALSE;
|
||||
|
||||
g_hash_table_insert (hash, g_strdup (member_name), option);
|
||||
}
|
||||
|
||||
g_value_set_boxed (value, hash);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
else if (strcmp (property_name, "env") == 0)
|
||||
{
|
||||
if (JSON_NODE_TYPE (property_node) == JSON_NODE_NULL)
|
||||
{
|
||||
g_value_set_boxed (value, NULL);
|
||||
return TRUE;
|
||||
}
|
||||
else if (JSON_NODE_TYPE (property_node) == JSON_NODE_OBJECT)
|
||||
{
|
||||
JsonObject *object = json_node_get_object (property_node);
|
||||
g_autoptr(GPtrArray) env = g_ptr_array_new_with_free_func (g_free);
|
||||
g_autoptr(GList) members = NULL;
|
||||
GList *l;
|
||||
|
||||
members = json_object_get_members (object);
|
||||
for (l = members; l != NULL; l = l->next)
|
||||
{
|
||||
const char *member_name = l->data;
|
||||
JsonNode *val;
|
||||
const char *val_str;
|
||||
|
||||
val = json_object_get_member (object, member_name);
|
||||
val_str = json_node_get_string (val);
|
||||
if (val_str == NULL)
|
||||
return FALSE;
|
||||
|
||||
g_ptr_array_add (env, g_strdup_printf ("%s=%s", member_name, val_str));
|
||||
}
|
||||
|
||||
g_ptr_array_add (env, NULL);
|
||||
g_value_set_boxed (value, g_ptr_array_free (g_steal_pointer (&env), FALSE));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
return json_serializable_default_deserialize_property (serializable,
|
||||
property_name,
|
||||
value,
|
||||
pspec, property_node);
|
||||
}
|
||||
|
||||
static void
|
||||
serializable_iface_init (JsonSerializableIface *serializable_iface)
|
||||
{
|
||||
serializable_iface->deserialize_property = builder_options_deserialize_property;
|
||||
}
|
||||
|
||||
static GList *
|
||||
get_arched_options (BuilderOptions *self, BuilderContext *context)
|
||||
{
|
||||
GList *options = NULL;
|
||||
const char *arch = builder_context_get_arch (context);
|
||||
BuilderOptions *arch_options;
|
||||
|
||||
arch_options = g_hash_table_lookup (self->arch, arch);
|
||||
if (arch_options)
|
||||
options = g_list_prepend (options, arch_options);
|
||||
|
||||
options = g_list_prepend (options, self);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
static GList *
|
||||
get_all_options (BuilderOptions *self, BuilderContext *context)
|
||||
{
|
||||
GList *options = NULL;
|
||||
BuilderOptions *global_options = builder_context_get_options (context);
|
||||
|
||||
if (self)
|
||||
options = get_arched_options (self, context);
|
||||
|
||||
if (global_options && global_options != self)
|
||||
options = g_list_concat (options, get_arched_options (global_options, context));
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
const char *
|
||||
builder_options_get_cflags (BuilderOptions *self, BuilderContext *context)
|
||||
{
|
||||
g_autoptr(GList) options = get_all_options (self, context);
|
||||
GList *l;
|
||||
|
||||
for (l = options; l != NULL; l = l->next)
|
||||
{
|
||||
BuilderOptions *o = l->data;
|
||||
if (o->cflags)
|
||||
return o->cflags;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *
|
||||
builder_options_get_cxxflags (BuilderOptions *self, BuilderContext *context)
|
||||
{
|
||||
g_autoptr(GList) options = get_all_options (self, context);
|
||||
GList *l;
|
||||
|
||||
for (l = options; l != NULL; l = l->next)
|
||||
{
|
||||
BuilderOptions *o = l->data;
|
||||
if (o->cxxflags)
|
||||
return o->cxxflags;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char **
|
||||
builder_options_get_env (BuilderOptions *self, BuilderContext *context)
|
||||
{
|
||||
g_autoptr(GList) options = get_all_options (self, context);
|
||||
GList *l;
|
||||
int i;
|
||||
char **envp = NULL;
|
||||
|
||||
for (l = options; l != NULL; l = l->next)
|
||||
{
|
||||
BuilderOptions *o = l->data;
|
||||
|
||||
if (o->env)
|
||||
{
|
||||
for (i = 0; o->env[i] != NULL; i++)
|
||||
{
|
||||
const char *line = o->env[i];
|
||||
const char *eq = strchr (line, '=');
|
||||
const char *value = "";
|
||||
g_autofree char *key = NULL;
|
||||
|
||||
if (eq)
|
||||
{
|
||||
key = g_strndup (line, eq - line);
|
||||
value = eq + 1;
|
||||
}
|
||||
else
|
||||
key = g_strdup (key);
|
||||
|
||||
envp = g_environ_setenv (envp, key, value, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return envp;
|
||||
}
|
||||
|
||||
char **
|
||||
builder_options_get_build_args (BuilderOptions *self,
|
||||
BuilderContext *context)
|
||||
{
|
||||
g_autoptr(GList) options = get_all_options (self, context);
|
||||
GList *l;
|
||||
int i;
|
||||
g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func (g_free);
|
||||
|
||||
/* Last argument wins, so reverse the list for per-module to win */
|
||||
options = g_list_reverse (options);
|
||||
|
||||
for (l = options; l != NULL; l = l->next)
|
||||
{
|
||||
BuilderOptions *o = l->data;
|
||||
|
||||
if (o->build_args)
|
||||
{
|
||||
for (i = 0; o->build_args[i] != NULL; i++)
|
||||
g_ptr_array_add (array, g_strdup (o->build_args[i]));
|
||||
}
|
||||
}
|
||||
|
||||
g_ptr_array_add (array, NULL);
|
||||
|
||||
return (char **)g_ptr_array_free (g_steal_pointer (&array), FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
builder_options_checksum (BuilderOptions *self,
|
||||
BuilderCache *cache,
|
||||
BuilderContext *context)
|
||||
{
|
||||
BuilderOptions *arch_options;
|
||||
|
||||
builder_cache_checksum_str (cache, BUILDER_OPTION_CHECKSUM_VERSION);
|
||||
builder_cache_checksum_str (cache, self->cflags);
|
||||
builder_cache_checksum_str (cache, self->cxxflags);
|
||||
builder_cache_checksum_strv (cache, self->env);
|
||||
builder_cache_checksum_strv (cache, self->build_args);
|
||||
|
||||
arch_options = g_hash_table_lookup (self->arch, builder_context_get_arch (context));
|
||||
if (arch_options)
|
||||
builder_options_checksum (arch_options, cache, context);
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright © 2015 Red Hat, Inc
|
||||
*
|
||||
* This program 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __BUILDER_OPTIONS_H__
|
||||
#define __BUILDER_OPTIONS_H__
|
||||
|
||||
#include <json-glib/json-glib.h>
|
||||
#include "builder-cache.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct BuilderContext BuilderContext;
|
||||
typedef struct BuilderOptions BuilderOptions;
|
||||
|
||||
#define BUILDER_TYPE_OPTIONS (builder_options_get_type())
|
||||
#define BUILDER_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BUILDER_TYPE_OPTIONS, BuilderOptions))
|
||||
#define BUILDER_IS_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BUILDER_TYPE_OPTIONS))
|
||||
|
||||
/* Bump this if format changes in incompatible ways to force rebuild */
|
||||
#define BUILDER_OPTION_CHECKSUM_VERSION "1"
|
||||
|
||||
GType builder_options_get_type (void);
|
||||
|
||||
const char *builder_options_get_cflags (BuilderOptions *self,
|
||||
BuilderContext *context);
|
||||
const char *builder_options_get_cxxflags (BuilderOptions *self,
|
||||
BuilderContext *context);
|
||||
char ** builder_options_get_env (BuilderOptions *self,
|
||||
BuilderContext *context);
|
||||
char ** builder_options_get_build_args (BuilderOptions *self,
|
||||
BuilderContext *context);
|
||||
void builder_options_checksum (BuilderOptions *self,
|
||||
BuilderCache *cache,
|
||||
BuilderContext *context);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(BuilderOptions, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __BUILDER_OPTIONS_H__ */
|
|
@ -0,0 +1,613 @@
|
|||
/* builder-source-archive.c
|
||||
*
|
||||
* Copyright (C) 2015 Red Hat, Inc
|
||||
*
|
||||
* This file 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 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This file 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 General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/statfs.h>
|
||||
|
||||
#include "xdg-app-utils.h"
|
||||
|
||||
#include "builder-utils.h"
|
||||
#include "builder-source-archive.h"
|
||||
|
||||
struct BuilderSourceArchive {
|
||||
BuilderSource parent;
|
||||
|
||||
char *url;
|
||||
char *sha256;
|
||||
guint strip_components;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
BuilderSourceClass parent_class;
|
||||
} BuilderSourceArchiveClass;
|
||||
|
||||
G_DEFINE_TYPE (BuilderSourceArchive, builder_source_archive, BUILDER_TYPE_SOURCE);
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_URL,
|
||||
PROP_SHA256,
|
||||
PROP_STRIP_COMPONENTS,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
UNKNOWN,
|
||||
TAR,
|
||||
TAR_GZIP,
|
||||
TAR_COMPRESS,
|
||||
TAR_BZIP2,
|
||||
TAR_LZIP,
|
||||
TAR_LZMA,
|
||||
TAR_LZOP,
|
||||
TAR_XZ,
|
||||
ZIP
|
||||
} BuilderArchiveType;
|
||||
|
||||
gboolean
|
||||
is_tar (BuilderArchiveType type)
|
||||
{
|
||||
return (type >= TAR) && (type <= TAR_XZ);
|
||||
}
|
||||
|
||||
const char *
|
||||
tar_decompress_flag (BuilderArchiveType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
default:
|
||||
case TAR:
|
||||
return NULL;
|
||||
case TAR_GZIP:
|
||||
return "-z";
|
||||
case TAR_COMPRESS:
|
||||
return "-Z";
|
||||
case TAR_BZIP2:
|
||||
return "-j";
|
||||
case TAR_LZIP:
|
||||
return "--lzip";
|
||||
case TAR_LZMA:
|
||||
return "--lzma";
|
||||
case TAR_LZOP:
|
||||
return "--lzop";
|
||||
case TAR_XZ:
|
||||
return "-J";
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_archive_finalize (GObject *object)
|
||||
{
|
||||
BuilderSourceArchive *self = (BuilderSourceArchive *)object;
|
||||
|
||||
g_free (self->url);
|
||||
g_free (self->sha256);
|
||||
|
||||
G_OBJECT_CLASS (builder_source_archive_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_archive_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BuilderSourceArchive *self = BUILDER_SOURCE_ARCHIVE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_URL:
|
||||
g_value_set_string (value, self->url);
|
||||
break;
|
||||
|
||||
case PROP_SHA256:
|
||||
g_value_set_string (value, self->sha256);
|
||||
break;
|
||||
|
||||
case PROP_STRIP_COMPONENTS:
|
||||
g_value_set_uint (value, self->strip_components);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_archive_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BuilderSourceArchive *self = BUILDER_SOURCE_ARCHIVE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_URL:
|
||||
g_free (self->url);
|
||||
self->url = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
case PROP_SHA256:
|
||||
g_free (self->sha256);
|
||||
self->sha256 = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
case PROP_STRIP_COMPONENTS:
|
||||
self->strip_components = g_value_get_uint (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static SoupURI *
|
||||
get_uri (BuilderSourceArchive *self,
|
||||
GError **error)
|
||||
{
|
||||
SoupURI *uri;
|
||||
|
||||
if (self->url == NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "URL not specified");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uri = soup_uri_new (self->url);
|
||||
if (uri == NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Invalid URL '%s'", self->url);
|
||||
return NULL;
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
static GFile *
|
||||
get_download_location (BuilderSourceArchive *self,
|
||||
BuilderContext *context,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(SoupURI) uri = NULL;
|
||||
const char *path;
|
||||
g_autofree char *base_name = NULL;
|
||||
GFile *download_dir = NULL;
|
||||
g_autoptr(GFile) sha256_dir = NULL;
|
||||
g_autoptr(GFile) file = NULL;
|
||||
|
||||
uri = get_uri (self, error);
|
||||
if (uri == NULL)
|
||||
return FALSE;
|
||||
|
||||
path = soup_uri_get_path (uri);
|
||||
|
||||
base_name = g_path_get_basename (path);
|
||||
|
||||
if (self->sha256 == NULL || *self->sha256 == 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Sha256 not specified");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
download_dir = builder_context_get_download_dir (context);
|
||||
sha256_dir = g_file_get_child (download_dir, self->sha256);
|
||||
file = g_file_get_child (sha256_dir, base_name);
|
||||
|
||||
return g_steal_pointer (&file);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
builder_source_archive_download (BuilderSource *source,
|
||||
BuilderContext *context,
|
||||
GError **error)
|
||||
{
|
||||
BuilderSourceArchive *self = BUILDER_SOURCE_ARCHIVE (source);
|
||||
g_autoptr (GFile) file = NULL;
|
||||
g_autoptr (GFile) dir = NULL;
|
||||
g_autoptr(SoupURI) uri = NULL;
|
||||
SoupSession *session;
|
||||
g_autofree char *url = NULL;
|
||||
g_autofree char *dir_path = NULL;
|
||||
g_autofree char *sha256 = NULL;
|
||||
g_autofree char *base_name = NULL;
|
||||
g_autoptr(SoupMessage) msg = NULL;
|
||||
|
||||
file = get_download_location (self, context, error);
|
||||
if (file == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (g_file_query_exists (file, NULL))
|
||||
return TRUE;
|
||||
|
||||
base_name = g_file_get_basename (file);
|
||||
|
||||
uri = get_uri (self, error);
|
||||
if (uri == NULL)
|
||||
return FALSE;
|
||||
|
||||
url = g_strdup (self->url);
|
||||
|
||||
session = builder_context_get_soup_session (context);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
g_clear_object (&msg);
|
||||
msg = soup_message_new ("GET", url);
|
||||
g_debug ("GET %s", self->url);
|
||||
g_print ("Downloading %s...", base_name);
|
||||
soup_session_send_message (session, msg);
|
||||
g_print ("done\n");
|
||||
|
||||
g_debug ("response: %d %s", msg->status_code, msg->reason_phrase);
|
||||
|
||||
if (SOUP_STATUS_IS_REDIRECTION (msg->status_code))
|
||||
{
|
||||
const char *header = soup_message_headers_get_one (msg->response_headers, "Location");
|
||||
if (header)
|
||||
{
|
||||
g_autoptr(SoupURI) new_uri = soup_uri_new_with_base (soup_message_get_uri (msg), header);
|
||||
g_free (url);
|
||||
url = soup_uri_to_string (uri, FALSE);
|
||||
g_debug (" -> %s", header);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Failed to download %s (error %d): %s", base_name, msg->status_code, msg->reason_phrase);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
break; /* No redirection */
|
||||
}
|
||||
|
||||
sha256 = g_compute_checksum_for_string (G_CHECKSUM_SHA256,
|
||||
msg->response_body->data,
|
||||
msg->response_body->length);
|
||||
|
||||
if (strcmp (sha256, self->sha256) != 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Wrong sha256 for %s, expected %s, was %s", base_name, self->sha256, sha256);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
dir = g_file_get_parent (file);
|
||||
dir_path = g_file_get_path (dir);
|
||||
g_mkdir_with_parents (dir_path, 0755);
|
||||
|
||||
if (!g_file_replace_contents (file,
|
||||
msg->response_body->data,
|
||||
msg->response_body->length,
|
||||
NULL, FALSE, G_FILE_CREATE_NONE, NULL,
|
||||
NULL, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
tar (GFile *dir,
|
||||
GError **error,
|
||||
const gchar *argv1,
|
||||
...)
|
||||
{
|
||||
g_autoptr(GSubprocessLauncher) launcher = NULL;
|
||||
g_autoptr(GSubprocess) subp = NULL;
|
||||
GPtrArray *args;
|
||||
const gchar *arg;
|
||||
va_list ap;
|
||||
|
||||
args = g_ptr_array_new ();
|
||||
g_ptr_array_add (args, "tar");
|
||||
va_start (ap, argv1);
|
||||
g_ptr_array_add (args, (gchar *) argv1);
|
||||
while ((arg = va_arg (ap, const gchar *)))
|
||||
g_ptr_array_add (args, (gchar *) arg);
|
||||
g_ptr_array_add (args, NULL);
|
||||
va_end (ap);
|
||||
|
||||
launcher = g_subprocess_launcher_new (0);
|
||||
|
||||
if (dir)
|
||||
{
|
||||
g_autofree char *path = g_file_get_path (dir);
|
||||
g_subprocess_launcher_set_cwd (launcher, path);
|
||||
}
|
||||
|
||||
subp = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
|
||||
g_ptr_array_free (args, TRUE);
|
||||
|
||||
if (subp == NULL ||
|
||||
!g_subprocess_wait_check (subp, NULL, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
unzip (GFile *dir,
|
||||
GError **error,
|
||||
const gchar *argv1,
|
||||
...)
|
||||
{
|
||||
g_autoptr(GSubprocessLauncher) launcher = NULL;
|
||||
g_autoptr(GSubprocess) subp = NULL;
|
||||
GPtrArray *args;
|
||||
const gchar *arg;
|
||||
va_list ap;
|
||||
|
||||
args = g_ptr_array_new ();
|
||||
g_ptr_array_add (args, "unzip");
|
||||
va_start (ap, argv1);
|
||||
g_ptr_array_add (args, (gchar *) argv1);
|
||||
while ((arg = va_arg (ap, const gchar *)))
|
||||
g_ptr_array_add (args, (gchar *) arg);
|
||||
g_ptr_array_add (args, NULL);
|
||||
va_end (ap);
|
||||
|
||||
launcher = g_subprocess_launcher_new (0);
|
||||
|
||||
if (dir)
|
||||
{
|
||||
g_autofree char *path = g_file_get_path (dir);
|
||||
g_subprocess_launcher_set_cwd (launcher, path);
|
||||
}
|
||||
|
||||
subp = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
|
||||
g_ptr_array_free (args, TRUE);
|
||||
|
||||
if (subp == NULL ||
|
||||
!g_subprocess_wait_check (subp, NULL, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
BuilderArchiveType
|
||||
get_type (GFile *archivefile)
|
||||
{
|
||||
g_autofree char *base_name = NULL;
|
||||
g_autofree gchar *lower = NULL;
|
||||
|
||||
base_name = g_file_get_basename (archivefile);
|
||||
lower = g_ascii_strdown (base_name, -1);
|
||||
|
||||
if (g_str_has_suffix (lower, ".tar"))
|
||||
return TAR;
|
||||
|
||||
if (g_str_has_suffix (lower, ".tar.gz") ||
|
||||
g_str_has_suffix (lower, ".tgz") ||
|
||||
g_str_has_suffix (lower, ".taz"))
|
||||
return TAR_GZIP;
|
||||
|
||||
if (g_str_has_suffix (lower, ".tar.Z") ||
|
||||
g_str_has_suffix (lower, ".taZ"))
|
||||
return TAR_COMPRESS;
|
||||
|
||||
if (g_str_has_suffix (lower, ".tar.bz2") ||
|
||||
g_str_has_suffix (lower, ".tz2") ||
|
||||
g_str_has_suffix (lower, ".tbz2") ||
|
||||
g_str_has_suffix (lower, ".tbz"))
|
||||
return TAR_BZIP2;
|
||||
|
||||
if (g_str_has_suffix (lower, ".tar.lz"))
|
||||
return TAR_LZIP;
|
||||
|
||||
if (g_str_has_suffix (lower, ".tar.lzma") ||
|
||||
g_str_has_suffix (lower, ".tlz"))
|
||||
return TAR_LZMA;
|
||||
|
||||
if (g_str_has_suffix (lower, ".tar.lzo"))
|
||||
return TAR_LZOP;
|
||||
|
||||
if (g_str_has_suffix (lower, ".tar.xz"))
|
||||
return TAR_XZ;
|
||||
|
||||
if (g_str_has_suffix (lower, ".zip"))
|
||||
return ZIP;
|
||||
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
strip_components_into (GFile *dest,
|
||||
GFile *src,
|
||||
int level,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GFileEnumerator) dir_enum = NULL;
|
||||
g_autoptr(GFileInfo) child_info = NULL;
|
||||
GError *temp_error = NULL;
|
||||
|
||||
dir_enum = g_file_enumerate_children (src, "standard::name,standard::type",
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
NULL, error);
|
||||
if (!dir_enum)
|
||||
return FALSE;;
|
||||
|
||||
while ((child_info = g_file_enumerator_next_file (dir_enum, NULL, &temp_error)))
|
||||
{
|
||||
g_autoptr(GFile) child = NULL;
|
||||
g_autoptr(GFile) dest_child = NULL;
|
||||
g_autoptr(GFileEnumerator) dir_enum2 = NULL;
|
||||
g_autoptr(GFileInfo) child_info2 = NULL;
|
||||
|
||||
child = g_file_get_child (src, g_file_info_get_name (child_info));
|
||||
|
||||
if (g_file_info_get_file_type (child_info) == G_FILE_TYPE_DIRECTORY &&
|
||||
level > 0)
|
||||
{
|
||||
if (!strip_components_into (dest, child, level - 1, error))
|
||||
return FALSE;
|
||||
|
||||
g_clear_object (&child_info);
|
||||
continue;
|
||||
}
|
||||
|
||||
dest_child = g_file_get_child (dest, g_file_info_get_name (child_info));
|
||||
if (!g_file_move (child, dest_child, G_FILE_COPY_NONE, NULL, NULL, NULL, error))
|
||||
return FALSE;
|
||||
|
||||
g_clear_object (&child_info);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (temp_error != NULL)
|
||||
{
|
||||
g_propagate_error (error, temp_error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!g_file_delete (src, NULL, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
builder_source_archive_extract (BuilderSource *source,
|
||||
GFile *dest,
|
||||
BuilderContext *context,
|
||||
GError **error)
|
||||
{
|
||||
BuilderSourceArchive *self = BUILDER_SOURCE_ARCHIVE (source);
|
||||
g_autoptr(GFile) archivefile = NULL;
|
||||
g_autofree char *archive_path = NULL;
|
||||
BuilderArchiveType type;
|
||||
|
||||
archivefile = get_download_location (self, context, error);
|
||||
if (archivefile == NULL)
|
||||
return FALSE;
|
||||
|
||||
type = get_type (archivefile);
|
||||
|
||||
archive_path = g_file_get_path (archivefile);
|
||||
|
||||
if (is_tar (type))
|
||||
{
|
||||
g_autofree char *strip_components = g_strdup_printf ("--strip-components=%u", self->strip_components);
|
||||
/* Note: tar_decompress_flag can return NULL, so put it last */
|
||||
if (!tar (dest, error, "xf", archive_path, strip_components, tar_decompress_flag (type), NULL))
|
||||
return FALSE;
|
||||
}
|
||||
else if (type == ZIP)
|
||||
{
|
||||
g_autoptr(GFile) zip_dest = NULL;
|
||||
|
||||
if (self->strip_components > 0)
|
||||
{
|
||||
g_autoptr(GFile) tmp_dir_template = g_file_get_child (dest, ".uncompressXXXXXX");
|
||||
g_autofree char *tmp_dir_path = g_file_get_path (tmp_dir_template);;
|
||||
|
||||
if (g_mkdtemp (tmp_dir_path) == NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Can't create uncompress directory");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
zip_dest = g_file_new_for_path (tmp_dir_path);
|
||||
}
|
||||
else
|
||||
zip_dest = g_object_ref (dest);
|
||||
|
||||
if (!unzip (zip_dest, error, archive_path, NULL))
|
||||
return FALSE;
|
||||
|
||||
if (self->strip_components > 0)
|
||||
{
|
||||
if (!strip_components_into (dest, zip_dest, self->strip_components, error))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Unknown archive format of '%s'", archive_path);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_archive_checksum (BuilderSource *source,
|
||||
BuilderCache *cache,
|
||||
BuilderContext *context)
|
||||
{
|
||||
BuilderSourceArchive *self = BUILDER_SOURCE_ARCHIVE (source);
|
||||
|
||||
builder_cache_checksum_str (cache, self->url);
|
||||
builder_cache_checksum_str (cache, self->sha256);
|
||||
builder_cache_checksum_uint32 (cache, self->strip_components);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
builder_source_archive_class_init (BuilderSourceArchiveClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
BuilderSourceClass *source_class = BUILDER_SOURCE_CLASS (klass);
|
||||
|
||||
object_class->finalize = builder_source_archive_finalize;
|
||||
object_class->get_property = builder_source_archive_get_property;
|
||||
object_class->set_property = builder_source_archive_set_property;
|
||||
|
||||
source_class->download = builder_source_archive_download;
|
||||
source_class->extract = builder_source_archive_extract;
|
||||
source_class->checksum = builder_source_archive_checksum;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_URL,
|
||||
g_param_spec_string ("url",
|
||||
"",
|
||||
"",
|
||||
NULL,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_SHA256,
|
||||
g_param_spec_string ("sha256",
|
||||
"",
|
||||
"",
|
||||
NULL,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_STRIP_COMPONENTS,
|
||||
g_param_spec_uint ("strip-components",
|
||||
"",
|
||||
"",
|
||||
0, G_MAXUINT,
|
||||
1,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_archive_init (BuilderSourceArchive *self)
|
||||
{
|
||||
self->strip_components = 1;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright © 2015 Red Hat, Inc
|
||||
*
|
||||
* This program 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __BUILDER_SOURCE_ARCHIVE_H__
|
||||
#define __BUILDER_SOURCE_ARCHIVE_H__
|
||||
|
||||
#include "builder-source.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct BuilderSourceArchive BuilderSourceArchive;
|
||||
|
||||
#define BUILDER_TYPE_SOURCE_ARCHIVE (builder_source_archive_get_type())
|
||||
#define BUILDER_SOURCE_ARCHIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BUILDER_TYPE_SOURCE_ARCHIVE, BuilderSourceArchive))
|
||||
#define BUILDER_IS_SOURCE_ARCHIVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BUILDER_TYPE_SOURCE_ARCHIVE))
|
||||
|
||||
GType builder_source_archive_get_type (void);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(BuilderSourceArchive, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __BUILDER_SOURCE_ARCHIVE_H__ */
|
|
@ -0,0 +1,373 @@
|
|||
/* builder-source-bzr.c
|
||||
*
|
||||
* Copyright (C) 2015 Red Hat, Inc
|
||||
*
|
||||
* This file 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 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This file 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 General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/statfs.h>
|
||||
|
||||
#include "builder-utils.h"
|
||||
|
||||
#include "builder-source-bzr.h"
|
||||
#include "builder-utils.h"
|
||||
|
||||
struct BuilderSourceBzr {
|
||||
BuilderSource parent;
|
||||
|
||||
char *url;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
BuilderSourceClass parent_class;
|
||||
} BuilderSourceBzrClass;
|
||||
|
||||
G_DEFINE_TYPE (BuilderSourceBzr, builder_source_bzr, BUILDER_TYPE_SOURCE);
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_URL,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
static void
|
||||
builder_source_bzr_finalize (GObject *object)
|
||||
{
|
||||
BuilderSourceBzr *self = (BuilderSourceBzr *)object;
|
||||
|
||||
g_free (self->url);
|
||||
|
||||
G_OBJECT_CLASS (builder_source_bzr_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_bzr_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BuilderSourceBzr *self = BUILDER_SOURCE_BZR (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_URL:
|
||||
g_value_set_string (value, self->url);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_bzr_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BuilderSourceBzr *self = BUILDER_SOURCE_BZR (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_URL:
|
||||
g_free (self->url);
|
||||
self->url = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GError *error;
|
||||
GError *splice_error;
|
||||
GMainLoop *loop;
|
||||
int refs;
|
||||
} BzrData;
|
||||
|
||||
static gboolean bzr (GFile *dir,
|
||||
char **output,
|
||||
GError **error,
|
||||
const gchar *argv1,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
|
||||
|
||||
static void
|
||||
bzr_data_exit (BzrData *data)
|
||||
{
|
||||
data->refs--;
|
||||
if (data->refs == 0)
|
||||
g_main_loop_quit (data->loop);
|
||||
}
|
||||
|
||||
static void
|
||||
bzr_output_spliced_cb (GObject *obj,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
BzrData *data = user_data;
|
||||
|
||||
g_output_stream_splice_finish (G_OUTPUT_STREAM (obj), result, &data->splice_error);
|
||||
bzr_data_exit (data);
|
||||
}
|
||||
|
||||
static void
|
||||
bzr_exit_cb (GObject *obj,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
BzrData *data = user_data;
|
||||
|
||||
g_subprocess_wait_check_finish (G_SUBPROCESS (obj), result, &data->error);
|
||||
bzr_data_exit (data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
bzr (GFile *dir,
|
||||
char **output,
|
||||
GError **error,
|
||||
const gchar *argv1,
|
||||
...)
|
||||
{
|
||||
g_autoptr(GSubprocessLauncher) launcher = NULL;
|
||||
g_autoptr(GSubprocess) subp = NULL;
|
||||
GPtrArray *args;
|
||||
const gchar *arg;
|
||||
GInputStream *in;
|
||||
g_autoptr(GOutputStream) out = NULL;
|
||||
g_autoptr(GMainLoop) loop = NULL;
|
||||
va_list ap;
|
||||
BzrData data = {0};
|
||||
|
||||
args = g_ptr_array_new ();
|
||||
g_ptr_array_add (args, "bzr");
|
||||
va_start (ap, argv1);
|
||||
g_ptr_array_add (args, (gchar *) argv1);
|
||||
while ((arg = va_arg (ap, const gchar *)))
|
||||
g_ptr_array_add (args, (gchar *) arg);
|
||||
g_ptr_array_add (args, NULL);
|
||||
va_end (ap);
|
||||
|
||||
launcher = g_subprocess_launcher_new (0);
|
||||
|
||||
if (output)
|
||||
g_subprocess_launcher_set_flags (launcher, G_SUBPROCESS_FLAGS_STDOUT_PIPE);
|
||||
|
||||
if (dir)
|
||||
{
|
||||
g_autofree char *path = g_file_get_path (dir);
|
||||
g_subprocess_launcher_set_cwd (launcher, path);
|
||||
}
|
||||
|
||||
subp = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
|
||||
g_ptr_array_free (args, TRUE);
|
||||
|
||||
if (subp == NULL)
|
||||
return FALSE;
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
data.loop = loop;
|
||||
data.refs = 1;
|
||||
|
||||
if (output)
|
||||
{
|
||||
data.refs++;
|
||||
in = g_subprocess_get_stdout_pipe (subp);
|
||||
out = g_memory_output_stream_new_resizable ();
|
||||
g_output_stream_splice_async (out,
|
||||
in,
|
||||
G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
|
||||
0,
|
||||
NULL,
|
||||
bzr_output_spliced_cb,
|
||||
&data);
|
||||
}
|
||||
|
||||
g_subprocess_wait_async (subp, NULL, bzr_exit_cb, &data);
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
if (data.error)
|
||||
{
|
||||
g_propagate_error (error, data.error);
|
||||
g_clear_error (&data.splice_error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (out)
|
||||
{
|
||||
if (data.splice_error)
|
||||
{
|
||||
g_propagate_error (error, data.splice_error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Null terminate */
|
||||
g_output_stream_write (out, "\0", 1, NULL, NULL);
|
||||
*output = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (out));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GFile *
|
||||
get_mirror_dir (BuilderSourceBzr *self, BuilderContext *context)
|
||||
{
|
||||
g_autoptr(GFile) bzr_dir = NULL;
|
||||
g_autofree char *filename = NULL;
|
||||
g_autofree char *bzr_dir_path = NULL;
|
||||
|
||||
bzr_dir = g_file_get_child (builder_context_get_state_dir (context),
|
||||
"bzr");
|
||||
|
||||
bzr_dir_path = g_file_get_path (bzr_dir);
|
||||
g_mkdir_with_parents (bzr_dir_path, 0755);
|
||||
|
||||
filename = builder_uri_to_filename (self->url);
|
||||
return g_file_get_child (bzr_dir, filename);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_current_commit (BuilderSourceBzr *self, BuilderContext *context, GError **error)
|
||||
{
|
||||
g_autoptr(GFile) mirror_dir = NULL;
|
||||
char *output = NULL;
|
||||
|
||||
mirror_dir = get_mirror_dir (self, context);
|
||||
|
||||
if (!bzr (mirror_dir, &output, error,
|
||||
"revno", NULL))
|
||||
return NULL;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
builder_source_bzr_download (BuilderSource *source,
|
||||
BuilderContext *context,
|
||||
GError **error)
|
||||
{
|
||||
BuilderSourceBzr *self = BUILDER_SOURCE_BZR (source);
|
||||
g_autoptr(GFile) mirror_dir = NULL;
|
||||
|
||||
if (self->url == NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "URL not specified");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mirror_dir = get_mirror_dir (self, context);
|
||||
|
||||
if (!g_file_query_exists (mirror_dir, NULL))
|
||||
{
|
||||
g_autofree char *filename = g_file_get_basename (mirror_dir);
|
||||
g_autoptr(GFile) parent = g_file_get_parent (mirror_dir);
|
||||
g_autofree char *filename_tmp = g_strconcat ("./", filename, ".clone_tmp", NULL);
|
||||
g_autoptr(GFile) mirror_dir_tmp = g_file_get_child (parent, filename_tmp);
|
||||
|
||||
if (!bzr (parent, NULL, error,
|
||||
"branch", self->url, filename_tmp, NULL) ||
|
||||
!g_file_move (mirror_dir_tmp, mirror_dir, 0, NULL, NULL, NULL, error))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!bzr (mirror_dir, NULL, error,
|
||||
"pull", NULL))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
builder_source_bzr_extract (BuilderSource *source,
|
||||
GFile *dest,
|
||||
BuilderContext *context,
|
||||
GError **error)
|
||||
{
|
||||
BuilderSourceBzr *self = BUILDER_SOURCE_BZR (source);
|
||||
g_autoptr(GFile) mirror_dir = NULL;
|
||||
g_autofree char *mirror_dir_path = NULL;
|
||||
g_autofree char *dest_path = NULL;
|
||||
|
||||
mirror_dir = get_mirror_dir (self, context);
|
||||
|
||||
mirror_dir_path = g_file_get_path (mirror_dir);
|
||||
dest_path = g_file_get_path (dest);
|
||||
|
||||
if (!bzr (NULL, NULL, error,
|
||||
"branch", "--stacked", mirror_dir_path, dest_path, "--use-existing-dir", NULL))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_bzr_checksum (BuilderSource *source,
|
||||
BuilderCache *cache,
|
||||
BuilderContext *context)
|
||||
{
|
||||
BuilderSourceBzr *self = BUILDER_SOURCE_BZR (source);
|
||||
g_autofree char *current_commit;
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
builder_cache_checksum_str (cache, self->url);
|
||||
|
||||
current_commit = get_current_commit (self, context, &error);
|
||||
if (current_commit)
|
||||
builder_cache_checksum_str (cache, current_commit);
|
||||
else if (error)
|
||||
g_warning ("Failed to get current bzr checksum: %s", error->message);
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_bzr_class_init (BuilderSourceBzrClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
BuilderSourceClass *source_class = BUILDER_SOURCE_CLASS (klass);
|
||||
|
||||
object_class->finalize = builder_source_bzr_finalize;
|
||||
object_class->get_property = builder_source_bzr_get_property;
|
||||
object_class->set_property = builder_source_bzr_set_property;
|
||||
|
||||
source_class->download = builder_source_bzr_download;
|
||||
source_class->extract = builder_source_bzr_extract;
|
||||
source_class->checksum = builder_source_bzr_checksum;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_URL,
|
||||
g_param_spec_string ("url",
|
||||
"",
|
||||
"",
|
||||
NULL,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_bzr_init (BuilderSourceBzr *self)
|
||||
{
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright © 2015 Red Hat, Inc
|
||||
*
|
||||
* This program 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __BUILDER_SOURCE_BZR_H__
|
||||
#define __BUILDER_SOURCE_BZR_H__
|
||||
|
||||
#include "builder-source.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct BuilderSourceBzr BuilderSourceBzr;
|
||||
|
||||
#define BUILDER_TYPE_SOURCE_BZR (builder_source_bzr_get_type())
|
||||
#define BUILDER_SOURCE_BZR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BUILDER_TYPE_SOURCE_BZR, BuilderSourceBzr))
|
||||
#define BUILDER_IS_SOURCE_BZR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BUILDER_TYPE_SOURCE_BZR))
|
||||
|
||||
GType builder_source_bzr_get_type (void);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(BuilderSourceBzr, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __BUILDER_SOURCE_BZR_H__ */
|
|
@ -0,0 +1,235 @@
|
|||
/* builder-source-file.c
|
||||
*
|
||||
* Copyright (C) 2015 Red Hat, Inc
|
||||
*
|
||||
* This file 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 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This file 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 General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/statfs.h>
|
||||
|
||||
#include "builder-utils.h"
|
||||
#include "builder-source-file.h"
|
||||
|
||||
struct BuilderSourceFile {
|
||||
BuilderSource parent;
|
||||
|
||||
char *path;
|
||||
char *dest_filename;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
BuilderSourceClass parent_class;
|
||||
} BuilderSourceFileClass;
|
||||
|
||||
G_DEFINE_TYPE (BuilderSourceFile, builder_source_file, BUILDER_TYPE_SOURCE);
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_PATH,
|
||||
PROP_DEST_FILENAME,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
static void
|
||||
builder_source_file_finalize (GObject *object)
|
||||
{
|
||||
BuilderSourceFile *self = (BuilderSourceFile *)object;
|
||||
|
||||
g_free (self->path);
|
||||
g_free (self->dest_filename);
|
||||
|
||||
G_OBJECT_CLASS (builder_source_file_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_file_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BuilderSourceFile *self = BUILDER_SOURCE_FILE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PATH:
|
||||
g_value_set_string (value, self->path);
|
||||
break;
|
||||
|
||||
case PROP_DEST_FILENAME:
|
||||
g_value_set_string (value, self->dest_filename);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_file_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BuilderSourceFile *self = BUILDER_SOURCE_FILE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PATH:
|
||||
g_free (self->path);
|
||||
self->path = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
case PROP_DEST_FILENAME:
|
||||
g_free (self->dest_filename);
|
||||
self->dest_filename = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static GFile *
|
||||
get_source_file (BuilderSourceFile *self,
|
||||
BuilderContext *context,
|
||||
GError **error)
|
||||
{
|
||||
GFile *base_dir = builder_context_get_base_dir (context);
|
||||
|
||||
if (self->path == NULL || self->path[0] == 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "path not specified");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return g_file_resolve_relative_path (base_dir, self->path);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
builder_source_file_download (BuilderSource *source,
|
||||
BuilderContext *context,
|
||||
GError **error)
|
||||
{
|
||||
BuilderSourceFile *self = BUILDER_SOURCE_FILE (source);
|
||||
g_autoptr(GFile) src = NULL;
|
||||
|
||||
src = get_source_file (self, context, error);
|
||||
if (src == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (!g_file_query_exists (src, NULL))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Can't find file at %s", self->path);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
builder_source_file_extract (BuilderSource *source,
|
||||
GFile *dest,
|
||||
BuilderContext *context,
|
||||
GError **error)
|
||||
{
|
||||
BuilderSourceFile *self = BUILDER_SOURCE_FILE (source);
|
||||
g_autoptr(GFile) src = NULL;
|
||||
g_autoptr(GFile) dest_file = NULL;
|
||||
g_autofree char *dest_filename = NULL;
|
||||
|
||||
src = get_source_file (self, context, error);
|
||||
if (src == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (self->dest_filename)
|
||||
dest_filename = g_strdup (self->dest_filename);
|
||||
else
|
||||
dest_filename = g_file_get_basename (src);
|
||||
|
||||
dest_file = g_file_get_child (dest, dest_filename);
|
||||
|
||||
if (!g_file_copy (src, dest_file,
|
||||
G_FILE_COPY_OVERWRITE,
|
||||
NULL,
|
||||
NULL, NULL,
|
||||
error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_file_checksum (BuilderSource *source,
|
||||
BuilderCache *cache,
|
||||
BuilderContext *context)
|
||||
{
|
||||
BuilderSourceFile *self = BUILDER_SOURCE_FILE (source);
|
||||
g_autoptr(GFile) src = NULL;
|
||||
g_autofree char *data = NULL;
|
||||
gsize len;
|
||||
|
||||
src = get_source_file (self, context, NULL);
|
||||
if (src == NULL)
|
||||
return;
|
||||
|
||||
if (g_file_load_contents (src, NULL, &data, &len, NULL, NULL))
|
||||
builder_cache_checksum_data (cache, (guchar *)data, len);
|
||||
|
||||
builder_cache_checksum_str (cache, self->path);
|
||||
builder_cache_checksum_str (cache, self->dest_filename);
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_file_class_init (BuilderSourceFileClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
BuilderSourceClass *source_class = BUILDER_SOURCE_CLASS (klass);
|
||||
|
||||
object_class->finalize = builder_source_file_finalize;
|
||||
object_class->get_property = builder_source_file_get_property;
|
||||
object_class->set_property = builder_source_file_set_property;
|
||||
|
||||
source_class->download = builder_source_file_download;
|
||||
source_class->extract = builder_source_file_extract;
|
||||
source_class->checksum = builder_source_file_checksum;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_PATH,
|
||||
g_param_spec_string ("path",
|
||||
"",
|
||||
"",
|
||||
NULL,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_DEST_FILENAME,
|
||||
g_param_spec_string ("dest-filename",
|
||||
"",
|
||||
"",
|
||||
NULL,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_file_init (BuilderSourceFile *self)
|
||||
{
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright © 2015 Red Hat, Inc
|
||||
*
|
||||
* This program 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __BUILDER_SOURCE_FILE_H__
|
||||
#define __BUILDER_SOURCE_FILE_H__
|
||||
|
||||
#include "builder-source.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct BuilderSourceFile BuilderSourceFile;
|
||||
|
||||
#define BUILDER_TYPE_SOURCE_FILE (builder_source_file_get_type())
|
||||
#define BUILDER_SOURCE_FILE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BUILDER_TYPE_SOURCE_FILE, BuilderSourceFile))
|
||||
#define BUILDER_IS_SOURCE_FILE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BUILDER_TYPE_SOURCE_FILE))
|
||||
|
||||
GType builder_source_file_get_type (void);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(BuilderSourceFile, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __BUILDER_SOURCE_FILE_H__ */
|
|
@ -0,0 +1,402 @@
|
|||
/* builder-source-git.c
|
||||
*
|
||||
* Copyright (C) 2015 Red Hat, Inc
|
||||
*
|
||||
* This file 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 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This file 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 General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/statfs.h>
|
||||
|
||||
#include "builder-utils.h"
|
||||
|
||||
#include "builder-source-git.h"
|
||||
#include "builder-utils.h"
|
||||
|
||||
struct BuilderSourceGit {
|
||||
BuilderSource parent;
|
||||
|
||||
char *url;
|
||||
char *branch;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
BuilderSourceClass parent_class;
|
||||
} BuilderSourceGitClass;
|
||||
|
||||
G_DEFINE_TYPE (BuilderSourceGit, builder_source_git, BUILDER_TYPE_SOURCE);
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_URL,
|
||||
PROP_BRANCH,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
static void
|
||||
builder_source_git_finalize (GObject *object)
|
||||
{
|
||||
BuilderSourceGit *self = (BuilderSourceGit *)object;
|
||||
|
||||
g_free (self->url);
|
||||
g_free (self->branch);
|
||||
|
||||
G_OBJECT_CLASS (builder_source_git_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_git_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BuilderSourceGit *self = BUILDER_SOURCE_GIT (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_URL:
|
||||
g_value_set_string (value, self->url);
|
||||
break;
|
||||
|
||||
case PROP_BRANCH:
|
||||
g_value_set_string (value, self->branch);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_git_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BuilderSourceGit *self = BUILDER_SOURCE_GIT (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_URL:
|
||||
g_free (self->url);
|
||||
self->url = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
case PROP_BRANCH:
|
||||
g_free (self->branch);
|
||||
self->branch = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GError *error;
|
||||
GError *splice_error;
|
||||
GMainLoop *loop;
|
||||
int refs;
|
||||
} GitData;
|
||||
|
||||
static gboolean git (GFile *dir,
|
||||
char **output,
|
||||
GError **error,
|
||||
const gchar *argv1,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
|
||||
|
||||
static void
|
||||
git_data_exit (GitData *data)
|
||||
{
|
||||
data->refs--;
|
||||
if (data->refs == 0)
|
||||
g_main_loop_quit (data->loop);
|
||||
}
|
||||
|
||||
static void
|
||||
git_output_spliced_cb (GObject *obj,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
GitData *data = user_data;
|
||||
|
||||
g_output_stream_splice_finish (G_OUTPUT_STREAM (obj), result, &data->splice_error);
|
||||
git_data_exit (data);
|
||||
}
|
||||
|
||||
static void
|
||||
git_exit_cb (GObject *obj,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
GitData *data = user_data;
|
||||
|
||||
g_subprocess_wait_check_finish (G_SUBPROCESS (obj), result, &data->error);
|
||||
git_data_exit (data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
git (GFile *dir,
|
||||
char **output,
|
||||
GError **error,
|
||||
const gchar *argv1,
|
||||
...)
|
||||
{
|
||||
g_autoptr(GSubprocessLauncher) launcher = NULL;
|
||||
g_autoptr(GSubprocess) subp = NULL;
|
||||
GPtrArray *args;
|
||||
const gchar *arg;
|
||||
GInputStream *in;
|
||||
g_autoptr(GOutputStream) out = NULL;
|
||||
g_autoptr(GMainLoop) loop = NULL;
|
||||
va_list ap;
|
||||
GitData data = {0};
|
||||
|
||||
args = g_ptr_array_new ();
|
||||
g_ptr_array_add (args, "git");
|
||||
va_start (ap, argv1);
|
||||
g_ptr_array_add (args, (gchar *) argv1);
|
||||
while ((arg = va_arg (ap, const gchar *)))
|
||||
g_ptr_array_add (args, (gchar *) arg);
|
||||
g_ptr_array_add (args, NULL);
|
||||
va_end (ap);
|
||||
|
||||
launcher = g_subprocess_launcher_new (0);
|
||||
|
||||
if (output)
|
||||
g_subprocess_launcher_set_flags (launcher, G_SUBPROCESS_FLAGS_STDOUT_PIPE);
|
||||
|
||||
if (dir)
|
||||
{
|
||||
g_autofree char *path = g_file_get_path (dir);
|
||||
g_subprocess_launcher_set_cwd (launcher, path);
|
||||
}
|
||||
|
||||
subp = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
|
||||
g_ptr_array_free (args, TRUE);
|
||||
|
||||
if (subp == NULL)
|
||||
return FALSE;
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
data.loop = loop;
|
||||
data.refs = 1;
|
||||
|
||||
if (output)
|
||||
{
|
||||
data.refs++;
|
||||
in = g_subprocess_get_stdout_pipe (subp);
|
||||
out = g_memory_output_stream_new_resizable ();
|
||||
g_output_stream_splice_async (out,
|
||||
in,
|
||||
G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
|
||||
0,
|
||||
NULL,
|
||||
git_output_spliced_cb,
|
||||
&data);
|
||||
}
|
||||
|
||||
g_subprocess_wait_async (subp, NULL, git_exit_cb, &data);
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
if (data.error)
|
||||
{
|
||||
g_propagate_error (error, data.error);
|
||||
g_clear_error (&data.splice_error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (out)
|
||||
{
|
||||
if (data.splice_error)
|
||||
{
|
||||
g_propagate_error (error, data.splice_error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Null terminate */
|
||||
g_output_stream_write (out, "\0", 1, NULL, NULL);
|
||||
*output = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (out));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GFile *
|
||||
get_mirror_dir (BuilderSourceGit *self, BuilderContext *context)
|
||||
{
|
||||
g_autoptr(GFile) git_dir = NULL;
|
||||
g_autofree char *filename = NULL;
|
||||
g_autofree char *git_dir_path = NULL;
|
||||
|
||||
git_dir = g_file_get_child (builder_context_get_state_dir (context),
|
||||
"git");
|
||||
|
||||
git_dir_path = g_file_get_path (git_dir);
|
||||
g_mkdir_with_parents (git_dir_path, 0755);
|
||||
|
||||
filename = builder_uri_to_filename (self->url);
|
||||
return g_file_get_child (git_dir, filename);
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_branch (BuilderSourceGit *self)
|
||||
{
|
||||
if (self->branch)
|
||||
return self->branch;
|
||||
else
|
||||
return "master";
|
||||
}
|
||||
|
||||
static char *
|
||||
get_current_commit (BuilderSourceGit *self, BuilderContext *context, GError **error)
|
||||
{
|
||||
g_autoptr(GFile) mirror_dir = NULL;
|
||||
char *output = NULL;
|
||||
|
||||
mirror_dir = get_mirror_dir (self, context);
|
||||
|
||||
if (!git (mirror_dir, &output, error,
|
||||
"rev-parse", get_branch (self), NULL))
|
||||
return NULL;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
builder_source_git_download (BuilderSource *source,
|
||||
BuilderContext *context,
|
||||
GError **error)
|
||||
{
|
||||
BuilderSourceGit *self = BUILDER_SOURCE_GIT (source);
|
||||
g_autoptr(GFile) mirror_dir = NULL;
|
||||
|
||||
if (self->url == NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "URL not specified");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mirror_dir = get_mirror_dir (self, context);
|
||||
|
||||
if (!g_file_query_exists (mirror_dir, NULL))
|
||||
{
|
||||
g_autofree char *filename = g_file_get_basename (mirror_dir);
|
||||
g_autoptr(GFile) parent = g_file_get_parent (mirror_dir);
|
||||
g_autofree char *filename_tmp = g_strconcat (filename, ".clone_tmp", NULL);
|
||||
g_autoptr(GFile) mirror_dir_tmp = g_file_get_child (parent, filename_tmp);
|
||||
|
||||
if (!git (parent, NULL, error,
|
||||
"clone", "--mirror", self->url, filename_tmp, NULL) ||
|
||||
!g_file_move (mirror_dir_tmp, mirror_dir, 0, NULL, NULL, NULL, error))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!git (mirror_dir, NULL, error,
|
||||
"fetch", NULL))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
builder_source_git_extract (BuilderSource *source,
|
||||
GFile *dest,
|
||||
BuilderContext *context,
|
||||
GError **error)
|
||||
{
|
||||
BuilderSourceGit *self = BUILDER_SOURCE_GIT (source);
|
||||
g_autoptr(GFile) mirror_dir = NULL;
|
||||
g_autofree char *mirror_dir_path = NULL;
|
||||
g_autofree char *dest_path = NULL;
|
||||
|
||||
mirror_dir = get_mirror_dir (self, context);
|
||||
|
||||
mirror_dir_path = g_file_get_path (mirror_dir);
|
||||
dest_path = g_file_get_path (dest);
|
||||
|
||||
if (!git (NULL, NULL, error,
|
||||
"clone", "--branch", get_branch (self), "--recursive", mirror_dir_path, dest_path, NULL))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_git_checksum (BuilderSource *source,
|
||||
BuilderCache *cache,
|
||||
BuilderContext *context)
|
||||
{
|
||||
BuilderSourceGit *self = BUILDER_SOURCE_GIT (source);
|
||||
g_autofree char *current_commit;
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
builder_cache_checksum_str (cache, self->url);
|
||||
builder_cache_checksum_str (cache, self->branch);
|
||||
|
||||
current_commit = get_current_commit (self, context, &error);
|
||||
if (current_commit)
|
||||
builder_cache_checksum_str (cache, current_commit);
|
||||
else if (error)
|
||||
g_warning ("Failed to get current git checksum: %s", error->message);
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_git_class_init (BuilderSourceGitClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
BuilderSourceClass *source_class = BUILDER_SOURCE_CLASS (klass);
|
||||
|
||||
object_class->finalize = builder_source_git_finalize;
|
||||
object_class->get_property = builder_source_git_get_property;
|
||||
object_class->set_property = builder_source_git_set_property;
|
||||
|
||||
source_class->download = builder_source_git_download;
|
||||
source_class->extract = builder_source_git_extract;
|
||||
source_class->checksum = builder_source_git_checksum;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_URL,
|
||||
g_param_spec_string ("url",
|
||||
"",
|
||||
"",
|
||||
NULL,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_BRANCH,
|
||||
g_param_spec_string ("branch",
|
||||
"",
|
||||
"",
|
||||
NULL,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_git_init (BuilderSourceGit *self)
|
||||
{
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright © 2015 Red Hat, Inc
|
||||
*
|
||||
* This program 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __BUILDER_SOURCE_GIT_H__
|
||||
#define __BUILDER_SOURCE_GIT_H__
|
||||
|
||||
#include "builder-source.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct BuilderSourceGit BuilderSourceGit;
|
||||
|
||||
#define BUILDER_TYPE_SOURCE_GIT (builder_source_git_get_type())
|
||||
#define BUILDER_SOURCE_GIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BUILDER_TYPE_SOURCE_GIT, BuilderSourceGit))
|
||||
#define BUILDER_IS_SOURCE_GIT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BUILDER_TYPE_SOURCE_GIT))
|
||||
|
||||
GType builder_source_git_get_type (void);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(BuilderSourceGit, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __BUILDER_SOURCE_GIT_H__ */
|
|
@ -0,0 +1,265 @@
|
|||
/* builder-source-patch.c
|
||||
*
|
||||
* Copyright (C) 2015 Red Hat, Inc
|
||||
*
|
||||
* This file 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 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This file 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 General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/statfs.h>
|
||||
|
||||
#include "xdg-app-utils.h"
|
||||
|
||||
#include "builder-utils.h"
|
||||
#include "builder-source-patch.h"
|
||||
|
||||
struct BuilderSourcePatch {
|
||||
BuilderSource parent;
|
||||
|
||||
char *path;
|
||||
guint strip_components;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
BuilderSourceClass parent_class;
|
||||
} BuilderSourcePatchClass;
|
||||
|
||||
G_DEFINE_TYPE (BuilderSourcePatch, builder_source_patch, BUILDER_TYPE_SOURCE);
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_PATH,
|
||||
PROP_STRIP_COMPONENTS,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
static void
|
||||
builder_source_patch_finalize (GObject *object)
|
||||
{
|
||||
BuilderSourcePatch *self = (BuilderSourcePatch *)object;
|
||||
|
||||
g_free (self->path);
|
||||
|
||||
G_OBJECT_CLASS (builder_source_patch_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_patch_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BuilderSourcePatch *self = BUILDER_SOURCE_PATCH (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PATH:
|
||||
g_value_set_string (value, self->path);
|
||||
break;
|
||||
|
||||
case PROP_STRIP_COMPONENTS:
|
||||
g_value_set_uint (value, self->strip_components);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_patch_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BuilderSourcePatch *self = BUILDER_SOURCE_PATCH (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PATH:
|
||||
g_free (self->path);
|
||||
self->path = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
case PROP_STRIP_COMPONENTS:
|
||||
self->strip_components = g_value_get_uint (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static GFile *
|
||||
get_source_file (BuilderSourcePatch *self,
|
||||
BuilderContext *context,
|
||||
GError **error)
|
||||
{
|
||||
if (self->path == NULL || self->path[0] == 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "path not specified");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return g_file_resolve_relative_path (builder_context_get_base_dir (context), self->path);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
builder_source_patch_download (BuilderSource *source,
|
||||
BuilderContext *context,
|
||||
GError **error)
|
||||
{
|
||||
BuilderSourcePatch *self = BUILDER_SOURCE_PATCH (source);
|
||||
g_autoptr(GFile) src = NULL;
|
||||
|
||||
src = get_source_file (self, context, error);
|
||||
if (src == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (!g_file_query_exists (src, NULL))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Can't find file at %s", self->path);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
patch (GFile *dir,
|
||||
GError **error,
|
||||
const gchar *argv1,
|
||||
...)
|
||||
{
|
||||
g_autoptr(GSubprocessLauncher) launcher = NULL;
|
||||
g_autoptr(GSubprocess) subp = NULL;
|
||||
GPtrArray *args;
|
||||
const gchar *arg;
|
||||
va_list ap;
|
||||
|
||||
args = g_ptr_array_new ();
|
||||
g_ptr_array_add (args, "patch");
|
||||
va_start (ap, argv1);
|
||||
g_ptr_array_add (args, (gchar *) argv1);
|
||||
while ((arg = va_arg (ap, const gchar *)))
|
||||
g_ptr_array_add (args, (gchar *) arg);
|
||||
g_ptr_array_add (args, NULL);
|
||||
va_end (ap);
|
||||
|
||||
launcher = g_subprocess_launcher_new (0);
|
||||
|
||||
if (dir)
|
||||
{
|
||||
g_autofree char *path = g_file_get_path (dir);
|
||||
g_subprocess_launcher_set_cwd (launcher, path);
|
||||
}
|
||||
|
||||
subp = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
|
||||
g_ptr_array_free (args, TRUE);
|
||||
|
||||
if (subp == NULL ||
|
||||
!g_subprocess_wait_check (subp, NULL, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
builder_source_patch_extract (BuilderSource *source,
|
||||
GFile *dest,
|
||||
BuilderContext *context,
|
||||
GError **error)
|
||||
{
|
||||
BuilderSourcePatch *self = BUILDER_SOURCE_PATCH (source);
|
||||
g_autoptr(GFile) patchfile = NULL;
|
||||
g_autofree char *patch_path = NULL;
|
||||
g_autofree char *strip_components = NULL;
|
||||
|
||||
patchfile = get_source_file (self, context, error);
|
||||
if (patchfile == NULL)
|
||||
return FALSE;
|
||||
|
||||
strip_components = g_strdup_printf ("-p%u", self->strip_components);
|
||||
patch_path = g_file_get_path (patchfile);
|
||||
if (!patch (dest, error, strip_components, "-i", patch_path, NULL))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_patch_checksum (BuilderSource *source,
|
||||
BuilderCache *cache,
|
||||
BuilderContext *context)
|
||||
{
|
||||
BuilderSourcePatch *self = BUILDER_SOURCE_PATCH (source);
|
||||
g_autoptr(GFile) src = NULL;
|
||||
g_autofree char *data = NULL;
|
||||
gsize len;
|
||||
|
||||
src = get_source_file (self, context, NULL);
|
||||
if (src == NULL)
|
||||
return;
|
||||
|
||||
if (g_file_load_contents (src, NULL, &data, &len, NULL, NULL))
|
||||
builder_cache_checksum_data (cache, (guchar *)data, len);
|
||||
|
||||
builder_cache_checksum_str (cache, self->path);
|
||||
builder_cache_checksum_uint32 (cache, self->strip_components);
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_patch_class_init (BuilderSourcePatchClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
BuilderSourceClass *source_class = BUILDER_SOURCE_CLASS (klass);
|
||||
|
||||
object_class->finalize = builder_source_patch_finalize;
|
||||
object_class->get_property = builder_source_patch_get_property;
|
||||
object_class->set_property = builder_source_patch_set_property;
|
||||
|
||||
source_class->download = builder_source_patch_download;
|
||||
source_class->extract = builder_source_patch_extract;
|
||||
source_class->checksum = builder_source_patch_checksum;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_PATH,
|
||||
g_param_spec_string ("path",
|
||||
"",
|
||||
"",
|
||||
NULL,
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_STRIP_COMPONENTS,
|
||||
g_param_spec_uint ("strip-components",
|
||||
"",
|
||||
"",
|
||||
0, G_MAXUINT,
|
||||
1,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_patch_init (BuilderSourcePatch *self)
|
||||
{
|
||||
self->strip_components = 1;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright © 2015 Red Hat, Inc
|
||||
*
|
||||
* This program 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __BUILDER_SOURCE_PATCH_H__
|
||||
#define __BUILDER_SOURCE_PATCH_H__
|
||||
|
||||
#include "builder-source.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct BuilderSourcePatch BuilderSourcePatch;
|
||||
|
||||
#define BUILDER_TYPE_SOURCE_PATCH (builder_source_patch_get_type())
|
||||
#define BUILDER_SOURCE_PATCH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BUILDER_TYPE_SOURCE_PATCH, BuilderSourcePatch))
|
||||
#define BUILDER_IS_SOURCE_PATCH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BUILDER_TYPE_SOURCE_PATCH))
|
||||
|
||||
GType builder_source_patch_get_type (void);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(BuilderSourcePatch, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __BUILDER_SOURCE_PATCH_H__ */
|
|
@ -0,0 +1,227 @@
|
|||
/* builder-source.c
|
||||
*
|
||||
* Copyright (C) 2015 Red Hat, Inc
|
||||
*
|
||||
* This file 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 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This file 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 General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/statfs.h>
|
||||
|
||||
#include "builder-utils.h"
|
||||
#include "builder-source.h"
|
||||
#include "builder-source-archive.h"
|
||||
#include "builder-source-patch.h"
|
||||
#include "builder-source-git.h"
|
||||
#include "builder-source-bzr.h"
|
||||
#include "builder-source-file.h"
|
||||
|
||||
static void serializable_iface_init (JsonSerializableIface *serializable_iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (BuilderSource, builder_source, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (JSON_TYPE_SERIALIZABLE, serializable_iface_init));
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_DEST,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
builder_source_finalize (GObject *object)
|
||||
{
|
||||
BuilderSource *self = BUILDER_SOURCE (object);
|
||||
|
||||
g_free (self->dest);
|
||||
|
||||
G_OBJECT_CLASS (builder_source_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BuilderSource *self = BUILDER_SOURCE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DEST:
|
||||
g_value_set_string (value, self->dest);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BuilderSource *self = BUILDER_SOURCE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DEST:
|
||||
g_free (self->dest);
|
||||
self->dest = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
builder_source_real_download (BuilderSource *self,
|
||||
BuilderContext *context,
|
||||
GError **error)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Download not implemented for type %s", g_type_name_from_instance ((GTypeInstance *)self));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
builder_source_real_extract (BuilderSource *self,
|
||||
GFile *dest,
|
||||
BuilderContext *context,
|
||||
GError **error)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Extract not implemented for type %s", g_type_name_from_instance ((GTypeInstance *)self));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_class_init (BuilderSourceClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = builder_source_finalize;
|
||||
object_class->get_property = builder_source_get_property;
|
||||
object_class->set_property = builder_source_set_property;
|
||||
|
||||
klass->download = builder_source_real_download;
|
||||
klass->extract = builder_source_real_extract;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_DEST,
|
||||
g_param_spec_string ("dest",
|
||||
"",
|
||||
"",
|
||||
NULL,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
builder_source_init (BuilderSource *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
serializable_iface_init (JsonSerializableIface *serializable_iface)
|
||||
{
|
||||
}
|
||||
|
||||
BuilderSource *
|
||||
builder_source_from_json (JsonNode *node)
|
||||
{
|
||||
JsonObject *object = json_node_get_object (node);
|
||||
const gchar *type;
|
||||
|
||||
type = json_object_get_string_member (object, "type");
|
||||
|
||||
if (strcmp (type, "archive") == 0)
|
||||
return (BuilderSource *)json_gobject_deserialize (BUILDER_TYPE_SOURCE_ARCHIVE, node);
|
||||
if (strcmp (type, "file") == 0)
|
||||
return (BuilderSource *)json_gobject_deserialize (BUILDER_TYPE_SOURCE_FILE, node);
|
||||
if (strcmp (type, "patch") == 0)
|
||||
return (BuilderSource *)json_gobject_deserialize (BUILDER_TYPE_SOURCE_PATCH, node);
|
||||
if (strcmp (type, "git") == 0)
|
||||
return (BuilderSource *)json_gobject_deserialize (BUILDER_TYPE_SOURCE_GIT, node);
|
||||
if (strcmp (type, "bzr") == 0)
|
||||
return (BuilderSource *)json_gobject_deserialize (BUILDER_TYPE_SOURCE_BZR, node);
|
||||
else if (type == NULL)
|
||||
g_warning ("Missing source type");
|
||||
else
|
||||
g_warning ("Unknown source type %s", type);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
builder_source_download (BuilderSource *self,
|
||||
BuilderContext *context,
|
||||
GError **error)
|
||||
{
|
||||
BuilderSourceClass *class;
|
||||
|
||||
class = BUILDER_SOURCE_GET_CLASS (self);
|
||||
|
||||
return class->download (self, context, error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
builder_source_extract (BuilderSource *self,
|
||||
GFile *dest,
|
||||
BuilderContext *context,
|
||||
GError **error)
|
||||
{
|
||||
BuilderSourceClass *class;
|
||||
g_autoptr(GFile) real_dest;
|
||||
|
||||
class = BUILDER_SOURCE_GET_CLASS (self);
|
||||
|
||||
if (self->dest != NULL)
|
||||
{
|
||||
real_dest = g_file_resolve_relative_path (dest, self->dest);
|
||||
|
||||
if (!g_file_query_exists (real_dest, NULL) &&
|
||||
!g_file_make_directory_with_parents (real_dest, NULL, error))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
real_dest = g_object_ref (dest);
|
||||
|
||||
|
||||
return class->extract (self, real_dest, context, error);
|
||||
}
|
||||
|
||||
void
|
||||
builder_source_checksum (BuilderSource *self,
|
||||
BuilderCache *cache,
|
||||
BuilderContext *context)
|
||||
{
|
||||
BuilderSourceClass *class;
|
||||
|
||||
class = BUILDER_SOURCE_GET_CLASS (self);
|
||||
|
||||
builder_cache_checksum_str (cache, self->dest);
|
||||
|
||||
class->checksum (self, cache, context);
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright © 2015 Red Hat, Inc
|
||||
*
|
||||
* This program 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __BUILDER_SOURCE_H__
|
||||
#define __BUILDER_SOURCE_H__
|
||||
|
||||
#include <json-glib/json-glib.h>
|
||||
|
||||
#include "builder-context.h"
|
||||
#include "builder-cache.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct BuilderSource BuilderSource;
|
||||
|
||||
#define BUILDER_TYPE_SOURCE (builder_source_get_type())
|
||||
#define BUILDER_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BUILDER_TYPE_SOURCE, BuilderSource))
|
||||
#define BUILDER_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), BUILDER_TYPE_SOURCE, BuilderSourceClass))
|
||||
#define BUILDER_IS_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BUILDER_TYPE_SOURCE))
|
||||
#define BUILDER_IS_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), BUILDER_TYPE_SOURCE))
|
||||
#define BUILDER_SOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), BUILDER_TYPE_SOURCE, BuilderSourceClass))
|
||||
|
||||
struct BuilderSource {
|
||||
GObject parent;
|
||||
|
||||
char *dest;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
GObjectClass parent_class;
|
||||
|
||||
gboolean (* download) (BuilderSource *self,
|
||||
BuilderContext *context,
|
||||
GError **error);
|
||||
gboolean (* extract) (BuilderSource *self,
|
||||
GFile *dest,
|
||||
BuilderContext *context,
|
||||
GError **error);
|
||||
void (* checksum) (BuilderSource *self,
|
||||
BuilderCache *cache,
|
||||
BuilderContext *context);
|
||||
} BuilderSourceClass;
|
||||
|
||||
GType builder_source_get_type (void);
|
||||
|
||||
BuilderSource * builder_source_from_json (JsonNode *node);
|
||||
|
||||
gboolean builder_source_download (BuilderSource *self,
|
||||
BuilderContext *context,
|
||||
GError **error);
|
||||
gboolean builder_source_extract (BuilderSource *self,
|
||||
GFile *dest,
|
||||
BuilderContext *context,
|
||||
GError **error);
|
||||
|
||||
void builder_source_checksum (BuilderSource *self,
|
||||
BuilderCache *cache,
|
||||
BuilderContext *context);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(BuilderSource, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __BUILDER_SOURCE_H__ */
|
|
@ -0,0 +1,119 @@
|
|||
/* builder-utils.c
|
||||
*
|
||||
* Copyright (C) 2015 Red Hat, Inc
|
||||
*
|
||||
* This file 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 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This file 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 General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "builder-utils.h"
|
||||
|
||||
char *
|
||||
builder_uri_to_filename (const char *uri)
|
||||
{
|
||||
GString *s;
|
||||
const char *p;
|
||||
gboolean saw_slash = FALSE;
|
||||
gboolean saw_after_slash = FALSE;
|
||||
|
||||
s = g_string_new ("");
|
||||
|
||||
for (p = uri; *p != 0; p++)
|
||||
{
|
||||
if (*p == '/')
|
||||
{
|
||||
saw_slash = TRUE;
|
||||
if (saw_after_slash) /* Skip first slashes */
|
||||
g_string_append_c (s, '_');
|
||||
continue;
|
||||
}
|
||||
else if (saw_slash)
|
||||
saw_after_slash = TRUE;
|
||||
g_string_append_c (s, *p);
|
||||
}
|
||||
|
||||
return g_string_free (s, FALSE);
|
||||
}
|
||||
|
||||
/* Returns end of matching path prefix, or NULL if no match */
|
||||
const char *
|
||||
path_prefix_match (const char *pattern,
|
||||
const char *string)
|
||||
{
|
||||
char c, test;
|
||||
const char *tmp;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
switch (c = *pattern++)
|
||||
{
|
||||
case 0:
|
||||
if (*string == '/' || *string == 0)
|
||||
return string;
|
||||
return NULL;
|
||||
|
||||
case '?':
|
||||
if (*string == '/' || *string == 0)
|
||||
return NULL;
|
||||
string++;
|
||||
break;
|
||||
|
||||
case '*':
|
||||
c = *pattern;
|
||||
|
||||
while (c == '*')
|
||||
c = *++pattern;
|
||||
|
||||
/* special case * at end */
|
||||
if (c == 0)
|
||||
{
|
||||
char *tmp = strchr (string, '/');
|
||||
if (tmp != NULL)
|
||||
return tmp;
|
||||
return string + strlen (string);
|
||||
}
|
||||
else if (c == '/')
|
||||
{
|
||||
string = strchr (string, '/');
|
||||
if (string == NULL)
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
while ((test = *string) != 0)
|
||||
{
|
||||
tmp = path_prefix_match (pattern, string);
|
||||
if (tmp != NULL)
|
||||
return tmp;
|
||||
if (test == '/')
|
||||
break;
|
||||
string++;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
default:
|
||||
if (c != *string)
|
||||
return NULL;
|
||||
string++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NULL; /* Should not be reached */
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright © 2015 Red Hat, Inc
|
||||
*
|
||||
* This program 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __BUILDER_UTILS_H__
|
||||
#define __BUILDER_UTILS_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <libsoup/soup.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct BuilderUtils BuilderUtils;
|
||||
|
||||
char *builder_uri_to_filename (const char *uri);
|
||||
|
||||
const char *path_prefix_match (const char *pattern,
|
||||
const char *string);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __BUILDER_UTILS_H__ */
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* Copyright © 2015 Red Hat, Inc
|
||||
*
|
||||
* This program 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <locale.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include "libglnx/libglnx.h"
|
||||
#include "libgsystem.h"
|
||||
|
||||
#include "builder-manifest.h"
|
||||
|
||||
static gboolean opt_verbose;
|
||||
static gboolean opt_version;
|
||||
static gboolean opt_disable_cache;
|
||||
static gboolean opt_download_only;
|
||||
static gboolean opt_disable_download;
|
||||
static gboolean opt_require_changes;
|
||||
|
||||
static GOptionEntry entries[] = {
|
||||
{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &opt_verbose, "Print debug information during command processing", NULL },
|
||||
{ "version", 0, 0, G_OPTION_ARG_NONE, &opt_version, "Print version information and exit", NULL },
|
||||
{ "disable-cache", 0, 0, G_OPTION_ARG_NONE, &opt_disable_cache, "Disable cache", NULL },
|
||||
{ "disable-download", 0, 0, G_OPTION_ARG_NONE, &opt_disable_download, "Don't download any new sources", NULL },
|
||||
{ "download-only", 0, 0, G_OPTION_ARG_NONE, &opt_download_only, "Only download sources, don't build", NULL },
|
||||
{ "require-changes", 0, 0, G_OPTION_ARG_NONE, &opt_require_changes, "Don't create app dir if no changes", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
message_handler (const gchar *log_domain,
|
||||
GLogLevelFlags log_level,
|
||||
const gchar *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
/* Make this look like normal console output */
|
||||
if (log_level & G_LOG_LEVEL_DEBUG)
|
||||
g_printerr ("XAB: %s\n", message);
|
||||
else
|
||||
g_printerr ("%s: %s\n", g_get_prgname (), message);
|
||||
}
|
||||
|
||||
int
|
||||
usage (GOptionContext *context, const char *message)
|
||||
{
|
||||
g_autofree gchar *help = g_option_context_get_help (context, TRUE, NULL);
|
||||
g_printerr ("%s\n", message);
|
||||
g_printerr ("%s", help);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
g_autofree const char *old_env = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(BuilderManifest) manifest = NULL;
|
||||
GOptionContext *context;
|
||||
const char *app_dir_path, *manifest_path;
|
||||
g_autofree gchar *json = NULL;
|
||||
g_autoptr(BuilderContext) build_context = NULL;
|
||||
g_autoptr(GFile) base_dir = NULL;
|
||||
g_autoptr(GFile) app_dir = NULL;
|
||||
g_autoptr(BuilderCache) cache = NULL;
|
||||
g_autofree char *cache_branch = NULL;
|
||||
|
||||
setlocale (LC_ALL, "");
|
||||
|
||||
g_log_set_handler (NULL, G_LOG_LEVEL_MESSAGE, message_handler, NULL);
|
||||
|
||||
g_set_prgname (argv[0]);
|
||||
|
||||
/* avoid gvfs (http://bugzilla.gnome.org/show_bug.cgi?id=526454) */
|
||||
old_env = g_strdup (g_getenv ("GIO_USE_VFS"));
|
||||
g_setenv ("GIO_USE_VFS", "local", TRUE);
|
||||
g_vfs_get_default ();
|
||||
if (old_env)
|
||||
g_setenv ("GIO_USE_VFS", old_env, TRUE);
|
||||
else
|
||||
g_unsetenv ("GIO_USE_VFS");
|
||||
|
||||
context = g_option_context_new ("DIRECTORY MANIFEST - Build manifest");
|
||||
g_option_context_add_main_entries (context, entries, NULL);
|
||||
if (!g_option_context_parse (context, &argc, &argv, &error))
|
||||
{
|
||||
g_printerr ("option parsing failed: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (opt_version)
|
||||
{
|
||||
g_print ("%s\n", PACKAGE_STRING);
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (opt_verbose)
|
||||
g_log_set_handler (NULL, G_LOG_LEVEL_DEBUG, message_handler, NULL);
|
||||
|
||||
if (argc == 1)
|
||||
return usage (context, "DIRECTORY must be specified");
|
||||
|
||||
app_dir_path = argv[1];
|
||||
|
||||
if (argc == 2)
|
||||
return usage (context, "MANIFEST must be specified");
|
||||
|
||||
manifest_path = argv[2];
|
||||
|
||||
if (!g_file_get_contents (manifest_path, &json, NULL, &error))
|
||||
{
|
||||
g_printerr ("Can't load '%s': %s\n", manifest_path, error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
manifest = (BuilderManifest *)json_gobject_from_data (BUILDER_TYPE_MANIFEST,
|
||||
json, -1, &error);
|
||||
if (manifest == NULL)
|
||||
{
|
||||
g_printerr ("Can't parse '%s': %s\n", manifest_path, error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
base_dir = g_file_new_for_path (g_get_current_dir ());
|
||||
app_dir = g_file_new_for_path (app_dir_path);
|
||||
|
||||
if (!gs_shutil_rm_rf (app_dir, NULL, &error))
|
||||
{
|
||||
g_print ("error removing old app dir '%s': %s\n", app_dir_path, error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
build_context = builder_context_new (base_dir, app_dir);
|
||||
|
||||
if (!opt_disable_download)
|
||||
{
|
||||
if (!builder_manifest_download (manifest, build_context, &error))
|
||||
{
|
||||
g_print ("error: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (opt_download_only)
|
||||
return 0;
|
||||
|
||||
cache_branch = g_path_get_basename (manifest_path);
|
||||
|
||||
cache = builder_cache_new (builder_context_get_cache_dir (build_context), app_dir, cache_branch);
|
||||
if (!builder_cache_open (cache, &error))
|
||||
{
|
||||
g_print ("Error opening cache: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (opt_disable_cache) /* This disables *lookups*, but we still build the cache */
|
||||
builder_cache_disable_lookups (cache);
|
||||
|
||||
builder_manifest_checksum (manifest, cache, build_context);
|
||||
|
||||
if (!builder_cache_lookup (cache))
|
||||
{
|
||||
g_autofree char *body =
|
||||
g_strdup_printf ("Initialized %s\n",
|
||||
builder_manifest_get_app_id (manifest));
|
||||
if (!builder_manifest_init_app_dir (manifest, build_context, &error))
|
||||
{
|
||||
g_print ("error: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!builder_cache_commit (cache, body, &error))
|
||||
{
|
||||
g_print ("error: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!builder_manifest_build (manifest, cache, build_context, &error))
|
||||
{
|
||||
g_print ("error: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!builder_manifest_cleanup (manifest, cache, build_context, &error))
|
||||
{
|
||||
g_print ("error: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!builder_manifest_finish (manifest, cache, build_context, &error))
|
||||
{
|
||||
g_print ("error: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!opt_require_changes)
|
||||
builder_cache_ensure_checkout (cache);
|
||||
|
||||
if (!builder_gc (cache, &error))
|
||||
{
|
||||
g_warning ("Failed to GC build cache: %s\n", error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -75,6 +75,10 @@ PKG_CHECK_MODULES(FUSE, [fuse])
|
|||
AC_SUBST(FUSE_CFLAGS)
|
||||
AC_SUBST(FUSE_LIBS)
|
||||
|
||||
PKG_CHECK_MODULES(JSON, [json-glib-1.0])
|
||||
AC_SUBST(JSON_CFLAGS)
|
||||
AC_SUBST(JSON_LIBS)
|
||||
|
||||
AC_ARG_ENABLE([seccomp],
|
||||
AC_HELP_STRING([--disable-seccomp],
|
||||
[Disable seccomp]),
|
||||
|
|
|
@ -37,6 +37,7 @@ man_MANS = \
|
|||
xdg-app-build-finish.1 \
|
||||
xdg-app-build-export.1 \
|
||||
xdg-app-repo-update.1 \
|
||||
xdg-app-builder.1 \
|
||||
$(NULL)
|
||||
|
||||
xml_files = $(man_MANS:.1=.xml)
|
||||
|
|
|
@ -0,0 +1,512 @@
|
|||
<?xml version='1.0'?> <!--*-nxml-*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
|
||||
<refentry id="xdg-app-builder">
|
||||
|
||||
<refentryinfo>
|
||||
<title>xdg-app builder</title>
|
||||
<productname>xdg-app</productname>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<contrib>Developer</contrib>
|
||||
<firstname>Alexander</firstname>
|
||||
<surname>Larsson</surname>
|
||||
<email>alexl@redhat.com</email>
|
||||
</author>
|
||||
</authorgroup>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>xdg-app-builder</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>xdg-app-builder</refname>
|
||||
<refpurpose>Help build application dependencies</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>xdg-app-builder</command>
|
||||
<arg choice="opt" rep="repeat">OPTION</arg>
|
||||
<arg choice="plain">DIRECTORY</arg>
|
||||
<arg choice="plain">MANIFEST</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para>
|
||||
<command>xdg-app-builder</command> is a wrapper around the <command>xdg-app build</command> command
|
||||
that automates the building of applications and their dependencies. It is one option you can use
|
||||
to build applications.
|
||||
</para>
|
||||
<para>
|
||||
The goal of <command>xdg-app-builder</command> is to push as much knowledge about how to build modules to
|
||||
the individual upstream projects. It does this by assuming that the modules adhere to the Build API specified
|
||||
at https://github.com/cgwalters/build-api. This essentially means that it follows the <command>./configure
|
||||
&& make && make install</command> scheme with an optional autogen script. If the upstream
|
||||
does not adhere to the API you can make it do so by adding patches and extra files.
|
||||
</para>
|
||||
<para>
|
||||
A invocation of <command>xdg-app-builder</command> proceeds in these stages, each being specified
|
||||
in detail in json format in <arg choice="plain">MANIFEST</arg>:
|
||||
<itemizedlist mark='bullet'>
|
||||
<listitem>
|
||||
<para>Download all sources</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Initialize the application directory with <command>xdg-app build-init</command></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Build and install each module with <command>xdg-app build</command></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Clean up the final build tree by removing unwanted files and e.g. stripping binaries</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Finish the application directory with <command>xdg-app build-finish</command></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
After this you will end up with a build of the application in <arg choice="plain">DIRECTORY</arg>, which you can
|
||||
export to a repository with the <command>xdg-app build-export</command> command.
|
||||
</para>
|
||||
<para>
|
||||
At each of the above steps xdg-app caches the result, and if you build the same file again, it will start
|
||||
of at the first step where something changes. For instance the first version controlled source that had
|
||||
new commits added, or the first module where some changes to the <arg choice="plain">MANIFEST</arg> file caused
|
||||
the build environment to change. This makes xdg-app-builder very efficient for incremental builds.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Manifest format</title>
|
||||
<refsect2>
|
||||
<title>Toplevel</title>
|
||||
<para>
|
||||
The top level of the json file describes global
|
||||
attributes of the application, and how it can be
|
||||
build, and the list of modules that need to be
|
||||
built.
|
||||
</para>
|
||||
<para>
|
||||
These are the properties that are accepted:
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>app-id</option></term>
|
||||
<listitem><para>A string defining the application id.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>version</option></term>
|
||||
<listitem><para>The version of the application, defaults to master.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>runtime</option></term>
|
||||
<listitem><para>The name of the runtime that the application uses.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>runtime-version</option></term>
|
||||
<listitem><para>The version of theruntime that the application uses, defaults to master.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>sdk</option></term>
|
||||
<listitem><para>The name of the development runtime that the application builds with.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>command</option></term>
|
||||
<listitem><para>The filename or path to the main binary of the application.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>build-options</option></term>
|
||||
<listitem><para>object specifying the build environment. See below for details.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>modules</option></term>
|
||||
<listitem><para>An array of object specifying the modules to be built in order.
|
||||
See below for details.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>cleanup</option></term>
|
||||
<listitem><para>An array of file patterns that should be removed at the end.
|
||||
Patterns starting with / are taken to be full pathnames, otherwise they just match
|
||||
the basename.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>finish-args</option></term>
|
||||
<listitem><para>An array of arguments passed to the <command>xdg-app build-finish</command> command</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>strip</option></term>
|
||||
<listitem><para>If this is true (the default) then all ELF files will be stripped during the cleanup phase.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>rename-desktop-file</option></term>
|
||||
<listitem><para>Any desktop file with this name will be renamed to a name based on app-id during the cleanup phase.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>rename-icon</option></term>
|
||||
<listitem><para>Any icon with this name will be renamed to a name based on app-id during the cleanup phase.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>desktop-file-name-prefix</option></term>
|
||||
<listitem><para>This string will be prefixed to the Name key in the main application desktop file.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>desktop-file-name-suffixed</option></term>
|
||||
<listitem><para>This string will be suffixed to the Name key in the main application desktop file.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
</refsect2>
|
||||
<refsect2>
|
||||
<title>Build Options</title>
|
||||
<para>
|
||||
Build options specify the build environment of a module, and can be specified globally as
|
||||
well as per-module. Options can also be specified on a per-architecture basis using the arch property.
|
||||
</para>
|
||||
<para>
|
||||
These are the properties that are accepted:
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>cflags</option></term>
|
||||
<listitem><para>This is set in the environment variable CFLAGS during the build.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>cxxflags</option></term>
|
||||
<listitem><para>This is set in the environment variable CXXFLAGS during the build.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>env</option></term>
|
||||
<listitem><para>This is a dictionary defining environment variables to be set during the build.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>arch</option></term>
|
||||
<listitem><para>This is a dictionary defining for each arch a separate build options object that override the main one</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect2>
|
||||
<refsect2>
|
||||
<title>Module</title>
|
||||
<para>
|
||||
Each module specifies a source that has to be separately built and installed. It contains
|
||||
the build options and a list of sources to download and extract before building.
|
||||
</para>
|
||||
<para>
|
||||
These are the properties that are accepted:
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>name</option></term>
|
||||
<listitem><para>The name of the module, used in e.g. build logs</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option></option>sources</term>
|
||||
<listitem><para>An array of objects defining sources that will be downloaded and extracted in order</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>config-opts</option></term>
|
||||
<listitem><para>An array of options that will be passed to configure</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>make-args</option></term>
|
||||
<listitem><para>An array of arguments that will be passed to make</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>make-install-args</option></term>
|
||||
<listitem><para>An array of arguments that will be passed to make install</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>rm-configure</option></term>
|
||||
<listitem><para>If true, remove the configure script before starting build</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>no-autogen</option></term>
|
||||
<listitem><para>Ignore the existance of an autogen script</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>build-options</option></term>
|
||||
<listitem><para>A build options object that can override global options</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>cleanup</option></term>
|
||||
<listitem><para>An array of file patterns that should be removed at the end.
|
||||
Patterns starting with / are taken to be full pathnames, otherwise they just match
|
||||
the basename. Note that any patterns will only match files installed by this module.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect2>
|
||||
<refsect2>
|
||||
<title>Sources</title>
|
||||
<para>
|
||||
These contain a pointer to the source that will be extracted into the source directory before
|
||||
the build starts. They can be of several types, distiguished by the type property.
|
||||
</para>
|
||||
<refsect3>
|
||||
<title>Archive sources (tar, zip)</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>type</option></term>
|
||||
<listitem><para>"archive"</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>url</option></term>
|
||||
<listitem><para>URL of the archive</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>sha256</option></term>
|
||||
<listitem><para>The sha256 checksum of the file, verified after download</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>strip-components</option></term>
|
||||
<listitem><para>The number of initial pathname components to strip during extraction. Defaults to 1.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>dest</option></term>
|
||||
<listitem><para>Directory inside the source dir where the archive will be extracted.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect3>
|
||||
<refsect3>
|
||||
<title>Git sources</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>type</option></term>
|
||||
<listitem><para>"git"</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>url</option></term>
|
||||
<listitem><para>URL of the git repostiory</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>branch</option></term>
|
||||
<listitem><para>The branch/tag/commit to use from the git repostiory</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>dest</option></term>
|
||||
<listitem><para>Directory inside the source dir where the repository will be checked out.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect3>
|
||||
<refsect3>
|
||||
<title>Bzr sources</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>type</option></term>
|
||||
<listitem><para>"bzr"</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>url</option></term>
|
||||
<listitem><para>URL of the bzr repostiory</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>dest</option></term>
|
||||
<listitem><para>Directory inside the source dir where the repository will be checked out.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect3>
|
||||
<refsect3>
|
||||
<title>File sources</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>type</option></term>
|
||||
<listitem><para>"file"</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>path</option></term>
|
||||
<listitem><para>The path of a local file that will be copied into the source dir</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>dest-filename</option></term>
|
||||
<listitem><para>Filename to use inside the source dir, default to the basename of path.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>dest</option></term>
|
||||
<listitem><para>Directory inside the source dir where the file will be copied.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect3>
|
||||
<refsect3>
|
||||
<title>Patch sources</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>type</option></term>
|
||||
<listitem><para>"patch"</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>path</option></term>
|
||||
<listitem><para>The path of a patch file that will be applied in the source dir</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>strip-components</option></term>
|
||||
<listitem><para>The value of the -p argument to patch, defaults to 1.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>dest</option></term>
|
||||
<listitem><para>Directory inside the source dir where the patch will be applied.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect3>
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
|
||||
<para>The following options are understood:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>-h</option></term>
|
||||
<term><option>--help</option></term>
|
||||
|
||||
<listitem><para>
|
||||
Show help options and exit.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-v</option></term>
|
||||
<term><option>--verbose</option></term>
|
||||
|
||||
<listitem><para>
|
||||
Print debug information during command processing.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--version</option></term>
|
||||
|
||||
<listitem><para>
|
||||
Print version information and exit.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--disable-cache</option></term>
|
||||
|
||||
<listitem><para>
|
||||
Don't look at the existing cache for a previous build, instead always rebuild modules.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--disable-download</option></term>
|
||||
|
||||
<listitem><para>
|
||||
Don't download any sources. This only works if some version of all sources are downloaded
|
||||
already. This is useful to rebuild things but without updating git or bzr repositories
|
||||
from the remote repository.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--disable-download</option></term>
|
||||
|
||||
<listitem><para>
|
||||
Exit successfully after downloading the required sources.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
|
||||
<para>
|
||||
<command>$ xdg-app-builder my-app-dir manifest.json</command>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Example manifest file:
|
||||
</para>
|
||||
<programlisting>
|
||||
{
|
||||
"app-id": "org.test.TestApp",
|
||||
"runtime": "org.freedesktop.Platform",
|
||||
"runtime-version": "1.2",
|
||||
"sdk": "org.freedesktop.Sdk",
|
||||
"command": "test",
|
||||
"clean": [ "/include", "*.la" ],
|
||||
"build-options" : {
|
||||
"cflags": "-O2 -g",
|
||||
"cxxflags": "-O2 -g",
|
||||
"env": {
|
||||
"V": "1"
|
||||
},
|
||||
"arch": {
|
||||
"x86_64": {
|
||||
"cflags": "-O3 -g",
|
||||
}
|
||||
}
|
||||
},
|
||||
"modules": [
|
||||
{
|
||||
{
|
||||
"name": "pygobject",
|
||||
"config-opts": [ "--disable-introspection" ],
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "http://ftp.gnome.org/pub/GNOME/sources/pygobject/2.28/pygobject-2.28.6.tar.xz",
|
||||
"sha256": "fb8a1d4f665130a125011659bd347c7339c944232163dbb9a34fd0686577adb8"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "required-pygobject-fix.patch"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"path": "pygobject-extra-file",
|
||||
"dest-filename": "extra-file"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "babl",
|
||||
"build-options" : { "cxxflags": "-O2 -g -std=c++11" },
|
||||
"cleanup": [ "/bin" ],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "git://git.gnome.org/babl"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "testapp",
|
||||
"sources": [
|
||||
{
|
||||
"type": "bzr",
|
||||
"url": "lp:testapp"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
</programlisting>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
|
||||
<para>
|
||||
<citerefentry><refentrytitle>xdg-app</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>xdg-app-build-init</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>xdg-app-build-build</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>xdg-app-build-finish</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>xdg-app-build-export</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
Loading…
Reference in New Issue