forked from Mirrors/flatpak-builder
Add xdg-app dump-runtime command
This creates a tar of the runtime as set up by xdg-apptingping/wmclass
parent
7af7d61fa0
commit
b25830d8f9
|
@ -17,6 +17,7 @@ xdg_app_SOURCES = \
|
|||
app/xdg-app-builtins-list.c \
|
||||
app/xdg-app-builtins-run.c \
|
||||
app/xdg-app-builtins-enter.c \
|
||||
app/xdg-app-builtins-dump.c \
|
||||
app/xdg-app-builtins-build-init.c \
|
||||
app/xdg-app-builtins-build.c \
|
||||
app/xdg-app-builtins-build-finish.c \
|
||||
|
@ -26,6 +27,6 @@ xdg_app_SOURCES = \
|
|||
$(xdp_dbus_built_sources) \
|
||||
$(NULL)
|
||||
|
||||
xdg_app_LDADD = $(BASE_LIBS) $(OSTREE_LIBS) $(SOUP_LIBS) libglnx.la libxdgapp.la
|
||||
xdg_app_CFLAGS = $(BASE_CFLAGS) $(OSTREE_CFLAGS) $(SOUP_CFLAGS)
|
||||
xdg_app_LDADD = $(BASE_LIBS) $(OSTREE_LIBS) $(SOUP_LIBS) $(LIBARCHIVE_LIBS) libglnx.la libxdgapp.la
|
||||
xdg_app_CFLAGS = $(BASE_CFLAGS) $(OSTREE_CFLAGS) $(SOUP_CFLAGS) $(LIBARCHIVE_CFLAGS)
|
||||
|
||||
|
|
|
@ -0,0 +1,309 @@
|
|||
/*
|
||||
* Copyright © 2014 Red Hat, Inc
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <locale.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libgsystem.h"
|
||||
#include "libglnx/libglnx.h"
|
||||
|
||||
#include "xdg-app-builtins.h"
|
||||
#include "xdg-app-utils.h"
|
||||
|
||||
static char *opt_arch;
|
||||
static char *opt_file;
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{ "arch", 0, 0, G_OPTION_ARG_STRING, &opt_arch, "Arch to make current for", "ARCH" },
|
||||
{ "file", 0, 0, G_OPTION_ARG_STRING, &opt_file, "Write to file instead of stdout", "PATH" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
#ifdef HAVE_LIBARCHIVE
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
|
||||
typedef struct archive write_archive_t;
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(write_archive_t, archive_write_free);
|
||||
|
||||
typedef struct archive_entry archive_entry_t;
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(archive_entry_t, archive_entry_free);
|
||||
|
||||
static gboolean
|
||||
dump_data (GFile *file,
|
||||
struct archive *archive,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
char buffer[32*1024];
|
||||
g_autoptr(GFileInputStream) in = NULL;
|
||||
gssize in_buffer;
|
||||
|
||||
in = g_file_read (file, cancellable, error);
|
||||
if (in == NULL)
|
||||
return FALSE;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
in_buffer = g_input_stream_read (G_INPUT_STREAM (in), buffer, sizeof (buffer), cancellable, error);
|
||||
if (in_buffer == -1)
|
||||
return FALSE;
|
||||
|
||||
if (in_buffer == 0)
|
||||
break;
|
||||
|
||||
if (archive_write_data (archive, buffer, in_buffer) < ARCHIVE_OK)
|
||||
return xdg_app_fail (error, "Can't write tar data");
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dump_files (GFile *dir,
|
||||
struct archive *archive,
|
||||
GCancellable *cancellable,
|
||||
char *parent,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GFileEnumerator) fe = NULL;
|
||||
gboolean ret = TRUE;
|
||||
GFileType type;
|
||||
|
||||
fe = g_file_enumerate_children (dir,
|
||||
"standard::name,standard::type,standard::is-symlink,standard::symlink-target,unix::mode,time::*",
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error);
|
||||
if (fe == NULL)
|
||||
return FALSE;
|
||||
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
g_autoptr(GFileInfo) info = g_file_enumerator_next_file (fe, cancellable, error);
|
||||
g_autofree char *path = NULL;
|
||||
g_autoptr(GFile) child = NULL;
|
||||
guint32 mode;
|
||||
g_autoptr(archive_entry_t) entry = archive_entry_new2 (archive);
|
||||
|
||||
if (!info)
|
||||
{
|
||||
if (error && *error != NULL)
|
||||
ret = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
type = g_file_info_get_file_type (info);
|
||||
mode = g_file_info_get_attribute_uint32 (info, "unix::mode");
|
||||
path = g_build_filename (parent, g_file_info_get_name (info), NULL);
|
||||
child = g_file_enumerator_get_child (fe, info);
|
||||
|
||||
archive_entry_set_pathname (entry, path);
|
||||
archive_entry_set_uid(entry, 0);
|
||||
archive_entry_set_gid(entry, 0);
|
||||
archive_entry_set_perm(entry, mode & 0777);
|
||||
archive_entry_set_mtime(entry, 0, 0);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case G_FILE_TYPE_SYMBOLIC_LINK:
|
||||
archive_entry_set_filetype (entry, AE_IFLNK);
|
||||
archive_entry_set_symlink (entry, g_file_info_get_symlink_target (info));
|
||||
break;
|
||||
|
||||
case G_FILE_TYPE_REGULAR:
|
||||
archive_entry_set_filetype (entry, AE_IFREG);
|
||||
archive_entry_set_size(entry, g_file_info_get_size (info));
|
||||
break;
|
||||
|
||||
case G_FILE_TYPE_DIRECTORY:
|
||||
archive_entry_set_filetype (entry, AE_IFDIR);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_error ("Unhandled type %d\n", type);
|
||||
break;
|
||||
}
|
||||
|
||||
if (archive_write_header (archive, entry) < ARCHIVE_OK)
|
||||
return xdg_app_fail (error, "Can't write tar header");
|
||||
|
||||
if (type == G_FILE_TYPE_REGULAR)
|
||||
{
|
||||
if (!dump_data (child, archive, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (archive_write_finish_entry (archive) < ARCHIVE_OK)
|
||||
return xdg_app_fail (error, "Can't finish tar entry");
|
||||
|
||||
if (type == G_FILE_TYPE_DIRECTORY)
|
||||
{
|
||||
if (!dump_files (child, archive, cancellable, path, error))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *extra_dirs[] = {
|
||||
"app",
|
||||
"dev",
|
||||
"home",
|
||||
"proc",
|
||||
"run",
|
||||
"run/host",
|
||||
"run/dbus",
|
||||
"run/media",
|
||||
"run/user",
|
||||
"sys",
|
||||
"usr",
|
||||
"tmp",
|
||||
"var",
|
||||
};
|
||||
|
||||
static struct {const char *path; const char *target; } extra_symlinks[] = {
|
||||
{"bin", "usr/bin" },
|
||||
{"sbin", "usr/sbin" },
|
||||
{"etc", "usr/etc" },
|
||||
{"lib", "usr/lib" },
|
||||
{"lib32", "usr/lib32" },
|
||||
{"lib64", "usr/lib64" },
|
||||
{"var/run", "/run" },
|
||||
{"var/tmp", "/tmp" },
|
||||
};
|
||||
|
||||
static gboolean
|
||||
dump_runtime (GFile *root, GCancellable *cancellable, GError **error)
|
||||
{
|
||||
int i;
|
||||
|
||||
g_autoptr(write_archive_t) archive = NULL;
|
||||
g_autoptr(GFile) files = g_file_get_child (root, "files");
|
||||
|
||||
archive = archive_write_new ();
|
||||
if (archive == NULL)
|
||||
return xdg_app_fail (error, "Can't allocate archive");
|
||||
|
||||
if (archive_write_set_format_gnutar (archive) < ARCHIVE_OK)
|
||||
return xdg_app_fail (error, "Can't set tar format");
|
||||
|
||||
if (archive_write_open_FILE (archive, stdout) < ARCHIVE_OK)
|
||||
return xdg_app_fail (error, "can't open stdout");
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(extra_dirs); i++)
|
||||
{
|
||||
g_autoptr(archive_entry_t) entry = archive_entry_new2 (archive);
|
||||
|
||||
archive_entry_set_pathname (entry, extra_dirs[i]);
|
||||
archive_entry_set_uid(entry, 0);
|
||||
archive_entry_set_gid(entry, 0);
|
||||
archive_entry_set_perm(entry, 0755);
|
||||
archive_entry_set_mtime(entry, 0, 0);
|
||||
archive_entry_set_filetype (entry, AE_IFDIR);
|
||||
|
||||
if (archive_write_header (archive, entry) < ARCHIVE_OK)
|
||||
return xdg_app_fail (error, "Can't write tar header");
|
||||
}
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(extra_symlinks); i++)
|
||||
{
|
||||
g_autoptr(archive_entry_t) entry = NULL;
|
||||
g_autoptr(GFile) dest = g_file_resolve_relative_path (files, extra_symlinks[i].target);
|
||||
|
||||
if (g_str_has_prefix (extra_symlinks[i].target, "usr/"))
|
||||
{
|
||||
g_autoptr(GFile) dest = g_file_resolve_relative_path (files, extra_symlinks[i].target + 4);
|
||||
|
||||
if (!g_file_query_exists (dest, cancellable))
|
||||
continue;
|
||||
}
|
||||
|
||||
entry = archive_entry_new2 (archive);
|
||||
|
||||
archive_entry_set_pathname (entry, extra_symlinks[i].path);
|
||||
archive_entry_set_uid(entry, 0);
|
||||
archive_entry_set_gid(entry, 0);
|
||||
archive_entry_set_perm(entry, 0755);
|
||||
archive_entry_set_mtime(entry, 0, 0);
|
||||
archive_entry_set_filetype (entry, AE_IFLNK);
|
||||
archive_entry_set_symlink (entry, extra_symlinks[i].target);
|
||||
|
||||
if (archive_write_header (archive, entry) < ARCHIVE_OK)
|
||||
return xdg_app_fail (error, "Can't write tar header");
|
||||
}
|
||||
|
||||
if (!dump_files (files, archive, cancellable, "usr", error))
|
||||
return FALSE;
|
||||
|
||||
if (archive_write_close (archive) < ARCHIVE_OK)
|
||||
return xdg_app_fail (error, "can't close archive");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
gboolean
|
||||
xdg_app_builtin_dump_runtime (int argc, char **argv, GCancellable *cancellable, GError **error)
|
||||
{
|
||||
g_autoptr(GOptionContext) context = NULL;
|
||||
g_autoptr(XdgAppDir) dir = NULL;
|
||||
const char *runtime;
|
||||
const char *branch = "master";
|
||||
g_autofree char *ref = NULL;
|
||||
OstreeRepo *repo;
|
||||
g_autofree char *commit = NULL;
|
||||
g_autoptr(GFile) root = NULL;
|
||||
|
||||
context = g_option_context_new ("RUNTIME BRANCH - Make branch of application current");
|
||||
|
||||
if (!xdg_app_option_context_parse (context, options, &argc, &argv, 0, &dir, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (argc < 3)
|
||||
return usage_error (context, "RUNTIME and BRANCH must be specified", error);
|
||||
|
||||
runtime = argv[1];
|
||||
branch = argv[2];
|
||||
|
||||
if (!xdg_app_is_valid_name (runtime))
|
||||
return xdg_app_fail (error, "'%s' is not a valid name", runtime);
|
||||
|
||||
if (!xdg_app_is_valid_branch (branch))
|
||||
return xdg_app_fail (error, "'%s' is not a valid branch name", branch);
|
||||
|
||||
ref = xdg_app_build_runtime_ref (runtime, branch, opt_arch);
|
||||
|
||||
repo = xdg_app_dir_get_repo (dir);
|
||||
|
||||
if (!ostree_repo_read_commit (repo, ref,
|
||||
&root, &commit, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
#ifdef HAVE_LIBARCHIVE
|
||||
return dump_runtime (root, cancellable, error);
|
||||
#else
|
||||
return xdg_app_fail (error, "Build without libarchive");
|
||||
#endif
|
||||
}
|
|
@ -71,6 +71,7 @@ BUILTINPROTO(build_export);
|
|||
BUILTINPROTO(repo_update);
|
||||
BUILTINPROTO(export_file);
|
||||
BUILTINPROTO(override);
|
||||
BUILTINPROTO(dump_runtime);
|
||||
|
||||
#undef BUILTINPROTO
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@ static XdgAppCommand commands[] = {
|
|||
{ "build", xdg_app_builtin_build },
|
||||
{ "build-finish", xdg_app_builtin_build_finish },
|
||||
{ "build-export", xdg_app_builtin_build_export },
|
||||
{ "dump-runtime", xdg_app_builtin_dump_runtime },
|
||||
{ "repo-update", xdg_app_builtin_repo_update },
|
||||
{ NULL }
|
||||
};
|
||||
|
|
|
@ -23,8 +23,8 @@ _xdg-app() {
|
|||
local dir cmd sdk loc
|
||||
|
||||
local -A VERBS=(
|
||||
[ALL]='add-remote modify-remote delete-remote ls-remote list-remotes install-runtime update-runtime uninstall-runtime list-runtimes install-app update-app uninstall-app list-apps run override enter export-file build-init build build-finish build-export repo-update make-app-current'
|
||||
[MODE]='add-remote modify-remote delete-remote ls-remote list-remotes install-runtime update-runtime uninstall-runtime list-runtimes install-app update-app uninstall-app list-apps make-app-current'
|
||||
[ALL]='add-remote modify-remote delete-remote ls-remote list-remotes install-runtime update-runtime uninstall-runtime list-runtimes install-app update-app uninstall-app list-apps run override enter export-file build-init build build-finish build-export repo-update make-app-current dump-runtime'
|
||||
[MODE]='add-remote modify-remote delete-remote ls-remote list-remotes install-runtime update-runtime uninstall-runtime list-runtimes install-app update-app uninstall-app list-apps make-app-current dump-runtime'
|
||||
[PERMS]='run override build build-finish'
|
||||
[UNINSTALL]='uninstall-runtime uninstall-app'
|
||||
[ARCH]='build-init install-runtime install-app run uninstall-runtime uninstall-app update-runtime update-app make-app-current'
|
||||
|
@ -240,7 +240,7 @@ _xdg-app() {
|
|||
comps=''
|
||||
;;
|
||||
|
||||
update-runtime|uninstall-runtime)
|
||||
update-runtime|uninstall-runtime|dump-runtime)
|
||||
if [[ -z $name ]]; then
|
||||
comps=$(xdg-app $mode list-runtimes)
|
||||
else
|
||||
|
|
28
configure.ac
28
configure.ac
|
@ -108,6 +108,34 @@ AC_ARG_ENABLE(sudo,
|
|||
[SUDO_BIN="sudo"], [SUDO_BIN=""])
|
||||
AC_SUBST([SUDO_BIN])
|
||||
|
||||
LIBARCHIVE_DEPENDENCY="libarchive >= 2.8.0"
|
||||
|
||||
AC_ARG_WITH(libarchive,
|
||||
AS_HELP_STRING([--without-libarchive], [Do not use libarchive]),
|
||||
:, with_libarchive=maybe)
|
||||
|
||||
AS_IF([ test x$with_libarchive != xno ], [
|
||||
AC_MSG_CHECKING([for $LIBARCHIVE_DEPENDENCY])
|
||||
PKG_CHECK_EXISTS($LIBARCHIVE_DEPENDENCY, have_libarchive=yes, have_libarchive=no)
|
||||
AC_MSG_RESULT([$have_libarchive])
|
||||
AS_IF([ test x$have_libarchive = xno && test x$with_libarchive != xmaybe ], [
|
||||
AC_MSG_ERROR([libarchive is enabled but could not be found])
|
||||
])
|
||||
AS_IF([ test x$have_libarchive = xyes], [
|
||||
AC_DEFINE([HAVE_LIBARCHIVE], 1, [Define if we have libarchive.pc])
|
||||
PKG_CHECK_MODULES(LIBARCHIVE, $LIBARCHIVE_DEPENDENCY)
|
||||
save_LIBS=$LIBS
|
||||
LIBS=$LIBARCHIVE_LIBS
|
||||
AC_CHECK_FUNCS(archive_read_support_filter_all)
|
||||
LIBS=$save_LIBS
|
||||
with_libarchive=yes
|
||||
], [
|
||||
with_libarchive=no
|
||||
])
|
||||
], [ with_libarchive=no ])
|
||||
AM_CONDITIONAL(USE_LIBARCHIVE, test $with_libarchive != no)
|
||||
|
||||
|
||||
AC_ARG_ENABLE(documentation,
|
||||
AC_HELP_STRING([--enable-documentation], [Build documentation]),,
|
||||
enable_documentation=yes)
|
||||
|
|
Loading…
Reference in New Issue