/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Richard Hughes * Copyright (C) 2008 Shishir Goel * * Licensed under the GNU General Public License Version 2 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_ARCHIVE_H #include #include #endif /* HAVE_ARCHIVE_H */ #include #include #include #include "egg-debug.h" #include "egg-string.h" #include "pk-tools-common.h" /** * pk_generate_pack_perhaps_resolve: **/ gchar * pk_generate_pack_perhaps_resolve (PkClient *client, PkBitfield filter, const gchar *package, GError **error) { gboolean ret; gboolean valid; guint i; guint length; const PkPackageObj *obj; PkPackageList *list; gchar **packages; /* check for NULL values */ if (package == NULL) { egg_warning ("Cannot resolve the package: invalid package"); return NULL; } /* have we passed a complete package_id? */ valid = pk_package_id_check (package); if (valid) { return g_strdup (package); } ret = pk_client_reset (client, error); if (ret == FALSE) { egg_warning ("failed to reset client task"); return NULL; } /* we need to resolve it */ packages = pk_package_ids_from_id (package); ret = pk_client_resolve (client, filter, packages, error); g_strfreev (packages); if (ret == FALSE) { egg_warning ("Resolve failed"); return NULL; } /* get length of items found */ list = pk_client_get_package_list (client); length = pk_package_list_get_size (list); g_object_unref (list); /* didn't resolve to anything, try to get a provide */ if (length == 0) { ret = pk_client_reset (client, error); if (ret == FALSE) { egg_warning ("failed to reset client task"); return NULL; } ret = pk_client_what_provides (client, filter, PK_PROVIDES_ENUM_ANY, package, error); if (ret == FALSE) { egg_warning ("WhatProvides is not supported in this backend"); return NULL; } } /* get length of items found again (we might have had success) */ list = pk_client_get_package_list (client); length = pk_package_list_get_size (list); if (length == 0) { egg_warning (_("Could not find a package match")); return NULL; } /* only found one, great! */ if (length == 1) { obj = pk_package_list_get_obj (list, 0); return pk_package_id_to_string (obj->id); } g_print ("%s\n", _("There are multiple package matches")); for (i=0; iid->name, obj->id->version, obj->id->arch); } /* find out what package the user wants to use */ i = pk_console_get_number (_("Please enter the package number: "), length); obj = pk_package_list_get_obj (list, i-1); g_object_unref (list); return pk_package_id_to_string (obj->id); } /** * pk_generate_pack_download_only: **/ gboolean pk_generate_pack_download_only (PkClient *client, gchar **package_ids, const gchar *directory) { gboolean ret; GError *error = NULL; /* check for NULL values */ if (package_ids == NULL || directory == NULL) { egg_warning (_("failed to download: invalid package_id and/or directory")); ret = FALSE; goto out; } egg_debug ("download+ %s %s", package_ids[0], directory); ret = pk_client_reset (client, &error); if (!ret) { egg_warning ("failed to download: %s", error->message); g_error_free (error); goto out; } ret = pk_client_download_packages (client, package_ids, directory, &error); if (!ret) { egg_warning ("failed to download: %s", error->message); g_error_free (error); goto out; } out: return ret; } /** * pk_generate_pack_exclude_packages: **/ gboolean pk_generate_pack_exclude_packages (PkPackageList *list, const gchar *package_list) { guint i; guint length; gboolean found; PkPackageList *list_packages; const PkPackageObj *obj; gboolean ret; list_packages = pk_package_list_new (); /* check for NULL values */ if (package_list == NULL) { egg_warning ("Cannot find the list of packages to be excluded"); ret = FALSE; goto out; } /* load a list of packages already found on the users system */ ret = pk_package_list_add_file (list_packages, package_list); if (!ret) goto out; /* do not just download everything, uselessly */ length = pk_package_list_get_size (list_packages); for (i=0; iid->name); } out: g_object_unref (list_packages); return ret; } /** * pk_generate_pack_set_metadata: **/ gboolean pk_generate_pack_set_metadata (const gchar *full_path) { gboolean ret = FALSE; gchar *distro_id = NULL; gchar *datetime = NULL; GError *error = NULL; GKeyFile *file = NULL; gchar *data = NULL; file = g_key_file_new (); /* check for NULL values */ if (full_path == NULL) { egg_warning (_("Could not find a valid metadata file")); goto out; } /* get needed data */ distro_id = pk_get_distro_id (); if (distro_id == NULL) goto out; datetime = pk_iso8601_present (); if (datetime == NULL) goto out; g_key_file_set_string (file, PK_SERVICE_PACK_GROUP_NAME, "distro_id", distro_id); g_key_file_set_string (file, PK_SERVICE_PACK_GROUP_NAME, "created", datetime); /* convert to text */ data = g_key_file_to_data (file, NULL, &error); if (data == NULL) { egg_warning ("failed to convert to text: %s", error->message); g_error_free (error); goto out; } /* save contents */ ret = g_file_set_contents (full_path, data, -1, &error); if (!ret) { egg_warning ("failed to save file: %s", error->message); g_error_free (error); goto out; } out: g_key_file_free (file); g_free (data); g_free (distro_id); g_free (datetime); return ret; } #ifdef HAVE_ARCHIVE_H /** * pk_generate_pack_archive_add_file: **/ static gboolean pk_generate_pack_archive_add_file (struct archive *arch, const gchar *filename, GError **error) { int retval; int len; int fd = -1; int wrote; gboolean ret = FALSE; gchar *filename_basename = NULL; struct archive_entry *entry = NULL; struct stat st; gchar buff[8192]; /* stat file */ retval = stat (filename, &st); if (retval != 0) { *error = g_error_new (1, 0, "file not found %s", filename); goto out; } egg_debug ("stat(%s), size=%lu bytes\n", filename, st.st_size); /* create new entry */ entry = archive_entry_new (); archive_entry_copy_stat (entry, &st); filename_basename = g_path_get_basename (filename); archive_entry_set_pathname (entry, filename_basename); /* ._BIG FAT BUG_. We should not have to do this, as it should be * set from archive_entry_copy_stat() */ archive_entry_set_size (entry, st.st_size); /* write header */ retval = archive_write_header (arch, entry); if (retval != ARCHIVE_OK) { *error = g_error_new (1, 0, "failed to write header: %s\n", archive_error_string (arch)); goto out; } /* open file to copy */ fd = open (filename, O_RDONLY); if (fd < 0) { *error = g_error_new (1, 0, "failed to get fd for %s", filename); goto out; } /* ITS4: ignore, buffer statically preallocated */ len = read (fd, buff, sizeof (buff)); /* write data to archive -- how come no convenience function? */ while (len > 0) { wrote = archive_write_data (arch, buff, len); if (wrote != len) egg_warning("wrote %i instead of %i\n", wrote, len); /* ITS4: ignore, buffer statically preallocated */ len = read (fd, buff, sizeof (buff)); } ret = TRUE; out: if (fd >= 0) close (fd); if (entry != NULL) archive_entry_free (entry); g_free (filename_basename); return ret; } /** * pk_generate_pack_create: **/ gboolean pk_generate_pack_create (const gchar *tarfilename, GPtrArray *file_array, GError **error) { struct archive *arch = NULL; gboolean ret = FALSE; const gchar *src; guint i; gchar *metadata_filename; g_return_val_if_fail (tarfilename != NULL, FALSE); g_return_val_if_fail (file_array != NULL, FALSE); g_return_val_if_fail (error != NULL, FALSE); /* create a file with metadata in it */ metadata_filename = g_build_filename (g_get_tmp_dir (), "metadata.conf", NULL); ret = pk_generate_pack_set_metadata (metadata_filename); if (!ret) { *error = g_error_new (1, 0, "failed to generate metadata file %s", metadata_filename); goto out; } g_ptr_array_add (file_array, g_strdup (metadata_filename)); /* we can only write tar achives */ arch = archive_write_new (); archive_write_set_compression_none (arch); archive_write_set_format_ustar (arch); archive_write_open_filename (arch, tarfilename); /* for each filename */ for (i=0; ilen; i++) { src = (const gchar *) g_ptr_array_index (file_array, i); /* try to add to archive */ ret = pk_generate_pack_archive_add_file (arch, src, error); if (!ret) goto out; } /* completed all okay */ ret = TRUE; out: g_free (metadata_filename); /* delete each filename */ for (i=0; ilen; i++) { src = (const gchar *) g_ptr_array_index (file_array, i); g_remove (src); } /* close the archive */ if (arch != NULL) { archive_write_close (arch); archive_write_finish (arch); } return ret; } #else /** * pk_generate_pack_create: **/ gboolean pk_generate_pack_create (const gchar *tarfilename, GPtrArray *file_array, GError **error) { *error = g_error_new (1, 0, "Cannot create pack as PackageKit as not built with libtar support"); return FALSE; } #endif /** * pk_generate_pack_scan_dir: **/ GPtrArray * pk_generate_pack_scan_dir (const gchar *directory) { gchar *src; GPtrArray *file_array = NULL; GDir *dir; const gchar *filename; /* check for NULL values */ if (directory == NULL) { egg_warning ("failed to get directory"); goto out; } /* try and open the directory */ dir = g_dir_open (directory, 0, NULL); if (dir == NULL) { egg_warning ("failed to get directory for %s", directory); goto out; } /* add each file to an array */ file_array = g_ptr_array_new (); while ((filename = g_dir_read_name (dir))) { src = g_build_filename (directory, filename, NULL); g_ptr_array_add (file_array, src); } g_dir_close (dir); out: return file_array; } /** * pk_generate_pack_main: **/ gboolean pk_generate_pack_main (const gchar *pack_filename, const gchar *directory, const gchar *package, const gchar *package_list, GError **error) { gchar *package_id; gchar **package_ids; PkPackageList *list = NULL; guint length; gboolean download; guint i; const PkPackageObj *obj; GPtrArray *file_array = NULL; PkClient *client; GError *error_local = NULL; gboolean ret = FALSE; gchar *text; client = pk_client_new (); pk_client_set_use_buffer (client, TRUE, NULL); pk_client_set_synchronous (client, TRUE, NULL); /* resolve package */ package_id = pk_generate_pack_perhaps_resolve (client, PK_FILTER_ENUM_NONE, package, &error_local); if (package_id == NULL) { egg_warning ("failed to resolve: %s", error_local->message); g_error_free (error_local); goto out; } /* download this package */ package_ids = pk_package_ids_from_id (package_id); ret = pk_generate_pack_download_only (client, package_ids, directory); if (!ret) { egg_warning ("failed to download main package: %s", error_local->message); g_error_free (error_local); goto out; } /* get depends */ ret = pk_client_reset (client, &error_local); if (!ret) { egg_warning ("failed to reset: %s", error_local->message); g_error_free (error_local); goto out; } egg_debug ("Getting depends for %s", package_id); ret = pk_client_get_depends (client, PK_FILTER_ENUM_NONE, package_ids, TRUE, &error_local); if (!ret) { egg_warning ("failed to get depends: %s", error_local->message); g_error_free (error_local); goto out; } g_strfreev (package_ids); /* get the deps */ list = pk_client_get_package_list (client); /* remove some deps */ ret = pk_generate_pack_exclude_packages (list, package_list); if (!ret) { egg_warning ("failed to exclude packages"); goto out; } /* list deps */ length = pk_package_list_get_size (list); for (i=0; imessage); g_error_free (error_local); goto out; } out: g_object_unref (client); if (list != NULL) g_object_unref (list); g_free (package_id); if (file_array != NULL) { g_ptr_array_foreach (file_array, (GFunc) g_free, NULL); g_ptr_array_free (file_array, TRUE); } return ret; } /*************************************************************************** *** MAKE CHECK TESTS *** ***************************************************************************/ #ifdef EGG_TEST #include "egg-test.h" void pk_genpack_test (EggTest *test) { PkClient *client = NULL; gboolean ret; gboolean retval; GError *error = NULL; gchar *file; PkPackageList *list = NULL; GPtrArray *file_array = NULL; gchar *src; gchar **package_ids; if (!egg_test_start (test, "PkGeneratePack")) return; /************************************************************/ egg_test_title (test, "get client"); client = pk_client_new (); if (client != NULL) egg_test_success (test, NULL); else egg_test_failed (test, NULL); /************************************************************/ egg_test_title (test, "test perhaps resolve NULL"); retval = pk_client_reset (client, &error); file = pk_generate_pack_perhaps_resolve (client, PK_FILTER_ENUM_NONE, NULL, &error); if (file == NULL) egg_test_success (test, NULL); else { egg_test_failed (test, "failed to resolve %s", error->message); g_error_free (error); } g_free (file); /************************************************************/ egg_test_title (test, "test perhaps resolve gitk"); retval = pk_client_reset(client, &error); file = pk_generate_pack_perhaps_resolve (client, PK_FILTER_ENUM_NONE, "gitk;1.5.5.1-1.fc9;i386;installed", &error); if (file != NULL && egg_strequal (file, "gitk;1.5.5.1-1.fc9;i386;installed")) egg_test_success (test, NULL); else egg_test_failed (test, "got: %s", file); g_free (file); /************************************************************/ egg_test_title (test, "download only NULL"); ret = pk_generate_pack_download_only (client, NULL, NULL); if (!ret) egg_test_success (test, NULL); else egg_test_failed (test, NULL); /************************************************************/ egg_test_title (test, "download only gitk"); package_ids = pk_package_ids_from_id ("gitk;1.5.5.1-1.fc9;i386;installed"); ret = pk_generate_pack_download_only (client, package_ids, "/tmp"); if (ret) egg_test_success (test, NULL); else egg_test_failed (test, NULL); g_strfreev (package_ids); g_object_unref (client); /************************************************************/ egg_test_title (test, "exclude NULL"); list = pk_package_list_new (); ret = pk_generate_pack_exclude_packages (list, NULL); if (!ret) egg_test_success (test, NULL); else egg_test_failed (test, NULL); /************************************************************/ egg_test_title (test, "exclude /var/lib/PackageKit/package-list.txt"); list = pk_package_list_new (); ret = pk_generate_pack_exclude_packages (list, "/var/lib/PackageKit/package-list.txt"); if (ret) egg_test_success (test, NULL); else egg_test_failed (test, NULL); g_object_unref (list); /************************************************************/ egg_test_title (test, "exclude false.txt"); list = pk_package_list_new (); ret = pk_generate_pack_exclude_packages (list, "/media/USB/false.txt"); if (!ret) egg_test_success (test, NULL); else egg_test_failed (test, NULL); g_object_unref (list); /************************************************************/ egg_test_title (test, "metadata NULL"); ret = pk_generate_pack_set_metadata (NULL); if (!ret) egg_test_success (test, NULL); else egg_test_failed (test, NULL); /************************************************************/ egg_test_title (test, "metadata /tmp/metadata.conf"); ret = pk_generate_pack_set_metadata ("/tmp/metadata.conf"); if (ret) egg_test_success (test, NULL); else egg_test_failed (test, NULL); g_remove ("/tmp/metadata.conf"); /************************************************************/ egg_test_title (test, "scandir NULL"); file_array = pk_generate_pack_scan_dir (NULL); if (file_array == NULL) egg_test_success (test, NULL); else egg_test_failed (test, NULL); /************************************************************/ egg_test_title (test, "scandir /tmp"); file_array = pk_generate_pack_scan_dir ("/tmp"); if (file_array != NULL) egg_test_success (test, NULL); else egg_test_failed (test, NULL); /************************************************************/ egg_test_title (test, "generate pack /tmp/gitk.servicepack gitk"); file_array = g_ptr_array_new (); src = g_build_filename ("/tmp", "gitk-1.5.5.1-1.fc9.i386.rpm", NULL); g_ptr_array_add (file_array, src); ret = pk_generate_pack_create ("/tmp/gitk.servicepack", file_array, &error); if (!ret) { if (error != NULL) { egg_test_failed (test, "failed to create pack %s" , error->message); g_error_free (error); } else { egg_test_failed (test, "could not set error"); } } else egg_test_success (test, NULL); if (file_array != NULL) { g_ptr_array_foreach (file_array, (GFunc) g_free, NULL); g_ptr_array_free (file_array, TRUE); } g_remove ("/tmp/gitk.servicepack"); /************************************************************/ egg_test_end (test); } #endif