builder: Allow building runtime sdks (based on existing sdk)

This includes a few different changes:
 * Add build-runtime boolean property
 * Rename "app-id" property to "id"
 * Add metadata property to use a custom base metadata file
 * Default to writable-sdk to TRUE for runtimes
 * Default prefix to /usr for runtimes
 * Put manifest in usr for runtimes
 * Pick up debuginfo from usr for runtimes
 * Make build-finish work on runtimes, but only export appdata
tingping/wmclass
Alexander Larsson 2016-01-18 11:43:02 +01:00
parent 701d800059
commit 3341fb08ad
8 changed files with 195 additions and 44 deletions

View File

@ -177,11 +177,11 @@ copy_exports (GFile *source,
}
static gboolean
collect_exports (GFile *base, const char *app_id, GCancellable *cancellable, GError **error)
collect_exports (GFile *base, const char *app_id, gboolean is_runtime, GCancellable *cancellable, GError **error)
{
g_autoptr(GFile) files = NULL;
g_autoptr(GFile) export = NULL;
const char *paths[] = {
const char *app_paths[] = {
"share/applications", /* Copy desktop files */
"share/appdata", /* Copy appdata files */
"share/icons/hicolor", /* Icons */
@ -189,9 +189,24 @@ collect_exports (GFile *base, const char *app_id, GCancellable *cancellable, GEr
"share/gnome-shell/search-providers", /* Search providers */
NULL,
};
const char *runtime_paths[] = {
"share/appdata", /* Copy appdata files */
NULL,
};
const char **paths;
int i;
files = g_file_get_child (base, "files");
if (is_runtime)
{
files = g_file_get_child (base, "usr");
paths = runtime_paths;
}
else
{
files = g_file_get_child (base, "files");
paths = app_paths;
}
export = g_file_get_child (base, "export");
if (!gs_file_ensure_directory (export, TRUE, cancellable, error))
@ -325,7 +340,8 @@ xdg_app_builtin_build_finish (int argc, char **argv, GCancellable *cancellable,
g_autoptr(GFile) export_dir = NULL;
g_autoptr(GFile) metadata_file = NULL;
g_autofree char *metadata_contents = NULL;
g_autofree char *app_id = NULL;
g_autofree char *id = NULL;
gboolean is_runtime;
gsize metadata_size;
const char *directory;
g_autoptr(GKeyFile) metakey = NULL;
@ -361,15 +377,20 @@ xdg_app_builtin_build_finish (int argc, char **argv, GCancellable *cancellable,
if (!g_key_file_load_from_data (metakey, metadata_contents, metadata_size, 0, error))
return FALSE;
app_id = g_key_file_get_string (metakey, "Application", "name", error);
if (app_id == NULL)
return FALSE;
id = g_key_file_get_string (metakey, "Application", "name", NULL);
if (id == NULL)
{
id = g_key_file_get_string (metakey, "Runtime", "name", NULL);
if (id == NULL)
return xdg_app_fail (error, "No name specified in the metadata");
is_runtime = TRUE;
}
if (g_file_query_exists (export_dir, cancellable))
return xdg_app_fail (error, "Build directory %s already finalized", directory);
g_debug ("Collecting exports");
if (!collect_exports (base, app_id, cancellable, error))
if (!collect_exports (base, id, is_runtime, cancellable, error))
return FALSE;
g_debug ("Updating metadata");

View File

@ -48,6 +48,7 @@ struct BuilderContext {
gboolean keep_build_dirs;
char **cleanup;
gboolean use_ccache;
gboolean build_runtime;
};
typedef struct {
@ -293,6 +294,19 @@ builder_context_get_keep_build_dirs (BuilderContext *self)
return self->keep_build_dirs;
}
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_enable_ccache (BuilderContext *self,
GError **error)

View File

@ -55,6 +55,9 @@ const char ** builder_context_get_global_cleanup (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);
BuilderContext *builder_context_new (GFile *base_dir,
GFile *app_dir);

View File

@ -37,11 +37,12 @@
struct BuilderManifest {
GObject parent;
char *app_id;
char *id;
char *branch;
char *runtime;
char *runtime_version;
char *sdk;
char *metadata;
char **cleanup;
char **cleanup_commands;
char **finish_args;
@ -51,6 +52,7 @@ struct BuilderManifest {
gboolean copy_icon;
char *desktop_file_name_prefix;
char *desktop_file_name_suffix;
gboolean build_runtime;
gboolean writable_sdk;
char *command;
BuilderOptions *build_options;
@ -68,16 +70,19 @@ G_DEFINE_TYPE_WITH_CODE (BuilderManifest, builder_manifest, G_TYPE_OBJECT,
enum {
PROP_0,
PROP_APP_ID,
PROP_APP_ID, /* Backwards compat with early version, use id */
PROP_ID,
PROP_BRANCH,
PROP_RUNTIME,
PROP_RUNTIME_VERSION,
PROP_SDK,
PROP_METADATA,
PROP_BUILD_OPTIONS,
PROP_COMMAND,
PROP_MODULES,
PROP_CLEANUP,
PROP_CLEANUP_COMMANDS,
PROP_BUILD_RUNTIME,
PROP_WRITABLE_SDK,
PROP_FINISH_ARGS,
PROP_RENAME_DESKTOP_FILE,
@ -94,11 +99,12 @@ builder_manifest_finalize (GObject *object)
{
BuilderManifest *self = (BuilderManifest *)object;
g_free (self->app_id);
g_free (self->id);
g_free (self->branch);
g_free (self->runtime);
g_free (self->runtime_version);
g_free (self->sdk);
g_free (self->metadata);
g_free (self->command);
g_clear_object (&self->build_options);
g_list_free_full (self->modules, g_object_unref);
@ -125,7 +131,11 @@ builder_manifest_get_property (GObject *object,
switch (prop_id)
{
case PROP_APP_ID:
g_value_set_string (value, self->app_id);
g_value_set_string (value, NULL);
break;
case PROP_ID:
g_value_set_string (value, self->id);
break;
case PROP_BRANCH:
@ -144,6 +154,10 @@ builder_manifest_get_property (GObject *object,
g_value_set_string (value, self->sdk);
break;
case PROP_METADATA:
g_value_set_string (value, self->metadata);
break;
case PROP_COMMAND:
g_value_set_string (value, self->command);
break;
@ -168,6 +182,10 @@ builder_manifest_get_property (GObject *object,
g_value_set_boxed (value, self->finish_args);
break;
case PROP_BUILD_RUNTIME:
g_value_set_boolean (value, self->build_runtime);
break;
case PROP_WRITABLE_SDK:
g_value_set_boolean (value, self->writable_sdk);
break;
@ -213,8 +231,13 @@ builder_manifest_set_property (GObject *object,
switch (prop_id)
{
case PROP_APP_ID:
g_free (self->app_id);
self->app_id = g_value_dup_string (value);
g_free (self->id);
self->id = g_value_dup_string (value);
break;
case PROP_ID:
g_free (self->id);
self->id = g_value_dup_string (value);
break;
case PROP_BRANCH:
@ -237,6 +260,11 @@ builder_manifest_set_property (GObject *object,
self->sdk = g_value_dup_string (value);
break;
case PROP_METADATA:
g_free (self->metadata);
self->metadata = g_value_dup_string (value);
break;
case PROP_COMMAND:
g_free (self->command);
self->command = g_value_dup_string (value);
@ -270,6 +298,10 @@ builder_manifest_set_property (GObject *object,
g_strfreev (tmp);
break;
case PROP_BUILD_RUNTIME:
self->build_runtime = g_value_get_boolean (value);
break;
case PROP_WRITABLE_SDK:
self->writable_sdk = g_value_get_boolean (value);
break;
@ -324,6 +356,13 @@ builder_manifest_class_init (BuilderManifestClass *klass)
"",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_ID,
g_param_spec_string ("id",
"",
"",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_BRANCH,
g_param_spec_string ("branch",
@ -352,6 +391,13 @@ builder_manifest_class_init (BuilderManifestClass *klass)
"",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_METADATA,
g_param_spec_string ("metadata",
"",
"",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_COMMAND,
g_param_spec_string ("command",
@ -393,6 +439,13 @@ builder_manifest_class_init (BuilderManifestClass *klass)
"",
G_TYPE_STRV,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_BUILD_RUNTIME,
g_param_spec_boolean ("build-runtime",
"",
"",
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_WRITABLE_SDK,
g_param_spec_boolean ("writable-sdk",
@ -549,9 +602,9 @@ serializable_iface_init (JsonSerializableIface *serializable_iface)
}
const char *
builder_manifest_get_app_id (BuilderManifest *self)
builder_manifest_get_id (BuilderManifest *self)
{
return self->app_id;
return self->id;
}
BuilderOptions *
@ -581,10 +634,10 @@ builder_manifest_init_app_dir (BuilderManifest *self,
g_autofree char *app_dir_path = g_file_get_path (app_dir);
g_autoptr(GSubprocess) subp = NULL;
if (self->app_id == NULL)
if (self->id == NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"app id not specified");
"id not specified");
return FALSE;
}
@ -608,11 +661,11 @@ builder_manifest_init_app_dir (BuilderManifest *self,
"xdg-app",
"build-init",
app_dir_path,
self->app_id,
self->id,
self->sdk,
self->runtime,
builder_manifest_get_runtime_version (self),
self->writable_sdk ? "-w" : NULL,
(self->writable_sdk || self->build_runtime) ? "-w" : NULL,
NULL);
if (subp == NULL ||
@ -629,11 +682,15 @@ builder_manifest_checksum (BuilderManifest *self,
BuilderContext *context)
{
builder_cache_checksum_str (cache, BUILDER_MANIFEST_CHECKSUM_VERSION);
builder_cache_checksum_str (cache, self->app_id);
builder_cache_checksum_str (cache, self->id);
/* No need to include version here, it doesn't affect the build */
builder_cache_checksum_str (cache, self->runtime);
builder_cache_checksum_str (cache, builder_manifest_get_runtime_version (self));
builder_cache_checksum_str (cache, self->sdk);
builder_cache_checksum_str (cache, self->metadata);
builder_cache_checksum_boolean (cache, self->writable_sdk);
builder_cache_checksum_boolean (cache, self->build_runtime);
if (self->build_options)
builder_options_checksum (self->build_options, cache, context);
}
@ -654,7 +711,6 @@ builder_manifest_checksum_for_cleanup (BuilderManifest *self,
builder_cache_checksum_boolean (cache, self->copy_icon);
builder_cache_checksum_str (cache, self->desktop_file_name_prefix);
builder_cache_checksum_str (cache, self->desktop_file_name_suffix);
builder_cache_checksum_boolean (cache, self->writable_sdk);
for (l = self->modules; l != NULL; l = l->next)
{
@ -671,6 +727,20 @@ builder_manifest_checksum_for_finish (BuilderManifest *self,
builder_cache_checksum_str (cache, BUILDER_MANIFEST_CHECKSUM_VERSION " foo");
builder_cache_checksum_strv (cache, self->finish_args);
builder_cache_checksum_str (cache, self->command);
if (self->metadata)
{
GFile *base_dir = builder_context_get_base_dir (context);
g_autoptr(GFile) metadata = g_file_resolve_relative_path (base_dir, self->metadata);
g_autofree char *data = NULL;
g_autoptr(GError) my_error = NULL;
gsize len;
if (g_file_load_contents (metadata, NULL, &data, &len, NULL, &my_error))
builder_cache_checksum_data (cache, (guchar *)data, len);
else
g_warning ("Can't load metadata file %s: %s", self->metadata, my_error->message);
}
}
gboolean
@ -703,8 +773,9 @@ builder_manifest_build (BuilderManifest *self,
builder_context_set_options (context, self->build_options);
builder_context_set_global_cleanup (context, (const char **)self->cleanup);
builder_context_set_build_runtime (context, self->build_runtime);
g_print ("Starting build of %s\n", self->app_id ? self->app_id : "app");
g_print ("Starting build of %s\n", self->id ? self->id : "app");
for (l = self->modules; l != NULL; l = l->next)
{
BuilderModule *m = l->data;
@ -884,7 +955,7 @@ rename_icon_cb (BuilderManifest *self,
source_name[strlen (self->rename_icon)] == '.')
{
const char *extension = source_name + strlen (self->rename_icon);
g_autofree char *new_name = g_strconcat (self->app_id, extension, NULL);
g_autofree char *new_name = g_strconcat (self->id, extension, NULL);
int res;
*found = TRUE;
@ -934,8 +1005,6 @@ builder_manifest_cleanup (BuilderManifest *self,
builder_manifest_checksum_for_cleanup (self, cache, context);
if (!builder_cache_lookup (cache, "cleanup"))
{
app_root = g_file_get_child (app_dir, "files");
g_print ("Cleaning up\n");
if (self->cleanup_commands)
@ -975,8 +1044,9 @@ builder_manifest_cleanup (BuilderManifest *self,
}
}
app_root = g_file_get_child (app_dir, "files");
appdata_dir = g_file_resolve_relative_path (app_root, "share/appdata");
appdata_basename = g_strdup_printf ("%s.appdata.xml", self->app_id);
appdata_basename = g_strdup_printf ("%s.appdata.xml", self->id);
appdata_file = g_file_get_child (appdata_dir, appdata_basename);
if (self->rename_appdata_file != NULL)
@ -992,7 +1062,7 @@ builder_manifest_cleanup (BuilderManifest *self,
{
g_autoptr(GFile) applications_dir = g_file_resolve_relative_path (app_root, "share/applications");
g_autoptr(GFile) src = g_file_get_child (applications_dir, self->rename_desktop_file);
g_autofree char *desktop_basename = g_strdup_printf ("%s.desktop", self->app_id);
g_autofree char *desktop_basename = g_strdup_printf ("%s.desktop", self->id);
g_autoptr(GFile) dest = g_file_get_child (applications_dir, desktop_basename);
g_print ("Renaming %s to %s\n", self->rename_desktop_file, desktop_basename);
@ -1055,7 +1125,7 @@ builder_manifest_cleanup (BuilderManifest *self,
self->desktop_file_name_suffix)
{
g_autoptr(GFile) applications_dir = g_file_resolve_relative_path (app_root, "share/applications");
g_autofree char *desktop_basename = g_strdup_printf ("%s.desktop", self->app_id);
g_autofree char *desktop_basename = g_strdup_printf ("%s.desktop", self->id);
g_autoptr(GFile) desktop = g_file_get_child (applications_dir, desktop_basename);
g_autoptr(GKeyFile) keyfile = g_key_file_new ();
g_autofree char *desktop_contents = NULL;
@ -1076,7 +1146,7 @@ builder_manifest_cleanup (BuilderManifest *self,
g_key_file_set_string (keyfile,
G_KEY_FILE_DESKTOP_GROUP,
G_KEY_FILE_DESKTOP_KEY_ICON,
self->app_id);
self->id);
if (self->desktop_file_name_suffix ||
self->desktop_file_name_prefix)
@ -1148,6 +1218,18 @@ builder_manifest_finish (BuilderManifest *self,
{
g_print ("Finishing app\n");
if (self->metadata)
{
GFile *base_dir = builder_context_get_base_dir (context);
GFile *app_dir = builder_context_get_app_dir (context);
g_autoptr(GFile) dest_metadata = g_file_get_child (app_dir, "metadata");
g_autoptr(GFile) src_metadata = g_file_resolve_relative_path (base_dir, self->metadata);
if (!g_file_copy (src_metadata, dest_metadata, G_FILE_COPY_OVERWRITE, NULL,
NULL, NULL, error))
return FALSE;
}
args = g_ptr_array_new_with_free_func (g_free);
g_ptr_array_add (args, g_strdup ("xdg-app"));
g_ptr_array_add (args, g_strdup ("build-finish"));
@ -1179,14 +1261,21 @@ builder_manifest_finish (BuilderManifest *self,
json = json_generator_to_data (generator, NULL);
g_object_unref (generator);
json_node_free (node);
manifest_file = g_file_resolve_relative_path (app_dir, "files/manifest.json");
if (self->build_runtime)
manifest_file = g_file_resolve_relative_path (app_dir, "usr/manifest.json");
else
manifest_file = g_file_resolve_relative_path (app_dir, "files/manifest.json");
if (!g_file_replace_contents (manifest_file, json, strlen (json), NULL, FALSE,
0, NULL, NULL, error))
return FALSE;
debuginfo_dir = g_file_resolve_relative_path (app_dir, "files/lib/debug");
if (self->build_runtime)
debuginfo_dir = g_file_resolve_relative_path (app_dir, "usr/lib/debug");
else
debuginfo_dir = g_file_resolve_relative_path (app_dir, "files/lib/debug");
if (g_file_query_exists (debuginfo_dir, NULL))
{
@ -1202,7 +1291,7 @@ builder_manifest_finish (BuilderManifest *self,
extension_contents = g_strdup_printf("\n"
"[Extension %s.Debug]\n"
"directory=lib/debug\n",
self->app_id);
self->id);
output = g_file_append_to (metadata_file, G_FILE_CREATE_NONE, NULL, error);
if (output == NULL)
@ -1213,7 +1302,7 @@ builder_manifest_finish (BuilderManifest *self,
return FALSE;
metadata_contents = g_strdup_printf("[Runtime]\n"
"name=%s.Debug\n", self->app_id);
"name=%s.Debug\n", self->id);
if (!g_file_replace_contents (metadata_debuginfo_file,
metadata_contents, strlen (metadata_contents), NULL, FALSE,
G_FILE_CREATE_REPLACE_DESTINATION,

View File

@ -40,7 +40,7 @@ typedef struct BuilderManifest BuilderManifest;
GType builder_manifest_get_type (void);
const char * builder_manifest_get_app_id (BuilderManifest *self);
const char * builder_manifest_get_id (BuilderManifest *self);
BuilderOptions *builder_manifest_get_build_options (BuilderManifest *self);
GList * builder_manifest_get_modules (BuilderManifest *self);

View File

@ -505,6 +505,9 @@ builder_options_get_prefix (BuilderOptions *self, BuilderContext *context)
return o->prefix;
}
if (builder_context_get_build_runtime (context))
return "/usr";
return "/app";
}

View File

@ -90,7 +90,8 @@ usage (GOptionContext *context, const char *message)
}
static gboolean
do_export (GError **error,
do_export (GError **error,
gboolean runtime,
...)
{
va_list ap;
@ -104,6 +105,9 @@ do_export (GError **error,
g_ptr_array_add (args, g_strdup ("xdg-app"));
g_ptr_array_add (args, g_strdup ("build-export"));
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));
@ -257,7 +261,7 @@ main (int argc,
{
g_autofree char *body =
g_strdup_printf ("Initialized %s\n",
builder_manifest_get_app_id (manifest));
builder_manifest_get_id (manifest));
if (!builder_manifest_init_app_dir (manifest, build_context, &error))
{
g_print ("error: %s\n", error->message);
@ -301,9 +305,13 @@ main (int argc,
{
g_autoptr(GFile) debuginfo_metadata = NULL;
g_print ("exporting %s to repo\n", builder_manifest_get_app_id (manifest));
g_print ("exporting %s to repo\n", builder_manifest_get_id (manifest));
if (!do_export (&error,"--exclude=/lib/debug/*", opt_repo, app_dir_path, NULL))
if (!do_export (&error,
builder_context_get_build_runtime (build_context),
"--exclude=/lib/debug/*",
"--include=/lib/debug/app",
opt_repo, app_dir_path, NULL))
{
g_print ("Export failed: %s\n", error->message);
return 1;
@ -312,9 +320,12 @@ main (int argc,
debuginfo_metadata = g_file_get_child (app_dir, "metadata.debuginfo");
if (g_file_query_exists (debuginfo_metadata, NULL))
{
g_print ("exporting %s.Debug to repo\n", builder_manifest_get_app_id (manifest));
g_print ("exporting %s.Debug to repo\n", builder_manifest_get_id (manifest));
if (!do_export (&error, "--runtime", "--metadata=metadata.debuginfo", "--files=files/lib/debug", opt_repo, app_dir_path, NULL))
if (!do_export (&error, TRUE,
"--metadata=metadata.debuginfo",
builder_context_get_build_runtime (build_context) ? "--files=usr/lib/debug" : "--files=files/lib/debug",
opt_repo, app_dir_path, NULL))
{
g_print ("Export failed: %s\n", error->message);
return 1;

View File

@ -99,7 +99,7 @@
</para>
<variablelist>
<varlistentry>
<term><option>app-id</option></term>
<term><option>id</option></term>
<listitem><para>A string defining the application id.</para></listitem>
</varlistentry>
<varlistentry>
@ -118,13 +118,22 @@
<term><option>sdk</option></term>
<listitem><para>The name of the development runtime that the application builds with.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>metadata</option></term>
<listitem><para>Use this file as the base metadata file when finishing.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>command</option></term>
<listitem><para>The filename or path to the main binary of the application.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>build-runtime</option></term>
<listitem><para>Build a new runtime instead of an application.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>writable-sdk</option></term>
<listitem><para>If true, use a writable copy of the sdk for /usr.</para></listitem>
<listitem><para>If true, use a writable copy of the sdk for /usr.
Defaults to true if --build-runtime is specieied</para></listitem>
</varlistentry>
<varlistentry>
<term><option>build-options</option></term>
@ -196,7 +205,8 @@
</varlistentry>
<varlistentry>
<term><option>prefix</option></term>
<listitem><para>The build prefix for the modules (defaults to <filename>/app</filename>).</para></listitem>
<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></term>