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>
21
#include <cwidget/fragment.h>
19
22
#include <cwidget/toplevel.h>
23
#include <cwidget/generic/util/ssprintf.h>
25
#include <sigc++/bind.h>
21
26
#include <sigc++/functors/ptr_fun.h>
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>
37
namespace cw = cwidget;
41
const int no_install_run_from_ui_preview_return = -1;
42
const int ui_preview_install_failed_return = -1;
44
// Completion routine for the UI preview; causes the program to
45
// return 0 if the install succeded and 1 otherwise.
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
51
void ui_preview_complete(bool success, int *result)
53
*result = success ? 0 : ui_preview_install_failed_return;
59
int result = no_install_run_from_ui_preview_return;
26
62
file_quit.connect(sigc::ptr_fun(cwidget::toplevel::exitmain));
63
install_finished.connect(sigc::bind(sigc::ptr_fun(ui_preview_complete),
27
65
do_package_run_or_show_preview();
32
70
void ui_solution_screen()
172
download_manager::result cmdline_do_download(download_manager *m)
213
/** \brief Used to display some statistics about how the cache
214
* changed after an update.
216
* Perhaps this should be extended to other commands too?
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;
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),
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; }
243
stats compute_apt_stats()
245
int num_upgradable = 0;
248
std::set<std::string> obsolete;
250
if(apt_cache_file == NULL)
251
return stats(0, 0, 0, obsolete);
253
for(pkgCache::PkgIterator p = (*apt_cache_file)->PkgBegin();
257
obsolete.insert(p.Name());
259
const pkgDepCache::StateCache &state = (*apt_cache_file)[p];
260
const aptitudeDepCache::aptitude_state &estate =
261
(*apt_cache_file)->get_ext_state(p);
263
// Q: this will count to-be-removed packages, should it?
264
if(state.Status != 2 && state.Upgradable())
267
if(state.NowBroken())
270
if((state.Status != 2 || state.CandidateVer != NULL) &&
275
return stats(num_broken, num_upgradable, num_new, obsolete);
278
void show_stats_change(stats initial, stats final,
283
using cw::util::ssprintf;
285
std::vector<cw::fragment *> fragments;
288
(show_unchanged && final.get_num_broken() != 0) ||
289
final.get_num_broken() != initial.get_num_broken())
292
ssprintf(ngettext("%d broken [%+d]",
294
final.get_num_broken()),
295
final.get_num_broken(),
296
final.get_num_broken() - initial.get_num_broken());
298
fragments.push_back(cw::text_fragment(change));
302
(show_unchanged && final.get_num_upgradable() != 0) ||
303
final.get_num_upgradable() != initial.get_num_upgradable())
306
ssprintf(ngettext("%d update [%+d]",
308
final.get_num_upgradable()),
309
final.get_num_upgradable(),
310
final.get_num_upgradable() - initial.get_num_upgradable());
312
fragments.push_back(cw::text_fragment(change));
316
(show_unchanged && final.get_num_new() != 0) ||
317
final.get_num_new() != initial.get_num_new())
320
ssprintf(ngettext("%d new [%+d]",
322
final.get_num_new()),
324
final.get_num_new() - initial.get_num_new());
326
fragments.push_back(cw::text_fragment(change));
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", ")));
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)
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())));
347
else if(new_obsolete.size() > 0)
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));
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", "))));
361
if(output_fragments.size() > 0)
363
cw::fragment *f = join_fragments(output_fragments, L"\n");
365
update_screen_width();
366
std::cout << f->layout(screen_width, screen_width, cw::style());
372
download_manager::result cmdline_do_download(download_manager *m,
375
stats initial_stats(0, 0, 0, std::set<std::string>());
174
376
OpTextProgress progress(aptcfg->FindI("Quiet", 0));
378
if(aptcfg->FindI("Quiet", 0) == 0)
380
// This does exactly what we want: nothing if the cache is
381
// already loaded, and loads the cache with a minimum of frills
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();
175
390
std::auto_ptr<download_signal_log> log(gen_cmdline_download_progress());
392
// Dump errors here because prepare() might check for pending errors
393
// and think something failed.
394
_error->DumpErrors();
177
396
if(!m->prepare(progress, *log.get(), log.get()))
178
397
return download_manager::failure;
187
406
while(finish_res == download_manager::do_again);
408
stats final_stats(0, 0, 0, std::set<std::string>());
409
if(aptcfg->FindI("Quiet", 0) == 0)
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);
189
418
return finish_res;
421
bool cmdline_is_search_pattern(const std::string &s)
423
return s.find_first_of("~?") != s.npos;
432
source_package find_source_package(const std::string &source_name,
433
const std::string &source_version)
435
if(apt_source_list == NULL)
438
pkgSrcRecords records(*apt_source_list);
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());
448
// Find the most recent source package for the given name.
449
source_package find_source_package(const std::string &source_name)
451
if(apt_source_list == NULL)
454
pkgSrcRecords records(*apt_source_list);
457
pkgSrcRecords::Parser *parser = records.Find(source_name.c_str());
458
source_package rval = parser;
460
while(parser != NULL)
462
if(_system->VS->CmpVersion(rval.get_version(), parser->Version()) < 0)
464
parser = records.Find(source_name.c_str());
471
source_package::source_package()
475
source_package::source_package(pkgSrcRecords::Parser *parser)
479
package = parser->Package();
480
version = parser->Version();
481
maintainer = parser->Maintainer();
482
section = parser->Section();
484
if(parser->Binaries() != NULL)
486
for(const char **b = parser->Binaries(); *b != NULL; ++b)
487
binaries.push_back(*b);
490
parser->BuildDepends(build_deps, false);
494
source_package find_source_by_archive(const std::string &source_name,
495
const std::string &archive)
497
if(apt_source_list == NULL)
500
for(pkgSourceList::const_iterator i = apt_source_list->begin();
501
i != apt_source_list->end(); ++i)
503
if((*i)->GetDist() != archive)
506
vector<pkgIndexFile *> *indexes = (*i)->GetIndexFiles();
508
for(vector<pkgIndexFile *>::const_iterator j = indexes->begin();
509
j != indexes->end(); ++j)
511
std::auto_ptr<pkgSrcRecords::Parser> p((*j)->CreateSrcParser());
513
if(_error->PendingError())
514
return source_package();
517
// Step through the file until we reach the end or find
519
while(p.get()->Step() == true)
521
if(_error->PendingError() == true)
522
return source_package();
524
if(p.get()->Package() == source_name)
525
return source_package(p.get());
531
return source_package();
534
source_package find_source_package(const std::string &package,
535
cmdline_version_source version_source,
536
const std::string &version_source_string_orig)
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)
543
string default_release = aptcfg->Find("APT::Default-Release");
544
if(version_source == cmdline_version_cand && !default_release.empty())
546
version_source = cmdline_version_archive;
547
version_source_string = default_release;
550
pkgCache::PkgIterator pkg = (*apt_cache_file)->FindPkg(package);
551
std::string source_package_name = package;
555
// First look for a source of the given name.
556
switch(version_source)
558
case cmdline_version_cand:
559
rval = find_source_package(source_package_name);
562
case cmdline_version_archive:
563
_error->DumpErrors();
564
rval = find_source_by_archive(source_package_name, version_source_string);
567
case cmdline_version_version:
568
rval = find_source_package(source_package_name, version_source_string);
575
// If no source of that name exists, try to find a real package
576
// and use its source.
579
pkgCache::VerIterator ver = cmdline_find_ver(pkg,
581
version_source_string);
585
pkgRecords::Parser &rec =
586
apt_package_records->Lookup(ver.FileList());
588
if(!rec.SourcePkg().empty())
589
source_package_name = rec.SourcePkg();
591
if(version_source == cmdline_version_version)
593
const std::string source_version =
594
rec.SourceVer().empty() ? ver.VerStr() : rec.SourceVer();
596
rval = find_source_package(source_package_name, source_version);
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())
603
pkgRecords::Parser &rec =
604
apt_package_records->Lookup(pkg.VersionList().FileList());
606
if(!rec.SourcePkg().empty())
607
source_package_name = rec.SourcePkg();
613
switch(version_source)
615
case cmdline_version_cand:
616
rval = find_source_package(source_package_name);
619
case cmdline_version_archive:
620
_error->DumpErrors();
621
rval = find_source_by_archive(source_package_name, version_source_string);
624
case cmdline_version_version:
625
rval = find_source_package(source_package_name, version_source_string);
633
void apply_user_tags(const std::vector<tag_application> &user_tags)
635
using namespace matching;
636
for(pkgCache::PkgIterator pkg = (*apt_cache_file)->PkgBegin();
639
for(std::vector<tag_application>::const_iterator it =
640
user_tags.begin(); it != user_tags.end(); ++it)
642
bool applicable = false;
643
if(it->get_matcher() != NULL)
645
if(matching::apply_matcher(it->get_matcher(), pkg,
647
*apt_package_records))
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.
665
(*apt_cache_file)->attach_user_tag(pkg, it->get_tag(), NULL);
667
(*apt_cache_file)->detach_user_tag(pkg, it->get_tag(), NULL);