1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2  *
3  * Copyright (C) 2014 Richard Hughes <richard@hughsie.com>
4  *
5  * SPDX-License-Identifier: LGPL-2.1+
6  */
7 
8 /**
9  * SECTION:asb-package
10  * @short_description: Object representing a package file.
11  * @stability: Unstable
12  *
13  * This object represents one package file.
14  */
15 
16 #include "config.h"
17 
18 #include <limits.h>
19 
20 #include "asb-package.h"
21 #include "asb-plugin.h"
22 
23 typedef struct
24 {
25 	AsbPackageKind	 kind;
26 	gboolean	 enabled;
27 	gboolean	 is_open;
28 	gchar		**filelist;
29 	guint		 filelist_refcount;
30 	GPtrArray	*deps;
31 	guint		 deps_refcount;
32 	gchar		*filename;
33 	gchar		*basename;
34 	gchar		*name;
35 	guint		 epoch;
36 	gchar		*version;
37 	gchar		*release;
38 	gchar		*arch;
39 	gchar		*url;
40 	gchar		*nevr;
41 	gchar		*nevra;
42 	gchar		*evr;
43 	gchar		*license;
44 	gchar		*vcs;
45 	gchar		*source_nevra;
46 	gchar		*source_pkgname;
47 	gsize		 log_written_len;
48 	GString		*log;
49 	GHashTable	*configs;
50 	GTimer		*timer;
51 	gdouble		 last_log;
52 	GPtrArray	*releases;
53 	GHashTable	*releases_hash;
54 	GMutex		 mutex_log;
55 } AsbPackagePrivate;
56 
G_DEFINE_TYPE_WITH_PRIVATE(AsbPackage,asb_package,G_TYPE_OBJECT)57 G_DEFINE_TYPE_WITH_PRIVATE (AsbPackage, asb_package, G_TYPE_OBJECT)
58 
59 #define GET_PRIVATE(o) (asb_package_get_instance_private (o))
60 
61 static void
62 asb_package_finalize (GObject *object)
63 {
64 	AsbPackage *pkg = ASB_PACKAGE (object);
65 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
66 
67 	g_mutex_clear (&priv->mutex_log);
68 	g_strfreev (priv->filelist);
69 	g_ptr_array_unref (priv->deps);
70 	g_free (priv->filename);
71 	g_free (priv->basename);
72 	g_free (priv->name);
73 	g_free (priv->version);
74 	g_free (priv->release);
75 	g_free (priv->arch);
76 	g_free (priv->url);
77 	g_free (priv->nevr);
78 	g_free (priv->nevra);
79 	g_free (priv->evr);
80 	g_free (priv->license);
81 	g_free (priv->vcs);
82 	g_free (priv->source_nevra);
83 	g_free (priv->source_pkgname);
84 	g_string_free (priv->log, TRUE);
85 	g_timer_destroy (priv->timer);
86 	g_hash_table_unref (priv->configs);
87 	g_ptr_array_unref (priv->releases);
88 	g_hash_table_unref (priv->releases_hash);
89 
90 	G_OBJECT_CLASS (asb_package_parent_class)->finalize (object);
91 }
92 
93 static void
asb_package_init(AsbPackage * pkg)94 asb_package_init (AsbPackage *pkg)
95 {
96 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
97 	priv->enabled = TRUE;
98 	priv->log = g_string_new (NULL);
99 	priv->timer = g_timer_new ();
100 	priv->deps = g_ptr_array_new_with_free_func (g_free);
101 	priv->configs = g_hash_table_new_full (g_str_hash, g_str_equal,
102 					       g_free, g_free);
103 	priv->releases = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
104 	priv->releases_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
105 						     g_free, (GDestroyNotify) g_object_unref);
106 	g_mutex_init (&priv->mutex_log);
107 }
108 
109 /**
110  * asb_package_get_enabled:
111  * @pkg: A #AsbPackage
112  *
113  * Gets if the package is enabled.
114  *
115  * Returns: enabled status
116  *
117  * Since: 0.1.0
118  **/
119 gboolean
asb_package_get_enabled(AsbPackage * pkg)120 asb_package_get_enabled (AsbPackage *pkg)
121 {
122 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
123 	return priv->enabled;
124 }
125 
126 /**
127  * asb_package_set_enabled:
128  * @pkg: A #AsbPackage
129  * @enabled: boolean
130  *
131  * Enables or disables the package.
132  *
133  * Since: 0.1.0
134  **/
135 void
asb_package_set_enabled(AsbPackage * pkg,gboolean enabled)136 asb_package_set_enabled (AsbPackage *pkg, gboolean enabled)
137 {
138 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
139 	priv->enabled = enabled;
140 }
141 
142 /**
143  * asb_package_log_start:
144  * @pkg: A #AsbPackage
145  *
146  * Starts the log timer.
147  *
148  * Since: 0.1.0
149  **/
150 void
asb_package_log_start(AsbPackage * pkg)151 asb_package_log_start (AsbPackage *pkg)
152 {
153 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
154 	g_timer_reset (priv->timer);
155 }
156 
157 /**
158  * asb_package_log:
159  * @pkg: A #AsbPackage
160  * @log_level: a #AsbPackageLogLevel
161  * @fmt: Format string
162  * @...: varargs
163  *
164  * Logs a message.
165  *
166  * Since: 0.1.0
167  **/
168 void
asb_package_log(AsbPackage * pkg,AsbPackageLogLevel log_level,const gchar * fmt,...)169 asb_package_log (AsbPackage *pkg,
170 		 AsbPackageLogLevel log_level,
171 		 const gchar *fmt, ...)
172 {
173 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
174 	va_list args;
175 	gdouble now;
176 	g_autofree gchar *tmp = NULL;
177 
178 	g_mutex_lock (&priv->mutex_log);
179 
180 	va_start (args, fmt);
181 	tmp = g_strdup_vprintf (fmt, args);
182 	va_end (args);
183 	if (g_getenv ("ASB_PROFILE") != NULL) {
184 		now = g_timer_elapsed (priv->timer, NULL) * 1000;
185 		g_string_append_printf (priv->log,
186 					"%05.0f\t+%05.0f\t",
187 					now, now - priv->last_log);
188 		priv->last_log = now;
189 	}
190 	switch (log_level) {
191 	case ASB_PACKAGE_LOG_LEVEL_INFO:
192 		g_debug ("INFO:    %s", tmp);
193 		g_string_append_printf (priv->log, "INFO:    %s\n", tmp);
194 		break;
195 	case ASB_PACKAGE_LOG_LEVEL_DEBUG:
196 		g_debug ("DEBUG:   %s", tmp);
197 		g_string_append_printf (priv->log, "DEBUG:   %s\n", tmp);
198 		break;
199 	case ASB_PACKAGE_LOG_LEVEL_WARNING:
200 		g_debug ("WARNING: %s", tmp);
201 		g_string_append_printf (priv->log, "WARNING: %s\n", tmp);
202 		break;
203 	default:
204 		g_debug ("%s", tmp);
205 		g_string_append_printf (priv->log, "%s\n", tmp);
206 		break;
207 	}
208 	g_mutex_unlock (&priv->mutex_log);
209 }
210 
211 /**
212  * asb_package_log_flush:
213  * @pkg: A #AsbPackage
214  * @error: A #GError or %NULL
215  *
216  * Flushes the log queue.
217  *
218  * Returns: %TRUE for success, %FALSE otherwise
219  *
220  * Since: 0.1.0
221  **/
222 gboolean
asb_package_log_flush(AsbPackage * pkg,GError ** error)223 asb_package_log_flush (AsbPackage *pkg, GError **error)
224 {
225 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
226 	g_autofree gchar *logfile = NULL;
227 	g_autofree gchar *logdir_char = NULL;
228 
229 	/* needs no update */
230 	if (priv->log_written_len == priv->log->len)
231 		return TRUE;
232 
233 	/* don't write if unset */
234 	if (asb_package_get_config (pkg, "LogDir") == NULL)
235 		return TRUE;
236 
237 	/* overwrite old log */
238 	logdir_char = g_strdup_printf ("%s/%c",
239 				       asb_package_get_config (pkg, "LogDir"),
240 				       g_ascii_tolower (priv->name[0]));
241 	if (!asb_utils_ensure_exists (logdir_char, error))
242 		return FALSE;
243 	priv->log_written_len = priv->log->len;
244 	logfile = g_strdup_printf ("%s/%s.log", logdir_char, priv->name);
245 	return g_file_set_contents (logfile, priv->log->str, -1, error);
246 }
247 
248 /**
249  * asb_package_get_filename:
250  * @pkg: A #AsbPackage
251  *
252  * Gets the filename of the package.
253  *
254  * Returns: utf8 filename
255  *
256  * Since: 0.1.0
257  **/
258 const gchar *
asb_package_get_filename(AsbPackage * pkg)259 asb_package_get_filename (AsbPackage *pkg)
260 {
261 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
262 	return priv->filename;
263 }
264 
265 /**
266  * asb_package_get_kind:
267  * @pkg: A #AsbPackage
268  *
269  * Gets the kind of the package.
270  *
271  * Returns: a #AsbPackageKind
272  *
273  * Since: 0.2.5
274  **/
275 AsbPackageKind
asb_package_get_kind(AsbPackage * pkg)276 asb_package_get_kind (AsbPackage *pkg)
277 {
278 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
279 	return priv->kind;
280 }
281 
282 /**
283  * asb_package_get_epoch:
284  * @pkg: A #AsbPackage
285  *
286  * Gets the epoch of the package.
287  *
288  * Returns: a #AsbPackageKind
289  *
290  * Since: 0.5.6
291  **/
292 guint
asb_package_get_epoch(AsbPackage * pkg)293 asb_package_get_epoch (AsbPackage *pkg)
294 {
295 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
296 	return priv->epoch;
297 }
298 
299 /**
300  * asb_package_get_basename:
301  * @pkg: A #AsbPackage
302  *
303  * Gets the package basename.
304  *
305  * Returns: utf8 string
306  *
307  * Since: 0.1.0
308  **/
309 const gchar *
asb_package_get_basename(AsbPackage * pkg)310 asb_package_get_basename (AsbPackage *pkg)
311 {
312 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
313 	return priv->basename;
314 }
315 
316 /**
317  * asb_package_get_name:
318  * @pkg: A #AsbPackage
319  *
320  * Gets the package name
321  *
322  * Returns: utf8 string
323  *
324  * Since: 0.1.0
325  **/
326 const gchar *
asb_package_get_name(AsbPackage * pkg)327 asb_package_get_name (AsbPackage *pkg)
328 {
329 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
330 	return priv->name;
331 }
332 
333 /**
334  * asb_package_get_version:
335  * @pkg: A #AsbPackage
336  *
337  * Gets the package version
338  *
339  * Returns: utf8 string
340  *
341  * Since: 0.3.5
342  **/
343 const gchar *
asb_package_get_version(AsbPackage * pkg)344 asb_package_get_version (AsbPackage *pkg)
345 {
346 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
347 	return priv->version;
348 }
349 
350 /**
351  * asb_package_get_release_str:
352  * @pkg: A #AsbPackage
353  *
354  * Gets the package release string
355  *
356  * Returns: utf8 string
357  *
358  * Since: 0.5.6
359  **/
360 const gchar *
asb_package_get_release_str(AsbPackage * pkg)361 asb_package_get_release_str (AsbPackage *pkg)
362 {
363 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
364 	return priv->release;
365 }
366 
367 /**
368  * asb_package_get_arch:
369  * @pkg: A #AsbPackage
370  *
371  * Gets the package architecture
372  *
373  * Returns: utf8 string
374  *
375  * Since: 0.3.0
376  **/
377 const gchar *
asb_package_get_arch(AsbPackage * pkg)378 asb_package_get_arch (AsbPackage *pkg)
379 {
380 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
381 	return priv->arch;
382 }
383 
384 /**
385  * asb_package_get_url:
386  * @pkg: A #AsbPackage
387  *
388  * Gets the package homepage URL
389  *
390  * Returns: utf8 string
391  *
392  * Since: 0.1.0
393  **/
394 const gchar *
asb_package_get_url(AsbPackage * pkg)395 asb_package_get_url (AsbPackage *pkg)
396 {
397 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
398 	return priv->url;
399 }
400 
401 /**
402  * asb_package_get_license:
403  * @pkg: A #AsbPackage
404  *
405  * Gets the package license.
406  *
407  * Returns: utf8 string
408  *
409  * Since: 0.1.0
410  **/
411 const gchar *
asb_package_get_license(AsbPackage * pkg)412 asb_package_get_license (AsbPackage *pkg)
413 {
414 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
415 	return priv->license;
416 }
417 
418 /**
419  * asb_package_get_vcs:
420  * @pkg: A #AsbPackage
421  *
422  * Gets the package version control system.
423  *
424  * Returns: utf8 string
425  *
426  * Since: 0.3.4
427  **/
428 const gchar *
asb_package_get_vcs(AsbPackage * pkg)429 asb_package_get_vcs (AsbPackage *pkg)
430 {
431 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
432 	return priv->vcs;
433 }
434 
435 /**
436  * asb_package_get_source:
437  * @pkg: A #AsbPackage
438  *
439  * Gets the package source nevra.
440  *
441  * Returns: utf8 string
442  *
443  * Since: 0.1.0
444  **/
445 const gchar *
asb_package_get_source(AsbPackage * pkg)446 asb_package_get_source (AsbPackage *pkg)
447 {
448 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
449 	return priv->source_nevra;
450 }
451 
452 /**
453  * asb_package_get_source_pkgname:
454  * @pkg: A #AsbPackage
455  *
456  * Gets the package source name.
457  *
458  * Returns: utf8 string
459  *
460  * Since: 0.2.4
461  **/
462 const gchar *
asb_package_get_source_pkgname(AsbPackage * pkg)463 asb_package_get_source_pkgname (AsbPackage *pkg)
464 {
465 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
466 	return priv->source_pkgname;
467 }
468 
469 /**
470  * asb_package_get_filelist:
471  * @pkg: A #AsbPackage
472  *
473  * Gets the package filelist.
474  *
475  * Returns: (transfer none) (element-type utf8): filelist
476  *
477  * Since: 0.1.0
478  **/
479 gchar **
asb_package_get_filelist(AsbPackage * pkg)480 asb_package_get_filelist (AsbPackage *pkg)
481 {
482 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
483 	return priv->filelist;
484 }
485 
486 /**
487  * asb_package_get_deps:
488  * @pkg: A #AsbPackage
489  *
490  * Get the package dependency list.
491  *
492  * Returns: (transfer none) (element-type utf8): deplist
493  *
494  * Since: 0.3.5
495  **/
496 GPtrArray *
asb_package_get_deps(AsbPackage * pkg)497 asb_package_get_deps (AsbPackage *pkg)
498 {
499 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
500 	return priv->deps;
501 }
502 
503 /**
504  * asb_package_set_kind:
505  * @pkg: A #AsbPackage
506  * @kind: A #AsbPackageKind
507  *
508  * Sets the package kind.
509  *
510  * Since: 0.2.5
511  **/
512 void
asb_package_set_kind(AsbPackage * pkg,AsbPackageKind kind)513 asb_package_set_kind (AsbPackage *pkg, AsbPackageKind kind)
514 {
515 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
516 	priv->kind = kind;
517 }
518 
519 /**
520  * asb_package_set_name:
521  * @pkg: A #AsbPackage
522  * @name: package name
523  *
524  * Sets the package name.
525  *
526  * Since: 0.1.0
527  **/
528 void
asb_package_set_name(AsbPackage * pkg,const gchar * name)529 asb_package_set_name (AsbPackage *pkg, const gchar *name)
530 {
531 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
532 	g_free (priv->name);
533 	priv->name = g_strdup (name);
534 }
535 
536 /**
537  * asb_package_set_version:
538  * @pkg: A #AsbPackage
539  * @version: package version
540  *
541  * Sets the package version.
542  *
543  * Since: 0.1.0
544  **/
545 void
asb_package_set_version(AsbPackage * pkg,const gchar * version)546 asb_package_set_version (AsbPackage *pkg, const gchar *version)
547 {
548 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
549 	g_free (priv->version);
550 	priv->version = g_strdup (version);
551 }
552 
553 /**
554  * asb_package_set_release:
555  * @pkg: A #AsbPackage
556  * @release: package release
557  *
558  * Sets the package release.
559  *
560  * Since: 0.1.0
561  **/
562 void
asb_package_set_release(AsbPackage * pkg,const gchar * release)563 asb_package_set_release (AsbPackage *pkg, const gchar *release)
564 {
565 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
566 	g_free (priv->release);
567 	priv->release = g_strdup (release);
568 }
569 
570 /**
571  * asb_package_set_arch:
572  * @pkg: A #AsbPackage
573  * @arch: package architecture
574  *
575  * Sets the package architecture.
576  *
577  * Since: 0.1.0
578  **/
579 void
asb_package_set_arch(AsbPackage * pkg,const gchar * arch)580 asb_package_set_arch (AsbPackage *pkg, const gchar *arch)
581 {
582 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
583 	g_free (priv->arch);
584 	priv->arch = g_strdup (arch);
585 }
586 
587 /**
588  * asb_package_set_epoch:
589  * @pkg: A #AsbPackage
590  * @epoch: epoch, or 0 for unset
591  *
592  * Sets the package epoch
593  *
594  * Since: 0.1.0
595  **/
596 void
asb_package_set_epoch(AsbPackage * pkg,guint epoch)597 asb_package_set_epoch (AsbPackage *pkg, guint epoch)
598 {
599 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
600 	priv->epoch = epoch;
601 }
602 
603 /**
604  * asb_package_set_url:
605  * @pkg: A #AsbPackage
606  * @url: homepage URL
607  *
608  * Sets the package URL.
609  *
610  * Since: 0.1.0
611  **/
612 void
asb_package_set_url(AsbPackage * pkg,const gchar * url)613 asb_package_set_url (AsbPackage *pkg, const gchar *url)
614 {
615 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
616 	g_free (priv->url);
617 	priv->url = g_strdup (url);
618 }
619 
620 /**
621  * asb_package_set_license:
622  * @pkg: A #AsbPackage
623  * @license: license string
624  *
625  * Sets the package license.
626  *
627  * Since: 0.1.0
628  **/
629 void
asb_package_set_license(AsbPackage * pkg,const gchar * license)630 asb_package_set_license (AsbPackage *pkg, const gchar *license)
631 {
632 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
633 	g_free (priv->license);
634 	priv->license = g_strdup (license);
635 }
636 
637 /**
638  * asb_package_set_vcs:
639  * @pkg: A #AsbPackage
640  * @vcs: vcs string
641  *
642  * Sets the package version control system.
643  *
644  * Since: 0.3.4
645  **/
646 void
asb_package_set_vcs(AsbPackage * pkg,const gchar * vcs)647 asb_package_set_vcs (AsbPackage *pkg, const gchar *vcs)
648 {
649 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
650 	g_free (priv->vcs);
651 	priv->vcs = g_strdup (vcs);
652 }
653 
654 /**
655  * asb_package_set_source:
656  * @pkg: A #AsbPackage
657  * @source: source string, e.g. the srpm nevra
658  *
659  * Sets the package source name, which is usually the parent of a set of
660  * subpackages.
661  *
662  * Since: 0.1.0
663  **/
664 void
asb_package_set_source(AsbPackage * pkg,const gchar * source)665 asb_package_set_source (AsbPackage *pkg, const gchar *source)
666 {
667 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
668 	g_free (priv->source_nevra);
669 	priv->source_nevra = g_strdup (source);
670 }
671 
672 /**
673  * asb_package_set_source_pkgname:
674  * @pkg: A #AsbPackage
675  * @source_pkgname: source string, e.g. the srpm name
676  *
677  * Sets the package source name, which is usually the parent of a set of
678  * subpackages.
679  *
680  * Since: 0.2.4
681  **/
682 void
asb_package_set_source_pkgname(AsbPackage * pkg,const gchar * source_pkgname)683 asb_package_set_source_pkgname (AsbPackage *pkg, const gchar *source_pkgname)
684 {
685 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
686 	g_free (priv->source_pkgname);
687 	priv->source_pkgname = g_strdup (source_pkgname);
688 }
689 
690 /**
691  * asb_package_add_dep:
692  * @pkg: A #AsbPackage
693  * @dep: package dep
694  *
695  * Add a package dependency.
696  *
697  * Since: 0.3.5
698  **/
699 void
asb_package_add_dep(AsbPackage * pkg,const gchar * dep)700 asb_package_add_dep (AsbPackage *pkg, const gchar *dep)
701 {
702 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
703 	g_ptr_array_add (priv->deps, g_strdup (dep));
704 }
705 
706 /**
707  * asb_package_set_filelist:
708  * @pkg: A #AsbPackage
709  * @filelist: package filelist
710  *
711  * Sets the package filelist.
712  *
713  * Since: 0.1.0
714  **/
715 void
asb_package_set_filelist(AsbPackage * pkg,gchar ** filelist)716 asb_package_set_filelist (AsbPackage *pkg, gchar **filelist)
717 {
718 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
719 	g_strfreev (priv->filelist);
720 	priv->filelist = g_strdupv (filelist);
721 }
722 
723 /**
724  * asb_package_get_nevr:
725  * @pkg: A #AsbPackage
726  *
727  * Gets the package NEVR.
728  *
729  * Returns: utf8 string
730  *
731  * Since: 0.1.0
732  **/
733 const gchar *
asb_package_get_nevr(AsbPackage * pkg)734 asb_package_get_nevr (AsbPackage *pkg)
735 {
736 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
737 	if (priv->nevr == NULL) {
738 		if (priv->epoch == 0) {
739 			priv->nevr = g_strdup_printf ("%s-%s-%s",
740 						      priv->name,
741 						      priv->version,
742 						      priv->release);
743 		} else {
744 			priv->nevr = g_strdup_printf ("%s-%u:%s-%s",
745 						      priv->name,
746 						      priv->epoch,
747 						      priv->version,
748 						      priv->release);
749 		}
750 	}
751 	return priv->nevr;
752 }
753 
754 /**
755  * asb_package_get_nevra:
756  * @pkg: A #AsbPackage
757  *
758  * Gets the package NEVRA.
759  *
760  * Returns: utf8 string
761  *
762  * Since: 0.3.0
763  **/
764 const gchar *
asb_package_get_nevra(AsbPackage * pkg)765 asb_package_get_nevra (AsbPackage *pkg)
766 {
767 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
768 	if (priv->nevra == NULL) {
769 		if (priv->epoch == 0) {
770 			priv->nevra = g_strdup_printf ("%s-%s-%s.%s",
771 						       priv->name,
772 						       priv->version,
773 						       priv->release,
774 						       priv->arch);
775 		} else {
776 			priv->nevra = g_strdup_printf ("%s-%u:%s-%s.%s",
777 						       priv->name,
778 						       priv->epoch,
779 						       priv->version,
780 						       priv->release,
781 						       priv->arch);
782 		}
783 	}
784 	return priv->nevra;
785 }
786 
787 /**
788  * asb_package_get_evr:
789  * @pkg: A #AsbPackage
790  *
791  * Gets the package EVR.
792  *
793  * Returns: utf8 string
794  *
795  * Since: 0.1.0
796  **/
797 const gchar *
asb_package_get_evr(AsbPackage * pkg)798 asb_package_get_evr (AsbPackage *pkg)
799 {
800 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
801 	if (priv->evr == NULL) {
802 		if (priv->epoch == 0) {
803 			priv->evr = g_strdup_printf ("%s-%s",
804 						     priv->version,
805 						     priv->release);
806 		} else {
807 			priv->evr = g_strdup_printf ("%u:%s-%s",
808 						     priv->epoch,
809 						     priv->version,
810 						     priv->release);
811 		}
812 	}
813 	return priv->evr;
814 }
815 
816 static void
asb_package_class_init(AsbPackageClass * klass)817 asb_package_class_init (AsbPackageClass *klass)
818 {
819 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
820 	object_class->finalize = asb_package_finalize;
821 }
822 
823 static void
asb_package_guess_from_filename(AsbPackage * pkg)824 asb_package_guess_from_filename (AsbPackage *pkg)
825 {
826 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
827 	g_autofree gchar *tmp = NULL;
828 	gchar *at;
829 
830 	/* remove .rpm extension */
831 	tmp = g_path_get_basename (priv->filename);
832 	at = g_strrstr (tmp, ".rpm");
833 	if (at == NULL)
834 		return;
835 	*at = '\0';
836 
837 	/* get arch */
838 	at = g_strrstr (tmp, ".");
839 	if (at == NULL)
840 		return;
841 	priv->arch = g_strdup (at + 1);
842 	*at = '\0';
843 
844 	/* get release */
845 	at = g_strrstr (tmp, "-");
846 	if (at == NULL)
847 		return;
848 	priv->release = g_strdup (at + 1);
849 	*at = '\0';
850 
851 	/* get version */
852 	at = g_strrstr (tmp, "-");
853 	if (at == NULL)
854 		return;
855 	priv->version = g_strdup (at + 1);
856 	*at = '\0';
857 
858 	/* get name */
859 	priv->name = g_strdup (tmp);
860 }
861 
862 /**
863  * asb_package_set_filename:
864  * @pkg: A #AsbPackage
865  * @filename: package filename
866  *
867  * Sets the package filename.
868  *
869  * Since: 0.3.5
870  **/
871 void
asb_package_set_filename(AsbPackage * pkg,const gchar * filename)872 asb_package_set_filename (AsbPackage *pkg, const gchar *filename)
873 {
874 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
875 	g_free (priv->basename);
876 	g_free (priv->filename);
877 	priv->basename = g_path_get_basename (filename);
878 	priv->filename = g_strdup (filename);
879 
880 	/* this only works for correctly formatted file names */
881 	asb_package_guess_from_filename (pkg);
882 }
883 
884 /**
885  * asb_package_open:
886  * @pkg: A #AsbPackage
887  * @filename: package filename
888  * @error: A #GError or %NULL
889  *
890  * Opens a package and parses the contents.
891  * As little i/o should be done at this point, and implementations
892  * should rely on asb_package_ensure() to set data.
893  *
894  * Returns: %TRUE for success, %FALSE otherwise
895  *
896  * Since: 0.1.0
897  **/
898 gboolean
asb_package_open(AsbPackage * pkg,const gchar * filename,GError ** error)899 asb_package_open (AsbPackage *pkg, const gchar *filename, GError **error)
900 {
901 	AsbPackageClass *klass = ASB_PACKAGE_GET_CLASS (pkg);
902 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
903 
904 	/* already open */
905 	if (priv->is_open)
906 		return TRUE;
907 	priv->is_open = TRUE;
908 
909 	/* save filename if not already set */
910 	if (priv->filename == NULL)
911 		asb_package_set_filename (pkg, filename);
912 
913 	/* call distro-specific method */
914 	if (klass->open != NULL)
915 		return klass->open (pkg, filename, error);
916 	return TRUE;
917 }
918 
919 /**
920  * asb_package_close:
921  * @pkg: A #AsbPackage
922  * @error: A #GError or %NULL
923  *
924  * Closes a package, which can be re-opened if required.
925  *
926  * Returns: %TRUE for success, %FALSE otherwise
927  *
928  * Since: 0.3.5
929  **/
930 gboolean
asb_package_close(AsbPackage * pkg,GError ** error)931 asb_package_close (AsbPackage *pkg, GError **error)
932 {
933 	AsbPackageClass *klass = ASB_PACKAGE_GET_CLASS (pkg);
934 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
935 
936 	/* already closed */
937 	if (!priv->is_open)
938 		return TRUE;
939 	priv->is_open = FALSE;
940 
941 	/* call distro-specific method */
942 	if (klass->close != NULL)
943 		return klass->close (pkg, error);
944 	return TRUE;
945 }
946 
947 /**
948  * asb_package_ensure:
949  * @pkg: A #AsbPackage
950  * @flags: #AsbPackageEnsureFlags
951  * @error: A #GError or %NULL
952  *
953  * Ensures data exists.
954  *
955  * Returns: %TRUE for success, %FALSE otherwise
956  *
957  * Since: 0.3.0
958  **/
959 gboolean
asb_package_ensure(AsbPackage * pkg,AsbPackageEnsureFlags flags,GError ** error)960 asb_package_ensure (AsbPackage *pkg,
961 		    AsbPackageEnsureFlags flags,
962 		    GError **error)
963 {
964 	AsbPackageClass *klass = ASB_PACKAGE_GET_CLASS (pkg);
965 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
966 
967 	/* reopen as required */
968 	if (!priv->is_open) {
969 		if (!asb_package_open (pkg, priv->filename, error))
970 			return FALSE;
971 	}
972 
973 	/* this is recounted */
974 	if (flags & ASB_PACKAGE_ENSURE_DEPS)
975 		priv->deps_refcount++;
976 	if (flags & ASB_PACKAGE_ENSURE_FILES)
977 		priv->filelist_refcount++;
978 
979 	/* clear flags */
980 	if (priv->name != NULL)
981 		flags &= ~ASB_PACKAGE_ENSURE_NEVRA;
982 	if (priv->license != NULL)
983 		flags &= ~ASB_PACKAGE_ENSURE_LICENSE;
984 	if (priv->vcs != NULL)
985 		flags &= ~ASB_PACKAGE_ENSURE_VCS;
986 	if (priv->url != NULL)
987 		flags &= ~ASB_PACKAGE_ENSURE_URL;
988 	if (priv->source_pkgname != NULL)
989 		flags &= ~ASB_PACKAGE_ENSURE_SOURCE;
990 	if (priv->filelist != NULL)
991 		flags &= ~ASB_PACKAGE_ENSURE_FILES;
992 	if (priv->deps->len > 0)
993 		flags &= ~ASB_PACKAGE_ENSURE_DEPS;
994 	if (priv->releases->len > 0)
995 		flags &= ~ASB_PACKAGE_ENSURE_RELEASES;
996 
997 	/* nothing to do! */
998 	if (flags == ASB_PACKAGE_ENSURE_NONE)
999 		return TRUE;
1000 
1001 	/* call distro-specific method */
1002 	if (klass->ensure != NULL)
1003 		return klass->ensure (pkg, flags, error);
1004 	return TRUE;
1005 }
1006 
1007 /**
1008  * asb_package_clear:
1009  * @pkg: A #AsbPackage
1010  * @flags: #AsbPackageEnsureFlags
1011  *
1012  * Deallocates previously ensured data.
1013  *
1014  * Since: 0.3.5
1015  **/
1016 void
asb_package_clear(AsbPackage * pkg,AsbPackageEnsureFlags flags)1017 asb_package_clear (AsbPackage *pkg, AsbPackageEnsureFlags flags)
1018 {
1019 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
1020 
1021 	/* this is recounted */
1022 	if (flags & ASB_PACKAGE_ENSURE_DEPS) {
1023 		if (priv->deps_refcount > 0 && --priv->deps_refcount == 0)
1024 			g_ptr_array_set_size (priv->deps, 0);
1025 	}
1026 	if (flags & ASB_PACKAGE_ENSURE_FILES) {
1027 		if (priv->filelist_refcount > 0 && --priv->filelist_refcount == 0) {
1028 			g_strfreev (priv->filelist);
1029 			priv->filelist = NULL;
1030 		}
1031 	}
1032 }
1033 
1034 /**
1035  * asb_package_explode:
1036  * @pkg: A #AsbPackage
1037  * @dir: directory to explode into
1038  * @glob: (element-type utf8): the glob list, or %NULL
1039  * @error: A #GError or %NULL
1040  *
1041  * Decompresses a package into a directory, optionally using a glob list.
1042  *
1043  * Returns: %TRUE for success, %FALSE otherwise
1044  *
1045  * Since: 0.1.0
1046  **/
1047 gboolean
asb_package_explode(AsbPackage * pkg,const gchar * dir,GPtrArray * glob,GError ** error)1048 asb_package_explode (AsbPackage *pkg,
1049 		     const gchar *dir,
1050 		     GPtrArray *glob,
1051 		     GError **error)
1052 {
1053 	AsbPackageClass *klass = ASB_PACKAGE_GET_CLASS (pkg);
1054 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
1055 	if (klass->explode != NULL)
1056 		return klass->explode (pkg, dir, glob, error);
1057 	return asb_utils_explode (priv->filename, dir, glob, error);
1058 }
1059 
1060 /**
1061  * asb_package_set_config:
1062  * @pkg: A #AsbPackage
1063  * @key: utf8 string
1064  * @value: utf8 string
1065  *
1066  * Sets a config attribute on a package.
1067  *
1068  * Since: 0.1.0
1069  **/
1070 void
asb_package_set_config(AsbPackage * pkg,const gchar * key,const gchar * value)1071 asb_package_set_config (AsbPackage *pkg, const gchar *key, const gchar *value)
1072 {
1073 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
1074 	g_hash_table_insert (priv->configs, g_strdup (key), g_strdup (value));
1075 }
1076 
1077 /**
1078  * asb_package_get_config:
1079  * @pkg: A #AsbPackage
1080  * @key: utf8 string
1081  *
1082  * Gets a config attribute from a package.
1083  *
1084  * Returns: utf8 string
1085  *
1086  * Since: 0.1.0
1087  **/
1088 const gchar *
asb_package_get_config(AsbPackage * pkg,const gchar * key)1089 asb_package_get_config (AsbPackage *pkg, const gchar *key)
1090 {
1091 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
1092 	return g_hash_table_lookup (priv->configs, key);
1093 }
1094 
1095 /**
1096  * asb_package_get_releases:
1097  * @pkg: A #AsbPackage
1098  *
1099  * Gets the releases of the package.
1100  *
1101  * Returns: (transfer none) (element-type AsRelease): the release data
1102  *
1103  * Since: 0.1.0
1104  **/
1105 GPtrArray *
asb_package_get_releases(AsbPackage * pkg)1106 asb_package_get_releases (AsbPackage *pkg)
1107 {
1108 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
1109 	return priv->releases;
1110 }
1111 
1112 /**
1113  * asb_package_compare:
1114  * @pkg1: A #AsbPackage
1115  * @pkg2: A #AsbPackage
1116  *
1117  * Compares one package with another.
1118  *
1119  * Returns: +1 for @pkg1 newer, 0 for the same and -1 if @pkg2 is newer
1120  *
1121  * Since: 0.1.0
1122  **/
1123 gint
asb_package_compare(AsbPackage * pkg1,AsbPackage * pkg2)1124 asb_package_compare (AsbPackage *pkg1, AsbPackage *pkg2)
1125 {
1126 	AsbPackagePrivate *priv1 = GET_PRIVATE (pkg1);
1127 	AsbPackagePrivate *priv2 = GET_PRIVATE (pkg2);
1128 	AsbPackageClass *klass = ASB_PACKAGE_GET_CLASS (pkg1);
1129 	gint rc;
1130 
1131 	/* class-specific compare method */
1132 	if (klass->compare != NULL)
1133 		return klass->compare (pkg1, pkg2);
1134 
1135 	/* check name */
1136 	rc = g_strcmp0 (priv1->name, priv2->name);
1137 	if (rc != 0)
1138 		return rc;
1139 
1140 	/* check epoch */
1141 	if (priv1->epoch < priv2->epoch)
1142 		return -1;
1143 	if (priv1->epoch > priv2->epoch)
1144 		return 1;
1145 
1146 	/* check version */
1147 	rc = as_utils_vercmp_full (priv1->version, priv2->version, AS_VERSION_COMPARE_FLAG_NONE);
1148 	if (rc != 0)
1149 		return rc;
1150 
1151 	/* check release */
1152 	rc = as_utils_vercmp_full (priv1->release, priv2->release, AS_VERSION_COMPARE_FLAG_NONE);
1153 	if (rc != 0)
1154 		return rc;
1155 
1156 	/* check arch */
1157 	return g_strcmp0 (priv1->arch, priv2->arch);
1158 }
1159 
1160 /**
1161  * asb_package_get_release:
1162  * @pkg: A #AsbPackage
1163  * @version: package version
1164  *
1165  * Gets the release for a specific version.
1166  *
1167  * Returns: (transfer none): an #AsRelease, or %NULL for not found
1168  *
1169  * Since: 0.1.0
1170  **/
1171 AsRelease *
asb_package_get_release(AsbPackage * pkg,const gchar * version)1172 asb_package_get_release	(AsbPackage *pkg, const gchar *version)
1173 {
1174 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
1175 	return g_hash_table_lookup (priv->releases_hash, version);
1176 }
1177 
1178 /**
1179  * asb_package_add_release:
1180  * @pkg: A #AsbPackage
1181  * @version: a package version
1182  * @release: a package release
1183  *
1184  * Adds a (downstream) release to a package.
1185  *
1186  * Since: 0.1.0
1187  **/
1188 void
asb_package_add_release(AsbPackage * pkg,const gchar * version,AsRelease * release)1189 asb_package_add_release	(AsbPackage *pkg,
1190 			 const gchar *version,
1191 			 AsRelease *release)
1192 {
1193 	AsbPackagePrivate *priv = GET_PRIVATE (pkg);
1194 	g_hash_table_insert (priv->releases_hash,
1195 			     g_strdup (version),
1196 			     g_object_ref (release));
1197 	g_ptr_array_add (priv->releases, g_object_ref (release));
1198 }
1199 
1200 /**
1201  * asb_package_new:
1202  *
1203  * Creates a new %AsbPackage.
1204  *
1205  * You don't need to use this function unless you want a memory-backed package
1206  * for testing purposes.
1207  *
1208  * Returns: a package
1209  *
1210  * Since: 0.2.2
1211  **/
1212 AsbPackage *
asb_package_new(void)1213 asb_package_new (void)
1214 {
1215 	AsbPackage *pkg;
1216 	pkg = g_object_new (ASB_TYPE_PACKAGE, NULL);
1217 	return ASB_PACKAGE (pkg);
1218 }
1219