0001-builder-Implement-support-for-.pisi-format.patch 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  1. From b31fb56588c264d297ca04f36a7b3162d3db7736 Mon Sep 17 00:00:00 2001
  2. From: Ikey Doherty <ikey@solus-project.com>
  3. Date: Sun, 26 Jul 2015 16:01:47 +0100
  4. Subject: [PATCH 1/2] builder: Implement support for Solus .pisi format
  5. This format is employed by the Solus Operating System, and is implemented
  6. in such a manner that it does not need to rely on executing the external
  7. pisi program, which is Pythonic, thus slower.
  8. This utilises code that is part of an ongoing rewrite of pisi, as such
  9. in the future it would be refactored to use a 'libpisi'. As such no pretense
  10. is held to support the "PiSi" format, which the Pythonic pisi is forked from,
  11. as that support will not hold in the future in libpisi.
  12. As of 25 Jun 2021, this patch adapted for appstream-glib 0.7.18 and .pisi format by:
  13. Berk Çakar <berkcakar@pisilinux.org>
  14. Signed-off-by: Ikey Doherty <ikey@solus-project.com>
  15. ---
  16. meson.build | 6 ++++++
  17. meson_options.txt | 1 +
  18. libappstream-builder/meson.build | 8 ++++++++
  19. libappstream-builder/asb-context.c | 7 +++++++
  20. libappstream-builder/asb-package-pisi.c | 532 +++++++++++++++++++++++++++++++
  21. libappstream-builder/asb-package-pisi.h | 60 ++++
  22. 5 files changed, 613 insertions(+)
  23. create mode 100644 libappstream-builder/asb-package-pisi.c
  24. create mode 100644 libappstream-builder/asb-package-pisi.h
  25. --- a/meson.build
  26. +++ b/meson.build
  27. @@ -97,6 +97,12 @@ if get_option('rpm')
  28. conf.set('HAVE_RPM', 1)
  29. endif
  30. +if get_option('pisi')
  31. + # dummy dependency for now...
  32. + pisi = dependency('libxml-2.0')
  33. + conf.set('HAVE_PISI', 1)
  34. +endif
  35. +
  36. # support loading yaml files
  37. if get_option('dep11')
  38. yaml = dependency('yaml-0.1')
  39. diff --git a/meson_options.txt b/meson_options.txt
  40. index 518ed89..9d6d543 100644
  41. --- a/meson_options.txt
  42. +++ b/meson_options.txt
  43. @@ -2,6 +2,7 @@ option('dep11', type : 'boolean', value : true, description : 'enable DEP-11')
  44. option('builder', type : 'boolean', value : true, description : 'enable AppStream builder')
  45. option('rpm', type : 'boolean', value : true, description : 'enable RPM support')
  46. option('alpm', type : 'boolean', value : false, description : 'enable ALPM support')
  47. +option('pisi', type : 'boolean', value : false, description : 'enable PiSi support')
  48. option('fonts', type : 'boolean', value : true, description : 'enable font support')
  49. option('stemmer', type : 'boolean', value : true, description : 'enable stemmer support')
  50. option('man', type : 'boolean', value : true, description : 'generate man pages')
  51. diff --git a/libappstream-builder/meson.build b/libappstream-builder/meson.build
  52. index 79e8a74..bf85c5d 100644
  53. --- a/libappstream-builder/meson.build
  54. +++ b/libappstream-builder/meson.build
  55. @@ -25,6 +25,10 @@ if get_option('alpm')
  56. deps = deps + [alpm]
  57. endif
  58. +if get_option('pisi')
  59. + deps = deps + [pisi]
  60. +endif
  61. +
  62. sources = [
  63. 'asb-app.c',
  64. 'asb-context.c',
  65. @@ -45,6 +49,10 @@ if get_option('alpm')
  66. sources = sources + ['asb-package-alpm.c']
  67. endif
  68. +if get_option('pisi')
  69. + sources = sources + ['asb-package-pisi.c']
  70. +endif
  71. +
  72. top_build_incdir = include_directories('..')
  73. asbuilder = static_library(
  74. diff --git a/libappstream-builder/asb-context.c b/libappstream-builder/asb-context.c
  75. index e2b83df..4fefadd 100644
  76. --- a/libappstream-builder/asb-context.c
  77. +++ b/libappstream-builder/asb-context.c
  78. @@ -32,6 +32,9 @@
  79. #ifdef HAVE_ALPM
  80. #include "asb-package-alpm.h"
  81. #endif
  82. +#ifdef HAVE_PISI
  83. +#include "asb-package-pisi.h"
  84. +#endif
  85. #include "asb-package-cab.h"
  86. #include "asb-package-deb.h"
  87. @@ -447,6 +452,10 @@ asb_context_add_filename (AsbContext *ctx, const gchar *filename, GError **error
  88. if (g_str_has_suffix (filename, ".pkg.tar") ||
  89. g_str_has_suffix (filename, ".pkg.tar.xz"))
  90. pkg = asb_package_alpm_new ();
  91. -#endif
  92. +#endif
  93. +#ifdef HAVE_PISI
  94. + if (g_str_has_suffix (filename, ".pisi"))
  95. + pkg = asb_package_pisi_new ();
  96. +#endif
  97. if (g_str_has_suffix (filename, ".cab"))
  98. pkg = asb_package_cab_new ();
  99. diff --git a/libappstream-builder/asb-package-pisi.c b/libappstream-builder/asb-package-pisi.c
  100. new file mode 100644
  101. index 0000000..cf6572c
  102. --- /dev/null
  103. +++ b/libappstream-builder/asb-package-pisi.c
  104. @@ -0,0 +1,532 @@
  105. +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  106. + *
  107. + * Copyright (C) 2015 Ikey Doherty <ikey@solus-project.com>
  108. + *
  109. + * Licensed under the GNU Lesser General Public License Version 2.1
  110. + *
  111. + * This library is free software; you can redistribute it and/or
  112. + * modify it under the terms of the GNU Lesser General Public
  113. + * License as published by the Free Software Foundation; either
  114. + * version 2.1 of the License, or (at your option) any later version.
  115. + *
  116. + * This library is distributed in the hope that it will be useful,
  117. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  118. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  119. + * Lesser General Public License for more details.
  120. + *
  121. + * You should have received a copy of the GNU Lesser General Public
  122. + * License along with this library; if not, write to the Free Software
  123. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  124. + */
  125. +
  126. +/**
  127. + * SECTION:asb-package-pisi
  128. + * @short_description: Object representing a .PISI package file.
  129. + * @stability: Unstable
  130. + *
  131. + * This object represents one .pisi package file.
  132. + */
  133. +
  134. +#include "config.h"
  135. +
  136. +#include "asb-package-pisi.h"
  137. +#include "asb-plugin.h"
  138. +
  139. +#include <archive.h>
  140. +#include <archive_entry.h>
  141. +#include <libxml/xmlreader.h>
  142. +#include <errno.h>
  143. +#include <string.h>
  144. +
  145. +G_DEFINE_TYPE (AsbPackagePisi, asb_package_pisi, ASB_TYPE_PACKAGE)
  146. +
  147. +/**
  148. + * Storage for pisi metadata
  149. + */
  150. +typedef struct pisi_meta_t {
  151. + gchar *name; /**<Binary package name */
  152. + gchar *source; /**<Distro source name */
  153. + gint release; /**<Release number */
  154. + gchar *version; /**<Package version */
  155. + gchar *url; /**<Upstream URL, i.e. homepage */
  156. + GSList *deps; /**<List of string-name dependencies */
  157. + GSList *licenses; /**<List of licenses (usually SPDX) */
  158. +} pisi_meta_t;
  159. +
  160. +/**
  161. + * State tracking for metadata.xml traversal
  162. + */
  163. +typedef struct meta_state_t {
  164. + gboolean in_name;
  165. + gboolean in_source;
  166. + gboolean in_packager;
  167. + gboolean in_url;
  168. + gboolean in_dep;
  169. + gboolean in_rundeps;
  170. + gboolean in_license;
  171. + gboolean in_package;
  172. + gboolean in_update;
  173. + gboolean in_version;
  174. + gboolean need_update;
  175. +} meta_state_t;
  176. +
  177. +/**
  178. + * State tracking for files.xml traversal
  179. + */
  180. +typedef struct file_state_t {
  181. + gboolean in_file;
  182. + gboolean in_path;
  183. +} file_state_t;
  184. +
  185. +/**
  186. + * Complete binary .pisi representation
  187. + */
  188. +typedef struct pisi_t {
  189. + pisi_meta_t *meta; /**<Metadata */
  190. + GPtrArray *files; /**<List of files (not directories) */
  191. +} pisi_t;
  192. +
  193. +
  194. +/**
  195. + * Process metadata.xml node
  196. + */
  197. +gboolean process_meta_node(meta_state_t *self, pisi_meta_t *meta, xmlTextReaderPtr r);
  198. +
  199. +/**
  200. + * Examine a metadata file, returning the appropriate storage when complete
  201. + */
  202. +pisi_meta_t *examine_metadata(const char *filename);
  203. +
  204. +/**
  205. + * Process a files.xml node
  206. + */
  207. +gboolean process_file_node(file_state_t *self, GPtrArray *ret, xmlTextReaderPtr r);
  208. +
  209. +/**
  210. + * Examine a files xml file, returning the appropriate storage when complete
  211. + */
  212. +GPtrArray *examine_files(const char *filename);
  213. +
  214. +/**
  215. + * Utility to free an pisi_meta_t
  216. + */
  217. +void pisi_meta_free(pisi_meta_t *pisi);
  218. +
  219. +/**
  220. + * Free sources for an pisi_t
  221. + */
  222. +void close_pisi(pisi_t *pisi);
  223. +
  224. +/**
  225. + * Open, and inspect, the archive identified by filename. This must be an
  226. + * .pisi file
  227. + */
  228. +pisi_t *open_pisi(const char *filename);
  229. +
  230. +gboolean process_meta_node(meta_state_t *self, pisi_meta_t *meta, xmlTextReaderPtr r)
  231. +{
  232. + const xmlChar *name = NULL;
  233. + int rel;
  234. + const xmlChar *val = NULL;
  235. +
  236. + name = xmlTextReaderConstName(r);
  237. + if (!name) {
  238. + return FALSE;
  239. + }
  240. +
  241. + if (xmlStrEqual(name, BAD_CAST "Source")) {
  242. + self->in_source = !self->in_source;
  243. + } else if (xmlStrEqual(name, BAD_CAST "Package")) {
  244. + self->in_package = !self->in_package;
  245. + } else if (xmlStrEqual(name, BAD_CAST "Update")) {
  246. + self->in_update = !self->in_update;
  247. + if (self->in_update) {
  248. + xmlChar *attr = xmlTextReaderGetAttribute(r, BAD_CAST "release");
  249. + if (!attr) {
  250. + fprintf(stderr, "Malformed spec: No release ID\n");
  251. + return FALSE;
  252. + }
  253. + rel = atoi((const char*)attr);
  254. + if (rel > meta->release) {
  255. + meta->release = rel;
  256. + self->need_update = TRUE;
  257. + }
  258. + xmlFree(attr);
  259. + }
  260. + }
  261. +
  262. + if (self->in_source) {
  263. + if (xmlStrEqual(name, BAD_CAST "Name")) {
  264. + self->in_name = !self->in_name;
  265. + } else if (xmlStrEqual(name, BAD_CAST "Packager")) {
  266. + self->in_packager = !self->in_packager;
  267. + } else if (xmlStrEqual(name, BAD_CAST "Homepage")) {
  268. + self->in_url = !self->in_url;
  269. + }
  270. + if (self->in_name && !self->in_packager && !meta->source) {
  271. + val = xmlTextReaderConstValue(r);
  272. + if (!val) {
  273. + return TRUE;
  274. + }
  275. + meta->source = g_strdup((gchar*)val);
  276. + } else if (self->in_url && !meta->url) {
  277. + val = xmlTextReaderConstValue(r);
  278. + if (!val) {
  279. + return TRUE;
  280. + }
  281. + meta->url = g_strdup((gchar*)val);
  282. + }
  283. + } else if (self->in_package) {
  284. + if (xmlStrEqual(name, BAD_CAST "Name")) {
  285. + self->in_name = !self->in_name;
  286. + } else if (xmlStrEqual(name, BAD_CAST "License")) {
  287. + self->in_license = !self->in_license;
  288. + } else if (xmlStrEqual(name, BAD_CAST "RuntimeDependencies")) {
  289. + self->in_rundeps = !self->in_rundeps;
  290. + }
  291. + if (self->in_name && !self->in_update) {
  292. + val = xmlTextReaderConstValue(r);
  293. + if (!val) {
  294. + return TRUE;
  295. + }
  296. + meta->name = g_strdup((gchar*)val);
  297. + } else if (self->in_license) {
  298. + val = xmlTextReaderConstValue(r);
  299. + if (!val) {
  300. + return TRUE;
  301. + }
  302. + meta->licenses = g_slist_prepend(meta->licenses, g_strdup((gchar*)val));
  303. + } else if (self->in_rundeps) {
  304. + if (xmlStrEqual(name, BAD_CAST "Dependency")) {
  305. + self->in_dep = !self->in_dep;
  306. + }
  307. + val = xmlTextReaderConstValue(r);
  308. + if (self->in_dep && val) {
  309. + meta->deps = g_slist_prepend(meta->deps, g_strdup((gchar*)val));
  310. + }
  311. + } else if (self->in_update && self->need_update) {
  312. + /* invariably we'll hit here only once from sorted (default) high-to-low history in spec */
  313. + if (xmlStrEqual(name, BAD_CAST "Version")) {
  314. + self->in_version = !self->in_version;
  315. + }
  316. + if (self->in_version) {
  317. + val = xmlTextReaderConstValue(r);
  318. + if (!val) {
  319. + return TRUE;
  320. + }
  321. + if (meta->version) {
  322. + g_free(meta->version);
  323. + }
  324. + meta->version = g_strdup((gchar*)val);
  325. + self->need_update = FALSE;
  326. + }
  327. + }
  328. + }
  329. + return TRUE;
  330. +}
  331. +
  332. +pisi_meta_t *examine_metadata(const char *filename)
  333. +{
  334. + xmlTextReaderPtr r = xmlReaderForFile(filename, NULL, 0);
  335. + int ret;
  336. + meta_state_t self = {0};
  337. + pisi_meta_t *meta = NULL;
  338. +
  339. + meta = calloc(1, sizeof(pisi_meta_t));
  340. + if (!meta) {
  341. + fprintf(stderr, "OOM\n");
  342. + return NULL;
  343. + }
  344. +
  345. + while ((ret = xmlTextReaderRead(r)) > 0) {
  346. + if (!process_meta_node(&self, meta, r)) {
  347. + fprintf(stderr, "process_meta_node exited abnormally\n");
  348. + break;
  349. + }
  350. + }
  351. +
  352. + xmlFreeTextReader(r);
  353. + return meta;
  354. +}
  355. +
  356. +gboolean process_file_node(file_state_t *self, GPtrArray *ret, xmlTextReaderPtr r)
  357. +{
  358. + const xmlChar *name = NULL;
  359. +
  360. + name = xmlTextReaderConstName(r);
  361. + if (!name) {
  362. + return FALSE;
  363. + }
  364. +
  365. + if (xmlStrEqual(name, BAD_CAST "File")) {
  366. + self->in_file = !self->in_file;
  367. + } else if (self->in_file && xmlStrEqual(name, BAD_CAST "Path")) {
  368. + self->in_path = !self->in_path;
  369. + } else if (self->in_path) {
  370. + const xmlChar *val = xmlTextReaderConstValue(r);
  371. + gchar *tmp = NULL;
  372. + if (!val) {
  373. + return TRUE;
  374. + }
  375. + if (val[0] != '/') {
  376. + tmp = g_strdup_printf("/%s", (gchar*)val);
  377. + } else {
  378. + tmp = g_strdup((gchar*)val);
  379. + }
  380. + g_ptr_array_add(ret, tmp);
  381. + }
  382. + return TRUE;
  383. +}
  384. +
  385. +GPtrArray *examine_files(const char *filename)
  386. +{
  387. + xmlTextReaderPtr r = xmlReaderForFile(filename, NULL, 0);
  388. + int ret;
  389. + file_state_t self = {0};
  390. + GPtrArray *arr = NULL;
  391. +
  392. + arr = g_ptr_array_new_with_free_func(g_free);
  393. + if (!arr) {
  394. + fprintf(stderr, "OOM\n");
  395. + return NULL;
  396. + }
  397. +
  398. + while ((ret = xmlTextReaderRead(r)) > 0) {
  399. + if (!process_file_node(&self, arr, r)) {
  400. + fprintf(stderr, "process_file_node exited abnormally\n");
  401. + break;
  402. + }
  403. + }
  404. +
  405. + g_ptr_array_add(arr, NULL);
  406. +
  407. + xmlFreeTextReader(r);
  408. + return arr;
  409. +}
  410. +
  411. +void pisi_meta_free(pisi_meta_t *pisi)
  412. +{
  413. + if (!pisi) {
  414. + return;
  415. + }
  416. + if (pisi->name) {
  417. + g_free(pisi->name);
  418. + }
  419. + if (pisi->source) {
  420. + g_free(pisi->source);
  421. + }
  422. + if (pisi->version) {
  423. + g_free(pisi->version);
  424. + }
  425. + if (pisi->url) {
  426. + g_free(pisi->url);
  427. + }
  428. + if (pisi->deps) {
  429. + g_slist_free_full(pisi->deps, g_free);
  430. + }
  431. + if (pisi->licenses) {
  432. + g_slist_free_full(pisi->licenses, g_free);
  433. + }
  434. + free(pisi);
  435. +}
  436. +
  437. +void close_pisi(pisi_t *pisi)
  438. +{
  439. + if (pisi->meta) {
  440. + pisi_meta_free(pisi->meta);
  441. + }
  442. + if (pisi->files) {
  443. + g_ptr_array_unref(pisi->files);
  444. + }
  445. + free(pisi);
  446. +}
  447. +
  448. +pisi_t *open_pisi(const char *filename)
  449. +{
  450. + pisi_t *ret = NULL;
  451. + pisi_meta_t *meta = NULL;
  452. + GPtrArray *files = NULL;
  453. + struct archive *a = NULL;
  454. + struct archive_entry *entry = NULL;
  455. + int r;
  456. + char fname[PATH_MAX];
  457. + char template[] = "/tmp/solus-pisi-XXXXXX";
  458. + int fd;
  459. +
  460. + a = archive_read_new();
  461. + archive_read_support_filter_all(a);
  462. + archive_read_support_format_all(a);
  463. +
  464. + /* open 'er up */
  465. + r = archive_read_open_filename(a, filename, 10480);
  466. + if (r != ARCHIVE_OK) {
  467. + fprintf(stderr, "Unable to open archive\n");
  468. + goto clean;
  469. + }
  470. +
  471. + while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
  472. + const char *name = archive_entry_pathname(entry);
  473. + gboolean filesxml = FALSE;
  474. +
  475. + if ((filesxml = g_str_equal(name, "files.xml")) || g_str_equal(name, "metadata.xml")) {
  476. + strncpy(fname, template, sizeof(template));
  477. + fd = mkstemp(fname);
  478. + if (fd <= 0) {
  479. + fprintf(stderr, "Failed to open temporary file: %s\n", strerror(errno));
  480. + goto clean;
  481. + }
  482. +
  483. + r = archive_read_data_into_fd(a, fd);
  484. + if (r != ARCHIVE_OK) {
  485. + fprintf(stderr, "Failed to extra file: %s\n", name);
  486. + close(fd);
  487. + (void)unlink(fname);
  488. + goto clean;
  489. + }
  490. +
  491. + if (filesxml) {
  492. + files = examine_files(fname);
  493. + } else {
  494. + meta = examine_metadata(fname);
  495. + }
  496. + close(fd);
  497. + (void)unlink(fname);
  498. +
  499. + } else {
  500. + archive_read_data_skip(a);
  501. + }
  502. + }
  503. +
  504. + if (!meta) {
  505. + fprintf(stderr, "Failed to inspect metadata\n");
  506. + goto bail;
  507. + }
  508. + if (!files) {
  509. + fprintf(stderr, "Failed to inspect files\n");
  510. + goto bail;
  511. + }
  512. +
  513. + ret = calloc(1, sizeof(pisi_t));
  514. + if (!ret) {
  515. + fprintf(stderr, "OOM\n");
  516. + goto bail;
  517. + }
  518. +
  519. + ret->meta = meta;
  520. + ret->files = files;
  521. +
  522. +clean:
  523. + archive_read_free(a);
  524. +
  525. + return ret;
  526. +
  527. +bail:
  528. + if (meta) {
  529. + pisi_meta_free(meta);
  530. + }
  531. + if (files) {
  532. + g_ptr_array_unref(files);
  533. + }
  534. + return NULL;
  535. +}
  536. +
  537. +/**
  538. + * asb_package_pisi_init:
  539. + **/
  540. +static void
  541. +asb_package_pisi_init (AsbPackagePisi *pkg)
  542. +{
  543. +}
  544. +
  545. +
  546. +/**
  547. + * asb_package_pisi_open:
  548. + **/
  549. +static gboolean
  550. +asb_package_pisi_open (AsbPackage *pkg, const gchar *filename, GError **error)
  551. +{
  552. + pisi_t *pisi = NULL;
  553. + gchar *rel = NULL;
  554. + GSList *elem = NULL;
  555. +
  556. + pisi = open_pisi(filename);
  557. + if (!pisi)
  558. + return FALSE;
  559. +
  560. + asb_package_set_name (pkg, pisi->meta->name);
  561. + asb_package_set_source (pkg, pisi->meta->source);
  562. +
  563. + rel = g_strdup_printf ("%d", pisi->meta->release);
  564. + asb_package_set_release (pkg, rel);
  565. + asb_package_set_version (pkg, pisi->meta->version);
  566. + asb_package_set_epoch (pkg, 1);
  567. + g_free(rel);
  568. +
  569. + for (elem = pisi->meta->deps; elem; elem = elem->next) {
  570. + asb_package_add_dep (pkg, elem->data);
  571. + }
  572. + asb_package_set_filelist (pkg, (gchar**)pisi->files->pdata);
  573. +
  574. + asb_package_set_license (pkg, pisi->meta->licenses->data);
  575. +
  576. + close_pisi(pisi);
  577. +
  578. + return TRUE;
  579. +}
  580. +
  581. +/**
  582. + * asb_package_pisi_explode:
  583. + **/
  584. +static gboolean
  585. +asb_package_pisi_explode (AsbPackage *pkg,
  586. + const gchar *dir,
  587. + GPtrArray *glob,
  588. + GError **error)
  589. +{
  590. + const char *name = "install.tar.xz";
  591. + g_autofree gchar *tpath = NULL;
  592. +
  593. + if (!asb_utils_explode (asb_package_get_filename (pkg),
  594. + dir, NULL, error)) {
  595. + return FALSE;
  596. + }
  597. +
  598. + tpath = g_build_filename(dir, name, NULL);
  599. + if (!g_file_test (tpath, G_FILE_TEST_EXISTS)) {
  600. + return FALSE;
  601. + }
  602. +
  603. + if (!asb_utils_explode (tpath, dir, glob, error)) {
  604. + return FALSE;
  605. + }
  606. +
  607. + return TRUE;
  608. +}
  609. +
  610. +/**
  611. + * asb_package_pisi_class_init:
  612. + **/
  613. +static void
  614. +asb_package_pisi_class_init (AsbPackagePisiClass *klass)
  615. +{
  616. + AsbPackageClass *package_class = ASB_PACKAGE_CLASS (klass);
  617. + package_class->open = asb_package_pisi_open;
  618. + package_class->explode = asb_package_pisi_explode;
  619. +}
  620. +
  621. +/**
  622. + * asb_package_pisi_new:
  623. + *
  624. + * Creates a new PISI package.
  625. + *
  626. + * Returns: a package
  627. + *
  628. + * Since: 0.1.0
  629. + **/
  630. +AsbPackage *
  631. +asb_package_pisi_new (void)
  632. +{
  633. + AsbPackage *pkg;
  634. + pkg = g_object_new (ASB_TYPE_PACKAGE_PISI, NULL);
  635. + return ASB_PACKAGE (pkg);
  636. +}
  637. diff --git a/libappstream-builder/asb-package-pisi.h b/libappstream-builder/asb-package-pisi.h
  638. new file mode 100644
  639. index 0000000..08dd01d
  640. --- /dev/null
  641. +++ b/libappstream-builder/asb-package-pisi.h
  642. @@ -0,0 +1,60 @@
  643. +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  644. + *
  645. + * Copyright (C) 2015 Ikey Doherty <ikey@solus-project.com>
  646. + *
  647. + * Licensed under the GNU Lesser General Public License Version 2.1
  648. + *
  649. + * This library is free software; you can redistribute it and/or
  650. + * modify it under the terms of the GNU Lesser General Public
  651. + * License as published by the Free Software Foundation; either
  652. + * version 2.1 of the License, or (at your option) any later version.
  653. + *
  654. + * This library is distributed in the hope that it will be useful,
  655. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  656. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  657. + * Lesser General Public License for more details.
  658. + *
  659. + * You should have received a copy of the GNU Lesser General Public
  660. + * License along with this library; if not, write to the Free Software
  661. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  662. + */
  663. +
  664. +#ifndef ASB_PACKAGE_PISI_H
  665. +#define ASB_PACKAGE_PISI_H
  666. +
  667. +#include <glib-object.h>
  668. +
  669. +#include <stdarg.h>
  670. +#include <appstream-glib.h>
  671. +
  672. +#include "asb-package.h"
  673. +
  674. +#define ASB_TYPE_PACKAGE_PISI (asb_package_pisi_get_type())
  675. +#define ASB_PACKAGE_PISI(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), ASB_TYPE_PACKAGE_PISI, AsbPackagePisi))
  676. +#define ASB_PACKAGE_PISI_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST((cls), ASB_TYPE_PACKAGE_PISI, AsbPackagePisiClass))
  677. +#define ASB_IS_PACKAGE_PISI(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), ASB_TYPE_PACKAGE_PISI))
  678. +#define ASB_IS_PACKAGE_PISI_CLASS(cls) (G_TYPE_CHECK_CLASS_TYPE((cls), ASB_TYPE_PACKAGE_PISI))
  679. +#define ASB_PACKAGE_PISI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), ASB_TYPE_PACKAGE_PISI, AsbPackagePisiClass))
  680. +
  681. +G_BEGIN_DECLS
  682. +
  683. +typedef struct _AsbPackagePisi AsbPackagePisi;
  684. +typedef struct _AsbPackagePisiClass AsbPackagePisiClass;
  685. +
  686. +struct _AsbPackagePisi
  687. +{
  688. + AsbPackage parent;
  689. +};
  690. +
  691. +struct _AsbPackagePisiClass
  692. +{
  693. + AsbPackageClass parent_class;
  694. +};
  695. +
  696. +GType asb_package_pisi_get_type (void);
  697. +
  698. +AsbPackage *asb_package_pisi_new (void);
  699. +
  700. +G_END_DECLS
  701. +
  702. +#endif /* ASB_PACKAGE_PISI_H */
  703. --
  704. 2.11.0