From: Michael Tremer Date: Mon, 10 Jun 2019 17:34:16 +0000 (+0100) Subject: Implement extracting archives from Python X-Git-Tag: 0.9.28~1285^2~955 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e7da5970211a96b574f2c7babf20e2da929d6d4a;p=pakfire.git Implement extracting archives from Python Signed-off-by: Michael Tremer --- diff --git a/src/_pakfire/archive.c b/src/_pakfire/archive.c index 36ba7f4cf..25b57b333 100644 --- a/src/_pakfire/archive.c +++ b/src/_pakfire/archive.c @@ -126,7 +126,35 @@ static PyObject* Archive_get_signatures(ArchiveObject* self) { return list; } +static PyObject* Archive_extract(ArchiveObject* self, PyObject* args) { + const char* target = NULL; + + if (!PyArg_ParseTuple(args, "|z", &target)) + return NULL; + + // Make extraction path + char* prefix = pakfire_archive_extraction_path(self->archive, target); + + // Extract payload + int r = pakfire_archive_extract(self->archive, prefix, PAKFIRE_ARCHIVE_USE_PAYLOAD); + pakfire_free(prefix); + + // Throw an exception on error + if (r) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + Py_RETURN_NONE; +} + static struct PyMethodDef Archive_methods[] = { + { + "extract", + (PyCFunction)Archive_extract, + METH_VARARGS, + NULL + }, { "read", (PyCFunction)Archive_read, diff --git a/src/libpakfire/archive.c b/src/libpakfire/archive.c index 727e48acb..5f90c33db 100644 --- a/src/libpakfire/archive.c +++ b/src/libpakfire/archive.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #define BLOCKSIZE 1024 * 1024 // 1MB @@ -731,6 +732,36 @@ out: return r; } +PAKFIRE_EXPORT char* pakfire_archive_extraction_path(PakfireArchive archive, const char* target) { + PakfireRepo repo = pakfire_repo_create(archive->pakfire, "dummy"); + + // Read package metadata + PakfirePackage pkg = pakfire_archive_make_package(archive, repo); + if (!pkg) { + pakfire_repo_unref(repo); + return NULL; + } + + const char* arch = pakfire_package_get_arch(pkg); + int is_source = (strcmp(arch, "src") == 0); + + // Use a good default for source packages + if (is_source && !target) + target = "/usr/src/packages"; + + char* nevra = pakfire_package_get_nevra(pkg); + + // Append package name and version to path + char* prefix = pakfire_path_join(target, nevra); + + // Cleanup + pakfire_package_unref(pkg); + pakfire_repo_unref(repo); + pakfire_free(nevra); + + return prefix; +} + PAKFIRE_EXPORT int pakfire_archive_extract(PakfireArchive archive, const char* prefix, int flags) { struct archive* a; struct archive* pa = NULL; @@ -743,6 +774,8 @@ PAKFIRE_EXPORT int pakfire_archive_extract(PakfireArchive archive, const char* p int use_payload = (flags & PAKFIRE_ARCHIVE_USE_PAYLOAD); + DEBUG(archive->pakfire, "Extracting %s to %s\n", archive->path, prefix); + if (use_payload) pa = archive_open_payload(a); diff --git a/src/libpakfire/include/pakfire/archive.h b/src/libpakfire/include/pakfire/archive.h index 1614bbb2f..5d30467a0 100644 --- a/src/libpakfire/include/pakfire/archive.h +++ b/src/libpakfire/include/pakfire/archive.h @@ -36,7 +36,8 @@ typedef enum pakfire_archive_verify_status { } pakfire_archive_verify_status_t; typedef enum pakfire_archive_flags { - PAKFIRE_ARCHIVE_USE_PAYLOAD = 1 << 0, + PAKFIRE_ARCHIVE_USE_PAYLOAD = 1 << 0, + PAKFIRE_ARCHIVE_ADD_FILENAME_PREFIX = 1 << 1, } pakfire_archive_flags_t; PakfireArchive pakfire_archive_create(Pakfire pakfire); @@ -50,6 +51,7 @@ PakfireArchive pakfire_archive_open(Pakfire pakfire, const char* path); int pakfire_archive_read(PakfireArchive archive, const char* filename, void** data, size_t* data_size, int flags); int pakfire_archive_extract(PakfireArchive archive, const char* prefix, int flags); +char* pakfire_archive_extraction_path(PakfireArchive archive, const char* target); const char* pakfire_archive_get_path(PakfireArchive archive); diff --git a/src/libpakfire/libpakfire.sym b/src/libpakfire/libpakfire.sym index efb78b245..663d8f050 100644 --- a/src/libpakfire/libpakfire.sym +++ b/src/libpakfire/libpakfire.sym @@ -46,6 +46,7 @@ global: pakfire_archive_count_signatures; pakfire_archive_create; pakfire_archive_extract; + pakfire_archive_extraction_path; pakfire_archive_get_filelist; pakfire_archive_get_format; pakfire_archive_get_path; diff --git a/src/pakfire/base.py b/src/pakfire/base.py index 09dc2da47..6cfdb1679 100644 --- a/src/pakfire/base.py +++ b/src/pakfire/base.py @@ -233,6 +233,25 @@ class PakfireContext(object): def search(self, pattern): return self.pakfire.search(pattern) + def extract(self, filenames, target=None): + if target and target == "/": + raise ValueError("Cannot extract to: %s" % target) + + archives = [] + + # Open all archives + for filename in filenames: + a = _pakfire.Archive(self.pakfire, filename) + archives.append(a) + + # Nothing to do when no archives where opened + if not archives: + return + + # Extract them all + for archive in archives: + archive.extract(target) + # Transactions def install(self, requires, **kwargs): diff --git a/src/pakfire/cli.py b/src/pakfire/cli.py index 8fcf186a3..2a8144059 100644 --- a/src/pakfire/cli.py +++ b/src/pakfire/cli.py @@ -388,37 +388,7 @@ class Cli(object): def handle_extract(self, ns): with self.pakfire(ns) as p: - # Open all packages. - pkgs = [] - for pkg in ns.package: - pkg = packages.open(self, None, pkg) - pkgs.append(pkg) - - target_prefix = ns.target - - # Search for binary packages. - binary_packages = any([p.type == "binary" for p in pkgs]) - source_packages = any([p.type == "source" for p in pkgs]) - - if binary_packages and source_packages: - raise Error(_("Cannot extract mixed package types")) - - if binary_packages and not target_prefix: - raise Error(_("You must provide an install directory with --target=...")) - - elif source_packages and not target_prefix: - target_prefix = "/usr/src/packages/" - - if target_prefix == "/": - raise Error(_("Cannot extract to /.")) - - for pkg in pkgs: - if pkg.type == "binary": - target_dir = target_prefix - elif pkg.type == "source": - target_dir = os.path.join(target_prefix, pkg.friendly_name) - - pkg.extract(message=_("Extracting"), prefix=target_dir) + p.extract(ns.package, target=ns.target) class CliBuilder(Cli):