[gnome-builder/wip/cosimoc/flatpak-greeter: 2/9] Add support for archive sources
- From: Cosimo Cecchi <cosimoc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/cosimoc/flatpak-greeter: 2/9] Add support for archive sources
- Date: Sat, 17 Dec 2016 08:48:18 +0000 (UTC)
commit 6c96b821d54a197e782347087b1dc672614ba829
Author: Simon Schampijer <simon schampijer endlessm com>
Date: Fri Dec 16 16:33:05 2016 -0800
Add support for archive sources
This work is heavily based on the archive sources support
in flatpak-builder.
plugins/flatpak/Makefile.am | 6 +-
plugins/flatpak/configure.ac | 3 +
plugins/flatpak/gbp-flatpak-clone-widget.c | 6 +
plugins/flatpak/gbp-flatpak-source-archive.c | 550 ++++++++++++++++++++++++++
plugins/flatpak/gbp-flatpak-source-archive.h | 28 ++
5 files changed, 591 insertions(+), 2 deletions(-)
---
diff --git a/plugins/flatpak/Makefile.am b/plugins/flatpak/Makefile.am
index 935f59f..a9f208d 100644
--- a/plugins/flatpak/Makefile.am
+++ b/plugins/flatpak/Makefile.am
@@ -25,14 +25,16 @@ libflatpak_plugin_la_SOURCES = \
gbp-flatpak-clone-widget.h \
gbp-flatpak-genesis-addin.c \
gbp-flatpak-genesis-addin.h \
+ gbp-flatpak-source-archive.c \
+ gbp-flatpak-source-archive.h \
$(NULL)
nodist_libflatpak_plugin_la_SOURCES = \
gbp-flatpak-resources.c \
gbp-flatpak-resources.h
-libflatpak_plugin_la_CFLAGS = $(PLUGIN_CFLAGS) $(FLATPAK_CFLAGS) $(GIT_CFLAGS)
-libflatpak_plugin_la_LIBADD = $(FLATPAK_LIBS) $(GIT_LIBS)
+libflatpak_plugin_la_CFLAGS = $(PLUGIN_CFLAGS) $(FLATPAK_CFLAGS) $(GIT_CFLAGS) $(SOUP_CFLAGS)
+libflatpak_plugin_la_LIBADD = $(FLATPAK_LIBS) $(GIT_LIBS) $(SOUP_LIBS)
libflatpak_plugin_la_LDFLAGS = $(PLUGIN_LDFLAGS)
glib_resources_c = gbp-flatpak-resources.c
diff --git a/plugins/flatpak/configure.ac b/plugins/flatpak/configure.ac
index d820b50..8595ecf 100644
--- a/plugins/flatpak/configure.ac
+++ b/plugins/flatpak/configure.ac
@@ -14,6 +14,9 @@ AS_IF([test "$enable_flatpak_plugin" != no],[
[have_flatpak=yes],
[have_flatpak=no])
+ PKG_CHECK_MODULES(SOUP, [libsoup-2.4])
+
+
AS_IF([test "$enable_flatpak_plugin" = "yes" && test "$have_flatpak" = "no"],[
AC_MSG_ERROR([--enable-flatpak-plugin requires flatpak >= flatpak_required_version])
])
diff --git a/plugins/flatpak/gbp-flatpak-clone-widget.c b/plugins/flatpak/gbp-flatpak-clone-widget.c
index 86ad1c0..0cc9db8 100644
--- a/plugins/flatpak/gbp-flatpak-clone-widget.c
+++ b/plugins/flatpak/gbp-flatpak-clone-widget.c
@@ -408,6 +408,12 @@ get_source (GbpFlatpakCloneWidget *self,
if (json_object_has_member (source_object, "branch"))
src->branch = g_strdup (json_object_get_string_member (source_object, "branch"));
}
+ else if (strcmp (json_object_get_string_member(source_object, "type"), "archive") == 0)
+ {
+ src->type = TYPE_ARCHIVE;
+ if (json_object_has_member (source_object, "sha256"))
+ src->sha = g_strdup (json_object_get_string_member (source_object, "sha256"));
+ }
url = json_object_get_string_member (source_object, "url");
src->uri = ide_vcs_uri_new (url);
diff --git a/plugins/flatpak/gbp-flatpak-source-archive.c b/plugins/flatpak/gbp-flatpak-source-archive.c
new file mode 100644
index 0000000..1fd4014
--- /dev/null
+++ b/plugins/flatpak/gbp-flatpak-source-archive.c
@@ -0,0 +1,550 @@
+/* gbp-flatpak-source-archive.c
+ *
+ * Copyright (C) 2016 Endless Mobile, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libsoup/soup.h>
+
+#include "config.h"
+#include "gbp-flatpak-source-archive.h"
+
+/* This file includes modified code from
+ * flatpak/builder/builder-source-archive.c
+ * Written by Alexander Larsson, originally licensed under GPL 2.1.
+ * Copyright Red Hat, Inc. 2015
+ */
+
+typedef enum {
+ UNKNOWN,
+ RPM,
+ TAR,
+ TAR_GZIP,
+ TAR_COMPRESS,
+ TAR_BZIP2,
+ TAR_LZIP,
+ TAR_LZMA,
+ TAR_LZOP,
+ TAR_XZ,
+ ZIP
+} ArchiveType;
+
+gboolean
+is_tar (ArchiveType type)
+{
+ return (type >= TAR) && (type <= TAR_XZ);
+}
+
+const char *
+tar_decompress_flag (ArchiveType type)
+{
+ if (type == TAR_GZIP)
+ return "-z";
+ else if (type == TAR_COMPRESS)
+ return "-Z";
+ else if (type == TAR_BZIP2)
+ return "-j";
+ else if (type == TAR_LZIP)
+ return "--lzip";
+ else if (type == TAR_LZMA)
+ return "--lzma";
+ else if (type == TAR_LZOP)
+ return "--lzop";
+ else if (type == TAR_XZ)
+ return "-J";
+ else
+ return NULL;
+}
+
+ArchiveType
+get_type (GFile *archivefile)
+{
+ g_autofree gchar *base_name = NULL;
+ g_autofree gchar *lower = NULL;
+
+ base_name = g_file_get_basename (archivefile);
+ lower = g_ascii_strdown (base_name, -1);
+
+ if (g_str_has_suffix (lower, ".tar"))
+ return TAR;
+
+ if (g_str_has_suffix (lower, ".tar.gz") ||
+ g_str_has_suffix (lower, ".tgz") ||
+ g_str_has_suffix (lower, ".taz"))
+ return TAR_GZIP;
+
+ if (g_str_has_suffix (lower, ".tar.Z") ||
+ g_str_has_suffix (lower, ".taZ"))
+ return TAR_COMPRESS;
+
+ if (g_str_has_suffix (lower, ".tar.bz2") ||
+ g_str_has_suffix (lower, ".tz2") ||
+ g_str_has_suffix (lower, ".tbz2") ||
+ g_str_has_suffix (lower, ".tbz"))
+ return TAR_BZIP2;
+
+ if (g_str_has_suffix (lower, ".tar.lz"))
+ return TAR_LZIP;
+
+ if (g_str_has_suffix (lower, ".tar.lzma") ||
+ g_str_has_suffix (lower, ".tlz"))
+ return TAR_LZMA;
+
+ if (g_str_has_suffix (lower, ".tar.lzo"))
+ return TAR_LZOP;
+
+ if (g_str_has_suffix (lower, ".tar.xz"))
+ return TAR_XZ;
+
+ if (g_str_has_suffix (lower, ".zip"))
+ return ZIP;
+
+ if (g_str_has_suffix (lower, ".rpm"))
+ return RPM;
+
+ return UNKNOWN;
+}
+
+typedef struct
+{
+ GError *error;
+ GError *splice_error;
+ GMainLoop *loop;
+ int refs;
+} SpawnData;
+
+static void
+spawn_data_exit (SpawnData *data)
+{
+ data->refs--;
+ if (data->refs == 0)
+ g_main_loop_quit (data->loop);
+}
+
+static void
+spawn_output_spliced_cb (GObject *obj,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ SpawnData *data = user_data;
+
+ g_output_stream_splice_finish (G_OUTPUT_STREAM (obj), result, &data->splice_error);
+ spawn_data_exit (data);
+}
+
+static void
+spawn_exit_cb (GObject *obj,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ SpawnData *data = user_data;
+
+ g_subprocess_wait_check_finish (G_SUBPROCESS (obj), result, &data->error);
+ spawn_data_exit (data);
+}
+
+static gboolean
+archive_spawnv (GFile *dir,
+ char **output,
+ GError **error,
+ const gchar * const *argv)
+{
+ g_autoptr(GSubprocessLauncher) launcher = NULL;
+ g_autoptr(GSubprocess) subp = NULL;
+ GInputStream *in;
+ g_autoptr(GOutputStream) out = NULL;
+ g_autoptr(GMainLoop) loop = NULL;
+ SpawnData data = {0};
+ g_autofree gchar *commandline = NULL;
+
+ launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
+
+ if (output)
+ g_subprocess_launcher_set_flags (launcher, G_SUBPROCESS_FLAGS_STDOUT_PIPE);
+
+ if (dir)
+ {
+ g_autofree char *path = g_file_get_path (dir);
+ g_subprocess_launcher_set_cwd (launcher, path);
+ }
+
+ commandline = g_strjoinv (" ", (gchar **) argv);
+ g_debug ("Running '%s'", commandline);
+
+ subp = g_subprocess_launcher_spawnv (launcher, argv, error);
+
+ if (subp == NULL)
+ return FALSE;
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ data.loop = loop;
+ data.refs = 1;
+
+ if (output)
+ {
+ data.refs++;
+ in = g_subprocess_get_stdout_pipe (subp);
+ out = g_memory_output_stream_new_resizable ();
+ g_output_stream_splice_async (out,
+ in,
+ G_OUTPUT_STREAM_SPLICE_NONE,
+ 0,
+ NULL,
+ spawn_output_spliced_cb,
+ &data);
+ }
+
+ g_subprocess_wait_async (subp, NULL, spawn_exit_cb, &data);
+
+ g_main_loop_run (loop);
+
+ if (data.error)
+ {
+ g_propagate_error (error, data.error);
+ g_clear_error (&data.splice_error);
+ return FALSE;
+ }
+
+ if (out)
+ {
+ if (data.splice_error)
+ {
+ g_propagate_error (error, data.splice_error);
+ return FALSE;
+ }
+
+ /* Null terminate */
+ g_output_stream_write (out, "\0", 1, NULL, NULL);
+ g_output_stream_close (out, NULL, NULL);
+ *output = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (out));
+ }
+
+ return TRUE;
+}
+
+static gboolean
+archive_spawn (GFile *dir,
+ char **output,
+ GError **error,
+ const gchar *argv0,
+ va_list ap)
+{
+ g_autoptr(GPtrArray) args = NULL;
+ const gchar *arg;
+
+ args = g_ptr_array_new ();
+ g_ptr_array_add (args, (gchar *) argv0);
+ while ((arg = va_arg (ap, const gchar *)))
+ g_ptr_array_add (args, (gchar *) arg);
+ g_ptr_array_add (args, NULL);
+
+ return archive_spawnv (dir, output, error, (const gchar * const *) args->pdata);
+}
+
+static gboolean
+tar (GFile *dir,
+ GError **error,
+ ...)
+{
+ gboolean res;
+ va_list ap;
+
+ va_start (ap, error);
+ res = archive_spawn (dir, NULL, error, "tar", ap);
+ va_end (ap);
+
+ return res;
+}
+
+static gboolean
+unzip (GFile *dir,
+ GError **error,
+ ...)
+{
+ gboolean res;
+ va_list ap;
+
+ va_start (ap, error);
+ res = archive_spawn (dir, NULL, error, "unzip", ap);
+ va_end (ap);
+
+ return res;
+}
+
+static gboolean
+unrpm (GFile *dir,
+ const char *rpm_path,
+ GError **error)
+{
+ const gchar *argv[] = {
+ "sh", "-c", "rpm2cpio \"$1\" | cpio -i -d",
+ "sh", /* shell's $0 */
+ rpm_path, /* shell's $1 */
+ NULL
+ };
+
+ return archive_spawnv (dir, NULL, error, argv);
+}
+
+static gboolean
+strip_components_into (GFile *dest,
+ GFile *src,
+ int level,
+ GError **error)
+{
+ g_autoptr(GFileEnumerator) dir_enum = NULL;
+ g_autoptr(GFileInfo) child_info = NULL;
+ GError *temp_error = NULL;
+
+ dir_enum = g_file_enumerate_children (src, "standard::name,standard::type",
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ NULL, error);
+ if (!dir_enum)
+ return FALSE;
+
+ while ((child_info = g_file_enumerator_next_file (dir_enum, NULL, &temp_error)))
+ {
+ g_autoptr(GFile) child = NULL;
+ g_autoptr(GFile) dest_child = NULL;
+
+ child = g_file_enumerator_get_child (dir_enum, child_info);
+
+ if (g_file_info_get_file_type (child_info) == G_FILE_TYPE_DIRECTORY &&
+ level > 0)
+ {
+ if (!strip_components_into (dest, child, level - 1, error))
+ return FALSE;
+
+ g_clear_object (&child_info);
+ continue;
+ }
+
+ dest_child = g_file_get_child (dest, g_file_info_get_name (child_info));
+ if (!g_file_move (child, dest_child, G_FILE_COPY_NONE, NULL, NULL, NULL, error))
+ return FALSE;
+
+ g_clear_object (&child_info);
+ }
+
+ if (temp_error != NULL)
+ {
+ g_propagate_error (error, temp_error);
+ return FALSE;
+ }
+
+ return g_file_delete (src, NULL, error);
+}
+
+static GFile *
+create_uncompress_directory (GFile *dest,
+ int strip_components,
+ GError **error)
+{
+ GFile *uncompress_dest = NULL;
+
+ if (strip_components > 0)
+ {
+ g_autoptr(GFile) tmp_dir_template = g_file_get_child (dest, ".uncompressXXXXXX");
+ g_autofree char *tmp_dir_path = g_file_get_path (tmp_dir_template);
+
+ if (g_mkdtemp (tmp_dir_path) == NULL)
+ {
+ int saved_errno = errno;
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Can't create uncompress directory: %s",
+ g_strerror (saved_errno));
+ return NULL;
+ }
+
+ uncompress_dest = g_file_new_for_path (tmp_dir_path);
+ }
+ else
+ {
+ uncompress_dest = g_object_ref (dest);
+ }
+
+ return uncompress_dest;
+}
+
+SoupSession *
+get_soup_session (void)
+{
+ return soup_session_new_with_options (SOUP_SESSION_USER_AGENT, PACKAGE_NAME,
+ NULL);
+}
+
+static GBytes *
+download_uri (SoupURI *uri,
+ GError **error)
+{
+ g_autoptr(SoupSession) session;
+ g_autoptr(SoupRequest) req = NULL;
+ g_autoptr(GInputStream) input = NULL;
+ g_autoptr(GOutputStream) out = NULL;
+
+ session = get_soup_session ();
+
+ req = soup_session_request_uri (session, uri, error);
+ if (req == NULL)
+ return NULL;
+
+ input = soup_request_send (req, NULL, error);
+ if (input == NULL)
+ return NULL;
+
+ out = g_memory_output_stream_new_resizable ();
+ if (!g_output_stream_splice (out,
+ input,
+ G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET | G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
+ NULL,
+ error))
+ return NULL;
+
+ return g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (out));
+}
+
+static gboolean
+download_archive (SoupURI *uri,
+ const gchar *sha,
+ GFile *archive_file,
+ GError **error)
+{
+ g_autoptr(GBytes) content = NULL;
+ g_autofree gchar *sha256 = NULL;
+
+ content = download_uri (uri, error);
+ if (content == NULL)
+ return FALSE;
+
+ sha256 = g_compute_checksum_for_bytes (G_CHECKSUM_SHA256, content);
+ if (g_strcmp0 (sha256, sha) != 0)
+ {
+ g_autofree gchar *path = g_file_get_path (archive_file);
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Wrong sha256 for %s, expected %s, was %s",
+ path, sha, sha256);
+ return FALSE;
+ }
+
+ return g_file_replace_contents (archive_file,
+ g_bytes_get_data (content, NULL),
+ g_bytes_get_size (content),
+ NULL, FALSE, G_FILE_CREATE_NONE, NULL,
+ NULL, error);
+}
+
+static gboolean
+extract_archive (GFile *destination,
+ GFile *archive_file,
+ int strip_components,
+ GError **error)
+{
+ ArchiveType type;
+ g_autofree char *archive_path = NULL;
+
+ archive_path = g_file_get_path (archive_file);
+
+ g_debug ("Uncompress %s\n", archive_path);
+
+ type = get_type (archive_file);
+
+ if (is_tar (type))
+ {
+ g_autofree char *strip_components_str = g_strdup_printf ("--strip-components=%u", strip_components);
+
+ /* tar_decompress_flag can return NULL, so put it last */
+ if (!tar (destination, error, "xf", archive_path, "--no-same-owner",
+ strip_components_str, tar_decompress_flag (type), NULL))
+ return FALSE;
+ }
+ else if (type == ZIP)
+ {
+ g_autoptr(GFile) zip_dest = NULL;
+
+ zip_dest = create_uncompress_directory (destination, strip_components, error);
+ if (zip_dest == NULL)
+ return FALSE;
+
+ if (!unzip (zip_dest, error, archive_path, NULL))
+ return FALSE;
+
+ if (strip_components > 0 &&
+ !strip_components_into (destination, zip_dest, strip_components, error))
+ return FALSE;
+ }
+ else if (type == RPM)
+ {
+ g_autoptr(GFile) rpm_dest = NULL;
+
+ rpm_dest = create_uncompress_directory (destination, strip_components, error);
+ if (rpm_dest == NULL)
+ return FALSE;
+
+ if (!unrpm (rpm_dest, archive_path, error))
+ return FALSE;
+
+ if (strip_components > 0 &&
+ !strip_components_into (destination, rpm_dest, strip_components, error))
+ return FALSE;
+ }
+ else
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Unknown archive format of '%s'", archive_path);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+GFile *
+fetch_archive (const gchar *url,
+ const gchar *sha,
+ const gchar *module_name,
+ GFile *destination,
+ GError **error)
+{
+ g_autoptr(GFile) archive_file = NULL;
+ g_autoptr(GFile) source_dir = NULL;
+ g_autoptr(SoupURI) uri = NULL;
+ g_autofree char *archive_name = NULL;
+ GError *local_error = NULL;
+
+ source_dir = g_file_get_child (destination, module_name);
+ if (!g_file_make_directory_with_parents (source_dir, NULL, &local_error))
+ {
+ if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_EXISTS))
+ {
+ g_propagate_error (error, local_error);
+ return NULL;
+ }
+
+ g_error_free (local_error);
+ }
+
+ uri = soup_uri_new (url);
+ archive_name = g_path_get_basename (soup_uri_get_path (uri));
+ archive_file = g_file_get_child (source_dir, archive_name);
+
+ if (!download_archive (uri, sha, archive_file, error))
+ return NULL;
+
+ if (!extract_archive (source_dir, archive_file, 1, error))
+ return NULL;
+
+ return g_steal_pointer (&source_dir);
+}
diff --git a/plugins/flatpak/gbp-flatpak-source-archive.h b/plugins/flatpak/gbp-flatpak-source-archive.h
new file mode 100644
index 0000000..b8a0249
--- /dev/null
+++ b/plugins/flatpak/gbp-flatpak-source-archive.h
@@ -0,0 +1,28 @@
+/* gbp-flatpak-source-archive.h
+ *
+ * Copyright (C) 2016 Endless Mobile, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GBP_FLATPAK_SOURCE_ARCHIVE_H
+#define GBP_FLATPAK_SOURCE_ARCHIVE_H
+
+GFile *fetch_archive (const gchar *url,
+ const gchar *sha,
+ const gchar *module_name,
+ GFile *destination,
+ GError **error);
+
+#endif /* GBP_FLATPAK_SOURCE_ARCHIVE_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]