diff --git a/doc/flatpak-builder.xml b/doc/flatpak-builder.xml
index 2241c370..840e34c0 100644
--- a/doc/flatpak-builder.xml
+++ b/doc/flatpak-builder.xml
@@ -348,6 +348,16 @@
+
+
+
+
+ Build an alternative version of the manifest specified by the name and the alt options
+ (like e.g. only-alts) in the manifest. If this is not specified the alternative used is
+ called "default".
+
+
+
diff --git a/doc/flatpak-manifest.xml b/doc/flatpak-manifest.xml
index eec91209..9e66cdcd 100644
--- a/doc/flatpak-manifest.xml
+++ b/doc/flatpak-manifest.xml
@@ -379,6 +379,10 @@
(object)
This is a dictionary defining for each arch a separate build options object that override the main one.
+
+ (object)
+ This is a dictionary defining for each named alternate build a separate options object that override the main one. This object may also have per-arch sub-options.
+
@@ -539,6 +543,14 @@
(array of strings)
Don't build on any of the arches listed.
+
+ (array of strings)
+ If non-empty, only build the module on the alternative builds listed.
+
+
+ (array of strings)
+ Don't build in any of the alternative builds listed.
+
(array of strings)
Extra files to clean up in the platform.
@@ -578,11 +590,19 @@
(array of strings)
- If non-empty, only build the module on the arches listed.
+ If non-empty, only include the source on the arches listed.
(array of strings)
- Don't build on any of the arches listed.
+ Don't include the source on any of the arches listed.
+
+
+ (array of strings)
+ If non-empty, only include the source on the alternative builds listed.
+
+
+ (array of strings)
+ Don't include the source on any of the alternative builds listed.
(string)
diff --git a/src/builder-context.c b/src/builder-context.c
index e8c921bc..afe54682 100644
--- a/src/builder-context.c
+++ b/src/builder-context.c
@@ -48,6 +48,7 @@ struct BuilderContext
SoupSession *soup_session;
CURL *curl_session;
char *arch;
+ char *alt;
char *stop_at;
GFile *download_dir;
@@ -118,6 +119,7 @@ builder_context_finalize (GObject *object)
g_clear_object (&self->options);
g_clear_object (&self->sdk_config);
g_free (self->arch);
+ g_free (self->alt);
g_free (self->state_subdir);
g_free (self->stop_at);
g_strfreev (self->cleanup);
@@ -563,6 +565,32 @@ builder_context_set_arch (BuilderContext *self,
self->arch = g_strdup (arch);
}
+const char *
+builder_context_get_alt (BuilderContext *self)
+{
+ return (const char *) self->alt;
+}
+
+const char *
+builder_context_get_defaulted_alt (BuilderContext *self)
+{
+ if (self->alt == NULL)
+ return "default";
+ return (const char *) self->alt;
+}
+
+void
+builder_context_set_alt (BuilderContext *self,
+ const char *alt)
+{
+ g_free (self->alt);
+
+ if (g_strcmp0 (alt, "default") == 0)
+ alt = NULL;
+
+ self->alt = g_strdup (alt);
+}
+
const char *
builder_context_get_stop_at (BuilderContext *self)
{
diff --git a/src/builder-context.h b/src/builder-context.h
index 97baa0ea..ca532222 100644
--- a/src/builder-context.h
+++ b/src/builder-context.h
@@ -74,6 +74,10 @@ CURL * builder_context_get_curl_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_alt (BuilderContext *self);
+const char * builder_context_get_defaulted_alt (BuilderContext *self);
+void builder_context_set_alt (BuilderContext *self,
+ const char *alt);
const char * builder_context_get_stop_at (BuilderContext *self);
void builder_context_set_stop_at (BuilderContext *self,
const char *module);
diff --git a/src/builder-main.c b/src/builder-main.c
index 5f09ea6a..5c4e7319 100644
--- a/src/builder-main.c
+++ b/src/builder-main.c
@@ -83,6 +83,7 @@ static char *opt_installation;
static gboolean opt_log_session_bus;
static gboolean opt_log_system_bus;
static gboolean opt_yes;
+static char *opt_alt;
static GOptionEntry entries[] = {
{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &opt_verbose, "Print debug information during command processing", NULL },
@@ -133,6 +134,7 @@ static GOptionEntry entries[] = {
{ "state-dir", 0, 0, G_OPTION_ARG_FILENAME, &opt_state_dir, "Use this directory for state instead of .flatpak-builder", "PATH" },
{ "assumeyes", 'y', 0, G_OPTION_ARG_NONE, &opt_yes, N_("Automatically answer yes for all questions"), NULL },
{ "no-shallow-clone", 0, 0, G_OPTION_ARG_NONE, &opt_no_shallow_clone, "Don't use shallow clones when mirroring git repos", NULL },
+ { "alt", 0, 0, G_OPTION_ARG_STRING, &opt_alt, "Build an alternative build", "ALTNAME"},
{ NULL }
};
@@ -317,8 +319,6 @@ main (int argc,
g_autoptr(GFile) manifest_file = NULL;
g_autoptr(GFile) app_dir = NULL;
g_autoptr(BuilderCache) cache = NULL;
- g_autofree char *cache_branch = NULL;
- g_autofree char *escaped_cache_branch = NULL;
g_autoptr(GFileEnumerator) dir_enum = NULL;
g_autoptr(GFileEnumerator) dir_enum2 = NULL;
g_autofree char *cwd = NULL;
@@ -450,6 +450,7 @@ main (int argc,
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);
+ builder_context_set_alt (build_context, opt_alt);
if (opt_sources_dirs)
{
@@ -723,23 +724,31 @@ main (int argc,
return 0;
}
- if (opt_state_dir)
- {
- /* If the state dir can be shared we need to use a global identifier for the key */
- g_autofree char *manifest_path = g_file_get_path (manifest_file);
- cache_branch = g_strconcat (builder_context_get_arch (build_context), "-", manifest_path + 1, NULL);
- }
- else
- cache_branch = g_strconcat (builder_context_get_arch (build_context), "-", manifest_basename, NULL);
-
- escaped_cache_branch = g_uri_escape_string (cache_branch, "", TRUE);
- for (p = escaped_cache_branch; *p; p++)
- {
- if (*p == '%')
- *p = '_';
- }
+ {
+ g_autofree char *cache_branch = NULL;
+ g_autofree char *escaped_cache_branch = NULL;
+ g_autofree char *manifest_path = g_file_get_path (manifest_file);
+ const char *reference = manifest_basename;
+ const char *alt = builder_context_get_alt (build_context);
+
+ /* If the state dir can be shared we need to use a global identifier for the key */
+ if (opt_state_dir)
+ reference = manifest_path + 1;
+
+ cache_branch = g_strconcat (builder_context_get_arch (build_context),
+ alt ? "-" : "", alt ? alt : "",
+ "-", reference, NULL);
+
+ escaped_cache_branch = g_uri_escape_string (cache_branch, "", TRUE);
+ for (p = escaped_cache_branch; *p; p++)
+ {
+ if (*p == '%')
+ *p = '_';
+ }
+
+ cache = builder_cache_new (build_context, app_dir, escaped_cache_branch);
+ }
- cache = builder_cache_new (build_context, app_dir, escaped_cache_branch);
if (!builder_cache_open (cache, &error))
{
g_printerr ("Error opening cache: %s\n", error->message);
diff --git a/src/builder-manifest.c b/src/builder-manifest.c
index eaa55af0..0663983a 100644
--- a/src/builder-manifest.c
+++ b/src/builder-manifest.c
@@ -1704,7 +1704,6 @@ builder_manifest_checksum (BuilderManifest *self,
builder_cache_checksum_str (cache, self->base_commit);
builder_cache_checksum_strv (cache, self->base_extensions);
builder_cache_checksum_compat_str (cache, self->extension_tag);
-
if (self->build_options)
builder_options_checksum (self->build_options, cache, context);
diff --git a/src/builder-module.c b/src/builder-module.c
index 497af3a4..5f0ae7f5 100644
--- a/src/builder-module.c
+++ b/src/builder-module.c
@@ -54,6 +54,8 @@ struct BuilderModule
char **ensure_writable;
char **only_arches;
char **skip_arches;
+ char **only_alts;
+ char **skip_alts;
gboolean disabled;
gboolean rm_configure;
gboolean no_autogen;
@@ -103,8 +105,10 @@ enum {
PROP_MAKE_INSTALL_ARGS,
PROP_ENSURE_WRITABLE,
PROP_ONLY_ARCHES,
- PROP_RUN_TESTS,
PROP_SKIP_ARCHES,
+ PROP_ONLY_ALTS,
+ PROP_SKIP_ALTS,
+ PROP_RUN_TESTS,
PROP_SOURCES,
PROP_BUILD_OPTIONS,
PROP_CLEANUP,
@@ -149,6 +153,8 @@ builder_module_finalize (GObject *object)
g_strfreev (self->ensure_writable);
g_strfreev (self->only_arches);
g_strfreev (self->skip_arches);
+ g_strfreev (self->only_alts);
+ g_strfreev (self->skip_alts);
g_clear_object (&self->build_options);
g_list_free_full (self->sources, g_object_unref);
g_strfreev (self->cleanup);
@@ -249,6 +255,14 @@ builder_module_get_property (GObject *object,
g_value_set_boxed (value, self->skip_arches);
break;
+ case PROP_ONLY_ALTS:
+ g_value_set_boxed (value, self->only_alts);
+ break;
+
+ case PROP_SKIP_ALTS:
+ g_value_set_boxed (value, self->skip_alts);
+ break;
+
case PROP_POST_INSTALL:
g_value_set_boxed (value, self->post_install);
break;
@@ -398,6 +412,18 @@ builder_module_set_property (GObject *object,
g_strfreev (tmp);
break;
+ case PROP_ONLY_ALTS:
+ tmp = self->only_alts;
+ self->only_alts = g_strdupv (g_value_get_boxed (value));
+ g_strfreev (tmp);
+ break;
+
+ case PROP_SKIP_ALTS:
+ tmp = self->skip_alts;
+ self->skip_alts = g_strdupv (g_value_get_boxed (value));
+ g_strfreev (tmp);
+ break;
+
case PROP_POST_INSTALL:
tmp = self->post_install;
self->post_install = g_strdupv (g_value_get_boxed (value));
@@ -601,6 +627,20 @@ builder_module_class_init (BuilderModuleClass *klass)
"",
G_TYPE_STRV,
G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_ONLY_ALTS,
+ g_param_spec_boxed ("only-alts",
+ "",
+ "",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_SKIP_ALTS,
+ g_param_spec_boxed ("skip-alts",
+ "",
+ "",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_POST_INSTALL,
g_param_spec_boxed ("post-install",
@@ -947,6 +987,15 @@ builder_module_is_enabled (BuilderModule *self,
g_strv_contains ((const char * const *)self->skip_arches, builder_context_get_arch (context)))
return FALSE;
+ if (self->only_alts != NULL &&
+ self->only_alts[0] != NULL &&
+ !g_strv_contains ((const char * const *) self->only_alts, builder_context_get_defaulted_alt (context)))
+ return FALSE;
+
+ if (self->skip_alts != NULL &&
+ g_strv_contains ((const char * const *)self->skip_alts, builder_context_get_defaulted_alt (context)))
+ return FALSE;
+
return TRUE;
}
@@ -1961,6 +2010,8 @@ builder_module_checksum (BuilderModule *self,
builder_cache_checksum_strv (cache, self->ensure_writable);
builder_cache_checksum_strv (cache, self->only_arches);
builder_cache_checksum_strv (cache, self->skip_arches);
+ builder_cache_checksum_compat_strv (cache, self->only_alts);
+ builder_cache_checksum_compat_strv (cache, self->skip_alts);
builder_cache_checksum_boolean (cache, self->rm_configure);
builder_cache_checksum_boolean (cache, self->no_autogen);
builder_cache_checksum_boolean (cache, self->disabled);
diff --git a/src/builder-options.c b/src/builder-options.c
index d1b9b209..fcfc66c4 100644
--- a/src/builder-options.c
+++ b/src/builder-options.c
@@ -62,6 +62,7 @@ struct BuilderOptions
char **make_args;
char **make_install_args;
GHashTable *arch;
+ GHashTable *alt;
};
typedef struct
@@ -91,6 +92,7 @@ enum {
PROP_NO_DEBUGINFO,
PROP_NO_DEBUGINFO_COMPRESSION,
PROP_ARCH,
+ PROP_ALT,
PROP_BUILD_ARGS,
PROP_TEST_ARGS,
PROP_CONFIG_OPTS,
@@ -130,6 +132,7 @@ builder_options_finalize (GObject *object)
g_strfreev (self->make_args);
g_strfreev (self->make_install_args);
g_hash_table_destroy (self->arch);
+ g_hash_table_destroy (self->alt);
G_OBJECT_CLASS (builder_options_parent_class)->finalize (object);
}
@@ -216,6 +219,10 @@ builder_options_get_property (GObject *object,
g_value_set_boxed (value, self->arch);
break;
+ case PROP_ALT:
+ g_value_set_boxed (value, self->alt);
+ break;
+
case PROP_BUILD_ARGS:
g_value_set_boxed (value, self->build_args);
break;
@@ -352,6 +359,12 @@ builder_options_set_property (GObject *object,
self->arch = g_value_dup_boxed (value);
break;
+ case PROP_ALT:
+ g_hash_table_destroy (self->alt);
+ /* NOTE: This takes ownership of the hash table! */
+ self->alt = g_value_dup_boxed (value);
+ break;
+
case PROP_BUILD_ARGS:
tmp = self->build_args;
self->build_args = g_strdupv (g_value_get_boxed (value));
@@ -534,6 +547,13 @@ builder_options_class_init (BuilderOptionsClass *klass)
"",
G_TYPE_HASH_TABLE,
G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_ALT,
+ g_param_spec_boxed ("alt",
+ "",
+ "",
+ G_TYPE_HASH_TABLE,
+ G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_BUILD_ARGS,
g_param_spec_boxed ("build-args",
@@ -597,6 +617,7 @@ 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);
+ self->alt = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
}
static JsonNode *
@@ -605,12 +626,19 @@ builder_options_serialize_property (JsonSerializable *serializable,
const GValue *value,
GParamSpec *pspec)
{
- if (strcmp (property_name, "arch") == 0)
+ if (strcmp (property_name, "arch") == 0 ||
+ strcmp (property_name, "alt") == 0)
{
BuilderOptions *self = BUILDER_OPTIONS (serializable);
JsonNode *retval = NULL;
+ GHashTable *ht;
- if (self->arch && g_hash_table_size (self->arch) > 0)
+ if (strcmp (property_name, "arch") == 0)
+ ht = self->arch;
+ else
+ ht = self->alt;
+
+ if (ht && g_hash_table_size (ht) > 0)
{
JsonObject *object;
GHashTableIter iter;
@@ -618,7 +646,7 @@ builder_options_serialize_property (JsonSerializable *serializable,
object = json_object_new ();
- g_hash_table_iter_init (&iter, self->arch);
+ g_hash_table_iter_init (&iter, ht);
while (g_hash_table_iter_next (&iter, &key, &value))
{
JsonNode *child = json_gobject_serialize (value);
@@ -686,7 +714,8 @@ builder_options_deserialize_property (JsonSerializable *serializable,
GParamSpec *pspec,
JsonNode *property_node)
{
- if (strcmp (property_name, "arch") == 0)
+ if (strcmp (property_name, "arch") == 0 ||
+ strcmp (property_name, "alt") == 0)
{
if (JSON_NODE_TYPE (property_node) == JSON_NODE_NULL)
{
@@ -790,17 +819,39 @@ get_arched_options (BuilderOptions *self, BuilderContext *context)
return options;
}
+static BuilderOptions *
+get_alt_options (BuilderOptions *self, BuilderContext *context)
+{
+ const char *alt = builder_context_get_defaulted_alt (context);
+ return g_hash_table_lookup (self->alt, alt);
+}
+
static GList *
get_all_options (BuilderOptions *self, BuilderContext *context)
{
- GList *options = NULL;
BuilderOptions *global_options = builder_context_get_options (context);
+ GList *options = NULL;
if (self)
- options = get_arched_options (self, context);
+ {
+ BuilderOptions *alt_options = get_alt_options (self, context);
+
+ if (alt_options)
+ options = g_list_concat (options, get_arched_options (alt_options, context));
+
+ options = g_list_concat (options, get_arched_options (self, context));
+ }
if (global_options && global_options != self)
- options = g_list_concat (options, get_arched_options (global_options, context));
+ {
+ BuilderOptions *global_alt_options = get_alt_options (global_options, context);
+
+ if (global_alt_options)
+ options = g_list_concat (options, get_arched_options (global_alt_options, context));
+
+ options = g_list_concat (options, get_arched_options (global_options, context));
+
+ }
return options;
}
diff --git a/src/builder-source.c b/src/builder-source.c
index c5edd720..d0373b60 100644
--- a/src/builder-source.c
+++ b/src/builder-source.c
@@ -50,6 +50,8 @@ enum {
PROP_DEST,
PROP_ONLY_ARCHES,
PROP_SKIP_ARCHES,
+ PROP_ONLY_ALTS,
+ PROP_SKIP_ALTS,
LAST_PROP
};
@@ -61,6 +63,10 @@ builder_source_finalize (GObject *object)
g_clear_object (&self->base_dir);
g_free (self->dest);
+ g_strfreev (self->only_arches);
+ g_strfreev (self->skip_arches);
+ g_strfreev (self->only_alts);
+ g_strfreev (self->skip_alts);
G_OBJECT_CLASS (builder_source_parent_class)->finalize (object);
}
@@ -94,6 +100,14 @@ builder_source_get_property (GObject *object,
g_value_set_boxed (value, self->skip_arches);
break;
+ case PROP_ONLY_ALTS:
+ g_value_set_boxed (value, self->only_alts);
+ break;
+
+ case PROP_SKIP_ALTS:
+ g_value_set_boxed (value, self->skip_alts);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -127,6 +141,18 @@ builder_source_set_property (GObject *object,
g_strfreev (tmp);
break;
+ case PROP_ONLY_ALTS:
+ tmp = self->only_alts;
+ self->only_alts = g_strdupv (g_value_get_boxed (value));
+ g_strfreev (tmp);
+ break;
+
+ case PROP_SKIP_ALTS:
+ tmp = self->skip_alts;
+ self->skip_alts = g_strdupv (g_value_get_boxed (value));
+ g_strfreev (tmp);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -215,6 +241,20 @@ builder_source_class_init (BuilderSourceClass *klass)
"",
G_TYPE_STRV,
G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_ONLY_ALTS,
+ g_param_spec_boxed ("only-alts",
+ "",
+ "",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_SKIP_ALTS,
+ g_param_spec_boxed ("skip-alts",
+ "",
+ "",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE));
}
static void
@@ -399,6 +439,8 @@ builder_source_checksum (BuilderSource *self,
builder_cache_checksum_str (cache, self->dest);
builder_cache_checksum_strv (cache, self->only_arches);
builder_cache_checksum_strv (cache, self->skip_arches);
+ builder_cache_checksum_compat_strv (cache, self->only_alts);
+ builder_cache_checksum_compat_strv (cache, self->skip_alts);
class->checksum (self, cache, context);
}
@@ -427,5 +469,14 @@ builder_source_is_enabled (BuilderSource *self,
g_strv_contains ((const char * const *)self->skip_arches, builder_context_get_arch (context)))
return FALSE;
+ if (self->only_alts != NULL &&
+ self->only_alts[0] != NULL &&
+ !g_strv_contains ((const char * const *) self->only_alts, builder_context_get_defaulted_alt (context)))
+ return FALSE;
+
+ if (self->skip_alts != NULL &&
+ g_strv_contains ((const char * const *)self->skip_alts, builder_context_get_defaulted_alt (context)))
+ return FALSE;
+
return TRUE;
}
diff --git a/src/builder-source.h b/src/builder-source.h
index 10456491..0b8d6722 100644
--- a/src/builder-source.h
+++ b/src/builder-source.h
@@ -45,6 +45,8 @@ struct BuilderSource
char *dest;
char **only_arches;
char **skip_arches;
+ char **only_alts;
+ char **skip_alts;
};
typedef struct