Add initial version of run command

tingping/wmclass
Alexander Larsson 2014-12-18 17:51:37 +01:00
parent 3b53ae6489
commit 13261318e0
6 changed files with 199 additions and 4 deletions

View File

@ -2,6 +2,7 @@ NULL =
AM_CPPFLAGS = \
-DXDG_APP_BASEDIR=\"$(datadir)/xdg-app\" \
-DHELPER=\"$(bindir)/xdg-app-helper\" \
$(NULL)
bin_PROGRAMS = \
@ -17,6 +18,7 @@ xdg_app_SOURCES = \
xdg-app-builtins-add-repo.c \
xdg-app-builtins-install.c \
xdg-app-builtins-update.c \
xdg-app-builtins-run.c \
xdg-app-dir.c \
xdg-app-dir.h \
xdg-app-utils.h \

View File

@ -0,0 +1,174 @@
#include "config.h"
#include <locale.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include "libgsystem.h"
#include "xdg-app-builtins.h"
#include "xdg-app-utils.h"
static char *opt_arch;
static char *opt_branch;
static gchar **opt_rest = NULL;
static GOptionEntry options[] = {
{ "arch", 0, 0, G_OPTION_ARG_STRING, &opt_arch, "Arch to install for", NULL },
{ "branch", 0, 0, G_OPTION_ARG_STRING, &opt_branch, "Branch to run", NULL },
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_rest,
"Special option that collects any remaining arguments for us" },
{ 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_run (int argc, char **argv, GCancellable *cancellable, GError **error)
{
GOptionContext *context;
gboolean ret = FALSE;
gs_unref_object XdgAppDir *user_dir = NULL;
gs_unref_object XdgAppDir *system_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 *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 *app;
const char *branch = "master";
int i;
context = g_option_context_new ("APP COMMAND - Run an app");
if (!xdg_app_option_context_parse (context, options, &argc, &argv, XDG_APP_BUILTIN_FLAG_NO_DIR, NULL, cancellable, error))
goto out;
if (g_strv_length (opt_rest) < 2)
{
usage_error (context, "APP and COMMAND must be specified", error);
goto out;
}
app = opt_rest[0];
if (opt_branch)
branch = opt_branch;
app_ref = xdg_app_build_app_ref (app, branch, opt_arch);
user_dir = xdg_app_dir_get_user ();
system_dir = xdg_app_dir_get_system ();
app_deploy = xdg_app_dir_get_if_deployed (user_dir, app_ref, NULL, cancellable);
if (app_deploy == NULL)
app_deploy = xdg_app_dir_get_if_deployed (system_dir, app_ref, NULL, cancellable);
if (app_deploy == NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "App %s branch %s not installed", app, branch);
goto out;
}
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", "runtime", error);
if (runtime == NULL)
goto out;
runtime_ref = g_build_filename ("runtime", runtime, NULL);
runtime_deploy = xdg_app_dir_get_if_deployed (user_dir, runtime_ref, NULL, cancellable);
if (runtime_deploy == NULL)
runtime_deploy = xdg_app_dir_get_if_deployed (system_dir, runtime_ref, NULL, cancellable);
if (runtime_deploy == NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Required runtime %s not installed", runtime);
goto out;
}
if (!xdg_app_dir_ensure_path (user_dir, cancellable, error))
goto out;
var = xdg_app_dir_get_app_data (user_dir, app);
if (!gs_file_ensure_directory (var, TRUE, cancellable, error))
goto out;
var_tmp = g_file_get_child (var, "tmp");
var_run = g_file_get_child (var, "run");
if (!g_file_make_symbolic_link (var_tmp, "/tmp", cancellable, &my_error) &&
!g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_EXISTS))
{
g_propagate_error (error, my_error);
my_error = NULL;
goto out;
}
if (!g_file_make_symbolic_link (var_run, "/run", cancellable, &my_error2) &&
!g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_EXISTS))
{
g_propagate_error (error, my_error2);
my_error2 = NULL;
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 ();
g_ptr_array_add (argv_array, HELPER);
g_ptr_array_add (argv_array, "-i");
g_ptr_array_add (argv_array, "-a");
g_ptr_array_add (argv_array, (char *)gs_file_get_path_cached (app_files));
g_ptr_array_add (argv_array, "-v");
g_ptr_array_add (argv_array, (char *)gs_file_get_path_cached (var));
g_ptr_array_add (argv_array, (char *)gs_file_get_path_cached (runtime_files));
for (i = 1; opt_rest[i] != NULL; i++)
g_ptr_array_add (argv_array, opt_rest[i]);
g_ptr_array_add (argv_array, NULL);
if (!execve (HELPER, (char **)argv_array->pdata, NULL))
{
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;
}

View File

@ -29,6 +29,7 @@ BUILTINPROTO(install_runtime);
BUILTINPROTO(update_runtime);
BUILTINPROTO(install_app);
BUILTINPROTO(update_app);
BUILTINPROTO(run);
#undef BUILTINPROTO

View File

@ -388,6 +388,23 @@ xdg_app_dir_deploy (XdgAppDir *self,
return ret;
}
GFile *
xdg_app_dir_get_if_deployed (XdgAppDir *self,
const char *ref,
const char *hash,
GCancellable *cancellable)
{
gs_unref_object GFile *deploy_base = NULL;
gs_unref_object GFile *deploy_dir = NULL;
deploy_base = xdg_app_dir_get_deploy_dir (self, ref);
deploy_dir = g_file_get_child (deploy_base, hash ? hash : "latest");
if (g_file_query_file_type (deploy_dir, G_FILE_QUERY_INFO_NONE, cancellable) == G_FILE_TYPE_DIRECTORY)
return g_object_ref (deploy_dir);
return NULL;
}
XdgAppDir*
xdg_app_dir_new (GFile *path, gboolean user)
{

View File

@ -31,6 +31,10 @@ gboolean xdg_app_dir_is_user (XdgAppDir *self);
GFile * xdg_app_dir_get_path (XdgAppDir *self);
GFile * xdg_app_dir_get_deploy_dir (XdgAppDir *self,
const char *ref);
GFile * xdg_app_dir_get_if_deployed(XdgAppDir *self,
const char *ref,
const char *hash,
GCancellable *cancellable);
GFile * xdg_app_dir_get_app_data (XdgAppDir *self,
const char *app);
OstreeRepo *xdg_app_dir_get_repo (XdgAppDir *self);

View File

@ -24,6 +24,7 @@ static XdgAppCommand commands[] = {
{ "update-runtime", xdg_app_builtin_update_runtime },
{ "install-app", xdg_app_builtin_install_app },
{ "update-app", xdg_app_builtin_update_app },
{ "run", xdg_app_builtin_run },
{ NULL }
};
@ -180,10 +181,6 @@ xdg_app_run (int argc,
continue;
}
}
else if (g_str_equal (argv[in], "--"))
{
break;
}
argv[out] = argv[in];
}