From 39a07fff297c8331455fd6de599ed621f1965e38 Mon Sep 17 00:00:00 2001 From: Iain Lane Date: Tue, 23 Aug 2016 15:10:42 +0100 Subject: [PATCH 1/5] Add a function to extract a whole archive to a directory We want to do this for langpacks. --- source/bindings/asgenstdlib.d | 13 +++++++ source/bindings/libarchive.d | 6 +++ source/zarchive.d | 68 ++++++++++++++++++++++++++++++++++ test/samples/test.tar.xz | Bin 0 -> 10240 bytes 4 files changed, 87 insertions(+) create mode 100644 source/bindings/asgenstdlib.d create mode 100644 test/samples/test.tar.xz diff --git a/source/bindings/asgenstdlib.d b/source/bindings/asgenstdlib.d new file mode 100644 index 00000000..6bbb06ed --- /dev/null +++ b/source/bindings/asgenstdlib.d @@ -0,0 +1,13 @@ +/* This was taken from + */ + +////////////////////////////////////////////////////////////////////////// // +// C API + +module bindings.asgenstdilb; + +extern(C): +nothrow: +@nogc: + +char* mkdtemp(char*); // Defined in IEEE 1003.1, 2008 Edition diff --git a/source/bindings/libarchive.d b/source/bindings/libarchive.d index c6488eec..1d175642 100644 --- a/source/bindings/libarchive.d +++ b/source/bindings/libarchive.d @@ -83,9 +83,11 @@ void archive_entry_set_size (archive_entry*, long); void archive_entry_set_filetype (archive_entry*, uint); void archive_entry_set_perm (archive_entry*, uint); void archive_entry_set_mtime (archive_entry*, ulong sec, long nsec); +long archive_entry_size (archive_entry*); const(char) *archive_entry_symlink (archive_entry*); archive *archive_write_new (); +int archive_write_finish_entry (archive*); int archive_write_free (archive*); int archive_write_close (archive*); @@ -100,3 +102,7 @@ int archive_write_set_format_by_name (archive*, const(char) *name); int archive_write_open_filename (archive*, const(char) *file); int archive_write_header (archive*, archive_entry*); size_t archive_write_data(archive*, const(void)*, size_t); +size_t archive_write_data_block (archive*, const(void)*, size_t, long); + +archive *archive_write_disk_new (); +int archive_write_disk_set_options (archive*, int); diff --git a/source/zarchive.d b/source/zarchive.d index d1443c7e..9b7750f2 100644 --- a/source/zarchive.d +++ b/source/zarchive.d @@ -247,6 +247,50 @@ public: return false; } + void extractArchive (const string dest) + in + { + import std.file : isDir; + assert (dest.isDir); + } + body + { + import std.file : chdir, getcwd; + + archive *ar; + archive *ar_dest; + archive_entry *en; + + const void *buf; + size_t size; + long offset; + + string cwd; + + cwd = getcwd (); + + ar = openArchive (); + scope(exit) archive_read_free (ar); + + dest.chdir; + scope(exit) cwd.chdir; + + ar_dest = archive_write_disk_new (); + scope(exit) archive_write_free (ar_dest); + + while (archive_read_next_header (ar, &en) == ARCHIVE_OK) { + if (archive_write_header (ar_dest, en) != ARCHIVE_OK || + archive_entry_size (en) <= 0) + continue; + + while (archive_read_data_block (ar, &buf, &size, &offset) == ARCHIVE_OK) { + if (archive_write_data_block (ar_dest, buf, size, offset) != ARCHIVE_OK) + throw new Exception ("Failed writing archive: %s".format( + archive_error_string (ar_dest).fromStringz)); + } + } + } + const(ubyte)[] readData (string fname) { import core.sys.posix.sys.stat; @@ -553,4 +597,28 @@ unittest 0x00, 0x00, ]; assert (decompressData (emptyGz) == ""); + + writeln ("TEST: ", "Extracting a tarball"); + + import bindings.asgenstdilb : mkdtemp; + import std.file : buildPath, tempDir; + + auto archive = buildPath (getcwd (), "test", "samples", "test.tar.xz"); + assert (archive.exists); + auto ar = new ArchiveDecompressor (); + + auto tmpdir = buildPath (tempDir, "asgenXXXXXX"); + auto ctmpdir = new char[](tmpdir.length + 1); + ctmpdir[0 .. tmpdir.length] = tmpdir[]; + ctmpdir[$ - 1] = '\0'; + + tmpdir = to!string(mkdtemp (ctmpdir.ptr)); + scope(exit) rmdirRecurse (tmpdir); + + ar.open (archive); + ar.extractArchive (tmpdir); + + auto path = buildPath (tmpdir, "b", "a"); + assert (path.exists); + assert (path.readText.chomp == "hello"); } diff --git a/test/samples/test.tar.xz b/test/samples/test.tar.xz new file mode 100644 index 0000000000000000000000000000000000000000..dd248b99b8df1a6155d8cdb9d11664923478121d GIT binary patch literal 10240 zcmeIvJqiLb5QgEYJwRlTaBYkTzSE=_!Z$qMJjw9UHaVNL z$7j>Wx3Bt$-)GAjOj8u~8hjLI!!K(A*Yl;EoReA(%WWg@-G1ZiFR$jQ3_q_IoO-V> z`%lmPM+@R~_+>5N&--7OT93PLK$C$00tg_000IagfB*srAb Date: Mon, 22 Aug 2016 15:15:20 +0100 Subject: [PATCH 2/5] Add a hook to the desktop file parser to run backend specific code --- source/backends/interfaces.d | 8 ++++++++ source/handlers/desktopparser.d | 3 +++ 2 files changed, 11 insertions(+) diff --git a/source/backends/interfaces.d b/source/backends/interfaces.d index b039ddfe..a752ca83 100644 --- a/source/backends/interfaces.d +++ b/source/backends/interfaces.d @@ -19,6 +19,9 @@ module backends.interfaces; +import appstream.Component; +import glib.KeyFile; + import std.string; import std.container; public import datastore; @@ -59,6 +62,11 @@ abstract class Package */ abstract const(ubyte)[] getFileData (string fname); + /** + * Retrieve backend-specific translations. + */ + string[string] processDesktopFile (KeyFile desktopFile, const string text) { return null; } + /** * Close the package. This function is called when we will * no longer request any file data from this package. diff --git a/source/handlers/desktopparser.d b/source/handlers/desktopparser.d index 0e341593..9ef90ff9 100644 --- a/source/handlers/desktopparser.d +++ b/source/handlers/desktopparser.d @@ -255,6 +255,9 @@ Component parseDesktopFile (GeneratorResult gres, string fname, string data, boo } } + /* run backend specific hooks */ + gres.pkg.processDesktopFile (cpt, df); + return cpt; } From 98f2df5112104a5cf0f6a93d8008ef6ba70cffa3 Mon Sep 17 00:00:00 2001 From: Iain Lane Date: Mon, 22 Aug 2016 16:48:30 +0100 Subject: [PATCH 3/5] Add an Ubuntu backend to retrieve langpack translations The first time that we encounter a package with an X-Ubuntu-Gettext-Domain key in its desktop file, we extract the langpacks and generate the locales that they reference. Then we can query these translations and stuff them into the component. --- source/backends/debian/debpkg.d | 17 ++- source/backends/debian/debpkgindex.d | 9 +- source/backends/interfaces.d | 1 + source/backends/ubuntu/package.d | 23 ++++ source/backends/ubuntu/ubupkg.d | 191 +++++++++++++++++++++++++++ source/backends/ubuntu/ubupkgindex.d | 62 +++++++++ source/bindings/asgenstdlib.d | 13 -- source/bindings/libarchive.d | 6 - source/config.d | 5 + source/engine.d | 4 + source/handlers/desktopparser.d | 33 ++--- source/utils.d | 1 + source/zarchive.d | 41 +++--- 13 files changed, 344 insertions(+), 62 deletions(-) create mode 100644 source/backends/ubuntu/package.d create mode 100644 source/backends/ubuntu/ubupkg.d create mode 100644 source/backends/ubuntu/ubupkgindex.d delete mode 100644 source/bindings/asgenstdlib.d diff --git a/source/backends/debian/debpkg.d b/source/backends/debian/debpkg.d index 80902897..61da145a 100644 --- a/source/backends/debian/debpkg.d +++ b/source/backends/debian/debpkg.d @@ -35,7 +35,7 @@ import utils : isRemote, downloadFile; class DebPackage : Package { -private: +protected: string pkgname; string pkgver; string pkgarch; @@ -61,7 +61,7 @@ public: override @property string filename () const { if (debFname.isRemote) { - immutable path = buildPath (tmpDir, debFname.baseName); + immutable path = buildNormalizedPath (tmpDir, debFname.baseName); downloadFile (debFname, path); return path; } @@ -121,6 +121,19 @@ public: return pa; } + protected void extractPackage (const string dest = buildPath (tmpDir, name)) + { + import std.file : exists; + import std.regex : ctRegex; + + if (!dest.exists) + mkdirRecurse (dest); + + auto pa = openPayloadArchive (); + + pa.extractArchive (dest); + } + private auto openControlArchive () { auto ca = new ArchiveDecompressor (); diff --git a/source/backends/debian/debpkgindex.d b/source/backends/debian/debpkgindex.d index 393dacb7..b6c38546 100644 --- a/source/backends/debian/debpkgindex.d +++ b/source/backends/debian/debpkgindex.d @@ -39,7 +39,7 @@ import utils : escapeXml, getFileContents, isRemote; class DebianPackageIndex : PackageIndex { -private: +protected: string rootDir; Package[][string] pkgCache; bool[string] indexChanged; @@ -175,6 +175,11 @@ public: return downloadIfNecessary (rootDir, tmpDir, buildPath (path, "Packages.%s")); } + protected DebPackage newPackage (string name, string ver, string arch) + { + return new DebPackage (name, ver, arch); + } + private DebPackage[] loadPackages (string suite, string section, string arch) { auto indexFname = getIndexFile (suite, section, arch); @@ -195,7 +200,7 @@ public: if (!name) continue; - auto pkg = new DebPackage (name, ver, arch); + auto pkg = newPackage (name, ver, arch); pkg.filename = buildPath (rootDir, fname); pkg.maintainer = tagf.readField ("Maintainer"); diff --git a/source/backends/interfaces.d b/source/backends/interfaces.d index a752ca83..176aea01 100644 --- a/source/backends/interfaces.d +++ b/source/backends/interfaces.d @@ -36,6 +36,7 @@ abstract class Package @property string ver () const @safe pure; @property string arch () const @safe pure; @property string maintainer () const; + @property Package[] otherPackages; /** * A associative array containing package descriptions. diff --git a/source/backends/ubuntu/package.d b/source/backends/ubuntu/package.d new file mode 100644 index 00000000..97150cf9 --- /dev/null +++ b/source/backends/ubuntu/package.d @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016 Matthias Klumpp + * + * Licensed under the GNU Lesser General Public License Version 3 + * + * 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 3 of the license, or + * (at your option) any later version. + * + * This software 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 software. If not, see . + */ + +module backends.ubuntu; + +public import backends.ubuntu.ubupkg; +public import backends.ubuntu.ubupkgindex; diff --git a/source/backends/ubuntu/ubupkg.d b/source/backends/ubuntu/ubupkg.d new file mode 100644 index 00000000..fbbfa9d7 --- /dev/null +++ b/source/backends/ubuntu/ubupkg.d @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2016 Canonical Ltd + * Author: Iain Lane + * + * Licensed under the GNU Lesser General Public License Version 3 + * + * 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 3 of the license, or + * (at your option) any later version. + * + * This software 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 software. If not, see . + */ + +module backends.ubuntu.ubupkg; + +import appstream.Component; + +import backends.debian.debpkg; +import backends.interfaces; + +import glib.Internationalization; +import glib.KeyFile; + +import std.container : Array; + +import logging; + +import utils : DESKTOP_GROUP; + +extern (C) char *bindtextdomain (const char *domainname, const char *dirName) nothrow @nogc; + +class UbuntuPackage : DebPackage +{ + this (string pname, string pver, string parch, string globalTmpDir, ref Array!Package allPackages) + { + this.globalTmpDir = globalTmpDir; + this.langpackDir = buildPath (globalTmpDir, "langpacks"); + this.localeDir = buildPath (langpackDir, "locales"); + this.allPackages = allPackages; + super (pname, pver, parch); + } + + override string[string] processDesktopFile (KeyFile desktopFile, const string text) + { + string langpackdomain; + + try { + langpackdomain = desktopFile.getString (DESKTOP_GROUP, + "X-Ubuntu-Gettext-Domain"); + } catch { + try { + langpackdomain = desktopFile.getString (DESKTOP_GROUP, + "X-GNOME-Gettext-Domain"); + } catch { + return null; + } + } + + logDebug ("%s has langpack domain %s", name, langpackdomain); + + synchronized { + extractLangpacks (); + return getTranslations (langpackdomain, text); + } + } + +private: + string globalTmpDir; + string langpackDir; + string localeDir; + string[] langpackLocales; + Array!Package allPackages; + + private void extractLangpacks () + { + import std.algorithm : filter, map; + import std.array : appender, array, split; + import std.file : dirEntries, exists, SpanMode, readText; + import std.parallelism : parallel; + import std.path : baseName; + import std.process : Pid, spawnProcess, wait; + import std.string : splitLines, startsWith; + + auto path = buildPath (langpackDir, "usr", "share", "locale-langpack"); + + if (!langpackDir.exists) { + bool[string] extracted; + + langpackDir.mkdirRecurse (); + + foreach (pkg; allPackages) { + if (!pkg.name.startsWith ("language-pack") || pkg.name in extracted) + continue; + + UbuntuPackage upkg = to!UbuntuPackage (pkg); + + logDebug ("Extracting %s", pkg.name); + upkg.extractPackage (langpackDir); + + extracted[pkg.name] = true; + } + + auto supportedd = buildPath (langpackDir, "var", "lib", "locales", "supported.d"); + + localeDir.mkdirRecurse (); + + foreach (locale; parallel (supportedd.dirEntries (SpanMode.shallow), 5)) + { + foreach (ref line; locale.readText.splitLines) { + auto components = line.split (" "); + auto localecharset = components[0].split ("."); + + auto outdir = buildPath (localeDir, components[0]); + logDebug ("Generating locale in %s", outdir); + + auto pid = spawnProcess (["/usr/bin/localedef", + "--no-archive", + "-i", + localecharset[0], + "-c", + "-f", + components[1], + outdir]); + + scope (exit) wait (pid); + } + } + + } + + if (langpackLocales is null) + langpackLocales = localeDir.dirEntries (SpanMode.shallow) + .filter!(f => f.isDir) + .map!(f => f.name.baseName) + .array; + } + + string[string] getTranslations (const string domain, const string text) + { + import core.stdc.locale; + import core.stdc.string : strdup; + + import std.c.stdlib : getenv, setenv, unsetenv; + import std.string : fromStringz, toStringz; + + char *[char *] env; + + foreach (ref var; ["LC_ALL", "LANG", "LANGUAGE", "LC_MESSAGES"]) { + auto value = getenv (var.toStringz); + if (value !is null) { + env[var.toStringz] = getenv (var.toStringz).strdup; + unsetenv (var.toStringz); + } + } + + scope (exit) { + foreach (key, val; env) + setenv (key, val, false); + } + + setenv ("LOCPATH", localeDir.toStringz, true); + + auto initialLocale = setlocale (LC_ALL, ""); + scope(exit) setlocale (LC_ALL, initialLocale); + + auto dir = buildPath (langpackDir, + "usr", + "share", + "locale-langpack"); + + string[string] ret; + + foreach (ref locale; langpackLocales) { + setlocale (LC_ALL, locale.toStringz); + bindtextdomain (domain.toStringz, dir.toStringz); + auto translatedtext = Internationalization.dgettext (domain, text); + + if (text != translatedtext) + ret[locale] = translatedtext; + } + + return ret; + } +} diff --git a/source/backends/ubuntu/ubupkgindex.d b/source/backends/ubuntu/ubupkgindex.d new file mode 100644 index 00000000..a27169b7 --- /dev/null +++ b/source/backends/ubuntu/ubupkgindex.d @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2016 Canonical Ltd + * Author: Iain Lane + * + * Licensed under the GNU Lesser General Public License Version 3 + * + * 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 3 of the license, or + * (at your option) any later version. + * + * This software 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 software. If not, see . + */ + +module backends.ubuntu.ubupkgindex; + +import backends.debian; +import backends.interfaces; +import backends.ubuntu.ubupkg; + +import std.container : Array, make; + +class UbuntuPackageIndex : DebianPackageIndex +{ + +public: + this (string dir) + { + /* + * UbuntuPackage needs to extract the langpacks, so we give it an array + * of all packages. We don't do this here, as you migh think makes + * sense, because it is a very expensive operation and we want to avoid + * doing it if it's not necessary (when no packages being processed are + * using langpacks). + */ + allPackages = make!(Array!Package); + super (dir); + } + + override DebPackage newPackage (string name, string ver, string arch) + { + return new UbuntuPackage (name, ver, arch, tmpDir, allPackages); + } + + override Package[] packagesFor (string suite, string section, string arch) + { + auto pkgs = super.packagesFor (suite, section, arch); + + allPackages ~= pkgs; + + return pkgs; + } +} + +private: + Array!Package allPackages; diff --git a/source/bindings/asgenstdlib.d b/source/bindings/asgenstdlib.d deleted file mode 100644 index 6bbb06ed..00000000 --- a/source/bindings/asgenstdlib.d +++ /dev/null @@ -1,13 +0,0 @@ -/* This was taken from - */ - -////////////////////////////////////////////////////////////////////////// // -// C API - -module bindings.asgenstdilb; - -extern(C): -nothrow: -@nogc: - -char* mkdtemp(char*); // Defined in IEEE 1003.1, 2008 Edition diff --git a/source/bindings/libarchive.d b/source/bindings/libarchive.d index 1d175642..c6488eec 100644 --- a/source/bindings/libarchive.d +++ b/source/bindings/libarchive.d @@ -83,11 +83,9 @@ void archive_entry_set_size (archive_entry*, long); void archive_entry_set_filetype (archive_entry*, uint); void archive_entry_set_perm (archive_entry*, uint); void archive_entry_set_mtime (archive_entry*, ulong sec, long nsec); -long archive_entry_size (archive_entry*); const(char) *archive_entry_symlink (archive_entry*); archive *archive_write_new (); -int archive_write_finish_entry (archive*); int archive_write_free (archive*); int archive_write_close (archive*); @@ -102,7 +100,3 @@ int archive_write_set_format_by_name (archive*, const(char) *name); int archive_write_open_filename (archive*, const(char) *file); int archive_write_header (archive*, archive_entry*); size_t archive_write_data(archive*, const(void)*, size_t); -size_t archive_write_data_block (archive*, const(void)*, size_t, long); - -archive *archive_write_disk_new (); -int archive_write_disk_set_options (archive*, int); diff --git a/source/config.d b/source/config.d index 107e703a..5c728b9f 100644 --- a/source/config.d +++ b/source/config.d @@ -65,6 +65,7 @@ enum Backend Unknown, Dummy, Debian, + Ubuntu, Archlinux, RpmMd } @@ -276,6 +277,10 @@ class Config this.backend = Backend.Debian; this.metadataType = DataType.YAML; break; + case "ubuntu": + this.backend = Backend.Ubuntu; + this.metadataType = DataType.YAML; + break; case "arch": case "archlinux": this.backend = Backend.Archlinux; diff --git a/source/engine.d b/source/engine.d index b369267c..cdc8763d 100644 --- a/source/engine.d +++ b/source/engine.d @@ -41,6 +41,7 @@ import utils : copyDir, stringArrayToByteArray; import backends.interfaces; import backends.dummy; import backends.debian; +import backends.ubuntu; import backends.archlinux; import backends.rpmmd; @@ -72,6 +73,9 @@ public: case Backend.Debian: pkgIndex = new DebianPackageIndex (conf.archiveRoot); break; + case Backend.Ubuntu: + pkgIndex = new UbuntuPackageIndex (conf.archiveRoot); + break; case Backend.Archlinux: pkgIndex = new ArchPackageIndex (conf.archiveRoot); break; diff --git a/source/handlers/desktopparser.d b/source/handlers/desktopparser.d index 9ef90ff9..555b98a9 100644 --- a/source/handlers/desktopparser.d +++ b/source/handlers/desktopparser.d @@ -35,9 +35,6 @@ import result; import utils; import config : Config, FormatVersion; - -immutable DESKTOP_GROUP = "Desktop Entry"; - private string getLocaleFromKey (string key) { if (!localeValid (key)) @@ -204,11 +201,18 @@ Component parseDesktopFile (GeneratorResult gres, string fname, string data, boo if (key.startsWith ("Name")) { immutable val = getValue (df, key); checkDesktopString (key, val); - cpt.setName (val, locale); + /* run backend specific hooks */ + auto translations = gres.pkg.processDesktopFile (df, val); + translations[locale] = val; + foreach (key, value; translations) + cpt.setName (value, key); } else if (key.startsWith ("Comment")) { immutable val = getValue (df, key); checkDesktopString (key, val); - cpt.setSummary (val, locale); + auto translations = gres.pkg.processDesktopFile (df, val); + translations[locale] = val; + foreach (key, value; translations) + cpt.setSummary (value, key); } else if (key == "Categories") { auto value = getValue (df, key); auto cats = value.split (";"); @@ -219,13 +223,15 @@ Component parseDesktopFile (GeneratorResult gres, string fname, string data, boo foreach (ref c; cats) cpt.addCategory (c); } else if (key.startsWith ("Keywords")) { - auto value = getValue (df, key); - auto kws = value.split (";"); - kws = kws.stripRight (""); - if (kws.empty) - continue; - - cpt.setKeywords (kws, locale); + auto val = getValue (df, key); + auto translations = gres.pkg.processDesktopFile (df, val); + translations[locale] = val; + foreach (key, value; translations) { + auto kws = value.split (";").stripRight (""); + if (kws.empty) + continue; + cpt.setKeywords (kws, key); + } } else if (key == "MimeType") { auto value = getValue (df, key); immutable mts = value.split (";"); @@ -255,9 +261,6 @@ Component parseDesktopFile (GeneratorResult gres, string fname, string data, boo } } - /* run backend specific hooks */ - gres.pkg.processDesktopFile (cpt, df); - return cpt; } diff --git a/source/utils.d b/source/utils.d index 1fbbf06a..00b36311 100644 --- a/source/utils.d +++ b/source/utils.d @@ -32,6 +32,7 @@ static import std.file; import logging; +public immutable DESKTOP_GROUP = "Desktop Entry"; public immutable GENERIC_BUFFER_SIZE = 2048; diff --git a/source/zarchive.d b/source/zarchive.d index 9b7750f2..ebece4ff 100644 --- a/source/zarchive.d +++ b/source/zarchive.d @@ -31,6 +31,14 @@ version (GNU) else import std.concurrency : Generator, yield; +version (unittest) { + version (GNU) { + extern(C) char *mkdtemp (char *) nothrow @nogc; + } else { + import core.sys.posix.stdlib; + } +} + import bindings.libarchive; private immutable DEFAULT_BLOCK_SIZE = 65536; @@ -255,38 +263,24 @@ public: } body { - import std.file : chdir, getcwd; - + import std.path; archive *ar; - archive *ar_dest; archive_entry *en; - const void *buf; - size_t size; - long offset; - - string cwd; - - cwd = getcwd (); - ar = openArchive (); scope(exit) archive_read_free (ar); - dest.chdir; - scope(exit) cwd.chdir; - - ar_dest = archive_write_disk_new (); - scope(exit) archive_write_free (ar_dest); - while (archive_read_next_header (ar, &en) == ARCHIVE_OK) { - if (archive_write_header (ar_dest, en) != ARCHIVE_OK || - archive_entry_size (en) <= 0) + auto pathname = buildPath (dest, archive_entry_pathname (en).fromStringz); + /* at the moment we only handle directories and files */ + if (archive_entry_filetype (en) == AE_IFDIR) { + if (!pathname.exists) + pathname.mkdir; continue; + } - while (archive_read_data_block (ar, &buf, &size, &offset) == ARCHIVE_OK) { - if (archive_write_data_block (ar_dest, buf, size, offset) != ARCHIVE_OK) - throw new Exception ("Failed writing archive: %s".format( - archive_error_string (ar_dest).fromStringz)); + if (archive_entry_filetype (en) == AE_IFREG) { + this.extractEntryTo (ar, pathname); } } } @@ -600,7 +594,6 @@ unittest writeln ("TEST: ", "Extracting a tarball"); - import bindings.asgenstdilb : mkdtemp; import std.file : buildPath, tempDir; auto archive = buildPath (getcwd (), "test", "samples", "test.tar.xz"); From b7c4ccfe4aca35500ef6116161c70874028a3a08 Mon Sep 17 00:00:00 2001 From: Iain Lane Date: Wed, 31 Aug 2016 15:50:09 +0100 Subject: [PATCH 4/5] Use getTestSamplesDir --- source/zarchive.d | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/zarchive.d b/source/zarchive.d index ebece4ff..d9c1e2fa 100644 --- a/source/zarchive.d +++ b/source/zarchive.d @@ -595,8 +595,9 @@ unittest writeln ("TEST: ", "Extracting a tarball"); import std.file : buildPath, tempDir; + import utils : getTestSamplesDir; - auto archive = buildPath (getcwd (), "test", "samples", "test.tar.xz"); + auto archive = buildPath (getTestSamplesDir (), "test.tar.xz"); assert (archive.exists); auto ar = new ArchiveDecompressor (); From aa04719a7abe90114ac8fcba384db6065971002a Mon Sep 17 00:00:00 2001 From: Iain Lane Date: Wed, 31 Aug 2016 16:46:06 +0100 Subject: [PATCH 5/5] Rename processDesktopFile to getDesktopFileTranslations --- source/backends/interfaces.d | 2 +- source/backends/ubuntu/ubupkg.d | 2 +- source/handlers/desktopparser.d | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/backends/interfaces.d b/source/backends/interfaces.d index 176aea01..fb35eae9 100644 --- a/source/backends/interfaces.d +++ b/source/backends/interfaces.d @@ -66,7 +66,7 @@ abstract class Package /** * Retrieve backend-specific translations. */ - string[string] processDesktopFile (KeyFile desktopFile, const string text) { return null; } + string[string] getDesktopFileTranslations (KeyFile desktopFile, const string text) { return null; } /** * Close the package. This function is called when we will diff --git a/source/backends/ubuntu/ubupkg.d b/source/backends/ubuntu/ubupkg.d index fbbfa9d7..4742f281 100644 --- a/source/backends/ubuntu/ubupkg.d +++ b/source/backends/ubuntu/ubupkg.d @@ -47,7 +47,7 @@ class UbuntuPackage : DebPackage super (pname, pver, parch); } - override string[string] processDesktopFile (KeyFile desktopFile, const string text) + override string[string] getDesktopFileTranslations (KeyFile desktopFile, const string text) { string langpackdomain; diff --git a/source/handlers/desktopparser.d b/source/handlers/desktopparser.d index 555b98a9..7fe09f57 100644 --- a/source/handlers/desktopparser.d +++ b/source/handlers/desktopparser.d @@ -202,14 +202,14 @@ Component parseDesktopFile (GeneratorResult gres, string fname, string data, boo immutable val = getValue (df, key); checkDesktopString (key, val); /* run backend specific hooks */ - auto translations = gres.pkg.processDesktopFile (df, val); + auto translations = gres.pkg.getDesktopFileTranslations (df, val); translations[locale] = val; foreach (key, value; translations) cpt.setName (value, key); } else if (key.startsWith ("Comment")) { immutable val = getValue (df, key); checkDesktopString (key, val); - auto translations = gres.pkg.processDesktopFile (df, val); + auto translations = gres.pkg.getDesktopFileTranslations (df, val); translations[locale] = val; foreach (key, value; translations) cpt.setSummary (value, key); @@ -224,7 +224,7 @@ Component parseDesktopFile (GeneratorResult gres, string fname, string data, boo cpt.addCategory (c); } else if (key.startsWith ("Keywords")) { auto val = getValue (df, key); - auto translations = gres.pkg.processDesktopFile (df, val); + auto translations = gres.pkg.getDesktopFileTranslations (df, val); translations[locale] = val; foreach (key, value; translations) { auto kws = value.split (";").stripRight ("");