Remove flatpak-builder from flatpak repo

This is now in a separate flatpak-builder repo
This commit is contained in:
Alexander Larsson
2017-08-25 11:02:11 +02:00
parent bbfb53abd6
commit 52bd146561
57 changed files with 0 additions and 18418 deletions

View File

@@ -89,7 +89,6 @@ include common/Makefile.am.inc
include data/Makefile.am.inc
include app/Makefile.am.inc
include lib/Makefile.am.inc
include builder/Makefile.am.inc
include session-helper/Makefile.am.inc
include system-helper/Makefile.am.inc
include dbus-proxy/Makefile.am.inc

View File

@@ -1,45 +0,0 @@
bin_PROGRAMS += \
flatpak-builder \
$(NULL)
flatpak_builder_SOURCES = \
builder/builder-main.c \
builder/builder-manifest.c \
builder/builder-manifest.h \
builder/builder-options.c \
builder/builder-options.h \
builder/builder-extension.c \
builder/builder-extension.h \
builder/builder-module.c \
builder/builder-module.h \
builder/builder-post-process.c \
builder/builder-post-process.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-script.c \
builder/builder-source-script.h \
builder/builder-source-shell.c \
builder/builder-source-shell.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 \
builder/builder-git.c \
builder/builder-git.h \
$(NULL)
flatpak_builder_LDADD = $(AM_LDADD) $(BASE_LIBS) $(OSTREE_LIBS) $(JSON_LIBS) $(SOUP_LIBS) $(LIBELF_LIBS) \
libglnx.la libflatpak-common.la
flatpak_builder_CFLAGS = $(AM_CFLAGS) $(BASE_CFLAGS) $(OSTREE_CFLAGS) $(JSON_CFLAGS) $(SOUP_CFLAGS)

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,86 +0,0 @@
/*
* 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.1 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>
#include <libglnx/libglnx.h>
G_BEGIN_DECLS
typedef struct BuilderCache BuilderCache;
typedef struct BuilderContext BuilderContext;
#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 (BuilderContext *context,
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,
const char *stage);
void builder_cache_ensure_checkout (BuilderCache *self);
gboolean builder_cache_has_checkout (BuilderCache *self);
gboolean builder_cache_commit (BuilderCache *self,
const char *body,
GError **error);
gboolean builder_cache_get_outstanding_changes (BuilderCache *self,
GPtrArray **changed_out,
GError **error);
GPtrArray *builder_cache_get_files (BuilderCache *self,
GError **error);
GPtrArray *builder_cache_get_changes (BuilderCache *self,
GError **error);
GPtrArray *builder_cache_get_all_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_compat_str (BuilderCache *self,
const char *str);
void builder_cache_checksum_strv (BuilderCache *self,
char **strv);
void builder_cache_checksum_compat_strv (BuilderCache *self,
char **strv);
void builder_cache_checksum_boolean (BuilderCache *self,
gboolean val);
void builder_cache_checksum_compat_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__ */

View File

@@ -1,904 +0,0 @@
/* 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 2 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 Lesser 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 <sys/prctl.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <glib/gi18n.h>
#include "flatpak-utils.h"
#include "builder-context.h"
#include "builder-cache.h"
#include "builder-utils.h"
struct BuilderContext
{
GObject parent;
GFile *app_dir;
GFile *run_dir; /* directory flatpak-builder was started from */
GFile *base_dir; /* directory with json manifest, origin for source files */
SoupSession *soup_session;
char *arch;
char *stop_at;
GFile *download_dir;
GPtrArray *sources_dirs;
GPtrArray *sources_urls;
GFile *state_dir;
GFile *build_dir;
GFile *cache_dir;
GFile *checksums_dir;
GFile *ccache_dir;
GFile *rofiles_dir;
GFile *rofiles_allocated_dir;
GLnxLockFile rofiles_file_lock;
BuilderOptions *options;
gboolean keep_build_dirs;
gboolean delete_build_dirs;
int jobs;
char **cleanup;
char **cleanup_platform;
gboolean use_ccache;
gboolean build_runtime;
gboolean build_extension;
gboolean separate_locales;
gboolean bundle_sources;
gboolean sandboxed;
gboolean rebuild_on_sdk_change;
gboolean use_rofiles;
gboolean have_rofiles;
};
typedef struct
{
GObjectClass parent_class;
} BuilderContextClass;
G_DEFINE_TYPE (BuilderContext, builder_context, G_TYPE_OBJECT);
enum {
PROP_0,
PROP_APP_DIR,
PROP_RUN_DIR,
LAST_PROP
};
static void
builder_context_finalize (GObject *object)
{
BuilderContext *self = (BuilderContext *) object;
g_clear_object (&self->state_dir);
g_clear_object (&self->download_dir);
g_clear_object (&self->build_dir);
g_clear_object (&self->cache_dir);
g_clear_object (&self->checksums_dir);
g_clear_object (&self->rofiles_dir);
g_clear_object (&self->ccache_dir);
g_clear_object (&self->app_dir);
g_clear_object (&self->run_dir);
g_clear_object (&self->base_dir);
g_clear_object (&self->soup_session);
g_clear_object (&self->options);
g_free (self->arch);
g_free (self->stop_at);
g_strfreev (self->cleanup);
g_strfreev (self->cleanup_platform);
glnx_release_lock_file(&self->rofiles_file_lock);
g_clear_pointer (&self->sources_dirs, g_ptr_array_unref);
g_clear_pointer (&self->sources_urls, g_ptr_array_unref);
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_RUN_DIR:
g_value_set_object (value, self->run_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_RUN_DIR:
g_set_object (&self->run_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->run_dir, ".flatpak-builder");
self->download_dir = g_file_get_child (self->state_dir, "downloads");
self->build_dir = g_file_get_child (self->state_dir, "build");
self->cache_dir = g_file_get_child (self->state_dir, "cache");
self->checksums_dir = g_file_get_child (self->state_dir, "checksums");
self->ccache_dir = g_file_get_child (self->state_dir, "ccache");
}
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_RUN_DIR,
g_param_spec_object ("run-dir",
"",
"",
G_TYPE_FILE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
}
static void
builder_context_init (BuilderContext *self)
{
GLnxLockFile init = GLNX_LOCK_FILE_INIT;
g_autofree char *path = NULL;
self->rofiles_file_lock = init;
path = g_find_program_in_path ("rofiles-fuse");
self->have_rofiles = path != NULL;
}
GFile *
builder_context_get_run_dir (BuilderContext *self)
{
return self->run_dir;
}
GFile *
builder_context_get_base_dir (BuilderContext *self)
{
return self->base_dir;
}
void
builder_context_set_base_dir (BuilderContext *self,
GFile *base_dir)
{
g_set_object (&self->base_dir, base_dir);
}
GFile *
builder_context_get_state_dir (BuilderContext *self)
{
return self->state_dir;
}
GFile *
builder_context_get_app_dir_raw (BuilderContext *self)
{
return self->app_dir;
}
GFile *
builder_context_get_app_dir (BuilderContext *self)
{
if (self->rofiles_dir)
return self->rofiles_dir;
return self->app_dir;
}
GFile *
builder_context_get_download_dir (BuilderContext *self)
{
return self->download_dir;
}
GPtrArray *
builder_context_get_sources_dirs (BuilderContext *self)
{
return self->sources_dirs;
}
void
builder_context_set_sources_dirs (BuilderContext *self,
GPtrArray *sources_dirs)
{
g_clear_pointer (&self->sources_dirs, g_ptr_array_unref);
self->sources_dirs = g_ptr_array_ref (sources_dirs);
}
GFile *
builder_context_find_in_sources_dirs_va (BuilderContext *self,
va_list args)
{
int i;
if (self->sources_dirs == NULL)
return NULL;
for (i = 0; i < self->sources_dirs->len; i++)
{
GFile *dir = g_ptr_array_index (self->sources_dirs, i);
g_autoptr(GFile) local_file = NULL;
va_list args2;
va_copy (args2, args);
local_file = flatpak_build_file_va (dir, args2);
va_end (args2);
if (g_file_query_exists (local_file, NULL))
return g_steal_pointer (&local_file);
}
return NULL;
}
GFile *
builder_context_find_in_sources_dirs (BuilderContext *self,
...)
{
GFile *res;
va_list args;
va_start (args, self);
res = builder_context_find_in_sources_dirs_va (self, args);
va_end (args);
return res;
}
GPtrArray *
builder_context_get_sources_urls (BuilderContext *self)
{
return self->sources_urls;
}
void
builder_context_set_sources_urls (BuilderContext *self,
GPtrArray *sources_urls)
{
g_clear_pointer (&self->sources_urls, g_ptr_array_unref);
self->sources_urls = g_ptr_array_ref (sources_urls);
}
gboolean
builder_context_download_uri (BuilderContext *self,
const char *url,
GFile *dest,
char *sha256,
GError **error)
{
int i;
g_autoptr(SoupURI) original_uri = soup_uri_new (url);
if (original_uri == NULL)
return flatpak_fail (error, _("Could not parse URI “%s”"), url);
g_print ("Downloading %s\n", url);
if (self->sources_urls != NULL)
{
g_autofree char *base_name = g_path_get_basename (soup_uri_get_path (original_uri));
g_autofree char *rel = g_build_filename ("downloads", sha256, base_name, NULL);
for (i = 0; i < self->sources_urls->len; i++)
{
SoupURI *base_uri = g_ptr_array_index (self->sources_urls, i);
g_autoptr(SoupURI) mirror_uri = soup_uri_new_with_base (base_uri, rel);
g_autofree char *mirror_uri_str = soup_uri_to_string (mirror_uri, FALSE);
g_print ("Trying mirror %s\n", mirror_uri_str);
g_autoptr(GError) my_error = NULL;
if (builder_download_uri (mirror_uri,
dest,
sha256,
builder_context_get_soup_session (self),
&my_error))
return TRUE;
if (!g_error_matches (my_error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND))
g_warning ("Error downloading from mirror: %s\n", my_error->message);
}
}
if (!builder_download_uri (original_uri,
dest,
sha256,
builder_context_get_soup_session (self),
error))
return FALSE;
return TRUE;
}
GFile *
builder_context_get_cache_dir (BuilderContext *self)
{
return self->cache_dir;
}
GFile *
builder_context_get_build_dir (BuilderContext *self)
{
return self->build_dir;
}
char *
builder_context_get_checksum_for (BuilderContext *self,
const char *name)
{
g_autoptr(GFile) checksum_file = g_file_get_child (self->checksums_dir, name);
g_autofree gchar *checksum = NULL;
if (!g_file_get_contents (flatpak_file_get_path_cached (checksum_file), &checksum, NULL, NULL))
return NULL;
return g_steal_pointer (&checksum);
}
void
builder_context_set_checksum_for (BuilderContext *self,
const char *name,
const char *checksum)
{
g_autoptr(GFile) checksum_file = g_file_get_child (self->checksums_dir, name);
if (!flatpak_mkdir_p (self->checksums_dir,
NULL, NULL))
return;
g_file_set_contents (flatpak_file_get_path_cached (checksum_file), checksum, -1, NULL);
}
GFile *
builder_context_allocate_build_subdir (BuilderContext *self,
const char *name,
GError **error)
{
g_autoptr(GError) my_error = NULL;
int count;
if (!flatpak_mkdir_p (self->build_dir,
NULL, error))
return NULL;
for (count = 1; count < 1000; count++)
{
g_autofree char *buildname = NULL;
g_autoptr(GFile) subdir = NULL;
buildname = g_strdup_printf ("%s-%d", name, count);
subdir = g_file_get_child (self->build_dir, buildname);
if (g_file_make_directory (subdir, NULL, &my_error))
return g_steal_pointer (&subdir);
else
{
if (!g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_EXISTS))
{
g_propagate_error (error, g_steal_pointer (&my_error));
return NULL;
}
g_clear_error (&my_error);
/* Already exists, try again */
}
}
flatpak_fail (error, "Unable to allocate build dir for %s\n", name);
return NULL;
}
GFile *
builder_context_get_ccache_dir (BuilderContext *self)
{
return self->ccache_dir;
}
SoupSession *
builder_context_get_soup_session (BuilderContext *self)
{
if (self->soup_session == NULL)
self->soup_session = flatpak_create_soup_session ("flatpak-builder " PACKAGE_VERSION);
return self->soup_session;
}
const char *
builder_context_get_arch (BuilderContext *self)
{
if (self->arch == NULL)
self->arch = g_strdup (flatpak_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);
}
const char *
builder_context_get_stop_at (BuilderContext *self)
{
return self->stop_at;
}
void
builder_context_set_stop_at (BuilderContext *self,
const char *module)
{
g_free (self->stop_at);
self->stop_at = g_strdup (module);
}
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_jobs (BuilderContext *self)
{
if (self->jobs == 0)
return (int) sysconf (_SC_NPROCESSORS_ONLN);
return self->jobs;
}
void
builder_context_set_jobs (BuilderContext *self,
int jobs)
{
self->jobs = jobs;
}
void
builder_context_set_keep_build_dirs (BuilderContext *self,
gboolean keep_build_dirs)
{
self->keep_build_dirs = keep_build_dirs;
}
void
builder_context_set_delete_build_dirs (BuilderContext *self,
gboolean delete_build_dirs)
{
self->delete_build_dirs = delete_build_dirs;
}
void
builder_context_set_global_cleanup (BuilderContext *self,
const char **cleanup)
{
g_strfreev (self->cleanup);
self->cleanup = g_strdupv ((char **) cleanup);
}
const char **
builder_context_get_global_cleanup (BuilderContext *self)
{
return (const char **) self->cleanup;
}
void
builder_context_set_global_cleanup_platform (BuilderContext *self,
const char **cleanup)
{
g_strfreev (self->cleanup_platform);
self->cleanup_platform = g_strdupv ((char **) cleanup);
}
const char **
builder_context_get_global_cleanup_platform (BuilderContext *self)
{
return (const char **) self->cleanup_platform;
}
gboolean
builder_context_get_keep_build_dirs (BuilderContext *self)
{
return self->keep_build_dirs;
}
gboolean
builder_context_get_delete_build_dirs (BuilderContext *self)
{
return self->delete_build_dirs;
}
void
builder_context_set_sandboxed (BuilderContext *self,
gboolean sandboxed)
{
self->sandboxed = sandboxed;
}
gboolean
builder_context_get_sandboxed (BuilderContext *self)
{
return self->sandboxed;
}
gboolean
builder_context_get_build_runtime (BuilderContext *self)
{
return self->build_runtime;
}
void
builder_context_set_build_runtime (BuilderContext *self,
gboolean build_runtime)
{
self->build_runtime = !!build_runtime;
}
gboolean
builder_context_get_build_extension (BuilderContext *self)
{
return self->build_extension;
}
void
builder_context_set_build_extension (BuilderContext *self,
gboolean build_extension)
{
self->build_extension = !!build_extension;
}
gboolean
builder_context_get_separate_locales (BuilderContext *self)
{
return self->separate_locales;
}
void
builder_context_set_separate_locales (BuilderContext *self,
gboolean separate_locales)
{
self->separate_locales = !!separate_locales;
}
gboolean
builder_context_get_bundle_sources (BuilderContext *self)
{
return self->bundle_sources;
}
void
builder_context_set_bundle_sources (BuilderContext *self,
gboolean bundle_sources)
{
self->bundle_sources = !!bundle_sources;
}
static char *rofiles_unmount_path = NULL;
static void
rofiles_umount_handler (int signum)
{
char *argv[] = { "fusermount", "-u", NULL,
NULL };
argv[2] = rofiles_unmount_path;
g_debug ("unmounting rofiles-fuse %s", rofiles_unmount_path);
g_spawn_sync (NULL, (char **)argv, NULL,
G_SPAWN_SEARCH_PATH | G_SPAWN_CLOEXEC_PIPES | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
NULL, NULL, NULL, NULL, NULL, NULL);
exit (0);
}
static void
rofiles_child_setup (gpointer user_data)
{
struct rlimit limit;
/* I had issues with rofiles-fuse running into EMFILE, so
lets push it as far up as we can */
if (getrlimit (RLIMIT_NOFILE, &limit) == 0 &&
limit.rlim_max != limit.rlim_cur)
{
limit.rlim_cur = limit.rlim_max;
setrlimit (RLIMIT_NOFILE, &limit);
}
}
gboolean
builder_context_enable_rofiles (BuilderContext *self,
GError **error)
{
g_autoptr(GFile) rofiles_base = NULL;
g_autoptr(GFile) rofiles_dir = NULL;
g_autofree char *tmpdir_name = NULL;
char *argv[] = { "rofiles-fuse",
"-o",
"kernel_cache,entry_timeout=60,attr_timeout=60,splice_write,splice_move",
(char *)flatpak_file_get_path_cached (self->app_dir),
NULL,
NULL };
gint exit_status;
pid_t child;
if (!self->use_rofiles)
return TRUE;
if (!self->have_rofiles)
{
g_warning ("rofiles-fuse not available, doing without");
return TRUE;
}
g_assert (self->rofiles_dir == NULL);
if (self->rofiles_allocated_dir == NULL)
{
rofiles_base = g_file_get_child (self->state_dir, "rofiles");
if (g_mkdir_with_parents (flatpak_file_get_path_cached (rofiles_base), 0755) != 0)
{
glnx_set_error_from_errno (error);
return FALSE;
}
if (!flatpak_allocate_tmpdir (AT_FDCWD,
flatpak_file_get_path_cached (rofiles_base),
"rofiles-",
&tmpdir_name, NULL,
&self->rofiles_file_lock,
NULL, NULL, error))
return FALSE;
self->rofiles_allocated_dir = g_file_get_child (rofiles_base, tmpdir_name);
/* Make sure we unmount the fuse fs if flatpak-builder dies unexpectedly */
rofiles_unmount_path = (char *)flatpak_file_get_path_cached (self->rofiles_allocated_dir);
child = fork ();
if (child == -1)
{
glnx_set_error_from_errno (error);
return FALSE;
}
if (child == 0)
{
/* In child */
struct sigaction new_action;
prctl (PR_SET_PDEATHSIG, SIGHUP);
new_action.sa_handler = rofiles_umount_handler;
sigemptyset (&new_action.sa_mask);
new_action.sa_flags = 0;
sigaction (SIGHUP, &new_action, NULL);
sigset (SIGINT, SIG_IGN);
sigset (SIGPIPE, SIG_IGN);
sigset (SIGSTOP, SIG_IGN);
while (TRUE)
pause ();
exit (0);
}
}
rofiles_dir = g_object_ref (self->rofiles_allocated_dir);
argv[4] = (char *)flatpak_file_get_path_cached (rofiles_dir);
g_debug ("starting: rofiles-fuse %s %s", argv[3], argv[4]);
if (!g_spawn_sync (NULL, (char **)argv, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_CLOEXEC_PIPES, rofiles_child_setup, NULL, NULL, NULL, &exit_status, error))
{
g_prefix_error (error, "Can't spawn rofiles-fuse");
return FALSE;
}
else if (exit_status != 0)
{
return flatpak_fail (error, "Failure spawning rofiles-fuse, exit_status: %d", exit_status);
}
self->rofiles_dir = g_steal_pointer (&rofiles_dir);
return TRUE;
}
gboolean
builder_context_disable_rofiles (BuilderContext *self,
GError **error)
{
char *argv[] = { "fusermount", "-u", NULL,
NULL };
if (!self->use_rofiles)
return TRUE;
if (!self->have_rofiles)
return TRUE;
g_assert (self->rofiles_dir != NULL);
argv[2] = (char *)flatpak_file_get_path_cached (self->rofiles_dir);
g_debug ("unmounting rofiles-fuse %s", rofiles_unmount_path);
g_spawn_sync (NULL, (char **)argv, NULL,
G_SPAWN_SEARCH_PATH | G_SPAWN_CLOEXEC_PIPES,
NULL, NULL, NULL, NULL, NULL, NULL);
g_clear_object (&self->rofiles_dir);
return TRUE;
}
gboolean
builder_context_get_rofiles_active (BuilderContext *self)
{
return self->rofiles_dir != NULL;
}
gboolean
builder_context_get_use_rofiles (BuilderContext *self)
{
return self->use_rofiles;
}
void
builder_context_set_use_rofiles (BuilderContext *self,
gboolean use_rofiles)
{
self->use_rofiles = use_rofiles;
}
gboolean
builder_context_get_rebuild_on_sdk_change (BuilderContext *self)
{
return self->rebuild_on_sdk_change;
}
void
builder_context_set_rebuild_on_sdk_change (BuilderContext *self,
gboolean rebuild_on_sdk_change)
{
self->rebuild_on_sdk_change = !!rebuild_on_sdk_change;
}
gboolean
builder_context_enable_ccache (BuilderContext *self,
GError **error)
{
g_autofree char *ccache_path = g_file_get_path (self->ccache_dir);
g_autofree char *ccache_bin_path = g_build_filename (ccache_path, "bin", NULL);
int i;
static const char *compilers[] = {
"cc",
"c++",
"gcc",
"g++"
};
if (g_mkdir_with_parents (ccache_bin_path, 0755) != 0)
{
glnx_set_error_from_errno (error);
return FALSE;
}
for (i = 0; i < G_N_ELEMENTS (compilers); i++)
{
const char *symlink_path = g_build_filename (ccache_bin_path, compilers[i], NULL);
if (symlink ("/usr/bin/ccache", symlink_path) && errno != EEXIST)
{
glnx_set_error_from_errno (error);
return FALSE;
}
}
self->use_ccache = TRUE;
return TRUE;
}
char **
builder_context_extend_env (BuilderContext *self,
char **envp)
{
if (self->use_ccache)
{
const char *old_path = g_environ_getenv (envp, "PATH");
g_autofree char *new_path = NULL;
if (old_path == NULL)
old_path = "/app/bin:/usr/bin"; /* This is the flatpak default PATH */
new_path = g_strdup_printf ("/run/ccache/bin:%s", old_path);
envp = g_environ_setenv (envp, "PATH", new_path, TRUE);
envp = g_environ_setenv (envp, "CCACHE_DIR", "/run/ccache", TRUE);
}
return envp;
}
BuilderContext *
builder_context_new (GFile *run_dir,
GFile *app_dir)
{
return g_object_new (BUILDER_TYPE_CONTEXT,
"run-dir", run_dir,
"app-dir", app_dir,
NULL);
}

View File

@@ -1,135 +0,0 @@
/*
* 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.1 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-cache.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_app_dir_raw (BuilderContext *self);
GFile * builder_context_get_run_dir (BuilderContext *self);
GFile * builder_context_get_base_dir (BuilderContext *self);
void builder_context_set_base_dir (BuilderContext *self,
GFile *base_dir);
GFile * builder_context_get_state_dir (BuilderContext *self);
GFile * builder_context_get_cache_dir (BuilderContext *self);
GFile * builder_context_get_build_dir (BuilderContext *self);
GFile * builder_context_allocate_build_subdir (BuilderContext *self,
const char *name,
GError **error);
GFile * builder_context_get_ccache_dir (BuilderContext *self);
GFile * builder_context_get_download_dir (BuilderContext *self);
GPtrArray * builder_context_get_sources_dirs (BuilderContext *self);
void builder_context_set_sources_dirs (BuilderContext *self,
GPtrArray *sources_dirs);
GFile * builder_context_find_in_sources_dirs (BuilderContext *self,
...) G_GNUC_NULL_TERMINATED;
GFile * builder_context_find_in_sources_dirs_va (BuilderContext *self,
va_list args);
GPtrArray * builder_context_get_sources_urls (BuilderContext *self);
void builder_context_set_sources_urls (BuilderContext *self,
GPtrArray *sources_urls);
gboolean builder_context_download_uri (BuilderContext *self,
const char *url,
GFile *dest,
char *sha256,
GError **error);
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);
const char * builder_context_get_stop_at (BuilderContext *self);
void builder_context_set_stop_at (BuilderContext *self,
const char *module);
int builder_context_get_jobs (BuilderContext *self);
void builder_context_set_jobs (BuilderContext *self,
int n_jobs);
void builder_context_set_keep_build_dirs (BuilderContext *self,
gboolean keep_build_dirs);
gboolean builder_context_get_delete_build_dirs (BuilderContext *self);
void builder_context_set_delete_build_dirs (BuilderContext *self,
gboolean delete_build_dirs);
gboolean builder_context_get_keep_build_dirs (BuilderContext *self);
void builder_context_set_sandboxed (BuilderContext *self,
gboolean sandboxed);
gboolean builder_context_get_sandboxed (BuilderContext *self);
void builder_context_set_global_cleanup (BuilderContext *self,
const char **cleanup);
const char ** builder_context_get_global_cleanup (BuilderContext *self);
void builder_context_set_global_cleanup_platform (BuilderContext *self,
const char **cleanup);
const char ** builder_context_get_global_cleanup_platform (BuilderContext *self);
BuilderOptions *builder_context_get_options (BuilderContext *self);
void builder_context_set_options (BuilderContext *self,
BuilderOptions *option);
gboolean builder_context_get_build_runtime (BuilderContext *self);
void builder_context_set_build_runtime (BuilderContext *self,
gboolean build_runtime);
gboolean builder_context_get_build_extension (BuilderContext *self);
void builder_context_set_build_extension (BuilderContext *self,
gboolean build_extension);
gboolean builder_context_get_separate_locales (BuilderContext *self);
void builder_context_set_separate_locales (BuilderContext *self,
gboolean separate_locales);
void builder_context_set_bundle_sources (BuilderContext *self,
gboolean bundle_sources);
gboolean builder_context_get_bundle_sources (BuilderContext *self);
gboolean builder_context_get_rebuild_on_sdk_change (BuilderContext *self);
void builder_context_set_rebuild_on_sdk_change (BuilderContext *self,
gboolean rebuild_on_sdk_change);
char * builder_context_get_checksum_for (BuilderContext *self,
const char *name);
void builder_context_set_checksum_for (BuilderContext *self,
const char *name,
const char *checksum);
BuilderContext *builder_context_new (GFile *run_dir,
GFile *app_dir);
gboolean builder_context_enable_ccache (BuilderContext *self,
GError **error);
gboolean builder_context_enable_rofiles (BuilderContext *self,
GError **error);
gboolean builder_context_disable_rofiles (BuilderContext *self,
GError **error);
gboolean builder_context_get_rofiles_active (BuilderContext *self);
gboolean builder_context_get_use_rofiles (BuilderContext *self);
void builder_context_set_use_rofiles (BuilderContext *self,
gboolean use_rofiles);
char ** builder_context_extend_env (BuilderContext *self,
char **envp);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (BuilderContext, g_object_unref)
G_END_DECLS
#endif /* __BUILDER_CONTEXT_H__ */

View File

@@ -1,425 +0,0 @@
/* builder-extension.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 2 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 Lesser 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 <glib/gi18n.h>
#include <gio/gio.h>
#include "libglnx/libglnx.h"
#include "flatpak-utils.h"
#include "flatpak-run.h"
#include "builder-utils.h"
#include "builder-extension.h"
struct BuilderExtension
{
GObject parent;
char *name;
char *directory;
gboolean bundle;
gboolean autodelete;
gboolean no_autodownload;
gboolean subdirectories;
char *add_ld_path;
char *download_if;
char *enable_if;
char *merge_dirs;
char *subdirectory_suffix;
char *version;
char *versions;
};
typedef struct
{
GObjectClass parent_class;
} BuilderExtensionClass;
G_DEFINE_TYPE (BuilderExtension, builder_extension, G_TYPE_OBJECT);
enum {
PROP_0,
PROP_DIRECTORY,
PROP_BUNDLE,
PROP_AUTODELETE,
PROP_ADD_LD_PATH,
PROP_DOWNLOAD_IF,
PROP_ENABLE_IF,
PROP_MERGE_DIRS,
PROP_NO_AUTODOWNLOAD,
PROP_SUBDIRECTORIES,
PROP_SUBDIRECTORY_SUFFIX,
PROP_VERSION,
PROP_VERSIONS,
LAST_PROP
};
static void
builder_extension_finalize (GObject *object)
{
BuilderExtension *self = (BuilderExtension *) object;
g_free (self->name);
g_free (self->directory);
g_free (self->add_ld_path);
g_free (self->download_if);
g_free (self->enable_if);
g_free (self->merge_dirs);
g_free (self->subdirectory_suffix);
g_free (self->version);
g_free (self->versions);
G_OBJECT_CLASS (builder_extension_parent_class)->finalize (object);
}
static void
builder_extension_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
BuilderExtension *self = BUILDER_EXTENSION (object);
switch (prop_id)
{
case PROP_DIRECTORY:
g_value_set_string (value, self->directory);
break;
case PROP_BUNDLE:
g_value_set_boolean (value, self->bundle);
break;
case PROP_AUTODELETE:
g_value_set_boolean (value, self->autodelete);
break;
case PROP_NO_AUTODOWNLOAD:
g_value_set_boolean (value, self->autodelete);
break;
case PROP_SUBDIRECTORIES:
g_value_set_boolean (value, self->autodelete);
break;
case PROP_ADD_LD_PATH:
g_value_set_string (value, self->add_ld_path);
break;
case PROP_DOWNLOAD_IF:
g_value_set_string (value, self->download_if);
break;
case PROP_ENABLE_IF:
g_value_set_string (value, self->enable_if);
break;
case PROP_MERGE_DIRS:
g_value_set_string (value, self->merge_dirs);
break;
case PROP_SUBDIRECTORY_SUFFIX:
g_value_set_string (value, self->subdirectory_suffix);
break;
case PROP_VERSION:
g_value_set_string (value, self->version);
break;
case PROP_VERSIONS:
g_value_set_string (value, self->versions);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
builder_extension_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
BuilderExtension *self = BUILDER_EXTENSION (object);
switch (prop_id)
{
case PROP_DIRECTORY:
g_clear_pointer (&self->directory, g_free);
self->directory = g_value_dup_string (value);
break;
case PROP_BUNDLE:
self->bundle = g_value_get_boolean (value);
break;
case PROP_AUTODELETE:
self->autodelete = g_value_get_boolean (value);
break;
case PROP_NO_AUTODOWNLOAD:
self->no_autodownload = g_value_get_boolean (value);
break;
case PROP_SUBDIRECTORIES:
self->subdirectories = g_value_get_boolean (value);
break;
case PROP_ADD_LD_PATH:
g_clear_pointer (&self->add_ld_path, g_free);
self->add_ld_path = g_value_dup_string (value);
break;
case PROP_DOWNLOAD_IF:
g_clear_pointer (&self->download_if, g_free);
self->download_if = g_value_dup_string (value);
break;
case PROP_ENABLE_IF:
g_clear_pointer (&self->enable_if, g_free);
self->enable_if = g_value_dup_string (value);
break;
case PROP_MERGE_DIRS:
g_clear_pointer (&self->merge_dirs, g_free);
self->merge_dirs = g_value_dup_string (value);
break;
case PROP_SUBDIRECTORY_SUFFIX:
g_clear_pointer (&self->subdirectory_suffix, g_free);
self->subdirectory_suffix = g_value_dup_string (value);
break;
case PROP_VERSION:
g_clear_pointer (&self->version, g_free);
self->version = g_value_dup_string (value);
break;
case PROP_VERSIONS:
g_clear_pointer (&self->versions, g_free);
self->versions = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
builder_extension_class_init (BuilderExtensionClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = builder_extension_finalize;
object_class->get_property = builder_extension_get_property;
object_class->set_property = builder_extension_set_property;
g_object_class_install_property (object_class,
PROP_DIRECTORY,
g_param_spec_string ("directory",
"",
"",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_BUNDLE,
g_param_spec_boolean ("bundle",
"",
"",
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_AUTODELETE,
g_param_spec_boolean ("autodelete",
"",
"",
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_NO_AUTODOWNLOAD,
g_param_spec_boolean ("no-autodownload",
"",
"",
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_SUBDIRECTORIES,
g_param_spec_boolean ("subdirectories",
"",
"",
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_ADD_LD_PATH,
g_param_spec_string ("add-ld-path",
"",
"",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_DOWNLOAD_IF,
g_param_spec_string ("download-if",
"",
"",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_ENABLE_IF,
g_param_spec_string ("enable-if",
"",
"",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_MERGE_DIRS,
g_param_spec_string ("merge-dirs",
"",
"",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_SUBDIRECTORY_SUFFIX,
g_param_spec_string ("subdirectory-suffix",
"",
"",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_VERSION,
g_param_spec_string ("version",
"",
"",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_VERSIONS,
g_param_spec_string ("versions",
"",
"",
NULL,
G_PARAM_READWRITE));
}
static void
builder_extension_init (BuilderExtension *self)
{
}
void
builder_extension_set_name (BuilderExtension *self,
const char *name)
{
g_free (self->name);
self->name = g_strdup (name);
}
const char *
builder_extension_get_name (BuilderExtension *self)
{
return self->name;
}
gboolean
builder_extension_is_bundled (BuilderExtension *self)
{
return self->bundle;
}
const char *
builder_extension_get_directory (BuilderExtension *self)
{
return self->directory;
}
static void
add_arg (BuilderExtension *self,
GPtrArray *args,
const char *key,
const char *value)
{
if (value == NULL)
return;
g_ptr_array_add (args,
g_strdup_printf ("--extension=%s=%s=%s", self->name, key, value));
}
static void
add_argb (BuilderExtension *self,
GPtrArray *args,
const char *key,
gboolean val)
{
if (val)
add_arg (self, args, key, "true");
}
void
builder_extension_add_finish_args (BuilderExtension *self,
GPtrArray *args)
{
if (self->directory == NULL)
{
g_warning ("No directory specified for extension '%s'", self->name);
return;
}
add_arg (self, args, FLATPAK_METADATA_KEY_DIRECTORY, self->directory);
add_argb (self, args, FLATPAK_METADATA_KEY_AUTODELETE, self->autodelete);
add_argb (self, args, FLATPAK_METADATA_KEY_NO_AUTODOWNLOAD, self->no_autodownload);
add_argb (self, args, FLATPAK_METADATA_KEY_SUBDIRECTORIES, self->subdirectories);
add_arg (self, args, FLATPAK_METADATA_KEY_ADD_LD_PATH, self->add_ld_path);
add_arg (self, args, FLATPAK_METADATA_KEY_DOWNLOAD_IF, self->download_if);
add_arg (self, args, FLATPAK_METADATA_KEY_ENABLE_IF, self->enable_if);
add_arg (self, args, FLATPAK_METADATA_KEY_MERGE_DIRS, self->merge_dirs);
add_arg (self, args, FLATPAK_METADATA_KEY_SUBDIRECTORY_SUFFIX, self->subdirectory_suffix);
add_arg (self, args, FLATPAK_METADATA_KEY_VERSION, self->version);
add_arg (self, args, FLATPAK_METADATA_KEY_VERSIONS, self->versions);
}
void
builder_extension_checksum (BuilderExtension *self,
BuilderCache *cache,
BuilderContext *context)
{
builder_cache_checksum_str (cache, BUILDER_EXTENSION_CHECKSUM_VERSION);
builder_cache_checksum_str (cache, self->name);
builder_cache_checksum_str (cache, self->directory);
builder_cache_checksum_boolean (cache, self->bundle);
builder_cache_checksum_boolean (cache, self->autodelete);
builder_cache_checksum_boolean (cache, self->no_autodownload);
builder_cache_checksum_boolean (cache, self->subdirectories);
builder_cache_checksum_str (cache, self->add_ld_path);
builder_cache_checksum_str (cache, self->download_if);
builder_cache_checksum_str (cache, self->enable_if);
builder_cache_checksum_str (cache, self->merge_dirs);
builder_cache_checksum_str (cache, self->subdirectory_suffix);
builder_cache_checksum_str (cache, self->version);
builder_cache_checksum_str (cache, self->versions);
}

View File

@@ -1,59 +0,0 @@
/*
* Copyright © 2017 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.1 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_EXTENSION_H__
#define __BUILDER_EXTENSION_H__
#include <json-glib/json-glib.h>
#include "builder-context.h"
#include "builder-cache.h"
G_BEGIN_DECLS
typedef struct BuilderExtension BuilderExtension;
#define BUILDER_TYPE_EXTENSION (builder_extension_get_type ())
#define BUILDER_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BUILDER_TYPE_EXTENSION, BuilderExtension))
#define BUILDER_IS_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BUILDER_TYPE_EXTENSION))
/* Bump this if format changes in incompatible ways to force rebuild */
#define BUILDER_EXTENSION_CHECKSUM_VERSION "1"
GType builder_extension_get_type (void);
void builder_extension_set_name (BuilderExtension *self,
const char *name);
const char * builder_extension_get_name (BuilderExtension *self);
gboolean builder_extension_is_bundled (BuilderExtension *self);
const char * builder_extension_get_directory (BuilderExtension *self);
void builder_extension_add_finish_args (BuilderExtension *self,
GPtrArray *args);
void builder_extension_checksum (BuilderExtension *self,
BuilderCache *cache,
BuilderContext *context);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (BuilderExtension, g_object_unref)
G_END_DECLS
#endif /* __BUILDER_EXTENSION_H__ */

View File

@@ -1,517 +0,0 @@
/* builder-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 2 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 Lesser 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-git.h"
#include "builder-utils.h"
#include "flatpak-utils.h"
static gboolean
git (GFile *dir,
char **output,
GError **error,
...)
{
gboolean res;
va_list ap;
va_start (ap, error);
res = flatpak_spawn (dir, output, error, "git", ap);
va_end (ap);
return res;
}
static GFile *
git_get_mirror_dir (const char *url_or_path,
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);
/* Technically a path isn't a uri but if it's absolute it should still be unique. */
filename = builder_uri_to_filename (url_or_path);
return g_file_get_child (git_dir, filename);
}
static char *
git_get_current_commit (GFile *repo_dir,
const char *branch,
gboolean ensure_commit,
BuilderContext *context,
GError **error)
{
char *output = NULL;
g_autofree char *arg = NULL;
if (ensure_commit)
arg = g_strconcat (branch, "^{commit}", NULL);
else
arg = g_strdup (branch);
if (!git (repo_dir, &output, error,
"rev-parse", arg, NULL))
return NULL;
/* Trim trailing whitespace */
g_strchomp (output);
return output;
}
char *
builder_git_get_current_commit (const char *repo_location,
const char *branch,
gboolean ensure_commit,
BuilderContext *context,
GError **error)
{
g_autoptr(GFile) mirror_dir = NULL;
mirror_dir = git_get_mirror_dir (repo_location, context);
return git_get_current_commit (mirror_dir, branch, ensure_commit, context, error);
}
static char *
make_absolute (const char *orig_parent, const char *orig_relpath, GError **error)
{
g_autofree char *parent = g_strdup (orig_parent);
const char *relpath = orig_relpath;
char *start;
char *parent_path;
if (!g_str_has_prefix (relpath, "../"))
return g_strdup (orig_relpath);
if (parent[strlen (parent) - 1] == '/')
parent[strlen (parent) - 1] = 0;
if ((start = strstr (parent, "://")))
start = start + 3;
else
start = parent;
parent_path = strchr (start, '/');
if (parent_path == NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Invalid uri or path %s", orig_parent);
return NULL;
}
while (g_str_has_prefix (relpath, "../"))
{
char *last_slash = strrchr (parent_path, '/');
if (last_slash == NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Invalid relative path %s for uri or path %s", orig_relpath, orig_parent);
return NULL;
}
relpath += 3;
*last_slash = 0;
}
return g_strconcat (parent, "/", relpath, NULL);
}
static gboolean
git_mirror_submodules (const char *repo_location,
const char *destination_path,
gboolean update,
GFile *mirror_dir,
gboolean disable_fsck,
const char *revision,
BuilderContext *context,
GError **error)
{
g_autoptr(GKeyFile) key_file = g_key_file_new ();
g_autofree gchar *rev_parse_output = NULL;
g_autofree gchar *submodule_data = NULL;
g_autofree gchar **submodules = NULL;
g_autofree gchar *gitmodules = g_strconcat (revision, ":.gitmodules", NULL);
gsize num_submodules;
if (!git (mirror_dir, &rev_parse_output, NULL, "rev-parse", "--verify", "--quiet", gitmodules, NULL))
return TRUE;
if (git (mirror_dir, &submodule_data, NULL, "show", gitmodules, NULL))
{
if (!g_key_file_load_from_data (key_file, submodule_data, -1,
G_KEY_FILE_NONE, error))
return FALSE;
submodules = g_key_file_get_groups (key_file, &num_submodules);
int i;
for (i = 0; i < num_submodules; i++)
{
g_autofree gchar *submodule = NULL;
g_autofree gchar *path = NULL;
g_autofree gchar *relative_url = NULL;
g_autofree gchar *absolute_url = NULL;
g_autofree gchar *ls_tree = NULL;
g_auto(GStrv) lines = NULL;
g_auto(GStrv) words = NULL;
submodule = submodules[i];
if (!g_str_has_prefix (submodule, "submodule \""))
continue;
path = g_key_file_get_string (key_file, submodule, "path", error);
if (path == NULL)
return FALSE;
relative_url = g_key_file_get_string (key_file, submodule, "url", error);
/* Remove any trailing whitespace */
g_strchomp (relative_url);
absolute_url = make_absolute (repo_location, relative_url, error);
if (absolute_url == NULL)
return FALSE;
if (!git (mirror_dir, &ls_tree, error, "ls-tree", revision, path, NULL))
return FALSE;
lines = g_strsplit (g_strstrip (ls_tree), "\n", 0);
if (g_strv_length (lines) != 1)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Not a gitlink tree: %s", path);
return FALSE;
}
words = g_strsplit_set (lines[0], " \t", 4);
if (g_strcmp0 (words[0], "160000") != 0)
continue;
if (!builder_git_mirror_repo (absolute_url, destination_path, update, TRUE, disable_fsck, words[2], context, error))
return FALSE;
}
}
return TRUE;
}
gboolean
builder_git_mirror_repo (const char *repo_location,
const char *destination_path,
gboolean update,
gboolean mirror_submodules,
gboolean disable_fsck,
const char *ref,
BuilderContext *context,
GError **error)
{
g_autoptr(GFile) cache_mirror_dir = NULL;
g_autoptr(GFile) mirror_dir = NULL;
g_autofree char *current_commit = NULL;
cache_mirror_dir = git_get_mirror_dir (repo_location, context);
if (destination_path != NULL)
{
g_autofree char *file_name = g_file_get_basename (cache_mirror_dir);
g_autofree char *destination_file_path = g_build_filename (destination_path,
file_name,
NULL);
mirror_dir = g_file_new_for_path (destination_file_path);
}
else
mirror_dir = g_object_ref (cache_mirror_dir);
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 *mirror_path = g_file_get_path (mirror_dir);
g_autofree char *path_tmp = g_strconcat (mirror_path, ".clone_XXXXXX", NULL);
g_autofree char *filename_tmp = NULL;
g_autoptr(GFile) mirror_dir_tmp = NULL;
g_autoptr(GFile) cached_git_dir = NULL;
gboolean res;
g_autoptr(GPtrArray) args = g_ptr_array_new ();
if (g_mkdtemp_full (path_tmp, 0755) == NULL)
return flatpak_fail (error, "Can't create temporary directory");
mirror_dir_tmp = g_file_new_for_path (path_tmp);
filename_tmp = g_file_get_basename (mirror_dir_tmp);
g_ptr_array_add (args, "git");
g_ptr_array_add (args, "clone");
if (!disable_fsck)
{
g_ptr_array_add (args, "-c");
g_ptr_array_add (args, "transfer.fsckObjects=1");
}
g_ptr_array_add (args, "--mirror");
/* If we're doing a regular download, look for cache sources */
if (destination_path == NULL)
cached_git_dir = builder_context_find_in_sources_dirs (context, "git", filename, NULL);
else
cached_git_dir = g_object_ref (cache_mirror_dir);
g_print ("Cloning git repo %s\n", repo_location);
if (cached_git_dir && update)
{
g_ptr_array_add (args, "--reference");
g_ptr_array_add (args, (char *)flatpak_file_get_path_cached (cached_git_dir));
}
/* Non-updating use of caches we just pull from the cache to avoid network i/o */
if (cached_git_dir && !update)
g_ptr_array_add (args, (char *)flatpak_file_get_path_cached (cached_git_dir));
else
g_ptr_array_add (args, (char *)repo_location);
g_ptr_array_add (args, filename_tmp);
g_ptr_array_add (args, NULL);
res = flatpak_spawnv (parent, NULL, 0, error,
(const gchar * const *) args->pdata);
if (cached_git_dir && !update &&
!git (mirror_dir_tmp, NULL, error,
"config", "--local", "remote.origin.url",
repo_location, NULL))
return FALSE;
/* Ensure we copy the files from the cache, to be safe if the extra source changes */
if (cached_git_dir && update)
{
g_autoptr(GFile) alternates = g_file_resolve_relative_path (mirror_dir_tmp, "objects/info/alternates");
if (!git (mirror_dir_tmp, NULL, error,
"repack", "-a", "-d", NULL))
return FALSE;
g_file_delete (alternates, NULL, NULL);
}
if (!res || !g_file_move (mirror_dir_tmp, mirror_dir, 0, NULL, NULL, NULL, error))
return FALSE;
}
else if (update)
{
g_print ("Fetching git repo %s\n", repo_location);
if (!git (mirror_dir, NULL, error,
"fetch", "-p", NULL))
return FALSE;
}
if (mirror_submodules)
{
current_commit = git_get_current_commit (mirror_dir, ref, FALSE, context, error);
if (current_commit == NULL)
return FALSE;
if (!git_mirror_submodules (repo_location, destination_path, update,
mirror_dir, disable_fsck, current_commit, context, error))
return FALSE;
}
return TRUE;
}
static gboolean
git_extract_submodule (const char *repo_location,
GFile *checkout_dir,
const char *revision,
BuilderContext *context,
GError **error)
{
g_autoptr(GKeyFile) key_file = g_key_file_new ();
g_autofree gchar *rev_parse_output = NULL;
g_autofree gchar *submodule_data = NULL;
g_autofree gchar **submodules = NULL;
g_autofree gchar *gitmodules = g_strconcat (revision, ":.gitmodules", NULL);
gsize num_submodules;
if (!git (checkout_dir, &rev_parse_output, NULL, "rev-parse", "--verify", "--quiet", gitmodules, NULL))
return TRUE;
if (git (checkout_dir, &submodule_data, NULL, "show", gitmodules, NULL))
{
if (!g_key_file_load_from_data (key_file, submodule_data, -1,
G_KEY_FILE_NONE, error))
return FALSE;
submodules = g_key_file_get_groups (key_file, &num_submodules);
int i;
for (i = 0; i < num_submodules; i++)
{
g_autofree gchar *submodule = NULL;
g_autofree gchar *name = NULL;
g_autofree gchar *update_method = NULL;
g_autofree gchar *path = NULL;
g_autofree gchar *relative_url = NULL;
g_autofree gchar *absolute_url = NULL;
g_autofree gchar *ls_tree = NULL;
g_auto(GStrv) lines = NULL;
g_auto(GStrv) words = NULL;
g_autoptr(GFile) mirror_dir = NULL;
g_autoptr(GFile) child_dir = NULL;
g_autofree gchar *mirror_dir_as_url = NULL;
g_autofree gchar *option = NULL;
gsize len;
submodule = submodules[i];
len = strlen (submodule);
if (!g_str_has_prefix (submodule, "submodule \""))
continue;
name = g_strndup (submodule + 11, len - 12);
/* Skip any submodules that are disabled (have the update method set to "none")
Only check if the command succeeds. If it fails, the update method is not set. */
update_method = g_key_file_get_string (key_file, submodule, "update", NULL);
if (g_strcmp0 (update_method, "none") == 0)
continue;
path = g_key_file_get_string (key_file, submodule, "path", error);
if (path == NULL)
return FALSE;
relative_url = g_key_file_get_string (key_file, submodule, "url", error);
absolute_url = make_absolute (repo_location, relative_url, error);
if (absolute_url == NULL)
return FALSE;
if (!git (checkout_dir, &ls_tree, error, "ls-tree", revision, path, NULL))
return FALSE;
lines = g_strsplit (g_strstrip (ls_tree), "\n", 0);
if (g_strv_length (lines) != 1)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Not a gitlink tree: %s", path);
return FALSE;
}
words = g_strsplit_set (lines[0], " \t", 4);
if (g_strcmp0 (words[0], "160000") != 0)
continue;
mirror_dir = git_get_mirror_dir (absolute_url, context);
mirror_dir_as_url = g_file_get_uri (mirror_dir);
option = g_strdup_printf ("submodule.%s.url", name);
if (!git (checkout_dir, NULL, error,
"config", option, mirror_dir_as_url, NULL))
return FALSE;
if (!git (checkout_dir, NULL, error,
"submodule", "update", "--init", path, NULL))
return FALSE;
child_dir = g_file_resolve_relative_path (checkout_dir, path);
if (!git_extract_submodule (absolute_url, child_dir, words[2], context, error))
return FALSE;
}
}
return TRUE;
}
gboolean
builder_git_checkout_dir (const char *repo_location,
const char *branch,
const char *dir,
GFile *dest,
BuilderContext *context,
GError **error)
{
g_autoptr(GFile) mirror_dir = NULL;
g_autofree char *mirror_dir_path = NULL;
g_autofree char *dest_path = NULL;
mirror_dir = git_get_mirror_dir (repo_location, context);
mirror_dir_path = g_file_get_path (mirror_dir);
dest_path = g_file_get_path (dest);
if (!git (NULL, NULL, error,
"clone", "-n", mirror_dir_path, dest_path, NULL))
return FALSE;
if (!git (dest, NULL, error,
"checkout", branch, "--", dir ? dir : ".", NULL))
return FALSE;
return TRUE;
}
gboolean
builder_git_checkout (const char *repo_location,
const char *branch,
GFile *dest,
BuilderContext *context,
GError **error)
{
g_autoptr(GFile) mirror_dir = NULL;
g_autofree char *mirror_dir_path = NULL;
g_autofree char *dest_path = NULL;
mirror_dir = git_get_mirror_dir (repo_location, context);
mirror_dir_path = g_file_get_path (mirror_dir);
dest_path = g_file_get_path (dest);
if (!git (NULL, NULL, error,
"clone", mirror_dir_path, dest_path, NULL))
return FALSE;
if (!git (dest, NULL, error,
"checkout", branch, NULL))
return FALSE;
if (!git_extract_submodule (repo_location, dest, branch, context, error))
return FALSE;
if (!git (dest, NULL, error,
"config", "--local", "remote.origin.url",
repo_location, NULL))
return FALSE;
return TRUE;
}

View File

@@ -1,55 +0,0 @@
/*
* 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.1 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_GIT_H__
#define __BUILDER_GIT_H__
#include "builder-context.h"
G_BEGIN_DECLS
gboolean builder_git_mirror_repo (const char *repo_location,
const char *destination_path,
gboolean update,
gboolean mirror_submodules,
gboolean disable_fsck,
const char *ref,
BuilderContext *context,
GError **error);
char * builder_git_get_current_commit (const char *repo_location,
const char *branch,
gboolean ensure_commit,
BuilderContext *context,
GError **error);
gboolean builder_git_checkout (const char *repo_location,
const char *branch,
GFile *dest,
BuilderContext *context,
GError **error);
gboolean builder_git_checkout_dir (const char *repo_location,
const char *branch,
const char *dir,
GFile *dest,
BuilderContext *context,
GError **error);
G_END_DECLS
#endif /* __BUILDER_GIT_H__ */

View File

@@ -1,928 +0,0 @@
/*
* 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.1 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 "builder-manifest.h"
#include "builder-utils.h"
#include "builder-git.h"
static gboolean opt_verbose;
static gboolean opt_version;
static gboolean opt_run;
static gboolean opt_disable_cache;
static gboolean opt_disable_rofiles;
static gboolean opt_download_only;
static gboolean opt_bundle_sources;
static gboolean opt_build_only;
static gboolean opt_finish_only;
static gboolean opt_export_only;
static gboolean opt_show_deps;
static gboolean opt_disable_download;
static gboolean opt_disable_updates;
static gboolean opt_ccache;
static gboolean opt_require_changes;
static gboolean opt_keep_build_dirs;
static gboolean opt_delete_build_dirs;
static gboolean opt_force_clean;
static gboolean opt_allow_missing_runtimes;
static gboolean opt_sandboxed;
static gboolean opt_rebuild_on_sdk_change;
static gboolean opt_skip_if_unchanged;
static char *opt_from_git;
static char *opt_from_git_branch;
static char *opt_stop_at;
static char *opt_build_shell;
static char *opt_arch;
static char *opt_default_branch;
static char *opt_repo;
static char *opt_subject;
static char *opt_body;
static char *opt_collection_id = NULL;
static char *opt_gpg_homedir;
static char **opt_key_ids;
static char **opt_sources_dirs;
static char **opt_sources_urls;
static int opt_jobs;
static char *opt_mirror_screenshots_url;
static char *opt_install_deps_from;
static gboolean opt_install_deps_only;
static gboolean opt_user;
static char *opt_installation;
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 },
{ "arch", 0, 0, G_OPTION_ARG_STRING, &opt_arch, "Architecture to build for (must be host compatible)", "ARCH" },
{ "default-branch", 0, 0, G_OPTION_ARG_STRING, &opt_default_branch, "Change the default branch", "BRANCH" },
{ "run", 0, 0, G_OPTION_ARG_NONE, &opt_run, "Run a command in the build directory (see --run --help)", NULL },
{ "ccache", 0, 0, G_OPTION_ARG_NONE, &opt_ccache, "Use ccache", NULL },
{ "disable-cache", 0, 0, G_OPTION_ARG_NONE, &opt_disable_cache, "Disable cache lookups", NULL },
{ "disable-rofiles-fuse", 0, 0, G_OPTION_ARG_NONE, &opt_disable_rofiles, "Disable rofiles-fuse use", NULL },
{ "disable-download", 0, 0, G_OPTION_ARG_NONE, &opt_disable_download, "Don't download any new sources", NULL },
{ "disable-updates", 0, 0, G_OPTION_ARG_NONE, &opt_disable_updates, "Only download missing sources, never update to latest vcs version", NULL },
{ "download-only", 0, 0, G_OPTION_ARG_NONE, &opt_download_only, "Only download sources, don't build", NULL },
{ "bundle-sources", 0, 0, G_OPTION_ARG_NONE, &opt_bundle_sources, "Bundle module sources as runtime", NULL },
{ "extra-sources", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_sources_dirs, "Add a directory of sources specified by SOURCE-DIR, multiple uses of this option possible", "SOURCE-DIR"},
{ "extra-sources-url", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_sources_urls, "Add a url of sources specified by SOURCE-URL multiple uses of this option possible", "SOURCE-URL"},
{ "build-only", 0, 0, G_OPTION_ARG_NONE, &opt_build_only, "Stop after build, don't run clean and finish phases", NULL },
{ "finish-only", 0, 0, G_OPTION_ARG_NONE, &opt_finish_only, "Only run clean and finish and export phases", NULL },
{ "export-only", 0, 0, G_OPTION_ARG_NONE, &opt_export_only, "Only run export phase", NULL },
{ "allow-missing-runtimes", 0, 0, G_OPTION_ARG_NONE, &opt_allow_missing_runtimes, "Don't fail if runtime and sdk missing", NULL },
{ "show-deps", 0, 0, G_OPTION_ARG_NONE, &opt_show_deps, "List the dependencies of the json file (see --show-deps --help)", NULL },
{ "require-changes", 0, 0, G_OPTION_ARG_NONE, &opt_require_changes, "Don't create app dir or export if no changes", NULL },
{ "keep-build-dirs", 0, 0, G_OPTION_ARG_NONE, &opt_keep_build_dirs, "Don't remove build directories after install", NULL },
{ "delete-build-dirs", 0, 0, G_OPTION_ARG_NONE, &opt_delete_build_dirs, "Always remove build directories, even after build failure", NULL },
{ "repo", 0, 0, G_OPTION_ARG_STRING, &opt_repo, "Repo to export into", "DIR"},
{ "subject", 's', 0, G_OPTION_ARG_STRING, &opt_subject, "One line subject (passed to build-export)", "SUBJECT" },
{ "body", 'b', 0, G_OPTION_ARG_STRING, &opt_body, "Full description (passed to build-export)", "BODY" },
#ifdef FLATPAK_ENABLE_P2P
{ "collection-id", 0, 0, G_OPTION_ARG_STRING, &opt_collection_id, "Collection ID (passed to build-export)", "COLLECTION-ID" },
#endif /* FLATPAK_ENABLE_P2P */
{ "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "GPG Key ID to sign the commit with", "KEY-ID"},
{ "gpg-homedir", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"},
{ "force-clean", 0, 0, G_OPTION_ARG_NONE, &opt_force_clean, "Erase previous contents of DIRECTORY", NULL },
{ "sandbox", 0, 0, G_OPTION_ARG_NONE, &opt_sandboxed, "Enforce sandboxing, disabling build-args", NULL },
{ "stop-at", 0, 0, G_OPTION_ARG_STRING, &opt_stop_at, "Stop building at this module (implies --build-only)", "MODULENAME"},
{ "jobs", 0, 0, G_OPTION_ARG_INT, &opt_jobs, "Number of parallel jobs to build (default=NCPU)", "JOBS"},
{ "rebuild-on-sdk-change", 0, 0, G_OPTION_ARG_NONE, &opt_rebuild_on_sdk_change, "Rebuild if sdk changes", NULL },
{ "skip-if-unchanged", 0, 0, G_OPTION_ARG_NONE, &opt_skip_if_unchanged, "Don't do anything if the json didn't change", NULL },
{ "build-shell", 0, 0, G_OPTION_ARG_STRING, &opt_build_shell, "Extract and prepare sources for module, then start build shell", "MODULENAME"},
{ "from-git", 0, 0, G_OPTION_ARG_STRING, &opt_from_git, "Get input files from git repo", "URL"},
{ "from-git-branch", 0, 0, G_OPTION_ARG_STRING, &opt_from_git_branch, "Branch to use in --from-git", "BRANCH"},
{ "mirror-screenshots-url", 0, 0, G_OPTION_ARG_STRING, &opt_mirror_screenshots_url, "Download and rewrite screenshots to match this url", "URL"},
{ "install-deps-from", 0, 0, G_OPTION_ARG_STRING, &opt_install_deps_from, "Install build dependencies from this remote", "REMOTE"},
{ "install-deps-only", 0, 0, G_OPTION_ARG_NONE, &opt_install_deps_only, "Stop after installing dependencies"},
{ "user", 0, 0, G_OPTION_ARG_NONE, &opt_user, "Install dependencies in user installations", NULL },
{ "system", 0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &opt_user, "Install dependencies in system-wide installations (default)", NULL },
{ "installation", 0, 0, G_OPTION_ARG_STRING, &opt_installation, "Install dependencies in a specific system-wide installation", "NAME" },
{ NULL }
};
static GOptionEntry run_entries[] = {
{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &opt_verbose, "Print debug information during command processing", NULL },
{ "arch", 0, 0, G_OPTION_ARG_STRING, &opt_arch, "Architecture to build for (must be host compatible)", "ARCH" },
{ "run", 0, 0, G_OPTION_ARG_NONE, &opt_run, "Run a command in the build directory", NULL },
{ "ccache", 0, 0, G_OPTION_ARG_NONE, &opt_ccache, "Use ccache", NULL },
{ NULL }
};
static GOptionEntry show_deps_entries[] = {
{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &opt_verbose, "Print debug information during command processing", NULL },
{ "show-deps", 0, 0, G_OPTION_ARG_NONE, &opt_show_deps, "List the dependencies of the json file (see --show-deps --help)", 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);
}
static 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;
}
static const char skip_arg[] = "skip";
static gboolean
do_export (BuilderContext *build_context,
GError **error,
gboolean runtime,
const gchar *location,
const gchar *directory,
char **exclude_dirs,
const gchar *branch,
const gchar *collection_id,
...)
{
va_list ap;
const char *arg;
int i;
g_autoptr(GPtrArray) args = NULL;
g_autoptr(GSubprocess) subp = NULL;
args = g_ptr_array_new_with_free_func (g_free);
g_ptr_array_add (args, g_strdup ("flatpak"));
g_ptr_array_add (args, g_strdup ("build-export"));
g_ptr_array_add (args, g_strdup_printf ("--arch=%s", builder_context_get_arch (build_context)));
if (runtime)
g_ptr_array_add (args, g_strdup ("--runtime"));
if (opt_subject)
g_ptr_array_add (args, g_strdup_printf ("--subject=%s", opt_subject));
if (opt_body)
g_ptr_array_add (args, g_strdup_printf ("--body=%s", opt_body));
if (opt_gpg_homedir)
g_ptr_array_add (args, g_strdup_printf ("--gpg-homedir=%s", opt_gpg_homedir));
for (i = 0; opt_key_ids != NULL && opt_key_ids[i] != NULL; i++)
g_ptr_array_add (args, g_strdup_printf ("--gpg-sign=%s", opt_key_ids[i]));
if (collection_id)
g_ptr_array_add (args, g_strdup_printf ("--collection-id=%s", collection_id));
/* Additional flags. */
va_start (ap, collection_id);
while ((arg = va_arg (ap, const gchar *)))
if (arg != skip_arg)
g_ptr_array_add (args, g_strdup ((gchar *) arg));
va_end (ap);
if (exclude_dirs)
{
for (i = 0; exclude_dirs[i] != NULL; i++)
g_ptr_array_add (args, g_strdup_printf ("--exclude=/%s/*", exclude_dirs[i]));
}
/* Mandatory positional arguments. */
g_ptr_array_add (args, g_strdup (location));
g_ptr_array_add (args, g_strdup (directory));
g_ptr_array_add (args, g_strdup (branch));
g_ptr_array_add (args, NULL);
subp =
g_subprocess_newv ((const gchar * const *) args->pdata,
G_SUBPROCESS_FLAGS_NONE,
error);
if (subp == NULL ||
!g_subprocess_wait_check (subp, NULL, error))
return FALSE;
return TRUE;
}
int
main (int argc,
char **argv)
{
g_autofree const char *old_env = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(BuilderManifest) manifest = NULL;
g_autoptr(GOptionContext) context = NULL;
const char *app_dir_path = NULL, *manifest_rel_path;
g_autofree gchar *json = NULL;
g_autofree gchar *json_sha256 = NULL;
g_autofree gchar *old_json_sha256 = NULL;
g_autoptr(BuilderContext) build_context = NULL;
g_autoptr(GFile) base_dir = NULL;
g_autoptr(GFile) manifest_file = NULL;
g_autoptr(GFile) app_dir = NULL;
g_autoptr(BuilderCache) cache = NULL;
g_autofree char *cache_branch = NULL;
g_autoptr(GFileEnumerator) dir_enum = NULL;
g_autoptr(GFileEnumerator) dir_enum2 = NULL;
g_autofree char *cwd = NULL;
g_autoptr(GFile) cwd_dir = NULL;
GFileInfo *next = NULL;
const char *platform_id = NULL;
g_autofree char **orig_argv = NULL;
gboolean is_run = FALSE;
gboolean is_show_deps = FALSE;
gboolean app_dir_is_empty = FALSE;
g_autoptr(FlatpakContext) arg_context = NULL;
g_autoptr(FlatpakTempDir) cleanup_manifest_dir = NULL;
g_autofree char *manifest_basename = NULL;
int i, first_non_arg, orig_argc;
int argnr;
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");
orig_argv = g_memdup (argv, sizeof (char *) * argc);
orig_argc = argc;
first_non_arg = 1;
for (i = 1; i < argc; i++)
{
if (argv[i][0] != '-')
break;
first_non_arg = i + 1;
if (strcmp (argv[i], "--run") == 0)
is_run = TRUE;
if (strcmp (argv[i], "--show-deps") == 0)
is_show_deps = TRUE;
}
if (is_run)
{
context = g_option_context_new ("DIRECTORY MANIFEST COMMAND [args] - Run command in build sandbox");
g_option_context_add_main_entries (context, run_entries, NULL);
arg_context = flatpak_context_new ();
g_option_context_add_group (context, flatpak_context_get_options (arg_context));
/* We drop the post-command part from the args, these go with the command in the sandbox */
argc = MIN (first_non_arg + 3, argc);
}
else if (is_show_deps)
{
context = g_option_context_new ("MANIFEST - Show manifest dependencies");
g_option_context_add_main_entries (context, show_deps_entries, NULL);
}
else
{
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 (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, message_handler, NULL);
argnr = 1;
if (!is_show_deps)
{
if (argc == argnr)
return usage (context, "DIRECTORY must be specified");
app_dir_path = argv[argnr++];
}
if (argc == argnr)
return usage (context, "MANIFEST must be specified");
manifest_rel_path = argv[argnr++];
manifest_basename = g_path_get_basename (manifest_rel_path);
#ifdef FLATPAK_ENABLE_P2P
if (opt_collection_id != NULL &&
!ostree_validate_collection_id (opt_collection_id, &error))
{
g_printerr ("%s is not a valid collection ID: %s", opt_collection_id, error->message);
return 1;
}
#endif /* FLATPAK_ENABLE_P2P */
if (app_dir_path)
app_dir = g_file_new_for_path (app_dir_path);
cwd = g_get_current_dir ();
cwd_dir = g_file_new_for_path (cwd);
build_context = builder_context_new (cwd_dir, app_dir);
builder_context_set_use_rofiles (build_context, !opt_disable_rofiles);
builder_context_set_keep_build_dirs (build_context, opt_keep_build_dirs);
builder_context_set_delete_build_dirs (build_context, opt_delete_build_dirs);
builder_context_set_sandboxed (build_context, opt_sandboxed);
builder_context_set_jobs (build_context, opt_jobs);
builder_context_set_rebuild_on_sdk_change (build_context, opt_rebuild_on_sdk_change);
builder_context_set_bundle_sources (build_context, opt_bundle_sources);
if (opt_sources_dirs)
{
g_autoptr(GPtrArray) sources_dirs = NULL;
sources_dirs = g_ptr_array_new_with_free_func (g_object_unref);
for (i = 0; opt_sources_dirs != NULL && opt_sources_dirs[i] != NULL; i++)
{
GFile *file = g_file_new_for_commandline_arg (opt_sources_dirs[i]);
g_ptr_array_add (sources_dirs, file);
}
builder_context_set_sources_dirs (build_context, sources_dirs);
}
if (opt_sources_urls)
{
g_autoptr(GPtrArray) sources_urls = NULL;
sources_urls = g_ptr_array_new_with_free_func ((GDestroyNotify)soup_uri_free);
for (i = 0; opt_sources_urls[i] != NULL; i++)
{
SoupURI *uri = soup_uri_new (opt_sources_urls[i]);
if (uri == NULL)
{
g_printerr ("Invalid URL '%s'", opt_sources_urls[i]);
return 1;
}
g_ptr_array_add (sources_urls, uri);
}
builder_context_set_sources_urls (build_context, sources_urls);
}
if (opt_arch)
builder_context_set_arch (build_context, opt_arch);
if (opt_stop_at)
{
opt_build_only = TRUE;
builder_context_set_stop_at (build_context, opt_stop_at);
}
if (opt_ccache &&
!builder_context_enable_ccache (build_context, &error))
{
g_printerr ("Can't initialize ccache use: %s\n", error->message);
return 1;
}
if (opt_from_git)
{
g_autofree char *manifest_dirname = g_path_get_dirname (manifest_rel_path);
const char *git_branch = opt_from_git_branch ? opt_from_git_branch : "master";
g_autofree char *git_origin_branch = g_strconcat ("origin/", git_branch, NULL);
g_autoptr(GFile) build_subdir = NULL;
if (!builder_git_mirror_repo (opt_from_git,
NULL,
!opt_disable_updates, FALSE, FALSE,
git_branch, build_context, &error))
{
g_printerr ("Can't clone manifest repo: %s\n", error->message);
return 1;
}
build_subdir = builder_context_allocate_build_subdir (build_context, manifest_basename, &error);
if (build_subdir == NULL)
{
g_printerr ("Can't check out manifest repo: %s\n", error->message);
return 1;
}
cleanup_manifest_dir = g_object_ref (build_subdir);
if (!builder_git_checkout_dir (opt_from_git,
git_origin_branch,
manifest_dirname,
build_subdir,
build_context,
&error))
{
g_printerr ("Can't check out manifest repo: %s\n", error->message);
return 1;
}
manifest_file = g_file_get_child (build_subdir, manifest_rel_path);
base_dir = g_file_resolve_relative_path (build_subdir, manifest_dirname);
}
else
{
manifest_file = g_file_new_for_path (manifest_rel_path);
base_dir = g_file_get_parent (manifest_file);
}
builder_context_set_base_dir (build_context, base_dir);
if (!g_file_get_contents (flatpak_file_get_path_cached (manifest_file), &json, NULL, &error))
{
g_printerr ("Can't load '%s': %s\n", manifest_rel_path, error->message);
return 1;
}
json_sha256 = g_compute_checksum_for_string (G_CHECKSUM_SHA256, json, -1);
if (opt_skip_if_unchanged)
{
old_json_sha256 = builder_context_get_checksum_for (build_context, manifest_basename);
if (old_json_sha256 != NULL && strcmp (json_sha256, old_json_sha256) == 0)
{
g_print ("No changes to manifest, skipping\n");
return 42;
}
}
/* Can't push this as user data to the demarshalling :/ */
builder_manifest_set_demarshal_base_dir (builder_context_get_base_dir (build_context));
manifest = (BuilderManifest *) json_gobject_from_data (BUILDER_TYPE_MANIFEST,
json, -1, &error);
builder_manifest_set_demarshal_base_dir (NULL);
if (manifest == NULL)
{
g_printerr ("Can't parse '%s': %s\n", manifest_rel_path, error->message);
return 1;
}
if (opt_default_branch)
builder_manifest_set_default_branch (manifest, opt_default_branch);
if (opt_collection_id)
builder_manifest_set_default_collection_id (manifest, opt_collection_id);
if (is_run && argc == 3)
return usage (context, "Program to run must be specified");
if (opt_show_deps && !is_show_deps)
return usage (context, "Can't use --show-deps after a non-option");
if (opt_run && !is_run)
return usage (context, "Can't use --run after a non-option");
if (is_show_deps)
{
if (!builder_manifest_show_deps (manifest, build_context, &error))
{
g_printerr ("Error running %s: %s\n", argv[3], error->message);
return 1;
}
return 0;
}
if (opt_install_deps_from != NULL)
{
if (!builder_manifest_install_deps (manifest, build_context, opt_install_deps_from, opt_user, opt_installation, &error))
{
g_printerr ("Error running %s: %s\n", argv[3], error->message);
return 1;
}
if (opt_install_deps_only)
return 0;
}
app_dir_is_empty = !g_file_query_exists (app_dir, NULL) ||
directory_is_empty (app_dir_path);
if (is_run)
{
g_assert (opt_run);
if (app_dir_is_empty)
{
g_printerr ("App dir '%s' is empty or doesn't exist.\n", app_dir_path);
return 1;
}
if (!builder_manifest_run (manifest, build_context, arg_context,
orig_argv + first_non_arg + 2,
orig_argc - first_non_arg - 2, &error))
{
g_printerr ("Error running %s: %s\n", argv[3], error->message);
return 1;
}
return 0;
}
g_assert (!opt_run);
g_assert (!opt_show_deps);
if (opt_export_only || opt_finish_only || opt_build_shell)
{
if (app_dir_is_empty)
{
g_printerr ("App dir '%s' is empty or doesn't exist.\n", app_dir_path);
return 1;
}
}
else
{
if (!app_dir_is_empty)
{
if (opt_force_clean)
{
g_print ("Emptying app dir '%s'\n", app_dir_path);
if (!flatpak_rm_rf (app_dir, NULL, &error))
{
g_printerr ("Couldn't empty app dir '%s': %s",
app_dir_path, error->message);
return 1;
}
}
else
{
g_printerr ("App dir '%s' is not empty. Please delete "
"the existing contents or use --force-clean.\n", app_dir_path);
return 1;
}
}
}
builder_context_set_checksum_for (build_context, manifest_basename, json_sha256);
if (!builder_manifest_start (manifest, opt_allow_missing_runtimes, build_context, &error))
{
g_printerr ("Failed to init: %s\n", error->message);
return 1;
}
if (!opt_finish_only &&
!opt_export_only &&
!opt_disable_download &&
!builder_manifest_download (manifest, !opt_disable_updates, opt_build_shell, build_context, &error))
{
g_printerr ("Failed to download sources: %s\n", error->message);
return 1;
}
if (opt_download_only)
return 0;
if (opt_build_shell)
{
if (!builder_manifest_build_shell (manifest, build_context, opt_build_shell, &error))
{
g_printerr ("Failed to setup module: %s\n", error->message);
return 1;
}
return 0;
}
cache_branch = g_strconcat (builder_context_get_arch (build_context), "-", manifest_basename, NULL);
cache = builder_cache_new (build_context, app_dir, cache_branch);
if (!builder_cache_open (cache, &error))
{
g_printerr ("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 (!opt_finish_only && !opt_export_only)
{
if (!builder_cache_lookup (cache, "init"))
{
g_autofree char *body =
g_strdup_printf ("Initialized %s\n",
builder_manifest_get_id (manifest));
if (!builder_manifest_init_app_dir (manifest, cache, build_context, &error))
{
g_printerr ("Error: %s\n", error->message);
return 1;
}
if (!builder_cache_commit (cache, body, &error))
{
g_printerr ("Error: %s\n", error->message);
return 1;
}
}
if (!builder_manifest_build (manifest, cache, build_context, &error))
{
g_printerr ("Error: %s\n", error->message);
return 1;
}
}
if (!opt_build_only && !opt_export_only)
{
if (!builder_manifest_cleanup (manifest, cache, build_context, &error))
{
g_printerr ("Error: %s\n", error->message);
return 1;
}
if (!builder_manifest_finish (manifest, cache, build_context, &error))
{
g_printerr ("Error: %s\n", error->message);
return 1;
}
if (!builder_manifest_create_platform (manifest, cache, build_context, &error))
{
g_printerr ("Error: %s\n", error->message);
return 1;
}
if (builder_context_get_bundle_sources (build_context) &&
!builder_manifest_bundle_sources (manifest, json, cache, build_context, &error))
{
g_printerr ("Error: %s\n", error->message);
return 1;
}
}
if (!opt_require_changes && !opt_export_only)
builder_cache_ensure_checkout (cache);
if (opt_mirror_screenshots_url && !opt_export_only)
{
g_autofree char *screenshot_subdir = g_strdup_printf ("%s-%s", builder_manifest_get_id (manifest),
builder_manifest_get_branch (manifest));
g_autofree char *url = g_build_filename (opt_mirror_screenshots_url, screenshot_subdir, NULL);
g_autofree char *xml_relpath = g_strdup_printf ("files/share/app-info/xmls/%s.xml.gz", builder_manifest_get_id (manifest));
g_autoptr(GFile) xml = g_file_resolve_relative_path (app_dir, xml_relpath);
g_autoptr(GFile) cache = flatpak_build_file (builder_context_get_state_dir (build_context), "screenshots-cache", NULL);
g_autoptr(GFile) screenshots = flatpak_build_file (app_dir, "screenshots", NULL);
g_autoptr(GFile) screenshots_sub = flatpak_build_file (screenshots, screenshot_subdir, NULL);
const char *argv[] = {
"appstream-util",
"mirror-screenshots",
flatpak_file_get_path_cached (xml),
url,
flatpak_file_get_path_cached (cache),
flatpak_file_get_path_cached (screenshots_sub),
NULL
};
g_print ("Mirroring screenshots from appdata\n");
if (!flatpak_mkdir_p (screenshots, NULL, &error))
{
g_printerr ("Error creating screenshot dir: %s\n", error->message);
return 1;
}
if (g_file_query_exists (xml, NULL))
{
if (!builder_maybe_host_spawnv (NULL,
NULL,
&error,
argv))
{
g_printerr ("Error mirroring screenshots: %s\n", error->message);
return 1;
}
}
g_print ("Saved screenshots in %s\n", flatpak_file_get_path_cached (screenshots));
}
if (!opt_build_only && opt_repo && (opt_export_only || builder_cache_has_checkout (cache)))
{
g_autoptr(GFile) debuginfo_metadata = NULL;
g_autoptr(GFile) sourcesinfo_metadata = NULL;
g_auto(GStrv) exclude_dirs = builder_manifest_get_exclude_dirs (manifest);
GList *l;
g_print ("Exporting %s to repo\n", builder_manifest_get_id (manifest));
if (!do_export (build_context, &error,
FALSE,
opt_repo, app_dir_path, exclude_dirs, builder_manifest_get_branch (manifest),
builder_manifest_get_collection_id (manifest),
"--exclude=/lib/debug/*",
"--include=/lib/debug/app",
builder_context_get_separate_locales (build_context) ? "--exclude=/share/runtime/locale/*/*" : skip_arg,
NULL))
{
g_printerr ("Export failed: %s\n", error->message);
return 1;
}
/* Export regular locale extensions */
dir_enum = g_file_enumerate_children (app_dir, "standard::name,standard::type",
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
NULL, NULL);
while (dir_enum != NULL &&
(next = g_file_enumerator_next_file (dir_enum, NULL, NULL)))
{
g_autoptr(GFileInfo) child_info = next;
const char *name = g_file_info_get_name (child_info);
g_autofree char *metadata_arg = NULL;
g_autofree char *files_arg = NULL;
g_autofree char *locale_id = builder_manifest_get_locale_id (manifest);
if (strcmp (name, "metadata.locale") == 0)
g_print ("Exporting %s to repo\n", locale_id);
else
continue;
metadata_arg = g_strdup_printf ("--metadata=%s", name);
files_arg = g_strconcat (builder_context_get_build_runtime (build_context) ? "--files=usr" : "--files=files",
"/share/runtime/locale/", NULL);
if (!do_export (build_context, &error, TRUE,
opt_repo, app_dir_path, NULL, builder_manifest_get_branch (manifest),
builder_manifest_get_collection_id (manifest),
metadata_arg,
files_arg,
NULL))
{
g_printerr ("Export failed: %s\n", error->message);
return 1;
}
}
/* Export debug extensions */
debuginfo_metadata = g_file_get_child (app_dir, "metadata.debuginfo");
if (g_file_query_exists (debuginfo_metadata, NULL))
{
g_autofree char *debug_id = builder_manifest_get_debug_id (manifest);
g_print ("Exporting %s to repo\n", debug_id);
if (!do_export (build_context, &error, TRUE,
opt_repo, app_dir_path, NULL, builder_manifest_get_branch (manifest),
builder_manifest_get_collection_id (manifest),
"--metadata=metadata.debuginfo",
builder_context_get_build_runtime (build_context) ? "--files=usr/lib/debug" : "--files=files/lib/debug",
NULL))
{
g_printerr ("Export failed: %s\n", error->message);
return 1;
}
}
for (l = builder_manifest_get_add_extensions (manifest); l != NULL; l = l->next)
{
BuilderExtension *e = l->data;
const char *extension_id = NULL;
g_autofree char *metadata_arg = NULL;
g_autofree char *files_arg = NULL;
if (!builder_extension_is_bundled (e))
continue;
extension_id = builder_extension_get_name (e);
g_print ("Exporting %s to repo\n", extension_id);
metadata_arg = g_strdup_printf ("--metadata=metadata.%s", extension_id);
files_arg = g_strdup_printf ("--files=%s/%s",
builder_context_get_build_runtime (build_context) ? "usr" : "files",
builder_extension_get_directory (e));
if (!do_export (build_context, &error, TRUE,
opt_repo, app_dir_path, NULL, builder_manifest_get_branch (manifest),
builder_manifest_get_collection_id (manifest),
metadata_arg, files_arg,
NULL))
{
g_printerr ("Export failed: %s\n", error->message);
return 1;
}
}
/* Export sources extensions */
sourcesinfo_metadata = g_file_get_child (app_dir, "metadata.sources");
if (g_file_query_exists (sourcesinfo_metadata, NULL))
{
g_autofree char *sources_id = builder_manifest_get_sources_id (manifest);
g_print ("Exporting %s to repo\n", sources_id);
if (!do_export (build_context, &error, TRUE,
opt_repo, app_dir_path, NULL, builder_manifest_get_branch (manifest),
builder_manifest_get_collection_id (manifest),
"--metadata=metadata.sources",
"--files=sources",
NULL))
{
g_printerr ("Export failed: %s\n", error->message);
return 1;
}
}
/* Export platform */
platform_id = builder_manifest_get_id_platform (manifest);
if (builder_context_get_build_runtime (build_context) &&
platform_id != NULL)
{
g_print ("Exporting %s to repo\n", platform_id);
if (!do_export (build_context, &error, TRUE,
opt_repo, app_dir_path, NULL, builder_manifest_get_branch (manifest),
builder_manifest_get_collection_id (manifest),
"--metadata=metadata.platform",
"--files=platform",
builder_context_get_separate_locales (build_context) ? "--exclude=/share/runtime/locale/*/*" : skip_arg,
NULL))
{
g_printerr ("Export failed: %s\n", error->message);
return 1;
}
}
/* Export platform locales */
dir_enum2 = g_file_enumerate_children (app_dir, "standard::name,standard::type",
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
NULL, NULL);
while (dir_enum2 != NULL &&
(next = g_file_enumerator_next_file (dir_enum2, NULL, NULL)))
{
g_autoptr(GFileInfo) child_info = next;
const char *name = g_file_info_get_name (child_info);
g_autofree char *metadata_arg = NULL;
g_autofree char *files_arg = NULL;
g_autofree char *locale_id = builder_manifest_get_locale_id_platform (manifest);
if (strcmp (name, "metadata.platform.locale") == 0)
g_print ("Exporting %s to repo\n", locale_id);
else
continue;
metadata_arg = g_strdup_printf ("--metadata=%s", name);
files_arg = g_strconcat ("--files=platform/share/runtime/locale/", NULL);
if (!do_export (build_context, &error, TRUE,
opt_repo, app_dir_path, NULL, builder_manifest_get_branch (manifest),
builder_manifest_get_collection_id (manifest),
metadata_arg,
files_arg,
NULL))
{
g_printerr ("Export failed: %s\n", error->message);
return 1;
}
}
}
if (!builder_gc (cache, &error))
{
g_warning ("Failed to GC build cache: %s", error->message);
g_clear_error (&error);
}
return 0;
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,132 +0,0 @@
/*
* 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.1 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 "flatpak-run.h"
#include "builder-options.h"
#include "builder-module.h"
#include "builder-cache.h"
#include "builder-extension.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 "4"
#define BUILDER_MANIFEST_CHECKSUM_CLEANUP_VERSION "1"
#define BUILDER_MANIFEST_CHECKSUM_FINISH_VERSION "2"
#define BUILDER_MANIFEST_CHECKSUM_BUNDLE_SOURCES_VERSION "1"
#define BUILDER_MANIFEST_CHECKSUM_PLATFORM_VERSION "1"
GType builder_manifest_get_type (void);
void builder_manifest_set_demarshal_base_dir (GFile *dir);
GFile *builder_manifest_get_demarshal_base_dir (void);
const char * builder_manifest_get_id (BuilderManifest *self);
char * builder_manifest_get_locale_id (BuilderManifest *self);
char * builder_manifest_get_debug_id (BuilderManifest *self);
char * builder_manifest_get_sources_id (BuilderManifest *self);
const char * builder_manifest_get_id_platform (BuilderManifest *self);
char * builder_manifest_get_locale_id_platform (BuilderManifest *self);
BuilderOptions *builder_manifest_get_build_options (BuilderManifest *self);
GList * builder_manifest_get_modules (BuilderManifest *self);
GList * builder_manifest_get_add_extensions (BuilderManifest *self);
const char * builder_manifest_get_branch (BuilderManifest *self);
void builder_manifest_set_default_branch (BuilderManifest *self,
const char *default_branch);
const char * builder_manifest_get_collection_id (BuilderManifest *self);
void builder_manifest_set_default_collection_id (BuilderManifest *self,
const char *default_collection_id);
char ** builder_manifest_get_exclude_dirs (BuilderManifest *self);
gboolean builder_manifest_start (BuilderManifest *self,
gboolean allow_missing_runtimes,
BuilderContext *context,
GError **error);
gboolean builder_manifest_init_app_dir (BuilderManifest *self,
BuilderCache *cache,
BuilderContext *context,
GError **error);
gboolean builder_manifest_download (BuilderManifest *self,
gboolean update_vcs,
const char *only_module,
BuilderContext *context,
GError **error);
gboolean builder_manifest_build_shell (BuilderManifest *self,
BuilderContext *context,
const char *modulename,
GError **error);
gboolean builder_manifest_build (BuilderManifest *self,
BuilderCache *cache,
BuilderContext *context,
GError **error);
gboolean builder_manifest_install_deps (BuilderManifest *self,
BuilderContext *context,
const char *remote,
gboolean opt_user,
const char *opt_installation,
GError **error);
gboolean builder_manifest_run (BuilderManifest *self,
BuilderContext *context,
FlatpakContext *arg_context,
char **argv,
int argc,
GError **error);
gboolean builder_manifest_show_deps (BuilderManifest *self,
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);
gboolean builder_manifest_bundle_sources (BuilderManifest *self,
const char *json,
BuilderCache *cache,
BuilderContext *context,
GError **error);
gboolean builder_manifest_create_platform (BuilderManifest *self,
BuilderCache *cache,
BuilderContext *context,
GError **error);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (BuilderManifest, g_object_unref)
G_END_DECLS
#endif /* __BUILDER_MANIFEST_H__ */

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,101 +0,0 @@
/*
* 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.1 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);
gboolean builder_module_is_enabled (BuilderModule *self,
BuilderContext *context);
gboolean builder_module_get_disabled (BuilderModule *self);
gboolean builder_module_should_build (BuilderModule *self);
GList * builder_module_get_sources (BuilderModule *self);
GList * builder_module_get_modules (BuilderModule *self);
void builder_module_set_json_path (BuilderModule *self,
const char *json_path);
void builder_module_set_base_dir (BuilderModule *self,
GFile* base_dir);
GPtrArray * builder_module_get_changes (BuilderModule *self);
void builder_module_set_changes (BuilderModule *self,
GPtrArray *changes);
gboolean builder_module_show_deps (BuilderModule *self,
BuilderContext *context,
GError **error);
gboolean builder_module_download_sources (BuilderModule *self,
gboolean update_vcs,
BuilderContext *context,
GError **error);
gboolean builder_module_extract_sources (BuilderModule *self,
GFile *dest,
BuilderContext *context,
GError **error);
gboolean builder_module_bundle_sources (BuilderModule *self,
BuilderContext *context,
GError **error);
gboolean builder_module_ensure_writable (BuilderModule *self,
BuilderCache *cache,
BuilderContext *context,
GError **error);
gboolean builder_module_build (BuilderModule *self,
BuilderCache *cache,
BuilderContext *context,
gboolean run_shell,
GError **error);
gboolean builder_module_update (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_checksum_for_platform (BuilderModule *self,
BuilderCache *cache,
BuilderContext *context);
void builder_module_cleanup_collect (BuilderModule *self,
gboolean platform,
BuilderContext *context,
GHashTable *to_remove_ht);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (BuilderModule, g_object_unref)
G_END_DECLS
#endif /* __BUILDER_MODULE_H__ */

View File

@@ -1,788 +0,0 @@
/* 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 2 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 Lesser 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;
gboolean strip;
gboolean no_debuginfo;
char *cflags;
char *cppflags;
char *cxxflags;
char *ldflags;
char *prefix;
char **env;
char **build_args;
char **config_opts;
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_CPPFLAGS,
PROP_CXXFLAGS,
PROP_LDFLAGS,
PROP_PREFIX,
PROP_ENV,
PROP_STRIP,
PROP_NO_DEBUGINFO,
PROP_ARCH,
PROP_BUILD_ARGS,
PROP_CONFIG_OPTS,
LAST_PROP
};
static void
builder_options_finalize (GObject *object)
{
BuilderOptions *self = (BuilderOptions *) object;
g_free (self->cflags);
g_free (self->cxxflags);
g_free (self->cppflags);
g_free (self->ldflags);
g_free (self->prefix);
g_strfreev (self->env);
g_strfreev (self->build_args);
g_strfreev (self->config_opts);
g_hash_table_destroy (self->arch);
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_CPPFLAGS:
g_value_set_string (value, self->cppflags);
break;
case PROP_CXXFLAGS:
g_value_set_string (value, self->cxxflags);
break;
case PROP_LDFLAGS:
g_value_set_string (value, self->ldflags);
break;
case PROP_PREFIX:
g_value_set_string (value, self->prefix);
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;
case PROP_CONFIG_OPTS:
g_value_set_boxed (value, self->config_opts);
break;
case PROP_STRIP:
g_value_set_boolean (value, self->strip);
break;
case PROP_NO_DEBUGINFO:
g_value_set_boolean (value, self->no_debuginfo);
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_CPPFLAGS:
g_clear_pointer (&self->cppflags, g_free);
self->cppflags = g_value_dup_string (value);
break;
case PROP_LDFLAGS:
g_clear_pointer (&self->ldflags, g_free);
self->ldflags = g_value_dup_string (value);
break;
case PROP_PREFIX:
g_clear_pointer (&self->prefix, g_free);
self->prefix = 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;
case PROP_CONFIG_OPTS:
tmp = self->config_opts;
self->config_opts = g_strdupv (g_value_get_boxed (value));
g_strfreev (tmp);
break;
case PROP_STRIP:
self->strip = g_value_get_boolean (value);
break;
case PROP_NO_DEBUGINFO:
self->no_debuginfo = g_value_get_boolean (value);
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_CPPFLAGS,
g_param_spec_string ("cppflags",
"",
"",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_LDFLAGS,
g_param_spec_string ("ldflags",
"",
"",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_PREFIX,
g_param_spec_string ("prefix",
"",
"",
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));
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_STRIP,
g_param_spec_boolean ("strip",
"",
"",
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_NO_DEBUGINFO,
g_param_spec_boolean ("no-debuginfo",
"",
"",
FALSE,
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 JsonNode *
builder_options_serialize_property (JsonSerializable *serializable,
const gchar *property_name,
const GValue *value,
GParamSpec *pspec)
{
if (strcmp (property_name, "arch") == 0)
{
BuilderOptions *self = BUILDER_OPTIONS (serializable);
JsonNode *retval = NULL;
if (self->arch && g_hash_table_size (self->arch) > 0)
{
JsonObject *object;
GHashTableIter iter;
gpointer key, value;
object = json_object_new ();
g_hash_table_iter_init (&iter, self->arch);
while (g_hash_table_iter_next (&iter, &key, &value))
{
JsonNode *child = json_gobject_serialize (value);
json_object_set_member (object, (char *) key, child);
}
retval = json_node_init_object (json_node_alloc (), object);
json_object_unref (object);
}
return retval;
}
else if (strcmp (property_name, "env") == 0)
{
BuilderOptions *self = BUILDER_OPTIONS (serializable);
JsonNode *retval = NULL;
if (self->env && g_strv_length (self->env) > 0)
{
JsonObject *object;
int i;
object = json_object_new ();
for (i = 0; self->env[i] != NULL; i++)
{
JsonNode *str = json_node_new (JSON_NODE_VALUE);
const char *equal;
g_autofree char *member = NULL;
equal = strchr (self->env[i], '=');
if (equal)
{
json_node_set_string (str, equal + 1);
member = g_strndup (self->env[i], equal - self->env[i]);
}
else
{
json_node_set_string (str, "");
member = g_strdup (self->env[i]);
}
json_object_set_member (object, member, str);
}
retval = json_node_init_object (json_node_alloc (), object);
json_object_unref (object);
}
return retval;
}
else
{
return json_serializable_default_serialize_property (serializable,
property_name,
value,
pspec);
}
}
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(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_take_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->serialize_property = builder_options_serialize_property;
serializable_iface->deserialize_property = builder_options_deserialize_property;
serializable_iface->find_property = builder_serializable_find_property_with_error;
}
static GList *
get_arched_options (BuilderOptions *self, BuilderContext *context)
{
GList *options = NULL;
const char *arch = builder_context_get_arch (context);
BuilderOptions *arch_options;
options = g_list_prepend (options, self);
arch_options = g_hash_table_lookup (self->arch, arch);
if (arch_options)
options = g_list_prepend (options, arch_options);
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;
}
static const char *
builder_options_get_flags (BuilderOptions *self, BuilderContext *context, size_t field_offset)
{
g_autoptr(GList) options = get_all_options (self, context);
GList *l;
GString *flags = NULL;
/* Last command flag wins, so reverse order */
options = g_list_reverse (options);
for (l = options; l != NULL; l = l->next)
{
BuilderOptions *o = l->data;
const char *flag = G_STRUCT_MEMBER (const char *, o, field_offset);
if (flag)
{
if (flags == NULL)
flags = g_string_new ("");
if (flags->len > 0)
g_string_append_c (flags, ' ');
g_string_append (flags, flag);
}
}
if (flags)
return g_string_free (flags, FALSE);
return NULL;
}
const char *
builder_options_get_cflags (BuilderOptions *self, BuilderContext *context)
{
return builder_options_get_flags (self, context, G_STRUCT_OFFSET (BuilderOptions, cflags));
}
const char *
builder_options_get_cxxflags (BuilderOptions *self, BuilderContext *context)
{
return builder_options_get_flags (self, context, G_STRUCT_OFFSET (BuilderOptions, cxxflags));
}
const char *
builder_options_get_cppflags (BuilderOptions *self, BuilderContext *context)
{
return builder_options_get_flags (self, context, G_STRUCT_OFFSET (BuilderOptions, cppflags));
}
const char *
builder_options_get_ldflags (BuilderOptions *self, BuilderContext *context)
{
return builder_options_get_flags (self, context, G_STRUCT_OFFSET (BuilderOptions, ldflags));
}
const char *
builder_options_get_prefix (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->prefix)
return o->prefix;
}
if (builder_context_get_build_runtime (context))
return "/usr";
return "/app";
}
gboolean
builder_options_get_strip (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->strip)
return TRUE;
}
return FALSE;
}
gboolean
builder_options_get_no_debuginfo (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->no_debuginfo)
return TRUE;
}
return FALSE;
}
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;
const char *cflags, *cppflags, *cxxflags, *ldflags;
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);
}
}
}
envp = builder_context_extend_env (context, envp);
cflags = builder_options_get_cflags (self, context);
if (cflags)
envp = g_environ_setenv (envp, "CFLAGS", cflags, FALSE);
cppflags = builder_options_get_cppflags (self, context);
if (cppflags)
envp = g_environ_setenv (envp, "CPPFLAGS", cppflags, FALSE);
cxxflags = builder_options_get_cxxflags (self, context);
if (cxxflags)
envp = g_environ_setenv (envp, "CXXFLAGS", cxxflags, FALSE);
ldflags = builder_options_get_ldflags (self, context);
if (ldflags)
envp = g_environ_setenv (envp, "LDFLAGS", ldflags, FALSE);
return envp;
}
char **
builder_options_get_build_args (BuilderOptions *self,
BuilderContext *context,
GError **error)
{
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]));
}
}
if (array->len > 0 && builder_context_get_sandboxed (context))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Can't specify build-args in sandboxed build");
return NULL;
}
g_ptr_array_add (array, NULL);
return (char **) g_ptr_array_free (g_steal_pointer (&array), FALSE);
}
char **
builder_options_get_config_opts (BuilderOptions *self,
BuilderContext *context,
char **base_opts)
{
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);
/* Start by adding the base options */
if (base_opts)
{
for (i = 0; base_opts[i] != NULL; i++)
g_ptr_array_add (array, g_strdup (base_opts[i]));
}
for (l = options; l != NULL; l = l->next)
{
BuilderOptions *o = l->data;
if (o->config_opts)
{
for (i = 0; o->config_opts[i] != NULL; i++)
g_ptr_array_add (array, g_strdup (o->config_opts[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_compat_str (cache, self->cppflags);
builder_cache_checksum_str (cache, self->ldflags);
builder_cache_checksum_str (cache, self->prefix);
builder_cache_checksum_strv (cache, self->env);
builder_cache_checksum_strv (cache, self->build_args);
builder_cache_checksum_strv (cache, self->config_opts);
builder_cache_checksum_boolean (cache, self->strip);
builder_cache_checksum_boolean (cache, self->no_debuginfo);
arch_options = g_hash_table_lookup (self->arch, builder_context_get_arch (context));
if (arch_options)
builder_options_checksum (arch_options, cache, context);
}

View File

@@ -1,70 +0,0 @@
/*
* 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.1 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 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);
const char *builder_options_get_cppflags (BuilderOptions *self,
BuilderContext *context);
const char *builder_options_get_ldflags (BuilderOptions *self,
BuilderContext *context);
const char *builder_options_get_prefix (BuilderOptions *self,
BuilderContext *context);
char ** builder_options_get_env (BuilderOptions *self,
BuilderContext *context);
char ** builder_options_get_build_args (BuilderOptions *self,
BuilderContext *context,
GError **error);
char ** builder_options_get_config_opts (BuilderOptions *self,
BuilderContext *context,
char **base_opts);
void builder_options_checksum (BuilderOptions *self,
BuilderCache *cache,
BuilderContext *context);
gboolean builder_options_get_no_debuginfo (BuilderOptions *self,
BuilderContext *context);
gboolean builder_options_get_strip (BuilderOptions *self,
BuilderContext *context);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (BuilderOptions, g_object_unref)
G_END_DECLS
#endif /* __BUILDER_OPTIONS_H__ */

View File

@@ -1,504 +0,0 @@
/* builder-post-process.c
*
* Copyright (C) 2017 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 2 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 Lesser 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 "flatpak-utils.h"
#include "builder-utils.h"
#include "builder-post-process.h"
static gboolean
invalidate_old_python_compiled (const char *path,
const char *rel_path,
GError **error)
{
struct stat stbuf;
g_autofree char *pyc = NULL;
g_autofree char *pyo = NULL;
g_autofree char *dir = NULL;
g_autofree char *py3dir = NULL;
g_autofree char *pyfilename = NULL;
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
/* This is a python file, not a .py[oc]. If it changed (mtime != 0) then
* this needs to invalidate any old (mtime == 0) .py[oc] files that could refer to it.
*/
if (lstat (path, &stbuf) != 0)
{
g_warning ("Can't stat %s", rel_path);
return TRUE;
}
if (stbuf.st_mtime == OSTREE_TIMESTAMP)
return TRUE; /* Previously handled .py */
pyc = g_strconcat (path, "c", NULL);
if (lstat (pyc, &stbuf) == 0 &&
stbuf.st_mtime == OSTREE_TIMESTAMP)
{
g_print ("Removing stale file %sc", rel_path);
if (unlink (pyc) != 0)
g_warning ("Unable to delete %s", pyc);
}
pyo = g_strconcat (path, "o", NULL);
if (lstat (pyo, &stbuf) == 0 &&
stbuf.st_mtime == OSTREE_TIMESTAMP)
{
g_print ("Removing stale file %so", rel_path);
if (unlink (pyo) != 0)
g_warning ("Unable to delete %s", pyo);
}
/* Handle python3 which is in a __pycache__ subdir */
pyfilename = g_path_get_basename (path);
pyfilename[strlen (pyfilename) - 2] = 0; /* skip "py" */
dir = g_path_get_dirname (path);
py3dir = g_build_filename (dir, "__pycache__", NULL);
if (glnx_dirfd_iterator_init_at (AT_FDCWD, py3dir, FALSE, &dfd_iter, NULL))
{
struct dirent *dent;
while (glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, NULL, NULL) &&
dent != NULL)
{
if (!(g_str_has_suffix (dent->d_name, ".pyc") ||
g_str_has_suffix (dent->d_name, ".pyo")))
continue;
if (!g_str_has_prefix (dent->d_name, pyfilename))
continue;
if (fstatat (dfd_iter.fd, dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW) == 0 &&
stbuf.st_mtime == OSTREE_TIMESTAMP)
{
g_print ("Removing stale file %s/__pycache__/%s", rel_path, dent->d_name);
if (unlinkat (dfd_iter.fd, dent->d_name, 0))
g_warning ("Unable to delete %s", dent->d_name);
}
}
}
return TRUE;
}
static gboolean
fixup_python_time_stamp (const char *path,
const char *rel_path,
GError **error)
{
glnx_fd_close int fd = -1;
g_auto(GLnxTmpfile) tmpf = { 0 };
guint8 buffer[8];
ssize_t res;
guint32 pyc_mtime;
g_autofree char *py_path = NULL;
struct stat stbuf;
gboolean remove_pyc = FALSE;
g_autofree char *path_basename = g_path_get_basename (path);
g_autofree char *dir = g_path_get_dirname (path);
g_autofree char *dir_basename = g_path_get_basename (dir);
fd = open (path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
if (fd == -1)
{
g_warning ("Can't open %s", rel_path);
return TRUE;
}
res = pread (fd, buffer, 8, 0);
if (res != 8)
{
g_warning ("Short read for %s", rel_path);
return TRUE;
}
if (buffer[2] != 0x0d || buffer[3] != 0x0a)
{
g_debug ("Not matching python magic: %s", rel_path);
return TRUE;
}
pyc_mtime =
(buffer[4] << 8*0) |
(buffer[5] << 8*1) |
(buffer[6] << 8*2) |
(buffer[7] << 8*3);
if (strcmp (dir_basename, "__pycache__") == 0)
{
/* Python3 */
g_autofree char *base = g_strdup (path_basename);
g_autofree char *real_dir = g_path_get_dirname (dir);
g_autofree char *py_basename = NULL;
char *dot;
dot = strrchr (base, '.');
if (dot == NULL)
return TRUE;
*dot = 0;
dot = strrchr (base, '.');
if (dot == NULL)
return TRUE;
*dot = 0;
py_basename = g_strconcat (base, ".py", NULL);
py_path = g_build_filename (real_dir, py_basename, NULL);
}
else
{
/* Python2 */
py_path = g_strndup (path, strlen (path) - 1);
}
/* Here we found a .pyc (or .pyo) file and a possible .py file that apply for it.
* There are several possible cases wrt their mtimes:
*
* py not existing: pyc is stale, remove it
* pyc mtime == 0: (.pyc is from an old commited module)
* py mtime == 0: Do nothing, already correct
* py mtime != 0: The py changed in this module, remove pyc
* pyc mtime != 0: (.pyc changed this module, or was never rewritten in base layer)
* py mtime == 0: Shouldn't happen in flatpak-builder, but could be an un-rewritten ctime lower layer, assume it matches and update timestamp
* py mtime != pyc mtime: new pyc doesn't match last py written in this module, remove it
* py mtime == pyc mtime: These match, but the py will be set to mtime 0 by ostree, so update timestamp in pyc.
*/
if (lstat (py_path, &stbuf) != 0)
{
/* pyc file without .py file, this happens for binary-only deployments.
* Accept it as-is. */
return TRUE;
}
else if (pyc_mtime == OSTREE_TIMESTAMP)
{
if (stbuf.st_mtime == OSTREE_TIMESTAMP)
return TRUE; /* Previously handled pyc */
remove_pyc = TRUE;
}
else /* pyc_mtime != 0 */
{
if (pyc_mtime != stbuf.st_mtime && stbuf.st_mtime != OSTREE_TIMESTAMP)
remove_pyc = TRUE;
/* else change mtime */
}
if (remove_pyc)
{
g_print ("Removing stale python bytecode file %s\n", rel_path);
if (unlink (path) != 0)
g_warning ("Unable to delete %s", rel_path);
return TRUE;
}
if (!glnx_open_tmpfile_linkable_at (AT_FDCWD, dir,
O_RDWR | O_CLOEXEC | O_NOFOLLOW,
&tmpf,
error))
return FALSE;
if (glnx_regfile_copy_bytes (fd, tmpf.fd, (off_t)-1) < 0)
return glnx_throw_errno_prefix (error, "copyfile");
/* Change to mtime 0 which is what ostree uses for checkouts */
buffer[4] = OSTREE_TIMESTAMP;
buffer[5] = buffer[6] = buffer[7] = 0;
res = pwrite (tmpf.fd, buffer, 8, 0);
if (res != 8)
{
glnx_set_error_from_errno (error);
return FALSE;
}
if (!glnx_link_tmpfile_at (&tmpf,
GLNX_LINK_TMPFILE_REPLACE,
AT_FDCWD,
path,
error))
return FALSE;
g_print ("Fixed up header mtime for %s\n", rel_path);
/* The mtime will be zeroed on cache commit. We don't want to do that now, because multiple
files could reference one .py file and we need the mtimes to match for them all */
return TRUE;
}
static gboolean
builder_post_process_python_time_stamp (GFile *app_dir,
GPtrArray *changed,
GError **error)
{
int i;
for (i = 0; i < changed->len; i++)
{
const char *rel_path = (char *) g_ptr_array_index (changed, i);
g_autoptr(GFile) file = NULL;
g_autofree char *path = NULL;
struct stat stbuf;
if (!(g_str_has_suffix (rel_path, ".py") ||
g_str_has_suffix (rel_path, ".pyc") ||
g_str_has_suffix (rel_path, ".pyo")))
continue;
file = g_file_resolve_relative_path (app_dir, rel_path);
path = g_file_get_path (file);
if (lstat (path, &stbuf) == -1)
continue;
if (!S_ISREG (stbuf.st_mode))
continue;
if (g_str_has_suffix (rel_path, ".py"))
{
if (!invalidate_old_python_compiled (path, rel_path, error))
return FALSE;
}
else
{
if (!fixup_python_time_stamp (path, rel_path, error))
return FALSE;
}
}
return TRUE;
}
static gboolean
builder_post_process_strip (GFile *app_dir,
GPtrArray *changed,
GError **error)
{
int i;
for (i = 0; i < changed->len; i++)
{
const char *rel_path = (char *) g_ptr_array_index (changed, i);
g_autoptr(GFile) file = g_file_resolve_relative_path (app_dir, rel_path);
g_autofree char *path = g_file_get_path (file);
gboolean is_shared, is_stripped;
if (!is_elf_file (path, &is_shared, &is_stripped))
continue;
if (is_stripped)
continue;
g_print ("stripping: %s\n", rel_path);
if (is_shared)
{
if (!strip (error, "--remove-section=.comment", "--remove-section=.note", "--strip-unneeded", path, NULL))
return FALSE;
}
else
{
if (!strip (error, "--remove-section=.comment", "--remove-section=.note", path, NULL))
return FALSE;
}
}
return TRUE;
}
static gboolean
builder_post_process_debuginfo (GFile *app_dir,
GPtrArray *changed,
BuilderContext *context,
GError **error)
{
g_autofree char *app_dir_path = g_file_get_path (app_dir);
int j;
for (j = 0; j < changed->len; j++)
{
const char *rel_path = (char *) g_ptr_array_index (changed, j);
g_autoptr(GFile) file = g_file_resolve_relative_path (app_dir, rel_path);
g_autofree char *path = g_file_get_path (file);
g_autofree char *debug_path = NULL;
g_autofree char *real_debug_path = NULL;
g_autofree char *rel_path_dir = g_path_get_dirname (rel_path);
g_autofree char *filename = g_path_get_basename (rel_path);
g_autofree char *filename_debug = g_strconcat (filename, ".debug", NULL);
g_autofree char *debug_dir = NULL;
g_autofree char *source_dir_path = NULL;
g_autoptr(GFile) source_dir = NULL;
g_autofree char *real_debug_dir = NULL;
gboolean is_shared, is_stripped;
if (!is_elf_file (path, &is_shared, &is_stripped))
continue;
if (is_stripped)
continue;
if (g_str_has_prefix (rel_path_dir, "files/"))
{
debug_dir = g_build_filename (app_dir_path, "files/lib/debug", rel_path_dir + strlen ("files/"), NULL);
real_debug_dir = g_build_filename ("/app/lib/debug", rel_path_dir + strlen ("files/"), NULL);
source_dir_path = g_build_filename (app_dir_path, "files/lib/debug/source", NULL);
}
else if (g_str_has_prefix (rel_path_dir, "usr/"))
{
debug_dir = g_build_filename (app_dir_path, "usr/lib/debug", rel_path_dir, NULL);
real_debug_dir = g_build_filename ("/usr/lib/debug", rel_path_dir, NULL);
source_dir_path = g_build_filename (app_dir_path, "usr/lib/debug/source", NULL);
}
if (debug_dir)
{
const char *builddir;
g_autoptr(GError) local_error = NULL;
g_auto(GStrv) file_refs = NULL;
if (g_mkdir_with_parents (debug_dir, 0755) != 0)
{
glnx_set_error_from_errno (error);
return FALSE;
}
source_dir = g_file_new_for_path (source_dir_path);
if (g_mkdir_with_parents (source_dir_path, 0755) != 0)
{
glnx_set_error_from_errno (error);
return FALSE;
}
if (builder_context_get_build_runtime (context))
builddir = "/run/build-runtime/";
else
builddir = "/run/build/";
debug_path = g_build_filename (debug_dir, filename_debug, NULL);
real_debug_path = g_build_filename (real_debug_dir, filename_debug, NULL);
file_refs = builder_get_debuginfo_file_references (path, &local_error);
if (file_refs == NULL)
{
g_warning ("%s", local_error->message);
}
else
{
GFile *build_dir = builder_context_get_build_dir (context);
int i;
for (i = 0; file_refs[i] != NULL; i++)
{
if (g_str_has_prefix (file_refs[i], builddir))
{
const char *relative_path = file_refs[i] + strlen (builddir);
g_autoptr(GFile) src = g_file_resolve_relative_path (build_dir, relative_path);
g_autoptr(GFile) dst = g_file_resolve_relative_path (source_dir, relative_path);
g_autoptr(GFile) dst_parent = g_file_get_parent (dst);
GFileType file_type;
if (!flatpak_mkdir_p (dst_parent, NULL, error))
return FALSE;
file_type = g_file_query_file_type (src, 0, NULL);
if (file_type == G_FILE_TYPE_DIRECTORY)
{
if (!flatpak_mkdir_p (dst, NULL, error))
return FALSE;
}
else if (file_type == G_FILE_TYPE_REGULAR)
{
/* Make sure the target is gone, because g_file_copy does
truncation on hardlinked destinations */
(void)g_file_delete (dst, NULL, NULL);
if (!g_file_copy (src, dst,
G_FILE_COPY_OVERWRITE,
NULL, NULL, NULL, error))
return FALSE;
}
}
}
}
g_print ("stripping %s to %s\n", path, debug_path);
/* Some files are hardlinked and eu-strip modifies in-place,
which breaks rofiles-fuse. Unlink them */
if (!flatpak_break_hardlink (file, error))
return FALSE;
if (!eu_strip (error, "--remove-comment", "--reloc-debug-sections",
"-f", debug_path,
"-F", real_debug_path,
path, NULL))
return FALSE;
}
}
return TRUE;
}
gboolean
builder_post_process (BuilderPostProcessFlags flags,
GFile *app_dir,
BuilderCache *cache,
BuilderContext *context,
GError **error)
{
g_autoptr(GPtrArray) changed = NULL;
if (!builder_cache_get_outstanding_changes (cache, &changed, error))
return FALSE;
if (flags & BUILDER_POST_PROCESS_FLAGS_PYTHON_TIMESTAMPS)
{
if (!builder_post_process_python_time_stamp (app_dir, changed,error))
return FALSE;
}
if (flags & BUILDER_POST_PROCESS_FLAGS_STRIP)
{
if (!builder_post_process_strip (app_dir, changed, error))
return FALSE;
}
else if (flags & BUILDER_POST_PROCESS_FLAGS_DEBUGINFO)
{
if (!builder_post_process_debuginfo (app_dir, changed, context, error))
return FALSE;
}
return TRUE;
}

View File

@@ -1,44 +0,0 @@
/*
* Copyright © 2017 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.1 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_POST_PROCESS_H__
#define __BUILDER_POST_PROCESS_H__
#include "builder-cache.h"
#include "builder-context.h"
G_BEGIN_DECLS
typedef enum {
BUILDER_POST_PROCESS_FLAGS_NONE = 0,
BUILDER_POST_PROCESS_FLAGS_PYTHON_TIMESTAMPS = 1<<0,
BUILDER_POST_PROCESS_FLAGS_STRIP = 1<<1,
BUILDER_POST_PROCESS_FLAGS_DEBUGINFO = 1<<2,
} BuilderPostProcessFlags;
gboolean builder_post_process (BuilderPostProcessFlags flags,
GFile *app_dir,
BuilderCache *cache,
BuilderContext *context,
GError **error);
G_END_DECLS
#endif /* __BUILDER_POST_PROCESS_H__ */

View File

@@ -1,701 +0,0 @@
/* 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 2 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 Lesser 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 "flatpak-utils.h"
#include "builder-utils.h"
#include "builder-source-archive.h"
struct BuilderSourceArchive
{
BuilderSource parent;
char *path;
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_PATH,
PROP_URL,
PROP_SHA256,
PROP_STRIP_COMPONENTS,
LAST_PROP
};
typedef enum {
UNKNOWN,
RPM,
TAR,
TAR_GZIP,
TAR_COMPRESS,
TAR_BZIP2,
TAR_LZIP,
TAR_LZMA,
TAR_LZOP,
TAR_XZ,
ZIP
} BuilderArchiveType;
static gboolean
is_tar (BuilderArchiveType type)
{
return (type >= TAR) && (type <= TAR_XZ);
}
static 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->path);
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_PATH:
g_value_set_string (value, self->path);
break;
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_PATH:
g_free (self->path);
self->path = g_value_dup_string (value);
break;
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,
gboolean *is_local,
GError **error)
{
g_autoptr(SoupURI) uri = NULL;
const char *path;
g_autofree char *base_name = 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;
}
file = builder_context_find_in_sources_dirs (context,
"downloads",
self->sha256,
base_name,
NULL);
if (file)
{
*is_local = TRUE;
return g_steal_pointer (&file);
}
return flatpak_build_file (builder_context_get_download_dir (context),
self->sha256,
base_name,
NULL);
}
static GFile *
get_source_file (BuilderSourceArchive *self,
BuilderContext *context,
gboolean *is_local,
GError **error)
{
GFile *base_dir = BUILDER_SOURCE (self)->base_dir;
if (self->url != NULL && self->url[0] != 0)
{
*is_local = FALSE;
return get_download_location (self, context, is_local, error);
}
if (self->path != NULL && self->path[0] != 0)
{
*is_local = TRUE;
return g_file_resolve_relative_path (base_dir, self->path);
}
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "source file path or url not specified");
return NULL;
}
static gboolean
builder_source_archive_show_deps (BuilderSource *source,
GError **error)
{
BuilderSourceArchive *self = BUILDER_SOURCE_ARCHIVE (source);
if (self->path && self->path[0] != 0)
g_print ("%s\n", self->path);
return TRUE;
}
static gboolean
builder_source_archive_download (BuilderSource *source,
gboolean update_vcs,
BuilderContext *context,
GError **error)
{
BuilderSourceArchive *self = BUILDER_SOURCE_ARCHIVE (source);
g_autoptr(GFile) file = NULL;
const char *sha256 = NULL;
g_autofree char *base_name = NULL;
gboolean is_local;
file = get_source_file (self, context, &is_local, error);
if (file == NULL)
return FALSE;
base_name = g_file_get_basename (file);
if (g_file_query_exists (file, NULL))
{
if (is_local && self->sha256 != NULL && *self->sha256 != 0)
{
g_autofree char *data = NULL;
gsize len;
if (!g_file_load_contents (file, NULL, &data, &len, NULL, error))
return FALSE;
sha256 = g_compute_checksum_for_string (G_CHECKSUM_SHA256, data, len);
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;
}
}
return TRUE;
}
if (is_local)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Can't find file at %s", self->path);
return FALSE;
}
if (!builder_context_download_uri (context,
self->url,
file,
self->sha256,
error))
return FALSE;
return TRUE;
}
static gboolean
tar (GFile *dir,
GError **error,
...)
{
gboolean res;
va_list ap;
va_start (ap, error);
res = flatpak_spawn (dir, NULL, error, "tar", ap);
va_end (ap);
return res;
}
static gboolean
unzip (GFile *dir,
GError **error,
...)
{
gboolean res;
va_list ap;
va_start (ap, error);
res = flatpak_spawn (dir, NULL, error, "unzip", ap);
va_end (ap);
return res;
}
static gboolean
unrpm (GFile *dir,
const char *rpm_path,
GError **error)
{
gboolean res;
const gchar *argv[] = { "sh", "-c", "rpm2cpio \"$1\" | cpio -i -d",
"sh", /* shell's $0 */
rpm_path, /* shell's $1 */
NULL };
res = flatpak_spawnv (dir, NULL, 0, error, argv);
return res;
}
static 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;
if (g_str_has_suffix (lower, ".rpm"))
return RPM;
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;
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 GFile *
create_uncompress_directory (BuilderSourceArchive *self, GFile *dest, GError **error)
{
GFile *uncompress_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 NULL;
}
uncompress_dest = g_file_new_for_path (tmp_dir_path);
}
else
{
uncompress_dest = g_object_ref (dest);
}
return uncompress_dest;
}
static gboolean
builder_source_archive_extract (BuilderSource *source,
GFile *dest,
BuilderOptions *build_options,
BuilderContext *context,
GError **error)
{
BuilderSourceArchive *self = BUILDER_SOURCE_ARCHIVE (source);
g_autoptr(GFile) archivefile = NULL;
g_autofree char *archive_path = NULL;
BuilderArchiveType type;
gboolean is_local;
archivefile = get_source_file (self, context, &is_local, 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, "--no-same-owner", strip_components, tar_decompress_flag (type), NULL))
return FALSE;
}
else if (type == ZIP)
{
g_autoptr(GFile) zip_dest = NULL;
zip_dest = create_uncompress_directory (self, dest, error);
if (zip_dest == NULL)
return FALSE;
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 if (type == RPM)
{
g_autoptr(GFile) rpm_dest = NULL;
rpm_dest = create_uncompress_directory (self, dest, error);
if (rpm_dest == NULL)
return FALSE;
if (!unrpm (rpm_dest, archive_path, error))
return FALSE;
if (self->strip_components > 0)
{
if (!strip_components_into (dest, rpm_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 gboolean
builder_source_archive_bundle (BuilderSource *source,
BuilderContext *context,
GError **error)
{
BuilderSourceArchive *self = BUILDER_SOURCE_ARCHIVE (source);
g_autoptr(GFile) file = NULL;
g_autoptr(GFile) download_dir = NULL;
g_autoptr(GFile) destination_file = NULL;
g_autofree char *download_dir_path = NULL;
g_autofree char *file_name = NULL;
g_autofree char *destination_file_path = NULL;
g_autofree char *app_dir_path = NULL;
gboolean is_local;
file = get_source_file (self, context, &is_local, error);
if (file == NULL)
return FALSE;
app_dir_path = g_file_get_path (builder_context_get_app_dir (context));
download_dir_path = g_build_filename (app_dir_path,
"sources",
"downloads",
self->sha256,
NULL);
download_dir = g_file_new_for_path (download_dir_path);
if (!flatpak_mkdir_p (download_dir, NULL, error))
return FALSE;
file_name = g_file_get_basename (file);
destination_file_path = g_build_filename (download_dir_path,
file_name,
NULL);
destination_file = g_file_new_for_path (destination_file_path);
if (!g_file_copy (file, destination_file,
G_FILE_COPY_OVERWRITE,
NULL,
NULL, NULL,
error))
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->show_deps = builder_source_archive_show_deps;
source_class->download = builder_source_archive_download;
source_class->extract = builder_source_archive_extract;
source_class->bundle = builder_source_archive_bundle;
source_class->checksum = builder_source_archive_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_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;
}

View File

@@ -1,40 +0,0 @@
/*
* 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.1 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__ */

View File

@@ -1,399 +0,0 @@
/* 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 2 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 Lesser 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"
#include "flatpak-utils.h"
struct BuilderSourceBzr
{
BuilderSource parent;
char *url;
char *revision;
};
typedef struct
{
BuilderSourceClass parent_class;
} BuilderSourceBzrClass;
G_DEFINE_TYPE (BuilderSourceBzr, builder_source_bzr, BUILDER_TYPE_SOURCE);
enum {
PROP_0,
PROP_URL,
PROP_REVISION,
LAST_PROP
};
static void
builder_source_bzr_finalize (GObject *object)
{
BuilderSourceBzr *self = (BuilderSourceBzr *) object;
g_free (self->url);
g_free (self->revision);
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;
case PROP_REVISION:
g_value_set_string (value, self->revision);
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;
case PROP_REVISION:
g_free (self->revision);
self->revision = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static gboolean
bzr (GFile *dir,
char **output,
GError **error,
...)
{
gboolean res;
va_list ap;
va_start (ap, error);
res = flatpak_spawn (dir, output, error, "bzr", ap);
va_end (ap);
return res;
}
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,
gboolean update_vcs,
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 FALSE;
}
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 *mirror_path = g_file_get_path (mirror_dir);
g_autofree char *path_tmp = g_strconcat (mirror_path, ".clone_XXXXXX", NULL);
g_autofree char *filename_tmp = NULL;
g_autoptr(GFile) mirror_dir_tmp = NULL;
g_autoptr(GFile) cached_bzr_dir = NULL;
const char *branch_source;
g_print ("Getting bzr repo %s\n", self->url);
if (g_mkdtemp_full (path_tmp, 0755) == NULL)
return flatpak_fail (error, "Can't create temporary directory");
/* bzr can't check out to the empty dir, so remove it */
rmdir (path_tmp);
mirror_dir_tmp = g_file_new_for_path (path_tmp);
filename_tmp = g_file_get_basename (mirror_dir_tmp);
branch_source = self->url;
cached_bzr_dir = builder_context_find_in_sources_dirs (context, "bzr", filename, NULL);
if (cached_bzr_dir != NULL)
branch_source = flatpak_file_get_path_cached (cached_bzr_dir);
if (!bzr (parent, NULL, error,
"branch", branch_source, filename_tmp, NULL))
return FALSE;
/* Rewrite to real url if we used the cache */
if (cached_bzr_dir != NULL)
{
g_autofree char *setting = g_strdup_printf ("parent_location=%s", self->url);
if (!bzr (mirror_dir_tmp, NULL, error,
"config", setting, NULL))
return FALSE;
if (update_vcs &&
!bzr (mirror_dir_tmp, NULL, error,
"pull", NULL))
return FALSE;
}
if (!g_file_move (mirror_dir_tmp, mirror_dir, 0, NULL, NULL, NULL, error))
return FALSE;
}
else if (update_vcs)
{
g_print ("Updating bzr repo %s\n", self->url);
if (!bzr (mirror_dir, NULL, error,
"pull", NULL))
return FALSE;
}
return TRUE;
}
static gboolean
builder_source_bzr_extract (BuilderSource *source,
GFile *dest,
BuilderOptions *build_options,
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;
if (self->revision)
{
g_autofree char *revarg = g_strdup_printf ("-r%s", self->revision);
if (!bzr (dest, NULL, error,
"revert", revarg, NULL))
return FALSE;
}
return TRUE;
}
static gboolean
builder_source_bzr_bundle (BuilderSource *source,
BuilderContext *context,
GError **error)
{
BuilderSourceBzr *self = BUILDER_SOURCE_BZR (source);
g_autoptr(GFile) sources_dir = NULL;
g_autoptr(GFile) dest_dir = NULL;
g_autoptr(GFile) dest_dir_tmp = NULL;
g_autoptr(GFile) bzr_sources_dir = NULL;
g_autofree char *sources_dir_path = NULL;
g_autofree char *base_name = NULL;
g_autofree char *base_name_tmp = NULL;
sources_dir = get_mirror_dir (self, context);
if (sources_dir == NULL) {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Can't locate repo with URL '%s'", self->url);
return FALSE;
}
base_name = g_file_get_basename (sources_dir);
bzr_sources_dir = flatpak_build_file (builder_context_get_app_dir (context),
"sources/bzr",
NULL);
if (!flatpak_mkdir_p (bzr_sources_dir, NULL, error))
return FALSE;
base_name_tmp = g_strconcat (base_name, ".clone_tmp", NULL);
dest_dir_tmp = flatpak_build_file (bzr_sources_dir,
base_name_tmp,
NULL);
dest_dir = flatpak_build_file (bzr_sources_dir,
base_name,
NULL);
sources_dir_path = g_file_get_path (sources_dir);
if (!bzr (bzr_sources_dir, NULL, error,
"branch", sources_dir_path, base_name_tmp, NULL) ||
!g_file_move (dest_dir_tmp, dest_dir, 0, NULL, NULL, NULL, error))
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 = NULL;
g_autoptr(GError) error = NULL;
builder_cache_checksum_str (cache, self->url);
builder_cache_checksum_str (cache, self->revision);
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 gboolean
builder_source_bzr_update (BuilderSource *source,
BuilderContext *context,
GError **error)
{
BuilderSourceBzr *self = BUILDER_SOURCE_BZR (source);
char *current_commit;
current_commit = get_current_commit (self, context, NULL);
if (current_commit)
{
g_free (self->revision);
self->revision = current_commit;
}
return TRUE;
}
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->bundle = builder_source_bzr_bundle;
source_class->update = builder_source_bzr_update;
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));
g_object_class_install_property (object_class,
PROP_REVISION,
g_param_spec_string ("revision",
"",
"",
NULL,
G_PARAM_READWRITE));
}
static void
builder_source_bzr_init (BuilderSourceBzr *self)
{
}

View File

@@ -1,40 +0,0 @@
/*
* 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.1 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__ */

View File

@@ -1,556 +0,0 @@
/* 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 2 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 Lesser 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 "flatpak-utils.h"
#include "builder-utils.h"
#include "builder-source-file.h"
struct BuilderSourceFile
{
BuilderSource parent;
char *path;
char *url;
char *sha256;
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_URL,
PROP_SHA256,
PROP_DEST_FILENAME,
LAST_PROP
};
static void
builder_source_file_finalize (GObject *object)
{
BuilderSourceFile *self = (BuilderSourceFile *) object;
g_free (self->path);
g_free (self->url);
g_free (self->sha256);
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_URL:
g_value_set_string (value, self->url);
break;
case PROP_SHA256:
g_value_set_string (value, self->sha256);
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_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_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 SoupURI *
get_uri (BuilderSourceFile *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 (BuilderSourceFile *self,
gboolean *is_inline,
BuilderContext *context,
GError **error)
{
g_autoptr(SoupURI) uri = NULL;
const char *path;
g_autofree char *base_name = NULL;
g_autoptr(GFile) file = NULL;
uri = get_uri (self, error);
if (uri == NULL)
return FALSE;
path = soup_uri_get_path (uri);
if (g_str_has_prefix (self->url, "data:"))
{
*is_inline = TRUE;
return g_file_new_for_path ("inline data");
}
*is_inline = FALSE;
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;
}
file = builder_context_find_in_sources_dirs (context,
"downloads",
self->sha256,
base_name,
NULL);
if (file != NULL)
return g_steal_pointer (&file);
file = flatpak_build_file (builder_context_get_download_dir (context),
self->sha256,
base_name,
NULL);
return g_steal_pointer (&file);
}
static GFile *
get_source_file (BuilderSourceFile *self,
BuilderContext *context,
gboolean *is_local,
gboolean *is_inline,
GError **error)
{
GFile *base_dir = BUILDER_SOURCE (self)->base_dir;
if (self->url != NULL && self->url[0] != 0)
{
*is_local = FALSE;
return get_download_location (self, is_inline, context, error);
}
if (self->path != NULL && self->path[0] != 0)
{
*is_local = TRUE;
*is_inline = FALSE;
return g_file_resolve_relative_path (base_dir, self->path);
}
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "source file path or url not specified");
return NULL;
}
static GBytes *
download_uri (const char *url,
BuilderContext *context,
GError **error)
{
SoupSession *session;
g_autoptr(SoupRequest) req = NULL;
g_autoptr(GInputStream) input = NULL;
g_autoptr(GOutputStream) out = NULL;
session = builder_context_get_soup_session (context);
req = soup_session_request (session, url, error);
if (req == NULL)
return NULL;
input = soup_request_send (req, NULL, error);
if (input == NULL)
return NULL;
out = g_memory_output_stream_new_resizable ();
if (!g_output_stream_splice (out,
input,
G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET | G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
NULL,
error))
return NULL;
return g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (out));
}
static gboolean
builder_source_file_show_deps (BuilderSource *source,
GError **error)
{
BuilderSourceFile *self = BUILDER_SOURCE_FILE (source);
if (self->path && self->path[0] != 0)
g_print ("%s\n", self->path);
return TRUE;
}
static gboolean
builder_source_file_download (BuilderSource *source,
gboolean update_vcs,
BuilderContext *context,
GError **error)
{
BuilderSourceFile *self = BUILDER_SOURCE_FILE (source);
g_autoptr(GFile) file = NULL;
gboolean is_local, is_inline;
g_autofree char *sha256 = NULL;
g_autofree char *base_name = NULL;
file = get_source_file (self, context, &is_local, &is_inline, error);
if (file == NULL)
return FALSE;
base_name = g_file_get_basename (file);
if (g_file_query_exists (file, NULL))
{
if (is_local && self->sha256 != NULL && *self->sha256 != 0)
{
g_autofree char *data = NULL;
gsize len;
if (!g_file_load_contents (file, NULL, &data, &len, NULL, error))
return FALSE;
sha256 = g_compute_checksum_for_string (G_CHECKSUM_SHA256, data, len);
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;
}
}
return TRUE;
}
if (is_local)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Can't find file at %s", self->path);
return FALSE;
}
if ((self->sha256 == NULL || *self->sha256 == 0) && !is_inline)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Sha256 not specified");
return FALSE;
}
if (!builder_context_download_uri (context,
self->url,
file,
self->sha256,
error))
return FALSE;
return TRUE;
}
static gboolean
builder_source_file_extract (BuilderSource *source,
GFile *dest,
BuilderOptions *build_options,
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;
gboolean is_local, is_inline;
src = get_source_file (self, context, &is_local, &is_inline, error);
if (src == NULL)
return FALSE;
if (self->dest_filename)
{
dest_filename = g_strdup (self->dest_filename);
}
else
{
if (is_inline)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"No dest-filename set for inline file data");
return FALSE;
}
dest_filename = g_file_get_basename (src);
}
dest_file = g_file_get_child (dest, dest_filename);
/* If the destination file exists, just delete it. We can encounter errors when
* trying to overwrite files that are not writable.
*/
if (g_file_query_exists (dest_file, NULL) && !g_file_delete (dest_file, NULL, error))
return FALSE;
if (is_inline)
{
g_autoptr(GBytes) content = NULL;
content = download_uri (self->url,
context,
error);
if (content == NULL)
return FALSE;
if (!g_file_set_contents (flatpak_file_get_path_cached (dest_file),
g_bytes_get_data (content, NULL),
g_bytes_get_size (content), error))
return FALSE;
}
else
{
/* Make sure the target is gone, because g_file_copy does
truncation on hardlinked destinations */
(void)g_file_delete (dest_file, NULL, NULL);
if (!g_file_copy (src, dest_file,
G_FILE_COPY_OVERWRITE,
NULL,
NULL, NULL,
error))
return FALSE;
}
return TRUE;
}
static gboolean
builder_source_file_bundle (BuilderSource *source,
BuilderContext *context,
GError **error)
{
BuilderSourceFile *self = BUILDER_SOURCE_FILE (source);
g_autoptr(GFile) file = NULL;
g_autoptr(GFile) destination_file = NULL;
g_autoptr(GFile) destination_dir = NULL;
g_autofree char *file_name = NULL;
gboolean is_local, is_inline;
file = get_source_file (self, context, &is_local, &is_inline, error);
if (file == NULL)
return FALSE;
/* Inline URIs (data://) need not be bundled */
if (is_inline)
return TRUE;
if (is_local)
{
GFile *manifest_base_dir = builder_context_get_base_dir (context);
g_autofree char *rel_path = g_file_get_relative_path (manifest_base_dir, file);
if (rel_path == NULL)
{
g_warning ("Local file %s is outside manifest tree, not bundling", flatpak_file_get_path_cached (file));
return TRUE;
}
destination_file = flatpak_build_file (builder_context_get_app_dir (context),
"sources/manifest", rel_path, NULL);
}
else
{
file_name = g_file_get_basename (file);
destination_file = flatpak_build_file (builder_context_get_app_dir (context),
"sources/downloads",
self->sha256,
file_name,
NULL);
}
destination_dir = g_file_get_parent (destination_file);
if (!flatpak_mkdir_p (destination_dir, NULL, error))
return FALSE;
if (!g_file_copy (file, destination_file,
G_FILE_COPY_OVERWRITE,
NULL,
NULL, NULL,
error))
return FALSE;
return TRUE;
}
static gboolean
builder_source_file_update (BuilderSource *source,
BuilderContext *context,
GError **error)
{
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;
gboolean is_local, is_inline;
src = get_source_file (self, context, &is_local, &is_inline, NULL);
if (src == NULL)
return;
if (is_local &&
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->url);
builder_cache_checksum_str (cache, self->sha256);
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->show_deps = builder_source_file_show_deps;
source_class->download = builder_source_file_download;
source_class->extract = builder_source_file_extract;
source_class->bundle = builder_source_file_bundle;
source_class->update = builder_source_file_update;
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_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_DEST_FILENAME,
g_param_spec_string ("dest-filename",
"",
"",
NULL,
G_PARAM_READWRITE));
}
static void
builder_source_file_init (BuilderSourceFile *self)
{
}

View File

@@ -1,40 +0,0 @@
/*
* 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.1 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__ */

View File

@@ -1,395 +0,0 @@
/* 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 2 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 Lesser 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-git.h"
#include "builder-utils.h"
#include "flatpak-utils.h"
struct BuilderSourceGit
{
BuilderSource parent;
char *url;
char *path;
char *branch;
char *commit;
gboolean disable_fsckobjects;
};
typedef struct
{
BuilderSourceClass parent_class;
} BuilderSourceGitClass;
G_DEFINE_TYPE (BuilderSourceGit, builder_source_git, BUILDER_TYPE_SOURCE);
enum {
PROP_0,
PROP_URL,
PROP_PATH,
PROP_BRANCH,
PROP_COMMIT,
PROP_DISABLE_FSCKOBJECTS,
LAST_PROP
};
static void
builder_source_git_finalize (GObject *object)
{
BuilderSourceGit *self = (BuilderSourceGit *) object;
g_free (self->url);
g_free (self->path);
g_free (self->branch);
g_free (self->commit);
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_PATH:
g_value_set_string (value, self->path);
break;
case PROP_BRANCH:
g_value_set_string (value, self->branch);
break;
case PROP_COMMIT:
g_value_set_string (value, self->commit);
break;
case PROP_DISABLE_FSCKOBJECTS:
g_value_set_boolean (value, self->disable_fsckobjects);
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_PATH:
g_free (self->path);
self->path = g_value_dup_string (value);
break;
case PROP_BRANCH:
g_free (self->branch);
self->branch = g_value_dup_string (value);
break;
case PROP_COMMIT:
g_free (self->commit);
self->commit = g_value_dup_string (value);
break;
case PROP_DISABLE_FSCKOBJECTS:
self->disable_fsckobjects = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static const char *
get_branch (BuilderSourceGit *self)
{
if (self->branch)
return self->branch;
else if (self->commit)
return self->commit;
else
return "master";
}
static char *
get_url_or_path (BuilderSourceGit *self,
BuilderContext *context,
GError **error)
{
g_autoptr(GFile) repo = NULL;
GFile *base_dir = BUILDER_SOURCE (self)->base_dir;
if (self->url == NULL && self->path == NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "No URL or path specified");
return NULL;
}
if (self->url)
{
g_autofree char *scheme = NULL;
scheme = g_uri_parse_scheme (self->url);
if (scheme == NULL)
{
repo = g_file_resolve_relative_path (base_dir, self->url);
return g_file_get_uri (repo);
}
return g_strdup (self->url);
}
repo = g_file_resolve_relative_path (base_dir,
self->path);
return g_file_get_path (repo);
}
static gboolean
builder_source_git_download (BuilderSource *source,
gboolean update_vcs,
BuilderContext *context,
GError **error)
{
BuilderSourceGit *self = BUILDER_SOURCE_GIT (source);
g_autofree char *location = NULL;
location = get_url_or_path (self, context, error);
if (location == NULL)
return FALSE;
if (!builder_git_mirror_repo (location,
NULL,
update_vcs, TRUE, self->disable_fsckobjects,
get_branch (self),
context,
error))
return FALSE;
if (self->commit != NULL && self->branch != NULL)
{
/* We want to support the commit being both a tag object and the real commit object that it points too */
g_autofree char *current_commit = builder_git_get_current_commit (location,get_branch (self), FALSE, context, error);
g_autofree char *current_commit2 = builder_git_get_current_commit (location,get_branch (self), TRUE, context, error);
if (current_commit == NULL || current_commit2 == NULL)
return FALSE;
if (strcmp (current_commit, self->commit) != 0 && strcmp (current_commit2, self->commit) != 0)
return flatpak_fail (error, "Git commit for branch %s is %s, but expected %s\n", self->branch, current_commit2, self->commit);
}
return TRUE;
}
static gboolean
builder_source_git_extract (BuilderSource *source,
GFile *dest,
BuilderOptions *build_options,
BuilderContext *context,
GError **error)
{
BuilderSourceGit *self = BUILDER_SOURCE_GIT (source);
g_autofree char *location = NULL;
location = get_url_or_path (self, context, error);
if (location == NULL)
return FALSE;
if (!builder_git_checkout (location, get_branch (self),
dest, context, error))
return FALSE;
return TRUE;
}
static gboolean
builder_source_git_bundle (BuilderSource *source,
BuilderContext *context,
GError **error)
{
BuilderSourceGit *self = BUILDER_SOURCE_GIT (source);
g_autofree char *location = NULL;
g_autoptr(GFile) mirror_dir = NULL;
location = get_url_or_path (self, context, error);
g_print ("builder_source_git_bundle %s\n", location);
if (location == NULL)
return FALSE;
mirror_dir = flatpak_build_file (builder_context_get_app_dir (context),
"sources/git",
NULL);
if (!flatpak_mkdir_p (mirror_dir, NULL, error))
return FALSE;
if (!builder_git_mirror_repo (location,
flatpak_file_get_path_cached (mirror_dir),
FALSE, TRUE, FALSE,
get_branch (self),
context,
error))
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 = NULL;
g_autoptr(GError) error = NULL;
g_autofree char *location = NULL;
builder_cache_checksum_str (cache, self->url);
builder_cache_checksum_str (cache, self->path);
builder_cache_checksum_str (cache, self->branch);
builder_cache_checksum_compat_str (cache, self->commit);
builder_cache_checksum_compat_boolean (cache, self->disable_fsckobjects);
location = get_url_or_path (self, context, &error);
if (location != NULL)
{
current_commit = builder_git_get_current_commit (location,get_branch (self), FALSE, 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);
}
else
{
g_warning ("No url or path");
}
}
static gboolean
builder_source_git_update (BuilderSource *source,
BuilderContext *context,
GError **error)
{
BuilderSourceGit *self = BUILDER_SOURCE_GIT (source);
char *current_commit;
g_autofree char *location = NULL;
location = get_url_or_path (self, context, error);
if (location == NULL)
return FALSE;
current_commit = builder_git_get_current_commit (location, get_branch (self), FALSE, context, NULL);
if (current_commit)
{
g_free (self->branch);
self->branch = current_commit;
}
return TRUE;
}
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->bundle = builder_source_git_bundle;
source_class->update = builder_source_git_update;
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_PATH,
g_param_spec_string ("path",
"",
"",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_BRANCH,
g_param_spec_string ("branch",
"",
"",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_COMMIT,
g_param_spec_string ("commit",
"",
"",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_DISABLE_FSCKOBJECTS,
g_param_spec_boolean ("disable-fsckobjects",
"",
"",
FALSE,
G_PARAM_READWRITE));
}
static void
builder_source_git_init (BuilderSourceGit *self)
{
}

View File

@@ -1,40 +0,0 @@
/*
* 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.1 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__ */

View File

@@ -1,375 +0,0 @@
/* 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 2 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 Lesser 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 "flatpak-utils.h"
#include "builder-utils.h"
#include "builder-source-patch.h"
struct BuilderSourcePatch
{
BuilderSource parent;
char *path;
guint strip_components;
gboolean use_git;
char **options;
};
typedef struct
{
BuilderSourceClass parent_class;
} BuilderSourcePatchClass;
G_DEFINE_TYPE (BuilderSourcePatch, builder_source_patch, BUILDER_TYPE_SOURCE);
enum {
PROP_0,
PROP_PATH,
PROP_STRIP_COMPONENTS,
PROP_USE_GIT,
PROP_OPTIONS,
LAST_PROP
};
static void
builder_source_patch_finalize (GObject *object)
{
BuilderSourcePatch *self = (BuilderSourcePatch *) object;
g_free (self->path);
g_strfreev (self->options);
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;
case PROP_USE_GIT:
g_value_set_boolean (value, self->use_git);
break;
case PROP_OPTIONS:
g_value_set_boxed (value, self->options);
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);
gchar **tmp;
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;
case PROP_USE_GIT:
self->use_git = g_value_get_boolean (value);
break;
case PROP_OPTIONS:
tmp = self->options;
self->options = g_strdupv (g_value_get_boxed (value));
g_strfreev (tmp);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static GFile *
get_source_file (BuilderSourcePatch *self,
BuilderContext *context,
GError **error)
{
GFile *base_dir = BUILDER_SOURCE (self)->base_dir;
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_patch_show_deps (BuilderSource *source,
GError **error)
{
BuilderSourcePatch *self = BUILDER_SOURCE_PATCH (source);
if (self->path && self->path[0] != 0)
g_print ("%s\n", self->path);
return TRUE;
}
static gboolean
builder_source_patch_download (BuilderSource *source,
gboolean update_vcs,
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,
gboolean use_git,
const char *patch_path,
char **extra_options,
GError **error,
...)
{
gboolean res;
GPtrArray *args;
const gchar *arg;
va_list ap;
int i;
va_start(ap, error);
args = g_ptr_array_new ();
if (use_git) {
g_ptr_array_add (args, "git");
g_ptr_array_add (args, "apply");
g_ptr_array_add (args, "-v");
} else {
g_ptr_array_add (args, "patch");
}
for (i = 0; extra_options != NULL && extra_options[i] != NULL; i++)
g_ptr_array_add (args, (gchar *) extra_options[i]);
while ((arg = va_arg (ap, const gchar *)))
g_ptr_array_add (args, (gchar *) arg);
if (use_git) {
g_ptr_array_add (args, (char *) patch_path);
} else {
g_ptr_array_add (args, "-i");
g_ptr_array_add (args, (char *) patch_path);
}
g_ptr_array_add (args, NULL);
res = flatpak_spawnv (dir, NULL, 0, error, (const char **) args->pdata);
g_ptr_array_free (args, TRUE);
va_end (ap);
return res;
}
static gboolean
builder_source_patch_extract (BuilderSource *source,
GFile *dest,
BuilderOptions *build_options,
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;
g_print ("Applying patch %s\n", self->path);
strip_components = g_strdup_printf ("-p%u", self->strip_components);
patch_path = g_file_get_path (patchfile);
if (!patch (dest, self->use_git, patch_path, self->options, error, strip_components, NULL))
return FALSE;
return TRUE;
}
static gboolean
builder_source_patch_bundle (BuilderSource *source,
BuilderContext *context,
GError **error)
{
BuilderSourcePatch *self = BUILDER_SOURCE_PATCH (source);
GFile *manifest_base_dir = builder_context_get_base_dir (context);
g_autoptr(GFile) src = NULL;
g_autoptr(GFile) destination_file = NULL;
g_autofree char *rel_path = NULL;
g_autoptr(GFile) destination_dir = NULL;
src = get_source_file (self, context, error);
if (src == NULL)
return FALSE;
rel_path = g_file_get_relative_path (manifest_base_dir, src);
if (rel_path == NULL)
{
g_warning ("Patch %s is outside manifest tree, not bundling", flatpak_file_get_path_cached (src));
return TRUE;
}
destination_file = flatpak_build_file (builder_context_get_app_dir (context),
"sources/manifest", rel_path, NULL);
destination_dir = g_file_get_parent (destination_file);
if (!flatpak_mkdir_p (destination_dir, NULL, error))
return FALSE;
if (!g_file_copy (src, destination_file,
G_FILE_COPY_OVERWRITE,
NULL,
NULL, NULL,
error))
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);
builder_cache_checksum_strv (cache, self->options);
}
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->show_deps = builder_source_patch_show_deps;
source_class->download = builder_source_patch_download;
source_class->extract = builder_source_patch_extract;
source_class->bundle = builder_source_patch_bundle;
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));
g_object_class_install_property (object_class,
PROP_USE_GIT,
g_param_spec_boolean ("use-git",
"",
"",
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_OPTIONS,
g_param_spec_boxed ("options",
"",
"",
G_TYPE_STRV,
G_PARAM_READWRITE));
}
static void
builder_source_patch_init (BuilderSourcePatch *self)
{
self->strip_components = 1;
}

View File

@@ -1,40 +0,0 @@
/*
* 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.1 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__ */

View File

@@ -1,232 +0,0 @@
/* builder-source-script.c
*
* Copyright (C) 2015 Red Hat, Inc
*
* This script 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 script 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 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 "flatpak-utils.h"
#include "builder-utils.h"
#include "builder-source-script.h"
struct BuilderSourceScript
{
BuilderSource parent;
char **commands;
char *dest_filename;
};
typedef struct
{
BuilderSourceClass parent_class;
} BuilderSourceScriptClass;
G_DEFINE_TYPE (BuilderSourceScript, builder_source_script, BUILDER_TYPE_SOURCE);
enum {
PROP_0,
PROP_COMMANDS,
PROP_DEST_FILENAME,
LAST_PROP
};
static void
builder_source_script_finalize (GObject *object)
{
BuilderSourceScript *self = (BuilderSourceScript *) object;
g_strfreev (self->commands);
g_free (self->dest_filename);
G_OBJECT_CLASS (builder_source_script_parent_class)->finalize (object);
}
static void
builder_source_script_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
BuilderSourceScript *self = BUILDER_SOURCE_SCRIPT (object);
switch (prop_id)
{
case PROP_COMMANDS:
g_value_set_boxed (value, self->commands);
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_script_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
BuilderSourceScript *self = BUILDER_SOURCE_SCRIPT (object);
gchar **tmp;
switch (prop_id)
{
case PROP_COMMANDS:
tmp = self->commands;
self->commands = g_strdupv (g_value_get_boxed (value));
g_strfreev (tmp);
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 gboolean
builder_source_script_download (BuilderSource *source,
gboolean update_vcs,
BuilderContext *context,
GError **error)
{
return TRUE;
}
static gboolean
builder_source_script_extract (BuilderSource *source,
GFile *dest,
BuilderOptions *build_options,
BuilderContext *context,
GError **error)
{
BuilderSourceScript *self = BUILDER_SOURCE_SCRIPT (source);
g_autoptr(GFile) dest_script = NULL;
const char *dest_filename;
g_autoptr(GString) script = NULL;
int i;
guint32 perms;
script = g_string_new ("#!/bin/sh\n");
if (self->commands)
{
for (i = 0; self->commands[i] != NULL; i++)
{
g_string_append (script, self->commands[i]);
g_string_append_c (script, '\n');
}
}
if (self->dest_filename)
dest_filename = self->dest_filename;
else
dest_filename = "autogen.sh";
dest_script = g_file_get_child (dest, dest_filename);
if (!g_file_set_contents (flatpak_file_get_path_cached (dest_script),
script->str,
script->len,
error))
return FALSE;
perms = 0755;
if (!g_file_set_attribute (dest_script,
G_FILE_ATTRIBUTE_UNIX_MODE,
G_FILE_ATTRIBUTE_TYPE_UINT32,
&perms,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
NULL, error))
return FALSE;
return TRUE;
}
static gboolean
builder_source_script_bundle (BuilderSource *source,
BuilderContext *context,
GError **error)
{
/* no need to bundle anything here as this part
can be reconstructed from the manifest */
return TRUE;
}
static void
builder_source_script_checksum (BuilderSource *source,
BuilderCache *cache,
BuilderContext *context)
{
BuilderSourceScript *self = BUILDER_SOURCE_SCRIPT (source);
builder_cache_checksum_strv (cache, self->commands);
builder_cache_checksum_str (cache, self->dest_filename);
}
static void
builder_source_script_class_init (BuilderSourceScriptClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
BuilderSourceClass *source_class = BUILDER_SOURCE_CLASS (klass);
object_class->finalize = builder_source_script_finalize;
object_class->get_property = builder_source_script_get_property;
object_class->set_property = builder_source_script_set_property;
source_class->download = builder_source_script_download;
source_class->extract = builder_source_script_extract;
source_class->bundle = builder_source_script_bundle;
source_class->checksum = builder_source_script_checksum;
g_object_class_install_property (object_class,
PROP_COMMANDS,
g_param_spec_boxed ("commands",
"",
"",
G_TYPE_STRV,
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_script_init (BuilderSourceScript *self)
{
}

View File

@@ -1,40 +0,0 @@
/*
* 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.1 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_SCRIPT_H__
#define __BUILDER_SOURCE_SCRIPT_H__
#include "builder-source.h"
G_BEGIN_DECLS
typedef struct BuilderSourceScript BuilderSourceScript;
#define BUILDER_TYPE_SOURCE_SCRIPT (builder_source_script_get_type ())
#define BUILDER_SOURCE_SCRIPT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BUILDER_TYPE_SOURCE_SCRIPT, BuilderSourceScript))
#define BUILDER_IS_SOURCE_SCRIPT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BUILDER_TYPE_SOURCE_SCRIPT))
GType builder_source_script_get_type (void);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (BuilderSourceScript, g_object_unref)
G_END_DECLS
#endif /* __BUILDER_SOURCE_SCRIPT_H__ */

View File

@@ -1,228 +0,0 @@
/* builder-source-shell.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 2 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 Lesser 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 "flatpak-utils.h"
#include "builder-utils.h"
#include "builder-source-shell.h"
struct BuilderSourceShell
{
BuilderSource parent;
char **commands;
};
typedef struct
{
BuilderSourceClass parent_class;
} BuilderSourceShellClass;
G_DEFINE_TYPE (BuilderSourceShell, builder_source_shell, BUILDER_TYPE_SOURCE);
enum {
PROP_0,
PROP_COMMANDS,
LAST_PROP
};
static void
builder_source_shell_finalize (GObject *object)
{
BuilderSourceShell *self = (BuilderSourceShell *) object;
g_strfreev (self->commands);
G_OBJECT_CLASS (builder_source_shell_parent_class)->finalize (object);
}
static void
builder_source_shell_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
BuilderSourceShell *self = BUILDER_SOURCE_SHELL (object);
switch (prop_id)
{
case PROP_COMMANDS:
g_value_set_boxed (value, self->commands);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
builder_source_shell_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
BuilderSourceShell *self = BUILDER_SOURCE_SHELL (object);
gchar **tmp;
switch (prop_id)
{
case PROP_COMMANDS:
tmp = self->commands;
self->commands = g_strdupv (g_value_get_boxed (value));
g_strfreev (tmp);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static gboolean
builder_source_shell_download (BuilderSource *source,
gboolean update_vcs,
BuilderContext *context,
GError **error)
{
return TRUE;
}
static gboolean
run_script (BuilderContext *context,
BuilderOptions *build_options,
GFile *source_dir,
const gchar *script,
GError **error)
{
GFile *app_dir = builder_context_get_app_dir (context);
g_autoptr(GPtrArray) args = NULL;
g_autofree char *source_dir_path = g_file_get_path (source_dir);
g_autofree char *source_dir_path_canonical = NULL;
g_autoptr(GFile) source_dir_path_canonical_file = NULL;
g_auto(GStrv) build_args = NULL;
int i;
args = g_ptr_array_new_with_free_func (g_free);
g_ptr_array_add (args, g_strdup ("flatpak"));
g_ptr_array_add (args, g_strdup ("build"));
source_dir_path_canonical = realpath (source_dir_path, NULL);
g_ptr_array_add (args, g_strdup ("--nofilesystem=host"));
g_ptr_array_add (args, g_strdup_printf ("--filesystem=%s", source_dir_path_canonical));
build_args = builder_options_get_build_args (build_options, context, error);
if (build_args == NULL)
return FALSE;
for (i = 0; build_args[i] != NULL; i++)
g_ptr_array_add (args, g_strdup (build_args[i]));
g_ptr_array_add (args, g_file_get_path (app_dir));
g_ptr_array_add (args, g_strdup ("/bin/sh"));
g_ptr_array_add (args, g_strdup ("-c"));
g_ptr_array_add (args, g_strdup (script));
g_ptr_array_add (args, NULL);
source_dir_path_canonical_file = g_file_new_for_path (source_dir_path_canonical);
return builder_maybe_host_spawnv (source_dir_path_canonical_file, NULL, error, (const char * const *)args->pdata);
}
static gboolean
builder_source_shell_extract (BuilderSource *source,
GFile *dest,
BuilderOptions *build_options,
BuilderContext *context,
GError **error)
{
BuilderSourceShell *self = BUILDER_SOURCE_SHELL (source);
int i;
if (self->commands)
{
for (i = 0; self->commands[i] != NULL; i++)
{
if (!run_script (context, build_options,
dest, self->commands[i], error))
return FALSE;
}
}
return TRUE;
}
static gboolean
builder_source_shell_bundle (BuilderSource *source,
BuilderContext *context,
GError **error)
{
/* no need to bundle anything here as this part
can be reconstructed from the manifest */
return TRUE;
}
static void
builder_source_shell_checksum (BuilderSource *source,
BuilderCache *cache,
BuilderContext *context)
{
BuilderSourceShell *self = BUILDER_SOURCE_SHELL (source);
builder_cache_checksum_strv (cache, self->commands);
}
static void
builder_source_shell_class_init (BuilderSourceShellClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
BuilderSourceClass *source_class = BUILDER_SOURCE_CLASS (klass);
object_class->finalize = builder_source_shell_finalize;
object_class->get_property = builder_source_shell_get_property;
object_class->set_property = builder_source_shell_set_property;
source_class->download = builder_source_shell_download;
source_class->extract = builder_source_shell_extract;
source_class->bundle = builder_source_shell_bundle;
source_class->checksum = builder_source_shell_checksum;
g_object_class_install_property (object_class,
PROP_COMMANDS,
g_param_spec_boxed ("commands",
"",
"",
G_TYPE_STRV,
G_PARAM_READWRITE));
}
static void
builder_source_shell_init (BuilderSourceShell *self)
{
}

View File

@@ -1,40 +0,0 @@
/*
* 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.1 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_SHELL_H__
#define __BUILDER_SOURCE_SHELL_H__
#include "builder-source.h"
G_BEGIN_DECLS
typedef struct BuilderSourceShell BuilderSourceShell;
#define BUILDER_TYPE_SOURCE_SHELL (builder_source_shell_get_type ())
#define BUILDER_SOURCE_SHELL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BUILDER_TYPE_SOURCE_SHELL, BuilderSourceShell))
#define BUILDER_IS_SOURCE_SHELL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BUILDER_TYPE_SOURCE_SHELL))
GType builder_source_shell_get_type (void);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (BuilderSourceShell, g_object_unref)
G_END_DECLS
#endif /* __BUILDER_SOURCE_SHELL_H__ */

View File

@@ -1,405 +0,0 @@
/* 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 2 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 Lesser 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"
#include "builder-source-script.h"
#include "builder-source-shell.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,
PROP_ONLY_ARCHES,
PROP_SKIP_ARCHES,
LAST_PROP
};
static void
builder_source_finalize (GObject *object)
{
BuilderSource *self = BUILDER_SOURCE (object);
g_clear_object (&self->base_dir);
g_free (self->dest);
G_OBJECT_CLASS (builder_source_parent_class)->finalize (object);
}
void
builder_source_set_base_dir (BuilderSource *self,
GFile *base_dir)
{
g_set_object (&self->base_dir, base_dir);
}
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;
case PROP_ONLY_ARCHES:
g_value_set_boxed (value, self->only_arches);
break;
case PROP_SKIP_ARCHES:
g_value_set_boxed (value, self->skip_arches);
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);
gchar **tmp;
switch (prop_id)
{
case PROP_DEST:
g_free (self->dest);
self->dest = g_value_dup_string (value);
break;
case PROP_ONLY_ARCHES:
tmp = self->only_arches;
self->only_arches = g_strdupv (g_value_get_boxed (value));
g_strfreev (tmp);
break;
case PROP_SKIP_ARCHES:
tmp = self->skip_arches;
self->skip_arches = g_strdupv (g_value_get_boxed (value));
g_strfreev (tmp);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static gboolean
builder_source_real_show_deps (BuilderSource *self,
GError **error)
{
return TRUE;
}
static gboolean
builder_source_real_download (BuilderSource *self,
gboolean update_vcs,
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,
BuilderOptions *build_options,
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 gboolean
builder_source_real_bundle (BuilderSource *self,
BuilderContext *context,
GError **error)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Bundle not implemented for type %s", g_type_name_from_instance ((GTypeInstance *) self));
return FALSE;
}
static gboolean
builder_source_real_update (BuilderSource *self,
BuilderContext *context,
GError **error)
{
return TRUE;
}
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->show_deps = builder_source_real_show_deps;
klass->download = builder_source_real_download;
klass->extract = builder_source_real_extract;
klass->bundle = builder_source_real_bundle;
klass->update = builder_source_real_update;
g_object_class_install_property (object_class,
PROP_DEST,
g_param_spec_string ("dest",
"",
"",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_ONLY_ARCHES,
g_param_spec_boxed ("only-arches",
"",
"",
G_TYPE_STRV,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_SKIP_ARCHES,
g_param_spec_boxed ("skip-arches",
"",
"",
G_TYPE_STRV,
G_PARAM_READWRITE));
}
static void
builder_source_init (BuilderSource *self)
{
}
static GParamSpec *
builder_source_find_property (JsonSerializable *serializable,
const char *name)
{
if (strcmp (name, "type") == 0)
return NULL;
return builder_serializable_find_property_with_error (serializable, name);
}
static void
serializable_iface_init (JsonSerializableIface *serializable_iface)
{
serializable_iface->find_property = builder_source_find_property;
}
JsonNode *
builder_source_to_json (BuilderSource *self)
{
JsonNode *node;
JsonObject *object;
const gchar *type = NULL;
node = json_gobject_serialize (G_OBJECT (self));
object = json_node_get_object (node);
if (BUILDER_IS_SOURCE_ARCHIVE (self))
type = "archive";
else if (BUILDER_IS_SOURCE_FILE (self))
type = "file";
else if (BUILDER_IS_SOURCE_SCRIPT (self))
type = "script";
else if (BUILDER_IS_SOURCE_SHELL (self))
type = "shell";
else if (BUILDER_IS_SOURCE_PATCH (self))
type = "patch";
else if (BUILDER_IS_SOURCE_GIT (self))
type = "git";
else if (BUILDER_IS_SOURCE_BZR (self))
type = "bzr";
else
g_warning ("Unknown source type");
if (type)
json_object_set_string_member (object, "type", type);
return node;
}
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 (type == NULL)
g_warning ("Missing source type");
else if (strcmp (type, "archive") == 0)
return (BuilderSource *) json_gobject_deserialize (BUILDER_TYPE_SOURCE_ARCHIVE, node);
else if (strcmp (type, "file") == 0)
return (BuilderSource *) json_gobject_deserialize (BUILDER_TYPE_SOURCE_FILE, node);
else if (strcmp (type, "script") == 0)
return (BuilderSource *) json_gobject_deserialize (BUILDER_TYPE_SOURCE_SCRIPT, node);
else if (strcmp (type, "shell") == 0)
return (BuilderSource *) json_gobject_deserialize (BUILDER_TYPE_SOURCE_SHELL, node);
else if (strcmp (type, "patch") == 0)
return (BuilderSource *) json_gobject_deserialize (BUILDER_TYPE_SOURCE_PATCH, node);
else if (strcmp (type, "git") == 0)
return (BuilderSource *) json_gobject_deserialize (BUILDER_TYPE_SOURCE_GIT, node);
else if (strcmp (type, "bzr") == 0)
return (BuilderSource *) json_gobject_deserialize (BUILDER_TYPE_SOURCE_BZR, node);
else
g_warning ("Unknown source type %s", type);
return NULL;
}
gboolean
builder_source_show_deps (BuilderSource *self,
GError **error)
{
BuilderSourceClass *class;
class = BUILDER_SOURCE_GET_CLASS (self);
return class->show_deps (self, error);
}
gboolean
builder_source_download (BuilderSource *self,
gboolean update_vcs,
BuilderContext *context,
GError **error)
{
BuilderSourceClass *class;
class = BUILDER_SOURCE_GET_CLASS (self);
return class->download (self, update_vcs, context, error);
}
gboolean
builder_source_extract (BuilderSource *self,
GFile *dest,
BuilderOptions *build_options,
BuilderContext *context,
GError **error)
{
BuilderSourceClass *class;
g_autoptr(GFile) real_dest = NULL;
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, build_options, context, error);
}
gboolean
builder_source_bundle (BuilderSource *self,
BuilderContext *context,
GError **error)
{
BuilderSourceClass *class;
class = BUILDER_SOURCE_GET_CLASS (self);
return class->bundle (self, context, error);
}
gboolean
builder_source_update (BuilderSource *self,
BuilderContext *context,
GError **error)
{
BuilderSourceClass *class = BUILDER_SOURCE_GET_CLASS (self);
return class->update (self, 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);
builder_cache_checksum_strv (cache, self->only_arches);
builder_cache_checksum_strv (cache, self->skip_arches);
class->checksum (self, cache, context);
}
gboolean
builder_source_is_enabled (BuilderSource *self,
BuilderContext *context)
{
if (self->only_arches != NULL &&
self->only_arches[0] != NULL &&
!g_strv_contains ((const char * const *) self->only_arches, builder_context_get_arch (context)))
return FALSE;
if (self->skip_arches != NULL &&
g_strv_contains ((const char * const *)self->skip_arches, builder_context_get_arch (context)))
return FALSE;
return TRUE;
}

View File

@@ -1,114 +0,0 @@
/*
* 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.1 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;
GFile *base_dir;
char *dest;
char **only_arches;
char **skip_arches;
};
typedef struct
{
GObjectClass parent_class;
gboolean (* show_deps)(BuilderSource *self,
GError **error);
gboolean (* download)(BuilderSource *self,
gboolean update_vcs,
BuilderContext *context,
GError **error);
gboolean (* extract)(BuilderSource *self,
GFile *dest,
BuilderOptions *build_options,
BuilderContext *context,
GError **error);
gboolean (* bundle)(BuilderSource *self,
BuilderContext *context,
GError **error);
gboolean (* update)(BuilderSource *self,
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);
JsonNode * builder_source_to_json (BuilderSource *self);
void builder_source_set_base_dir (BuilderSource *self,
GFile *base_dir);
gboolean builder_source_show_deps (BuilderSource *self,
GError **error);
gboolean builder_source_download (BuilderSource *self,
gboolean update_vcs,
BuilderContext *context,
GError **error);
gboolean builder_source_extract (BuilderSource *self,
GFile *dest,
BuilderOptions *build_options,
BuilderContext *context,
GError **error);
gboolean builder_source_bundle (BuilderSource *self,
BuilderContext *context,
GError **error);
gboolean builder_source_update (BuilderSource *self,
BuilderContext *context,
GError **error);
void builder_source_checksum (BuilderSource *self,
BuilderCache *cache,
BuilderContext *context);
gboolean builder_source_is_enabled (BuilderSource *self,
BuilderContext *context);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (BuilderSource, g_object_unref)
G_END_DECLS
#endif /* __BUILDER_SOURCE_H__ */

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,80 +0,0 @@
/*
* 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.1 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>
#include <json-glib/json-glib.h>
G_BEGIN_DECLS
typedef struct BuilderUtils BuilderUtils;
char *builder_uri_to_filename (const char *uri);
gboolean strip (GError **error,
...);
gboolean eu_strip (GError **error,
...);
gboolean is_elf_file (const char *path,
gboolean *is_shared,
gboolean *is_stripped);
char ** builder_get_debuginfo_file_references (const char *filename,
GError **error);
gboolean directory_is_empty (const char *path);
gboolean flatpak_matches_path_pattern (const char *path,
const char *pattern);
void flatpak_collect_matches_for_path_pattern (const char *path,
const char *pattern,
const char *add_prefix,
GHashTable *to_remove_ht);
gboolean builder_migrate_locale_dirs (GFile *root_dir,
GError **error);
gboolean builder_host_spawnv (GFile *dir,
char **output,
GError **error,
const gchar * const *argv);
gboolean builder_maybe_host_spawnv (GFile *dir,
char **output,
GError **error,
const gchar * const *argv);
gboolean builder_download_uri (SoupURI *uri,
GFile *dest,
char *sha256,
SoupSession *soup_session,
GError **error);
GParamSpec * builder_serializable_find_property_with_error (JsonSerializable *serializable,
const char *name);
void builder_set_term_title (const gchar *format,
...) G_GNUC_PRINTF (1, 2);
G_END_DECLS
#endif /* __BUILDER_UTILS_H__ */

View File

@@ -47,11 +47,9 @@ man1 = \
flatpak-build-sign.1 \
flatpak-build-commit-from.1 \
flatpak-repo.1 \
flatpak-builder.1 \
$(NULL)
man5 = \
flatpak-manifest.5 \
flatpak-metadata.5 \
flatpak-flatpakrepo.5 \
flatpak-flatpakref.5 \

View File

@@ -1,632 +0,0 @@
<?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="flatpak-builder">
<refentryinfo>
<title>flatpak builder</title>
<productname>flatpak</productname>
<authorgroup>
<author>
<contrib>Developer</contrib>
<firstname>Alexander</firstname>
<surname>Larsson</surname>
<email>alexl@redhat.com</email>
</author>
</authorgroup>
</refentryinfo>
<refmeta>
<refentrytitle>flatpak-builder</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
<refname>flatpak-builder</refname>
<refpurpose>Help build application dependencies</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>flatpak-builder</command>
<arg choice="opt" rep="repeat">OPTION</arg>
<arg choice="plain">DIRECTORY</arg>
<arg choice="plain">MANIFEST</arg>
</cmdsynopsis>
<cmdsynopsis>
<command>flatpak-builder</command>
<arg choice="plain">--run</arg>
<arg choice="opt" rep="repeat">OPTION</arg>
<arg choice="plain">DIRECTORY</arg>
<arg choice="plain">MANIFEST</arg>
<arg choice="plain">COMMAND</arg>
</cmdsynopsis>
<cmdsynopsis>
<command>flatpak-builder</command>
<arg choice="plain">--show-deps</arg>
<arg choice="opt" rep="repeat">OPTION</arg>
<arg choice="plain">MANIFEST</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
<command>flatpak-builder</command> is a wrapper around the <command>flatpak 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>flatpak-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
&amp;&amp; make &amp;&amp; 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>
An invocation of <command>flatpak-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>flatpak build-init</command></para>
</listitem>
<listitem>
<para>Build and install each module with <command>flatpak 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>flatpak 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>flatpak build-export</command> command. If you use the <option>--repo</option>
option, flatpak-builder will do the export for you at the end of the build process. When flatpak-builder does the
export, it also stores the manifest that was used for the build in /app/manifest.json. The manifest is 'resolved',
i.e. git branch names are replaced by the actual commit IDs that were used in the build.
</para>
<para>
At each of the above steps flatpak caches the result, and if you build the same file again, it will start
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 flatpak-builder very efficient for incremental builds.
</para>
<!-- FIXME: Uncomment this when enable-p2p is enabled unconditionally.
<para>
When building a flatpak to be published to the internet,
<option>-FIXME-collection-id=COLLECTION-ID</option> should be specified
as a globally unique reverse DNS value to identify the collection of
flatpaks this will be added to. Setting a globally unique collection
ID allows the apps in the repository to be shared over peer to peer
systems without needing further configuration.
</para>
-->
</refsect1>
<refsect1>
<title>Manifest</title>
<para>The manifest file is a json file whose format is described in detail in its own manual page.</para>
</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>--arch=ARCH</option></term>
<listitem><para>
Specify the machine architecture to build for. If no architecture is specified, the host architecture will be automatically detected. Only host compatible architectures can be specified.
</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-rofiles-fuse</option></term>
<listitem><para>
Disable the use of rofiles-fuse to optimize the cache use via hardlink checkouts.
</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 if you want to guarantee that no network i/o is done. However, the
build will fail if some source is not locally available.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--disable-updates</option></term>
<listitem><para>
Download missing sources, but don't update local mirrors of version control repos. This is useful
to rebuild things but without updating git or bzr repositories from the remote repository.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--run</option></term>
<listitem><para>
Run a command in a sandbox based on the build dir. This starts flatpak build, with some extra
arguments to give the same environment as the build, and the same permissions the final app
will have. The command to run must be the last argument passed to
flatpak-builder, after the directory and the manifest.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--build-shell=MODULENAME</option></term>
<listitem><para>
Extract and prepare the sources for the named module, and then start
a shell in a sandbox identical to the one flatpak-builder would use for buildng the module.
This is useful to debug a module.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--show-deps</option></term>
<listitem><para>
List all the (local) files that the manifest depends on.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--download-only</option></term>
<listitem><para>
Exit successfully after downloading the required sources.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--build-only</option></term>
<listitem><para>
Don't do the cleanup and finish stages, which is useful if you
want to build more things into the app.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--finish-only</option></term>
<listitem><para>
Only do the cleanup, finish and export stages, picking up
where a --build-only command left off.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--export-only</option></term>
<listitem><para>
Only do the export stages, picking up the build result from a previous build.
This can be used to split the build and export/signature into two calls
by leaving out --repo in the first call.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--require-changes</option></term>
<listitem><para>
Do nothing, leaving a non-existent <arg choice="plain">DIRECTORY</arg> if nothing changes since
last cached build. If this is not specified, the latest version from the cache will be put
into <arg choice="plain">DIRECTORY</arg>.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--keep-build-dirs</option></term>
<listitem><para>
Don't remove the sources and build after having built and installed each module.
This also creates a symlink to the build directory with a stable name ("build-modulename").
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--delete-build-dirs</option></term>
<listitem><para>
Always remove the sources and build after having built each module, even if the build
failed. The default is to keep failed build directories but remote successful ones.
This is useful in e.g. automatic build systems.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--ccache</option></term>
<listitem><para>
Enable use of ccache in the build (needs ccache in the sdk)
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--stop-at=MODULENAME</option></term>
<listitem><para>
Stop at the specified module, ignoring it and all the following ones
in both the "download" and "build" phases. This is useful for debugging
and development. For instance, you can build all the dependencies, but
stop at the main application so that you can then do a build from a
pre-existing checkout. Implies --build-only.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--repo=DIR</option></term>
<listitem><para>
When build is done, run export the result to this repository.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-s</option></term>
<term><option>--subject=SUBJECT</option></term>
<listitem><para>
One line subject for the commit message.
Used when exporting the build results.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-b</option></term>
<term><option>--body=BODY</option></term>
<listitem><para>
Full description for the commit message.
Used when exporting the build results.
</para></listitem>
</varlistentry>
<!-- FIXME: Uncomment this when enable-p2p is enabled unconditionally.
<varlistentry>
<term><option>-FIXME-collection-id=COLLECTION-ID</option></term>
<listitem><para>
Set as the collection ID of the repository. Setting a globally
unique collection ID allows the apps in the repository to be shared over
peer to peer systems without needing further configuration.
If building in an existing repository, the collection ID
must match the existing configured collection ID for that
repository.
</para></listitem>
</varlistentry>
-->
<varlistentry>
<term><option>--gpg-sign=KEYID</option></term>
<listitem><para>
Sign the commit with this GPG key.
Used when exporting the build results.
This option can be used multiple times.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--gpg-homedir=PATH</option></term>
<listitem><para>
GPG Homedir to use when looking for keyrings.
Used when exporting the build results.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--jobs=JOBS</option></term>
<listitem><para>
Limit the number of parallel jobs during the build.
The default is the number of CPUs on the machine.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--force-clean</option></term>
<listitem><para>
Erase the previous contents of DIRECTORY if it is
not empty.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--sandbox</option></term>
<listitem><para>
Disable the possibility to specify build-args that
are passed to flatpak build. This means the build
process can't break out of its sandbox, and is
useful when building less trusted software.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--allow-missing-runtimes</option></term>
<listitem><para>
Do not immediately fail if the sdk or platform runtimes
are not installed on this system. Attempting to build any
manifest modules will still fail if the sdk is missing, but
may be useful for apps that install files without a sandbox
build.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--rebuild-on-sdk-change</option></term>
<listitem><para>
Record the exact version of the sdk in the cache, and rebuild everything
if it changes. This is useful if you're building against an API-unstable
runtime, like a nightly build.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--skip-if-unchanged</option></term>
<listitem><para>
If the json is unchanged since the last build of this filename, then
do nothing, and return exit code 42.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--mirror-screenshots-url=URL</option></term>
<listitem><para>
Mirror any screenshots in the appstream and rewrite the appstream xml
as if they were on the specified URL. The resulting files will
be stored in the "screenshots" subdirectory in the app directory
and needs to be copied to the specified URL for the appdata to work.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--extra-sources=SOURCE-DIR</option></term>
<listitem><para>
When downloading sources (archives, files, git, bzr), look in this
directory for pre-existing copies and use them instead of downloading.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--extra-sources-url=URL</option></term>
<listitem><para>
When downloading sources (archives, files, git, bzr), look at this url
for mirrored downloads before downloading from the original url.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--from-git=GIT</option></term>
<listitem><para>
Look for the manifest in the given git repository. If this option is
given, MANIFEST is interpreted as a relative path inside the repository.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--from-git-branch=BRANCH</option></term>
<listitem><para>
The branch to use with --from-git.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--install-deps-from=REMOTE</option></term>
<listitem><para>
Install/update build required dependencies from the specified remote.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--install-deps-only</option></term>
<listitem><para>
Stop after downloading dependencies.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--user</option></term>
<listitem><para>
Install the dependencies in a per-user installation.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--system</option></term>
<listitem><para>
Install the dependenceis in the default system-wide installation.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--installation=NAME</option></term>
<listitem><para>
Install the dependencies in a system-wide installation
specified by <arg choice="plain">NAME</arg> among those defined in
<filename>/etc/flatpak/installations.d/</filename>. Using
<arg choice="plain">--installation=default</arg> is equivalent to using
<arg choice="plain">--system</arg>.
</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Caching</title>
<para>
flatpak-builder caches sources and partial build results in
the .flatpak-builder subdirectory of the current directory. If you
use <option>--keep-build-dirs</option>, build directories for each
module are also stored here.
</para>
<para>
It is safe to remove the contents of the .flatpak-builder
directory. This will force a full build the next time you build.
</para>
</refsect1>
<refsect1>
<title>Examples</title>
<para>
<command>$ flatpak-builder my-app-dir manifest.json</command>
</para>
<para>
Example manifest file:
</para>
<programlisting>
{
"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>flatpak</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>flatpak-manifest</refentrytitle><manvolnum>5</manvolnum></citerefentry>
<citerefentry><refentrytitle>flatpak-build-init</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>flatpak-build</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>flatpak-build-finish</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>flatpak-build-export</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>

View File

@@ -16,7 +16,6 @@
<chapter>
<title>Executables</title>
<xi:include href="@srcdir@/flatpak.xml"/>
<xi:include href="@srcdir@/flatpak-builder.xml"/>
</chapter>
<chapter>
<title>Commands</title>
@@ -53,7 +52,6 @@
<xi:include href="@srcdir@/flatpak-metadata.xml"/>
<xi:include href="@srcdir@/flatpak-flatpakrepo.xml"/>
<xi:include href="@srcdir@/flatpak-flatpakref.xml"/>
<xi:include href="@srcdir@/flatpak-manifest.xml"/>
<xi:include href="@srcdir@/flatpak-remote.xml"/>
<xi:include href="@srcdir@/flatpak-installation.xml"/>
</chapter>

View File

@@ -1,710 +0,0 @@
<?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="flatpak-manifest">
<refentryinfo>
<title>flatpak manifest</title>
<productname>flatpak</productname>
<authorgroup>
<author>
<contrib>Developer</contrib>
<firstname>Alexander</firstname>
<surname>Larsson</surname>
<email>alexl@redhat.com</email>
</author>
</authorgroup>
</refentryinfo>
<refmeta>
<refentrytitle>flatpak manifest</refentrytitle>
<manvolnum>5</manvolnum>
</refmeta>
<refnamediv>
<refname>flatpak-manifest</refname>
<refpurpose>Information for building an application</refpurpose>
</refnamediv>
<refsect1>
<title>Description</title>
<para>
Flatpak uses manifest, or recipe, files in a json format to describe how an
application and its bundled dependencies can be built from sources. The manifest
gets used by flatpak-builder.
</para>
</refsect1>
<refsect1>
<title>File format</title>
<para>
The top level of the json file describes global attributes of the application, how
it can be built, and the list of modules that need to be built.
</para>
<refsect2>
<title>Toplevel properties</title>
<para>
These are the properties that are accepted:
</para>
<variablelist>
<varlistentry>
<term><option>id</option> or <option>app-id</option> (string)</term>
<listitem><para>A string defining the application id.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>branch</option> (string)</term>
<listitem><para>The branch of the application, defaults to master.</para></listitem>
</varlistentry>
<!-- FIXME: Uncomment this when enable-p2p is enabled unconditionally.
<varlistentry>
<term><option>collection-id</option> (string)</term>
<listitem><para>The collection ID of the repository,
defaults to being unset. Setting a globally
unique collection ID allows the apps in the repository to be shared over
peer to peer systems without needing further configuration.
If building in an existing repository, the collection ID
must match the existing configured collection ID for that
repository.</para></listitem>
</varlistentry>
-->
<varlistentry>
<term><option>runtime</option> (string)</term>
<listitem><para>The name of the runtime that the application uses.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>runtime-version</option> (string)</term>
<listitem><para>The version of the runtime that the application uses, defaults to master.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>sdk</option> (string)</term>
<listitem><para>The name of the development runtime that the application builds with.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>var</option> (string)</term>
<listitem><para>Initialize the (otherwise empty) writable /var in the build with a copy of this runtime.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>metadata</option> (string)</term>
<listitem><para>Use this file as the base metadata file when finishing.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>command</option> (string)</term>
<listitem><para>The filename or path to the main binary of the application. Note that this is really just a single file, not a commandline. If you want to pass arguments, install a shell script wrapper and use that as the command.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>build-runtime</option> (boolean)</term>
<listitem><para>Build a new runtime instead of an application.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>build-extension</option> (boolean)</term>
<listitem><para>Build an extension.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>separate-locales</option> (boolean)</term>
<listitem><para>Separate out locale files and translations to an extension runtime. Defaults to true.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>id-platform</option> (string)</term>
<listitem><para>When building a runtime sdk, also create a platform based on it with this id.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>metadata-platform</option> (string)</term>
<listitem><para>The metadata file to use for the platform we create.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>writable-sdk</option> (boolean)</term>
<listitem><para>If true, use a writable copy of the sdk for /usr.
Defaults to true if build-runtime is specified.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>appstream-compose</option> (boolean)</term>
<listitem><para>Run appstream-compose during cleanup phase. Defaults to true.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>sdk-extensions</option> (array of strings)</term>
<listitem><para>Install these extra sdk extensions in /usr.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>platform-extensions</option> (array of strings)</term>
<listitem><para>Install these extra sdk extensions when creating the platform.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>base</option> (string)</term>
<listitem><para>Start with the files from the specified application. This can be
used to create applications that extend another application.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>base-version</option> (string)</term>
<listitem><para>Use this specific version of the application specified in base.
If unspecified, this uses the value specified in branch</para></listitem>
</varlistentry>
<varlistentry>
<term><option>base-extensions</option> (array of strings)</term>
<listitem><para>Install these extra extensions from the base application when initializing
the application directory.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>inherit-extensions</option> (array of strings)</term>
<listitem><para>Inherit these extra extensions points from the base application or sdk when
finishing the build.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>tags</option> (array of strings)</term>
<listitem><para>Add these tags to the metadata file.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>build-options</option> (object)</term>
<listitem><para>Object specifying the build environment. See below for details.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>modules</option> (array of objects or string)</term>
<listitem><para>An array of objects specifying the modules to be built in order.
String members in the array are interpreted as the name of a separate json file that contains a module.
See below for details.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>add-extensions</option> (objects)</term>
<listitem><para>This is a dictionary of extension objects. The key is the name of the extension. See below for details.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>cleanup</option> (array of strings)</term>
<listitem><para>An array of file patterns that should be removed at the end.
Patterns starting with / are taken to be full pathnames (without the /app prefix), otherwise they just match
the basename.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>cleanup-commands</option> (array of strings)</term>
<listitem><para>An array of commandlines that are run during the cleanup phase.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>cleanup-platform</option> (array of strings)</term>
<listitem><para>Extra files to clean up in the platform.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>cleanup-platform-commands</option> (array of strings)</term>
<listitem><para>An array of commandlines that are run during the cleanup phase of the platform.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>finish-args</option> (array of strings)</term>
<listitem><para>An array of arguments passed to the <command>flatpak build-finish</command> command.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>rename-desktop-file</option> (string)</term>
<listitem><para>Any desktop file with this name will be renamed to a name based on id during the cleanup phase.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>rename-appdata-file</option> (string)</term>
<listitem><para>Any appdata file with this name will be renamed to a name based on id during the cleanup phase.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>rename-icon</option> (string)</term>
<listitem><para>Any icon with this name will be renamed to a name based on id during the cleanup phase. Note that this is the icon name, not the full filenames, so it should not include a filename extension. </para></listitem>
</varlistentry>
<varlistentry>
<term><option>copy-icon</option> (boolean)</term>
<listitem><para>If rename-icon is set, keep a copy of the old icon file.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>desktop-file-name-prefix</option> (string)</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-suffix</option> (string)</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> (string)</term>
<listitem><para>This is set in the environment variable CFLAGS during the build. Multiple specifications of this (in e.g. per-arch area) are concatinated with spaces inbetween.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>cppflags</option> (string)</term>
<listitem><para>This is set in the environment variable CPPFLAGS during the build. Multiple specifications of this (in e.g. per-arch area) are concatinated with spaces inbetween.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>cxxflags</option> (string)</term>
<listitem><para>This is set in the environment variable CXXFLAGS during the build. Multiple specifications of this (in e.g. per-arch area) are concatinated with spaces inbetween.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>ldflags</option> (string)</term>
<listitem><para>This is set in the environment variable LDFLAGS during the build. Multiple specifications of this (in e.g. per-arch area) are concatinated with spaces inbetween.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>prefix</option> (string)</term>
<listitem><para>The build prefix for the modules (defaults to <filename>/app</filename> for
applications and <filename>/usr</filename> for runtimes).</para></listitem>
</varlistentry>
<varlistentry>
<term><option>env</option> (object)</term>
<listitem><para>This is a dictionary defining environment variables to be set during the build. Elements in this override the properties that set the environment, like cflags and ldflags.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>build-args</option> (array of strings)</term>
<listitem><para>This is an array containing extra options to pass to flatpak build.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>config-opts</option> (array of strings)</term>
<listitem><para>This is an array containing extra options to pass to configure.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>strip</option> (boolean)</term>
<listitem><para>If this is true (the default is false) then all ELF files will be stripped after install.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>no-debuginfo</option> (boolean)</term>
<listitem><para>By default (if strip is not true) flatpak-builder extracts all debug info in ELF files to a separate files
and puts this in an extension. If you want to disable this, set no-debuginfo to true.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>arch</option> (object)</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>Extension</title>
<para>
Extension define extension points in the app/runtime that can be implemented by extensions, supplying extra files
which are available during runtime..
</para>
<para>
These are the properties that are accepted:
</para>
<variablelist>
<varlistentry>
<term><option>directory</option> (string)</term>
<listitem><para>The directory where the extension is mounted.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>bundle</option> (boolean)</term>
<listitem><para>If this is true, then the data
created in the extension directory is omitted from
the result, and instead packaged in a separate
extension..</para></listitem>
</varlistentry>
</variablelist>
<para>
Additionally the standard flatpak extension properies
are supported, and put directly into the metadata file:
autodelete, no-autodownload, subdirectories,
add-ld-path, download-if, enable-if, merge-dirs,
subdirectory-suffix, version, versions.
</para>
</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>
Modules can be nested, in order to turn related modules on and off with a single key.
</para>
<para>
These are the properties that are accepted:
</para>
<variablelist>
<varlistentry>
<term><option>name</option> (string)</term>
<listitem><para>The name of the module, used in e.g. build logs. The name is also used for constructing filenames and commandline arguments, therefore using spaces or '/' in this string is a bad idea.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>disabled</option> (boolean)</term>
<listitem><para>If true, skip this module</para></listitem>
</varlistentry>
<varlistentry>
<term><option>sources</option> (array of objects)</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> (array of strings)</term>
<listitem><para>An array of options that will be passed to configure</para></listitem>
</varlistentry>
<varlistentry>
<term><option>make-args</option> (array of strings)</term>
<listitem><para>An array of arguments that will be passed to make</para></listitem>
</varlistentry>
<varlistentry>
<term><option>make-install-args</option> (array of strings)</term>
<listitem><para>An array of arguments that will be passed to make install</para></listitem>
</varlistentry>
<varlistentry>
<term><option>rm-configure</option> (boolean)</term>
<listitem><para>If true, remove the configure script before starting build</para></listitem>
</varlistentry>
<varlistentry>
<term><option>no-autogen</option> (boolean)</term>
<listitem><para>Ignore the existence of an autogen script</para></listitem>
</varlistentry>
<varlistentry>
<term><option>no-parallel-make</option> (boolean)</term>
<listitem><para>Don't call make with arguments to build in parallel</para></listitem>
</varlistentry>
<varlistentry>
<term><option>install-rule</option> (string)</term>
<listitem><para>Name of the rule passed to make for the install phase, default is install</para></listitem>
</varlistentry>
<varlistentry>
<term><option>no-make-install</option> (boolean)</term>
<listitem><para>Don't run the make install (or equivalent) stage</para></listitem>
</varlistentry>
<varlistentry>
<term><option>no-python-timestamp-fix</option> (boolean)</term>
<listitem><para>Don't fix up the *.py[oc] header timestamps for ostree use.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>cmake</option> (boolean)</term>
<listitem><para>Use cmake instead of configure (deprecated: use buildsystem instead)</para></listitem>
</varlistentry>
<varlistentry>
<term><option>buildsystem</option> (string)</term>
<listitem><para>Build system to use: autotools, cmake, cmake-ninja, meson, simple</para></listitem>
</varlistentry>
<varlistentry>
<term><option>builddir</option> (boolean)</term>
<listitem><para>Use a build directory that is separate from the source directory</para></listitem>
</varlistentry>
<varlistentry>
<term><option>subdir</option> (string)</term>
<listitem><para>Build inside this subdirectory of the extracted sources</para></listitem>
</varlistentry>
<varlistentry>
<term><option>build-options</option> (object)</term>
<listitem><para>A build options object that can override global options</para></listitem>
</varlistentry>
<varlistentry>
<term><option>build-commands</option> (array of strings)</term>
<listitem><para>An array of commands to run during build (between make and make install if those are used).
This is primarily useful when using the "simple" buildsystem.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>post-install</option> (array of strings)</term>
<listitem><para>An array of shell commands that are run after the install phase. Can for example
clean up the install dir, or install extra files.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>cleanup</option> (array of strings)</term>
<listitem><para>An array of file patterns that should be removed at the end.
Patterns starting with / are taken to be full pathnames (without the /app prefix), otherwise they just match
the basename. Note that any patterns will only match files installed by this module.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>ensure-writable</option> (array of strings)</term>
<listitem><para>The way the builder works is that files in the install directory
are hard-links to the cached files, so you're not allowed to modify them in-place.
If you list a file in this then the hardlink will be broken and you can modify it.
This is a workaround, ideally installing files should replace files, not modify
existing ones.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>only-arches</option> (array of strings)</term>
<listitem><para>If non-empty, only build the module on the arches listed.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>skip-arches</option> (array of strings)</term>
<listitem><para>Don't build on any of the arches listed.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>cleanup-platform</option> (array of strings)</term>
<listitem><para>Extra files to clean up in the platform.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>modules</option> (array of objects or strings)</term>
<listitem><para>An array of objects specifying nested modules to be built before this one.
String members in the array are interpreted as names of a separate json file that contains a 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, distinguished by the type property.
</para>
<refsect3>
<title>All sources</title>
<variablelist>
<varlistentry>
<term><option>only-arches</option> (array of strings)</term>
<listitem><para>If non-empty, only build the module on the arches listed.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>skip-arches</option> (array of strings)</term>
<listitem><para>Don't build on any of the arches listed.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>dest</option> (string)</term>
<listitem><para>Directory inside the source dir where this source will be extracted.</para></listitem>
</varlistentry>
</variablelist>
</refsect3>
<refsect3>
<title>Archive sources (tar, zip)</title>
<variablelist>
<varlistentry>
<term><option>type</option></term>
<listitem><para>"archive"</para></listitem>
</varlistentry>
<varlistentry>
<term><option>path</option> (string)</term>
<listitem><para>The path of the archive</para></listitem>
</varlistentry>
<varlistentry>
<term><option>url</option> (string)</term>
<listitem><para>The URL of a remote archive that will be downloaded. This overrides path if both are specified.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>sha256</option> (string)</term>
<listitem><para>The sha256 checksum of the file, verified after download</para></listitem>
</varlistentry>
<varlistentry>
<term><option>strip-components</option> (integer)</term>
<listitem><para>The number of initial pathname components to strip during extraction. Defaults to 1.</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>path</option> (string)</term>
<listitem><para>The path to a local checkout of the git repository. Due to how git-clone works, this will be much faster than specifying a URL of file:///...</para></listitem>
</varlistentry>
<varlistentry>
<term><option>url</option> (string)</term>
<listitem><para>URL of the git repository. This overrides path if both are specified.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>branch</option> (string)</term>
<listitem><para>The branch/tag to use from the git repository</para></listitem>
</varlistentry>
<varlistentry>
<term><option>commit</option> (string)</term>
<listitem><para>The commit to use from the git repository. If branch is also specified, then it is verified that the branch/tag is at this specific commit. This is
a readable way to document that you're using a particular tag, but verify that it does not change.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>disable-fsckobjects</option> (boolean)</term>
<listitem><para>Don't use transfer.fsckObjects=1 to mirror git repository. This may be needed for some (broken) repositories.</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> (string)</term>
<listitem><para>URL of the bzr repository</para></listitem>
</varlistentry>
<varlistentry>
<term><option>revision</option> (string)</term>
<listitem><para>A specific revision to use in the branch</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> (string)</term>
<listitem><para>The path of a local file that will be copied into the source dir</para></listitem>
</varlistentry>
<varlistentry>
<term><option>url</option> (string)</term>
<listitem><para>The URL of a remote file that will be downloaded and copied into the source dir. This overrides path if both are specified.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>sha256</option> (string)</term>
<listitem><para>The sha256 checksum of the file, verified after download. This is optional for local files.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>dest-filename</option> (string)</term>
<listitem><para>Filename to use inside the source dir, default to the basename of path.</para></listitem>
</varlistentry>
</variablelist>
</refsect3>
<refsect3>
<title>Script sources</title>
<para>
This is a way to create a shell (/bin/sh) script from an inline set of commands.
</para>
<variablelist>
<varlistentry>
<term><option>type</option></term>
<listitem><para>"script"</para></listitem>
</varlistentry>
<varlistentry>
<term><option>commands</option> (array of strings)</term>
<listitem><para>An array of shell commands that will be put in a shellscript file</para></listitem>
</varlistentry>
<varlistentry>
<term><option>dest-filename</option> (string)</term>
<listitem><para>Filename to use inside the source dir, default to the basename of path.</para></listitem>
</varlistentry>
</variablelist>
</refsect3>
<refsect3>
<title>Shell sources</title>
<para>
This is a way to create/modify the sources by running shell commands.
</para>
<variablelist>
<varlistentry>
<term><option>type</option></term>
<listitem><para>"shell"</para></listitem>
</varlistentry>
<varlistentry>
<term><option>commands</option> (array of strings)</term>
<listitem><para>An array of shell commands that will be run during source extraction</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> (string)</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> (integer)</term>
<listitem><para>The value of the -p argument to patch, defaults to 1.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>use-git</option> (boolean)</term>
<listitem><para>Whether to use "git apply" rather than "patch" to apply the patch, required when the patch file contains binary diffs.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>options</option> (array of strings)</term>
<listitem><para>Extra options to pass to the patch command.</para></listitem>
</varlistentry>
</variablelist>
</refsect3>
</refsect2>
</refsect1>
<refsect1>
<title>Examples</title>
<para>
<command>$ flatpak-builder my-app-dir manifest.json</command>
</para>
<para>
Example manifest file:
</para>
<programlisting>
{
"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>flatpak-builder</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>

View File

@@ -29,8 +29,6 @@ app/flatpak-builtins-uninstall.c
app/flatpak-builtins-update.c
app/flatpak-main.c
app/flatpak-transaction.c
builder/builder-context.c
builder/builder-module.c
common/flatpak-dir.c
common/flatpak-run.c
common/flatpak-utils.c

View File

@@ -78,12 +78,9 @@ tests/test-basic.sh: tests/package_version.txt
dist_installed_test_extra_scripts += \
buildutil/tap-driver.sh \
tests/empty-configure \
tests/test-configure \
tests/make-test-app.sh \
tests/make-test-runtime.sh \
tests/make-test-bundles.sh \
tests/testpython.py \
tests/test-webserver.sh \
$(NULL)
@@ -91,20 +88,7 @@ dist_installed_test_data = \
tests/libtest.sh \
tests/org.test.Hello.png \
tests/package_version.txt \
tests/test.json \
tests/test-runtime.json \
tests/module1.json \
tests/data1 \
tests/data1.patch \
tests/module2.json \
tests/data2 \
tests/data2.patch \
tests/session.conf.in \
tests/0001-Add-test-logo.patch \
tests/org.test.Python.json \
tests/org.test.Python2.json \
tests/importme.py \
tests/importme2.py \
$(NULL)
installed_test_keyringdir = $(installed_testdir)/test-keyring
@@ -138,8 +122,6 @@ dist_test_scripts = \
tests/test-extensions.sh \
tests/test-bundle.sh \
tests/test-bundle-system.sh \
tests/test-builder.sh \
tests/test-builder-python.sh \
tests/test-oci.sh \
tests/test-unsigned-summaries.sh \
tests/test-update-remote-configuration.sh \

View File

@@ -1 +0,0 @@
Some data1

View File

@@ -1,5 +0,0 @@
--- data1 2017-04-24 09:24:02.861719643 +0200
+++ data1.mod 2017-04-24 09:35:44.589157410 +0200
@@ -1 +1 @@
-Some data1
+Some modified data1

View File

@@ -1 +0,0 @@
some data2

View File

@@ -1,5 +0,0 @@
--- tests/data2 2017-04-24 09:31:18.793726921 +0200
+++ tests/data2.mod 2017-04-24 09:36:26.485552769 +0200
@@ -1 +1 @@
-some data2
+some modified data2

View File

@@ -1,9 +0,0 @@
#!/bin/sh
cat <<EOF > Makefile
all:
echo Building
install:
echo Installing
EOF

View File

@@ -1,2 +0,0 @@
import sys
foo = "first "

View File

@@ -1,2 +0,0 @@
import sys
foo = "modified"

View File

@@ -103,7 +103,6 @@ if [ x${USE_DELTAS-} == xyes ] ; then
fi
export FLATPAK="${CMD_PREFIX} flatpak"
export FLATPAK_BUILDER="${CMD_PREFIX} flatpak-builder"
assert_streq () {
test "$1" = "$2" || (echo 1>&2 "$1 != $2"; exit 1)

View File

@@ -1,63 +0,0 @@
{
"app-id": "org.test.Python",
"runtime": "org.test.PythonPlatform",
"sdk": "org.test.PythonSdk",
"command": "testpython.py",
"modules": [
{
"name": "compiled-python",
"post-install": [
"mkdir /app/bin",
"cp testpython.py /app/bin",
"cp importme.py /app/bin",
/* Compile importme.py */
"/app/bin/testpython.py"
],
"sources": [
{
"type": "file",
"path": "empty-configure",
"dest-filename": "configure"
},
{
"type": "file",
"path": "testpython.py"
},
{
"type": "file",
"path": "importme.py"
}
]
},
{
"name": "modify-python",
"post-install": [
"cp --remove-destination importme2.py /app/bin/importme.py"
],
"sources": [
{
"type": "file",
"path": "empty-configure",
"dest-filename": "configure"
},
{
"type": "file",
"path": "importme2.py"
}
]
},
{
"name": "recompile-modified-python",
"post-install": [
"/app/bin/testpython.py"
],
"sources": [
{
"type": "file",
"path": "empty-configure",
"dest-filename": "configure"
}
]
}
]
}

View File

@@ -1,37 +0,0 @@
{
"app-id": "org.test.Python2",
"runtime": "org.test.PythonPlatform",
"sdk": "org.test.PythonSdk",
"command": "testpython.py",
"modules": [
{
"name": "compiled-python",
"post-install": [
"mkdir /app/bin",
"cp testpython.py /app/bin",
"cp importme.py /app/bin",
/* Compile importme.py */
"/app/bin/testpython.py",
/* Remove .py file, but keep .pyc */
"rm /app/bin/importme.py",
/* Make sure it still works */
"/app/bin/testpython.py"
],
"sources": [
{
"type": "file",
"path": "empty-configure",
"dest-filename": "configure"
},
{
"type": "file",
"path": "testpython.py"
},
{
"type": "file",
"path": "importme.py"
}
]
}
]
}

View File

@@ -1,65 +0,0 @@
#!/bin/bash
#
# Copyright (C) 2011 Colin Walters <walters@verbum.org>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
set -euo pipefail
. $(dirname $0)/libtest.sh
skip_without_bwrap
skip_without_user_xattrs
skip_without_python2
echo "1..2"
setup_repo
install_repo
setup_python2_repo
install_python2_repo
# Need /var/tmp cwd for xattrs
REPO=`pwd`/repo
cd $TEST_DATA_DIR/
cp $(dirname $0)/org.test.Python.json .
cp $(dirname $0)/org.test.Python2.json .
cp -a $(dirname $0)/empty-configure .
cp -a $(dirname $0)/testpython.py .
cp $(dirname $0)/importme.py .
cp $(dirname $0)/importme2.py .
chmod u+w *.py
flatpak-builder --force-clean appdir org.test.Python.json
assert_has_file appdir/files/bin/importme.pyc
flatpak-builder --run appdir org.test.Python.json testpython.py > testpython.out
assert_file_has_content testpython.out ^modified$
echo "ok handled pyc rewriting multiple times"
flatpak-builder --force-clean appdir org.test.Python2.json
assert_not_has_file appdir/files/bin/importme.py
assert_has_file appdir/files/bin/importme.pyc
flatpak-builder --run appdir org.test.Python2.json testpython.py > testpython.out
assert_file_has_content testpython.out "^first $"
echo "ok handled .pyc without .py"

View File

@@ -1,98 +0,0 @@
#!/bin/bash
#
# Copyright (C) 2011 Colin Walters <walters@verbum.org>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
set -euo pipefail
. $(dirname $0)/libtest.sh
skip_without_bwrap
skip_without_user_xattrs
echo "1..4"
setup_repo
install_repo
setup_sdk_repo
install_sdk_repo
# Need /var/tmp cwd for xattrs
REPO=`pwd`/repos/test
cd $TEST_DATA_DIR/
cp -a $(dirname $0)/test-configure .
echo "version1" > app-data
cp $(dirname $0)/test.json .
cp $(dirname $0)/test-runtime.json .
cp $(dirname $0)/0001-Add-test-logo.patch .
mkdir include1
cp $(dirname $0)/module1.json include1/
cp $(dirname $0)/data1 include1/
cp $(dirname $0)/data1.patch include1/
mkdir include1/include2
cp $(dirname $0)/module2.json include1/include2/
cp $(dirname $0)/data2 include1/include2/
cp $(dirname $0)/data2.patch include1/include2/
${FLATPAK_BUILDER} --repo=$REPO $FL_GPGARGS --force-clean appdir test.json
assert_file_has_content appdir/files/share/app-data version1
assert_file_has_content appdir/metadata shared=network;
assert_file_has_content appdir/metadata tags=test;
assert_file_has_content appdir/files/ran_module1 module1
assert_file_has_content appdir/files/ran_module2 module2
assert_not_has_file appdir/files/cleanup/a_filee
assert_not_has_file appdir/files/bin/file.cleanup
assert_has_file appdir/files/cleaned_up > out
assert_has_file appdir/files/share/icons/org.test.Hello.png
assert_file_has_content appdir/files/out '^foo$'
assert_file_has_content appdir/files/out2 '^foo2$'
${FLATPAK} build appdir /app/bin/hello2.sh > hello_out2
assert_file_has_content hello_out2 '^Hello world2, from a sandbox$'
echo "ok build"
${FLATPAK} ${U} install test-repo org.test.Hello2 master
run org.test.Hello2 > hello_out3
assert_file_has_content hello_out3 '^Hello world2, from a sandbox$'
run --command=cat org.test.Hello2 /app/share/app-data > app_data_1
assert_file_has_content app_data_1 version1
echo "ok install+run"
echo "version2" > app-data
${FLATPAK_BUILDER} $FL_GPGARGS --repo=$REPO --force-clean appdir test.json
assert_file_has_content appdir/files/share/app-data version2
${FLATPAK} ${U} update org.test.Hello2 master
run --command=cat org.test.Hello2 /app/share/app-data > app_data_2
assert_file_has_content app_data_2 version2
echo "ok update"
# The build-args of --help should prevent the faulty cleanup and
# platform-cleanup commands from executing
${FLATPAK_BUILDER} $FL_GPGARGS --repo=$REPO --force-clean runtimedir \
test-runtime.json
echo "ok runtime build cleanup with build-args"

View File

@@ -1,79 +0,0 @@
{
"app-id": "org.test.Hello2",
"runtime": "org.test.Platform",
"sdk": "org.test.Sdk",
"command": "hello2.sh",
"tags": ["test"],
"finish-args": [
"--share=network"
],
"build-options" : {
"cflags": "-O2 -g",
"cxxflags": "-O2 -g",
"env": {
"FOO": "bar",
"V": "1"
}
},
"cleanup": ["/cleanup", "*.cleanup"],
"cleanup-commands": [ "touch /app/cleaned_up" ],
"modules": [
"include1/module1.json",
{
"name": "root",
"modules": [
{
"name": "test",
"config-opts": ["--some-arg"],
"post-install": [ "touch /app/bin/file.cleanup", "mkdir -p /app/share/icons/", "cp org.test.Hello.png /app/share/icons/" ],
"make-args": ["BAR=2" ],
"make-install-args": ["BAR=3" ],
"build-commands": [ "echo foo > /app/out" ],
"sources": [
{
"type": "file",
"path": "test-configure",
"dest-filename": "configure",
"sha256": "675a1ac2feec4d4f54e581b4b01bc3cfd2c1cf31aa5963574d31228c8a11b7e7"
},
{
"type": "file",
"path": "app-data"
},
{
"type": "script",
"dest-filename": "hello2.sh",
"commands": [ "echo \"Hello world2, from a sandbox\"" ]
},
{
"type": "shell",
"commands": [
"mkdir /app/cleanup/",
"touch /app/cleanup/a_file"
]
},
{
"type": "patch",
"path": "0001-Add-test-logo.patch",
"use-git": true
}
]
},
{
"name": "test2",
"build-commands": [ "echo foo2 > /app/out2" ],
"buildsystem": "simple",
"sources": [
{
"type": "file",
"path": "app-data"
}
]
},
{
"name": "empty"
}
]
}
]
}

View File

@@ -1,4 +0,0 @@
#!/usr/bin/python2
import importme
print importme.foo