langupdate.cc File Reference


Detailed Description

Parse the cache output.

Author:
Neil Williams <codehelp@debian.org>

#include "config.h"
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <locale.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <apt-pkg/configuration.h>
#include "langupdate.h"
#include "aptcache.h"
#define GNU_WARRANTY
#define DPKG_II   "^Package: (.*)$"
#define GREX_EMPTY   GRegexMatchFlags(0)
#define DEBUG   ""
 debug handling
#define APTCONFIGSTR
 Configuration string for apt.
static guint c = 0
static const gchar * sourceslist = "/var/lib/langupdate/sources.list"
static GList * installed = NULL
static GList * targets = NULL
static gchar * suite_codename = NULL
static gchar * user_suite = NULL
static gboolean verbose = false
static gboolean dry_run = false
static gboolean show_version = false
static GOptionEntry entries []
gchar * lu_get_aptstring (void)
 Collate the various apt options into a string.
static void output (gpointer value, gpointer data)
static gchar * parse_installed (const gchar *pkg, const gchar *locale)
 Parses list of all installed packages.
static gboolean append_sourceslist (const gchar *lang)
 write the sources list
static void lu_check_allowed_suites (gchar *user_suite)
 checks the user specified suite against the allowed list
gint main (gint argc, gchar *argv[])
 Read the apt-cache to know what is available. then compare dpkg_list with apt_list.


Define Documentation

#define APTCONFIGSTR

Value:

"-o APT::Get::List-Cleanup=off " \
 "-o Apt::Install-Recommends=false " \
 "-o Dir=/var/lib/langupdate " \
 "-o Dir::Etc=/var/lib/langupdate " \
 "-o Dir::Etc::SourceList=sources.list " \
 "-o Dir::State::Status=/var/lib/langupdate/status "
Configuration string for apt.

Provides the main mechanism to separate the tdeb cache from the apt cache.

Note:
options that specify the suite are deliberately omitted.

#define DEBUG   ""

debug handling

In theory, apt should not care about the architecture because the translations are Architecture: all. In practice, it appears that apt is not expecting an entire repository of architecture-independent packages. Emdebian only supports prebuilt target packages for arm (not armel or armeb) so apt will only find cache data if set to look for arm packages. Hence, if langupdate is being built on a different architecture, the langupdate cache needs to force apt to look for arm packages or the langupdate cache is likely to be empty.

This only arises during development and debugging. Once built for arm, langupdate does not need to pass the Apt::Architecture option.

FOREIGN is defined with a test in ./configure - update the test there if Emdebian gains support for other prebuilt target package architectures.

#define DPKG_II   "^Package: (.*)$"

#define GNU_WARRANTY

Value:

"Copyright (C) 2007 Neil Williams <codehelp@debian.org>\n" \
"This is free software; see the source for copying conditions.  There is NO\n" \
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"

#define GREX_EMPTY   GRegexMatchFlags(0)


Function Documentation

static gboolean append_sourceslist ( const gchar *  lang  )  [static]

write the sources list

00207 {
00208     FILE * fout = NULL;
00209 
00210     fout = fopen (sourceslist, "a");
00211     if (!fout)
00212     {
00213         g_warning (_("failed to create sources list: '%s'"), sourceslist);
00214         return false;
00215     }
00216     fprintf (fout, "deb http://buildd.emdebian.org/locale/ %s %s\n", suite_codename, lang);
00217     fclose (fout);
00218     return true;

static void lu_check_allowed_suites ( gchar *  user_suite  )  [static]

checks the user specified suite against the allowed list

Sets the user specified suite if supported, otherwise sets the langupdate default (unstable).

00229 {
00230     gchar * allowed, * match;
00231 
00232     match = NULL;
00233     /* Translators: used with the --suite option to confirm
00234     the suite codename entered by the user. */
00235     g_print ("%s: %s %s\n", PACKAGE, _("checking Emdebian support for: "), user_suite);
00236     allowed = g_strdup("unstable sid testing lenny stable");
00237     match = g_strrstr_len (allowed, strlen(allowed), user_suite);
00238     if (match)
00239         suite_codename = g_strdup(user_suite);
00240     else
00241     {
00242         g_warning (_("Suite '%s' is not supported by Emdebian."), user_suite);
00243         g_print ("\n%s: %s", PACKAGE, _("Using the default suite: unstable.\n"));
00244         suite_codename = g_strdup("unstable");
00245     }   g_free (user_suite);
00246     g_free (allowed);

gchar* lu_get_aptstring ( void   ) 

Collate the various apt options into a string.

return the configuration options for apt

Depending on various settings, the apt configuration list needs to be adjusted so it cannot be completely defined as a macro. This function adds the customisations, creates a newly allocated string and returns it. The caller is responsible for freeing the string.

Also sets the langupdate cache data to the same configuration if this has not been done already.

Returns:
newly allocated string of apt options or NULL on error.
00120 {
00121     return g_strconcat (DEBUG, APTCONFIGSTR, "-o Dir::State=",
00122         suite_codename, " -o Dir::Cache=", suite_codename, NULL);

gint main ( gint  argc,
gchar *  argv[] 
)

Read the apt-cache to know what is available. then compare dpkg_list with apt_list.

00254 {
00255     GError * em_gerr;
00256     gchar * dpkg, *code;
00257     const gchar * const * locale_v;
00258     GList * dpkg_list, * p, *choices, *locales;
00259     GHashTable * tbl;
00260     gchar ** status_list;
00261     guint mcount, c, l;
00262     gint hdl;
00263     GOptionContext *context;
00264 
00265     em_gerr = NULL;
00266     locales = dpkg_list = choices = NULL;
00267     tbl = g_hash_table_new (g_str_hash, g_str_equal);
00268     l = mcount = 0;
00269 #ifdef ENABLE_NLS
00270     setlocale (LC_ALL, "");
00271     bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR);
00272     bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
00273     textdomain (GETTEXT_PACKAGE);
00274 #endif
00275     context = g_option_context_new (_("- updates language support for emdebian"));
00276     g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
00277     g_option_context_parse (context, &argc, &argv, &em_gerr);
00278     if (show_version)
00279     {
00280         g_print ("%s (%s).\n", PACKAGE, VERSION);
00281         g_print ("%s", GNU_WARRANTY);
00282         exit (0);
00283     }
00284     if (!user_suite)
00285         suite_codename = g_strdup("unstable");
00286     else
00287         lu_check_allowed_suites(user_suite);
00288 #ifdef FOREIGN
00289     g_print ("%s: %s - %s\n", PACKAGE, HOST_OS, _("Foreign architecture, forcing a dry run."));
00290 #else
00291     if (dry_run)
00292         g_print ("%s: %s\n", PACKAGE, _("Dry run, just showing cache data for installable packages."));
00293 #endif
00294     locale_v = g_get_language_names ();
00295     if (!locale_v)
00296         return 0;
00297     while (strcmp (locale_v[l], "C") != 0)
00298     {
00299         code = g_ascii_strdown (locale_v[l], -1);
00300         if (!g_strrstr(code, "."))
00301         {
00302             gchar * root;
00303             GRegex * patt;
00304 
00305             em_gerr = NULL;
00306             patt = g_regex_new ("_", G_REGEX_OPTIMIZE, GREX_EMPTY, &em_gerr);
00307             if (em_gerr)
00308             {
00309                 g_warning (em_gerr->message);
00310                 g_clear_error (&em_gerr);
00311             }
00312             em_gerr = NULL;
00313             code = g_regex_replace (patt, code, -1, 0, "-", GREX_EMPTY, &em_gerr);
00314             if (em_gerr)
00315             {
00316                 g_warning (em_gerr->message);
00317                 g_clear_error (&em_gerr);
00318             }
00319             locales = g_list_append (locales, code);
00320             // need to get the root lang only here
00321             root = g_strndup(code, 2);
00322             if (!g_hash_table_lookup(tbl, root))
00323             {
00324                 if (!append_sourceslist (root)) 
00325                     return -1;
00326                 g_hash_table_insert (tbl, root, code);
00327             }
00328         }
00329         else
00330             g_free (code);
00331         l++;
00332     }
00333     g_return_val_if_fail (apt_init (sourceslist, suite_codename, verbose), -1);
00334     if (!g_file_get_contents (DPKG_FILE, &dpkg, NULL, &em_gerr))
00335     {
00336         g_critical (em_gerr->message);
00337         g_message (_("Unable to open the dpkg status file."));
00338         g_clear_error (&em_gerr);
00339         return -1;
00340     }
00341     status_list = g_strsplit (dpkg, "\n", -1);
00342 
00343     for (mcount = 0; mcount <= g_strv_length(status_list); mcount++)
00344     {
00345         gchar * pkg;
00346         if (!status_list[mcount])
00347             continue;
00348         pkg = parse_installed (status_list[mcount], (gchar*)locales->data);
00349         if (pkg)
00350             dpkg_list = g_list_prepend (dpkg_list, pkg);
00351     }
00352     for (p = dpkg_list; p != NULL; p = p->next)
00353     {
00354         gchar * pkg = (gchar*)p->data;
00355         if (aptcache_lookup (pkg))
00356             choices = g_list_prepend (choices, pkg);
00357     }
00358     c = g_list_length (choices);
00359     choices = g_list_sort (choices, check_pkg_name);
00360     c = g_list_length (choices);
00361     fprintf (stdout, ngettext("%d package can be installed\n\n",
00362         "%d packages can be installed\n\n", c), c);
00363     g_list_foreach (choices, output, NULL);
00364     g_hash_table_destroy (tbl);
00365     g_list_free (locales);
00366     g_list_free (choices);
00367     g_unlink ("/var/lib/langupdate/unstable/lists/lock");
00368     g_unlink ("/var/lib/langupdate/lock");
00369 #ifndef FOREIGN
00370     g_unlink (sourceslist);
00371 #endif
00372     return 0;

static void output ( gpointer  value,
gpointer  data 
) [static]

install each available package name

Todo:
run all install operations in one call.

Todo:
rationalise error output.
00131 {
00132     gchar * name, * hdl, * hdl_err, * config_str, * cmd, * func;
00133     gint err_status = 0;
00134     GError * gerr = NULL;
00135 
00136     c++;
00137     config_str = lu_get_aptstring();
00138     if (dry_run)
00139     {
00140         cmd = g_strdup("apt-cache");
00141         func = g_strdup("show");
00142     }
00143     else
00144     {
00145         cmd = g_strdup ("apt-get");
00146         func = g_strdup("install -y");
00147     }
00148     if ((value) && (strcmp ((gchar*)value, "")))
00149         name = g_strdup_printf ( "%s %s %s %s", cmd, config_str, func, (gchar*)value);
00150     g_spawn_command_line_sync (name, &hdl, &hdl_err, &err_status, &gerr);
00151     if (gerr) 
00152     {
00154         fprintf (stdout, _("apt returned an error:%s\n"), hdl_err);
00155         fprintf (stdout, _("status code:%d\n"), err_status);
00156         fprintf (stdout, "%s\n", gerr->message);
00157         return;
00158     }
00159     if (dry_run)
00160         fprintf (stdout, "%s\n", hdl);

static gchar* parse_installed ( const gchar *  pkg,
const gchar *  locale 
) [static]

Parses list of all installed packages.

Store a list of existing target packages by skipping those already installed.

00170 {
00171     GList * match;
00172     gchar ** pos;
00173     gchar * r, *target, * lang;
00174 
00175     pos = g_strsplit (pkg, ": ", -1);
00176     if (!pos[0])
00177         return NULL;
00178     r = NULL;
00179     match = NULL;
00180     lang = g_strconcat ("-", LOCALE_SUFFIX, "-", locale, NULL);
00181     if (0 == strcmp (pos[0], PACKAGE_CHK))
00182     {
00183         r = g_strdup (pos[1]);
00184         if (g_str_has_suffix (r, lang))
00185         {
00186             installed = g_list_prepend (installed, r);
00187             /* in case the target occurs later in the list */
00188             targets = g_list_remove (targets, r);
00189             return NULL;
00190         }
00191         /* generate a target name. */
00192         target = g_strconcat (r, lang, NULL);
00193         match = g_list_find_custom (installed, target, check_pkg_name);
00194         if (g_list_length (match) != 0)
00195             targets = g_list_prepend (targets, target);
00196         g_strfreev (pos);
00197         g_free (r);
00198         return target;
00199     }
00200     g_free (lang);
00201     return NULL;


Variable Documentation

guint c = 0 [static]

gboolean dry_run = false [static]

GOptionEntry entries[] [static]

Initial value:

 
{
    { "dry-run", 'n', 0, G_OPTION_ARG_NONE, &dry_run, _("Only show the cache data, do not install"), 0 },
    { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, _("Be verbose"), NULL },
    { "suite", 0, 0, G_OPTION_ARG_STRING, &user_suite, 
        _("Specify the apt suite name [default unstable]"), _("codename") },
    { "version", 0, 0, G_OPTION_ARG_NONE, &show_version, _("Show version information "
        "and exit."), 0},
    { NULL }
}

GList* installed = NULL [static]

gboolean show_version = false [static]

const gchar* sourceslist = "/var/lib/langupdate/sources.list" [static]

gchar* suite_codename = NULL [static]

GList* targets = NULL [static]

gchar* user_suite = NULL [static]

gboolean verbose = false [static]


Generated on Sun Dec 2 19:03:19 2007 for langupdate by  doxygen 1.5.4