diff --git a/Makefile.am b/Makefile.am index b33fcdda..c0d50b6b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -20,6 +20,7 @@ xdg_app_SOURCES = \ xdg-app-builtins-update.c \ xdg-app-builtins-run.c \ xdg-app-builtins-build-init.c \ + xdg-app-builtins-build.c \ xdg-app-dir.c \ xdg-app-dir.h \ xdg-app-utils.h \ diff --git a/xdg-app-builtins-build.c b/xdg-app-builtins-build.c new file mode 100644 index 00000000..28d48b62 --- /dev/null +++ b/xdg-app-builtins-build.c @@ -0,0 +1,174 @@ +#include "config.h" + +#include +#include +#include +#include +#include + +#include "libgsystem.h" + +#include "xdg-app-builtins.h" +#include "xdg-app-utils.h" + +static gboolean opt_runtime; +static gboolean opt_network; +static gboolean opt_x11; + +static GOptionEntry options[] = { + { "runtime", 'r', 0, G_OPTION_ARG_NONE, &opt_runtime, "Use non-devel runtime", NULL }, + { "network", 'n', 0, G_OPTION_ARG_NONE, &opt_network, "Allow network access", NULL }, + { "x11", 'x', 0, G_OPTION_ARG_NONE, &opt_x11, "Allow x11 access", NULL }, + { NULL } +}; + +static void +usage_error (GOptionContext *context, const char *message, GError **error) +{ + gs_free gchar *help = g_option_context_get_help (context, TRUE, NULL); + g_printerr ("%s", help); + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, message); +} + +#define _gs_unref_keyfile __attribute__ ((cleanup(gs_local_keyfile_unref))) + +gboolean +xdg_app_builtin_build (int argc, char **argv, GCancellable *cancellable, GError **error) +{ + GOptionContext *context; + gboolean ret = FALSE; + gs_unref_object XdgAppDir *user_dir = NULL; + gs_unref_variant_builder GVariantBuilder *optbuilder = NULL; + gs_unref_object GFile *deploy_base = NULL; + gs_unref_object GFile *var = NULL; + gs_unref_object GFile *var_tmp = NULL; + gs_unref_object GFile *var_run = NULL; + gs_unref_object GFile *app_deploy = NULL; + gs_unref_object GFile *app_files = NULL; + gs_unref_object GFile *runtime_deploy = NULL; + gs_unref_object GFile *runtime_files = NULL; + gs_unref_object GFile *metadata = NULL; + gs_free char *metadata_contents = NULL; + gs_free char *runtime = NULL; + gs_free char *default_command = NULL; + gs_free char *runtime_ref = NULL; + gs_free char *app_ref = NULL; + _gs_unref_keyfile GKeyFile *metakey = NULL; + gs_free_error GError *my_error = NULL; + gs_free_error GError *my_error2 = NULL; + gs_unref_ptrarray GPtrArray *argv_array = NULL; + gsize metadata_size; + const char *directory = NULL; + const char *command = "/bin/sh"; + int i; + int rest_argv_start, rest_argc; + + context = g_option_context_new ("DIRECTORY [COMMAND [args...]] - Build in directory"); + + 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; + } + } + + if (rest_argc == 0) + { + usage_error (context, "DIRECTORY must be specified", error); + goto out; + } + + + if (!xdg_app_option_context_parse (context, options, &argc, &argv, XDG_APP_BUILTIN_FLAG_NO_DIR, NULL, cancellable, error)) + goto out; + + directory = argv[rest_argv_start]; + if (rest_argc >= 2) + command = argv[rest_argv_start+1]; + + app_deploy = g_file_new_for_commandline_arg (directory); + + metadata = g_file_get_child (app_deploy, "metadata"); + if (!g_file_load_contents (metadata, cancellable, &metadata_contents, &metadata_size, NULL, error)) + goto out; + + metakey = g_key_file_new (); + if (!g_key_file_load_from_data (metakey, metadata_contents, metadata_size, 0, error)) + goto out; + + runtime = g_key_file_get_string (metakey, "Application", opt_runtime ? "runtime" : "sdk", error); + if (runtime == NULL) + goto out; + + runtime_ref = g_build_filename ("runtime", runtime, NULL); + + runtime_deploy = xdg_app_find_deploy_dir_for_ref (runtime_ref, cancellable, error); + if (runtime_deploy == NULL) + goto out; + + var = g_file_get_child (app_deploy, "var"); + if (!gs_file_ensure_directory (var, TRUE, cancellable, error)) + goto out; + + app_files = g_file_get_child (app_deploy, "files"); + runtime_files = g_file_get_child (runtime_deploy, "files"); + + argv_array = g_ptr_array_new_with_free_func (g_free); + g_ptr_array_add (argv_array, g_strdup (HELPER)); + + g_ptr_array_add (argv_array, g_strdup ("-i")); + g_ptr_array_add (argv_array, g_strdup ("-f")); + g_ptr_array_add (argv_array, g_strdup ("-H")); + + if (opt_network) + g_ptr_array_add (argv_array, g_strdup ("-n")); + + if (opt_x11) + xdg_app_run_add_x11_args (argv_array); + else + xdg_app_run_add_no_x11_args (argv_array); + + g_ptr_array_add (argv_array, g_strdup ("-w")); + g_ptr_array_add (argv_array, g_strdup ("-a")); + g_ptr_array_add (argv_array, g_file_get_path (app_files)); + g_ptr_array_add (argv_array, g_strdup ("-v")); + g_ptr_array_add (argv_array, g_file_get_path (var)); + g_ptr_array_add (argv_array, g_file_get_path (runtime_files)); + + g_ptr_array_add (argv_array, g_strdup (command)); + for (i = 2; i < rest_argc; i++) + g_ptr_array_add (argv_array, g_strdup (argv[rest_argv_start + i])); + + g_ptr_array_add (argv_array, NULL); + + g_setenv ("ACLOCAL_PATH", "/self/share/aclocal", TRUE); + g_setenv ("C_INCLUDE_PATH", "/self/include", TRUE); + g_setenv ("CPLUS_INCLUDE_PATH", "/self/include", TRUE); + g_setenv ("GI_TYPELIB_PATH", "/self/lib/girepository-1.0", TRUE); + g_setenv ("LDFLAGS", "-L/self/lib ", TRUE); + g_setenv ("PKG_CONFIG_PATH", "/self/lib/pkgconfig:/self/share/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig", TRUE); + + g_setenv ("XDG_DATA_DIRS", "/self/share:/usr/share", TRUE); + g_unsetenv ("LD_LIBRARY_PATH"); + g_setenv ("PATH", "/self/bin:/usr/bin", TRUE); + + if (!execv (HELPER, (char **)argv_array->pdata)) + { + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "Unable to start app"); + goto out; + } + + /* Not actually reached... */ + ret = TRUE; + + out: + if (context) + g_option_context_free (context); + return ret; +} diff --git a/xdg-app-builtins-run.c b/xdg-app-builtins-run.c index df75e9a0..3903c5c6 100644 --- a/xdg-app-builtins-run.c +++ b/xdg-app-builtins-run.c @@ -20,7 +20,7 @@ static GOptionEntry options[] = { { "arch", 0, 0, G_OPTION_ARG_STRING, &opt_arch, "Arch to use", NULL }, { "command", 0, 0, G_OPTION_ARG_STRING, &opt_command, "Command to run", NULL }, { "branch", 0, 0, G_OPTION_ARG_STRING, &opt_branch, "Branch to run", NULL }, - { "devel", 0, 0, G_OPTION_ARG_NONE, &opt_devel, "Use development runtime", NULL }, + { "devel", 'd', 0, G_OPTION_ARG_NONE, &opt_devel, "Use development runtime", NULL }, { NULL } }; @@ -56,7 +56,7 @@ extract_unix_path_from_dbus_addres (const char *address) return g_strndup (path, path_end - path); } -static void +void xdg_app_run_add_x11_args (GPtrArray *argv_array) { char *x11_socket = NULL; @@ -79,13 +79,13 @@ xdg_app_run_add_x11_args (GPtrArray *argv_array) } } -static void +void xdg_app_run_add_no_x11_args (GPtrArray *argv_array) { g_unsetenv ("DISPLAY"); } -static void +void xdg_app_run_add_pulseaudio_args (GPtrArray *argv_array) { char *pulseaudio_socket = g_build_filename (g_get_user_runtime_dir (), "pulse/native", NULL); @@ -96,7 +96,7 @@ xdg_app_run_add_pulseaudio_args (GPtrArray *argv_array) } } -static void +void xdg_app_run_add_system_dbus_args (GPtrArray *argv_array) { const char *dbus_address = g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"); @@ -116,7 +116,7 @@ xdg_app_run_add_system_dbus_args (GPtrArray *argv_array) } } -static void +void xdg_app_run_add_session_dbus_args (GPtrArray *argv_array) { const char *dbus_address = g_getenv ("DBUS_SESSION_BUS_ADDRESS"); diff --git a/xdg-app-builtins.h b/xdg-app-builtins.h index af873d54..ebcaa40b 100644 --- a/xdg-app-builtins.h +++ b/xdg-app-builtins.h @@ -31,9 +31,16 @@ BUILTINPROTO(install_app); BUILTINPROTO(update_app); BUILTINPROTO(run); BUILTINPROTO(build_init); +BUILTINPROTO(build); #undef BUILTINPROTO +void xdg_app_run_add_x11_args (GPtrArray *argv_array); +void xdg_app_run_add_no_x11_args (GPtrArray *argv_array); +void xdg_app_run_add_pulseaudio_args (GPtrArray *argv_array); +void xdg_app_run_add_system_dbus_args (GPtrArray *argv_array); +void xdg_app_run_add_session_dbus_args (GPtrArray *argv_array); + G_END_DECLS #endif /* __XDG_APP_BUILTINS_H__ */ diff --git a/xdg-app-main.c b/xdg-app-main.c index b4726de5..167659e6 100644 --- a/xdg-app-main.c +++ b/xdg-app-main.c @@ -26,6 +26,7 @@ static XdgAppCommand commands[] = { { "update-app", xdg_app_builtin_update_app }, { "run", xdg_app_builtin_run }, { "build-init", xdg_app_builtin_build_init }, + { "build", xdg_app_builtin_build }, { NULL } }; diff --git a/xdg-app-utils.h b/xdg-app-utils.h index 4e4dcdc4..9df49f87 100644 --- a/xdg-app-utils.h +++ b/xdg-app-utils.h @@ -18,5 +18,4 @@ GFile * xdg_app_find_deploy_dir_for_ref (const char *ref, GCancellable *cancellable, GError **error); - #endif /* __XDG_APP_UTILS_H__ */