[gnome-software/wip/temp/ubuntu-xenial-rebased: 224/326] apt: Read lists of installed files from dpkg directly
- From: Iain Lane <iainl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software/wip/temp/ubuntu-xenial-rebased: 224/326] apt: Read lists of installed files from dpkg directly
- Date: Fri, 29 Apr 2016 10:06:10 +0000 (UTC)
commit 4bd0eefd0689a5eed8325336db2658848de517de
Author: Iain Lane <iain orangesquash org uk>
Date: Wed Apr 13 14:40:46 2016 +0100
apt: Read lists of installed files from dpkg directly
This is needed so that we can map from IDs, such as those from
AppStream, back to packages.
src/plugins/gs-plugin-apt.cc | 215 +++++++++++++++++++++++++++++++++++++++++-
1 files changed, 213 insertions(+), 2 deletions(-)
---
diff --git a/src/plugins/gs-plugin-apt.cc b/src/plugins/gs-plugin-apt.cc
index f9c50d4..1eccd43 100644
--- a/src/plugins/gs-plugin-apt.cc
+++ b/src/plugins/gs-plugin-apt.cc
@@ -46,6 +46,24 @@
#define LICENSE_URL "http://www.ubuntu.com/about/about-ubuntu/licensing"
+#define INFO_DIR "/var/lib/dpkg/info"
+
+typedef struct
+{
+ GMutex pending_mutex;
+ GCond pending_cond;
+
+ GMutex dispatched_mutex;
+ GCond dispatched_cond;
+
+ GMutex hashtable_mutex;
+
+ guint still_to_read;
+ guint dispatched_reads;
+
+ GsPlugin *plugin;
+} ReadListData;
+
typedef struct {
gchar *name;
gchar *section;
@@ -64,6 +82,7 @@ typedef struct {
struct GsPluginPrivate {
gsize loaded;
GHashTable *package_info;
+ GHashTable *installed_files;
GList *installed_packages;
GList *updatable_packages;
};
@@ -125,6 +144,11 @@ gs_plugin_initialize (GsPlugin *plugin)
NULL,
free_package_info);
+ plugin->priv->installed_files = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_free);
+
pkgInitConfig (*_config);
pkgInitSystem (*_config, _system);
}
@@ -133,10 +157,158 @@ void
gs_plugin_destroy (GsPlugin *plugin)
{
g_hash_table_unref (plugin->priv->package_info);
+ g_hash_table_unref (plugin->priv->installed_files);
g_list_free (plugin->priv->installed_packages);
g_list_free (plugin->priv->updatable_packages);
}
+
+static void
+read_list_file_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ g_autoptr(GFileInputStream) stream = NULL;
+ g_autoptr(GFile) file = NULL;
+ ReadListData *data;
+ g_autofree gchar *buffer = NULL;
+ g_autofree gchar *filename = NULL;
+ g_autoptr(GFileInfo) info = NULL;
+ g_auto(GStrv) file_lines = NULL;
+ g_auto(GStrv) file_components = NULL;
+ gchar *line;
+
+ file = G_FILE (object);
+ data = (ReadListData *) user_data;
+ stream = g_file_read_finish (file, res, NULL);
+
+ info = g_file_input_stream_query_info (stream,
+ G_FILE_ATTRIBUTE_STANDARD_SIZE,
+ NULL,
+ NULL);
+
+ if (!info)
+ return;
+
+ if (!g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE))
+ return;
+
+ buffer = (gchar *) g_malloc0 (g_file_info_get_size (info) + 1);
+
+ if (!g_input_stream_read_all (G_INPUT_STREAM (stream),
+ buffer,
+ g_file_info_get_size (info),
+ NULL,
+ NULL,
+ NULL))
+ return;
+
+ g_input_stream_close (G_INPUT_STREAM (stream), NULL, NULL);
+
+ file_lines = g_strsplit (buffer, "\n", -1);
+
+ filename = g_file_get_basename (file);
+ file_components = g_strsplit (filename, ".", 2);
+
+ for (int i = 0; file_lines[i]; ++i)
+ if (g_str_has_suffix (file_lines[i], ".desktop") ||
+ g_str_has_suffix (file_lines[i], ".metainfo.xml") ||
+ g_str_has_suffix (file_lines[i], ".appdata.xml"))
+ {
+ g_mutex_lock (&data->hashtable_mutex);
+ /* filename -> package */
+ g_hash_table_insert (data->plugin->priv->installed_files,
+ g_strdup (file_lines[i]),
+ g_strdup (file_components[0]));
+ g_mutex_unlock (&data->hashtable_mutex);
+ }
+
+ g_mutex_lock (&data->dispatched_mutex);
+ (data->dispatched_reads)--;
+ g_cond_signal(&data->dispatched_cond);
+ g_mutex_unlock(&data->dispatched_mutex);
+
+ g_mutex_lock (&data->pending_mutex);
+ (data->still_to_read)--;
+ g_cond_signal (&data->pending_cond);
+ g_mutex_unlock (&data->pending_mutex);
+}
+
+static void
+read_list_file (GList *files,
+ ReadListData *data)
+{
+ GFile *gfile;
+ GList *files_iter;
+
+ for (files_iter = files; files_iter; files_iter = files_iter->next)
+ {
+ /* freed in read_list_file_cb */
+ gfile = g_file_new_for_path ((gchar *) files_iter->data);
+
+ g_mutex_lock (&data->dispatched_mutex);
+ g_file_read_async (gfile,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ read_list_file_cb,
+ data);
+
+ (data->dispatched_reads)++;
+
+ while (data->dispatched_reads >= 500)
+ g_cond_wait (&data->dispatched_cond, &data->dispatched_mutex);
+
+ g_mutex_unlock (&data->dispatched_mutex);
+ }
+}
+
+static void
+look_for_files (GsPlugin *plugin)
+{
+
+ ReadListData data;
+ GList *files = NULL;
+
+ data.still_to_read = 0;
+ data.dispatched_reads = 0;
+ g_cond_init (&data.pending_cond);
+ g_mutex_init (&data.pending_mutex);
+ g_cond_init (&data.dispatched_cond);
+ g_mutex_init (&data.dispatched_mutex);
+ g_mutex_init (&data.hashtable_mutex);
+ data.plugin = plugin;
+
+ g_autoptr (GDir) dir = NULL;
+ const gchar *file;
+
+ dir = g_dir_open (INFO_DIR, 0, NULL);
+
+ while (file = g_dir_read_name (dir))
+ if (g_str_has_suffix (file, ".list") &&
+ /* app-install-data contains loads of .desktop files, but they aren't installed by it */
+ (!g_strcmp0 (file, "app-install-data.list") == 0))
+ {
+ files = g_list_append (files, g_build_filename (INFO_DIR, file, NULL));
+ data.still_to_read++;
+ }
+
+ read_list_file (files, &data);
+
+ /* Wait until all the reads are done */
+ g_mutex_lock (&data.pending_mutex);
+ while (data.still_to_read > 0)
+ g_cond_wait (&data.pending_cond, &data.pending_mutex);
+ g_mutex_unlock (&data.pending_mutex);
+
+ g_mutex_clear (&data.pending_mutex);
+ g_cond_clear (&data.pending_cond);
+ g_mutex_clear (&data.dispatched_mutex);
+ g_cond_clear (&data.dispatched_cond);
+ g_mutex_clear (&data.hashtable_mutex);
+
+ g_list_free_full (files, g_free);
+}
+
static gboolean
version_newer (const gchar *v0, const gchar *v1)
{
@@ -262,6 +434,9 @@ load_apt_db (GsPlugin *plugin, GError **error)
return FALSE;
}
+ /* load filename -> package map into plugin->priv->installed_files */
+ look_for_files (plugin);
+
return TRUE;
}
@@ -356,6 +531,9 @@ gs_plugin_refine (GsPlugin *plugin,
GError **error)
{
GList *link;
+ GsApp *app;
+ PackageInfo *info;
+ const gchar *tmp;
/* Load database once */
if (g_once_init_enter (&plugin->priv->loaded)) {
@@ -368,8 +546,7 @@ gs_plugin_refine (GsPlugin *plugin,
}
for (link = *list; link; link = link->next) {
- GsApp *app = (GsApp *) link->data;
- PackageInfo *info;
+ app = (GsApp *) link->data;
if (gs_app_get_source_default (app) == NULL)
continue;
@@ -411,6 +588,40 @@ gs_plugin_refine (GsPlugin *plugin,
}
}
+ for (link = *list; link != NULL; link = link->next) {
+ g_autofree gchar *fn = NULL;
+ gchar *package = NULL;
+ app = GS_APP (link->data);
+ if (gs_app_get_source_id_default (app) != NULL)
+ continue;
+ tmp = gs_app_get_id (app);
+ if (tmp == NULL)
+ continue;
+ switch (gs_app_get_kind (app)) {
+ case AS_APP_KIND_DESKTOP:
+ fn = g_strdup_printf ("/usr/share/applications/%s", tmp);
+ break;
+ case AS_APP_KIND_ADDON:
+ fn = g_strdup_printf ("/usr/share/appdata/%s.metainfo.xml", tmp);
+ break;
+ default:
+ break;
+ }
+ if (fn == NULL)
+ continue;
+ if (!g_file_test (fn, G_FILE_TEST_EXISTS)) {
+ g_debug ("ignoring %s as does not exist", fn);
+ continue;
+ }
+ package = (gchar *) g_hash_table_lookup (plugin->priv->installed_files,
+ fn);
+ if (package == NULL)
+ continue;
+ g_debug ("%s => %s", gs_app_get_id (app), package);
+ gs_app_add_source (app, package);
+ gs_app_set_management_plugin (app, "apt");
+ }
+
return TRUE;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]