1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /* This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License,
5 * version 2, as published by the Free Software Foundation
7 * This program is distributed in the hope that it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 #include "xml-parser.h"
24 /* Make room for 2500 package ids, 40 bytes + '\0' each */
25 #define PACKAGE_IDS_CHUNK 41 * 2500
27 typedef struct _UpdateInfo UpdateInfo;
29 typedef void (*InfoInitFn) (UpdateInfo *update_info, sqlite3 *db, GError **err);
30 typedef void (*InfoCleanFn) (UpdateInfo *update_info);
32 typedef void (*XmlParseFn) (const char *filename,
33 CountFn count_callback,
34 PackageFn package_callback,
38 typedef void (*WriteDbPackageFn) (UpdateInfo *update_info, Package *package);
40 typedef void (*IndexTablesFn) (sqlite3 *db, GError **err);
44 sqlite3_stmt *remove_handle;
45 guint32 count_from_md;
46 guint32 packages_seen;
49 GHashTable *current_packages;
50 GHashTable *all_packages;
51 GStringChunk *package_ids_chunk;
53 gpointer python_callback;
56 InfoCleanFn info_clean;
57 CreateTablesFn create_tables;
58 WriteDbPackageFn write_package;
60 IndexTablesFn index_tables;
66 update_info_init (UpdateInfo *info, GError **err)
71 sql = "DELETE FROM packages WHERE pkgKey = ?";
72 rc = sqlite3_prepare (info->db, sql, -1, &info->remove_handle, NULL);
73 if (rc != SQLITE_OK) {
74 g_set_error (err, YUM_DB_ERROR, YUM_DB_ERROR,
75 "Can not prepare package removal: %s",
76 sqlite3_errmsg (info->db));
77 sqlite3_finalize (info->remove_handle);
81 info->count_from_md = 0;
82 info->packages_seen = 0;
85 info->all_packages = g_hash_table_new (g_str_hash, g_str_equal);
86 info->package_ids_chunk = g_string_chunk_new (PACKAGE_IDS_CHUNK);
87 info->timer = g_timer_new ();
88 g_timer_start (info->timer);
89 info->current_packages = yum_db_read_package_ids (info->db, err);
93 remove_entry (gpointer key, gpointer value, gpointer user_data)
95 UpdateInfo *info = (UpdateInfo *) user_data;
97 if (g_hash_table_lookup (info->all_packages, key) == NULL) {
100 sqlite3_bind_int (info->remove_handle, 1, GPOINTER_TO_INT (value));
101 rc = sqlite3_step (info->remove_handle);
102 sqlite3_reset (info->remove_handle);
104 if (rc != SQLITE_DONE)
105 g_warning ("Error removing package from SQL: %s",
106 sqlite3_errmsg (info->db));
113 update_info_remove_old_entries (UpdateInfo *info)
115 g_hash_table_foreach (info->current_packages, remove_entry, info);
119 count_cb (guint32 count, gpointer user_data)
121 UpdateInfo *info = (UpdateInfo *) user_data;
123 info->count_from_md = count;
127 update_info_done (UpdateInfo *info, GError **err)
129 if (info->remove_handle)
130 sqlite3_finalize (info->remove_handle);
131 if (info->current_packages)
132 g_hash_table_destroy (info->current_packages);
133 if (info->all_packages)
134 g_hash_table_destroy (info->all_packages);
135 if (info->package_ids_chunk)
136 g_string_chunk_free (info->package_ids_chunk);
138 g_timer_stop (info->timer);
140 g_message ("Added %d new packages, deleted %d old in %.2f seconds",
141 info->add_count, info->del_count,
142 g_timer_elapsed (info->timer, NULL));
145 g_timer_destroy (info->timer);
152 UpdateInfo update_info;
153 sqlite3_stmt *pkg_handle;
154 sqlite3_stmt *requires_handle;
155 sqlite3_stmt *provides_handle;
156 sqlite3_stmt *conflicts_handle;
157 sqlite3_stmt *obsoletes_handle;
158 sqlite3_stmt *files_handle;
162 package_writer_info_init (UpdateInfo *update_info, sqlite3 *db, GError **err)
164 PackageWriterInfo *info = (PackageWriterInfo *) update_info;
166 info->pkg_handle = yum_db_package_prepare (db, err);
169 info->requires_handle = yum_db_dependency_prepare (db, "requires", err);
172 info->provides_handle = yum_db_dependency_prepare (db, "provides", err);
175 info->conflicts_handle = yum_db_dependency_prepare (db, "conflicts", err);
178 info->obsoletes_handle = yum_db_dependency_prepare (db, "obsoletes", err);
181 info->files_handle = yum_db_file_prepare (db, err);
185 write_deps (sqlite3 *db, sqlite3_stmt *handle, gint64 pkgKey,
190 for (iter = deps; iter; iter = iter->next)
191 yum_db_dependency_write (db, handle, pkgKey, (Dependency *) iter->data,
196 write_requirements (sqlite3 *db, sqlite3_stmt *handle, gint64 pkgKey,
201 for (iter = deps; iter; iter = iter->next)
202 yum_db_dependency_write (db, handle, pkgKey, (Dependency *) iter->data,
208 write_files (sqlite3 *db, sqlite3_stmt *handle, Package *pkg)
212 for (iter = pkg->files; iter; iter = iter->next)
213 yum_db_file_write (db, handle, pkg->pkgKey,
214 (PackageFile *) iter->data);
218 write_package_to_db (UpdateInfo *update_info, Package *package)
220 PackageWriterInfo *info = (PackageWriterInfo *) update_info;
222 yum_db_package_write (update_info->db, info->pkg_handle, package);
224 write_requirements (update_info->db, info->requires_handle,
225 package->pkgKey, package->requires);
226 write_deps (update_info->db, info->provides_handle,
227 package->pkgKey, package->provides);
228 write_deps (update_info->db, info->conflicts_handle,
229 package->pkgKey, package->conflicts);
230 write_deps (update_info->db, info->obsoletes_handle,
231 package->pkgKey, package->obsoletes);
233 write_files (update_info->db, info->files_handle, package);
237 package_writer_info_clean (UpdateInfo *update_info)
239 PackageWriterInfo *info = (PackageWriterInfo *) update_info;
241 if (info->pkg_handle)
242 sqlite3_finalize (info->pkg_handle);
243 if (info->requires_handle)
244 sqlite3_finalize (info->requires_handle);
245 if (info->provides_handle)
246 sqlite3_finalize (info->provides_handle);
247 if (info->conflicts_handle)
248 sqlite3_finalize (info->conflicts_handle);
249 if (info->obsoletes_handle)
250 sqlite3_finalize (info->obsoletes_handle);
251 if (info->files_handle)
252 sqlite3_finalize (info->files_handle);
259 UpdateInfo update_info;
260 sqlite3_stmt *pkg_handle;
261 sqlite3_stmt *file_handle;
265 update_filelist_info_init (UpdateInfo *update_info, sqlite3 *db, GError **err)
267 FileListInfo *info = (FileListInfo *) update_info;
269 info->pkg_handle = yum_db_package_ids_prepare (db, err);
273 info->file_handle = yum_db_filelists_prepare (db, err);
277 update_filelist_info_clean (UpdateInfo *update_info)
279 FileListInfo *info = (FileListInfo *) update_info;
281 if (info->pkg_handle)
282 sqlite3_finalize (info->pkg_handle);
283 if (info->file_handle)
284 sqlite3_finalize (info->file_handle);
288 write_filelist_package_to_db (UpdateInfo *update_info, Package *package)
290 FileListInfo *info = (FileListInfo *) update_info;
292 yum_db_package_ids_write (update_info->db, info->pkg_handle, package);
293 yum_db_filelists_write (update_info->db, info->file_handle, package);
300 UpdateInfo update_info;
301 sqlite3_stmt *pkg_handle;
302 sqlite3_stmt *changelog_handle;
306 update_other_info_init (UpdateInfo *update_info, sqlite3 *db, GError **err)
308 UpdateOtherInfo *info = (UpdateOtherInfo *) update_info;
309 info->pkg_handle = yum_db_package_ids_prepare (db, err);
313 info->changelog_handle = yum_db_changelog_prepare (db, err);
317 update_other_info_clean (UpdateInfo *update_info)
319 UpdateOtherInfo *info = (UpdateOtherInfo *) update_info;
321 if (info->pkg_handle)
322 sqlite3_finalize (info->pkg_handle);
323 if (info->changelog_handle)
324 sqlite3_finalize (info->changelog_handle);
328 write_other_package_to_db (UpdateInfo *update_info, Package *package)
330 UpdateOtherInfo *info = (UpdateOtherInfo *) update_info;
332 yum_db_package_ids_write (update_info->db, info->pkg_handle, package);
333 yum_db_changelog_write (update_info->db, info->changelog_handle, package);
337 /*****************************************************************************/
340 progress_cb (UpdateInfo *update_info)
342 PyObject *progress = (PyObject *) update_info->python_callback;
343 PyObject *repoid = (PyObject *) update_info->user_data;
349 args = PyTuple_New (3);
350 PyTuple_SET_ITEM (args, 0, PyInt_FromLong (update_info->packages_seen));
351 PyTuple_SET_ITEM (args, 1, PyInt_FromLong (update_info->count_from_md));
352 PyTuple_SET_ITEM (args, 2, repoid);
354 result = PyEval_CallObject (progress, args);
360 update_package_cb (Package *p, gpointer user_data)
362 UpdateInfo *update_info = (UpdateInfo *) user_data;
364 /* TODO: Wire in logging of skipped packages */
365 if (p->pkgId == NULL) {
369 g_hash_table_insert (update_info->all_packages,
370 g_string_chunk_insert (update_info->package_ids_chunk,
372 GINT_TO_POINTER (1));
374 if (g_hash_table_lookup (update_info->current_packages,
377 update_info->write_package (update_info, p);
378 update_info->add_count++;
381 if (update_info->count_from_md > 0 && update_info->python_callback) {
382 update_info->packages_seen++;
383 progress_cb (update_info);
388 update_packages (UpdateInfo *update_info,
389 const char *md_filename,
390 const char *checksum,
391 gpointer python_callback,
397 db_filename = yum_db_filename (md_filename);
398 update_info->db = yum_db_open (db_filename, checksum,
399 update_info->create_tables,
405 if (!update_info->db)
408 update_info_init (update_info, err);
412 update_info->python_callback = python_callback;
413 update_info->user_data = user_data;
415 update_info->info_init (update_info, update_info->db, err);
419 sqlite3_exec (update_info->db, "BEGIN", NULL, NULL, NULL);
420 update_info->xml_parse (md_filename,
427 sqlite3_exec (update_info->db, "COMMIT", NULL, NULL, NULL);
429 update_info->index_tables (update_info->db, err);
433 update_info_remove_old_entries (update_info);
434 yum_db_dbinfo_update (update_info->db, checksum, err);
437 update_info->info_clean (update_info);
438 update_info_done (update_info, err);
441 sqlite3_close (update_info->db);
444 g_free (db_filename);
451 /*********************************************************************/
454 py_parse_args (PyObject *args,
455 const char **md_filename,
456 const char **checksum,
463 if (!PyArg_ParseTuple (args, "ssOO", md_filename, checksum, &callback,
467 if (PyObject_HasAttrString (callback, "log")) {
468 *log = PyObject_GetAttrString (callback, "log");
470 if (!PyCallable_Check (*log)) {
471 PyErr_SetString (PyExc_TypeError, "parameter must be callable");
476 if (PyObject_HasAttrString (callback, "progressbar")) {
477 *progress = PyObject_GetAttrString (callback, "progressbar");
479 if (!PyCallable_Check (*progress)) {
480 PyErr_SetString (PyExc_TypeError, "parameter must be callable");
489 log_cb (const gchar *log_domain,
490 GLogLevelFlags log_level,
491 const gchar *message,
494 PyObject *callback = (PyObject *) user_data;
502 args = PyTuple_New (2);
505 case G_LOG_LEVEL_DEBUG:
508 case G_LOG_LEVEL_MESSAGE:
511 case G_LOG_LEVEL_WARNING:
514 case G_LOG_LEVEL_CRITICAL:
520 PyTuple_SET_ITEM (args, 0, PyInt_FromLong (level));
521 PyTuple_SET_ITEM (args, 1, PyString_FromString (message));
523 result = PyEval_CallObject (callback, args);
529 py_update (PyObject *self, PyObject *args, UpdateInfo *update_info)
531 const char *md_filename = NULL;
532 const char *checksum = NULL;
533 PyObject *log = NULL;
534 PyObject *progress = NULL;
535 PyObject *repoid = NULL;
538 PyObject *ret = NULL;
541 if (!py_parse_args (args, &md_filename, &checksum, &log, &progress,
545 GLogLevelFlags level = G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_WARNING |
546 G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_DEBUG;
547 log_id = g_log_set_handler (NULL, level, log_cb, log);
549 db_filename = update_packages (update_info, md_filename, checksum,
550 progress, repoid, &err);
552 g_log_remove_handler (NULL, log_id);
555 ret = PyString_FromString (db_filename);
556 g_free (db_filename);
558 PyErr_SetString (PyExc_TypeError, err->message);
566 py_update_primary (PyObject *self, PyObject *args)
568 PackageWriterInfo info;
569 memset (&info, 0, sizeof (PackageWriterInfo));
571 info.update_info.info_init = package_writer_info_init;
572 info.update_info.info_clean = package_writer_info_clean;
573 info.update_info.create_tables = yum_db_create_primary_tables;
574 info.update_info.write_package = write_package_to_db;
575 info.update_info.xml_parse = yum_xml_parse_primary;
576 info.update_info.index_tables = yum_db_index_primary_tables;
578 return py_update (self, args, (UpdateInfo *) &info);
582 py_update_filelist (PyObject *self, PyObject *args)
585 memset (&info, 0, sizeof (FileListInfo));
587 info.update_info.info_init = update_filelist_info_init;
588 info.update_info.info_clean = update_filelist_info_clean;
589 info.update_info.create_tables = yum_db_create_filelist_tables;
590 info.update_info.write_package = write_filelist_package_to_db;
591 info.update_info.xml_parse = yum_xml_parse_filelists;
592 info.update_info.index_tables = yum_db_index_filelist_tables;
594 return py_update (self, args, (UpdateInfo *) &info);
598 py_update_other (PyObject *self, PyObject *args)
600 UpdateOtherInfo info;
601 memset (&info, 0, sizeof (UpdateOtherInfo));
603 info.update_info.info_init = update_other_info_init;
604 info.update_info.info_clean = update_other_info_clean;
605 info.update_info.create_tables = yum_db_create_other_tables;
606 info.update_info.write_package = write_other_package_to_db;
607 info.update_info.xml_parse = yum_xml_parse_other;
608 info.update_info.index_tables = yum_db_index_other_tables;
610 return py_update (self, args, (UpdateInfo *) &info);
613 static PyMethodDef SqliteMethods[] = {
614 {"update_primary", py_update_primary, METH_VARARGS,
615 "Parse YUM primary.xml metadata."},
616 {"update_filelist", py_update_filelist, METH_VARARGS,
617 "Parse YUM filelists.xml metadata."},
618 {"update_other", py_update_other, METH_VARARGS,
619 "Parse YUM other.xml metadata."},
621 {NULL, NULL, 0, NULL}
625 init_sqlitecache (void)
629 m = Py_InitModule ("_sqlitecache", SqliteMethods);
631 d = PyModule_GetDict(m);
632 PyDict_SetItemString(d, "DBVERSION", PyInt_FromLong(YUM_SQLITE_CACHE_DBVERSION));