| Summary: | apt-get install не решает автоматически конфликты, если pkgCache::Version > 1 | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Product: | Sisyphus | Reporter: | Denis Rastyogin <rastyoginds> | ||||||||
| Component: | apt | Assignee: | Ivan Zakharyaschev <imz> | ||||||||
| Status: | UNCONFIRMED --- | QA Contact: | qa-sisyphus | ||||||||
| Severity: | normal | ||||||||||
| Priority: | P5 | CC: | boyarsh, glebfm, imz, ldv, placeholder, vt | ||||||||
| Version: | unstable | ||||||||||
| Hardware: | x86_64 | ||||||||||
| OS: | Linux | ||||||||||
| Attachments: |
|
||||||||||
Created attachment 18752 [details]
лог без таска
Created attachment 18753 [details]
лог с таском
Спасибо! Хорошее наблюдение и разбор кода. Вся эта система такая запутанная... Раз Вы разобрались неплохо, может быть, Вы сможете пояснить некоторые вещи, как Вы их понимаете: 1. Почему нельзя просто сразу их все удалять? Я думаю так: В этом цикле for (pkgCache::Version * const *V = VList.get(); *V != nullptr; V++) Start и End не меняются (на практике без булевских зависимостей совпадают?) и Start->Type будет всегда Conflicts, например. (Можно было бы не внутри цикла проверять, а снаружи, и написать два альтернативных цикла по типу зависимости вместо одного, чтобы всё не мешать в кучу. Мне сейчас кажется, так было бы понятнее.) 2. Не будет ли там нежелательного эффекта на пакеты, которые Provides "виртуальный" пакет, который подпадает под Conflicts или Obsoletes? Про Conflicts я точно не знаю, но Obsoletes, как я понимаю, на такие не должно влиять, а в VList и такие тоже лежат как результат AllTargets(), или не так? const SPtrArray<pkgCache::Version * const> VList(Start.AllTargets()); В Sisyphus такой же код, там сначала исправим.
1. Да, действительно, лучше это вынести из текущего цикла. Я побоялся того, что придется переносить некоторые условия с break, чтобы сохранить существующую логику добавления.)
2. Предполагаю, что случай с виртуальными пакетами должен исключаться уже существующим условием:
if (Cache[Pkg].InstallVer != Ver.operator const pkgCache::Version *() &&
(Start->Type == pkgCache::Dep::Conflicts ||
Start->Type == pkgCache::Dep::Obsoletes))
Мы, по сути, игнорируем здесь версии, которые не совпадают с установленными, и при Conflicts или Obsoletes не пытаемся их удалять. Значит, виртуальные пакеты в этом случае тоже не должны влиять. (так как они же не установлены?)
|
Created attachment 18751 [details] патч Воспроизведение: без доп. тасков все работает apt-get install qemu-img qemu -y && apt-get install pve-qemu-img -y -o Debug::pkgProblemResolver=yes -o Debug::pkgRemoveDepends=yes -o Debug::pkgMarkInstall=yes && apt-get install -y qemu-img qemu log_default.txt если добавить таск (например 376145) apt-repo add 376145 apt-get update apt-get install qemu-img qemu -y && apt-get install pve-qemu-img -y -o Debug::pkgProblemResolver=yes -o Debug::pkgRemoveDepends=yes -o Debug::pkgMarkInstall=yes && apt-get install -y qemu-img qemu log_376145.txt Тестировалась на 0.5.15lorg2-alt87, но на 0.5.15lorg2-alt96 проблема тоже должна быть. Причина: Как оказалось, проблема даже не столько в самих конфликтах, сколько в том, как apt их обрабатывает. Конфликты есть в задании и в пакете qemu-8.2.6-alt0.p10.1, но в последнем случае apt автоматически решает их в пользу удаления. А вот в случае 376145 одновременно присутствуют две pkgCache::Version — одна относится к заданию, а другая — к P10. В результате apt проверяет обе версии. Когда рассматривается первая версия, apt действительно планирует пометить конфликтующий пакет на удаление: apt-pkg/algorithms.cc: LEnd->Pkg = Pkg; LEnd->Dep = End; LEnd++; Но до того, как это происходит, обрабатывается следующее условие: // CNC:2002-07-09 if (*(V + 1) != 0) // XXX: Look for other solutions? continue; То есть, если в списке версий есть другие возможные варианты, apt решает их сначала проверить и откладывает пометку на удаление. В случае без таска других вариантов нет, и удаление в итоге происходит. А вот в 376145, когда apt доходит до версии в репозитории, он наталкивается на такое условие: if (Cache[Pkg].InstallVer != Ver.operator const pkgCache::Version *() && (Start->Type == pkgCache::Dep::Conflicts || Start->Type == pkgCache::Dep::Obsoletes)) continue; Это условие означает: если рассматриваемая версия не установлена, и это Conflicts или Obsoletes, то просто пропускаем её. Никаких действий не выполняется, включая удаление. В результате — пометка на удаление, которую должны были поставить в первом случае, не ставится вообще, потому что apt решил "поискать другие варианты", а во втором случае просто вышел из проверки, не найдя установленной версии. В итоге конфликт не решается автоматически в случае с таском. Прикладываю патч, который решает данную проблему: 0.5.15lorg2-alt87-apt-pkg-algorithms.cc-fix-kill-list-logic-to-collect.patch