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