gboolean flatpak_builtin_build (int argc, char **argv, GCancellable *cancellable, GError **error) { g_autoptr(GOptionContext) context = NULL; g_autoptr(FlatpakDeploy) runtime_deploy = NULL; g_autoptr(GVariant) runtime_deploy_data = NULL; g_autoptr(FlatpakDeploy) extensionof_deploy = NULL; g_autoptr(GFile) var = NULL; g_autoptr(GFile) var_tmp = NULL; g_autoptr(GFile) var_lib = NULL; g_autoptr(GFile) usr = NULL; g_autoptr(GFile) res_deploy = NULL; g_autoptr(GFile) res_files = NULL; g_autoptr(GFile) app_files = NULL; gboolean app_files_ro = FALSE; g_autoptr(GFile) runtime_files = NULL; g_autoptr(GFile) metadata = NULL; g_autofree char *metadata_contents = NULL; g_autofree char *runtime = NULL; g_autofree char *runtime_ref = NULL; g_autofree char *extensionof_ref = NULL; g_autofree char *extensionof_tag = NULL; g_autofree char *extension_point = NULL; g_autofree char *extension_tmpfs_point = NULL; g_autoptr(GKeyFile) metakey = NULL; g_autoptr(GKeyFile) runtime_metakey = NULL; g_autoptr(FlatpakBwrap) bwrap = NULL; g_auto(GStrv) minimal_envp = NULL; gsize metadata_size; const char *directory = NULL; const char *command = "/bin/sh"; g_autofree char *id = NULL; int i; int rest_argv_start, rest_argc; g_autoptr(FlatpakContext) arg_context = NULL; g_autoptr(FlatpakContext) app_context = NULL; gboolean custom_usr; g_auto(GStrv) runtime_ref_parts = NULL; FlatpakRunFlags run_flags; const char *group = NULL; const char *runtime_key = NULL; const char *dest = NULL; gboolean is_app = FALSE; gboolean is_extension = FALSE; gboolean is_app_extension = FALSE; g_autofree char *app_info_path = NULL; g_autofree char *app_extensions = NULL; g_autofree char *runtime_extensions = NULL; g_autofree char *instance_id_host_dir = NULL; char pid_str[64]; g_autofree char *pid_path = NULL; g_autoptr(GFile) app_id_dir = NULL; context = g_option_context_new (_("DIRECTORY [COMMAND [ARGUMENT…]] - Build in directory")); g_option_context_set_translation_domain (context, GETTEXT_PACKAGE); rest_argc = 0; for (i = 1; i < argc; i++) { /* The non-option is the directory, take it out of the arguments */ if (argv[i][0] != '-') { rest_argv_start = i; rest_argc = argc - i; argc = i; break; } } arg_context = flatpak_context_new (); g_option_context_add_group (context, flatpak_context_get_options (arg_context)); if (!flatpak_option_context_parse (context, options, &argc, &argv, FLATPAK_BUILTIN_FLAG_NO_DIR, NULL, cancellable, error)) return FALSE; if (rest_argc == 0) return usage_error (context, _("DIRECTORY must be specified"), error); directory = argv[rest_argv_start]; if (rest_argc >= 2) command = argv[rest_argv_start + 1]; res_deploy = g_file_new_for_commandline_arg (directory); metadata = g_file_get_child (res_deploy, opt_metadata ? opt_metadata : "metadata"); if (!g_file_query_exists (res_deploy, NULL) || !g_file_query_exists (metadata, NULL)) return flatpak_fail (error, _("Build directory %s not initialized, use flatpak build-init"), directory); if (!g_file_load_contents (metadata, cancellable, &metadata_contents, &metadata_size, NULL, error)) return FALSE; metakey = g_key_file_new (); if (!g_key_file_load_from_data (metakey, metadata_contents, metadata_size, 0, error)) return FALSE; if (g_key_file_has_group (metakey, FLATPAK_METADATA_GROUP_APPLICATION)) { group = FLATPAK_METADATA_GROUP_APPLICATION; is_app = TRUE; } else if (g_key_file_has_group (metakey, FLATPAK_METADATA_GROUP_RUNTIME)) { group = FLATPAK_METADATA_GROUP_RUNTIME; } else return flatpak_fail (error, _("metadata invalid, not application or runtime")); extensionof_ref = g_key_file_get_string (metakey, FLATPAK_METADATA_GROUP_EXTENSION_OF, FLATPAK_METADATA_KEY_REF, NULL); if (extensionof_ref != NULL) { is_extension = TRUE; if (g_str_has_prefix (extensionof_ref, "app/")) is_app_extension = TRUE; } extensionof_tag = g_key_file_get_string (metakey, FLATPAK_METADATA_GROUP_EXTENSION_OF, FLATPAK_METADATA_KEY_TAG, NULL); id = g_key_file_get_string (metakey, group, FLATPAK_METADATA_KEY_NAME, error); if (id == NULL) return FALSE; if (opt_runtime) runtime_key = FLATPAK_METADATA_KEY_RUNTIME; else runtime_key = FLATPAK_METADATA_KEY_SDK; runtime = g_key_file_get_string (metakey, group, runtime_key, error); if (runtime == NULL) return FALSE; runtime_ref = g_build_filename ("runtime", runtime, NULL); runtime_ref_parts = flatpak_decompose_ref (runtime_ref, error); if (runtime_ref_parts == NULL) return FALSE; custom_usr = FALSE; usr = g_file_get_child (res_deploy, opt_sdk_dir ? opt_sdk_dir : "usr"); if (g_file_query_exists (usr, cancellable)) { custom_usr = TRUE; runtime_files = g_object_ref (usr); } else { runtime_deploy = flatpak_find_deploy_for_ref (runtime_ref, NULL, cancellable, error); if (runtime_deploy == NULL) return FALSE; runtime_deploy_data = flatpak_deploy_get_deploy_data (runtime_deploy, FLATPAK_DEPLOY_VERSION_ANY, cancellable, error); if (runtime_deploy_data == NULL) return FALSE; runtime_metakey = flatpak_deploy_get_metadata (runtime_deploy); runtime_files = flatpak_deploy_get_files (runtime_deploy); } var = g_file_get_child (res_deploy, "var"); var_tmp = g_file_get_child (var, "tmp"); if (!flatpak_mkdir_p (var_tmp, cancellable, error)) return FALSE; var_lib = g_file_get_child (var, "lib"); if (!flatpak_mkdir_p (var_lib, cancellable, error)) return FALSE; res_files = g_file_get_child (res_deploy, "files"); if (is_app) { app_files = g_object_ref (res_files); if (opt_with_appdir) app_id_dir = flatpak_ensure_data_dir (id, cancellable, NULL); } else if (is_extension) { g_autoptr(GKeyFile) x_metakey = NULL; g_autofree char *x_group = NULL; g_autofree char *x_dir = NULL; g_autofree char *x_subdir_suffix = NULL; char *x_subdir = NULL; g_autofree char *bare_extension_point = NULL; extensionof_deploy = flatpak_find_deploy_for_ref (extensionof_ref, NULL, cancellable, error); if (extensionof_deploy == NULL) return FALSE; x_metakey = flatpak_deploy_get_metadata (extensionof_deploy); /* Since we have tagged extensions, it is possible that an extension could * be listed more than once in the "parent" flatpak. In that case, we should * try and disambiguate using the following rules: * * 1. Use the 'tag=' key in the ExtensionOfSection and if not found: * 2. Use the only extension point available if there is only one. * 3. If there are no matching groups, return NULL. * 4. In all other cases, error out. */ if (!find_matching_extension_group_in_metakey (x_metakey, id, extensionof_tag, &x_group, error)) return FALSE; if (x_group == NULL) { /* Failed, look for subdirectories=true parent */ char *last_dot = strrchr (id, '.'); if (last_dot != NULL) { char *parent_id = g_strndup (id, last_dot - id); if (!find_matching_extension_group_in_metakey (x_metakey, parent_id, extensionof_tag, &x_group, error)) return FALSE; if (x_group != NULL && g_key_file_get_boolean (x_metakey, x_group, FLATPAK_METADATA_KEY_SUBDIRECTORIES, NULL)) x_subdir = last_dot + 1; } if (x_subdir == NULL) return flatpak_fail (error, _("No extension point matching %s in %s"), id, extensionof_ref); } x_dir = g_key_file_get_string (x_metakey, x_group, FLATPAK_METADATA_KEY_DIRECTORY, error); if (x_dir == NULL) return FALSE; x_subdir_suffix = g_key_file_get_string (x_metakey, x_group, FLATPAK_METADATA_KEY_SUBDIRECTORY_SUFFIX, NULL); if (is_app_extension) { app_files = flatpak_deploy_get_files (extensionof_deploy); app_files_ro = TRUE; if (x_subdir != NULL) extension_tmpfs_point = g_build_filename ("/app", x_dir, NULL); bare_extension_point = g_build_filename ("/app", x_dir, x_subdir, NULL); } else { if (x_subdir != NULL) extension_tmpfs_point = g_build_filename ("/usr", x_dir, NULL); bare_extension_point = g_build_filename ("/usr", x_dir, x_subdir, NULL); } extension_point = g_build_filename (bare_extension_point, x_subdir_suffix, NULL); } app_context = flatpak_app_compute_permissions (metakey, runtime_metakey, error); if (app_context == NULL) return FALSE; flatpak_context_allow_host_fs (app_context); flatpak_context_merge (app_context, arg_context); minimal_envp = flatpak_run_get_minimal_env (TRUE, FALSE); bwrap = flatpak_bwrap_new (minimal_envp); flatpak_bwrap_add_args (bwrap, flatpak_get_bwrap (), NULL); run_flags = FLATPAK_RUN_FLAG_DEVEL | FLATPAK_RUN_FLAG_MULTIARCH | FLATPAK_RUN_FLAG_NO_SESSION_HELPER | FLATPAK_RUN_FLAG_SET_PERSONALITY | FLATPAK_RUN_FLAG_NO_A11Y_BUS_PROXY; if (opt_die_with_parent) run_flags |= FLATPAK_RUN_FLAG_DIE_WITH_PARENT; if (custom_usr) run_flags |= FLATPAK_RUN_FLAG_WRITABLE_ETC; run_flags |= flatpak_context_get_run_flags (app_context); /* Unless manually specified, we disable dbus proxy */ if (!flatpak_context_get_needs_session_bus_proxy (arg_context)) run_flags |= FLATPAK_RUN_FLAG_NO_SESSION_BUS_PROXY; if (!flatpak_context_get_needs_system_bus_proxy (arg_context)) run_flags |= FLATPAK_RUN_FLAG_NO_SYSTEM_BUS_PROXY; if (opt_log_session_bus) run_flags |= FLATPAK_RUN_FLAG_LOG_SESSION_BUS; if (opt_log_system_bus) run_flags |= FLATPAK_RUN_FLAG_LOG_SYSTEM_BUS; /* Never set up an a11y bus for builds */ run_flags |= FLATPAK_RUN_FLAG_NO_A11Y_BUS_PROXY; if (!flatpak_run_setup_base_argv (bwrap, runtime_files, app_id_dir, runtime_ref_parts[2], run_flags, error)) return FALSE; flatpak_bwrap_add_args (bwrap, (custom_usr && !opt_readonly) ? "--bind" : "--ro-bind", flatpak_file_get_path_cached (runtime_files), "/usr", NULL); if (!custom_usr) flatpak_bwrap_add_args (bwrap, "--lock-file", "/usr/.ref", NULL); if (app_files) flatpak_bwrap_add_args (bwrap, (app_files_ro || opt_readonly) ? "--ro-bind" : "--bind", flatpak_file_get_path_cached (app_files), "/app", NULL); else flatpak_bwrap_add_args (bwrap, "--dir", "/app", NULL); if (extension_tmpfs_point) flatpak_bwrap_add_args (bwrap, "--tmpfs", extension_tmpfs_point, NULL); /* We add the actual bind below so that we're not shadowed by other extensions or their tmpfs */ if (extension_point) dest = extension_point; else if (is_app) dest = g_strdup ("/app"); else dest = g_strdup ("/usr"); flatpak_bwrap_add_args (bwrap, "--setenv", "FLATPAK_DEST", dest, "--setenv", "FLATPAK_ID", id, "--setenv", "FLATPAK_ARCH", runtime_ref_parts[2], NULL); /* Persist some stuff in /var. We can't persist everything because that breaks /var things * from the host to work. For example the /home -> /var/home on atomic. * The interesting things to contain during the build is /var/tmp (for tempfiles shared during builds) * and things like /var/lib/rpm, if the installation uses packages. */ flatpak_bwrap_add_args (bwrap, "--bind", flatpak_file_get_path_cached (var_lib), "/var/lib", NULL); flatpak_bwrap_add_args (bwrap, "--bind", flatpak_file_get_path_cached (var_tmp), "/var/tmp", NULL); flatpak_run_apply_env_vars (bwrap, app_context); if (is_app) { /* We don't actually know the final branchname yet, so use "nobranch" as fallback to avoid unexpected matches. This means any extension point used at build time must have explicit versions to work. */ g_autofree char *fake_ref = g_strdup_printf ("app/%s/%s/nobranch", id, runtime_ref_parts[2]); if (!flatpak_run_add_extension_args (bwrap, metakey, fake_ref, FALSE, &app_extensions, cancellable, error)) return FALSE; } if (!custom_usr && !flatpak_run_add_extension_args (bwrap, runtime_metakey, runtime_ref, FALSE, &runtime_extensions, cancellable, error)) return FALSE; /* Mount this after the above extensions so we always win */ if (extension_point) flatpak_bwrap_add_args (bwrap, "--bind", flatpak_file_get_path_cached (res_files), extension_point, NULL); if (!flatpak_run_add_app_info_args (bwrap, app_files, NULL, app_extensions, runtime_files, runtime_deploy_data, runtime_extensions, id, NULL, runtime_ref, app_id_dir, app_context, NULL, FALSE, TRUE, TRUE, &app_info_path, &instance_id_host_dir, error)) return FALSE; if (!flatpak_run_add_environment_args (bwrap, app_info_path, run_flags, id, app_context, app_id_dir, NULL, cancellable, error)) return FALSE; for (i = 0; opt_bind_mounts != NULL && opt_bind_mounts[i] != NULL; i++) { char *split = strchr (opt_bind_mounts[i], '='); if (split == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Missing '=' in bind mount option '%s'"), opt_bind_mounts[i]); return FALSE; } *split++ = 0; flatpak_bwrap_add_args (bwrap, "--bind", split, opt_bind_mounts[i], NULL); } if (opt_build_dir != NULL) { flatpak_bwrap_add_args (bwrap, "--chdir", opt_build_dir, NULL); } if (!flatpak_bwrap_bundle_args (bwrap, 1, -1, FALSE, error)) return FALSE; flatpak_bwrap_add_args (bwrap, command, NULL); flatpak_bwrap_append_argsv (bwrap, &argv[rest_argv_start + 2], rest_argc - 2); g_ptr_array_add (bwrap->argv, NULL); g_snprintf (pid_str, sizeof (pid_str), "%d", getpid ()); pid_path = g_build_filename (instance_id_host_dir, "pid", NULL); g_file_set_contents (pid_path, pid_str, -1, NULL); /* Ensure we unset O_CLOEXEC */ child_setup (bwrap->fds); if (execvpe (flatpak_get_bwrap (), (char **) bwrap->argv->pdata, bwrap->envp) == -1) { g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), _("Unable to start app")); return FALSE; } /* Not actually reached... */ 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_path; g_autofree gchar *json = 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; GFileInfo *next = NULL; const char *platform_id = NULL; g_autofree char **orig_argv; gboolean is_run = FALSE; gboolean is_show_deps = FALSE; gboolean app_dir_is_empty = FALSE; g_autoptr(FlatpakContext) arg_context = 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_path = argv[argnr++]; if (!g_file_get_contents (manifest_path, &json, NULL, &error)) { g_printerr ("Can't load '%s': %s\n", manifest_path, error->message); return 1; } manifest = (BuilderManifest *) json_gobject_from_data (BUILDER_TYPE_MANIFEST, json, -1, &error); if (manifest == NULL) { g_printerr ("Can't parse '%s': %s\n", manifest_path, error->message); return 1; } if (is_run && argc == 3) return usage (context, "Program to run must be specified"); if (is_show_deps) { if (!builder_manifest_show_deps (manifest, &error)) { g_printerr ("Error running %s: %s\n", argv[3], error->message); return 1; } return 0; } manifest_file = g_file_new_for_path (manifest_path); base_dir = g_file_get_parent (manifest_file); app_dir = g_file_new_for_path (app_dir_path); build_context = builder_context_new (base_dir, app_dir); builder_context_set_keep_build_dirs (build_context, opt_keep_build_dirs); builder_context_set_sandboxed (build_context, opt_sandboxed); builder_context_set_jobs (build_context, opt_jobs); 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; } 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_finish_only && !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.\n", app_dir_path); return 1; } } if (opt_finish_only && app_dir_is_empty) { g_printerr ("App dir '%s' is empty or doesn't exist.\n", app_dir_path); return 1; } 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_disable_download && !builder_manifest_download (manifest, !opt_disable_updates, build_context, &error)) { g_printerr ("Failed to download sources: %s\n", error->message); return 1; } if (opt_download_only) return 0; cache_branch = g_path_get_basename (manifest_path); cache = builder_cache_new (builder_context_get_cache_dir (build_context), app_dir, cache_branch); if (!builder_cache_open (cache, &error)) { g_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) { 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, 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) { 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 (!opt_require_changes) builder_cache_ensure_checkout (cache); if (!opt_build_only && opt_repo && builder_cache_has_checkout (cache)) { g_autoptr(GFile) debuginfo_metadata = NULL; g_print ("Exporting %s to repo\n", builder_manifest_get_id (manifest)); if (!do_export (build_context, &error, builder_context_get_build_runtime (build_context), "--exclude=/lib/debug/*", "--include=/lib/debug/app", builder_context_get_separate_locales (build_context) ? "--exclude=/share/runtime/locale/*/*" : skip_arg, opt_repo, app_dir_path, builder_manifest_get_branch (manifest), 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, metadata_arg, files_arg, opt_repo, app_dir_path, builder_manifest_get_branch (manifest), 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, "--metadata=metadata.debuginfo", builder_context_get_build_runtime (build_context) ? "--files=usr/lib/debug" : "--files=files/lib/debug", opt_repo, app_dir_path, builder_manifest_get_branch (manifest), 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, "--metadata=metadata.platform", "--files=platform", builder_context_get_separate_locales (build_context) ? "--exclude=/share/runtime/locale/*/*" : skip_arg, opt_repo, app_dir_path, builder_manifest_get_branch (manifest), 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, metadata_arg, files_arg, opt_repo, app_dir_path, builder_manifest_get_branch (manifest), NULL)) { g_printerr ("Export failed: %s\n", error->message); return 1; } } } if (!builder_gc (cache, &error)) { g_warning ("Failed to GC build cache: %s\n", error->message); g_clear_error (&error); } return 0; }