root/trunk/third/nautilus/components/services/install/lib/eazel-install-logic.c @ 15547

Revision 15547, 66.7 KB (checked in by ghudson, 9 years ago)

This commit was generated by cvs2svn to compensate for changes in r15546,
which included commits to RCS files with non-trunk default branches.

Line 
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2/*
3 * Copyright (C) 2000 Eazel, Inc
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 *
20 * Authors: Eskil Heyn Olsen  <eskil@eazel.com>
21 */
22
23#include "eazel-install-logic.h"
24#include "eazel-install-xml-package-list.h"
25#include "eazel-install-public.h"
26#include "eazel-install-private.h"
27#include "eazel-install-rpm-glue.h"
28#include "eazel-install-query.h"
29#include "eazel-install-logic2.h"
30
31/* We use rpmvercmp to compare versions... */
32#include <rpm/rpmlib.h>
33#include <rpm/misc.h>
34
35#ifndef EAZEL_INSTALL_NO_CORBA
36#include <libtrilobite/libtrilobite.h>
37#else
38#include <libtrilobite/libtrilobite-service.h>
39#include <libtrilobite/trilobite-root-helper.h>
40#endif
41
42#include <libtrilobite/trilobite-core-utils.h>
43#include <string.h>
44#include <time.h>
45
46#include <errno.h>
47#include <sys/stat.h>
48#include <sys/types.h>
49#include <fcntl.h>
50#include <unistd.h>
51#include <ctype.h>
52#ifdef EAZEL_INSTALL_SLIM
53#include <sys/wait.h>
54#endif
55
56static gboolean eazel_install_do_install_packages (EazelInstall *service,
57                                                   GList* packages);
58
59static int eazel_install_start_transaction (EazelInstall *service, 
60                                            GList* packages);
61
62static gboolean eazel_install_ensure_deps (EazelInstall *service, 
63                                           GList **filenames, 
64                                           GList **fails);
65
66static void eazel_uninstall_globber (EazelInstall *service,
67                                     GList **packages,
68                                     GList **failed);
69
70static gboolean eazel_install_download_packages (EazelInstall *service,
71                                                 gboolean toplevel,
72                                                 GList **packages,
73                                                 GList **failed_packages);
74
75static gboolean  eazel_install_check_for_file_conflicts (EazelInstall *service,
76                                                         PackageData *pack,
77                                                         GList **breaks,
78                                                         GList **requires);
79
80static void eazel_install_prune_packages (EazelInstall *service, 
81                                          PackageData *pack, 
82                                          ...);
83/*
84   Checks for pre-existance of all the packages
85 */
86static void
87eazel_install_pre_install_packages (EazelInstall *service,
88                                    GList **packages) 
89{
90        GList *iterator;
91        GList *failed_packages = NULL;
92
93        for (iterator = *packages; iterator; iterator = g_list_next (iterator)) {
94                PackageData *pack = (PackageData*)iterator->data;
95                EazelInstallStatus inst_status;
96                gboolean skip = FALSE;
97               
98                inst_status = eazel_install_check_existing_packages (service, pack);
99
100                /* If in force mode, install it under all circumstances.
101                   if not, only install if not already installed in same
102                   version or up/downgrade is set */
103                if (eazel_install_get_force (service) ||
104                    (eazel_install_get_downgrade (service) && inst_status == EAZEL_INSTALL_STATUS_DOWNGRADES) ||
105                    (eazel_install_get_update (service) && inst_status == EAZEL_INSTALL_STATUS_UPGRADES) ||
106                    inst_status == EAZEL_INSTALL_STATUS_NEW_PACKAGE) {
107                        skip = FALSE;
108                } else {
109                        skip = TRUE;
110                }
111               
112                if (skip) {
113                        trilobite_debug ("Skipping %s...", pack->name);
114#if 0
115                        /* Nuke the modifies list again, since we don't want to see them */
116                        g_list_foreach (pack->modifies,
117                                        (GFunc)packagedata_destroy,
118                                        GINT_TO_POINTER (TRUE));
119                        g_list_free (pack->modifies);
120                        pack->modifies = NULL;
121#endif
122
123                        /* Add it to the list of packages to nuke at the end
124                           of this function */
125                        failed_packages = g_list_prepend (failed_packages, pack);
126                }
127        }
128       
129        for (iterator = failed_packages; iterator; iterator=g_list_next (iterator)) {
130                eazel_install_prune_packages (service, 
131                                              (PackageData*)iterator->data,
132                                              packages, NULL);
133        }
134        g_list_free (failed_packages);
135}
136
137EazelInstallStatus
138ei_install_packages (EazelInstall *service, GList *categories) {
139        EazelInstallStatus result;
140
141        if (categories == NULL) {
142                trilobite_debug (_("Reading the install package list %s"), eazel_install_get_package_list (service));
143                categories = parse_local_xml_package_list (eazel_install_get_package_list (service), NULL, NULL);
144        }
145
146        result = EAZEL_INSTALL_NOTHING;
147        if (categories != NULL) {
148                /* First, collect all packages in one list */
149                GList *packages = categorylist_flatten_to_packagelist (categories);
150
151                /* Now download all the packages */
152                if (eazel_install_download_packages (service, TRUE, &packages, NULL)) {
153
154                        /* check for packages that are already installed */
155                        eazel_install_pre_install_packages (service, &packages);
156
157                        /* Files downloaded, now install */
158                        if (eazel_install_do_install_packages (service, packages)) {
159                                result |= EAZEL_INSTALL_INSTALL_OK;
160                        }
161                }
162        }
163       
164        return result;
165} /* end install_new_packages */
166
167/*
168  Download all the packages and keep doing that by recursively
169  calling eazel_install_download_packages with package->soft_depends
170 */
171static gboolean
172eazel_install_download_packages (EazelInstall *service,
173                                 gboolean toplevel,
174                                 GList **packages,
175                                 GList **failed_packages)
176{
177        GList *iterator;
178        gboolean result = TRUE;
179        GList *remove_list = NULL;
180
181        g_assert (packages);
182        g_assert (*packages);
183
184        for (iterator = *packages; (iterator != NULL) && result; iterator = g_list_next (iterator)) {
185                PackageData* package = (PackageData*)iterator->data;
186                gboolean fetch_package;
187               
188                fetch_package = TRUE;
189
190                trilobite_debug ("init for %s (%s/%s)", package->name, package->version ? package->version : "NO VERSION",
191                                toplevel?"TRUE":"FALSE");
192                /* if filename in the package is set, but the file
193                   does not exist, get it anyway */
194                if (package->filename) {
195                        trilobite_debug ("Filename set, and file exists = %d", 
196                                   g_file_test (package->filename, G_FILE_TEST_ISFILE));
197                        if (g_file_test (package->filename, G_FILE_TEST_ISFILE)) {
198                                /* Don't fetch, but load rpm header and return
199                                   ok */
200                                fetch_package = FALSE; 
201                                result = TRUE;
202                                package = eazel_package_system_load_package (service->private->package_system,
203                                                                             package, 
204                                                                             package->filename,
205                                                                             PACKAGE_FILL_NO_DIRS_IN_PROVIDES);
206                        } else {
207                                /* The file didn't exist, remove the
208                                   leading path and set the filename, plus
209                                   toggle the fetch_package to TRUE */
210                                g_free (package->filename);
211                                package->filename = g_strdup (g_basename (package->filename));
212                        }
213                } else if (!eazel_install_get_force (service) && package->version) {
214                        /* If the package has a version set, check that we don't already have
215                           the same or newer installed. This is almost the same check as
216                           in eazel_install_pre_install_package. The reason for two checks is
217                           - first check before download (if possible)
218                           - after download, when we for sure have access to the version, check again
219                           - we do this before do_dependency_check to avoid downloaded soft_deps.
220                        */
221                        EazelInstallStatus inst_status;
222
223                        inst_status = eazel_install_check_existing_packages (service, package);
224                        if (eazel_install_get_downgrade (service) && inst_status == EAZEL_INSTALL_STATUS_DOWNGRADES) {
225                                trilobite_debug (_("Will download %s"), package->name);
226                                /* must download... */
227                        } else if (inst_status == EAZEL_INSTALL_STATUS_QUO ||
228                                   inst_status == EAZEL_INSTALL_STATUS_DOWNGRADES) {
229                                /* Nuke the modifies list again, since we don't want to see them */
230                                g_list_foreach (package->modifies, 
231                                                (GFunc)packagedata_destroy, 
232                                                GINT_TO_POINTER (TRUE));
233                                g_list_free (package->modifies);
234                                package->modifies = NULL;
235                                /* don't fecth the package */
236                                fetch_package = FALSE;
237                                /* Add it to the list of packages to nuke at the end
238                                   of this function */
239                                remove_list = g_list_prepend (remove_list, package);
240                                trilobite_debug (_("%s already installed"), package->name);
241                        }
242                } 
243
244                if (fetch_package) {
245                        result = eazel_install_fetch_package (service, package);
246
247                        if (!result) {
248                                package->status = PACKAGE_CANNOT_OPEN;
249                                remove_list = g_list_prepend (remove_list, package);
250                        } else {
251#if 0
252                                /* If downloaded package has soft_deps,
253                                   fetch them by a recursive call */
254                                if (package->soft_depends) {
255                                        result = eazel_install_download_packages (service,
256                                                                                  FALSE,
257                                                                                  &package->soft_depends,
258                                                                                  NULL);
259                                }
260#endif
261                        }
262                }
263
264                if (result) {
265                        package->toplevel = toplevel;
266                        if (package->source_package) {
267                                package->status = PACKAGE_SOURCE_NOT_SUPPORTED;
268                                remove_list = g_list_prepend (remove_list, package);
269                        }
270                        if (strlen ("debug")) {
271                                char *tmp = packagedata_dump (package, TRUE);
272                                fprintf (stderr, "%s", tmp);
273                                g_free (tmp);
274                        }
275                }
276        }
277
278        for (iterator = remove_list; iterator; iterator = g_list_next (iterator)) {
279                PackageData *package = (PackageData*)(iterator->data);
280                eazel_install_prune_packages (service, package, packages, NULL);
281        }
282
283        if (failed_packages) {
284                (*failed_packages) = remove_list;
285        }
286
287        return result;
288}
289
290/*
291  This function checks all files in pack->provides, and
292  checks if another already installed package owns this file.
293  returns FALSE is there are no conflicts, and TRUE if there
294  are.
295
296  If there are conflicts because of a related package,
297  this package is added to *requires.
298 */
299static gboolean
300eazel_install_check_for_file_conflicts (EazelInstall *service,
301                                        PackageData *pack,
302                                        GList **breaks,
303                                        GList **requires)
304{
305        GList *owners;
306        GList *iterator;
307        /* Set optimism to high */
308        gboolean result = FALSE;
309       
310        g_assert (service);
311        g_assert (pack);
312        g_assert (requires);
313        g_assert (*requires == NULL);
314
315        trilobite_debug ("Checking file conflicts for %s", pack->name);
316
317        for (iterator = pack->provides; iterator; glist_step (iterator)) {
318                char *filename = (char*)iterator->data;         
319
320                /* many packages will supply some dirs, eg /usr/share/locale/../LC_MESSAGES
321                   dirs, so don't check those
322
323                   eazel-install-types
324                   (packagedata_fill_from_rpm_header) now does not add
325                   these. This is more safe, as checking the file
326                   could still cause a conflict, if the file was not
327                   on the system but two dirs had the same dir
328
329                if (g_file_test (filename, G_FILE_TEST_ISDIR)) {
330                        continue;
331                } */
332
333                owners = eazel_package_system_query (service->private->package_system,
334                                                     service->private->cur_root,
335                                                     filename,
336                                                     EAZEL_PACKAGE_SYSTEM_QUERY_OWNS,
337                                                     PACKAGE_FILL_NO_DIRS_IN_PROVIDES);
338                packagedata_list_prune (&owners, pack->modifies, TRUE, TRUE);
339               
340                if (g_list_length (owners) > 1) {
341                        GList *pit;
342                        /* FIXME bugzilla.eazel.com 3511:
343                           More than one packages owns this file,
344                           this cannot happen (or should not at least)
345                        */
346                        trilobite_debug ("***************************************************");
347                        trilobite_debug ("More than one package owns the file %s", filename);
348                        trilobite_debug ("This is filed as bug 2959");
349                        trilobite_debug ("Try rpm --rebuilddb");
350                        for (pit = owners; pit; pit = g_list_next (pit)) {
351                                char *tmp;
352                                PackageData *owner = (PackageData*)(pit->data);
353                                tmp = packagedata_get_readable_name (owner);
354                                trilobite_debug ("a owner is %s", tmp);
355                                g_free (tmp);
356                        }
357                        trilobite_debug ("halting...");
358                        g_assert_not_reached ();
359                } else if (g_list_length (owners) == 1) {
360                        PackageData *owner = (PackageData*)owners->data;
361                       
362                        /* If the package owner is already in the breaks list for the package,
363                           or in the *requires, continue  */
364                        if (g_list_find_custom (*breaks, owner->name, 
365                                                (GCompareFunc)eazel_install_package_name_compare) ||
366                            g_list_find_custom (*requires, owner->name, 
367                                                (GCompareFunc)eazel_install_package_name_compare)) {
368                                /* trilobite_debug ("already breaking %s", owner->name); */
369                                packagedata_destroy (owner, TRUE);
370                                owner = NULL;
371                                continue;
372                        }
373
374                        if (strcmp (pack->name, owner->name)) {
375                                trilobite_debug ("file %s from package %s conflicts with file from package %s", 
376                                                 filename, pack->name, owner->name);
377
378                                result = TRUE;
379                                if (eazel_install_check_if_related_package (service, pack, owner)) {
380                                        trilobite_debug ("Package %s may be related to %s", 
381                                                         owner->name, pack->name);
382                                        g_free (owner->version);
383                                        owner->version = g_strdup (pack->version);
384                                        (*requires) = g_list_prepend (*requires, owner);
385                                } else {
386                                        owner->status = PACKAGE_FILE_CONFLICT;
387                                        (*breaks) = g_list_prepend (*breaks, owner);
388                                }
389                               
390                        } else {
391                                /* else it's the same package and it's okay */
392                                /* so FREE IT YOU SICK MONKEY! */
393                                packagedata_destroy (owner, TRUE);
394                        }
395                }
396                /* free the _simple_query result list */
397                g_list_free (owners);
398
399#ifdef EAZEL_INSTALL_SLIM
400                /* In the slim, we need to enter the g_main_loop during file check */           
401                g_main_iteration (FALSE);
402#endif
403
404        }
405        return result;
406}
407
408static gboolean
409eazel_install_do_install_packages (EazelInstall *service,
410                                  GList* packages) 
411{
412        gboolean rv = TRUE;
413        GList* failedfiles = NULL;
414
415        if (packages) {
416                rv = FALSE;
417                eazel_install_ensure_deps (service, &packages, &failedfiles);
418                if (g_list_length (packages)) {
419                        if (eazel_install_start_transaction (service, packages) == 0) {
420                                rv = TRUE;
421                        }                       
422                        g_list_free (packages);
423                }
424        }
425
426        return rv;
427} /* end install_packages */
428
429static EazelInstallStatus
430uninstall_all_packages (EazelInstall *service,
431                        GList *categories) 
432{
433        EazelInstallStatus result = EAZEL_INSTALL_UNINSTALL_OK;
434
435        while (categories) {
436                CategoryData* cat = categories->data;
437                GList *failed;
438
439                trilobite_debug (_("Category = %s"), cat->name);
440
441                failed = NULL;
442                eazel_uninstall_globber (service, &cat->packages, &failed);
443
444                if (eazel_install_start_transaction (service, cat->packages) != 0) {
445                        result = EAZEL_INSTALL_NOTHING;
446                }
447
448                categories = g_list_next (categories);
449        }
450        return result;
451}
452
453EazelInstallStatus
454ei_uninstall_packages (EazelInstall *service,
455                    GList* categories) 
456{
457        EazelInstallStatus result = EAZEL_INSTALL_NOTHING;
458       
459        result |= uninstall_all_packages (service, categories);
460
461        return result;
462
463} /* end install_new_packages */
464
465
466static GList *
467ei_get_packages_with_mod_flag (GList *packages,
468                               PackageModification mod) 
469{
470        GList *it;
471        GList *res;
472       
473        res = NULL;
474        for (it = packages; it; it = g_list_next (it)) {
475                PackageData *pack;
476                pack = (PackageData*)it->data;
477                if (pack->modify_status == mod) {
478                        res = g_list_prepend (res, pack);
479                }
480                if (pack->soft_depends) {
481                        res = g_list_concat (res, 
482                                             ei_get_packages_with_mod_flag (pack->soft_depends, mod));
483                }
484                if (pack->modifies) {
485                        res = g_list_concat (res, 
486                                             ei_get_packages_with_mod_flag (pack->modifies, mod));
487                }
488        }
489        return res;
490}
491
492/* Function to prune the uninstall list for elements marked as downgrade */
493static void
494ei_check_uninst_vs_downgrade (GList **inst, 
495                              GList **down) 
496{
497        GList *it;
498        GList *remove;
499       
500        remove = NULL;
501        for (it = *inst; it; it = g_list_next (it)) {
502                GList *entry;
503                PackageData *pack;
504
505                pack = (PackageData*)it->data;
506                entry = g_list_find_custom (*down, pack->name, (GCompareFunc)eazel_install_package_name_compare);
507                if (entry != NULL) {
508                        remove = g_list_prepend (remove, it->data);
509                }
510        }
511
512        for (it = remove; it; it = g_list_next (it)) {
513                (*inst) = g_list_remove (*inst, it->data);
514        }
515}
516
517static void hest (PackageData *pack, char *str) {
518        trilobite_debug ("Must %s %s", str, pack->name);
519}
520
521EazelInstallStatus
522ei_revert_transaction (EazelInstall *service, 
523                    GList *packages)
524{
525        GList *uninst, *inst, *upgrade, *downgrade;
526        CategoryData *cat;
527        GList *categories;
528        EazelInstallStatus result = EAZEL_INSTALL_NOTHING;
529
530        uninst = ei_get_packages_with_mod_flag (packages, PACKAGE_MOD_INSTALLED);
531        inst = ei_get_packages_with_mod_flag (packages, PACKAGE_MOD_UNINSTALLED);
532        upgrade = ei_get_packages_with_mod_flag (packages, PACKAGE_MOD_DOWNGRADED);
533        downgrade = ei_get_packages_with_mod_flag (packages, PACKAGE_MOD_UPGRADED);
534
535        ei_check_uninst_vs_downgrade (&uninst, &downgrade);
536
537        g_list_foreach (uninst, (GFunc)hest, "uninstall");
538        g_list_foreach (inst, (GFunc)hest, "install");
539        g_list_foreach (downgrade, (GFunc)hest, "downgrade");
540        g_list_foreach (upgrade, (GFunc)hest, "upgrade");
541
542        cat = categorydata_new ();
543        categories = g_list_prepend (NULL, cat);
544
545        if (uninst) {
546                eazel_install_set_uninstall (service, TRUE);
547                eazel_install_set_downgrade (service, FALSE);
548                eazel_install_set_update (service, FALSE);
549                cat->packages = uninst;
550                result |= ei_uninstall_packages (service, categories);
551        }
552        if (inst) {
553                eazel_install_set_uninstall (service, FALSE);
554                eazel_install_set_downgrade (service, FALSE);
555                eazel_install_set_update (service, FALSE);
556                cat->packages = inst;
557                result |= ei_install_packages (service, categories);
558        }
559        if (downgrade) {
560                eazel_install_set_uninstall (service, FALSE);
561                eazel_install_set_downgrade (service, TRUE);
562                eazel_install_set_update (service, FALSE);
563                cat->packages = downgrade;
564                result |= ei_install_packages (service, categories);
565        }
566        if (upgrade) {
567                eazel_install_set_uninstall (service, FALSE);
568                eazel_install_set_downgrade (service, TRUE);
569                eazel_install_set_update (service, TRUE);
570                cat->packages = upgrade;
571                result |= ei_install_packages (service, categories);
572                g_list_foreach (upgrade, (GFunc)packagedata_destroy, GINT_TO_POINTER (TRUE));
573        }
574
575        return result;
576}
577
578
579void
580eazel_install_do_transaction_add_to_transaction (EazelInstall *service,
581                                                 PackageData *pack)
582{
583        service->private->transaction = g_list_prepend (service->private->transaction,
584                                                        pack);
585}
586
587static void
588eazel_install_do_transaction_save_report_helper (xmlNodePtr node,
589                                                     GList *packages)
590{
591        GList *iterator;
592
593        for (iterator = packages; iterator; iterator = g_list_next (iterator)) {
594                PackageData *pack;
595                char *tmp;
596                pack = (PackageData*)iterator->data;
597                switch (pack->modify_status) {
598                case PACKAGE_MOD_INSTALLED:                     
599                        tmp = g_strdup_printf ("Installed %s", pack->name);
600                        xmlNewChild (node, NULL, "DESCRIPTION", tmp);
601                        g_free (tmp);
602                        break;
603                case PACKAGE_MOD_UNINSTALLED:                   
604                        tmp = g_strdup_printf ("Uninstalled %s", pack->name);
605                        xmlNewChild (node, NULL, "DESCRIPTION", tmp);
606                        g_free (tmp);
607                        break;
608                default:
609                        break;
610                }
611                if (pack->modifies) {
612                        eazel_install_do_transaction_save_report_helper (node, pack->modifies);
613                }
614        }
615}
616
617static void
618eazel_install_do_transaction_save_report (EazelInstall *service) 
619{
620        FILE *outfile;
621        xmlDocPtr doc;
622        xmlNodePtr node, root;
623        char *name = NULL;
624
625        if (eazel_install_get_transaction_dir (service) == NULL) {
626                g_warning ("Transaction directory not set, not storing transaction report");
627        }
628
629        /* Ensure the transaction dir is present */
630        if (! g_file_test (eazel_install_get_transaction_dir (service), G_FILE_TEST_ISDIR)) {
631                int retval;
632                retval = mkdir (eazel_install_get_transaction_dir (service), 0755);                   
633                if (retval < 0) {
634                        if (errno != EEXIST) {
635                                g_warning (_("Could not create transaction directory (%s)! ***\n"), 
636                                           eazel_install_get_transaction_dir (service));
637                                return;
638                        }
639                }
640        }
641
642        /* Create xml */
643        doc = xmlNewDoc ("1.0");
644        root = node = xmlNewNode (NULL, "TRANSACTION");
645        xmlDocSetRootElement (doc, node);
646
647        /* Make a unique name */
648        name = g_strdup_printf ("%s/transaction.%lu", eazel_install_get_transaction_dir (service),
649                                (unsigned long) time (NULL));
650        while (g_file_test (name, G_FILE_TEST_ISFILE)) {
651                g_free (name);
652                sleep (1);
653                name = g_strdup_printf ("%s/transaction.%lu", 
654                                        eazel_install_get_transaction_dir (service), 
655                                        (unsigned long) time (NULL));
656        }
657
658        trilobite_debug (_("Writing transaction to %s"), name);
659       
660        /* Open and save */
661        outfile = fopen (name, "w");
662        xmlAddChild (root, eazel_install_packagelist_to_xml (service->private->transaction, FALSE));
663        node = xmlAddChild (node, xmlNewNode (NULL, "DESCRIPTIONS"));
664
665        {
666                char *tmp;
667                tmp = g_strdup_printf ("%lu", (unsigned long) time (NULL));             
668                xmlNewChild (node, NULL, "DATE", tmp);
669                g_free (tmp);
670        }
671
672        eazel_install_do_transaction_save_report_helper (node, service->private->transaction);
673
674        xmlDocDump (outfile, doc);
675       
676        fclose (outfile);
677        g_free (name);
678}
679
680/*
681   This checks, that for a given set of packages, no two packages
682   contains the same file.
683   This is done by filling a hashtable with the files from
684   package->provides (which have full pathname) and link to the
685   owning package. Before adding a file to the hashtable, lookup the
686   file first. If result is non-null, problem...
687
688   Did I mention that this function leaks memory like a russian submarine?  -robey
689 */
690static gboolean
691eazel_install_do_transaction_all_files_check (EazelInstall *service,
692                                              GList **packages)
693{
694        gboolean result = TRUE;
695        GList *iterator;
696        GList *conflicts = NULL;  /* PackageRequirements. ->package is the first found package
697                                     that providing a file, ->required is the second file that
698                                     has the same file */
699        GHashTable *file_to_pack; /* maps from a filename to a packagedata struct */
700       
701        if (eazel_install_get_force (service) || 
702            eazel_install_get_ignore_file_conflicts (service) ||
703                (g_list_length (*packages) == 1 )) {           
704                trilobite_debug ("not performing file conflict check");
705                return result;
706        }
707
708        file_to_pack = g_hash_table_new (g_str_hash, g_str_equal);
709
710        /* Check all the packages */
711        for (iterator = *packages; iterator; glist_step (iterator)) {
712                PackageData *pack = (PackageData*)iterator->data;
713                GList *file_iterator;
714                int reported_yet = FALSE;
715                int other_conflicts = 0;
716
717                /* Check all files provided */
718                for (file_iterator = pack->provides; file_iterator; glist_step (file_iterator)) {
719                        char *fname = (char*)file_iterator->data;
720                        /* Lookup and check what happens... */
721                        PackageData *previous_pack = g_hash_table_lookup (file_to_pack,
722                                                                          fname);
723                        if (previous_pack) {
724                                /* Dang, fname is owned by previous_pack but pack also adds it */
725                                /* The use of reported_yet && other_conflicts is purely for
726                                   debug nicety. It ensures that only one fileconflicts pr
727                                   package is printed, whereas the alternative is eg. 200 */
728                                if (! reported_yet) {
729                                        trilobite_debug ("conflict, file %s from package %s is also in %s", 
730                                                         fname, 
731                                                         pack->name,
732                                                         previous_pack->name);
733                                        reported_yet = TRUE;
734                                } else {
735                                        other_conflicts++;
736                                }
737                                if (!g_list_find_custom (conflicts, 
738                                                         pack,
739                                                         (GCompareFunc)eazel_install_requirement_dep_compare)) {
740                                        PackageRequirement *req;
741                                       
742                                        req = packagerequirement_new (previous_pack, pack);
743                                        conflicts = g_list_prepend (conflicts, req);
744                                }
745                        } else {
746                                /* File is ok */
747                                g_hash_table_insert (file_to_pack, 
748                                                     fname,
749                                                     pack);
750                        }
751                }
752                if (other_conflicts) {
753                        trilobite_debug ("(%d other conflicts from the same package... *sigh*)", other_conflicts);
754                }
755        }
756
757        for (iterator = conflicts; iterator; glist_step (iterator)) {
758                PackageRequirement *req = (PackageRequirement*)iterator->data;
759               
760                result = FALSE;
761                /* Need to fail the package here to fully fix bug
762                   FIXME bugzilla.eazel.com 3374: */
763                trilobite_debug ("Conflict between %s and %s", req->package->name, req->required->name);
764                req->package->status = PACKAGE_FILE_CONFLICT;
765                req->required->status = PACKAGE_FILE_CONFLICT;
766                packagedata_add_pack_to_breaks (req->package, req->required);
767                eazel_install_prune_packages (service, req->package, packages, NULL);
768        }
769
770        return result;
771}
772
773
774static unsigned long
775get_total_size_of_packages (const GList *packages)
776{
777        const GList *iterator;
778        unsigned long result = 0;
779        for (iterator = packages; iterator; iterator = g_list_next (iterator)) {
780                PackageData *pack = (PackageData*)iterator->data;
781                result += pack->bytesize;
782        }
783        return result;
784}
785
786/* A GHRFunc to clean
787   out the name_to_package hash table
788*/
789static gboolean
790eazel_install_clean_name_to_package_hash (char *key,
791                                          PackageData *pack,
792                                          EazelInstall *service)
793{
794        g_free (key);
795        return TRUE;
796}
797
798gboolean eazel_install_start_signal (EazelPackageSystem *system,
799                                     EazelPackageSystemOperation op,
800                                     const PackageData *pack,
801                                     EazelInstall *service)
802{
803        service->private->infoblock[2]++;
804        switch (op) {
805        case EAZEL_PACKAGE_SYSTEM_OPERATION_INSTALL:
806                break;
807        case EAZEL_PACKAGE_SYSTEM_OPERATION_UNINSTALL:
808                eazel_install_emit_install_progress (service, 
809                                                     pack,
810                                                     service->private->infoblock[2], service->private->infoblock[3],
811                                                     0, pack->bytesize,
812                                                     service->private->infoblock[4], service->private->infoblock[5]);                               
813                break;
814        default:
815                break;
816        }
817        return TRUE;
818}
819
820gboolean eazel_install_end_signal (EazelPackageSystem *system,
821                                   EazelPackageSystemOperation op,
822                                   const PackageData *pack,
823                                   EazelInstall *service)
824{
825        switch (op) {
826        case EAZEL_PACKAGE_SYSTEM_OPERATION_INSTALL:
827        case EAZEL_PACKAGE_SYSTEM_OPERATION_UNINSTALL:
828                eazel_install_emit_install_progress (service, 
829                                                     pack,
830                                                     service->private->infoblock[2], service->private->infoblock[3],
831                                                     pack->bytesize, pack->bytesize,
832                                                     service->private->infoblock[4], service->private->infoblock[5]);                               
833                break;
834        default:
835                break;
836        }
837        return TRUE;
838}
839
840gboolean  eazel_install_progress_signal (EazelPackageSystem *system,
841                                         EazelPackageSystemOperation op,
842                                         const PackageData *pack,
843                                         unsigned long *info,
844                                         EazelInstall *service)
845{
846        service->private->infoblock[4] = info[4];
847        if ((info[0] != 0) && (info[0] != info[1])) {
848                switch (op) {
849                case EAZEL_PACKAGE_SYSTEM_OPERATION_INSTALL:
850                case EAZEL_PACKAGE_SYSTEM_OPERATION_UNINSTALL:
851                        eazel_install_emit_install_progress (service, 
852                                                             pack,
853                                                             service->private->infoblock[2], service->private->infoblock[3],
854                                                             info[0], pack->bytesize,
855                                                             info[4], info[5]);
856                        break;
857                default:
858                        break;
859                }
860        }
861        return TRUE;
862}
863
864gboolean eazel_install_failed_signal (EazelPackageSystem *system,
865                                      EazelPackageSystemOperation op,
866                                      const PackageData *pack,
867                                      EazelInstall *service)
868{
869        trilobite_debug ("*** %s failed", pack->name);
870        if (pack->toplevel) {
871                trilobite_debug ("emiting failed for %s", pack->name);
872                if (op==EAZEL_PACKAGE_SYSTEM_OPERATION_INSTALL) {
873                        eazel_install_emit_install_failed (service, pack);
874                } else if (op==EAZEL_PACKAGE_SYSTEM_OPERATION_UNINSTALL) {
875                        eazel_install_emit_uninstall_failed (service, pack);
876                }
877        }
878        return TRUE;
879}
880
881/* This begins the package transaction.
882   Return value is number of failed packages
883*/
884
885int
886eazel_install_start_transaction (EazelInstall *service,
887                                 GList* packages) 
888{
889        TrilobiteRootHelper *root_helper;
890        int res;
891        int flag = 0;
892
893        if (g_list_length (packages) == 0) {
894                return -1;
895        }
896
897        res = 0;
898
899        if (service->private->downloaded_files) {
900                /* I need to get the length here, because all_files_check can alter the list */
901                int l  = g_list_length (packages);
902                /* Unless we're force installing, check file conflicts */
903                if (eazel_install_get_force (service) == FALSE) {
904                        if(!check_md5_on_files (service, packages)) {
905                                res = l;
906                        }
907                }
908        }
909
910        if (eazel_install_get_test (service)) {
911                flag |= EAZEL_PACKAGE_SYSTEM_OPERATION_TEST;
912        }
913        if (eazel_install_get_force (service)) {
914                flag |= EAZEL_PACKAGE_SYSTEM_OPERATION_FORCE;
915        }
916        if (eazel_install_get_update (service)) {
917                flag |= EAZEL_PACKAGE_SYSTEM_OPERATION_UPGRADE;
918        }
919        if (eazel_install_get_downgrade (service)) {
920                flag |= EAZEL_PACKAGE_SYSTEM_OPERATION_DOWNGRADE;
921        }
922
923        root_helper = gtk_object_get_data (GTK_OBJECT (service), "trilobite-root-helper");
924        gtk_object_set_data (GTK_OBJECT (service->private->package_system), 
925                             "trilobite-root-helper", root_helper);     
926
927        /* Init the hack var to emit the old style progress signals */
928        service->private->infoblock [0] = 0;
929        service->private->infoblock [1] = 0;
930        service->private->infoblock [2] = 0;
931        service->private->infoblock [3] = g_list_length (packages);
932        service->private->infoblock [4] = 0;
933        service->private->infoblock [5] = get_total_size_of_packages (packages);
934
935        if (eazel_install_emit_preflight_check (service, packages)) {
936                /* this makes the primary packages appear before their dependencies.  very useful for installs
937                 * via the install-view, where only toplevel packages cause the package detail info to update.
938                 */
939                packages = g_list_reverse (packages);
940
941                if (eazel_install_get_uninstall (service)) {
942                        eazel_package_system_uninstall (service->private->package_system,
943                                                        service->private->cur_root,
944                                                        packages,
945                                                        flag);
946                } else {
947                        eazel_package_system_install (service->private->package_system,
948                                                      service->private->cur_root,
949                                                      packages,
950                                                      flag);
951                }
952
953                eazel_install_do_transaction_save_report (service);
954        }
955       
956        g_list_free (service->private->transaction);
957        service->private->transaction = NULL;
958
959        g_hash_table_foreach_remove (service->private->name_to_package_hash,
960                                     (GHRFunc)eazel_install_clean_name_to_package_hash,
961                                     service);
962
963        return res;
964} /* end start_transaction */
965
966
967/* Checks if pack depends on dep, by doing a deep tree search */
968static gboolean
969eazel_install_check_if_depends_on (PackageData *pack, 
970                                   PackageData *dep) 
971{
972        gboolean result = FALSE;
973        GList *iterator;
974
975        for (iterator = pack->soft_depends; !result && iterator; glist_step (iterator)) {
976                PackageData *nisse = (PackageData*)iterator->data;
977                if (nisse == dep) {
978                        result = TRUE;
979                } else if (eazel_install_check_if_depends_on (nisse, dep)) {
980                        /* trilobite_debug ("nope, recursing"); */
981                        result = TRUE;
982                }
983        }
984
985        return result;
986}
987
988/*
989  The helper for eazel_install_prune_packages.
990  If the package is in "pruned", it has already been marked
991  for pruning.
992  Otherwise, prune first it's softdepends, then all
993  packages that depend on it.
994 */
995static void
996eazel_install_prune_packages_helper (EazelInstall *service, 
997                                     GList **packages,
998                                     GList **pruned,
999                                     PackageData *pack)
1000{
1001        GList *iterator;
1002        char *tmp;
1003
1004        g_return_if_fail (pack!=NULL);
1005        /* If already pruned, abort */
1006        if (g_list_find (*pruned, pack) || pack->name==NULL) {
1007                return;
1008        }
1009        tmp = packagedata_get_readable_name (pack);
1010        trilobite_debug (_("Removing package %s (0x%p) %s"), 
1011                         tmp,
1012                         pack,
1013                         pack->toplevel ? "(emit fail)" :"()");
1014        g_free (tmp);
1015        if (pack->toplevel) {
1016                /* We only emit signal for the toplevel packages,
1017                   and only delete them. They _destroy function destroys
1018                   the entire dep tree */
1019                eazel_install_emit_install_failed (service, pack);
1020        }
1021        /* Add to list of pruned packages */
1022        (*pruned) = g_list_prepend (*pruned, pack);
1023
1024        /* Prune all it's soft_deps */
1025        for (iterator = pack->soft_depends; iterator; iterator = g_list_next (iterator)) {
1026                PackageData *sub;
1027                sub = (PackageData*)iterator->data;
1028                eazel_install_prune_packages_helper (service, packages, pruned, sub);
1029        }
1030       
1031        /* For all packages in "packages", check if they depend on this */
1032        for (iterator = *packages; iterator; iterator = g_list_next (iterator)) {
1033                PackageData *super;
1034               
1035                super = (PackageData*)iterator->data;
1036                /* FIXME bugzilla.eazel.com 3542:
1037                   This is the cause of 3542.
1038                   In this specific case, gnome-print is removed from the toplevel and from
1039                   1st sublevel of soft_deps.
1040                   The problem is, that this g_list_find only looks down one level, and does'nt
1041                   search the entire tree, duh.
1042                   I need a find_custom call that does this the right way */
1043                if (eazel_install_check_if_depends_on (super, pack)) {                 
1044                        eazel_install_prune_packages_helper (service, packages, pruned, super);
1045                }
1046        }
1047}
1048
1049/*
1050  Used to remove a package "pack" and all
1051  packages in "packages" that depends
1052  on "pack".
1053 
1054  To do this, we need the _helper, which gathers
1055  the stripped files into "pruned". That way, we
1056  can safely traverse without altering
1057  the lists during the for loops (as g_list_remove
1058  will fuck up the for loop).
1059
1060  This may end in a recursive loop if
1061  the ->soft_depends points to something
1062  upwards in the dep tree (circular dependency)
1063
1064  First it calls prune_helper for all the given packages,
1065  at each iteration it removes the pruned (from list "pruned")
1066  packages.
1067
1068  Finally it deallocates all the pruned packages.
1069 
1070*/
1071
1072static void
1073eazel_install_prune_packages (EazelInstall *service, 
1074                              PackageData *pack, 
1075                              ...)
1076{
1077        va_list ap;
1078        GList *pruned;
1079        GList *iterator;
1080        GList **packages;
1081
1082        g_return_if_fail (pack!=NULL);
1083
1084        va_start (ap, pack);
1085       
1086        pruned = NULL;
1087        while ( (packages = va_arg (ap, GList **)) != NULL) {
1088                eazel_install_prune_packages_helper (service,
1089                                                     packages,
1090                                                     &pruned,
1091                                                     pack);
1092                for (iterator = pruned; iterator; iterator = g_list_next (iterator)) {
1093                        PackageData *pack = (PackageData*)iterator->data;
1094                        /* trilobite_debug ("%s pruned", pack->name); */
1095                        (*packages) = g_list_remove (*packages, pack);
1096                };
1097        } 
1098       
1099        /* Note, don't destroy, all packages are destroyed when the
1100           categories are destroyed
1101        for (iterator = pruned; iterator; iterator = g_list_next (iterator)) {
1102                PackageData *pack;
1103                pack = (PackageData*)iterator->data;
1104                packagedata_destroy (pack, TRUE);
1105        };
1106        */
1107
1108        g_list_free (pruned);
1109
1110        va_end (ap);
1111}
1112
1113static void
1114eazel_install_add_to_extras_foreach (char *key, GList *list, GList **extrapackages)
1115{
1116        GList *iterator;
1117        PackageData *dep;
1118        for (iterator = list; iterator; iterator = g_list_next (iterator)) {
1119                dep = (PackageData*)iterator->data;
1120                (*extrapackages) =  g_list_prepend (*extrapackages, dep);               
1121        }
1122        g_list_free (list);
1123}
1124
1125
1126/*
1127  This function tests wheter "package" and "dep"
1128  seems to be related in some way.
1129  This is done by checking the package->modifies list for
1130  elements that have same version as dep->version.
1131  I then compare these elements against dep->name,
1132  and if one matches the x-y-z vs dep->name=x-y scheme,
1133  I declare that "package" and "dep" are related
1134*/
1135gboolean
1136eazel_install_check_if_related_package (EazelInstall *service,
1137                                        PackageData *package,
1138                                        PackageData *dep)
1139{
1140        /* Pessimisn mode = HIGH */
1141        gboolean result = FALSE;
1142        GList *potiental_mates;
1143        GList *iterator;
1144        char **dep_name_elements;
1145       
1146        dep_name_elements = g_strsplit (dep->name, "-", 80);
1147
1148        /* First check, if package modifies a package with the same version
1149           number as dep->version */
1150        potiental_mates = g_list_find_custom (package->modifies, 
1151                                              dep->version, 
1152                                              (GCompareFunc)eazel_install_package_version_compare);
1153        for (iterator = potiental_mates; iterator; glist_step (iterator)) {
1154                PackageData *modpack = (PackageData*)iterator->data;
1155               
1156                if ((modpack->modify_status == PACKAGE_MOD_UPGRADED) ||
1157                    (modpack->modify_status == PACKAGE_MOD_DOWNGRADED)) {                       
1158                        char **mod_name_elements;
1159                        char *dep_name_iterator;
1160                        char *mod_name_iterator;
1161                        int cnt = 0;
1162
1163                        mod_name_elements = g_strsplit (modpack->name, "-", 80);
1164                       
1165                        for (cnt=0; TRUE;cnt++) {
1166                                dep_name_iterator = dep_name_elements[cnt];
1167                                mod_name_iterator = mod_name_elements[cnt];
1168#if 0
1169                                trilobite_debug ("dep name iterator = \"%s\"", dep_name_iterator);
1170                                trilobite_debug ("mod name iterator = \"%s\"", mod_name_iterator);
1171#endif
1172                                if ((dep_name_iterator==NULL) ||
1173                                    (mod_name_iterator==NULL)) {
1174                                        break;
1175                                }
1176                                if ((strlen (dep_name_iterator) == strlen (mod_name_iterator)) &&
1177                                    (strcmp (dep_name_iterator, mod_name_iterator)==0)) {
1178                                        continue;
1179                                }
1180                                break;
1181                        }
1182                        if (cnt >= 1) {
1183                                trilobite_debug ("%s-%s seems to be a child package of %s-%s, which %s-%s updates",
1184                                                 dep->name, dep->version, 
1185                                                 modpack->name, modpack->version,
1186                                                 package->name, package->version);
1187                                if (!result) {
1188                                        result = TRUE;
1189                                } else {
1190                                        trilobite_debug ("but what blows is, the previous also did!!");
1191                                        g_assert_not_reached ();
1192                                }                               
1193                        } else {
1194                                trilobite_debug ("%s-%s is not related to %s-%s", 
1195                                                 dep->name, dep->version, 
1196                                                 package->name, package->version);
1197                        }
1198                        g_strfreev (dep_name_elements);
1199                        g_strfreev (mod_name_elements);                 
1200                }
1201        }
1202        return result;
1203}
1204
1205static gboolean
1206eazel_install_fetch_dependencies (EazelInstall *service, 
1207                                  GList **packages,
1208                                  GList **extrapackages,
1209                                  GList **failedpackages,
1210                                  GList *requirements)
1211{
1212        GList *iterator;
1213        /* Contains the packages downloaded when handling the list of requirements */
1214        GList *extras_in_this_batch = NULL;
1215        GHashTable *extras;
1216        gboolean fetch_result;
1217       
1218        extras = g_hash_table_new (g_str_hash, g_str_equal);
1219        fetch_result = FALSE;
1220
1221        trilobite_debug ("%d requirements to be fetched/resolved", g_list_length (requirements));
1222        for (iterator = requirements; iterator; glist_step (iterator)) {
1223                PackageRequirement *req = (PackageRequirement*)iterator->data;
1224                PackageData *pack = req->package;
1225                PackageData *dep = req->required;
1226
1227                /* Check to see if the package system happened to file a requirement
1228                   for a package that was also failed... */
1229                if (g_list_find_custom (*failedpackages,
1230                                        pack,
1231                                        (GCompareFunc)eazel_install_package_compare)) {
1232                        char *tmp;
1233                        tmp = packagedata_get_readable_name (pack);
1234                        trilobite_debug ("%s already failed, will not download it's requirements", tmp);
1235                        g_free (tmp);
1236                        packagedata_destroy (dep, TRUE);
1237                        continue;
1238                }
1239
1240                /* We use the unknown status later, to see if
1241                   we should set it or not */
1242                dep->status = PACKAGE_UNKNOWN_STATUS;
1243               
1244                /* Emit the signal here, since then we won't have to make that
1245                   call in for every package system (when I say every, we know
1246                   I mean "both"...) */
1247                eazel_install_emit_dependency_check_pre_ei2 (service, pack, dep);
1248                packagedata_add_pack_to_soft_depends (pack, dep);
1249
1250                fetch_result = eazel_install_fetch_package (service, dep);
1251
1252                if (fetch_result) {
1253                        if (dep->source_package) {
1254                                dep->status = PACKAGE_SOURCE_NOT_SUPPORTED;
1255                                fetch_result = FALSE;
1256                        }
1257                }
1258
1259                if (fetch_result) {
1260                        /* If the package we just downloaded was already in packages,
1261                           but we just had a dependency conflict, we're in the funky case,
1262                           were pacakge foo is not installed. But the dependecy stuff has caused
1263                           it to be downloaded in version x.y, and later in v.w. This means that
1264                           the first conflict (causing x.y to be downloaded) now happens again.
1265                        */
1266                        if (g_list_find_custom (*packages,
1267                                                dep->name,
1268                                                (GCompareFunc)eazel_install_package_name_compare)) {
1269                                GList *pack_entry;
1270
1271                                pack_entry = g_list_find_custom (*packages,
1272                                                                 dep,
1273                                                                 (GCompareFunc)eazel_install_package_other_version_compare);
1274                                trilobite_debug ("Circular dependency  %s-%s-%s at 0x%p", 
1275                                                 dep->name, dep->version, dep->minor, dep);
1276
1277                                if (pack_entry) {
1278                                        PackageData *evil_package = packagedata_copy ((PackageData*)(pack_entry->data), FALSE);
1279                                        packagedata_add_pack_to_breaks (dep, evil_package); 
1280                                        trilobite_debug ("Circular dependency caused by %s-%s-%s at 0x%p", 
1281                                                         evil_package->name,
1282                                                         evil_package->version,
1283                                                         evil_package->minor, 
1284                                                         evil_package);
1285                                        evil_package->status = PACKAGE_CIRCULAR_DEPENDENCY;
1286                                } else {
1287                                        trilobite_debug ("This is Bad: I cannot set the funky break list");
1288                                }
1289                                dep->status = PACKAGE_CIRCULAR_DEPENDENCY;
1290                                fetch_result = FALSE;
1291                        }
1292                }
1293
1294                if (fetch_result) {
1295                        EazelInstallStatus inst_status;
1296                        /* This sets the dep->modifies and checks for a funky case.
1297                           This case is sort of like the one above.
1298                           If the call returns 0, the following must have happened ;
1299                           We had a dependency saying that foo required bar-x.y.
1300                           So we download bar and now discover that bar is already installed
1301                           in the exact same version (x.y). So that means, another
1302                           dependency solving caused us to up/downgrade bar to another
1303                           version, and the following dep check then caused a
1304                           conflict indicating that we should *not* do this up/downgrade.
1305                           
1306                           Solution:  fail the downgraded package
1307                           
1308                           I assume the packages have the same name...
1309                        */
1310                        inst_status = eazel_install_check_existing_packages (service, dep);
1311                        if (inst_status == EAZEL_INSTALL_STATUS_QUO) {
1312                                GList *pack_entry;
1313                               
1314                                trilobite_debug ("package %s required %s", pack->name, dep->name);
1315                                trilobite_debug ("This is because some other package was downloaded");
1316                                trilobite_debug ("and crushed this, since %s is already installed", dep->name);
1317                               
1318                                /* Use name compare here, as we expect the package to have the same name */
1319                                pack_entry = g_list_find_custom (*packages,
1320                                                                 dep->name,
1321                                                                 (GCompareFunc)eazel_install_package_name_compare);
1322                                if (pack_entry) {
1323                                        /* FIXME bugzilla.eazel.com
1324                                           I suspect that adding this to adding evil_package to pack's breaks
1325                                           might yield a more pleasant tree */
1326                                        PackageData *evil_package = (PackageData*)pack_entry->data;
1327                                        packagedata_add_pack_to_breaks (evil_package, dep);
1328                                        evil_package->status = PACKAGE_BREAKS_DEPENDENCY;
1329                                } else {
1330                                        trilobite_debug ("This is also Bad: I cannot set the funky break list");
1331                                }
1332                                dep->status = PACKAGE_CIRCULAR_DEPENDENCY;
1333                                fetch_result = FALSE;
1334                        } else if (eazel_install_get_downgrade (service)==FALSE && 
1335                                   inst_status == EAZEL_INSTALL_STATUS_DOWNGRADES) {
1336                                /* Bad, we're downgrading but not allowed to downgrade */
1337                                fetch_result = FALSE;
1338                        } else if (eazel_install_get_update (service)==FALSE && 
1339                                   inst_status == EAZEL_INSTALL_STATUS_UPGRADES) {
1340                                /* Bad, we're upgrading but not allowed to upgrade */
1341                                fetch_result = FALSE;
1342                        }
1343
1344                }
1345               
1346                if (fetch_result) {
1347                        /* if it succeeds, add to a list of extras for this package
1348                           We cannot just put it into extrapackages, as a later dep
1349                           might fail, and than we have to fail the package */
1350                        GList *extralist;
1351                       
1352                        /* Check if a previous requirement download solved this
1353                           Note, we don't check till after download, since only a download
1354                           will reveal the packagename in case we need to download
1355                           using fetch_package using the pack->provides.
1356                           This is a paranoia check in addition to a check done
1357                           in do_dependency_check, since a dep check might say
1358                           that we require two files that are provided by the same
1359                           package, and we only want to get the package once.
1360                           Eg. nautilus requires libgconf-gtk-1.so and libgconf-1.so,
1361                           both provided by gconf, so we fetch gconf twice */
1362                        if (g_list_find_custom (extras_in_this_batch,
1363                                                dep,
1364                                                (GCompareFunc)eazel_install_package_compare)) {
1365                                trilobite_debug ("already handled %s", dep->name);
1366                                packagedata_remove_soft_dep (dep, pack); 
1367                                dep = NULL;
1368                                continue;
1369                        }
1370                       
1371                        /* This maintains a list of extra packages for
1372                           a package. So when a requirement D for package A fails,
1373                           and we've already downloaded B & C for A,
1374                           we can easily find B & D and remove them */
1375                        extralist = g_hash_table_lookup (extras, pack->name);
1376                        extralist = g_list_append (extralist, dep);
1377                        g_hash_table_insert (extras, pack->name, extralist);
1378                       
1379                        /* This list contains all the packages added in this call
1380                           to fetch_rpm_dependencies. It's used in the initial check,
1381                           to avoid that multiple requests for a file results in
1382                           multiple downloads */
1383                        extras_in_this_batch = g_list_prepend (extras_in_this_batch, dep);
1384                       
1385                        pack->status = PACKAGE_PARTLY_RESOLVED;
1386                } else {
1387                        /*
1388                          If it fails
1389                          1) remove it from the extras hashtable for the package,
1390                          thereby ensuring the fetched packages before the fail aren't added
1391                          2) add the package to the list of stuff to remove (deleting it
1392                          immediately from packages will cause
1393                          eazel_install_match_package_data_from_rpm_conflict
1394                          to return zero. This is fine if we then just do a continue, but
1395                          this way, we get all the missing deps into pack->soft_depends
1396                          3) add to list of failed packages
1397                        */
1398                        GList *extralist;
1399                       
1400                        pack->status = PACKAGE_DEPENDENCY_FAIL;
1401                        if (dep->status == PACKAGE_UNKNOWN_STATUS) {
1402                                dep->status = PACKAGE_CANNOT_OPEN;
1403                        }
1404
1405                        trilobite_debug ("Fetching %s failed, status %s/%s", 
1406                                         packagedata_get_readable_name (dep),
1407                                         packagedata_status_enum_to_str (dep->status),
1408                                         packagedata_modstatus_enum_to_str (dep->modify_status));
1409                                                               
1410                        if (!eazel_install_get_force (service)) {
1411                                /* Remove the extra packages for this package */
1412                                extralist = g_hash_table_lookup (extras, pack->name);                   
1413                                /* Remove all the extras from the soft_deps (is this what we want ?) */
1414                                g_list_foreach (extralist, (GFunc)packagedata_remove_soft_dep, pack); 
1415                                g_list_free (extralist);
1416                                g_hash_table_remove (extras, pack->name);
1417                               
1418                                /* Don't add it to failedpackages more than once */
1419                                if (g_list_find (*failedpackages, pack) == NULL) {
1420                                        (*failedpackages) = g_list_prepend (*failedpackages, pack);
1421                                }
1422                                (*packages) = g_list_remove (*packages, pack);
1423                               
1424                                /* Don't process anymore */
1425                                break;
1426                        }
1427                }
1428        }
1429       
1430        /* iterate over all the lists in extras and add to extrapackages */
1431        g_hash_table_foreach (extras, (GHFunc)eazel_install_add_to_extras_foreach, extrapackages);
1432        g_hash_table_destroy (extras);
1433        g_list_free (extras_in_this_batch);
1434
1435        if (*failedpackages) {
1436                return FALSE;
1437        } else {
1438                return TRUE;
1439        }
1440}
1441
1442static void
1443dump_one_package (PackageData *pack, char *prefix)
1444{
1445        char *softprefix, *hardprefix, *modprefix, *breakprefix;
1446        char *packname;
1447
1448        if (pack->name == NULL) {
1449                if (pack->provides && pack->provides->data) {
1450                        packname = g_strdup_printf ("[provider of %s]", (char *)(pack->provides->data));
1451                } else {
1452                        packname = g_strdup ("[mystery package]");
1453                }
1454        } else {
1455                packname = g_strdup_printf ("%s-%s-%s", pack->name, pack->version, pack->minor);
1456        }
1457
1458        trilobite_debug ("%s%s (stat %s/%s), 0x%08X", 
1459                         prefix, packname,
1460                         packagedata_status_enum_to_str (pack->status),
1461                         packagedata_modstatus_enum_to_str (pack->modify_status),
1462                         (unsigned int)pack);
1463        g_free (packname);
1464
1465        softprefix = g_strdup_printf ("%s (s) ", prefix);
1466        hardprefix = g_strdup_printf ("%s (h) ", prefix);
1467        breakprefix = g_strdup_printf ("%s (b) ", prefix);
1468        modprefix = g_strdup_printf ("%s (m) ", prefix);
1469        g_list_foreach (pack->soft_depends, (GFunc)dump_one_package, softprefix);
1470        g_list_foreach (pack->hard_depends, (GFunc)dump_one_package, hardprefix);
1471        g_list_foreach (pack->modifies, (GFunc)dump_one_package, modprefix);
1472        g_list_foreach (pack->breaks, (GFunc)dump_one_package, breakprefix);
1473        g_free (softprefix);
1474        g_free (hardprefix);
1475        g_free (modprefix);
1476        g_free (breakprefix);
1477}
1478
1479static void
1480dump_packages_foreach (PackageData *pack, gpointer unused)
1481{
1482        if (pack->toplevel) {
1483                dump_one_package (pack, "");
1484        }
1485}
1486
1487void
1488dump_packages (GList *packages)
1489{
1490        trilobite_debug ("#####  PACKAGE TREE  #####");
1491        g_list_foreach (packages, (GFunc)dump_packages_foreach, NULL);
1492        trilobite_debug ("-----  end  -----");
1493}
1494
1495static void
1496print_package_list (char *str, GList *packages, gboolean show_deps)
1497{
1498        GList *iterator;
1499        PackageData *pack;
1500        char *tmp = NULL;
1501        char *dep = " depends on ";
1502        /*      char *breaks = " breaks ";*/
1503
1504        trilobite_debug ("---------------------------");
1505        trilobite_debug ("%s", str);
1506        for (iterator = packages; iterator; iterator = g_list_next (iterator)) {
1507                pack = (PackageData*)iterator->data;
1508                if (show_deps) {
1509                        GList *it2;
1510                        tmp = g_strdup (dep);
1511                        it2 = pack->soft_depends;
1512                        while (it2) { 
1513                                char *tmp2;
1514                                tmp2 = g_strdup_printf ("%s%s ", tmp ,
1515                                                        ((PackageData*)it2->data)->name);
1516                                g_free (tmp);
1517                                tmp = tmp2;
1518                                it2 = g_list_next (it2);
1519                        }
1520/*
1521                        tmp = g_strdup (breaks);
1522                        it2 = pack->breaks;
1523                        while (it2) {
1524                                char *tmp2;
1525                                PackageData *p2;
1526                                p2 = (PackageData*)it2->data;
1527                                tmp2 = g_strdup_printf ("%s%s(%db%dd) ", tmp , rpmfilename_from_packagedata (p2),
1528                                                        g_list_length (p2->breaks),
1529                                                        g_list_length (p2->soft_depends));
1530                                g_free (tmp);
1531                                tmp = tmp2;
1532                                it2 = g_list_next (it2);
1533                        }
1534*/
1535                }
1536                trilobite_debug ("* %s (%s) %s", 
1537                           pack->name, 
1538                           pack->toplevel ? "true" : "", 
1539                           (tmp && strlen (tmp) > strlen (dep)) ? tmp : "");
1540                g_free (tmp);
1541                tmp = NULL;
1542        }
1543}
1544
1545/*
1546  Helperfunction to create PackageRequirements for fileconflicts. Should be
1547  used for packagesystems that don't do this (eg. RPM) */
1548static void
1549eazel_install_do_file_conflict_check (EazelInstall *service,
1550                                      GList **packages,
1551                                      GList **failedpackages,
1552                                      GList **requirements)
1553{
1554        GList *iterator;
1555        GList *tmp_failed = NULL;
1556
1557        if (eazel_install_get_ignore_file_conflicts (service) ||
1558            eazel_install_get_force (service)) {
1559                trilobite_debug ("not performing file conflict check");
1560        }
1561
1562        /* Now do file conflicts on all packages */
1563        for (iterator = *packages; iterator; glist_step (iterator)) {
1564                PackageData *pack = (PackageData*)iterator->data;
1565                GList *required = NULL;
1566
1567                /* If we haven't tested conflicts yet */
1568                if (pack->conflicts_checked == FALSE) {
1569                        GList *breaks = NULL;
1570                        pack->conflicts_checked = TRUE;                 
1571                        if (eazel_install_check_for_file_conflicts (service, pack, &breaks, &required)) {
1572                                if (required) {
1573                                        /* Create PackageRequirements for all the requirements */
1574                                        GList *reqiterator;
1575                                        for (reqiterator = required;reqiterator;glist_step (reqiterator)) {
1576                                                PackageData *required_pack = (PackageData*)reqiterator->data;
1577                                                if (g_list_find_custom (*packages, 
1578                                                                        required_pack->name,
1579                                                                        (GCompareFunc)eazel_install_package_name_compare)) {
1580                                                        trilobite_debug ("but we're updating it (requirement)");
1581                                                        /* packagedata_destroy (broken_package, FALSE); */
1582                                                } else {
1583                                                        PackageRequirement *req;
1584                                                        req = packagerequirement_new (pack, required_pack);
1585                                                        (*requirements) = g_list_prepend (*requirements, req);
1586                                                }
1587                                        }
1588                                }
1589                                if (breaks) {
1590                                        GList *break_iterator;
1591                                        gboolean fail_it = FALSE;
1592                                        for (break_iterator = breaks; break_iterator; glist_step (break_iterator)) {
1593                                                PackageData *broken_package = (PackageData*)break_iterator->data;
1594                                                trilobite_debug ("breaking %s", broken_package->name);
1595                                                if (g_list_find_custom (*packages, 
1596                                                                        broken_package->name,
1597                                                                        (GCompareFunc)eazel_install_package_name_compare)) {
1598                                                        trilobite_debug ("but we're updating it");
1599                                                        /* packagedata_destroy (broken_package, FALSE); */
1600                                                } else {
1601                                                        fail_it = TRUE;
1602                                                        packagedata_add_pack_to_breaks (pack, broken_package);
1603                                                }
1604                                        }
1605                                        if (fail_it) {
1606                                                tmp_failed = g_list_prepend (tmp_failed, pack);
1607                                        }
1608                                }
1609                        } else {
1610                                /* No file conflicts */
1611                        }
1612                }
1613        }
1614       
1615        /* Now clean up */
1616        for (iterator = tmp_failed; iterator; glist_step (iterator)) {
1617                PackageData *cpack = (PackageData*)(iterator->data);
1618                (*failedpackages) = g_list_prepend (*failedpackages, cpack);
1619                (*packages) = g_list_remove (*packages, cpack);
1620        }
1621}
1622
1623/*
1624   Use package system to do the dependency check
1625 */
1626static void
1627eazel_install_do_dependency_check (EazelInstall *service,
1628                                   GList **packages,
1629                                   GList **failedpackages,
1630                                   GList **requirements)
1631{
1632        eazel_install_do_rpm_dependency_check (service, 
1633                                               packages,
1634                                               failedpackages,
1635                                               requirements);
1636        /* RPM's depCheck doens't do fileconflicts, so we do
1637                   them ourselves */
1638        eazel_install_do_file_conflict_check (service, 
1639                                              packages,
1640                                              failedpackages,
1641                                              requirements);
1642}
1643
1644/*
1645  Given a glist of PackageData's, ensure_deps_are_fetched checks deps
1646  for them all, if deps fail, fetch the depency and add to packages.
1647  Returns FALSE if outfiles was set, TRUE is all dependencies were satisfied.
1648  If a dep could not be found, that name is added to fails)
1649 */
1650static gboolean
1651eazel_install_ensure_deps (EazelInstall *service, 
1652                           GList **packages, 
1653                           GList **failedpackages)
1654{
1655        GList *extrapackages = NULL; /* This list contains packages that were added to "packages" */
1656        gboolean result;             
1657        GList *requirements = NULL;  /* This list contains the PackageRequirements for the dependecy failures */
1658
1659        g_return_val_if_fail (packages != NULL, TRUE);
1660        g_return_val_if_fail (*packages != NULL, TRUE);
1661
1662        g_return_val_if_fail (g_list_length (*packages)>=1, FALSE);
1663        result = TRUE;
1664       
1665        trilobite_debug ("Into eazel_install_ensure_deps");
1666
1667        /* First we load headers and prepare them.
1668           The datastructures depend on the packagesystem,
1669           and are places in service->private->packsys.
1670        */
1671               
1672        eazel_install_do_dependency_check (service, 
1673                                           packages, 
1674                                           failedpackages,
1675                                           &requirements);             
1676       
1677        if (requirements != NULL) {
1678                GList *iterator;
1679               
1680                extrapackages = NULL;
1681               
1682                /* For all the packages, set state to partly_resolved. */
1683                for (iterator=*packages; iterator; iterator = g_list_next (iterator)) {
1684                        PackageData *pack;
1685                        pack = (PackageData*)iterator->data;
1686                        pack->status = PACKAGE_PARTLY_RESOLVED;
1687                }
1688               
1689                trilobite_debug ("%d dependency failure(s)", g_list_length (requirements));
1690               
1691                /* Fetch the needed stuff.
1692                   "extrapackages" gets the new packages added,
1693                   packages in "failedpackages" are packages moved from
1694                   "packages" that could not be resolved. */
1695                eazel_install_fetch_dependencies (service, 
1696                                                  packages,
1697                                                  &extrapackages,
1698                                                  failedpackages,
1699                                                  requirements);
1700
1701                /* Delete the PackageRequirements.
1702                   Note, that we just need to free the structure, both elements
1703                   are kept, req->package in extrapackages or failedpackages and
1704                   req->required will be in req->package's breaks/soft_depends.
1705                */
1706                g_list_foreach (requirements, (GFunc)g_free, NULL);
1707                g_list_free (requirements);
1708               
1709                /* Some debug printing */
1710                dump_packages (*packages);
1711                print_package_list ("Packages that were fetched", extrapackages, FALSE);
1712                print_package_list ("Packages that failed", *failedpackages, TRUE);
1713        } else {
1714                GList *iterator;
1715               
1716                /* Deps are fine, set all packages to resolved */
1717                for (iterator=*packages; iterator; iterator = g_list_next (iterator)) {
1718                        PackageData *pack;
1719                        pack = (PackageData*)iterator->data;
1720                        pack->status = PACKAGE_RESOLVED;
1721                }
1722                trilobite_debug (_("Dependencies appear ok"));
1723
1724                if (!eazel_install_do_transaction_all_files_check (service, packages)) {
1725                        trilobite_debug (_("But there are file conflicts"));
1726                        /* Now recurse into eazel_install_ensure_deps with
1727                           the new "packages" list */
1728                        eazel_install_ensure_deps (service, packages, failedpackages);
1729                } else {
1730                        trilobite_debug ("Dependencies still appear ok");
1731                }
1732
1733        }
1734
1735        /* If there was failedpackages, prune them from the tree
1736           and the "extrapackages".
1737           We need to strip from "extrapackages" as well, since :
1738           while installing A & B, C was added for A, D was
1739           added for B but B also needs E (but not found). Therefore
1740           we strip D from "extrapackages" and B is stripped
1741           from "packages". Keeping D around would
1742           install a non-needed package
1743        */
1744        if (*failedpackages) {
1745                GList *iterator;
1746
1747                for (iterator = *failedpackages; iterator; iterator = g_list_next (iterator)) {
1748                        PackageData *pack;
1749                        pack = (PackageData*)iterator->data;
1750                        trilobite_debug ("calling prune on %s", pack->name);
1751                        eazel_install_prune_packages (service, pack, packages, 
1752                                                              &extrapackages, NULL);
1753                }                       
1754        } 
1755        /* If there were conflicts, we'll have called fetch_dependencies and might
1756           have downloaded extra packages. So we have to recurse and process these */
1757        if (extrapackages) {
1758                GList *iterator;
1759               
1760                /* Add to "packages" */
1761                for (iterator = extrapackages; iterator; iterator = g_list_next (iterator)) {
1762                        (*packages) = g_list_append (*packages, iterator->data);
1763                }
1764                g_list_free (extrapackages);
1765               
1766                /* Now recurse into eazel_install_ensure_deps with
1767                   the new "packages" list */
1768                eazel_install_ensure_deps (service, packages, failedpackages);
1769               
1770                /* Now remove the packages that failed from "packages"
1771                   and copy them into "failedpackages".  */
1772                for (iterator = *failedpackages; iterator; iterator = g_list_next (iterator)) {
1773                        PackageData *pack;
1774                        pack = (PackageData*)iterator->data;
1775                        (*packages) = g_list_remove (*packages, pack);                                 
1776                }
1777        }
1778        dump_packages (*packages);
1779                     
1780        return result;
1781}
1782
1783/* This traverses upwards in the deptree from the initial list, and adds
1784   all packages that will break to "breaks" */
1785static void
1786eazel_uninstall_upward_traverse (EazelInstall *service,
1787                                 GList **packages,
1788                                 GList **failed,
1789                                 GList **breaks)
1790{
1791        GList *iterator;
1792        /*
1793          Create set
1794          add all packs from packages to set
1795          dep check
1796          for all break, add to packages and recurse
1797         */
1798
1799        trilobite_debug ("in eazel_uninstall_upward_traverse");
1800
1801        g_assert (packages!=NULL);
1802        g_assert (*packages!=NULL);
1803        g_assert (breaks!=NULL);
1804        g_assert (*breaks==NULL);
1805
1806        /* Open the package system */
1807
1808        /* Add all packages to the set */
1809
1810        for (iterator = *packages; iterator; iterator = g_list_next (iterator)) {
1811                PackageData *pack = (PackageData*)iterator->data;
1812                GList *matches = NULL;
1813                GList *match_iterator;
1814                GList *tmp_breaks = NULL;
1815                GList *break_iterator = NULL;
1816               
1817                trilobite_debug ("checking reqs by %s", rpmname_from_packagedata (pack));
1818                matches = eazel_package_system_query (service->private->package_system,
1819                                                      service->private->cur_root,
1820                                                      pack,
1821                                                      EAZEL_PACKAGE_SYSTEM_QUERY_REQUIRES,
1822                                                      PACKAGE_FILL_NO_DIRS_IN_PROVIDES);
1823                packagedata_list_prune (&matches, *packages, TRUE, TRUE);
1824               
1825                for (match_iterator = matches; match_iterator; match_iterator = g_list_next (match_iterator)) {
1826                        PackageData *requiredby = (PackageData*)match_iterator->data;;
1827                       
1828                        requiredby->status = PACKAGE_DEPENDENCY_FAIL;
1829                        pack->status = PACKAGE_BREAKS_DEPENDENCY;
1830                        trilobite_debug ("logic.c: %s requires %s", requiredby->name, pack->name);
1831
1832                        /* If we're already marked it as breaking, go on
1833                        if (g_list_find_custom (*breaks, (gpointer)requiredby->name,
1834                                                (GCompareFunc)eazel_install_package_name_compare)) {
1835                                trilobite_debug ("skip %s", requiredby->name);
1836                                packagedata_destroy (requiredby, TRUE);
1837                                requiredby = NULL;
1838                                continue;
1839                        }
1840                        */
1841
1842                        /* Guess not, mark it as breaking (and that pack is the offender */
1843                        packagedata_add_pack_to_breaks (pack, requiredby);
1844                        (*breaks) = g_list_prepend ((*breaks), requiredby);
1845
1846                        /* If the package has not been failed yet (and is a toplevel),
1847                           fail it */
1848                        if (!g_list_find_custom (*failed, (gpointer)pack->name, 
1849                                                 (GCompareFunc)eazel_install_package_name_compare) &&
1850                            pack->toplevel) {
1851                                (*failed) = g_list_prepend (*failed, pack);
1852                        }
1853                }
1854                /* fre the list structure from _simple_query */
1855                g_list_free (matches);
1856               
1857                if (*breaks) {
1858                        eazel_uninstall_upward_traverse (service, breaks, failed, &tmp_breaks);
1859                }
1860               
1861                for (break_iterator = tmp_breaks; break_iterator; break_iterator = g_list_next (break_iterator)) {
1862                        (*breaks) = g_list_prepend ((*breaks), break_iterator->data);
1863                }
1864        }
1865       
1866        for (iterator = *failed; iterator; iterator = g_list_next (iterator)) {
1867                (*packages) = g_list_remove (*packages, iterator->data);
1868        }
1869
1870        trilobite_debug ("out eazel_uninstall_upward_traverse");
1871}
1872
1873/* This traverses downwards on all requirements in "packages",
1874   checks that their uninstall do _not_ break anything, and
1875   adds thm to requires */
1876
1877static void
1878eazel_uninstall_downward_traverse (EazelInstall *service,
1879                                   GList **packages,
1880                                   GList **failed,
1881                                   GList **requires)
1882{
1883        GList *iterator;
1884        GList *tmp_requires = NULL;
1885
1886        /*
1887           create set
1888           find all requirements from "packages"
1889           add all packs + requirements from "packages" to set
1890           dep check
1891           for all breaks, remove from requirements
1892           recurse calling eazel_uninstall_downward_traverse (requirements, &tmp)
1893           add all from tmp to requirements
1894        */
1895        trilobite_debug ("in eazel_uninstall_downward_traverse");
1896       
1897        /* First iterate across the packages in "packages" */
1898        for (iterator = *packages; iterator; iterator = g_list_next (iterator)) {
1899                GList *matches = NULL;
1900                PackageData *pack;
1901                GList *match_iterator;
1902
1903                pack = (PackageData*)iterator->data;
1904
1905                matches = eazel_package_system_query (service->private->package_system,
1906                                                      service->private->cur_root,
1907                                                      pack->name,
1908                                                      EAZEL_PACKAGE_SYSTEM_QUERY_MATCHES,
1909                                                      PACKAGE_FILL_NO_DIRS_IN_PROVIDES);
1910                trilobite_debug ("%s had %d hits", pack->name, g_list_length (matches));
1911
1912                /* Now iterate over all packages that match pack->name */
1913                for (match_iterator = matches; match_iterator; match_iterator = g_list_next (match_iterator)) {
1914                        PackageData *matched_pack;
1915                        const char **require_name;
1916                        int require_name_count;
1917                        Header hd;
1918                        int type;
1919                        int j;
1920
1921                        matched_pack = (PackageData*)match_iterator->data;
1922                        hd = ((Header) matched_pack->packsys_struc);
1923
1924                        if (!headerGetEntry(hd, RPMTAG_REQUIRENAME, &type, (void **) &require_name,
1925                                            &require_name_count)) {
1926                                require_name_count = 0;
1927                        }
1928                       
1929                        trilobite_debug ("requirename count = %d", require_name_count);
1930                       
1931                        /* No iterate over all packages required by the current package */
1932                        for (j = 0; j < require_name_count; j++) {
1933                                if ((*require_name[j] != '/') &&
1934                                    !strstr (require_name[j], ".so")) {
1935                                        PackageData *tmp_pack = packagedata_new ();
1936                                        GList *second_matches;
1937                                        GList *second_match_iterator;
1938
1939                                        tmp_pack->name = g_strdup (require_name[j]);
1940                                        second_matches = 
1941                                                eazel_package_system_query (service->private->package_system,
1942                                                                            service->private->cur_root,
1943                                                                            tmp_pack,
1944                                                                            EAZEL_PACKAGE_SYSTEM_QUERY_REQUIRES,
1945                                                                            PACKAGE_FILL_NO_DIRS_IN_PROVIDES);
1946                                        packagedata_list_prune (&second_matches, *packages, TRUE, TRUE);
1947                                        packagedata_list_prune (&second_matches, *requires, TRUE, TRUE);
1948                                        packagedata_destroy (tmp_pack, TRUE);
1949
1950                                        /* Iterate over all packages that match the required package */
1951                                        for (second_match_iterator = second_matches;
1952                                             second_match_iterator; 
1953                                             second_match_iterator = g_list_next (second_match_iterator)) {
1954                                                PackageData *isrequired;
1955
1956                                                isrequired = (PackageData*)second_match_iterator->data;
1957                                                if (g_list_find_custom (*requires, isrequired->name,
1958                                                                        (GCompareFunc)eazel_install_package_name_compare) ||
1959                                                    g_list_find_custom (*packages, isrequired->name,
1960                                                                        (GCompareFunc)eazel_install_package_name_compare)) {
1961                                                        trilobite_debug ("skipped %s", isrequired->name);
1962                                                        packagedata_destroy (isrequired, TRUE);\
1963                                                        isrequired = NULL;
1964                                                        continue;
1965                                                }               
1966                                                trilobite_debug ("** %s requires %s", pack->name, isrequired->name);
1967
1968                                                {
1969                                                        GList *third_matches;
1970
1971                                                        /* Search for packages
1972                                                           requiring the requirement, excluding
1973                                                           all pacakges from requires and packages */
1974                                                        third_matches = 
1975                                                                eazel_package_system_query (service->private->package_system,
1976                                                                                            service->private->cur_root,
1977                                                                                            pack->name,
1978                                                                                            EAZEL_PACKAGE_SYSTEM_QUERY_REQUIRES,
1979                                                                                            PACKAGE_FILL_NO_DIRS_IN_PROVIDES);
1980                                                        packagedata_list_prune (&third_matches, 
1981                                                                                *packages, TRUE, TRUE);
1982                                                        packagedata_list_prune (&third_matches, 
1983                                                                                *requires, TRUE, TRUE);
1984                                                        packagedata_list_prune (&third_matches, 
1985                                                                                tmp_requires, TRUE, TRUE);
1986                                                       
1987                                                        if (third_matches) {
1988                                                                trilobite_debug ("skipped %s, others depend on it", 
1989                                                                           isrequired->name);
1990                                                                print_package_list ("BY", third_matches, FALSE);
1991                                                                g_list_foreach (third_matches, 
1992                                                                                (GFunc)packagedata_destroy, 
1993                                                                                GINT_TO_POINTER (TRUE));
1994                                                                g_list_free (third_matches);
1995                                                                third_matches = NULL;
1996                                                                packagedata_destroy (isrequired, TRUE);
1997                                                                isrequired = NULL;
1998                                                        } else {
1999                                                                trilobite_debug ("Also nuking %s", isrequired->name);
2000                                                                tmp_requires = g_list_prepend (tmp_requires, 
2001                                                                                               isrequired);
2002                                                        }
2003                                                }
2004                                        }
2005                                        g_list_free (second_matches);
2006                                } else {
2007                                        trilobite_debug ("must lookup %s", require_name[j]);
2008                                        /* FIXME bugzilla.eazel.com 1541:
2009                                           lookup package "p" that provides requires[j],
2010                                           if packages that that require "p" are not in "packages"
2011                                           don't add it, otherwise add to requires */
2012                                }
2013                        }
2014
2015                        headerFree (hd);
2016                }
2017                g_list_foreach (matches, (GFunc)packagedata_destroy, GINT_TO_POINTER (TRUE));
2018                g_list_free (matches);
2019                matches = NULL;
2020        }
2021
2022        if (tmp_requires) {
2023                eazel_uninstall_downward_traverse (service, &tmp_requires, failed, requires);
2024        }
2025
2026        /* Now move the entries in tmp_requires into *requires */
2027        for (iterator = tmp_requires; iterator; iterator = g_list_next (iterator)) {
2028                (*requires) = g_list_prepend (*requires, iterator->data);
2029        }
2030        g_list_free (tmp_requires);
2031
2032        trilobite_debug ("out eazel_uninstall_downward_traverse");
2033}
2034
2035static void
2036eazel_uninstall_check_for_install (EazelInstall *service,
2037                                   GList **packages,
2038                                   GList **failed)
2039{
2040        GList *iterator;
2041        GList *remove  = NULL;
2042        GList *result = NULL;
2043
2044        trilobite_debug ("in eazel_uninstall_check_for_install");
2045        g_assert (packages);
2046        trilobite_debug ("g_list_length (*packages) = %d", g_list_length (*packages)); 
2047        for (iterator = *packages; iterator; iterator = g_list_next (iterator)) {               
2048                PackageData *pack = (PackageData*)iterator->data;
2049                GList *matches;
2050
2051                matches = eazel_package_system_query (service->private->package_system,
2052                                                      service->private->cur_root,
2053                                                      pack->name,
2054                                                      EAZEL_PACKAGE_SYSTEM_QUERY_MATCHES,
2055                                                      PACKAGE_FILL_NO_TEXT | PACKAGE_FILL_NO_DEPENDENCIES | PACKAGE_FILL_NO_DIRS_IN_PROVIDES);
2056                /* If it's installed, continue */
2057                if (matches) {
2058                        GList *match_it;
2059                        gboolean any = FALSE;
2060                        for (match_it = matches; match_it; match_it = g_list_next (match_it)) {
2061                                PackageData *matched = (PackageData*)match_it->data;
2062                                if (eazel_install_package_matches_versioning (matched, 
2063                                                                              pack->version, 
2064                                                                              pack->minor,
2065                                                                              EAZEL_SOFTCAT_SENSE_EQ)) {
2066                                        matched->toplevel = TRUE;
2067                                        /* mark that at least one matched */
2068                                        any = TRUE;
2069                                        result = g_list_prepend (result, matched);
2070                                } else {
2071                                        packagedata_destroy (matched, TRUE);
2072                                }
2073                               
2074                        } 
2075                        if (!any) {
2076                                pack->status = PACKAGE_CANNOT_OPEN;
2077                                remove = g_list_prepend (remove, pack);
2078                        }
2079                        g_list_free (matches);
2080                        continue;
2081                } else {
2082                        pack->status = PACKAGE_CANNOT_OPEN;
2083                        remove = g_list_prepend (remove, pack);
2084                }               
2085        }
2086
2087        for (iterator = remove; iterator; iterator=g_list_next (iterator)) {
2088                (*packages) = g_list_remove (*packages, iterator->data);
2089                (*failed) = g_list_prepend (*failed, iterator->data);
2090        }
2091        g_list_free (remove);
2092        remove = NULL;
2093
2094        trilobite_debug ("g_list_length (*packages) = %d", g_list_length (*packages)); 
2095        trilobite_debug ("g_list_length (result) = %d", g_list_length (result)); 
2096
2097        g_list_foreach (*packages, (GFunc)packagedata_destroy, FALSE);
2098        g_list_free (*packages);
2099        (*packages) = result;
2100
2101        trilobite_debug ("out eazel_uninstall_check_for_install");
2102}
2103
2104/* Calls the upward and downward traversal */
2105static void
2106eazel_uninstall_globber (EazelInstall *service,
2107                         GList **packages,
2108                         GList **failed)
2109{
2110        GList *iterator;
2111        GList *tmp;
2112
2113        /*
2114          call upward with packages
2115          call downward with packages and &tmp
2116          add all from &tmp to packages
2117        */
2118
2119        trilobite_debug ("in eazel_uninstall_globber");
2120
2121        tmp = NULL;
2122
2123        eazel_uninstall_check_for_install (service, packages, failed);
2124        for (iterator = *failed; iterator; iterator = g_list_next (iterator)) {
2125                trilobite_debug ("not installed %s", ((PackageData*)iterator->data)->name);
2126                eazel_install_emit_uninstall_failed (service, (PackageData*)iterator->data);
2127        }
2128               
2129        /* If there are still packages and we're not forcing,
2130           do upwards traversel */
2131        if (*packages && !eazel_install_get_force (service)) {
2132                eazel_uninstall_upward_traverse (service, packages, failed, &tmp);
2133                print_package_list ("FAILED", *failed, TRUE);
2134                for (iterator = *failed; iterator; iterator = g_list_next (iterator)) {
2135                        PackageData *pack = (PackageData*)iterator->data;
2136                        trilobite_debug ("failed %s", pack->name);
2137                        dump_one_package (pack, "");
2138                        eazel_install_emit_uninstall_failed (service, pack);
2139                }
2140                g_list_free (tmp);
2141        }
2142
2143/*
2144  I've disabled downwards traverse untill it's done.
2145
2146        tmp = NULL;
2147        eazel_uninstall_downward_traverse (service, packages, failed, &tmp);
2148        for (iterator = tmp; iterator; iterator = g_list_next (iterator)) {
2149                g_message ("also doing %s", ((PackageData*)iterator->data)->name);
2150                (*packages) = g_list_prepend (*packages, iterator->data);
2151        }
2152        g_list_free (tmp);
2153*/
2154
2155        trilobite_debug ("out eazel_uninstall_glob");
2156}
Note: See TracBrowser for help on using the browser.