summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2015-07-23 22:19:34 +0100
committerRichard Hughes <richard@hughsie.com>2015-07-27 09:45:00 +0100
commit7fdc8c83f7ab463b1429b410efcb6627df2c91f4 (patch)
treeca302ae88b6963cacaee6863a60542b718602202
parenta228c324d8df884fc56c3464e373878e68139fa3 (diff)
downloadappstream-glib-7fdc8c83f7ab463b1429b410efcb6627df2c91f4.tar.gz
Emit the AsStore::changed signal if files or directories change
-rw-r--r--libappstream-glib/as-self-test.c148
-rw-r--r--libappstream-glib/as-store.c374
-rw-r--r--libappstream-glib/as-store.h19
3 files changed, 463 insertions, 78 deletions
diff --git a/libappstream-glib/as-self-test.c b/libappstream-glib/as-self-test.c
index a117c92..2e93970 100644
--- a/libappstream-glib/as-self-test.c
+++ b/libappstream-glib/as-self-test.c
@@ -2447,6 +2447,152 @@ as_test_store_embedded_func (void)
g_assert (g_file_test ("/tmp/origin/32x32/eog.png", G_FILE_TEST_EXISTS));
}
+static void
+store_changed_cb (AsStore *store, guint *cnt)
+{
+ as_test_loop_quit ();
+ (*cnt)++;
+ g_debug ("changed callback, now #%i", *cnt);
+}
+
+/* automatically reload changed directories */
+static void
+as_test_store_auto_reload_dir_func (void)
+{
+ AsApp *app;
+ gboolean ret;
+ guint cnt = 0;
+ _cleanup_error_free_ GError *error = NULL;
+ _cleanup_object_unref_ AsStore *store = NULL;
+
+ /* add this file to a store */
+ store = as_store_new ();
+ g_signal_connect (store, "changed",
+ G_CALLBACK (store_changed_cb), &cnt);
+ as_store_set_watch_flags (store, AS_STORE_WATCH_FLAG_ADDED |
+ AS_STORE_WATCH_FLAG_REMOVED);
+
+ as_store_set_destdir (store, "/tmp/repo-tmp");
+ g_mkdir_with_parents ("/tmp/repo-tmp/usr/share/app-info/xmls", 0700);
+ g_unlink ("/tmp/repo-tmp/usr/share/app-info/xmls/foo.xml");
+
+ /* load store */
+ ret = as_store_load (store, AS_STORE_LOAD_FLAG_APP_INFO_SYSTEM, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+ g_assert_cmpint (cnt, ==, 1);
+
+ /* create file */
+ ret = g_file_set_contents ("/tmp/repo-tmp/usr/share/app-info/xmls/foo.xml",
+ "<components version=\"0.6\">"
+ "<component type=\"desktop\">"
+ "<id>test.desktop</id>"
+ "</component>"
+ "</components>",
+ -1, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+
+ as_test_loop_run_with_timeout (2000);
+ g_assert_cmpint (cnt, ==, 2);
+
+ /* verify */
+ app = as_store_get_app_by_id (store, "test.desktop");
+ g_assert (app != NULL);
+
+ /* remove file */
+ g_unlink ("/tmp/repo-tmp/usr/share/app-info/xmls/foo.xml");
+ as_test_loop_run_with_timeout (2000);
+ g_assert_cmpint (cnt, ==, 3);
+ app = as_store_get_app_by_id (store, "test.desktop");
+ g_assert (app == NULL);
+}
+
+/* automatically reload changed files */
+static void
+as_test_store_auto_reload_file_func (void)
+{
+ AsApp *app;
+ AsRelease *rel;
+ gboolean ret;
+ guint cnt = 0;
+ _cleanup_error_free_ GError *error = NULL;
+ _cleanup_object_unref_ AsStore *store = NULL;
+ _cleanup_object_unref_ GFile *file = NULL;
+
+ /* set initial file */
+ ret = g_file_set_contents ("/tmp/foo.xml",
+ "<components version=\"0.6\">"
+ "<component type=\"desktop\">"
+ "<id>test.desktop</id>"
+ "<releases>"
+ "<release version=\"0.1.2\" timestamp=\"123\">"
+ "</release>"
+ "</releases>"
+ "</component>"
+ "</components>",
+ -1, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+
+ /* add this file to a store */
+ store = as_store_new ();
+ g_signal_connect (store, "changed",
+ G_CALLBACK (store_changed_cb), &cnt);
+ as_store_set_watch_flags (store, AS_STORE_WATCH_FLAG_ADDED |
+ AS_STORE_WATCH_FLAG_REMOVED);
+ file = g_file_new_for_path ("/tmp/foo.xml");
+ ret = as_store_from_file (store, file, NULL, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+ g_assert_cmpint (cnt, ==, 1);
+
+ /* verify */
+ app = as_store_get_app_by_id (store, "test.desktop");
+ g_assert (app != NULL);
+ rel = as_app_get_release_default (app);
+ g_assert_cmpstr (as_release_get_version (rel), ==, "0.1.2");
+ g_assert_cmpstr (as_app_get_source_file (app), ==, "/tmp/foo.xml");
+
+ /* change the file, and ensure we get the callback */
+ g_debug ("changing file");
+ ret = g_file_set_contents ("/tmp/foo.xml",
+ "<components version=\"0.6\">"
+ "<component type=\"desktop\">"
+ "<id>test.desktop</id>"
+ "<releases>"
+ "<release version=\"0.1.0\" timestamp=\"100\">"
+ "</release>"
+ "</releases>"
+ "</component>"
+ "<component type=\"desktop\">"
+ "<id>baz.desktop</id>"
+ "</component>"
+ "</components>",
+ -1, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+ as_test_loop_run_with_timeout (2000);
+ g_assert_cmpint (cnt, ==, 2);
+
+ /* verify */
+ app = as_store_get_app_by_id (store, "baz.desktop");
+ g_assert (app != NULL);
+ app = as_store_get_app_by_id (store, "test.desktop");
+ g_assert (app != NULL);
+ rel = as_app_get_release_default (app);
+ g_assert_cmpstr (as_release_get_version (rel), ==, "0.1.0");
+
+ /* remove file */
+ g_unlink ("/tmp/foo.xml");
+ as_test_loop_run_with_timeout (2000);
+ g_assert_cmpint (cnt, ==, 3);
+ app = as_store_get_app_by_id (store, "baz.desktop");
+ g_assert (app == NULL);
+ app = as_store_get_app_by_id (store, "test.desktop");
+ g_assert (app == NULL);
+}
+
/* demote the .desktop "application" to an addon */
static void
as_test_store_demote_func (void)
@@ -4039,6 +4185,8 @@ main (int argc, char **argv)
g_test_add_func ("/AppStream/monitor{file}", as_test_monitor_file_func);
g_test_add_func ("/AppStream/yaml", as_test_yaml_func);
g_test_add_func ("/AppStream/store", as_test_store_func);
+ g_test_add_func ("/AppStream/store{auto-reload-dir}", as_test_store_auto_reload_dir_func);
+ g_test_add_func ("/AppStream/store{auto-reload-file}", as_test_store_auto_reload_file_func);
g_test_add_func ("/AppStream/store{demote}", as_test_store_demote_func);
g_test_add_func ("/AppStream/store{merges}", as_test_store_merges_func);
g_test_add_func ("/AppStream/store{merges-local}", as_test_store_merges_local_func);
diff --git a/libappstream-glib/as-store.c b/libappstream-glib/as-store.c
index 2083ceb..52fb030 100644
--- a/libappstream-glib/as-store.c
+++ b/libappstream-glib/as-store.c
@@ -40,6 +40,7 @@
#include "as-cleanup.h"
#include "as-node-private.h"
#include "as-problem.h"
+#include "as-monitor.h"
#include "as-store.h"
#include "as-utils-private.h"
#include "as-yaml.h"
@@ -62,11 +63,14 @@ struct _AsStorePrivate
GPtrArray *array; /* of AsApp */
GHashTable *hash_id; /* of AsApp{id} */
GHashTable *hash_pkgname; /* of AsApp{pkgname} */
- GPtrArray *file_monitors; /* of GFileMonitor */
+ AsMonitor *monitor;
GHashTable *metadata_indexes; /* GHashTable{key} */
AsStoreAddFlags add_flags;
+ AsStoreWatchFlags watch_flags;
AsStoreProblems problems;
guint32 filter;
+ guint changed_block_refcnt;
+ gboolean is_pending_changed_signal;
};
G_DEFINE_TYPE_WITH_PRIVATE (AsStore, as_store, G_TYPE_OBJECT)
@@ -109,7 +113,7 @@ as_store_finalize (GObject *object)
g_free (priv->origin);
g_free (priv->builder_id);
g_ptr_array_unref (priv->array);
- g_ptr_array_unref (priv->file_monitors);
+ g_object_unref (priv->monitor);
g_hash_table_unref (priv->hash_id);
g_hash_table_unref (priv->hash_pkgname);
g_hash_table_unref (priv->metadata_indexes);
@@ -118,30 +122,6 @@ as_store_finalize (GObject *object)
}
/**
- * as_store_init:
- **/
-static void
-as_store_init (AsStore *store)
-{
- AsStorePrivate *priv = GET_PRIVATE (store);
- priv->api_version = AS_API_VERSION_NEWEST;
- priv->array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
- priv->hash_id = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- NULL,
- NULL);
- priv->hash_pkgname = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- (GDestroyNotify) g_object_unref);
- priv->file_monitors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
- priv->metadata_indexes = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- (GDestroyNotify) g_hash_table_unref);
-}
-
-/**
* as_store_class_init:
**/
static void
@@ -153,8 +133,8 @@ as_store_class_init (AsStoreClass *klass)
* AsStore::changed:
* @device: the #AsStore instance that emitted the signal
*
- * The ::changed signal is emitted when the files backing the store
- * have changed.
+ * The ::changed signal is emitted when components have been added
+ * or removed from the store.
*
* Since: 0.1.2
**/
@@ -169,6 +149,64 @@ as_store_class_init (AsStoreClass *klass)
}
/**
+ * as_store_perhaps_emit_changed:
+ */
+static void
+as_store_perhaps_emit_changed (AsStore *store, const gchar *details)
+{
+ AsStorePrivate *priv = GET_PRIVATE (store);
+ if (priv->changed_block_refcnt > 0) {
+ priv->is_pending_changed_signal = TRUE;
+ return;
+ }
+ if (!priv->is_pending_changed_signal) {
+ priv->is_pending_changed_signal = TRUE;
+ return;
+ }
+ g_debug ("Emitting ::changed() [%s]", details);
+ g_signal_emit (store, signals[SIGNAL_CHANGED], 0);
+ priv->is_pending_changed_signal = FALSE;
+}
+
+/**
+ * as_store_changed_inhibit:
+ */
+static guint32 *
+as_store_changed_inhibit (AsStore *store)
+{
+ AsStorePrivate *priv = GET_PRIVATE (store);
+ priv->changed_block_refcnt++;
+ return &priv->changed_block_refcnt;
+}
+
+/**
+ * as_store_changed_uninhibit:
+ */
+static void
+as_store_changed_uninhibit (guint32 **tok)
+{
+ if (tok == NULL || *tok == NULL)
+ return;
+ if (*(*tok) == 0) {
+ g_critical ("changed_block_refcnt already zero");
+ return;
+ }
+ (*(*tok))--;
+ *tok = NULL;
+}
+
+/**
+ * as_store_changed_uninhibit_cb:
+ */
+static void
+as_store_changed_uninhibit_cb (void *v)
+{
+ as_store_changed_uninhibit ((guint32 **)v);
+}
+
+#define _cleanup_uninhibit_ __attribute__ ((cleanup(as_store_changed_uninhibit_cb)))
+
+/**
* as_store_add_filter:
* @store: a #AsStore instance.
* @kind: a #AsIdKind, e.g. %AS_ID_KIND_FIRMWARE
@@ -562,6 +600,9 @@ as_store_remove_app (AsStore *store, AsApp *app)
g_hash_table_remove (priv->hash_id, as_app_get_id (app));
g_ptr_array_remove (priv->array, app);
g_hash_table_remove_all (priv->metadata_indexes);
+
+ /* removed */
+ as_store_perhaps_emit_changed (store, "remove-app");
}
/**
@@ -589,6 +630,9 @@ as_store_remove_app_by_id (AsStore *store, const gchar *id)
g_ptr_array_remove (priv->array, app);
}
g_hash_table_remove_all (priv->metadata_indexes);
+
+ /* removed */
+ as_store_perhaps_emit_changed (store, "remove-app-by-id");
}
/**
@@ -713,6 +757,9 @@ as_store_add_app (AsStore *store, AsApp *app)
g_strdup (pkgname),
g_object_ref (app));
}
+
+ /* added */
+ as_store_perhaps_emit_changed (store, "add-app");
}
/**
@@ -765,9 +812,13 @@ as_store_from_root (AsStore *store,
const gchar *tmp;
_cleanup_free_ AsNodeContext *ctx = NULL;
_cleanup_free_ gchar *icon_path = NULL;
+ _cleanup_uninhibit_ guint32 *tok = NULL;
g_return_val_if_fail (AS_IS_STORE (store), FALSE);
+ /* emit once when finished */
+ tok = as_store_changed_inhibit (store);
+
apps = as_node_find (root, "components");
if (apps == NULL) {
apps = as_node_find (root, "applications");
@@ -843,6 +894,10 @@ as_store_from_root (AsStore *store,
/* add addon kinds to their parent AsApp */
as_store_match_addons (store);
+ /* this store has changed */
+ as_store_changed_uninhibit (&tok);
+ as_store_perhaps_emit_changed (store, "from-root");
+
return TRUE;
}
@@ -863,6 +918,7 @@ as_store_load_yaml_file (AsStore *store,
_cleanup_free_ AsNodeContext *ctx = NULL;
_cleanup_free_ gchar *icon_path = NULL;
_cleanup_yaml_unref_ GNode *root = NULL;
+ _cleanup_uninhibit_ guint32 *tok = NULL;
/* load file */
root = as_yaml_from_file (file, cancellable, error);
@@ -892,6 +948,9 @@ as_store_load_yaml_file (AsStore *store,
NULL);
}
+ /* emit once when finished */
+ tok = as_store_changed_inhibit (store);
+
/* parse applications */
ctx = as_node_context_new ();
for (app_n = root->children->next; app_n != NULL; app_n = app_n->next) {
@@ -908,10 +967,113 @@ as_store_load_yaml_file (AsStore *store,
if (as_app_get_id (app) != NULL)
as_store_add_app (store, app);
}
+
+ /* emit changed */
+ as_store_changed_uninhibit (&tok);
+ as_store_perhaps_emit_changed (store, "yaml-file");
+
return TRUE;
}
/**
+ * as_store_remove_by_source_file:
+ */
+static void
+as_store_remove_by_source_file (AsStore *store, const gchar *filename)
+{
+ AsApp *app;
+ GPtrArray *apps;
+ guint i;
+ const gchar *tmp;
+ _cleanup_ptrarray_unref_ GPtrArray *ids = NULL;
+
+ /* find any applications in the store with this source file */
+ ids = g_ptr_array_new_with_free_func (g_free);
+ apps = as_store_get_apps (store);
+ for (i = 0; i < apps->len; i++) {
+ app = g_ptr_array_index (apps, i);
+ if (g_strcmp0 (as_app_get_source_file (app), filename) != 0)
+ continue;
+ g_ptr_array_add (ids, g_strdup (as_app_get_id (app)));
+ }
+
+ /* remove these from the store */
+ for (i = 0; i < ids->len; i++) {
+ tmp = g_ptr_array_index (ids, i);
+ g_debug ("removing %s as %s invalid", tmp, filename);
+ as_store_remove_app_by_id (store, tmp);
+ }
+
+ /* the store changed */
+ as_store_perhaps_emit_changed (store, "remove-by-source-file");
+}
+
+/**
+ * as_store_monitor_changed_cb:
+ */
+static void
+as_store_monitor_changed_cb (AsMonitor *monitor,
+ const gchar *filename,
+ AsStore *store)
+{
+ AsStorePrivate *priv = GET_PRIVATE (store);
+
+ /* reload, or emit a signal */
+ if (priv->watch_flags & AS_STORE_WATCH_FLAG_ADDED) {
+ _cleanup_error_free_ GError *error = NULL;
+ _cleanup_object_unref_ GFile *file = NULL;
+ _cleanup_uninhibit_ guint32 *tok = NULL;
+ tok = as_store_changed_inhibit (store);
+ as_store_remove_by_source_file (store, filename);
+ g_debug ("rescanning %s", filename);
+ file = g_file_new_for_path (filename);
+ if (!as_store_from_file (store, file, NULL, NULL, &error))
+ g_warning ("failed to rescan: %s", error->message);
+ }
+ as_store_perhaps_emit_changed (store, "file changed");
+}
+
+/**
+ * as_store_monitor_added_cb:
+ */
+static void
+as_store_monitor_added_cb (AsMonitor *monitor,
+ const gchar *filename,
+ AsStore *store)
+{
+ AsStorePrivate *priv = GET_PRIVATE (store);
+
+ /* reload, or emit a signal */
+ if (priv->watch_flags & AS_STORE_WATCH_FLAG_ADDED) {
+ _cleanup_error_free_ GError *error = NULL;
+ _cleanup_object_unref_ GFile *file = NULL;
+ g_debug ("scanning %s", filename);
+ file = g_file_new_for_path (filename);
+ if (!as_store_from_file (store, file, NULL, NULL, &error))
+ g_warning ("failed to rescan: %s", error->message);
+ } else {
+ as_store_perhaps_emit_changed (store, "file added");
+ }
+}
+
+/**
+ * as_store_monitor_removed_cb:
+ */
+static void
+as_store_monitor_removed_cb (AsMonitor *monitor,
+ const gchar *filename,
+ AsStore *store)
+{
+ AsStorePrivate *priv = GET_PRIVATE (store);
+ /* remove, or emit a signal */
+ if (priv->watch_flags & AS_STORE_WATCH_FLAG_REMOVED) {
+ as_store_remove_by_source_file (store, filename);
+ } else {
+ as_store_perhaps_emit_changed (store, "file removed");
+ }
+}
+
+/**
* as_store_from_file:
* @store: a #AsStore instance.
* @file: a #GFile.
@@ -937,6 +1099,7 @@ as_store_from_file (AsStore *store,
GCancellable *cancellable,
GError **error)
{
+ AsStorePrivate *priv = GET_PRIVATE (store);
_cleanup_free_ gchar *filename = NULL;
_cleanup_error_free_ GError *error_local = NULL;
_cleanup_node_unref_ GNode *root = NULL;
@@ -962,6 +1125,16 @@ as_store_from_file (AsStore *store,
filename, error_local->message);
return FALSE;
}
+
+ /* watch for file changes */
+ if (priv->watch_flags > 0) {
+ if (!as_monitor_add_file (priv->monitor,
+ filename,
+ cancellable,
+ error))
+ return FALSE;
+ }
+
return as_store_from_root (store, root, icon_root, filename, error);
}
@@ -1375,6 +1548,39 @@ as_store_set_add_flags (AsStore *store, AsStoreAddFlags add_flags)
}
/**
+ * as_store_get_watch_flags:
+ * @store: a #AsStore instance.
+ *
+ * Gets the flags used for adding files to the store.
+ *
+ * Returns: the #AsStoreWatchFlags, or 0 if unset
+ *
+ * Since: 0.4.2
+ **/
+AsStoreWatchFlags
+as_store_get_watch_flags (AsStore *store)
+{
+ AsStorePrivate *priv = GET_PRIVATE (store);
+ return priv->watch_flags;
+}
+
+/**
+ * as_store_set_watch_flags:
+ * @store: a #AsStore instance.
+ * @watch_flags: the #AsStoreWatchFlags, e.g. %AS_STORE_WATCH_FLAG_NONE
+ *
+ * Sets the flags used when adding files to the store.
+ *
+ * Since: 0.4.2
+ **/
+void
+as_store_set_watch_flags (AsStore *store, AsStoreWatchFlags watch_flags)
+{
+ AsStorePrivate *priv = GET_PRIVATE (store);
+ priv->watch_flags = watch_flags;
+}
+
+/**
* as_store_guess_origin_fallback:
*/
static gboolean
@@ -1436,53 +1642,6 @@ as_store_load_app_info_file (AsStore *store,
}
/**
- * as_store_cache_changed_cb:
- */
-static void
-as_store_cache_changed_cb (GFileMonitor *monitor,
- GFile *file, GFile *other_file,
- GFileMonitorEvent event_type,
- AsStore *store)
-{
- g_debug ("Emitting ::changed()");
- g_signal_emit (store, signals[SIGNAL_CHANGED], 0);
-}
-
-/**
- * as_store_monitor_directory:
- **/
-static gboolean
-as_store_monitor_directory (AsStore *store,
- const gchar *path,
- GCancellable *cancellable,
- GError **error)
-{
- AsStorePrivate *priv = GET_PRIVATE (store);
- _cleanup_error_free_ GError *error_local = NULL;
- _cleanup_object_unref_ GFile *file = NULL;
- _cleanup_object_unref_ GFileMonitor *monitor = NULL;
-
- file = g_file_new_for_path (path);
- monitor = g_file_monitor_directory (file,
- G_FILE_MONITOR_NONE,
- cancellable,
- &error_local);
- if (monitor == NULL) {
- g_set_error (error,
- AS_STORE_ERROR,
- AS_STORE_ERROR_FAILED,
- "Failed to monitor %s: %s",
- path, error_local->message);
- return FALSE;
- }
- g_signal_connect (monitor, "changed",
- G_CALLBACK (as_store_cache_changed_cb),
- store);
- g_ptr_array_add (priv->file_monitors, g_object_ref (monitor));
- return TRUE;
-}
-
-/**
* as_store_load_app_info:
**/
static gboolean
@@ -1492,11 +1651,16 @@ as_store_load_app_info (AsStore *store,
GCancellable *cancellable,
GError **error)
{
+ AsStorePrivate *priv = GET_PRIVATE (store);
const gchar *tmp;
_cleanup_dir_close_ GDir *dir = NULL;
_cleanup_error_free_ GError *error_local = NULL;
_cleanup_free_ gchar *icon_root = NULL;
_cleanup_free_ gchar *path_md = NULL;
+ _cleanup_uninhibit_ guint32 *tok = NULL;
+
+ /* emit once when finished */
+ tok = as_store_changed_inhibit (store);
/* search all files */
path_md = g_build_filename (path, format, NULL);
@@ -1524,11 +1688,16 @@ as_store_load_app_info (AsStore *store,
}
/* watch the directories for changes */
- if (!as_store_monitor_directory (store, path_md, cancellable, error))
- return FALSE;
- if (!as_store_monitor_directory (store, icon_root, cancellable, error))
+ if (!as_monitor_add_directory (priv->monitor,
+ path_md,
+ cancellable,
+ error))
return FALSE;
+ /* emit changed */
+ as_store_changed_uninhibit (&tok);
+ as_store_perhaps_emit_changed (store, "load-app-info");
+
return TRUE;
}
@@ -1676,11 +1845,15 @@ as_store_load_installed (AsStore *store,
GError *error_local = NULL;
const gchar *tmp;
_cleanup_dir_close_ GDir *dir = NULL;
+ _cleanup_uninhibit_ guint32 *tok = NULL;
dir = g_dir_open (path, 0, error);
if (dir == NULL)
return FALSE;
+ /* emit once when finished */
+ tok = as_store_changed_inhibit (store);
+
/* relax the checks when parsing */
if (flags & AS_STORE_LOAD_FLAG_ALLOW_VETO)
parse_flags |= AS_APP_PARSE_FLAG_ALLOW_VETO;
@@ -1726,6 +1899,11 @@ as_store_load_installed (AsStore *store,
as_app_set_state (app, AS_APP_STATE_INSTALLED);
as_store_add_app (store, app);
}
+
+ /* emit changed */
+ as_store_changed_uninhibit (&tok);
+ as_store_perhaps_emit_changed (store, "load-installed");
+
return TRUE;
}
@@ -1769,6 +1947,7 @@ as_store_load (AsStore *store,
GCancellable *cancellable,
GError **error)
{
+ /* load from multiple locations */
AsStorePrivate *priv = GET_PRIVATE (store);
const gchar * const * data_dirs;
const gchar *tmp;
@@ -1776,6 +1955,7 @@ as_store_load (AsStore *store,
guint i;
_cleanup_ptrarray_unref_ GPtrArray *app_info = NULL;
_cleanup_ptrarray_unref_ GPtrArray *installed = NULL;
+ _cleanup_uninhibit_ guint32 *tok = NULL;
/* system locations */
app_info = g_ptr_array_new_with_free_func (g_free);
@@ -1825,6 +2005,7 @@ as_store_load (AsStore *store,
}
/* load each app-info path if it exists */
+ tok = as_store_changed_inhibit (store);
for (i = 0; i < app_info->len; i++) {
_cleanup_free_ gchar *dest = NULL;
tmp = g_ptr_array_index (app_info, i);
@@ -1860,6 +2041,9 @@ as_store_load (AsStore *store,
/* match again, for applications extended from different roots */
as_store_match_addons (store);
+ /* emit changed */
+ as_store_changed_uninhibit (&tok);
+ as_store_perhaps_emit_changed (store, "store-load");
return TRUE;
}
@@ -2103,6 +2287,40 @@ as_store_validate (AsStore *store, AsAppValidateFlags flags, GError **error)
}
/**
+ * as_store_init:
+ **/
+static void
+as_store_init (AsStore *store)
+{
+ AsStorePrivate *priv = GET_PRIVATE (store);
+ priv->api_version = AS_API_VERSION_NEWEST;
+ priv->array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
+ priv->watch_flags = AS_STORE_WATCH_FLAG_NONE;
+ priv->hash_id = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ NULL,
+ NULL);
+ priv->hash_pkgname = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify) g_object_unref);
+ priv->monitor = as_monitor_new ();
+ g_signal_connect (priv->monitor, "changed",
+ G_CALLBACK (as_store_monitor_changed_cb),
+ store);
+ g_signal_connect (priv->monitor, "added",
+ G_CALLBACK (as_store_monitor_added_cb),
+ store);
+ g_signal_connect (priv->monitor, "removed",
+ G_CALLBACK (as_store_monitor_removed_cb),
+ store);
+ priv->metadata_indexes = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify) g_hash_table_unref);
+}
+
+/**
* as_store_new:
*
* Creates a new #AsStore.
diff --git a/libappstream-glib/as-store.h b/libappstream-glib/as-store.h
index cb85fa7..b289c7d 100644
--- a/libappstream-glib/as-store.h
+++ b/libappstream-glib/as-store.h
@@ -102,6 +102,22 @@ typedef enum {
} AsStoreAddFlags;
/**
+ * AsStoreWatchFlags:
+ * @AS_STORE_WATCH_FLAG_NONE: No extra flags to use
+ * @AS_STORE_WATCH_FLAG_ADDED: Add applications if files change or are added
+ * @AS_STORE_WATCH_FLAG_REMOVED: Remove applications if files are changed or deleted
+ *
+ * The flags to use when local files are added or removed from the store.
+ **/
+typedef enum {
+ AS_STORE_WATCH_FLAG_NONE = 0, /* Since: 0.4.2 */
+ AS_STORE_WATCH_FLAG_ADDED = 1, /* Since: 0.4.2 */
+ AS_STORE_WATCH_FLAG_REMOVED = 2, /* Since: 0.4.2 */
+ /*< private >*/
+ AS_STORE_WATCH_FLAG_LAST
+} AsStoreWatchFlags;
+
+/**
* AsStoreError:
* @AS_STORE_ERROR_FAILED: Generic failure
*
@@ -185,6 +201,9 @@ void as_store_set_api_version (AsStore *store,
AsStoreAddFlags as_store_get_add_flags (AsStore *store);
void as_store_set_add_flags (AsStore *store,
AsStoreAddFlags add_flags);
+AsStoreWatchFlags as_store_get_watch_flags (AsStore *store);
+void as_store_set_watch_flags (AsStore *store,
+ AsStoreWatchFlags watch_flags);
GPtrArray *as_store_validate (AsStore *store,
AsAppValidateFlags flags,
GError **error);