No flags found
Use flags to group coverage reports by test type, project and/or folders.
Then setup custom commit statuses and notifications for each flag.
e.g., #unittest #integration
#production #enterprise
#frontend #backend
15f32c4
... +34 ...
e5f9d66
Use flags to group coverage reports by test type, project and/or folders.
Then setup custom commit statuses and notifications for each flag.
e.g., #unittest #integration
#production #enterprise
#frontend #backend
| 1018 | 1018 | return false; |
|
| 1019 | 1019 | } |
|
| 1020 | 1020 | /*}}}*/ |
|
| 1021 | - | ||
| 1022 | - | /*}}}*/ |
|
| 1023 | - | int pkgAcquire::Item::Priority() /*{{{*/ |
|
| 1021 | + | int pkgAcquire::Item::Priority() /*{{{*/ |
|
| 1024 | 1022 | { |
|
| 1025 | 1023 | // Stage 1: Meta indices and diff indices |
|
| 1026 | 1024 | // - those need to be fetched first to have progress reporting working |
| 1925 | 1923 | } |
|
| 1926 | 1924 | else if(MetaIndex->CheckAuthDone(Message) == true) |
|
| 1927 | 1925 | { |
|
| 1928 | - | if (TransactionManager->IMSHit == false) |
|
| 1926 | + | auto const Releasegpg = GetFinalFilename(); |
|
| 1927 | + | auto const Release = MetaIndex->GetFinalFilename(); |
|
| 1928 | + | // if this is an IMS-Hit on Release ensure we also have the the Release.gpg file stored |
|
| 1929 | + | // (previously an unknown pubkey) – but only if the Release file exists locally (unlikely |
|
| 1930 | + | // event of InRelease removed from the mirror causing fallback but still an IMS-Hit) |
|
| 1931 | + | if (TransactionManager->IMSHit == false || |
|
| 1932 | + | (FileExists(Releasegpg) == false && FileExists(Release) == true)) |
|
| 1929 | 1933 | { |
|
| 1930 | - | TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename()); |
|
| 1931 | - | TransactionManager->TransactionStageCopy(MetaIndex, MetaIndex->DestFile, MetaIndex->GetFinalFilename()); |
|
| 1934 | + | TransactionManager->TransactionStageCopy(this, DestFile, Releasegpg); |
|
| 1935 | + | TransactionManager->TransactionStageCopy(MetaIndex, MetaIndex->DestFile, Release); |
|
| 1932 | 1936 | } |
|
| 1933 | 1937 | } |
|
| 1934 | 1938 | else if (MetaIndex->Status != StatAuthError) |
| 2051 | 2055 | { |
|
| 2052 | 2056 | // list cleanup needs to know that this file as well as the already |
|
| 2053 | 2057 | // present index is ours, so we create an empty diff to save it for us |
|
| 2054 | - | new pkgAcqIndexDiffs(Owner, TransactionManager, Target); |
|
| 2058 | + | new pkgAcqIndexDiffs(Owner, TransactionManager, Target, UsedMirror, Target.URI); |
|
| 2055 | 2059 | } |
|
| 2056 | 2060 | /*}}}*/ |
|
| 2057 | 2061 | static bool RemoveFileForBootstrapLinking(bool const Debug, std::string const &For, std::string const &Boot)/*{{{*/ |
| 2427 | 2431 | } |
|
| 2428 | 2432 | } |
|
| 2429 | 2433 | ||
| 2434 | + | std::string indexURI = Desc.URI; |
|
| 2435 | + | auto const byhashidx = indexURI.find("/by-hash/"); |
|
| 2436 | + | if (byhashidx != std::string::npos) |
|
| 2437 | + | indexURI = indexURI.substr(0, byhashidx - strlen(".diff")); |
|
| 2438 | + | else |
|
| 2439 | + | { |
|
| 2440 | + | auto end = indexURI.length() - strlen(".diff/Index"); |
|
| 2441 | + | if (CurrentCompressionExtension != "uncompressed") |
|
| 2442 | + | end -= (1 + CurrentCompressionExtension.length()); |
|
| 2443 | + | indexURI = indexURI.substr(0, end); |
|
| 2444 | + | } |
|
| 2445 | + | ||
| 2430 | 2446 | if (pdiff_merge == false) |
|
| 2431 | - | new pkgAcqIndexDiffs(Owner, TransactionManager, Target, available_patches); |
|
| 2447 | + | new pkgAcqIndexDiffs(Owner, TransactionManager, Target, UsedMirror, indexURI, available_patches); |
|
| 2432 | 2448 | else |
|
| 2433 | 2449 | { |
|
| 2434 | 2450 | diffs = new std::vector<pkgAcqIndexMergeDiffs*>(available_patches.size()); |
|
| 2435 | 2451 | for(size_t i = 0; i < available_patches.size(); ++i) |
|
| 2436 | 2452 | (*diffs)[i] = new pkgAcqIndexMergeDiffs(Owner, TransactionManager, |
|
| 2437 | - | Target, |
|
| 2453 | + | Target, UsedMirror, indexURI, |
|
| 2438 | 2454 | available_patches[i], |
|
| 2439 | 2455 | diffs); |
|
| 2440 | 2456 | } |
| 2504 | 2520 | pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire * const Owner, |
|
| 2505 | 2521 | pkgAcqMetaClearSig * const TransactionManager, |
|
| 2506 | 2522 | IndexTarget const &Target, |
|
| 2523 | + | std::string const &indexUsedMirror, std::string const &indexURI, |
|
| 2507 | 2524 | vector<DiffInfo> const &diffs) |
|
| 2508 | - | : pkgAcqBaseIndex(Owner, TransactionManager, Target), d(NULL), |
|
| 2525 | + | : pkgAcqBaseIndex(Owner, TransactionManager, Target), indexURI(indexURI), |
|
| 2509 | 2526 | available_patches(diffs) |
|
| 2510 | 2527 | { |
|
| 2511 | 2528 | DestFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target); |
| 2516 | 2533 | Description = Target.Description; |
|
| 2517 | 2534 | Desc.ShortDesc = Target.ShortDesc; |
|
| 2518 | 2535 | ||
| 2536 | + | UsedMirror = indexUsedMirror; |
|
| 2537 | + | if (UsedMirror == "DIRECT") |
|
| 2538 | + | UsedMirror.clear(); |
|
| 2539 | + | else if (UsedMirror.empty() == false && Description.find(" ") != string::npos) |
|
| 2540 | + | Description.replace(0, Description.find(" "), UsedMirror); |
|
| 2541 | + | ||
| 2519 | 2542 | if(available_patches.empty() == true) |
|
| 2520 | 2543 | { |
|
| 2521 | 2544 | // we are done (yeah!), check hashes against the final file |
| 2630 | 2653 | } |
|
| 2631 | 2654 | ||
| 2632 | 2655 | // queue the right diff |
|
| 2633 | - | Desc.URI = Target.URI + ".diff/" + available_patches[0].file + ".gz"; |
|
| 2656 | + | Desc.URI = indexURI + ".diff/" + available_patches[0].file + ".gz"; |
|
| 2634 | 2657 | Desc.Description = Description + " " + available_patches[0].file + string(".pdiff"); |
|
| 2635 | 2658 | DestFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI + ".diff/" + available_patches[0].file), Target); |
|
| 2636 | 2659 |
| 2683 | 2706 | // see if there is more to download |
|
| 2684 | 2707 | if(available_patches.empty() == false) |
|
| 2685 | 2708 | { |
|
| 2686 | - | new pkgAcqIndexDiffs(Owner, TransactionManager, Target, available_patches); |
|
| 2709 | + | new pkgAcqIndexDiffs(Owner, TransactionManager, Target, UsedMirror, indexURI, available_patches); |
|
| 2687 | 2710 | Finish(); |
|
| 2688 | 2711 | } else { |
|
| 2689 | 2712 | DestFile = PatchedFile; |
| 2712 | 2735 | pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire * const Owner, |
|
| 2713 | 2736 | pkgAcqMetaClearSig * const TransactionManager, |
|
| 2714 | 2737 | IndexTarget const &Target, |
|
| 2738 | + | std::string const &indexUsedMirror, std::string const &indexURI, |
|
| 2715 | 2739 | DiffInfo const &patch, |
|
| 2716 | 2740 | std::vector<pkgAcqIndexMergeDiffs*> const * const allPatches) |
|
| 2717 | - | : pkgAcqBaseIndex(Owner, TransactionManager, Target), d(NULL), |
|
| 2718 | - | patch(patch), allPatches(allPatches), State(StateFetchDiff) |
|
| 2741 | + | : pkgAcqBaseIndex(Owner, TransactionManager, Target), indexURI(indexURI), |
|
| 2742 | + | patch(patch), allPatches(allPatches), State(StateFetchDiff) |
|
| 2719 | 2743 | { |
|
| 2720 | 2744 | Debug = _config->FindB("Debug::pkgAcquire::Diffs",false); |
|
| 2721 | 2745 | ||
| 2722 | - | Desc.Owner = this; |
|
| 2723 | 2746 | Description = Target.Description; |
|
| 2747 | + | UsedMirror = indexUsedMirror; |
|
| 2748 | + | if (UsedMirror == "DIRECT") |
|
| 2749 | + | UsedMirror.clear(); |
|
| 2750 | + | else if (UsedMirror.empty() == false && Description.find(" ") != string::npos) |
|
| 2751 | + | Description.replace(0, Description.find(" "), UsedMirror); |
|
| 2752 | + | ||
| 2753 | + | Desc.Owner = this; |
|
| 2724 | 2754 | Desc.ShortDesc = Target.ShortDesc; |
|
| 2725 | - | Desc.URI = Target.URI + ".diff/" + patch.file + ".gz"; |
|
| 2755 | + | Desc.URI = indexURI + ".diff/" + patch.file + ".gz"; |
|
| 2726 | 2756 | Desc.Description = Description + " " + patch.file + ".pdiff"; |
|
| 2727 | - | DestFile = GetPartialFileNameFromURI(Desc.URI); |
|
| 2757 | + | DestFile = GetPartialFileNameFromURI(Target.URI + ".diff/" + patch.file + ".gz"); |
|
| 2728 | 2758 | ||
| 2729 | 2759 | if(Debug) |
|
| 2730 | 2760 | std::clog << "pkgAcqIndexMergeDiffs: " << Desc.URI << std::endl; |
| 143 | 143 | // of each array is the key, entry 1 is the value. |
|
| 144 | 144 | const std::pair<const char *, const char *> PackageProcessingOps[] = { |
|
| 145 | 145 | std::make_pair("install", N_("Installing %s")), |
|
| 146 | + | // we don't care for the difference |
|
| 147 | + | std::make_pair("upgrade", N_("Installing %s")), |
|
| 146 | 148 | std::make_pair("configure", N_("Configuring %s")), |
|
| 147 | 149 | std::make_pair("remove", N_("Removing %s")), |
|
| 148 | 150 | std::make_pair("purge", N_("Completely removing %s")), |
| 615 | 617 | { |
|
| 616 | 618 | pkgname = APT::String::Strip(list[2]); |
|
| 617 | 619 | action = APT::String::Strip(list[1]); |
|
| 618 | - | // we don't care for the difference (as dpkg doesn't really either) |
|
| 619 | - | if (action == "upgrade") |
|
| 620 | - | action = "install"; |
|
| 621 | 620 | } |
|
| 622 | 621 | // "status" has the form: "status: pkg: state" |
|
| 623 | - | // with state in ["half-installed", "unpacked", "half-configured", |
|
| 622 | + | // with state in ["half-installed", "unpacked", "half-configured", |
|
| 624 | 623 | // "installed", "config-files", "not-installed"] |
|
| 625 | 624 | else if (prefix == "status") |
|
| 626 | 625 | { |
|
| 627 | 626 | pkgname = APT::String::Strip(list[1]); |
|
| 628 | 627 | action = APT::String::Strip(list[2]); |
|
| 629 | - | } else { |
|
| 630 | - | if (Debug == true) |
|
| 631 | - | std::clog << "unknown prefix '" << prefix << "'" << std::endl; |
|
| 632 | - | return; |
|
| 633 | - | } |
|
| 634 | - | ||
| 635 | 628 | ||
| 636 | - | /* handle the special cases first: |
|
| 629 | + | /* handle the special cases first: |
|
| 637 | 630 | ||
| 638 | - | errors look like this: |
|
| 639 | - | 'status: /var/cache/apt/archives/krecipes_0.8.1-0ubuntu1_i386.deb : error : trying to overwrite `/usr/share/doc/kde/HTML/en/krecipes/krectip.png', which is also in package krecipes-data |
|
| 640 | - | and conffile-prompt like this |
|
| 641 | - | 'status:/etc/compiz.conf/compiz.conf : conffile-prompt: 'current-conffile' 'new-conffile' useredited distedited |
|
| 642 | - | */ |
|
| 643 | - | if (prefix == "status") |
|
| 644 | - | { |
|
| 631 | + | errors look like this: |
|
| 632 | + | 'status: /var/cache/apt/archives/krecipes_0.8.1-0ubuntu1_i386.deb : error : trying to overwrite `/usr/share/doc/kde/HTML/en/krecipes/krectip.png', which is also in package krecipes-data |
|
| 633 | + | and conffile-prompt like this |
|
| 634 | + | 'status:/etc/compiz.conf/compiz.conf : conffile-prompt: 'current-conffile' 'new-conffile' useredited distedited |
|
| 635 | + | */ |
|
| 645 | 636 | if(action == "error") |
|
| 646 | 637 | { |
|
| 647 | - | d->progress->Error(pkgname, PackagesDone, PackagesTotal, |
|
| 648 | - | list[3]); |
|
| 649 | - | pkgFailures++; |
|
| 638 | + | d->progress->Error(pkgname, PackagesDone, PackagesTotal, list[3]); |
|
| 639 | + | ++pkgFailures; |
|
| 650 | 640 | WriteApportReport(pkgname.c_str(), list[3].c_str()); |
|
| 651 | 641 | return; |
|
| 652 | 642 | } |
|
| 653 | 643 | else if(action == "conffile-prompt") |
|
| 654 | 644 | { |
|
| 655 | - | d->progress->ConffilePrompt(pkgname, PackagesDone, PackagesTotal, |
|
| 656 | - | list[3]); |
|
| 645 | + | d->progress->ConffilePrompt(pkgname, PackagesDone, PackagesTotal, list[3]); |
|
| 657 | 646 | return; |
|
| 658 | 647 | } |
|
| 648 | + | } else { |
|
| 649 | + | if (Debug == true) |
|
| 650 | + | std::clog << "unknown prefix '" << prefix << "'" << std::endl; |
|
| 651 | + | return; |
|
| 659 | 652 | } |
|
| 660 | 653 | ||
| 661 | - | // at this point we know that we should have a valid pkgname, so build all |
|
| 662 | - | // the info from it |
|
| 663 | - | ||
| 664 | - | // dpkg does not always send "pkgname:arch" so we add it here if needed |
|
| 654 | + | // At this point we have a pkgname, but it might not be arch-qualified ! |
|
| 665 | 655 | if (pkgname.find(":") == std::string::npos) |
|
| 666 | 656 | { |
|
| 667 | - | // find the package in the group that is touched by dpkg |
|
| 668 | - | // if there are multiple pkgs dpkg would send us a full pkgname:arch |
|
| 669 | 657 | pkgCache::GrpIterator Grp = Cache.FindGrp(pkgname); |
|
| 670 | - | if (Grp.end() == false) |
|
| 671 | - | for (auto P = Grp.PackageList(); P.end() != true; P = Grp.NextPkg(P)) |
|
| 672 | - | if(Cache[P].Keep() == false || Cache[P].ReInstall() == true) |
|
| 658 | + | /* No arch means that dpkg believes there can only be one package |
|
| 659 | + | this can refer to so lets see what could be candidates here: */ |
|
| 660 | + | std::vector<pkgCache::PkgIterator> candset; |
|
| 661 | + | for (auto P = Grp.PackageList(); P.end() != true; P = Grp.NextPkg(P)) |
|
| 662 | + | { |
|
| 663 | + | if (PackageOps.find(P.FullName()) != PackageOps.end()) |
|
| 664 | + | candset.push_back(P); |
|
| 665 | + | // packages can disappear without them having any interaction itself |
|
| 666 | + | // so we have to consider these as candidates, too |
|
| 667 | + | else if (P->CurrentVer != 0 && action == "disappear") |
|
| 668 | + | candset.push_back(P); |
|
| 669 | + | } |
|
| 670 | + | if (unlikely(candset.empty())) |
|
| 671 | + | { |
|
| 672 | + | if (Debug == true) |
|
| 673 | + | std::clog << "unable to figure out which package is dpkg refering to with '" << pkgname << "'! (1)" << std::endl; |
|
| 674 | + | return; |
|
| 675 | + | } |
|
| 676 | + | else if (candset.size() == 1) // we are lucky |
|
| 677 | + | pkgname = candset.cbegin()->FullName(); |
|
| 678 | + | else |
|
| 679 | + | { |
|
| 680 | + | /* here be dragons^Wassumptions about dpkg: |
|
| 681 | + | - an M-A:same version is always arch-qualified |
|
| 682 | + | - a package from a foreign arch is (in newer versions) */ |
|
| 683 | + | size_t installedInstances = 0, wannabeInstances = 0; |
|
| 684 | + | for (auto const &P: candset) |
|
| 685 | + | { |
|
| 686 | + | if (P->CurrentVer != 0) |
|
| 687 | + | { |
|
| 688 | + | ++installedInstances; |
|
| 689 | + | if (Cache[P].Delete() == false) |
|
| 690 | + | ++wannabeInstances; |
|
| 691 | + | } |
|
| 692 | + | else if (Cache[P].Install()) |
|
| 693 | + | ++wannabeInstances; |
|
| 694 | + | } |
|
| 695 | + | // the package becomes M-A:same, so we are still talking about current |
|
| 696 | + | if (installedInstances == 1 && wannabeInstances >= 2) |
|
| 697 | + | { |
|
| 698 | + | for (auto const &P: candset) |
|
| 673 | 699 | { |
|
| 674 | - | auto fullname = P.FullName(); |
|
| 675 | - | if (Cache[P].Delete() && PackageOps[fullname].size() <= PackageOpsDone[fullname]) |
|
| 700 | + | if (P->CurrentVer == 0) |
|
| 676 | 701 | continue; |
|
| 677 | - | pkgname = std::move(fullname); |
|
| 702 | + | pkgname = P.FullName(); |
|
| 703 | + | break; |
|
| 704 | + | } |
|
| 705 | + | } |
|
| 706 | + | // the package was M-A:same, it isn't now, so we can only talk about that |
|
| 707 | + | else if (installedInstances >= 2 && wannabeInstances == 1) |
|
| 708 | + | { |
|
| 709 | + | for (auto const &P: candset) |
|
| 710 | + | { |
|
| 711 | + | auto const IV = Cache[P].InstVerIter(Cache); |
|
| 712 | + | if (IV.end()) |
|
| 713 | + | continue; |
|
| 714 | + | pkgname = P.FullName(); |
|
| 678 | 715 | break; |
|
| 679 | 716 | } |
|
| 717 | + | } |
|
| 718 | + | // that is a crossgrade |
|
| 719 | + | else if (installedInstances == 1 && wannabeInstances == 1 && candset.size() == 2) |
|
| 720 | + | { |
|
| 721 | + | auto const PkgHasCurrentVersion = [](pkgCache::PkgIterator const &P) { return P->CurrentVer != 0; }; |
|
| 722 | + | auto const P = std::find_if(candset.begin(), candset.end(), PkgHasCurrentVersion); |
|
| 723 | + | if (unlikely(P == candset.end())) |
|
| 724 | + | { |
|
| 725 | + | if (Debug == true) |
|
| 726 | + | std::clog << "situation for '" << pkgname << "' looked like a crossgrade, but no current version?!" << std::endl; |
|
| 727 | + | return; |
|
| 728 | + | } |
|
| 729 | + | auto fullname = P->FullName(); |
|
| 730 | + | if (PackageOps[fullname].size() != PackageOpsDone[fullname]) |
|
| 731 | + | pkgname = std::move(fullname); |
|
| 732 | + | else |
|
| 733 | + | pkgname = std::find_if_not(candset.begin(), candset.end(), PkgHasCurrentVersion)->FullName(); |
|
| 734 | + | } |
|
| 735 | + | // we are desperate: so "just" take the native one, but that might change mid-air, |
|
| 736 | + | // so we have to ask dpkg what it believes native is at the moment… all the time |
|
| 737 | + | else |
|
| 738 | + | { |
|
| 739 | + | std::vector<std::string> sArgs = debSystem::GetDpkgBaseCommand(); |
|
| 740 | + | sArgs.push_back("--print-architecture"); |
|
| 741 | + | int outputFd = -1; |
|
| 742 | + | pid_t const dpkgNativeArch = debSystem::ExecDpkg(sArgs, nullptr, &outputFd, true); |
|
| 743 | + | if (unlikely(dpkgNativeArch == -1)) |
|
| 744 | + | { |
|
| 745 | + | if (Debug == true) |
|
| 746 | + | std::clog << "calling dpkg failed to ask it for its current native architecture to expand '" << pkgname << "'!" << std::endl; |
|
| 747 | + | return; |
|
| 748 | + | } |
|
| 749 | + | FILE *dpkg = fdopen(outputFd, "r"); |
|
| 750 | + | if(dpkg != NULL) |
|
| 751 | + | { |
|
| 752 | + | char* buf = NULL; |
|
| 753 | + | size_t bufsize = 0; |
|
| 754 | + | if (getline(&buf, &bufsize, dpkg) != -1) |
|
| 755 | + | pkgname += ':' + bufsize; |
|
| 756 | + | free(buf); |
|
| 757 | + | fclose(dpkg); |
|
| 758 | + | } |
|
| 759 | + | ExecWait(dpkgNativeArch, "dpkg --print-architecture", true); |
|
| 760 | + | if (pkgname.find(':') != std::string::npos) |
|
| 761 | + | { |
|
| 762 | + | if (Debug == true) |
|
| 763 | + | std::clog << "unable to figure out which package is dpkg refering to with '" << pkgname << "'! (2)" << std::endl; |
|
| 764 | + | return; |
|
| 765 | + | } |
|
| 766 | + | } |
|
| 767 | + | } |
|
| 680 | 768 | } |
|
| 681 | 769 | ||
| 682 | 770 | std::string arch = ""; |
| 690 | 778 | // 'processing: action: pkg' |
|
| 691 | 779 | if(prefix == "processing") |
|
| 692 | 780 | { |
|
| 693 | - | const std::pair<const char *, const char *> * const iter = |
|
| 694 | - | std::find_if(PackageProcessingOpsBegin, |
|
| 695 | - | PackageProcessingOpsEnd, |
|
| 696 | - | MatchProcessingOp(action.c_str())); |
|
| 781 | + | auto const iter = std::find_if(PackageProcessingOpsBegin, PackageProcessingOpsEnd, MatchProcessingOp(action.c_str())); |
|
| 697 | 782 | if(iter == PackageProcessingOpsEnd) |
|
| 698 | 783 | { |
|
| 699 | 784 | if (Debug == true) |
| 709 | 794 | // short pkgnames? |
|
| 710 | 795 | if (action == "disappear") |
|
| 711 | 796 | handleDisappearAction(pkgname); |
|
| 797 | + | else if (action == "upgrade") |
|
| 798 | + | handleCrossUpgradeAction(pkgname); |
|
| 712 | 799 | return; |
|
| 713 | 800 | } |
|
| 714 | 801 | ||
| 715 | 802 | if (prefix == "status") |
|
| 716 | 803 | { |
|
| 717 | 804 | std::vector<struct DpkgState> &states = PackageOps[pkgname]; |
|
| 718 | - | if (action == "triggers-pending") |
|
| 719 | - | { |
|
| 720 | - | if (Debug == true) |
|
| 721 | - | std::clog << "(parsed from dpkg) pkg: " << pkgname |
|
| 722 | - | << " action: " << action << " (prefix 2 to " |
|
| 723 | - | << PackageOpsDone[pkgname] << " of " << states.size() << ")" << endl; |
|
| 724 | - | ||
| 725 | - | states.insert(states.begin(), {"installed", N_("Installed %s")}); |
|
| 726 | - | states.insert(states.begin(), {"half-configured", N_("Configuring %s")}); |
|
| 727 | - | PackagesTotal += 2; |
|
| 728 | - | } |
|
| 729 | - | else if(PackageOpsDone[pkgname] < states.size()) |
|
| 805 | + | if(PackageOpsDone[pkgname] < states.size()) |
|
| 730 | 806 | { |
|
| 731 | 807 | char const * next_action = states[PackageOpsDone[pkgname]].state; |
|
| 732 | 808 | if (next_action) |
| 763 | 839 | strprintf(msg, translation, i18n_pkgname.c_str()); |
|
| 764 | 840 | d->progress->StatusChanged(pkgname, PackagesDone, PackagesTotal, msg); |
|
| 765 | 841 | } |
|
| 766 | - | else if (action == "unpacked" && strcmp(next_action, "config-files") == 0) |
|
| 767 | - | { |
|
| 768 | - | // in a crossgrade what looked like a remove first is really an unpack over it |
|
| 769 | - | ++PackageOpsDone[pkgname]; |
|
| 770 | - | ++PackagesDone; |
|
| 771 | - | ||
| 772 | - | auto const Pkg = Cache.FindPkg(pkgname); |
|
| 773 | - | if (likely(Pkg.end() == false)) |
|
| 774 | - | { |
|
| 775 | - | auto const Grp = Pkg.Group(); |
|
| 776 | - | if (likely(Grp.end() == false)) |
|
| 777 | - | { |
|
| 778 | - | for (auto P = Grp.PackageList(); P.end() != true; P = Grp.NextPkg(P)) |
|
| 779 | - | if(Cache[P].Install()) |
|
| 780 | - | { |
|
| 781 | - | auto && Ops = PackageOps[P.FullName()]; |
|
| 782 | - | auto const unpackOp = std::find_if(Ops.cbegin(), Ops.cend(), [](DpkgState const &s) { return strcmp(s.state, "unpacked") == 0; }); |
|
| 783 | - | if (unpackOp != Ops.cend()) |
|
| 784 | - | { |
|
| 785 | - | auto const skipped = std::distance(Ops.cbegin(), unpackOp); |
|
| 786 | - | PackagesDone += skipped; |
|
| 787 | - | PackageOpsDone[P.FullName()] += skipped; |
|
| 788 | - | break; |
|
| 789 | - | } |
|
| 790 | - | } |
|
| 791 | - | } |
|
| 792 | - | } |
|
| 793 | - | } |
|
| 794 | 842 | } |
|
| 795 | 843 | } |
|
| 844 | + | else if (action == "triggers-pending") |
|
| 845 | + | { |
|
| 846 | + | if (Debug == true) |
|
| 847 | + | std::clog << "(parsed from dpkg) pkg: " << pkgname |
|
| 848 | + | << " action: " << action << " (prefix 2 to " |
|
| 849 | + | << PackageOpsDone[pkgname] << " of " << states.size() << ")" << endl; |
|
| 850 | + | ||
| 851 | + | states.insert(states.begin(), {"installed", N_("Installed %s")}); |
|
| 852 | + | states.insert(states.begin(), {"half-configured", N_("Configuring %s")}); |
|
| 853 | + | PackagesTotal += 2; |
|
| 854 | + | } |
|
| 796 | 855 | } |
|
| 797 | 856 | } |
|
| 798 | 857 | /*}}}*/ |
| 803 | 862 | if (unlikely(Pkg.end() == true)) |
|
| 804 | 863 | return; |
|
| 805 | 864 | ||
| 865 | + | // a disappeared package has no further actions |
|
| 866 | + | auto const ROps = PackageOps[Pkg.FullName()].size(); |
|
| 867 | + | auto && ROpsDone = PackageOpsDone[Pkg.FullName()]; |
|
| 868 | + | PackagesDone += ROps - ROpsDone; |
|
| 869 | + | ROpsDone = ROps; |
|
| 870 | + | ||
| 806 | 871 | // record the package name for display and stuff later |
|
| 807 | 872 | disappearedPkgs.insert(Pkg.FullName(true)); |
|
| 808 | 873 |
| 844 | 909 | } |
|
| 845 | 910 | } |
|
| 846 | 911 | /*}}}*/ |
|
| 912 | + | void pkgDPkgPM::handleCrossUpgradeAction(string const &pkgname) /*{{{*/ |
|
| 913 | + | { |
|
| 914 | + | // in a crossgrade what looked like a remove first is really an unpack over it |
|
| 915 | + | auto const Pkg = Cache.FindPkg(pkgname); |
|
| 916 | + | if (likely(Pkg.end() == false) && Cache[Pkg].Delete()) |
|
| 917 | + | { |
|
| 918 | + | auto const Grp = Pkg.Group(); |
|
| 919 | + | if (likely(Grp.end() == false)) |
|
| 920 | + | { |
|
| 921 | + | for (auto P = Grp.PackageList(); P.end() != true; P = Grp.NextPkg(P)) |
|
| 922 | + | if(Cache[P].Install()) |
|
| 923 | + | { |
|
| 924 | + | auto && Ops = PackageOps[P.FullName()]; |
|
| 925 | + | auto const unpackOp = std::find_if(Ops.cbegin(), Ops.cend(), [](DpkgState const &s) { return strcmp(s.state, "unpacked") == 0; }); |
|
| 926 | + | if (unpackOp != Ops.cend()) |
|
| 927 | + | { |
|
| 928 | + | // skip ahead in the crossgraded packages |
|
| 929 | + | auto const skipped = std::distance(Ops.cbegin(), unpackOp); |
|
| 930 | + | PackagesDone += skipped; |
|
| 931 | + | PackageOpsDone[P.FullName()] += skipped; |
|
| 932 | + | // finish the crossremoved package |
|
| 933 | + | auto const ROps = PackageOps[Pkg.FullName()].size(); |
|
| 934 | + | auto && ROpsDone = PackageOpsDone[Pkg.FullName()]; |
|
| 935 | + | PackagesDone += ROps - ROpsDone; |
|
| 936 | + | ROpsDone = ROps; |
|
| 937 | + | break; |
|
| 938 | + | } |
|
| 939 | + | } |
|
| 940 | + | } |
|
| 941 | + | } |
|
| 942 | + | } |
|
| 943 | + | /*}}}*/ |
|
| 847 | 944 | // DPkgPM::DoDpkgStatusFd /*{{{*/ |
|
| 848 | 945 | void pkgDPkgPM::DoDpkgStatusFd(int statusfd) |
|
| 849 | 946 | { |
| 1087 | 1184 | ++PackagesTotal; |
|
| 1088 | 1185 | return true; |
|
| 1089 | 1186 | }); |
|
| 1187 | + | if ((I.Op == Item::Remove || I.Op == Item::Purge) && I.Pkg->CurrentVer != 0) |
|
| 1188 | + | { |
|
| 1189 | + | if (I.Pkg->CurrentState == pkgCache::State::UnPacked || |
|
| 1190 | + | I.Pkg->CurrentState == pkgCache::State::HalfInstalled) |
|
| 1191 | + | { |
|
| 1192 | + | if (likely(strcmp(PackageOps[name][0].state, "half-configured") == 0)) |
|
| 1193 | + | { |
|
| 1194 | + | ++PackageOpsDone[name]; |
|
| 1195 | + | --PackagesTotal; |
|
| 1196 | + | } |
|
| 1197 | + | } |
|
| 1198 | + | } |
|
| 1090 | 1199 | } |
|
| 1091 | 1200 | /* one extra: We don't want the progress bar to reach 100%, especially not |
|
| 1092 | 1201 | if we call dpkg --configure --pending and process a bunch of triggers |
| 1327 | 1436 | if (I.Op == Item::Install && alreadyConfigured.insert(I.Pkg->ID).second == true) |
|
| 1328 | 1437 | AppendList.emplace_back(Item::Configure, I.Pkg); |
|
| 1329 | 1438 | for (auto Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg) |
|
| 1330 | - | if (Pkg.State() == pkgCache::PkgIterator::NeedsConfigure && alreadyConfigured.insert(Pkg->ID).second == true) |
|
| 1439 | + | if (Pkg.State() == pkgCache::PkgIterator::NeedsConfigure && |
|
| 1440 | + | Cache[Pkg].Delete() == false && alreadyConfigured.insert(Pkg->ID).second == true) |
|
| 1331 | 1441 | AppendList.emplace_back(Item::Configure, Pkg); |
|
| 1332 | 1442 | std::move(AppendList.begin(), AppendList.end(), std::back_inserter(List)); |
|
| 1333 | 1443 | } |
| 1397 | 1507 | dpkg_recursive_install = Cache.VS().CmpVersion("1.18.5", dpkgpkg.CurrentVer().VerStr()) <= 0; |
|
| 1398 | 1508 | } |
|
| 1399 | 1509 | // no point in doing this dance for a handful of packages only |
|
| 1400 | - | unsigned int const dpkg_recursive_install_min = _config->FindB("dpkg::install::recursive::minimum", 5); |
|
| 1510 | + | unsigned int const dpkg_recursive_install_min = _config->FindI("dpkg::install::recursive::minimum", 5); |
|
| 1401 | 1511 | // FIXME: workaround for dpkg bug, see our ./test-bug-740843-versioned-up-down-breaks test |
|
| 1402 | 1512 | bool const dpkg_recursive_install_numbered = _config->FindB("dpkg::install::recursive::numbered", true); |
|
| 1403 | 1513 |
| 1428 | 1538 | continue; |
|
| 1429 | 1539 | ||
| 1430 | 1540 | auto const Grp = I->Pkg.Group(); |
|
| 1431 | - | size_t installedInstances = 0; |
|
| 1541 | + | size_t installedInstances = 0, wannabeInstances = 0; |
|
| 1542 | + | bool multiArchInstances = false; |
|
| 1432 | 1543 | for (auto Pkg = Grp.PackageList(); Pkg.end() == false; Pkg = Grp.NextPkg(Pkg)) |
|
| 1433 | - | if (Pkg->CurrentVer != 0 || Cache[Pkg].Install()) |
|
| 1544 | + | { |
|
| 1545 | + | if (Pkg->CurrentVer != 0) |
|
| 1546 | + | { |
|
| 1434 | 1547 | ++installedInstances; |
|
| 1435 | - | if (installedInstances == 2) |
|
| 1548 | + | if (Cache[Pkg].Delete() == false) |
|
| 1549 | + | ++wannabeInstances; |
|
| 1550 | + | } |
|
| 1551 | + | else if (PackageOps.find(Pkg.FullName()) != PackageOps.end()) |
|
| 1552 | + | ++wannabeInstances; |
|
| 1553 | + | if (multiArchInstances == false) |
|
| 1554 | + | { |
|
| 1555 | + | auto const V = Cache[Pkg].InstVerIter(Cache); |
|
| 1556 | + | if (V.end() == false && (Pkg->CurrentVer == 0 || V != Pkg.CurrentVer())) |
|
| 1557 | + | multiArchInstances = ((V->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same); |
|
| 1558 | + | } |
|
| 1559 | + | } |
|
| 1560 | + | /* theoretically the installed check would be enough as some wannabe will |
|
| 1561 | + | be first and hence be the crossgrade we were looking for, but #844300 |
|
| 1562 | + | prevents this so we keep these situations explicit removes. |
|
| 1563 | + | It is also the reason why neither of them can be a M-A:same package */ |
|
| 1564 | + | if (installedInstances == 1 && wannabeInstances == 1 && multiArchInstances == false) |
|
| 1436 | 1565 | { |
|
| 1437 | 1566 | auto const FirstInstall = std::find_if_not(I, List.end(), |
|
| 1438 | 1567 | [](Item const &i) { return i.Op == Item::Remove || i.Op == Item::Purge; }); |
| 1994 | 2123 | ||
| 1995 | 2124 | if (noopDPkgInvocation == false) |
|
| 1996 | 2125 | { |
|
| 2126 | + | if (d->dpkg_error.empty() && (PackagesDone + 1) != PackagesTotal) |
|
| 2127 | + | { |
|
| 2128 | + | std::string pkglist; |
|
| 2129 | + | for (auto const &PO: PackageOps) |
|
| 2130 | + | if (PO.second.size() != PackageOpsDone[PO.first]) |
|
| 2131 | + | { |
|
| 2132 | + | if (pkglist.empty() == false) |
|
| 2133 | + | pkglist.append(" "); |
|
| 2134 | + | pkglist.append(PO.first); |
|
| 2135 | + | } |
|
| 2136 | + | /* who cares about correct progress? As we depend on it for skipping actions |
|
| 2137 | + | our parsing should be correct. People will no doubt be confused if they see |
|
| 2138 | + | this message, but the dpkg warning about unknown packages isn't much better |
|
| 2139 | + | from a user POV and combined we might have a chance to figure out what is wrong */ |
|
| 2140 | + | _error->Warning("APT had planned for dpkg to do more than it reported back (%u vs %u).\n" |
|
| 2141 | + | "Affected packages: %s", PackagesDone, PackagesTotal, pkglist.c_str()); |
|
| 2142 | + | } |
|
| 2143 | + | ||
| 1997 | 2144 | std::string const oldpkgcache = _config->FindFile("Dir::cache::pkgcache"); |
|
| 1998 | 2145 | if (oldpkgcache.empty() == false && RealFileExists(oldpkgcache) == true && |
|
| 1999 | 2146 | RemoveFile("pkgDPkgPM::Go", oldpkgcache)) |
| 931 | 931 | } |
|
| 932 | 932 | /*}}}*/ |
|
| 933 | 933 | // EDSP::WriteError - format an error message to be send to file descriptor /*{{{*/ |
|
| 934 | + | static std::string formatMessage(std::string const &msg) |
|
| 935 | + | { |
|
| 936 | + | return SubstVar(SubstVar(APT::String::Strip(msg), "\n\n", "\n.\n"), "\n", "\n "); |
|
| 937 | + | } |
|
| 934 | 938 | bool EDSP::WriteError(char const * const uuid, std::string const &message, FILE* output) { |
|
| 935 | 939 | fprintf(output, "Error: %s\n", uuid); |
|
| 936 | - | fprintf(output, "Message: %s\n\n", SubstVar(SubstVar(message, "\n\n", "\n.\n"), "\n", "\n ").c_str()); |
|
| 940 | + | fprintf(output, "Message: %s\n\n", formatMessage(message).c_str()); |
|
| 937 | 941 | return true; |
|
| 938 | 942 | } |
|
| 939 | 943 | bool EDSP::WriteError(char const * const uuid, std::string const &message, FileFd &output) { |
|
| 940 | 944 | return WriteOkay(output, "Error: ", uuid, "\n", |
|
| 941 | - | "Message: ", SubstVar(SubstVar(message, "\n\n", "\n.\n"), "\n", "\n "), |
|
| 945 | + | "Message: ", formatMessage(message), |
|
| 942 | 946 | "\n\n"); |
|
| 943 | 947 | } |
|
| 944 | 948 | /*}}}*/ |
| 662 | 662 | FileFd inp, out; |
|
| 663 | 663 | if (inp.Open(Path, FileFd::ReadOnly, FileFd::Extension) == false) |
|
| 664 | 664 | { |
|
| 665 | - | std::cerr << "FAILED to open inp " << Path << std::endl; |
|
| 665 | + | if (Debug == true) |
|
| 666 | + | std::clog << "FAILED to open inp " << Path << std::endl; |
|
| 666 | 667 | return _error->Error("Failed to open inp %s", Path.c_str()); |
|
| 667 | 668 | } |
|
| 668 | 669 | if (out.Open(Itm->DestFile, FileFd::WriteOnly | FileFd::Create | FileFd::Empty | FileFd::BufferedWrite, FileFd::Extension) == false) |
|
| 669 | 670 | { |
|
| 670 | - | std::cerr << "FAILED to open out " << Itm->DestFile << std::endl; |
|
| 671 | + | if (Debug == true) |
|
| 672 | + | std::clog << "FAILED to open out " << Itm->DestFile << std::endl; |
|
| 671 | 673 | return _error->Error("Failed to open out %s", Itm->DestFile.c_str()); |
|
| 672 | 674 | } |
|
| 673 | 675 |
| 686 | 688 | inp.Close(); |
|
| 687 | 689 | ||
| 688 | 690 | if (_error->PendingError() == true) { |
|
| 689 | - | std::cerr << "FAILED to read or write files" << std::endl; |
|
| 691 | + | if (Debug == true) |
|
| 692 | + | std::clog << "FAILED to read or write files" << std::endl; |
|
| 690 | 693 | return false; |
|
| 691 | 694 | } |
|
| 692 | 695 |
| 2778 | 2778 | return result; |
|
| 2779 | 2779 | } |
|
| 2780 | 2780 | /*}}}*/ |
|
| 2781 | - | std::string GetTempDir() /*{{{*/ |
|
| 2781 | + | static std::string APT_NONNULL(1) GetTempDirEnv(char const * const env) /*{{{*/ |
|
| 2782 | 2782 | { |
|
| 2783 | - | const char *tmpdir = getenv("TMPDIR"); |
|
| 2783 | + | const char *tmpdir = getenv(env); |
|
| 2784 | 2784 | ||
| 2785 | 2785 | #ifdef P_tmpdir |
|
| 2786 | 2786 | if (!tmpdir) |
| 2792 | 2792 | stat(tmpdir, &st) != 0 || (st.st_mode & S_IFDIR) == 0) // exists and is directory |
|
| 2793 | 2793 | tmpdir = "/tmp"; |
|
| 2794 | 2794 | else if (geteuid() != 0 && // root can do everything anyway |
|
| 2795 | - | faccessat(-1, tmpdir, R_OK | W_OK | X_OK, AT_EACCESS | AT_SYMLINK_NOFOLLOW) != 0) // current user has rwx access to directory |
|
| 2795 | + | faccessat(AT_FDCWD, tmpdir, R_OK | W_OK | X_OK, AT_EACCESS) != 0) // current user has rwx access to directory |
|
| 2796 | 2796 | tmpdir = "/tmp"; |
|
| 2797 | 2797 | ||
| 2798 | 2798 | return string(tmpdir); |
|
| 2799 | + | } |
|
| 2800 | + | /*}}}*/ |
|
| 2801 | + | std::string GetTempDir() /*{{{*/ |
|
| 2802 | + | { |
|
| 2803 | + | return GetTempDirEnv("TMPDIR"); |
|
| 2799 | 2804 | } |
|
| 2800 | 2805 | std::string GetTempDir(std::string const &User) |
|
| 2801 | 2806 | { |
| 3051 | 3056 | return _error->Error("Could restore a uid to root, privilege dropping did not work"); |
|
| 3052 | 3057 | } |
|
| 3053 | 3058 | ||
| 3059 | + | if (_config->FindB("APT::Sandbox::ResetEnvironment", true)) |
|
| 3060 | + | { |
|
| 3061 | + | setenv("HOME", pw->pw_dir, 1); |
|
| 3062 | + | setenv("USER", pw->pw_name, 1); |
|
| 3063 | + | setenv("USERNAME", pw->pw_name, 1); |
|
| 3064 | + | setenv("LOGNAME", pw->pw_name, 1); |
|
| 3065 | + | auto const shell = flNotDir(pw->pw_shell); |
|
| 3066 | + | if (shell == "false" || shell == "nologin") |
|
| 3067 | + | setenv("SHELL", "/bin/sh", 1); |
|
| 3068 | + | else |
|
| 3069 | + | setenv("SHELL", pw->pw_shell, 1); |
|
| 3070 | + | auto const apt_setenv_tmp = [](char const * const env) { |
|
| 3071 | + | auto const tmpdir = getenv(env); |
|
| 3072 | + | if (tmpdir != nullptr) |
|
| 3073 | + | { |
|
| 3074 | + | auto const ourtmpdir = GetTempDirEnv(env); |
|
| 3075 | + | if (ourtmpdir != tmpdir) |
|
| 3076 | + | setenv(env, ourtmpdir.c_str(), 1); |
|
| 3077 | + | } |
|
| 3078 | + | }; |
|
| 3079 | + | apt_setenv_tmp("TMPDIR"); |
|
| 3080 | + | apt_setenv_tmp("TEMPDIR"); |
|
| 3081 | + | apt_setenv_tmp("TMP"); |
|
| 3082 | + | apt_setenv_tmp("TEMP"); |
|
| 3083 | + | } |
|
| 3084 | + | ||
| 3054 | 3085 | return true; |
|
| 3055 | 3086 | } |
|
| 3056 | 3087 | /*}}}*/ |
| 779 | 779 | */ |
|
| 780 | 780 | class APT_HIDDEN pkgAcqIndexMergeDiffs : public pkgAcqBaseIndex |
|
| 781 | 781 | { |
|
| 782 | - | void * const d; |
|
| 782 | + | std::string const indexURI; |
|
| 783 | 783 | ||
| 784 | 784 | protected: |
|
| 785 | 785 |
| 830 | 830 | /** \brief Create an index merge-diff item. |
|
| 831 | 831 | * |
|
| 832 | 832 | * \param Owner The pkgAcquire object that owns this item. |
|
| 833 | - | * |
|
| 834 | - | * \param URI The URI of the package index file being |
|
| 835 | - | * reconstructed. |
|
| 836 | - | * |
|
| 837 | - | * \param URIDesc A long description of this item. |
|
| 838 | - | * |
|
| 839 | - | * \param ShortDesc A brief description of this item. |
|
| 840 | - | * |
|
| 833 | + | * \param TransactionManager responsible for this item |
|
| 834 | + | * \param Target we intend to built via pdiff patching |
|
| 835 | + | * \param baseURI is the URI used for the Index, but stripped down to Target |
|
| 836 | + | * \param DiffInfo of the patch in question |
|
| 841 | 837 | * \param patch contains infos about the patch this item is supposed |
|
| 842 | 838 | * to download which were read from the index |
|
| 843 | - | * |
|
| 844 | 839 | * \param allPatches contains all related items so that each item can |
|
| 845 | 840 | * check if it was the last one to complete the download step |
|
| 846 | 841 | */ |
|
| 847 | 842 | pkgAcqIndexMergeDiffs(pkgAcquire * const Owner, pkgAcqMetaClearSig * const TransactionManager, |
|
| 848 | - | IndexTarget const &Target, DiffInfo const &patch, |
|
| 849 | - | std::vector<pkgAcqIndexMergeDiffs*> const * const allPatches) APT_NONNULL(2, 3, 6); |
|
| 843 | + | IndexTarget const &Target, std::string const &indexUsedMirror, |
|
| 844 | + | std::string const &indexURI, DiffInfo const &patch, |
|
| 845 | + | std::vector<pkgAcqIndexMergeDiffs*> const * const allPatches) APT_NONNULL(2, 3, 8); |
|
| 850 | 846 | virtual ~pkgAcqIndexMergeDiffs(); |
|
| 851 | 847 | }; |
|
| 852 | 848 | /*}}}*/ |
| 863 | 859 | */ |
|
| 864 | 860 | class APT_HIDDEN pkgAcqIndexDiffs : public pkgAcqBaseIndex |
|
| 865 | 861 | { |
|
| 866 | - | void * const d; |
|
| 862 | + | std::string const indexURI; |
|
| 867 | 863 | ||
| 868 | 864 | private: |
|
| 869 | 865 |
| 943 | 939 | * \a diffs is empty, or QueueNextDiff() otherwise. |
|
| 944 | 940 | * |
|
| 945 | 941 | * \param Owner The pkgAcquire object that owns this item. |
|
| 946 | - | * |
|
| 947 | - | * \param URI The URI of the package index file being |
|
| 948 | - | * reconstructed. |
|
| 949 | - | * |
|
| 950 | - | * \param URIDesc A long description of this item. |
|
| 951 | - | * |
|
| 952 | - | * \param ShortDesc A brief description of this item. |
|
| 953 | - | * |
|
| 942 | + | * \param TransactionManager responsible for this item |
|
| 943 | + | * \param Target we want to built via pdiff patching |
|
| 944 | + | * \param baseURI is the URI used for the Index, but stripped down to Target |
|
| 954 | 945 | * \param diffs The remaining diffs from the index of diffs. They |
|
| 955 | 946 | * should be ordered so that each diff appears before any diff |
|
| 956 | 947 | * that depends on it. |
|
| 957 | 948 | */ |
|
| 958 | 949 | pkgAcqIndexDiffs(pkgAcquire * const Owner, pkgAcqMetaClearSig * const TransactionManager, |
|
| 959 | 950 | IndexTarget const &Target, |
|
| 951 | + | std::string const &indexUsedMirror, std::string const &indexURI, |
|
| 960 | 952 | std::vector<DiffInfo> const &diffs=std::vector<DiffInfo>()) APT_NONNULL(2, 3); |
|
| 961 | 953 | virtual ~pkgAcqIndexDiffs(); |
|
| 962 | 954 | }; |
| 136 | 136 | _error->PendingError() == true) |
|
| 137 | 137 | return false; |
|
| 138 | 138 | ||
| 139 | - | if (_config->FindB("APT::Get::Fix-Missing",false) == true && |
|
| 140 | - | _config->FindB("APT::Get::Download",true) == false) |
|
| 139 | + | if (_config->FindB("APT::Get::Download",true) == false) |
|
| 141 | 140 | { |
|
| 142 | 141 | bool Missing = false; |
|
| 143 | 142 | RemoveDownloadNeedingItemsFromFetcher(Fetcher, Missing); |
|
| 144 | 143 | if (Missing) |
|
| 145 | - | PM->FixMissing(); |
|
| 144 | + | { |
|
| 145 | + | if (_config->FindB("APT::Get::Fix-Missing",false)) |
|
| 146 | + | PM->FixMissing(); |
|
| 147 | + | else |
|
| 148 | + | return _error->Error(_("Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?")); |
|
| 149 | + | } |
|
| 146 | 150 | Fetcher.Shutdown(); |
|
| 147 | - | if (PM->GetArchives(&Fetcher,List,&Recs) == false || |
|
| 148 | - | _error->PendingError() == true) |
|
| 151 | + | if (_error->PendingError() == true) |
|
| 149 | 152 | return false; |
|
| 150 | 153 | } |
|
| 151 | 154 |
| 396 | 399 | /* Remove unused automatic packages */ |
|
| 397 | 400 | bool DoAutomaticRemove(CacheFile &Cache) |
|
| 398 | 401 | { |
|
| 399 | - | bool Debug = _config->FindI("Debug::pkgAutoRemove",false); |
|
| 402 | + | bool Debug = _config->FindB("Debug::pkgAutoRemove",false); |
|
| 400 | 403 | bool doAutoRemove = _config->FindB("APT::Get::AutomaticRemove", false); |
|
| 401 | 404 | bool hideAutoRemove = _config->FindB("APT::Get::HideAutoRemove"); |
|
| 402 | 405 |
| 426 | 429 | { |
|
| 427 | 430 | if(Pkg.CurrentVer() != 0 || Cache[Pkg].Install()) |
|
| 428 | 431 | if(Debug) |
|
| 429 | - | std::cout << "We could delete %s" << Pkg.FullName(true).c_str() << std::endl; |
|
| 432 | + | std::cout << "We could delete " << APT::PrettyPkg(Cache, Pkg) << std::endl; |
|
| 430 | 433 | ||
| 431 | 434 | if (doAutoRemove) |
|
| 432 | 435 | { |
|
| 433 | - | if(Pkg.CurrentVer() != 0 && |
|
| 436 | + | if(Pkg.CurrentVer() != 0 && |
|
| 434 | 437 | Pkg->CurrentState != pkgCache::State::ConfigFiles) |
|
| 435 | 438 | Cache->MarkDelete(Pkg, purgePkgs, 0, false); |
|
| 436 | 439 | else |
| 475 | 478 | if (R.IsNegative() == true || |
|
| 476 | 479 | Cache->IsImportantDep(R) == false) |
|
| 477 | 480 | continue; |
|
| 478 | - | pkgCache::PkgIterator N = R.ParentPkg(); |
|
| 479 | - | if (N.end() == true || (N->CurrentVer == 0 && (*Cache)[N].Install() == false)) |
|
| 481 | + | auto const RV = R.ParentVer(); |
|
| 482 | + | if (unlikely(RV.end() == true)) |
|
| 483 | + | continue; |
|
| 484 | + | auto const RP = RV.ParentPkg(); |
|
| 485 | + | // check if that dependency comes from an interesting version |
|
| 486 | + | if (RP.CurrentVer() == RV) |
|
| 487 | + | { |
|
| 488 | + | if ((*Cache)[RP].Keep() == false) |
|
| 489 | + | continue; |
|
| 490 | + | } |
|
| 491 | + | else if (Cache[RP].CandidateVerIter(Cache) == RV) |
|
| 492 | + | { |
|
| 493 | + | if ((*Cache)[RP].NewInstall() == false && (*Cache)[RP].Upgrade() == false) |
|
| 494 | + | continue; |
|
| 495 | + | } |
|
| 496 | + | else // ignore dependency from a non-candidate version |
|
| 480 | 497 | continue; |
|
| 481 | 498 | if (Debug == true) |
|
| 482 | - | std::clog << "Save " << APT::PrettyPkg(Cache, Pkg) << " as another installed garbage package depends on it" << std::endl; |
|
| 499 | + | std::clog << "Save " << APT::PrettyPkg(Cache, Pkg) << " as another installed package depends on it: " << APT::PrettyPkg(Cache, RP) << std::endl; |
|
| 483 | 500 | Cache->MarkInstall(Pkg, false, 0, false); |
|
| 484 | 501 | if (hideAutoRemove == false) |
|
| 485 | 502 | ++autoRemoveCount; |
| 495 | 512 | } |
|
| 496 | 513 | } while (Changed == true); |
|
| 497 | 514 | } |
|
| 515 | + | // trigger marking now so that the package list below is correct |
|
| 516 | + | group.release(); |
|
| 498 | 517 | ||
| 499 | 518 | // Now see if we had destroyed anything (if we had done anything) |
|
| 500 | 519 | if (Cache->BrokenCount() != 0) |
| 71 | 71 | ListUpdate(Stat, *List); |
|
| 72 | 72 | } |
|
| 73 | 73 | ||
| 74 | + | if (_config->FindB("pkgCacheFile::Generate", true) == false) |
|
| 75 | + | return true; |
|
| 76 | + | ||
| 74 | 77 | // Rebuild the cache. |
|
| 75 | - | if (_config->FindB("pkgCacheFile::Generate", true) == true) |
|
| 76 | - | { |
|
| 77 | - | pkgCacheFile::RemoveCaches(); |
|
| 78 | - | if (Cache.BuildCaches() == false) |
|
| 79 | - | return false; |
|
| 80 | - | } |
|
| 78 | + | pkgCacheFile::RemoveCaches(); |
|
| 79 | + | if (Cache.BuildCaches(false) == false) |
|
| 80 | + | return false; |
|
| 81 | 81 | ||
| 82 | 82 | // show basic stats (if the user whishes) |
|
| 83 | 83 | if (_config->FindB("APT::Cmd::Show-Update-Stats", false) == true) |
|
| 84 | 84 | { |
|
| 85 | 85 | int upgradable = 0; |
|
| 86 | - | if (Cache.Open() == false) |
|
| 86 | + | if (Cache.Open(false) == false) |
|
| 87 | 87 | return false; |
|
| 88 | 88 | for (pkgCache::PkgIterator I = Cache->PkgBegin(); I.end() != true; ++I) |
|
| 89 | 89 | { |
| 495 | 495 | return _error->Error(_("Failed to fetch some archives.")); |
|
| 496 | 496 | } |
|
| 497 | 497 | ||
| 498 | - | if (_config->FindB("APT::Get::Download-only",false) == true) |
|
| 498 | + | if (diffOnly || tarOnly || dscOnly || _config->FindB("APT::Get::Download-only",false) == true) |
|
| 499 | 499 | { |
|
| 500 | 500 | c1out << _("Download complete and in download only mode") << std::endl; |
|
| 501 | 501 | return true; |
| 509 | 509 | bool const fixBroken = _config->FindB("APT::Get::Fix-Broken", false); |
|
| 510 | 510 | for (unsigned I = 0; I != J; ++I) |
|
| 511 | 511 | { |
|
| 512 | - | std::string Dir = Dsc[I].Package + '-' + Cache.GetPkgCache()->VS->UpstreamVersion(Dsc[I].Version.c_str()); |
|
| 513 | - | ||
| 514 | - | // Diff only mode only fetches .diff files |
|
| 515 | - | if (_config->FindB("APT::Get::Diff-Only",false) == true || |
|
| 516 | - | _config->FindB("APT::Get::Tar-Only",false) == true || |
|
| 517 | - | Dsc[I].Dsc.empty() == true) |
|
| 512 | + | if (unlikely(Dsc[I].Dsc.empty() == true)) |
|
| 518 | 513 | continue; |
|
| 514 | + | std::string const Dir = Dsc[I].Package + '-' + Cache.GetPkgCache()->VS->UpstreamVersion(Dsc[I].Version.c_str()); |
|
| 519 | 515 | ||
| 520 | 516 | // See if the package is already unpacked |
|
| 521 | 517 | struct stat Stat; |
| 117 | 117 | if (chmod(partial.c_str(), 0700) != 0) |
|
| 118 | 118 | _error->WarningE("SetupAPTPartialDirectory", "chmod 0700 of directory %s failed", partial.c_str()); |
|
| 119 | 119 | ||
| 120 | + | _error->PushToStack(); |
|
| 121 | + | // remove 'old' FAILED files to stop us from collecting them for no reason |
|
| 122 | + | for (auto const &Failed: GetListOfFilesInDir(partial, "FAILED", false, false)) |
|
| 123 | + | RemoveFile("SetupAPTPartialDirectory", Failed); |
|
| 124 | + | _error->RevertToStack(); |
|
| 125 | + | ||
| 120 | 126 | return true; |
|
| 121 | 127 | } |
|
| 122 | 128 | bool pkgAcquire::Setup(pkgAcquireStatus *Progress, string const &Lock) |
| 894 | 900 | /* */ |
|
| 895 | 901 | bool pkgAcquire::Queue::Enqueue(ItemDesc &Item) |
|
| 896 | 902 | { |
|
| 903 | + | // MetaKeysMatch checks whether the two items have no non-matching |
|
| 904 | + | // meta-keys. If the items are not transaction items, it returns |
|
| 905 | + | // true, so other items can still be merged. |
|
| 906 | + | auto MetaKeysMatch = [](pkgAcquire::ItemDesc const &A, pkgAcquire::Queue::QItem const *B) { |
|
| 907 | + | auto OwnerA = dynamic_cast<pkgAcqTransactionItem*>(A.Owner); |
|
| 908 | + | if (OwnerA == nullptr) |
|
| 909 | + | return true; |
|
| 910 | + | ||
| 911 | + | for (auto const & OwnerBUncast : B->Owners) { |
|
| 912 | + | auto OwnerB = dynamic_cast<pkgAcqTransactionItem*>(OwnerBUncast); |
|
| 913 | + | ||
| 914 | + | if (OwnerB != nullptr && OwnerA->GetMetaKey() != OwnerB->GetMetaKey()) |
|
| 915 | + | return false; |
|
| 916 | + | } |
|
| 917 | + | return true; |
|
| 918 | + | }; |
|
| 897 | 919 | QItem **OptimalI = &Items; |
|
| 898 | 920 | QItem **I = &Items; |
|
| 899 | 921 | // move to the end of the queue and check for duplicates here |
|
| 900 | 922 | for (; *I != 0; ) { |
|
| 901 | - | if (Item.URI == (*I)->URI) |
|
| 923 | + | if (Item.URI == (*I)->URI && MetaKeysMatch(Item, *I)) |
|
| 902 | 924 | { |
|
| 903 | 925 | if (_config->FindB("Debug::pkgAcquire::Worker",false) == true) |
|
| 904 | 926 | std::cerr << " @ Queue: Action combined for " << Item.URI << " and " << (*I)->URI << std::endl; |
| 1154 | 1176 | return Maximum; |
|
| 1155 | 1177 | } |
|
| 1156 | 1178 | /*}}}*/ |
|
| 1157 | - | APT_PURE int pkgAcquire::Queue::QItem::GetPriority() const /*{{{*/ |
|
| 1179 | + | APT_PURE int pkgAcquire::Queue::QItem::GetPriority() const /*{{{*/ |
|
| 1158 | 1180 | { |
|
| 1159 | 1181 | int Priority = 0; |
|
| 1160 | 1182 | for (auto const &O: Owners) |
| 1363 | 1363 | ScopedErrorRevert() { _error->PushToStack(); } |
|
| 1364 | 1364 | ~ScopedErrorRevert() { _error->RevertToStack(); } |
|
| 1365 | 1365 | }; |
|
| 1366 | - | static bool CheckValidity(const string &CacheFile, |
|
| 1366 | + | static bool CheckValidity(FileFd &CacheFile, std::string const &CacheFileName, |
|
| 1367 | 1367 | pkgSourceList &List, |
|
| 1368 | 1368 | FileIterator const Start, |
|
| 1369 | 1369 | FileIterator const End, |
|
| 1370 | 1370 | MMap **OutMap = 0, |
|
| 1371 | 1371 | pkgCache **OutCache = 0) |
|
| 1372 | 1372 | { |
|
| 1373 | + | if (CacheFileName.empty()) |
|
| 1374 | + | return false; |
|
| 1373 | 1375 | ScopedErrorRevert ser; |
|
| 1376 | + | ||
| 1374 | 1377 | bool const Debug = _config->FindB("Debug::pkgCacheGen", false); |
|
| 1375 | 1378 | // No file, certainly invalid |
|
| 1376 | - | if (CacheFile.empty() == true || FileExists(CacheFile) == false) |
|
| 1379 | + | if (CacheFile.Open(CacheFileName, FileFd::ReadOnly, FileFd::None) == false) |
|
| 1377 | 1380 | { |
|
| 1378 | 1381 | if (Debug == true) |
|
| 1379 | - | std::clog << "CacheFile " << CacheFile << " doesn't exist" << std::endl; |
|
| 1382 | + | std::clog << "CacheFile " << CacheFileName << " doesn't exist" << std::endl; |
|
| 1380 | 1383 | return false; |
|
| 1381 | 1384 | } |
|
| 1382 | 1385 | ||
| 1383 | - | if (List.GetLastModifiedTime() > GetModificationTime(CacheFile)) |
|
| 1386 | + | if (List.GetLastModifiedTime() > CacheFile.ModificationTime()) |
|
| 1384 | 1387 | { |
|
| 1385 | 1388 | if (Debug == true) |
|
| 1386 | 1389 | std::clog << "sources.list is newer than the cache" << std::endl; |
|
| 1387 | 1390 | return false; |
|
| 1388 | 1391 | } |
|
| 1389 | 1392 | ||
| 1390 | 1393 | // Map it |
|
| 1391 | - | FileFd CacheF(CacheFile,FileFd::ReadOnly); |
|
| 1392 | - | std::unique_ptr<MMap> Map(new MMap(CacheF,0)); |
|
| 1394 | + | std::unique_ptr<MMap> Map(new MMap(CacheFile,0)); |
|
| 1393 | 1395 | if (unlikely(Map->validData()) == false) |
|
| 1394 | 1396 | return false; |
|
| 1395 | 1397 | std::unique_ptr<pkgCache> CacheP(new pkgCache(Map.get())); |
|
| 1396 | 1398 | pkgCache &Cache = *CacheP.get(); |
|
| 1397 | 1399 | if (_error->PendingError() || Map->Size() == 0) |
|
| 1398 | 1400 | { |
|
| 1399 | 1401 | if (Debug == true) |
|
| 1400 | - | std::clog << "Errors are pending or Map is empty() for " << CacheFile << std::endl; |
|
| 1402 | + | std::clog << "Errors are pending or Map is empty() for " << CacheFileName << std::endl; |
|
| 1401 | 1403 | return false; |
|
| 1402 | 1404 | } |
|
| 1403 | 1405 |
| 1623 | 1625 | return true; |
|
| 1624 | 1626 | } |
|
| 1625 | 1627 | static bool loadBackMMapFromFile(std::unique_ptr<pkgCacheGenerator> &Gen, |
|
| 1626 | - | std::unique_ptr<DynamicMMap> &Map, OpProgress * const Progress, std::string const &FileName) |
|
| 1628 | + | std::unique_ptr<DynamicMMap> &Map, OpProgress * const Progress, FileFd &CacheF) |
|
| 1627 | 1629 | { |
|
| 1628 | 1630 | Map.reset(CreateDynamicMMap(NULL, 0)); |
|
| 1629 | 1631 | if (unlikely(Map->validData()) == false) |
|
| 1630 | 1632 | return false; |
|
| 1631 | - | FileFd CacheF(FileName, FileFd::ReadOnly); |
|
| 1632 | - | if (CacheF.IsOpen() == false || CacheF.Failed()) |
|
| 1633 | + | if (CacheF.IsOpen() == false || CacheF.Seek(0) == false || CacheF.Failed()) |
|
| 1633 | 1634 | return false; |
|
| 1634 | 1635 | _error->PushToStack(); |
|
| 1635 | 1636 | map_pointer_t const alloc = Map->RawAllocate(CacheF.Size()); |
| 1661 | 1662 | return false; |
|
| 1662 | 1663 | ||
| 1663 | 1664 | // Decide if we can write to the files.. |
|
| 1664 | - | string const CacheFile = _config->FindFile("Dir::Cache::pkgcache"); |
|
| 1665 | - | string const SrcCacheFile = _config->FindFile("Dir::Cache::srcpkgcache"); |
|
| 1665 | + | string const CacheFileName = _config->FindFile("Dir::Cache::pkgcache"); |
|
| 1666 | + | string const SrcCacheFileName = _config->FindFile("Dir::Cache::srcpkgcache"); |
|
| 1666 | 1667 | ||
| 1667 | 1668 | // ensure the cache directory exists |
|
| 1668 | - | if (CacheFile.empty() == false || SrcCacheFile.empty() == false) |
|
| 1669 | + | if (CacheFileName.empty() == false || SrcCacheFileName.empty() == false) |
|
| 1669 | 1670 | { |
|
| 1670 | 1671 | string dir = _config->FindDir("Dir::Cache"); |
|
| 1671 | 1672 | size_t const len = dir.size(); |
|
| 1672 | 1673 | if (len > 5 && dir.find("/apt/", len - 6, 5) == len - 5) |
|
| 1673 | 1674 | dir = dir.substr(0, len - 5); |
|
| 1674 | - | if (CacheFile.empty() == false) |
|
| 1675 | - | CreateDirectory(dir, flNotFile(CacheFile)); |
|
| 1676 | - | if (SrcCacheFile.empty() == false) |
|
| 1677 | - | CreateDirectory(dir, flNotFile(SrcCacheFile)); |
|
| 1675 | + | if (CacheFileName.empty() == false) |
|
| 1676 | + | CreateDirectory(dir, flNotFile(CacheFileName)); |
|
| 1677 | + | if (SrcCacheFileName.empty() == false) |
|
| 1678 | + | CreateDirectory(dir, flNotFile(SrcCacheFileName)); |
|
| 1678 | 1679 | } |
|
| 1679 | 1680 | ||
| 1680 | 1681 | if (Progress != NULL) |
| 1683 | 1684 | bool pkgcache_fine = false; |
|
| 1684 | 1685 | bool srcpkgcache_fine = false; |
|
| 1685 | 1686 | bool volatile_fine = List.GetVolatileFiles().empty(); |
|
| 1686 | - | ||
| 1687 | - | if (CheckValidity(CacheFile, List, Files.begin(), Files.end(), volatile_fine ? OutMap : NULL, |
|
| 1687 | + | FileFd CacheFile; |
|
| 1688 | + | if (CheckValidity(CacheFile, CacheFileName, List, Files.begin(), Files.end(), volatile_fine ? OutMap : NULL, |
|
| 1688 | 1689 | volatile_fine ? OutCache : NULL) == true) |
|
| 1689 | 1690 | { |
|
| 1690 | 1691 | if (Debug == true) |
|
| 1691 | 1692 | std::clog << "pkgcache.bin is valid - no need to build any cache" << std::endl; |
|
| 1692 | 1693 | pkgcache_fine = true; |
|
| 1693 | 1694 | srcpkgcache_fine = true; |
|
| 1694 | 1695 | } |
|
| 1696 | + | ||
| 1697 | + | FileFd SrcCacheFile; |
|
| 1695 | 1698 | if (pkgcache_fine == false) |
|
| 1696 | 1699 | { |
|
| 1697 | - | if (CheckValidity(SrcCacheFile, List, Files.end(), Files.end()) == true) |
|
| 1700 | + | if (CheckValidity(SrcCacheFile, SrcCacheFileName, List, Files.end(), Files.end()) == true) |
|
| 1698 | 1701 | { |
|
| 1699 | 1702 | if (Debug == true) |
|
| 1700 | 1703 | std::clog << "srcpkgcache.bin is valid - it can be reused" << std::endl; |
| 1712 | 1715 | bool Writeable = false; |
|
| 1713 | 1716 | if (srcpkgcache_fine == false || pkgcache_fine == false) |
|
| 1714 | 1717 | { |
|
| 1715 | - | if (CacheFile.empty() == false) |
|
| 1716 | - | Writeable = access(flNotFile(CacheFile).c_str(),W_OK) == 0; |
|
| 1717 | - | else if (SrcCacheFile.empty() == false) |
|
| 1718 | - | Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0; |
|
| 1718 | + | if (CacheFileName.empty() == false) |
|
| 1719 | + | Writeable = access(flNotFile(CacheFileName).c_str(),W_OK) == 0; |
|
| 1720 | + | else if (SrcCacheFileName.empty() == false) |
|
| 1721 | + | Writeable = access(flNotFile(SrcCacheFileName).c_str(),W_OK) == 0; |
|
| 1719 | 1722 | ||
| 1720 | 1723 | if (Debug == true) |
|
| 1721 | 1724 | std::clog << "Do we have write-access to the cache files? " << (Writeable ? "YES" : "NO") << std::endl; |
| 1754 | 1757 | Files.end(),Files.end()) == false) |
|
| 1755 | 1758 | return false; |
|
| 1756 | 1759 | ||
| 1757 | - | if (Writeable == true && SrcCacheFile.empty() == false) |
|
| 1758 | - | if (writeBackMMapToFile(Gen.get(), Map.get(), SrcCacheFile) == false) |
|
| 1760 | + | if (Writeable == true && SrcCacheFileName.empty() == false) |
|
| 1761 | + | if (writeBackMMapToFile(Gen.get(), Map.get(), SrcCacheFileName) == false) |
|
| 1759 | 1762 | return false; |
|
| 1760 | 1763 | } |
|
| 1761 | 1764 |
| 1767 | 1770 | Files.begin(), Files.end()) == false) |
|
| 1768 | 1771 | return false; |
|
| 1769 | 1772 | ||
| 1770 | - | if (Writeable == true && CacheFile.empty() == false) |
|
| 1771 | - | if (writeBackMMapToFile(Gen.get(), Map.get(), CacheFile) == false) |
|
| 1773 | + | if (Writeable == true && CacheFileName.empty() == false) |
|
| 1774 | + | if (writeBackMMapToFile(Gen.get(), Map.get(), CacheFileName) == false) |
|
| 1772 | 1775 | return false; |
|
| 1773 | 1776 | } |
|
| 1774 | 1777 |
| 180 | 180 | return true; |
|
| 181 | 181 | } |
|
| 182 | 182 | ||
| 183 | - | if (stringcasecmp(Tag,"Content-Range:") == 0) |
|
| 183 | + | // The Content-Range field only has a meaning in HTTP/1.1 for the |
|
| 184 | + | // 206 (Partial Content) and 416 (Range Not Satisfiable) responses |
|
| 185 | + | // according to RFC7233 "Range Requests", §4.2, so only consider it |
|
| 186 | + | // for such responses. |
|
| 187 | + | if ((Result == 416 || Result == 206) && stringcasecmp(Tag,"Content-Range:") == 0) |
|
| 184 | 188 | { |
|
| 185 | 189 | HaveContent = true; |
|
| 186 | 190 |
| 770 | 774 | // We need to flush the data, the header is like a 404 w/ error text |
|
| 771 | 775 | case ERROR_WITH_CONTENT_PAGE: |
|
| 772 | 776 | { |
|
| 773 | - | Fail(); |
|
| 774 | 777 | Server->RunDataToDevNull(); |
|
| 778 | + | Fail(); |
|
| 775 | 779 | break; |
|
| 776 | 780 | } |
|
| 777 | 781 |
| 1144 | 1144 | pkgCache::PkgIterator I = Cache.PkgBegin(); |
|
| 1145 | 1145 | for (;I.end() != true; ++I) { |
|
| 1146 | 1146 | if (Cache[I].NewInstall() && !(Flags[I->ID] & PreInstalled)) { |
|
| 1147 | - | if(_config->FindI("Debug::pkgAutoRemove",false)) { |
|
| 1147 | + | if(_config->FindB("Debug::pkgAutoRemove",false)) { |
|
| 1148 | 1148 | std::clog << "Resolve installed new pkg: " << I.FullName(false) |
|
| 1149 | 1149 | << " (now marking it as auto)" << std::endl; |
|
| 1150 | 1150 | } |
| 1101 | 1101 | UseByHash = _config->Find("Acquire::By-Hash", UseByHash); |
|
| 1102 | 1102 | { |
|
| 1103 | 1103 | std::string const host = ::URI(URI).Host; |
|
| 1104 | - | UseByHash = _config->Find("APT::Acquire::" + host + "::By-Hash", UseByHash); |
|
| 1105 | - | UseByHash = _config->Find("Acquire::" + host + "::By-Hash", UseByHash); |
|
| 1104 | + | if (host.empty() == false) |
|
| 1105 | + | { |
|
| 1106 | + | UseByHash = _config->Find("APT::Acquire::" + host + "::By-Hash", UseByHash); |
|
| 1107 | + | UseByHash = _config->Find("Acquire::" + host + "::By-Hash", UseByHash); |
|
| 1108 | + | } |
|
| 1106 | 1109 | std::map<std::string, std::string>::const_iterator const opt = Options.find("by-hash"); |
|
| 1107 | 1110 | if (opt != Options.end()) |
|
| 1108 | 1111 | UseByHash = opt->second; |
| 61 | 61 | string Result = Section.Find("Package").to_string(); |
|
| 62 | 62 | ||
| 63 | 63 | // Normalize mixed case package names to lower case, like dpkg does |
|
| 64 | - | // See Bug#807012 for details |
|
| 65 | - | std::transform(Result.begin(), Result.end(), Result.begin(), tolower_ascii); |
|
| 64 | + | // See Bug#807012 for details. |
|
| 65 | + | // Only do this when the package name does not contain a / - as that |
|
| 66 | + | // indicates that the package name was derived from a filename given |
|
| 67 | + | // to install or build-dep or similar (Bug#854794) |
|
| 68 | + | if (likely(Result.find('/') == string::npos)) |
|
| 69 | + | { |
|
| 70 | + | for (char &c: Result) |
|
| 71 | + | { |
|
| 72 | + | char l = tolower_ascii_inline(c); |
|
| 73 | + | if (unlikely(l != c)) |
|
| 74 | + | c = l; |
|
| 75 | + | } |
|
| 76 | + | } |
|
| 66 | 77 | ||
| 67 | 78 | if(unlikely(Result.empty() == true)) |
|
| 68 | 79 | _error->Error("Encountered a section with no Package: header"); |
| 365 | 365 | curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, DL_MIN_SPEED); |
|
| 366 | 366 | curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, timeout); |
|
| 367 | 367 | ||
| 368 | + | if(_config->FindB("Acquire::ForceIPv4", false) == true) |
|
| 369 | + | curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); |
|
| 370 | + | else if(_config->FindB("Acquire::ForceIPv6", false) == true) |
|
| 371 | + | curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6); |
|
| 372 | + | ||
| 368 | 373 | // debug |
|
| 369 | 374 | if (Debug == true) |
|
| 370 | 375 | curl_easy_setopt(curl, CURLOPT_VERBOSE, true); |
Learn more Showing 16 files with coverage changes found.
apt-pkg/acquire-method.cc
apt-pkg/cacheiterators.h
apt-pkg/deb/debmetaindex.cc
apt-private/private-source.cc
apt-pkg/contrib/fileutl.cc
apt-pkg/contrib/strutl.cc
apt-private/private-install.cc
methods/connect.cc
apt-private/private-moo.cc
methods/http.cc
methods/gpgv.cc
methods/aptmethod.h
methods/https.cc
methods/server.cc
methods/server.h
| Files | Coverage |
|---|---|
| apt-inst | 23.56% |
| apt-pkg | -0.14% 78.12% |
| apt-private | 0.09% 85.86% |
| cmdline | 84.90% |
| ftparchive | 74.93% |
| methods | +3.26% 60.64% |
| test | 84.18% |
| Project Totals (196 files) | 77.24% |
e5f9d668158819990287639cf49f92a0c9830510f0f27795bcba3a346a83cc23b4d5e3ce33287f2fb71ceba238429b09092216c2581c82eedb375a27c032030c85f796addf0210f6c949929effe9cfa40a9b9ce81b4ebeb883dfeedf6e1f1099e635797ee183b7826838667e06e2a26a8547d294f405f672ea04415f32c4