~ubuntu-branches/ubuntu/lucid/aptitude/lucid-proposed

« back to all changes in this revision

Viewing changes to src/cmdline/cmdline_util.cc

  • Committer: Bazaar Package Importer
  • Author(s): Michael Vogt
  • Date: 2008-05-27 10:28:10 UTC
  • mfrom: (1.2.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20080527102810-pxc090mnjkr4xlek
Tags: 0.4.11.2-1ubuntu1
* Merge from debian unstable, remaining changes:
  - 03_branding.dpatch: ubuntu branding
  - 04_changelog.dpatch: take changelogs from changelogs.ubuntu.com
  - 07_hide_recommends_warning.dpatch: do not show a warning about
    missing recommends
  - 08_ubuntu_default_source.dpatch: do not clean lists directory
    on transient network failures
  - 11_gxx43.dpatch:build tests without -Werror
* Updated:
  - 03_branding.dpatch
* Disabled 07_hide_recommends warning because we do install 
  recommends now by default too

Show diffs side-by-side

added added

removed removed

Lines of Context:
6
6
 
7
7
#include "cmdline_common.h"
8
8
#include "cmdline_progress.h"
 
9
#include "cmdline_show.h" // For operator<<
9
10
 
10
11
#include <aptitude.h>
11
12
#include <ui.h>
15
16
#include <generic/apt/config_signal.h>
16
17
#include <generic/apt/download_manager.h>
17
18
#include <generic/apt/download_signal_log.h>
 
19
#include <generic/apt/matchers.h>
18
20
 
 
21
#include <cwidget/fragment.h>
19
22
#include <cwidget/toplevel.h>
 
23
#include <cwidget/generic/util/ssprintf.h>
20
24
 
 
25
#include <sigc++/bind.h>
21
26
#include <sigc++/functors/ptr_fun.h>
22
27
 
 
28
#include <apt-pkg/error.h>
 
29
#include <apt-pkg/indexfile.h>
 
30
#include <apt-pkg/metaindex.h>
 
31
#include <apt-pkg/pkgsystem.h>
 
32
#include <apt-pkg/sourcelist.h>
 
33
#include <apt-pkg/version.h>
 
34
 
 
35
#include <algorithm>
 
36
 
 
37
namespace cw = cwidget;
 
38
 
 
39
namespace
 
40
{
 
41
  const int no_install_run_from_ui_preview_return = -1;
 
42
  const int ui_preview_install_failed_return = -1;
 
43
 
 
44
  // Completion routine for the UI preview; causes the program to
 
45
  // return 0 if the install succeded and 1 otherwise.
 
46
  //
 
47
  // There's a question in my mind of what to do if the user cancels
 
48
  // the preview or runs multiple previews.  At the moment we return
 
49
  // -1 if the preview is cancelled and the result of the last install
 
50
  // run otherwise.
 
51
  void ui_preview_complete(bool success, int *result)
 
52
  {
 
53
    *result = success ? 0 : ui_preview_install_failed_return;
 
54
  }
 
55
}
 
56
 
23
57
void ui_preview()
24
58
{
 
59
  int result = no_install_run_from_ui_preview_return;
 
60
 
25
61
  ui_init();
26
62
  file_quit.connect(sigc::ptr_fun(cwidget::toplevel::exitmain));
 
63
  install_finished.connect(sigc::bind(sigc::ptr_fun(ui_preview_complete),
 
64
                                      &result));
27
65
  do_package_run_or_show_preview();
28
66
  ui_main();
29
 
  exit(0);
 
67
  exit(result);
30
68
}
31
69
 
32
70
void ui_solution_screen()
169
207
  return true;
170
208
}
171
209
 
172
 
download_manager::result cmdline_do_download(download_manager *m)
173
 
{
 
210
 
 
211
namespace
 
212
{
 
213
  /** \brief Used to display some statistics about how the cache
 
214
   *  changed after an update.
 
215
   *
 
216
   *  Perhaps this should be extended to other commands too?
 
217
   */
 
218
  class stats
 
219
  {
 
220
    int num_broken;
 
221
    int num_upgradable;
 
222
    int num_new;
 
223
    // A set of package names that are obsolete.  Names are stored
 
224
    // since iterators aren't preserved over cache refreshes.
 
225
    std::set<std::string> obsolete;
 
226
 
 
227
  public:
 
228
    stats(int _num_broken, int _num_upgradable, int _num_new,
 
229
          const std::set<std::string> &_obsolete)
 
230
      : num_broken(_num_broken),
 
231
        num_upgradable(_num_upgradable),
 
232
        num_new(_num_new),
 
233
        obsolete(_obsolete)
 
234
    {
 
235
    }
 
236
 
 
237
    int get_num_broken() const { return num_broken; }
 
238
    int get_num_upgradable() const { return num_upgradable; }
 
239
    int get_num_new() const { return num_new; }
 
240
    const std::set<std::string> &get_obsolete() const { return obsolete; }
 
241
  };
 
242
 
 
243
  stats compute_apt_stats()
 
244
  {
 
245
    int num_upgradable = 0;
 
246
    int num_new = 0;
 
247
    int num_broken = 0;
 
248
    std::set<std::string> obsolete;
 
249
 
 
250
    if(apt_cache_file == NULL)
 
251
      return stats(0, 0, 0, obsolete);
 
252
 
 
253
    for(pkgCache::PkgIterator p = (*apt_cache_file)->PkgBegin();
 
254
        !p.end(); ++p)
 
255
      {
 
256
        if(pkg_obsolete(p))
 
257
          obsolete.insert(p.Name());
 
258
 
 
259
        const pkgDepCache::StateCache &state = (*apt_cache_file)[p];
 
260
        const aptitudeDepCache::aptitude_state &estate =
 
261
          (*apt_cache_file)->get_ext_state(p);
 
262
 
 
263
        // Q: this will count to-be-removed packages, should it?
 
264
        if(state.Status != 2 && state.Upgradable())
 
265
          ++num_upgradable;
 
266
 
 
267
        if(state.NowBroken())
 
268
          ++num_broken;
 
269
 
 
270
        if((state.Status != 2 || state.CandidateVer != NULL) &&
 
271
           estate.new_package)
 
272
          ++num_new;
 
273
      }
 
274
 
 
275
    return stats(num_broken, num_upgradable, num_new, obsolete);
 
276
  }
 
277
 
 
278
  void show_stats_change(stats initial, stats final,
 
279
                         bool show_all,
 
280
                         bool show_unchanged)
 
281
  {
 
282
    using cw::fragf;
 
283
    using cw::util::ssprintf;
 
284
 
 
285
    std::vector<cw::fragment *> fragments;
 
286
 
 
287
    if(show_all ||
 
288
       (show_unchanged && final.get_num_broken() != 0) ||
 
289
       final.get_num_broken() != initial.get_num_broken())
 
290
      {
 
291
        std::string change =
 
292
          ssprintf(ngettext("%d broken [%+d]",
 
293
                            "%d broken [%+d]",
 
294
                            final.get_num_broken()),
 
295
                   final.get_num_broken(),
 
296
                   final.get_num_broken() - initial.get_num_broken());
 
297
 
 
298
        fragments.push_back(cw::text_fragment(change));
 
299
      }
 
300
 
 
301
    if(show_all ||
 
302
       (show_unchanged && final.get_num_upgradable() != 0) ||
 
303
       final.get_num_upgradable() != initial.get_num_upgradable())
 
304
      {
 
305
        std::string change =
 
306
          ssprintf(ngettext("%d update [%+d]",
 
307
                            "%d updates [%+d]",
 
308
                            final.get_num_upgradable()),
 
309
                   final.get_num_upgradable(),
 
310
                   final.get_num_upgradable() - initial.get_num_upgradable());
 
311
 
 
312
        fragments.push_back(cw::text_fragment(change));
 
313
      }
 
314
 
 
315
    if(show_all ||
 
316
       (show_unchanged && final.get_num_new() != 0) ||
 
317
       final.get_num_new() != initial.get_num_new())
 
318
      {
 
319
        std::string change =
 
320
          ssprintf(ngettext("%d new [%+d]",
 
321
                            "%d new [%+d]",
 
322
                            final.get_num_new()),
 
323
                   final.get_num_new(),
 
324
                   final.get_num_new() - initial.get_num_new());
 
325
 
 
326
        fragments.push_back(cw::text_fragment(change));
 
327
      }
 
328
 
 
329
    std::vector<cw::fragment *> output_fragments;
 
330
    if(fragments.size() > 0)
 
331
      output_fragments.push_back(fragf(_("Current status: %F."),
 
332
                                       cw::join_fragments(fragments, L", ")));
 
333
 
 
334
    std::cout << std::endl;
 
335
    std::vector<std::string> new_obsolete;
 
336
    std::set_difference(final.get_obsolete().begin(), final.get_obsolete().end(),
 
337
                        initial.get_obsolete().begin(), initial.get_obsolete().end(),
 
338
                        std::back_insert_iterator<std::vector<std::string> >(new_obsolete));
 
339
    const int obsolete_list_limit = aptcfg->FindI(PACKAGE "::Max-Obsolete-List-Length", 50);
 
340
    if(new_obsolete.size() > obsolete_list_limit)
 
341
      {
 
342
        output_fragments.push_back(cw::text_fragment(ssprintf(ngettext("There is %d newly obsolete package.",
 
343
                                                                       "There are %d newly obsolete packages.",
 
344
                                                                       new_obsolete.size()),
 
345
                                                              new_obsolete.size())));
 
346
      }
 
347
    else if(new_obsolete.size() > 0)
 
348
      {
 
349
        std::vector<cw::fragment *> package_name_fragments;
 
350
        for(std::vector<std::string>::const_iterator it =
 
351
              new_obsolete.begin(); it != new_obsolete.end(); ++it)
 
352
          package_name_fragments.push_back(cw::text_fragment(*it));
 
353
 
 
354
        output_fragments.push_back(cw::dropbox(cw::text_fragment(ssprintf(ngettext("There is %d newly obsolete package: ",
 
355
                                                                                   "There are %d newly obsolete packages: ",
 
356
                                                                                   new_obsolete.size()),
 
357
                                                                          (int)new_obsolete.size())),
 
358
                                               wrapbox(cw::join_fragments(package_name_fragments, L", "))));
 
359
      }
 
360
 
 
361
    if(output_fragments.size() > 0)
 
362
      {
 
363
        cw::fragment *f = join_fragments(output_fragments, L"\n");
 
364
 
 
365
        update_screen_width();
 
366
        std::cout << f->layout(screen_width, screen_width, cw::style());
 
367
        delete f;
 
368
      }
 
369
  }
 
370
}
 
371
 
 
372
download_manager::result cmdline_do_download(download_manager *m,
 
373
                                             int verbose)
 
374
{
 
375
  stats initial_stats(0, 0, 0, std::set<std::string>());
174
376
  OpTextProgress progress(aptcfg->FindI("Quiet", 0));
 
377
 
 
378
  if(aptcfg->FindI("Quiet", 0) == 0)
 
379
    {
 
380
      // This does exactly what we want: nothing if the cache is
 
381
      // already loaded, and loads the cache with a minimum of frills
 
382
      // otherwise.
 
383
      OpProgress tmpProgress;
 
384
      // Dump errors so we don't spuriously think we failed.
 
385
      _error->DumpErrors();
 
386
      apt_load_cache(&tmpProgress, false, NULL);
 
387
      initial_stats = compute_apt_stats();
 
388
    }
 
389
 
175
390
  std::auto_ptr<download_signal_log> log(gen_cmdline_download_progress());
176
391
 
 
392
  // Dump errors here because prepare() might check for pending errors
 
393
  // and think something failed.
 
394
  _error->DumpErrors();
 
395
 
177
396
  if(!m->prepare(progress, *log.get(), log.get()))
178
397
    return download_manager::failure;
179
398
 
186
405
    }
187
406
  while(finish_res == download_manager::do_again);
188
407
 
 
408
  stats final_stats(0, 0, 0, std::set<std::string>());
 
409
  if(aptcfg->FindI("Quiet", 0) == 0)
 
410
    {
 
411
      OpProgress tmpProgress;
 
412
      apt_load_cache(&tmpProgress, false, NULL);
 
413
      final_stats = compute_apt_stats();
 
414
      show_stats_change(initial_stats, final_stats,
 
415
                        verbose >= 1, verbose >= 2);
 
416
    }
 
417
 
189
418
  return finish_res;
190
419
}
 
420
 
 
421
bool cmdline_is_search_pattern(const std::string &s)
 
422
{
 
423
  return s.find_first_of("~?") != s.npos;
 
424
}
 
425
 
 
426
namespace aptitude
 
427
{
 
428
  namespace cmdline
 
429
  {
 
430
    namespace
 
431
    {
 
432
      source_package find_source_package(const std::string &source_name,
 
433
                                         const std::string &source_version)
 
434
      {
 
435
        if(apt_source_list == NULL)
 
436
          return NULL;
 
437
 
 
438
        pkgSrcRecords records(*apt_source_list);
 
439
        records.Restart();
 
440
 
 
441
        pkgSrcRecords::Parser *parser = records.Find(source_name.c_str());
 
442
        while(parser != NULL && parser->Version() != source_version)
 
443
          parser = records.Find(source_name.c_str());
 
444
 
 
445
        return parser;
 
446
      }
 
447
 
 
448
      // Find the most recent source package for the given name.
 
449
      source_package find_source_package(const std::string &source_name)
 
450
      {
 
451
        if(apt_source_list == NULL)
 
452
          return NULL;
 
453
 
 
454
        pkgSrcRecords records(*apt_source_list);
 
455
        records.Restart();
 
456
 
 
457
        pkgSrcRecords::Parser *parser = records.Find(source_name.c_str());
 
458
        source_package rval = parser;
 
459
 
 
460
        while(parser != NULL)
 
461
          {
 
462
            if(_system->VS->CmpVersion(rval.get_version(), parser->Version()) < 0)
 
463
              rval = parser;
 
464
            parser = records.Find(source_name.c_str());
 
465
          }
 
466
 
 
467
        return rval;
 
468
      }
 
469
    }
 
470
 
 
471
    source_package::source_package()
 
472
    {
 
473
    }
 
474
 
 
475
    source_package::source_package(pkgSrcRecords::Parser *parser)
 
476
    {
 
477
      if(parser != NULL)
 
478
        {
 
479
          package = parser->Package();
 
480
          version = parser->Version();
 
481
          maintainer = parser->Maintainer();
 
482
          section = parser->Section();
 
483
 
 
484
          if(parser->Binaries() != NULL)
 
485
            {
 
486
              for(const char **b = parser->Binaries(); *b != NULL; ++b)
 
487
                binaries.push_back(*b);
 
488
            }
 
489
 
 
490
          parser->BuildDepends(build_deps, false);
 
491
        }
 
492
    }
 
493
 
 
494
    source_package find_source_by_archive(const std::string &source_name,
 
495
                                          const std::string &archive)
 
496
    {
 
497
      if(apt_source_list == NULL)
 
498
        return NULL;
 
499
 
 
500
      for(pkgSourceList::const_iterator i = apt_source_list->begin();
 
501
          i != apt_source_list->end(); ++i)
 
502
        {
 
503
          if((*i)->GetDist() != archive)
 
504
            continue;
 
505
 
 
506
          vector<pkgIndexFile *> *indexes = (*i)->GetIndexFiles();
 
507
 
 
508
          for(vector<pkgIndexFile *>::const_iterator j = indexes->begin();
 
509
              j != indexes->end(); ++j)
 
510
            {
 
511
              std::auto_ptr<pkgSrcRecords::Parser> p((*j)->CreateSrcParser());
 
512
 
 
513
              if(_error->PendingError())
 
514
                return source_package();
 
515
              if(p.get() != 0)
 
516
                {
 
517
                  // Step through the file until we reach the end or find
 
518
                  // the package:
 
519
                  while(p.get()->Step() == true)
 
520
                    {
 
521
                      if(_error->PendingError() == true)
 
522
                        return source_package();
 
523
 
 
524
                      if(p.get()->Package() == source_name)
 
525
                        return source_package(p.get());
 
526
                    }
 
527
                }
 
528
            }
 
529
        }
 
530
 
 
531
      return source_package();
 
532
    }
 
533
 
 
534
    source_package find_source_package(const std::string &package,
 
535
                                       cmdline_version_source version_source,
 
536
                                       const std::string &version_source_string_orig)
 
537
    {
 
538
      // This will be set below to the package archive if necessary.
 
539
      std::string version_source_string(version_source_string_orig);
 
540
      if(apt_cache_file == NULL || apt_package_records == NULL || apt_source_list == NULL)
 
541
        return NULL;
 
542
 
 
543
      string default_release = aptcfg->Find("APT::Default-Release");
 
544
      if(version_source == cmdline_version_cand && !default_release.empty())
 
545
        {
 
546
          version_source        = cmdline_version_archive;
 
547
          version_source_string = default_release;
 
548
        }
 
549
 
 
550
      pkgCache::PkgIterator pkg = (*apt_cache_file)->FindPkg(package);
 
551
      std::string source_package_name = package;
 
552
 
 
553
      source_package rval;
 
554
 
 
555
      // First look for a source of the given name.
 
556
      switch(version_source)
 
557
        {
 
558
        case cmdline_version_cand:
 
559
          rval = find_source_package(source_package_name);
 
560
          break;
 
561
 
 
562
        case cmdline_version_archive:
 
563
          _error->DumpErrors();
 
564
          rval = find_source_by_archive(source_package_name, version_source_string);
 
565
          break;
 
566
 
 
567
        case cmdline_version_version:
 
568
          rval = find_source_package(source_package_name, version_source_string);
 
569
          break;
 
570
        }
 
571
 
 
572
      if(rval.valid())
 
573
        return rval;
 
574
 
 
575
      // If no source of that name exists, try to find a real package
 
576
      // and use its source.
 
577
      if(!pkg.end())
 
578
        {
 
579
          pkgCache::VerIterator ver = cmdline_find_ver(pkg,
 
580
                                                       version_source,
 
581
                                                       version_source_string);
 
582
 
 
583
          if(!ver.end())
 
584
            {
 
585
              pkgRecords::Parser &rec =
 
586
                apt_package_records->Lookup(ver.FileList());
 
587
 
 
588
              if(!rec.SourcePkg().empty())
 
589
                source_package_name = rec.SourcePkg();
 
590
 
 
591
              if(version_source == cmdline_version_version)
 
592
                {
 
593
                  const std::string source_version =
 
594
                    rec.SourceVer().empty() ? ver.VerStr() : rec.SourceVer();
 
595
 
 
596
                  rval = find_source_package(source_package_name, source_version);
 
597
                }
 
598
            }
 
599
          // Last-ditch effort: if no matching version was found but
 
600
          // a source package can be found, use that and try again below.
 
601
          else if(!pkg.VersionList().end())
 
602
            {
 
603
              pkgRecords::Parser &rec =
 
604
                apt_package_records->Lookup(pkg.VersionList().FileList());
 
605
 
 
606
              if(!rec.SourcePkg().empty())
 
607
                source_package_name = rec.SourcePkg();
 
608
            }
 
609
        }
 
610
 
 
611
      if(!rval.valid())
 
612
        {
 
613
          switch(version_source)
 
614
            {
 
615
            case cmdline_version_cand:
 
616
              rval = find_source_package(source_package_name);
 
617
              break;
 
618
 
 
619
            case cmdline_version_archive:
 
620
              _error->DumpErrors();
 
621
              rval = find_source_by_archive(source_package_name, version_source_string);
 
622
              break;
 
623
 
 
624
            case cmdline_version_version:
 
625
              rval = find_source_package(source_package_name, version_source_string);
 
626
              break;
 
627
            }
 
628
        }
 
629
 
 
630
      return rval;
 
631
    }
 
632
 
 
633
    void apply_user_tags(const std::vector<tag_application> &user_tags)
 
634
    {
 
635
      using namespace matching;
 
636
      for(pkgCache::PkgIterator pkg = (*apt_cache_file)->PkgBegin();
 
637
          !pkg.end(); ++pkg)
 
638
        {
 
639
          for(std::vector<tag_application>::const_iterator it = 
 
640
                user_tags.begin(); it != user_tags.end(); ++it)
 
641
            {
 
642
              bool applicable = false;
 
643
              if(it->get_matcher() != NULL)
 
644
                {
 
645
                  if(matching::apply_matcher(it->get_matcher(), pkg,
 
646
                                   *apt_cache_file,
 
647
                                   *apt_package_records))
 
648
                    applicable = true;
 
649
                }
 
650
              else
 
651
                {
 
652
                  const pkgDepCache::StateCache &state = (*apt_cache_file)[pkg];
 
653
                  // Perhaps we should somehow filter out automatic
 
654
                  // changes here, but that's hard and might be
 
655
                  // unpredictable (which would make the user sad).
 
656
                  // Instead we just add the tag to all packages that
 
657
                  // are being modified.
 
658
                  if(!state.Keep())
 
659
                    applicable = true;
 
660
                }
 
661
 
 
662
              if(applicable)
 
663
                {
 
664
                  if(it->get_is_add())
 
665
                    (*apt_cache_file)->attach_user_tag(pkg, it->get_tag(), NULL);
 
666
                  else
 
667
                    (*apt_cache_file)->detach_user_tag(pkg, it->get_tag(), NULL);
 
668
                }
 
669
            }
 
670
        }
 
671
    }
 
672
  }
 
673
}