MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
-NamespaceIndentation: None
+NamespaceIndentation: All
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: true
#
SET(LIBZYPP_MAJOR "17")
SET(LIBZYPP_COMPATMINOR "22")
-SET(LIBZYPP_MINOR "23")
-SET(LIBZYPP_PATCH "8")
+SET(LIBZYPP_MINOR "24")
+SET(LIBZYPP_PATCH "1")
#
-# LAST RELEASED: 17.23.8 (22)
+# LAST RELEASED: 17.24.1 (22)
# (The number in parenthesis is LIBZYPP_COMPATMINOR)
#=======
\li \c ZYPP_MEDIA_CURL_DEBUG=<1|2> Log http headers, if \c 2 also log server responses.
\li \c ZYPP_MEDIA_CURL_IPRESOLVE=<4|6> Tell curl to resolve names to IPv4/IPv6 addresses only.
+\li \c ZYPP_RPM_DEBUG=1 Log verbose output from all rpm commands.
+
\subsection zypp-envars-mediabackend Selecting the mediabackend to use.
\li \c ZYPP_MULTICURL=0 Turn off multicurl (metalink and zsync) and fall back to plain libcurl.
-------------------------------------------------------------------
+Thu Jul 16 18:04:18 CEST 2020 - ma@suse.de
+
+- Fix bsc#1174011 auth=basic ignored in some cases (bsc#1174011)
+ Proactively send credentials if the URL specifes '?auth=basic'
+ and a username.
+- ZYPP_MEDIA_CURL_DEBUG: Strip credentials in header log (bsc#1174011)
+- version 17.24.1 (22)
+
+-------------------------------------------------------------------
+Tue Jul 14 13:19:56 CEST 2020 - ma@suse.de
+
+- Completey rework the purge-kernels algorithm (fix bsc#1173106)
+ The new code is closer to the original perl script, grouping the
+ packages by name before applying the keep spec.
+- Set ZYPP_RPM_DEBUG=1 to capture verbose rpm command output
+ (implements #228)
+- version 17.24.0 (22)
+
+-------------------------------------------------------------------
Fri Jun 26 14:13:10 CEST 2020 - ma@suse.de
- Fix core dump with corrupted history file (bsc#1170801)
"Project-Id-Version: zypp.fi\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-12-05 14:22+0100\n"
-"PO-Revision-Date: 2020-01-13 19:59+0000\n"
-"Last-Translator: Tommi Nieminen <software@legisign.org>\n"
+"PO-Revision-Date: 2020-06-28 06:55+0000\n"
+"Last-Translator: Kimmo Kujansuu <mrkujansuu@gmail.com>\n"
"Language-Team: Finnish <https://l10n.opensuse.org/projects/libzypp/master/fi/"
">\n"
"Language: fi\n"
#: zypp/Url.cc:327 zypp/Url.cc:341
msgid "Unable to parse Url components"
-msgstr "Verkko-osoitteen jäsentäminen ei onnistu."
+msgstr "Verkko-osoitteen jäsentäminen ei onnistu"
#: zypp/VendorSupportOptions.cc:14
msgid "unknown"
#: zypp/media/MediaException.cc:146
#, c-format, boost-format
msgid "Error occurred while setting download (curl) options for '%s':"
-msgstr "Virhe asetettaessa lataajan (curl) valintoja osoitteelle \"%s\"."
+msgstr "Virhe määritettäessä kohteen '%s' latausasetuksia (curl):"
#: zypp/media/MediaException.cc:153
#, c-format, boost-format
"Project-Id-Version: YaST (@memory@)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-12-05 14:22+0100\n"
-"PO-Revision-Date: 2019-08-26 11:51+0000\n"
+"PO-Revision-Date: 2020-06-29 19:45+0000\n"
"Last-Translator: Manuel Vazquez <xixirei@yahoo.es>\n"
"Language-Team: Galician <https://l10n.opensuse.org/projects/libzypp/master/"
"gl/>\n"
#: zypp/solver/detail/SATResolver.cc:1389
#, boost-format
msgid "allow to install the PTF %1%"
-msgstr ""
+msgstr "permitir a instalación de PTF %1%"
#. translator: %1% is a package name
#: zypp/solver/detail/SATResolver.cc:1392
#, boost-format
msgid "install %1% although it is blacklisted"
-msgstr ""
+msgstr "instalar %1% aínda que estea na lista negra"
#: zypp/solver/detail/SATResolver.cc:1412
#, c-format, boost-format
"Project-Id-Version: zypp.hi\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-12-05 14:22+0100\n"
-"PO-Revision-Date: 2007-08-24 22:33+0530\n"
-"Last-Translator: Sangeeta Kumari <k.sangeeta09@gmail.com>\n"
-"Language-Team: Hindi <en@li.org>\n"
+"PO-Revision-Date: 2020-06-29 19:45+0000\n"
+"Last-Translator: Panwar <caspian7pena@gmail.com>\n"
+"Language-Team: Hindi <https://l10n.opensuse.org/projects/libzypp/master/hi/>"
+"\n"
"Language: hi\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n > 1);\n"
-"X-Generator: KBabel 1.11.4\n"
+"Plural-Forms: nplurals=2; plural=n > 1;\n"
+"X-Generator: Weblate 3.6.1\n"
#. dubious: Throw on malformed known types, otherwise log a warning.
#: zypp/CheckSum.cc:136
#: zypp/CountryCode.cc:50
msgid "Unknown country: "
-msgstr "अज्ञात देश :"
+msgstr "अज्ञात देश : "
#. Defined CountryCode constants
#. Defined LanguageCode constants
#: zypp/target/rpm/RpmDb.cc:1929
#, c-format, boost-format
msgid "Changed configuration files for %s:"
-msgstr "%s: के लिए परिवर्तित कंफिगरेशन फाइलें"
+msgstr "%s हेतु विन्यास फ़ाइलें जिन्हें बदला गया :"
#. %s = filenames
#: zypp/target/rpm/RpmDb.cc:2104
"Project-Id-Version: zypp.uk\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-12-05 14:22+0100\n"
-"PO-Revision-Date: 2018-04-14 04:38+0000\n"
-"Last-Translator: Andriy Bandura <andriykopanytsia@gmail.com>\n"
+"PO-Revision-Date: 2020-06-29 19:45+0000\n"
+"Last-Translator: Lesath <4lesath@gmail.com>\n"
"Language-Team: Ukrainian <https://l10n.opensuse.org/projects/libzypp/master/"
"uk/>\n"
"Language: uk\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
-"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 2.18\n"
+"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<="
+"4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
+"X-Generator: Weblate 3.6.1\n"
#. dubious: Throw on malformed known types, otherwise log a warning.
#: zypp/CheckSum.cc:136
#, c-format, boost-format
msgid "Dubious type '%s' for %u byte checksum '%s'"
-msgstr "Сумнівний тип \"%s\" для %u байтової контрольної суми \"%s\""
+msgstr "Сумнівний тип «%s» для %u байтової контрольної суми «%s»"
#: zypp/CountryCode.cc:50
msgid "Unknown country: "
#. :AFG:004:
#: zypp/CountryCode.cc:161
msgid "Antigua and Barbuda"
-msgstr "ТÑ\80инÑ\96дад Ñ\82а Тобаго"
+msgstr "Ð\90нÑ\82игÑ\83а Ñ\96 Ð\91аÑ\80бÑ\83да"
#. :ATG:028:
#: zypp/CountryCode.cc:162
#. :ALB:008:
#: zypp/CountryCode.cc:164
msgid "Armenia"
-msgstr "Ð\90Ñ\80генÑ\82ина"
+msgstr "Ð\92Ñ\96Ñ\80менÑ\96Ñ\8f"
# AN
# fuzzy
#. :ARM:051:
#: zypp/CountryCode.cc:165
msgid "Netherlands Antilles"
-msgstr "Ð\93олландÑ\96Ñ\8f"
+msgstr "Ð\9dÑ\96деÑ\80ландÑ\81Ñ\8cкÑ\96 Ð\90нÑ\82илÑ\8cÑ\81Ñ\8cкÑ\96 оÑ\81Ñ\82Ñ\80ови"
#. :ANT:530:
#: zypp/CountryCode.cc:166
#. :ARG:032:
#: zypp/CountryCode.cc:169
msgid "American Samoa"
-msgstr "Африка, північ"
+msgstr "Американське Самоа"
#. :ASM:016:
#: zypp/CountryCode.cc:170
#. :BEL:056:
#: zypp/CountryCode.cc:179
msgid "Burkina Faso"
-msgstr "Буркіна Фасо"
+msgstr "Буркіна-Фасо"
#. :BFA:854:
#: zypp/CountryCode.cc:180
#. :BGR:100:
#: zypp/CountryCode.cc:181
msgid "Bahrain"
-msgstr "Бразилія"
+msgstr "Бахрейн"
#. :BHR:048:
#: zypp/CountryCode.cc:182
#. :BRA:076:
#: zypp/CountryCode.cc:188
msgid "Bahamas"
-msgstr "Ð\9fанама"
+msgstr "Ð\91агамÑ\81Ñ\8cкÑ\96 оÑ\81Ñ\82Ñ\80ови"
# BH
# fuzzy
#. :BLR:112:
#: zypp/CountryCode.cc:193
msgid "Belize"
-msgstr "Ð\91елÑ\8cгÑ\96Ñ\8f"
+msgstr "Ð\91елÑ\96з"
#. :BLZ:084:
#: zypp/CountryCode.cc:194
#. :CUB:192:
#: zypp/CountryCode.cc:208
msgid "Cape Verde"
-msgstr "Ð\9aапо Верде"
+msgstr "Ð\9aабо-Верде"
#. :CPV:132:
#: zypp/CountryCode.cc:209
#. :DNK:208:
#: zypp/CountryCode.cc:215
msgid "Dominica"
-msgstr "Ð Ñ\83мÑ\83нÑ\96Ñ\8f"
+msgstr "Ð\94омÑ\96нÑ\96ка"
#. :DMA:212:
#: zypp/CountryCode.cc:216
#. :ESP:724:
#: zypp/CountryCode.cc:224
msgid "Ethiopia"
-msgstr "Ð\95Ñ\81Ñ\82онія"
+msgstr "Ð\95Ñ\84Ñ\96опія"
#. :ETH:231:
#: zypp/CountryCode.cc:225
#. :GAB:266:
#: zypp/CountryCode.cc:233
msgid "United Kingdom"
-msgstr "Ð\9eб'Ñ\94днане Королівство"
+msgstr "СполÑ\83Ñ\87ене Королівство"
# GD
#. :GBR:826:
# fuzzy
#: zypp/CountryCode.cc:238
msgid "Ghana"
-msgstr "Ð\9aиÑ\82ай"
+msgstr "Ð\93ана"
#. :GHA:288:
#: zypp/CountryCode.cc:239
#. :GRL:304:
#: zypp/CountryCode.cc:241
msgid "Gambia"
-msgstr "Ямайка"
+msgstr "Ð\93амбÑ\96Ñ\8f"
# GU
# fuzzy
#. :GTM:320:
#: zypp/CountryCode.cc:248
msgid "Guam"
-msgstr "Гватемала"
+msgstr "Гуам"
#. :GUM:316:
#: zypp/CountryCode.cc:249
#. :GUY:328:
#: zypp/CountryCode.cc:251
msgid "Hong Kong"
-msgstr "Ð\93онг Ð\9aонг"
+msgstr "Ð\93онконг"
#. :HKG:344:
#: zypp/CountryCode.cc:252
#. :IRQ:368:
#: zypp/CountryCode.cc:264
msgid "Iran"
-msgstr "Ізраїль"
+msgstr "Іран"
#. :IRN:364:
#: zypp/CountryCode.cc:265
#. :KGZ:417:
#: zypp/CountryCode.cc:273
msgid "Cambodia"
-msgstr "Ð\9aолÑ\83мбÑ\96Ñ\8f"
+msgstr "Ð\9aамбоджа"
#. :KHM:116:
#: zypp/CountryCode.cc:274
#. :CYM:136:
#: zypp/CountryCode.cc:281
msgid "Kazakhstan"
-msgstr "ТайванÑ\8c"
+msgstr "Ð\9aазаÑ\85Ñ\81Ñ\82ан"
#. :KAZ:398:
#: zypp/CountryCode.cc:282
#. :LKA:144:
#: zypp/CountryCode.cc:287
msgid "Liberia"
-msgstr "СеÑ\80бія"
+msgstr "Ð\9bÑ\96беÑ\80ія"
#. :LBR:430:
#: zypp/CountryCode.cc:288
#. :MHL:584:
#: zypp/CountryCode.cc:300
msgid "Macedonia"
-msgstr "Македонія"
+msgstr "Ð\9fÑ\96внÑ\96Ñ\87на Ð\9cакедонÑ\96Ñ\8f"
# ML
# fuzzy
#. :MKD:807:
#: zypp/CountryCode.cc:301
msgid "Mali"
-msgstr "Ð\9cалÑ\8cÑ\82а"
+msgstr "Ð\9cалÑ\96"
# MM
# fuzzy
#. :MLI:466:
#: zypp/CountryCode.cc:302
msgid "Myanmar"
-msgstr "Ð\9fанама"
+msgstr "Ð\9câ\80\99Ñ\8fнма"
#. :MMR:104:
#: zypp/CountryCode.cc:303
#. :MNG:496:
#: zypp/CountryCode.cc:304
msgid "Macao"
-msgstr "Ð\9cалÑ\8cÑ\82а"
+msgstr "Ð\90оминÑ\8c"
#. :MAC:446:
#: zypp/CountryCode.cc:305
#. :MTQ:474:
#: zypp/CountryCode.cc:307
msgid "Mauritania"
-msgstr "Ð\9bиÑ\82ва"
+msgstr "Ð\9cавÑ\80Ñ\96Ñ\82анÑ\96Ñ\8f"
#. :MRT:478:
#: zypp/CountryCode.cc:308
#. :MLT:470:
#: zypp/CountryCode.cc:310
msgid "Mauritius"
-msgstr "Ð\9bиÑ\82ва"
+msgstr "Ð\9cавÑ\80Ñ\96кÑ\96й"
# MV
# fuzzy
#. :MUS:480:
#: zypp/CountryCode.cc:311
msgid "Maldives"
-msgstr "Мальта"
+msgstr "Мальдіви"
# MW
# fuzzy
#. :MDV:462:
#: zypp/CountryCode.cc:312
msgid "Malawi"
-msgstr "Мальта"
+msgstr "Малаві"
#. :MWI:454:
#: zypp/CountryCode.cc:313
#. :NAM:516:
#: zypp/CountryCode.cc:317
msgid "New Caledonia"
-msgstr "Ð\9cакедонія"
+msgstr "Ð\9dова Ð\9aаледонія"
# NG
# fuzzy
#. :PCN:612:
#: zypp/CountryCode.cc:338
msgid "Puerto Rico"
-msgstr "Пуерто ріко"
+msgstr "Пуерто-Ріко"
#. :PRI:630:
#: zypp/CountryCode.cc:339
#. :PRT:620:
#: zypp/CountryCode.cc:341
msgid "Palau"
-msgstr "Парагвай"
+msgstr "Палау"
#. :PLW:585:
#: zypp/CountryCode.cc:342
#. :RUS:643:
#: zypp/CountryCode.cc:348
msgid "Rwanda"
-msgstr "Ð\9aанада"
+msgstr "Ð Ñ\83анда"
#. :RWA:646:
#: zypp/CountryCode.cc:349
#. :SJM:744:
#: zypp/CountryCode.cc:358
msgid "Slovakia"
-msgstr "СловаÑ\86Ñ\8cка"
+msgstr "СловаÑ\87Ñ\87ина"
#. :SVK:703:
#: zypp/CountryCode.cc:359
#. :SEN:686:
#: zypp/CountryCode.cc:362
msgid "Somalia"
-msgstr "Ð Ñ\83мÑ\83нÑ\96Ñ\8f"
+msgstr "СомалÑ\96"
#. :SOM:706:
#: zypp/CountryCode.cc:363
#. :SLV:222:
#: zypp/CountryCode.cc:366
msgid "Syria"
-msgstr "СеÑ\80бія"
+msgstr "СиÑ\80ія"
# SZ
# fuzzy
#. :SYR:760:
#: zypp/CountryCode.cc:367
msgid "Swaziland"
-msgstr "ТаÑ\97ланд"
+msgstr "Ð\95Ñ\81ваÑ\82Ñ\96нÑ\96"
#. :SWZ:748:
#: zypp/CountryCode.cc:368
#. :TCA:796:
#: zypp/CountryCode.cc:369
msgid "Chad"
-msgstr "Ð\9aиÑ\82ай"
+msgstr "Чад"
#. :TCD:148:
#: zypp/CountryCode.cc:370
#. :UKR:804:
#: zypp/CountryCode.cc:385
msgid "Uganda"
-msgstr "Ð\9aанада"
+msgstr "Уганда"
# UM
# fuzzy
#. :UGA:800:
#: zypp/CountryCode.cc:386
msgid "United States Minor Outlying Islands"
-msgstr "США"
+msgstr "Ð\92Ñ\96ддаленÑ\96 оÑ\81Ñ\82Ñ\80ови СШÐ\90"
# US
# fuzzy
#. :UZB:860:
#: zypp/CountryCode.cc:390
msgid "Holy See (Vatican City State)"
-msgstr "Святий Престіл (Ватикан, місто-держава)"
+msgstr "Святий Престол (Ватикан, місто-держава)"
# VC
# fuzzy
#. :VIR:850:
#: zypp/CountryCode.cc:395
msgid "Vietnam"
-msgstr "В'єтнамська"
+msgstr "В'єтнам"
#. :VNM:704:
#: zypp/CountryCode.cc:396
#. :ZAF:710:
#: zypp/CountryCode.cc:402
msgid "Zambia"
-msgstr "Ямайка"
+msgstr "Ð\97амбÑ\96Ñ\8f"
#. :ZMB:894:
#: zypp/CountryCode.cc:403
#: zypp/Dep.cc:96
msgid "Provides"
-msgstr "Ð\9dадаÑ\94"
+msgstr "Ð\9eзнаки"
#: zypp/Dep.cc:97
msgid "Prerequires"
#: zypp/ExternalProgram.cc:362
#, c-format, boost-format
msgid "Can't chroot to '%s' (%s)."
-msgstr "Не вдалося створити chroot для \"%s\" (%s)."
+msgstr "Не вдалося створити chroot для «%s» (%s)."
#: zypp/ExternalProgram.cc:372
#, c-format, boost-format
msgid "Can't chdir to '%s' inside chroot '%s' (%s)."
-msgstr ""
-"Неможливо змінити каталог на '%s' всередині середовища chroot '%s' (%s)."
+msgstr "Неможливо зробити chdir «%s» всередині chroot «%s» (%s)."
#: zypp/ExternalProgram.cc:373
#, c-format, boost-format
msgid "Can't chdir to '%s' (%s)."
-msgstr "Ð\9dеможливо змÑ\96ниÑ\82и каÑ\82алог на '%s' (%s)."
+msgstr "Ð\9dеможливо змÑ\96ниÑ\82и диÑ\80екÑ\82оÑ\80Ñ\96Ñ\8e на «%s» (%s)."
#. don't want to get here
#: zypp/ExternalProgram.cc:385
#, c-format, boost-format
msgid "Can't exec '%s' (%s)."
-msgstr "Не вдалося виконати \"%s\" (%s)."
+msgstr "Не вдалося виконати «%s» (%s)."
#: zypp/ExternalProgram.cc:393
#, c-format, boost-format
#: zypp/ExternalProgram.cc:542
#, c-format, boost-format
msgid "Command was killed by signal %d (%s)."
-msgstr "Ð\9aомандÑ\83 бÑ\83ло зÑ\83пинено за сигналом %d (%s)."
+msgstr "Ð\9aомандÑ\83 бÑ\83ло вбиÑ\82о за сигналом %d (%s)."
#: zypp/ExternalProgram.cc:547
msgid "Command exited with unknown error."
#: zypp/KeyRing.cc:609
#, c-format, boost-format
msgid "Signature file %s not found"
-msgstr "Файл підпису \"%s\" не знайдено"
+msgstr "Файл підпису «%s» не знайдено"
#: zypp/LanguageCode.cc:49
msgid "Unknown language: "
#. language code: ara ar
#: zypp/LanguageCode.cc:201
msgid "Arabic"
-msgstr "Ð\90Ñ\80абÑ\81Ñ\8cкий"
+msgstr "Ð\90Ñ\80абÑ\81Ñ\8cка"
#. language code: arc
#: zypp/LanguageCode.cc:203
#. language code: arw
#: zypp/LanguageCode.cc:217
msgid "Arawak"
-msgstr "Аравак"
+msgstr "Аравацька"
#. language code: asm as
#: zypp/LanguageCode.cc:219
#. language code: ave ae
#: zypp/LanguageCode.cc:229
msgid "Avestan"
-msgstr "Авестан"
+msgstr "Авестійська"
# SZ
# fuzzy
#: zypp/RepoInfo.cc:517
#, boost-format
msgid "Looking for gpg key ID %1% in cache %2%."
-msgstr ""
+msgstr "Пошук ID ключа для gpg %1% у кеші %2%."
#. translator: %1% is a gpg key ID like 3DBDC284
#. %2% is a repositories name
#: zypp/RepoInfo.cc:545
#, boost-format
msgid "Looking for gpg key ID %1% in repository %2%."
-msgstr ""
+msgstr "Пошук ID ключа для gpg %1% у сховищі %2%."
#. translator: %1% is a repositories name
#: zypp/RepoInfo.cc:569
#, boost-format
msgid "Repository %1% does not define additional 'gpgkey=' URLs."
-msgstr ""
+msgstr "Сховище %1% не визначає додаткові мережеві адреси для «gpgkey=»."
#: zypp/RepoManager.cc:312
#, boost-format
msgid "Cannot read repo directory '%1%': Permission denied"
-msgstr "Ð\9dеможливо пÑ\80оÑ\87иÑ\82аÑ\82и каÑ\82алог Ñ\81Ñ\85овиÑ\89а '%1%': Ð\94оÑ\81Ñ\82Ñ\83п забоÑ\80онений"
+msgstr "Ð\9dеможливо пÑ\80оÑ\87иÑ\82аÑ\82и диÑ\80екÑ\82оÑ\80Ñ\96Ñ\8e Ñ\81Ñ\85овиÑ\89а '%1%': Ð\94оÑ\81Ñ\82Ñ\83п забоÑ\80онено"
#. TranslatorExplanation '%s' is a pathname
#: zypp/RepoManager.cc:320 zypp/RepoManager.cc:783 zypp/RepoManager.cc:1536
#: zypp/repo/PluginServices.cc:49
#, c-format, boost-format
msgid "Failed to read directory '%s'"
-msgstr "Ð\9dе вдалоÑ\81Ñ\8c пÑ\80оÑ\87иÑ\82аÑ\82и каÑ\82алог «%s»"
+msgstr "Ð\9dе вдалоÑ\81Ñ\8c пÑ\80оÑ\87иÑ\82аÑ\82и диÑ\80екÑ\82оÑ\80Ñ\96Ñ\8e «%s»"
#: zypp/RepoManager.cc:330
#, boost-format
#: zypp/RepoManager.cc:1148
msgid "Can't create metadata cache directory."
-msgstr "Ð\9dеможливо Ñ\81Ñ\82воÑ\80иÑ\82и каÑ\82алог кешу метаданих."
+msgstr "Ð\9dеможливо Ñ\81Ñ\82воÑ\80иÑ\82и диÑ\80екÑ\82оÑ\80Ñ\96Ñ\8e кешу метаданих."
#: zypp/RepoManager.cc:1294
#, c-format, boost-format
msgid "Building repository '%s' cache"
-msgstr "Створення кешу сховища \"%s\""
+msgstr "Створення кешу сховища «%s»"
#: zypp/RepoManager.cc:1314
#, c-format, boost-format
#: zypp/RepoManager.cc:1618
#, c-format, boost-format
msgid "Adding repository '%s'"
-msgstr "Додавання сховища \"%s\""
+msgstr "Додавання сховища «%s»"
#. TranslatorExplanation '%s' is an URL
#: zypp/RepoManager.cc:1706
#: zypp/RepoManager.cc:1747
#, c-format, boost-format
msgid "Removing repository '%s'"
-msgstr "Вилучення сховища \"%s\""
+msgstr "Вилучення сховища «%s»"
#: zypp/RepoManager.cc:1766 zypp/RepoManager.cc:1844
msgid "Can't figure out where the repo is stored."
#: zypp/Url.cc:153
#, c-format, boost-format
msgid "Invalid LDAP URL query parameter '%s'"
-msgstr "Не чинний параметр запиту \"%s\" URL LDAP"
+msgstr "Не чинний параметр запиту «%s» URL LDAP"
#: zypp/Url.cc:301
msgid "Unable to clone Url object"
#: zypp/VendorSupportOptions.cc:31
msgid "invalid"
-msgstr "нечинний"
+msgstr "недійсний"
#: zypp/VendorSupportOptions.cc:39
msgid "The level of support is unspecified"
#: zypp/base/StrMatcher.cc:157
#, c-format, boost-format
msgid "Invalid regular expression '%s': regcomp returned %d"
-msgstr "Некоректний формальний вираз \"%s\": regcomp повернула %d"
+msgstr "Некоректний формальний вираз «%s»: regcomp повернула %d"
#: zypp/base/StrMatcher.cc:158
#, c-format, boost-format
msgid "Invalid regular expression '%s'"
-msgstr "Нечинний формальний вираз «%s»"
+msgstr "Недійсний формальний вираз «%s»"
#. !\todo add comma to the message for the next release
#: zypp/media/MediaCIFS.cc:427 zypp/media/MediaCurl.cc:1738
#, c-format, boost-format
msgid "Authentication required for '%s'"
-msgstr "Потрібна автентифікація для \"%s\""
+msgstr "Потрібна автентифікація для «%s»"
#: zypp/media/MediaCurl.cc:1111
msgid ""
"Visit the SUSE Customer Center to check whether your registration is valid "
"and has not expired."
msgstr ""
+"Відвідайте Центр клієнтів SUSE, щоб перевірити, чи ваша реєстрація дійсна та "
+"чи не закінчився термін дії."
#: zypp/media/MediaCurl.cc:1113
msgid ""
#: zypp/media/MediaException.cc:53
#, c-format, boost-format
msgid "Medium not opened when trying to perform action '%s'."
-msgstr "Носій не було відкрито під час спроби виконання дії \"%s\"."
+msgstr "Носій не було відкрито під час спроби виконання дії «%s»."
#: zypp/media/MediaException.cc:58
#, c-format, boost-format
msgid "File '%s' not found on medium '%s'"
-msgstr "Файл \"%s\" не знайдено на носії \"%s\""
+msgstr "Файл «%s» не знайдено на носії «%s»"
#: zypp/media/MediaException.cc:63
#, c-format, boost-format
msgid "Cannot write file '%s'."
-msgstr "Неможливо записати у файл \"%s\"."
+msgstr "Неможливо записати у файл «%s»."
#: zypp/media/MediaException.cc:68
msgid "Medium not attached"
#: zypp/media/MediaException.cc:79
#, c-format, boost-format
msgid "Download (curl) initialization failed for '%s'"
-msgstr "Започаткування завантаження (curl) зазнало невдачі для \"%s\""
+msgstr "Започаткування завантаження (curl) зазнало невдачі для «%s»"
#: zypp/media/MediaException.cc:84
#, c-format, boost-format
msgid "System exception '%s' on medium '%s'."
-msgstr "Системне виключення \"%s\" на носії \"%s\"."
+msgstr "Системне виключення «%s» на носії «%s»."
#: zypp/media/MediaException.cc:89
#, c-format, boost-format
msgid "Path '%s' on medium '%s' is not a file."
-msgstr "Шлях \"%s\" на носії \"%s\" не є файлом."
+msgstr "Шлях «%s» на носії «%s» не є файлом."
#: zypp/media/MediaException.cc:94
#, c-format, boost-format
msgid "Path '%s' on medium '%s' is not a directory."
-msgstr "Шлях \"%s\" на носії \"%s\" не є каталогом."
+msgstr "Шлях «%s» на носії «%s» не є директорією."
#: zypp/media/MediaException.cc:101
msgid "Malformed URI"
#: zypp/media/MediaException.cc:126
#, c-format, boost-format
msgid "Unsupported URI scheme in '%s'."
-msgstr "Непідтримувана схема URI у \"%s\"."
+msgstr "Непідтримувана схема URI у «%s»."
#: zypp/media/MediaException.cc:131
msgid "Operation not supported by medium"
"Error code: %s\n"
"Error message: %s\n"
msgstr ""
-"Помилка завантаження (curl) для \"%s\":\n"
+"Помилка завантаження (curl) для «%s»:\n"
"Код помилки: %s\n"
"Повідомлення про помилку: %s\n"
#, c-format, boost-format
msgid "Error occurred while setting download (curl) options for '%s':"
msgstr ""
-"Під час встановлення параметрів завантаження (curl) для \"%s\" сталася "
-"помилка:"
+"Під час встановлення параметрів завантаження (curl) для «%s» сталася помилка:"
#: zypp/media/MediaException.cc:153
#, c-format, boost-format
msgid "Media source '%s' does not contain the desired medium"
-msgstr "Пристрій носія \"%s\" не містить бажаного носія"
+msgstr "Пристрій носія «%s» не містить бажаного носія"
#: zypp/media/MediaException.cc:158
#, c-format, boost-format
msgid "Medium '%s' is in use by another instance"
-msgstr "Носій \"%s\" використовується іншою копією програми"
+msgstr "Носій «%s» використовується іншою копією програми"
#: zypp/media/MediaException.cc:164
msgid "Cannot eject any media"
#: zypp/media/MediaException.cc:166
#, c-format, boost-format
msgid "Cannot eject media '%s'"
-msgstr "Не вдається виштовхнути носія \"%s\""
+msgstr "Не вдається виштовхнути носія «%s»"
#: zypp/media/MediaException.cc:181
#, c-format, boost-format
msgid "Permission to access '%s' denied."
-msgstr "Дозвіл на доступ до \"%s\" заборонено."
+msgstr "Дозвіл на доступ до «%s» заборонено."
#: zypp/media/MediaException.cc:189
#, c-format, boost-format
msgid "Timeout exceeded when accessing '%s'."
-msgstr "Перевищено час очікування при спробі доступу до '%s'."
+msgstr "Перевищено час очікування при спробі доступу до «%s»."
#: zypp/media/MediaException.cc:197
#, c-format, boost-format
msgid "Downloaded data exceeded the expected filesize '%s' of '%s'."
-msgstr ""
+msgstr "Завантажені дані перевищили очікуваний розмір файлу «%s» у «%s»."
#: zypp/media/MediaException.cc:205
#, c-format, boost-format
msgid " SSL certificate problem, verify that the CA cert is OK for '%s'."
msgstr ""
" Проблема з сертифікатом SSL, перевірте чи все гаразд з сертифікатом CA для "
-"\"%s\"."
+"«%s»."
#: zypp/media/MediaHandler.cc:370
msgid ""
"Create attach point: Can't find a writable directory to create an attach "
"point"
msgstr ""
-"СÑ\82воÑ\80Ñ\8eÑ\94мо Ñ\82оÑ\87кÑ\83 монÑ\82Ñ\83ваннÑ\8f: неможливо знайÑ\82и каÑ\82алог з можливÑ\96Ñ\81Ñ\82Ñ\8e запиÑ\81Ñ\83 длÑ\8f "
-"створення точки монтування"
+"СÑ\82воÑ\80Ñ\8eÑ\94мо Ñ\82оÑ\87кÑ\83 монÑ\82Ñ\83ваннÑ\8f: неможливо знайÑ\82и диÑ\80екÑ\82оÑ\80Ñ\96Ñ\8e з можливÑ\96Ñ\81Ñ\82Ñ\8e запиÑ\81Ñ\83 "
+"для створення точки монтування"
#: zypp/media/MediaUserAuth.cc:136
#, c-format, boost-format
msgid "Unsupported HTTP authentication method '%s'"
-msgstr "Метод автентифікації HTTP \"%s\", який не підтримується"
+msgstr "Метод автентифікації HTTP «%s», який не підтримується"
#: zypp/misc/CheckAccessDeleted.cc:444
msgid "Please install package 'lsof' first."
#: zypp/repo/RepoProvideFile.cc:261
#, c-format, boost-format
msgid "Can't provide file '%s' from repository '%s'"
-msgstr "Неможливо надати файл \"%s\" зі сховища \"%s\""
+msgstr "Неможливо надати файл «%s» зі сховища «%s»"
#: zypp/repo/RepoProvideFile.cc:267
msgid "No url in repository."
#: zypp/solver/detail/SATResolver.cc:1386
#, boost-format
msgid "install %1% although it has been retracted"
-msgstr ""
+msgstr "встановити %1% хоч він і був відкладений"
#. translator: %1% is a package name
#: zypp/solver/detail/SATResolver.cc:1389
#, boost-format
msgid "allow to install the PTF %1%"
-msgstr ""
+msgstr "дозволити встановити PTF %1%"
#. translator: %1% is a package name
#: zypp/solver/detail/SATResolver.cc:1392
#, boost-format
msgid "install %1% although it is blacklisted"
-msgstr ""
+msgstr "встановити %1% хоч він і був у чорному списку"
#: zypp/solver/detail/SATResolver.cc:1412
#, c-format, boost-format
#: zypp/url/UrlBase.cc:173
#, c-format, boost-format
msgid "Invalid %s component '%s'"
-msgstr "Не чинний %s компонент \"%s\""
+msgstr "Не чинний %s компонент «%s»"
#: zypp/url/UrlBase.cc:180
#, c-format, boost-format
#: zypp/url/UrlBase.cc:830
#, c-format, boost-format
msgid "Invalid Url scheme '%s'"
-msgstr "Не чинна схема URL \"%s\""
+msgstr "Не чинна схема URL «%s»"
#: zypp/url/UrlBase.cc:949
msgid "Url scheme does not allow a username"
#: zypp/url/UrlBase.cc:1049
#, c-format, boost-format
msgid "Invalid host component '%s'"
-msgstr "Не чинний компонент вузла \"%s\""
+msgstr "Не чинний компонент вузла «%s»"
#: zypp/url/UrlBase.cc:1070
msgid "Url scheme does not allow a port"
#: zypp/url/UrlBase.cc:1081
#, c-format, boost-format
msgid "Invalid port component '%s'"
-msgstr "Не чинний компонент порту \"%s\""
+msgstr "Не чинний компонент порту «%s»"
#: zypp/url/UrlBase.cc:1098
msgid "Url scheme requires path name"
return pck.name() + "-" + pck.edition().asString() + "." + pck.arch().asString();
}
- using TestSample = std::tuple<Pathname, std::string, zypp::Arch, std::string, std::map<std::string, bool> >;
+ using TestSample = std::tuple<
+ Pathname, // repoPath
+ std::string, // uname_r
+ zypp::Arch, // arch
+ std::string, // keepSpec
+ std::map<std::string, bool> // expectedRems
+ >;
std::vector<TestSample> maketestdata() {
return {
// left over devel packages that need to go away too
{ "kernel-devel-1-1.2.noarch", false },
{ "kernel-source-1-1.2.noarch", false },
- { "kernel-default-devel-1-3.2.x86_64", false },
- { "kernel-devel-1-3.2.noarch", false },
- { "kernel-source-1-3.2.noarch", false },
+ { "kernel-default-devel-1-3.x86_64", false },
+ { "kernel-default-devel-debuginfo-1-3.x86_64", false },
+ { "kernel-devel-1-3.noarch", false },
}
},
//test that keeps only the running kernel
// left over devel packages that need to go away too
{ "kernel-devel-1-1.2.noarch", false },
{ "kernel-source-1-1.2.noarch", false },
- { "kernel-default-devel-1-3.2.x86_64", false },
- { "kernel-devel-1-3.2.noarch", false },
- { "kernel-source-1-3.2.noarch", false },
+ { "kernel-default-devel-1-3.x86_64", false },
+ { "kernel-devel-1-3.noarch", false },
+ { "kernel-default-devel-1-3.x86_64", false },
+ { "kernel-default-devel-debuginfo-1-3.x86_64", false },
}
},
TestSample {
{ "kernel-syms-1-5.x86_64", false },
{ "dummy-kmp-default-1-0.x86_64", false },
// left over devel packages that need to go away too
- { "kernel-devel-1-1.2.noarch", false },
- { "kernel-source-1-1.2.noarch", false },
- { "kernel-default-devel-1-3.2.x86_64", false },
- { "kernel-devel-1-3.2.noarch", false },
- { "kernel-source-1-3.2.noarch", false },
+ { "kernel-default-devel-1-3.x86_64", false },
+ { "kernel-default-devel-debuginfo-1-3.x86_64", false },
+ { "kernel-devel-1-3.noarch", false },
}
},
TestSample {
{ "kernel-devel-1-2.noarch", false },
{ "kernel-livepatch-default-1-2.x86_64", false },
{ "kernel-syms-1-2.x86_64", false },
+ // the following packages are not held back because they do not fit keep spec and no deps are keeping them
+ { "kernel-default-devel-1-1.x86_64", false },
+ { "kernel-default-devel-debuginfo-1-1.x86_64", false },
+ { "kernel-devel-1-1.noarch", false},
+ { "kernel-syms-1-1.x86_64", false},
}
},
TestSample {
{ "kernel-devel-1-2.noarch", false },
{ "kernel-livepatch-default-1-2.x86_64", false },
{ "kernel-syms-1-2.x86_64", false },
+ { "kernel-default-devel-1-5.x86_64", false },
+ { "kernel-default-devel-debuginfo-1-5.x86_64", false },
+ { "kernel-devel-1-5.noarch", false },
+ { "kernel-syms-1-5.x86_64", false },
}
},
TestSample {
Arch("x86_64"),
"running,1-2",
{
+ { "kernel-default-devel-1-5.x86_64", false },
+ { "kernel-default-devel-debuginfo-1-5.x86_64", false },
+ { "kernel-devel-1-5.noarch", false },
+ { "kernel-syms-1-5.x86_64", false },
}
},
TestSample {
{ "kernel-default-1-1.aarch64", false },
{ "kernel-default-1-1.i686", false },
- /*
- { "kernel-default-devel-1-1.x86_64", false },
- { "kernel-default-devel-debuginfo-1-1.x86_64", false },
- { "kernel-syms-1-1.x86_64", false },
- */
+ //{ "kernel-syms-1-1.x86_64", false },
+ //{ "kernel-default-devel-1-1.x86_64", false },
+ //{ "kernel-default-devel-debuginfo-1-1.x86_64", false },
{ "kernel-default-1-2.aarch64", false },
{ "kernel-default-1-2.i686", false },
{ "kernel-livepatch-default-1-2.i686", false },
{ "kernel-livepatch-default-1-2.x86_64", false },
- /*
- Since kernel-syms package requires do not care about architecture, every kernel-syms
- package for flavour-version will be kept as long as a kernel-flavour-devel package of any arch is installed
{ "kernel-syms-1-1.aarch64", false },
{ "kernel-syms-1-1.i686", false },
- */
+
{ "kernel-syms-1-2.aarch64", false },
{ "kernel-syms-1-2.i686", false },
{ "kernel-syms-1-2.x86_64", false },
}
},
+ TestSample {
+ TESTS_SRC_DIR"/zypp/data/PurgeKernels/rebuild",
+ "1-1-default",
+ Arch("x86_64"),
+ "running",
+ {
+ { "kernel-source-1-1.noarch", false },
+ }
+ }
};
}
}
removeCount++;
auto pck = expectedRemovals.find( makeNVRA(*it) );
- BOOST_REQUIRE_MESSAGE( pck != expectedRemovals.end(), std::string("Unexpected package removed: ") + makeNVRA(*it) );
+ BOOST_REQUIRE_MESSAGE( pck != expectedRemovals.end(), std::string("Unexpected package removed: ") + makeNVRA(*it) + (it->status().isByUser() ? " (by user)" : " (autoremoved)") );
pck->second = true;
}
#include <zypp/base/LogTools.h>
#include <zypp/base/String.h>
+#include <zypp/base/Regex.h>
using boost::unit_test::test_suite;
using boost::unit_test::test_case;
}
}
}
+
+BOOST_AUTO_TEST_CASE(regex_subst)
+{
+ const std::string input = "StRi_g: Hello this is a StRiNg with multiple Stri_g mentions to replace StRi_g";
+ str::regex rxexpr( "(St[rR]i[nN_]g)" );
+ BOOST_REQUIRE_EQUAL( rxexpr.get()->re_nsub, 1 );
+
+ {
+ const std::string result = str::regex_substitute( input, rxexpr, "FooBar", true );
+ BOOST_REQUIRE_EQUAL( result, "FooBar: Hello this is a FooBar with multiple FooBar mentions to replace FooBar" );
+ }
+
+ {
+ const std::string result = str::regex_substitute( input, rxexpr, "FooBar", false );
+ BOOST_REQUIRE_EQUAL( result, "FooBar: Hello this is a StRiNg with multiple Stri_g mentions to replace StRi_g" );
+ }
+
+ {
+ const std::string nomatch = "Text with no match";
+ const std::string result = str::regex_substitute( nomatch , rxexpr, "FooBar", false );
+ BOOST_REQUIRE_EQUAL( result, nomatch );
+ }
+
+ {
+ const std::string input = "StRi_gString: Hello this is a StRiNg with multiple Stri_g mentions to replace StRi_g";
+ str::regex rxexpr( "(^St[rR]i[nN_]g)" );
+ const std::string result = str::regex_substitute( input, rxexpr, "FooBar", true );
+ BOOST_REQUIRE_EQUAL( result, "FooBarString: Hello this is a StRiNg with multiple Stri_g mentions to replace StRi_g" );
+ }
+
+ {
+ const std::string input = "StRi_gString\n: Hello this is a StRiNg with multiple Stri_g mentions to replace StRi_g";
+ str::regex rxexpr( "(String$)", str::regex::match_extended | str::regex::newline );
+ const std::string result = str::regex_substitute( input, rxexpr, "FooBar", true );
+ BOOST_REQUIRE_EQUAL( result, "StRi_gFooBar\n: Hello this is a StRiNg with multiple Stri_g mentions to replace StRi_g" );
+ }
+
+ {
+ const std::string input = "Hello StRi_gString\n: Hello.";
+ str::regex rxexpr( "((^: Hello)|(String\n))", str::regex::match_extended);
+ const std::string result = str::regex_substitute( input, rxexpr, " FooBar", true );
+ BOOST_REQUIRE_EQUAL( result, "Hello StRi_g FooBar FooBar." );
+ }
+
+ {
+ const std::string input = "4.12.14-lp151.28.48-default";
+ const std::string flavour = str::regex_substitute( input, str::regex( ".*-", str::regex::match_extended ), "", true );
+ BOOST_REQUIRE_EQUAL( flavour, "default" );
+ std::string version = str::regex_substitute( input, str::regex( "-[^-]*$", str::regex::match_extended ), "", true );
+ BOOST_REQUIRE_EQUAL( version, "4.12.14-lp151.28.48" );
+ const std::string release = str::regex_substitute( version, str::regex( ".*-", str::regex::match_extended ), "", true );
+ BOOST_REQUIRE_EQUAL( release, "lp151.28.48" );
+ }
+
+}
<!-- END KERNEL SET -->
-</channel></subchannel>
+</subchannel>
+</channel>
--- /dev/null
+<channel><subchannel>
+<package>
+ <name>glibc</name>
+ <vendor>openSUSE</vendor>
+ <history>
+ <update>
+ <arch>x86_64</arch>
+ <version>1</version><release>1</release>
+ </update>
+ </history>
+ <provides>
+ <dep name='glibc' op='==' version='1' release='1' />
+ </provides>
+</package>
+
+<package>
+ <name>kernel-firmware</name>
+ <provides>
+ <dep name='kernel-firmware' op='==' version='20190312' release='lp151.2.3.1' />
+ </provides>
+</package>
+
+<package>
+ <name>kernel-macros</name>
+ <vendor>openSUSE</vendor>
+ <history>
+ <update>
+ <arch>noarch</arch>
+ <version>1</version><release>0</release>
+ </update>
+ </history>
+ <provides>
+ <dep name='kernel-subpackage-macros' />
+ <dep name='kernel-macros' op='==' version='1' release='0' />
+ </provides>
+</package>
+
+<!-- START KERNEL SET -->
+<package>
+ <name>kernel-default</name>
+ <vendor>openSUSE</vendor>
+ <history>
+ <update>
+ <arch>x86_64</arch>
+ <version>1</version><release>1.2</release>
+ </update>
+ </history>
+ <provides>
+ <dep name='multiversion(kernel)' />
+ <dep name='kernel-default-1-1' />
+ <dep name='kernel' op='==' version='1' release='1' />
+ <dep name='kernel-default' op='==' version='1' release='1' />
+ <dep name='kernel-default' op='==' version='1' release='1.2' />
+ <dep name='kernel-uname-r' op='==' version='1-1' release='default' />
+ </provides>
+ <recommends>
+ <dep name='kernel-firmware' />
+ </recommends>
+</package>
+
+<package>
+ <name>kernel-default-devel</name>
+ <vendor>openSUSE</vendor>
+ <history>
+ <update>
+ <arch>x86_64</arch>
+ <version>1</version><release>1.2</release>
+ </update>
+ </history>
+ <provides>
+ <dep name='multiversion(kernel)' />
+ <dep name='kernel-default-devel' op='==' version='1' release='1.2' />
+ </provides>
+ <requires>
+ <dep name='kernel-devel' op='==' version='1' release='1.2' />
+ </requires>
+ <supplements>
+ <dep name='packageand(kernel-default:kernel-devel)' />
+ </supplements>
+</package>
+
+<package>
+ <name>kernel-default-devel-debuginfo</name>
+ <vendor>openSUSE</vendor>
+ <history>
+ <update>
+ <arch>x86_64</arch>
+ <version>1</version><release>1.2</release>
+ </update>
+ </history>
+ <provides>
+ <dep name='kernel-default-devel-debuginfo' op='==' version='1' release='1.2' />
+ </provides>
+</package>
+
+<package>
+ <name>kernel-devel</name>
+ <vendor>openSUSE</vendor>
+ <history>
+ <update>
+ <arch>noarch</arch>
+ <version>1</version><release>1</release>
+ </update>
+ </history>
+ <provides>
+ <dep name='multiversion(kernel)' />
+ <dep name='kernel-devel' op='==' version='1' release='1' />
+ <dep name='kernel-devel' op='==' version='1' release='1.2' />
+ </provides>
+ <requires>
+ <dep name='kernel-macros' />
+ </requires>
+</package>
+
+<package>
+ <name>kernel-source</name>
+ <vendor>openSUSE</vendor>
+ <history>
+ <update>
+ <arch>noarch</arch>
+ <version>1</version><release>1</release>
+ </update>
+ </history>
+ <provides>
+ <dep name='multiversion(kernel)' />
+ <dep name='kernel-source' op='==' version='1' release='1' />
+ </provides>
+ <requires>
+ <dep name='kernel-devel' op='==' version='1' release='1' />
+ </requires>
+</package>
+
+
+<package>
+ <name>kernel-source</name>
+ <vendor>openSUSE</vendor>
+ <history>
+ <update>
+ <arch>noarch</arch>
+ <version>1</version><release>1.2</release>
+ </update>
+ </history>
+ <provides>
+ <dep name='multiversion(kernel)' />
+ <dep name='kernel-source' op='==' version='1' release='1.2' />
+ </provides>
+ <requires>
+ <dep name='kernel-devel' op='==' version='1' release='1.2' />
+ </requires>
+</package>
+
+<package>
+ <name>kernel-syms</name>
+ <vendor>openSUSE</vendor>
+ <buildtime>1570603549</buildtime>
+ <history>
+ <update>
+ <arch>x86_64</arch>
+ <version>1</version><release>1</release>
+ </update>
+ </history>
+ <provides>
+ <dep name='multiversion(kernel)' />
+ <dep name='kernel-syms' op='==' version='1' release='1' />
+ </provides>
+ <requires>
+ <dep name='kernel-devel' op='==' version='1' release='1' />
+ <dep name='kernel-default-devel' op='==' version='1' release='1' />
+ </requires>
+</package>
+<!-- END KERNEL SET -->
+
+</channel></subchannel>
--- /dev/null
+<?xml version="1.0"?>
+<test>
+<setup arch="x86_64">
+ <system file="solver-system.xml"/>
+ <locale name="en_US" />
+ <locale name="de" />
+</setup>
+</test>
</update>
</history>
<provides>
+ <dep name='multiversion(kernel)' />
<dep name='kernel-source' op='==' version='1' release='1' />
</provides>
<requires>
</history>
<provides>
<dep name='multiversion(kernel)' />
+ <dep name='kernel-devel' op='==' version='1' release='1' />
<dep name='kernel-devel' op='==' version='1' release='1.2' />
</provides>
<requires>
</update>
</history>
<provides>
+ <dep name='multiversion(kernel)' />
+ <dep name='kernel-source' op='==' version='1' release='1' />
<dep name='kernel-source' op='==' version='1' release='1.2' />
</provides>
<requires>
</history>
<provides>
<dep name='multiversion(kernel)' />
+ <dep name='kernel-default-devel' op='==' version='1' release='3' />
<dep name='kernel-default-devel' op='==' version='1' release='3.2' />
</provides>
<requires>
</history>
<provides>
<dep name='multiversion(kernel)' />
+ <dep name='kernel-devel' op='==' version='1' release='3' />
<dep name='kernel-devel' op='==' version='1' release='3.2' />
</provides>
<requires>
</update>
</history>
<provides>
+ <dep name='multiversion(kernel)' />
+ <dep name='kernel-source' op='==' version='1' release='3' />
<dep name='kernel-source' op='==' version='1' release='3.2' />
</provides>
<requires>
</provides>
<requires>
<dep name='kernel-default-devel'/>
- <dep name='ksym(foobar)' op='==' version='abdcfee' />
+ <dep name='ksym(foobar)' op='==' version='abdcfee' />
</requires>
</package>
</provides>
<requires>
<dep name='kernel-default-devel'/>
- <dep name='ksym(foobar)' op='==' version='abdcfee' />
+ <dep name='ksym(foobar)' op='==' version='abdcfee' />
</requires>
</package>
<dep name='package-needing-krnlmodule' op='==' version='1' release='0' />
</provides>
<requires>
- <dep name='dummy-kmp-default' op='==' version='1' release='0' />
+ <dep name='dummy-kmp-default' op='==' version='1' release='0' />
</requires>
</package>
#include <zypp/zyppng/media/network/networkrequesterror.h>
#include <zypp/zyppng/media/network/networkrequestdispatcher.h>
#include <zypp/zyppng/media/network/request.h>
+#include <zypp/media/CredentialManager.h>
#include <zypp/TmpPath.h>
#include <zypp/PathInfo.h>
#include <zypp/ZConfig.h>
BOOST_REQUIRE( !gotAuthRequest );
}
}
+
+/**
+ * Test for bsc#1174011 auth=basic ignored in some cases
+ *
+ * If the URL specifes ?auth=basic libzypp should proactively send credentials we have available in the cred store
+ */
+BOOST_DATA_TEST_CASE( dltest_auth_basic, bdata::make( withSSL ), withSSL )
+{
+ //don't write or read creds from real settings dir
+ zypp::filesystem::TmpDir repoManagerRoot;
+ zypp::ZConfig::instance().setRepoManagerRoot( repoManagerRoot.path() );
+
+ auto ev = zyppng::EventDispatcher::createMain();
+
+ zyppng::Downloader downloader;
+
+ WebServer web((zypp::Pathname(TESTS_SRC_DIR)/"/zyppng/data/downloader").c_str(), 10001, withSSL );
+ BOOST_REQUIRE( web.start() );
+
+ zypp::filesystem::TmpFile targetFile;
+ zyppng::Url weburl (web.url());
+ weburl.setPathName("/handler/test.txt");
+ weburl.setQueryParam("auth", "basic");
+ weburl.setUsername("test");
+
+ // make sure the creds are already available
+ zypp::media::CredentialManager cm( repoManagerRoot.path() );
+ zypp::media::AuthData data ("test", "test");
+ data.setUrl( weburl );
+ cm.addCred( data );
+ cm.save();
+
+ zyppng::TransferSettings set = web.transferSettings();
+
+ web.addRequestHandler( "test.txt", createAuthHandler() );
+ web.addRequestHandler( "quit", [ &ev ]( WebServer::Request & ){ ev->quit();} );
+
+ {
+ // simply check by request count if the test was successfull:
+ // if the proactive code adding the credentials to the first request is not executed we will
+ // have more than 1 request.
+ int reqCount = 0;
+ auto dispatcher = downloader.requestDispatcher();
+ dispatcher->sigDownloadStarted().connect([&]( zyppng::NetworkRequestDispatcher &, zyppng::NetworkRequest & ){
+ reqCount++;
+ });
+
+
+ auto dl = downloader.downloadFile( weburl, targetFile.path() );
+ dl->setMultiPartHandlingEnabled( false );
+
+ dl->settings() = set;
+
+ dl->sigFinished( ).connect([ &ev ]( zyppng::Download & ){
+ ev->quit();
+ });
+
+ dl->start();
+ ev->run();
+ BOOST_TEST_REQ_SUCCESS( dl );
+ BOOST_REQUIRE_EQUAL( reqCount, 1 );
+ }
+}
#include <zypp/base/String.h>
#include <zypp/base/Logger.h>
#include <zypp/base/Regex.h>
+#include <zypp/base/Iterator.h>
#include <zypp/ui/Selectable.h>
#include <zypp/PurgeKernels.h>
#include <zypp/PoolQuery.h>
#include <map>
#include <unordered_map>
#include <sys/utsname.h>
+#include <functional>
+#include <array>
#undef ZYPP_BASE_LOGGER_LOGGROUP
#define ZYPP_BASE_LOGGER_LOGGROUP "PurgeKernels"
namespace zypp {
+ using Flavour = std::string;
+ using SolvableList = std::list<sat::Solvable::IdType>;
+ using EditionToSolvableMap = std::map<Edition, SolvableList >;
+ using ArchToEditionMap = std::map<Arch, EditionToSolvableMap >;
+
+ struct GroupInfo {
+
+ enum GroupType {
+ None, //<< Just here to support default construction
+ Kernels, //<< Map contains kernel packages, so need to receive special handling and flavour matching
+ RelatedBinaries, //<< Map contains related binary packages, so need to receive special handling and flavour matching
+ Sources //<< Map contains source packages, so when matching those against running we ignore the flavour
+ } groupType;
+
+ GroupInfo( const GroupType type = None, std::string flav = "") : groupType(type), groupFlavour( std::move(flav) ) { }
+
+ ArchToEditionMap archToEdMap; //<< Map of actual packages
+ std::string groupFlavour; //<< This would contain a specific flavour if there is one calculated
+ };
+ using GroupMap = std::unordered_map<std::string, GroupInfo>;
+
struct PurgeKernels::Impl {
Impl() {
struct utsname unameData;
if ( uname( &unameData) == 0 ) {
- _kernelArch = Arch( unameData.machine );
- _uname_r = std::string( unameData.release );
+
+ const auto archStr = str::regex_substitute( unameData.machine, str::regex( "^i.86$", str::regex::match_extended ), "i586" );
+
+ _kernelArch = Arch( archStr );
+ setUnameR( std::string( unameData.release ) );
+
+ _detectedRunning = true;
+
+ MIL << "Detected running kernel: " << _runningKernelEdition << " " << _runningKernelFlavour << " " << _kernelArch << std::endl;
+
+ } else {
+ MIL << "Failed to detect running kernel: " << errno << std::endl;
}
}
- bool removePackageAndCheck( PoolItem &item, const str::regex &validRemovals ) const;
- void parseKeepSpec();
- void fillKeepList( const std::unordered_map< std::string, std::map< Arch, std::map<Edition, sat::Solvable> > > &installedKernels, std::set<sat::Solvable::IdType> &list ) const;
- void cleanDevelAndSrcPackages ( const str::regex &validRemovals, std::set<Edition> &validEditions, const std::string &flavour = std::string() );
+ void setUnameR ( const std::string &uname ) {
- static std::string detectRunningKernel() {
+ _uname_r = uname;
- std::string kernelVersion;
- std::ifstream procKernel( "/proc/sys/kernel/osrelease" );
- if ( procKernel ) {
- std::getline( procKernel, kernelVersion );
- }
- return kernelVersion;
+ MIL << "Set uname " << uname << std::endl;
+
+ const std::string flavour = str::regex_substitute( _uname_r, str::regex( ".*-", str::regex::match_extended ), "", true );
+ std::string version = str::regex_substitute( _uname_r, str::regex( "-[^-]*$", str::regex::match_extended | str::regex::newline ), "", true );
+ const std::string release = str::regex_substitute( version, str::regex( ".*-", str::regex::match_extended ), "", true );
+
+ version = str::regex_substitute( version, str::regex( "-[^-]*$", str::regex::match_extended | str::regex::newline ), "", true );
+
+ // from purge-kernels script, was copied from kernel-source/rpm/mkspec
+ version = str::regex_substitute( version, str::regex( "\\.0-rc", str::regex::match_extended ), ".rc", true );
+ version = str::regex_substitute( version, str::regex( "-rc\\d+", str::regex::match_extended ), "", true );
+ version = str::regex_substitute( version, str::regex( "-", str::regex::match_extended ), ".", true );
+
+ _runningKernelEdition = Edition( version, release );
+ _runningKernelFlavour = flavour;
+
+ MIL << "Parsed info from uname: " << std::endl;
+ MIL << "Kernel Flavour: " << _runningKernelFlavour << std::endl;
+ MIL << "Kernel Edition: " << _runningKernelEdition << std::endl;
}
+ bool removePackageAndCheck( const sat::Solvable::IdType id, const std::set<sat::Solvable::IdType> &keepList , const std::set<sat::Solvable::IdType> &removeList ) const;
+ static bool versionMatch ( const Edition &a, const Edition &b );
+ void parseKeepSpec();
+ void fillKeepList(const GroupMap &installedKernels, std::set<sat::Solvable::IdType> &keepList , std::set<sat::Solvable::IdType> &removeList ) const;
std::set<size_t> _keepLatestOffsets = { 0 };
std::set<size_t> _keepOldestOffsets;
std::set<Edition> _keepSpecificEditions;
std::string _uname_r;
+ Edition _runningKernelEdition;
+ Flavour _runningKernelFlavour;
Arch _kernelArch;
std::string _keepSpec = ZConfig::instance().multiversionKernels();
- bool _keepRunning = true;
+ bool _keepRunning = true;
+ bool _detectedRunning = false;
};
/*!
* tries to remove a the \ref PoolItem \a pi from the pool, solves and checks if no unexpected packages are removed due to the \a validRemovals regex.
* If the constraint fails the changes are reverted and \a false is returned.
*/
- bool PurgeKernels::Impl::removePackageAndCheck( PoolItem &pi, const str::regex &validRemovals ) const
+ bool PurgeKernels::Impl::removePackageAndCheck( const sat::Solvable::IdType id, const std::set<sat::Solvable::IdType> &keepList , const std::set<sat::Solvable::IdType> &removeList ) const
{
const filter::ByStatus toBeUninstalledFilter( &ResStatus::isToBeUninstalled );
+
+ PoolItem pi ( (sat::Solvable(id)) );
+
auto pool = ResPool::instance();
+ // make sure the pool is clean
+ if ( !pool.resolver().resolvePool() ) {
+ MIL << "Pool failed to resolve, not doing anything" << std::endl;
+ return false;
+ }
+
+ MIL << "Request to remove package: " << pi << std::endl;
+
+ //list of packages that are allowed to be removed automatically.
+ const str::regex validRemovals("(kernel-syms(-.*)?|kgraft-patch(-.*)?|kernel-livepatch(-.*)?|.*-kmp(-.*)?)");
+
+ if ( ui::asSelectable()( pi )->hasLocks() ) {
+ MIL << "Package " << pi << " is locked by the user, not removing." << std::endl;
+ return false;
+ }
+
//remember which packages are already marked for removal, we do not need to check them again
std::set< sat::Solvable::IdType> currentSetOfRemovals;
- for ( auto it = pool.byStatusBegin( toBeUninstalledFilter ); it != pool.byStatusEnd( toBeUninstalledFilter ); it++ )
+ for ( auto it = pool.byStatusBegin( toBeUninstalledFilter ); it != pool.byStatusEnd( toBeUninstalledFilter ); it++ ) {
currentSetOfRemovals.insert( it->id() );
+ }
pi.status().setToBeUninstalled( ResStatus::USER );
return false;
}
+ std::set<sat::Solvable::IdType> removedInThisRun;
+ removedInThisRun.insert( pi.id() );
+
for ( auto it = pool.byStatusBegin( toBeUninstalledFilter ); it != pool.byStatusEnd( toBeUninstalledFilter ); it++ ) {
- //this was set by us or marked by a previous removal, ignore them
- if ( it->status().isByUser() || (currentSetOfRemovals.find( it->id() ) != currentSetOfRemovals.end()) )
+ //check if that package is removeable
+ if ( it->status().isByUser() //this was set by us, ignore it
+ || (currentSetOfRemovals.find( it->id() ) != currentSetOfRemovals.end()) //this was marked by a previous removal, ignore them
+ )
+ continue;
+
+ // remember for later we need remove the debugsource and debuginfo packages as well
+ removedInThisRun.insert( it->id() );
+
+ MIL << "Package " << PoolItem(*it) << " was marked by the solver for removal." << std::endl;
+
+ // if we do not plan to remove that package anyway, we need to check if its allowed to be removed ( package in removelist can never be in keep list )
+ if ( removeList.find( it->id() ) != removeList.end() )
continue;
+ if ( keepList.find( it->id() ) != keepList.end() ) {
+ MIL << "Package " << PoolItem(*it) << " is in keep spec, skipping" << pi << std::endl;
+ pi.statusReset();
+ return false;
+ }
+
str::smatch what;
if ( !str::regex_match( it->name(), what, validRemovals) ) {
MIL << "Package " << PoolItem(*it) << " should not be removed, skipping " << pi << std::endl;
}
}
- MIL << "Removing package: " << pi << std::endl;
+ MIL << "Successfully marked package: " << pi << " for removal."<<std::endl;
+
+ //now check and mark the -debugsource and -debuginfo packages for this package and all the packages that were removed. Maybe collect it before and just remove here
+ MIL << "Trying to remove debuginfo for: " << pi <<"."<<std::endl;
+ for ( const auto id : removedInThisRun ) {
+
+ const auto solvable = sat::Solvable(id);
+ if ( solvable.arch() == Arch_noarch ||
+ solvable.arch() == Arch_empty )
+ continue;
+
+ for ( const auto suffix : { "-debugsource", "-debuginfo" } ) {
+ PoolQuery q;
+ q.addKind( zypp::ResKind::package );
+ q.addDependency( sat::SolvAttr::provides, Capability( solvable.name()+suffix, Rel::EQ, solvable.edition() ) );
+ q.setInstalledOnly();
+ q.setMatchExact();
+
+ for ( const auto debugPackage : q ) {
+
+ if ( debugPackage.arch() != solvable.arch() )
+ continue;
+
+ MIL << "Found debug package for " << solvable << " : " << debugPackage << std::endl;
+ //if removing the package fails it will not stop us from going on , so no need to check
+ removePackageAndCheck( debugPackage.id(), keepList, removeList );
+ }
+ }
+ }
+ MIL << "Finished removing debuginfo for: " << pi <<"."<<std::endl;
+
return true;
}
/*!
+ * Return true if \a a == \a b or \a a == (\a b minus rebuild counter)
+ */
+ bool PurgeKernels::Impl::versionMatch( const Edition &a, const Edition &b )
+ {
+ // the build counter should not be considered here, so if there is one we cut it off
+ const auto dotOffset = b.release().find_last_of(".");
+ if ( dotOffset != std::string::npos ) {
+ return a == zypp::Edition( b.version(), b.release().substr( 0, dotOffset ), b.epoch() );
+ }
+ return a == b;
+ }
+
+ /*!
* Parse the config line keep spec that tells us which kernels should be kept
*/
void PurgeKernels::Impl::parseKeepSpec( )
}
/*!
- * Go over the list of installed kernels and mark those as "do not remove" that match
- * a entry in the keep spec
+ * Go over the list of available Editions for each flavour/arch combinations, apply the keep spec and mark the
+ * packages that belong to a matching category as to keep
+ *
+ * All packages with Arch_noarch will only be matched against the version but NOT the flavour, reasoning for that is
+ * simply that source flavours not necessarily match the binary flavours. Without a translation table that would not be
+ * doable. This is also what the perl script did.
+ *
*/
- void PurgeKernels::Impl::fillKeepList( const std::unordered_map<std::string, std::map<Arch, std::map<Edition, sat::Solvable> > > &installedKernels, std::set<sat::Solvable::IdType> &list ) const
+ void PurgeKernels::Impl::fillKeepList( const GroupMap &installedKernels, std::set<sat::Solvable::IdType> &keepList, std::set<sat::Solvable::IdType> &removeList ) const
{
- for ( const auto &flavourMap : installedKernels ) {
- for ( const auto &archMap : flavourMap.second ) {
+
+ const auto markAsKeep = [ &keepList, &removeList ]( const auto &pck ) {
+ MIL << "Marking package " << sat::Solvable(pck) << " as to keep." << std::endl;
+ keepList.insert( pck ) ;
+ removeList.erase( pck );
+ };
+
+ const auto versionPredicate = []( const auto &edition ){
+ return [ &edition ]( const auto &elem ) {
+ return versionMatch( edition, elem.first );
+ };
+ };
+
+ for ( const auto &groupInfo : installedKernels ) {
+
+ MIL << "Starting with group " << groupInfo.first << std::endl;
+
+ for ( const auto &archMap : groupInfo.second.archToEdMap ) {
+
+ MIL << "Starting with arch " << archMap.first << std::endl;
+
size_t currOff = 0; //the current "oldest" offset ( runs from map start to end )
size_t currROff = archMap.second.size() - 1; // the current "latest" offset ( runs from map end to start )
- for ( const auto &kernelMap : archMap.second ) {
- //if we find one of the running offsets in the keepspec, we add the kernel id the the list of packages to keep
- if ( _keepOldestOffsets.find( currOff ) != _keepOldestOffsets.end()
- || _keepLatestOffsets.find( currROff ) != _keepLatestOffsets.end()
- // a kernel might be explicitely locked by version
- || _keepSpecificEditions.find( kernelMap.second.edition() ) != _keepSpecificEditions.end() ) {
- MIL << "Marking kernel " << kernelMap.second << " as to keep." << std::endl;
- list.insert( kernelMap.second.id() ) ;
- }
- currOff++;
- currROff--;
- }
- }
- }
- }
+ const EditionToSolvableMap &map = archMap.second;
- /*!
- * This cleans up the source and devel packages tree for a specific flavour.
- */
- void PurgeKernels::Impl::cleanDevelAndSrcPackages(const str::regex &validRemovals, std::set<Edition> &validEditions, const std::string &flavour )
- {
- bool isWithFlavour = flavour.size();
+ if ( _keepRunning
+ && ( ( archMap.first == _kernelArch && groupInfo.second.groupFlavour == _runningKernelFlavour )
+ || groupInfo.second.groupType == GroupInfo::Sources ) ) {
- if ( isWithFlavour )
- MIL << "Trying to remove source/devel packages for flavour " << flavour << std::endl;
- else
- MIL << "Trying to remove global/default source/devel packages "<< std::endl;
+ MIL << "Matching packages against running kernel "<< _runningKernelEdition << "-" << _runningKernelFlavour << "-" <<_kernelArch << std::endl;
- auto withFlavour = [&isWithFlavour, &flavour]( const std::string &name ) {
- return isWithFlavour ? name+"-"+flavour : name;
- };
+ auto it = std::find_if( map.begin(), map.end(), versionPredicate( _runningKernelEdition ) );
+ if ( it == map.end() ) {
- //try to remove the kernel-devel-flavour and kernel-source-flavour packages
- PoolQuery q;
- q.addKind( zypp::ResKind::package );
+ // If we look at Sources we cannot match the flavour but we still want to keep on checking the rest of the keep spec
+ if ( groupInfo.second.groupType != GroupInfo::Sources ) {
+ MIL << "Running kernel "<< _runningKernelEdition << "-" << _runningKernelFlavour << "-" <<_kernelArch << " not installed."<<std::endl;
+ MIL << "NOT removing any packages for flavor "<<_runningKernelFlavour<<"-"<<_kernelArch<<" ."<<std::endl;
- q.addAttribute( sat::SolvAttr::name, withFlavour("kernel-devel") );
- q.addAttribute( sat::SolvAttr::name, withFlavour("kernel-source") );
- q.setInstalledOnly();
- q.setMatchExact();
+ for ( const auto &kernelMap : map ) {
+ for( const auto &pck : kernelMap.second )
+ markAsKeep(pck);
+ }
+ continue;
+ }
- for ( auto installedSrcPck : q ) {
- // For now print a message that we are removing a source package that has no corresponding kernel installed.
- // This was changed due to bug #1171224 because orphaned kernel-source/devel packages were kept due to package
- // rebuilds that did not obsolete the previously installed release, e.g. kernel-source-1-1.1 vs kernel-source-1-1.2
- if ( validEditions.find( installedSrcPck.edition() ) == validEditions.end() ) {
- MIL << "Trying to remove source package " << installedSrcPck << " no corresponding kernel with the same version was installed." << std::endl;
- }
+ } else {
+ // there could be multiple matches here because of rebuild counter, lets try to find the last one
+ MIL << "Found possible running candidate edition: " << it->first << std::endl;
+ auto nit = it;
+ for ( nit++ ; nit != map.end() && versionMatch( _runningKernelEdition, nit->first ) ; nit++ ) {
+ MIL << "Found possible more recent running candidate edition: " << nit->first << std::endl;
+ it = nit;
+ }
+ }
- //if no package providing kernel-flavour = VERSION is installed , we are free to remove the package
- PoolQuery instKrnl;
- instKrnl.addKind( zypp::ResKind::package );
- instKrnl.setInstalledOnly();
- instKrnl.setMatchExact();
- instKrnl.addDependency( sat::SolvAttr::provides, withFlavour("kernel"), Rel::EQ, installedSrcPck.edition() );
+ // mark all packages of the running version as keep
+ if ( it != map.end() ) {
+ for( const auto &pck : it->second ) {
+ markAsKeep(pck);
+ }
+ }
+ }
- bool found = std::any_of ( instKrnl.begin(), instKrnl.end(), []( auto it ) { return !PoolItem(it).status().isToBeUninstalled(); } );
- if ( found ) {
- MIL << "Skipping source package " << installedSrcPck << " binary packages with the same edition are still installed" << std::endl;
- continue;
- }
+ for ( const auto &kernelMap : map ) {
+ //if we find one of the running offsets in the keepspec, we add the kernel id the the list of packages to keep
+ if ( _keepOldestOffsets.find( currOff ) != _keepOldestOffsets.end()
+ || _keepLatestOffsets.find( currROff ) != _keepLatestOffsets.end()
+ // a kernel might be explicitely locked by version
+ // this will currently keep all editions that match, so if keep spec has 1-1 , this will keep 1-1 but also all 1-1.n
+ || std::find_if( _keepSpecificEditions.begin(), _keepSpecificEditions.end(),
+ [ edition = &kernelMap.first ]( const auto &elem ) { return versionMatch( *edition, elem ); } ) != _keepSpecificEditions.end() ) {
- PoolItem pi( installedSrcPck );
- removePackageAndCheck( pi, validRemovals );
+ for( const auto &pck : kernelMap.second ) {
+ markAsKeep(pck);
+ }
+ }
+ currOff++;
+ currROff--;
+ }
+ }
}
}
void PurgeKernels::markObsoleteKernels()
{
- if ( _pimpl->_keepSpec.empty() )
+ MIL << std::endl << "--------------------- Starting to mark obsolete kernels ---------------------"<<std::endl;
+
+ if ( _pimpl->_keepSpec.empty() ) {
+ WAR << "Keep spec is empty, removing nothing." << std::endl;
return;
+ }
_pimpl->parseKeepSpec();
+ if ( _pimpl->_keepRunning && !_pimpl->_detectedRunning ) {
+ WAR << "Unable to detect running kernel, but keeping the running kernel was requested. Not removing any packages." << std::endl;
+ return;
+ }
+
auto pool = ResPool::instance();
pool.resolver().setForceResolve( true ); // set allow uninstall flag
const filter::ByStatus toBeUninstalledFilter( &ResStatus::isToBeUninstalled );
- //list of packages that are allowed to be removed automatically.
- const str::regex validRemovals("(kernel-syms(-.*)?|kgraft-patch(-.*)?|kernel-livepatch(-.*)?|.*-kmp(-.*)?)");
-
- //list of packages that are allowed to be removed automatically when uninstalling kernel-devel packages
- const str::regex validDevelRemovals("(kernel-source(-.*)?|(kernel-syms(-.*)?)|(kernel-devel(-.*)?)|(kernel(-.*)?-devel))");
-
// kernel flavour regex
const str::regex kernelFlavourRegex("^kernel-(.*)$");
- // the map of all installed kernels, grouped by Flavour -> Arch -> Version
- std::unordered_map< std::string, std::map< Arch, std::map<Edition, sat::Solvable> > > installedKernels;
+ // the map of all installed kernel packages, grouped by Flavour -> Arch -> Version -> (List of all packages in that category)
+ // devel and source packages are grouped together
+ GroupMap installedKrnlPackages;
- // the set of kernel package IDs that have to be kept always
- std::set<sat::Solvable::IdType> packagesToKeep;
-
- //collect the list of installed kernel packages
- PoolQuery q;
- q.addKind( zypp::ResKind::package );
- q.addAttribute( sat::SolvAttr::provides, "kernel" );
- q.setInstalledOnly();
- q.setMatchExact();
- MIL << "Searching for obsolete kernels." << std::endl;
+ // packages that we plan to remove
+ std::set<sat::Solvable::IdType> packagesToRemove;
- for ( auto installedKernel : q ) {
+ const auto addPackageToMap = [&installedKrnlPackages, &packagesToRemove] ( const GroupInfo::GroupType type, const std::string &ident, const std::string &flavour, const auto &installedKrnlPck ) {
- MIL << "Found installed kernel " << installedKernel << std::endl;
+ if ( !installedKrnlPackages.count( ident ) )
+ installedKrnlPackages.insert( std::make_pair( ident, GroupInfo(type, flavour) ) );
- //we can not simply skip the running kernel to make sure the keep-spec works correctly
- if ( _pimpl->_keepRunning
- && installedKernel.provides().matches( Capability( "kernel-uname-r", Rel::EQ, Edition( _pimpl->_uname_r ) ) )
- && installedKernel.arch() == _pimpl->_kernelArch ) {
- MIL << "Marking kernel " << installedKernel << " as to keep." << std::endl;
- packagesToKeep.insert( installedKernel.id() );
+ auto &groupInfo = installedKrnlPackages[ ident ];
+ if ( groupInfo.groupType != type || groupInfo.groupFlavour != flavour ) {
+ ERR << "Got inconsistent type and flavour for ident this is a BUG: " << ident << std::endl
+ << "Original Flavour-Type: "<<groupInfo.groupFlavour<<"-"<<groupInfo.groupType << std::endl
+ << "Competing Flavour-Type: "<< flavour << "-" << type << std::endl;
}
- str::smatch what;
- str::regex_match( installedKernel.name(), what, kernelFlavourRegex );
- if ( what[1].empty() ) {
- WAR << "Could not detect kernel flavour for: " << installedKernel << " ...skipping" << std::endl;
- continue;
- }
+ const auto currArch = installedKrnlPck.arch();
+ if ( !groupInfo.archToEdMap.count( currArch ) )
+ groupInfo.archToEdMap.insert( std::make_pair( currArch , EditionToSolvableMap {} ) );
- const std::string flavour = what[1];
- if ( !installedKernels.count( flavour ) )
- installedKernels.insert( std::make_pair( flavour, std::map< Arch, std::map<Edition, sat::Solvable> > {} ) );
+ auto &editionToSolvableMap = groupInfo.archToEdMap[ currArch ];
- auto &flavourMap = installedKernels[ flavour ];
- if ( !flavourMap.count( installedKernel.arch() ) )
- flavourMap.insert( std::make_pair( installedKernel.arch(), std::map<Edition, sat::Solvable>{} ) );
+ const auto currEd = installedKrnlPck.edition();
+ if ( !editionToSolvableMap.count( currEd ) )
+ editionToSolvableMap.insert( std::make_pair( currEd, SolvableList{} ) );
- flavourMap[ installedKernel.arch() ].insert( std::make_pair( installedKernel.edition(), installedKernel ) );
- }
+ editionToSolvableMap[currEd].push_back( installedKrnlPck.id() );
- _pimpl->fillKeepList( installedKernels, packagesToKeep );
+ //in the first step we collect all packages in this list, then later we will remove the packages we want to explicitely keep
+ packagesToRemove.insert( installedKrnlPck.id() );
+ };
+ // the set of package IDs that have to be kept always
+ std::set<sat::Solvable::IdType> packagesToKeep;
- MIL << "Starting to remove obsolete kernels." << std::endl;
+ //collect the list of installed kernel packages
+ PoolQuery q;
+ q.addKind( zypp::ResKind::package );
+ q.addAttribute( sat::SolvAttr::provides, "multiversion(kernel)" );
+ q.setInstalledOnly();
+ q.setMatchExact();
+ MIL << "Searching for obsolete multiversion kernel packages." << std::endl;
- std::set<Edition> removedVersions;
+ for ( auto installedKrnlPck : q ) {
- /*
- * If there is a KMP or livepatch depending on the package remove it as well. If
- * there is another package depending on the kernel keep the kernel. If there is
- * a package that depends on a KMP keep the KMP and a kernel required to use the
- * KMP.
- */
- for ( const auto &flavourMap : installedKernels ) {
+ MIL << "Found installed multiversion kernel package " << installedKrnlPck << std::endl;
- // collect all removed versions of this edition
- std::set<Edition> removedFlavourVersions;
+ if ( installedKrnlPck.provides().matches(Capability("kernel-uname-r")) ) {
+ MIL << "Identified as a kernel package " << std::endl;
- for ( const auto &archMap : flavourMap.second ) {
- for ( const auto &kernelMap : archMap.second ) {
- auto &installedKernel = kernelMap.second;
+ // we group kernel packages by flavour
+ str::smatch what;
+ str::regex_match( installedKrnlPck.name(), what, kernelFlavourRegex );
+ if ( what[1].empty() ) {
+ WAR << "Could not detect flavour for: " << installedKrnlPck << " ...skipping" << std::endl;
+ continue;
+ }
- // if the kernel is locked by the user, its not removed automatically
- if ( ui::asSelectable()( installedKernel )->hasLocks() )
- continue;
+ std::string flavour = what[1];
- // this package is in the keep spec, do not touch
- if ( packagesToKeep.count( installedKernel.id() ) )
- continue;
+ // XXX: No dashes in flavor names
+ const auto dash = flavour.find_first_of('-');
+ if ( dash != std::string::npos ) {
+ flavour = flavour.substr( 0, dash );
+ }
- // try to remove the kernel package, check afterwards if only expected packages have been removed
- PoolItem pi( installedKernel );
- if ( !_pimpl->removePackageAndCheck( pi, validRemovals ) ) {
- continue;
- }
+ // the ident for kernels is the flavour, to also handle cases like kernel-base and kernel which should be in the same group handled together
+ addPackageToMap( GroupInfo::Kernels, flavour, flavour, installedKrnlPck );
- removedFlavourVersions.insert( installedKernel.edition() );
+ } else {
- //lets remove the kernel-flavour-devel package too
- PoolQuery develPckQ;
- develPckQ.addKind( zypp::ResKind::package );
- develPckQ.addDependency( sat::SolvAttr::name, installedKernel.name()+"-devel", Rel::EQ, installedKernel.edition() );
- develPckQ.addDependency( sat::SolvAttr::name, installedKernel.name()+"-devel-debuginfo", Rel::EQ, installedKernel.edition() );
- develPckQ.setInstalledOnly();
- develPckQ.setMatchExact();
+ const str::regex explicitelyHandled("kernel-syms(-.*)?|kernel(-.*)?-devel");
- for ( auto krnlDevPck : develPckQ ) {
+ MIL << "Not a kernel package, inspecting more closely " << std::endl;
- if ( krnlDevPck.arch() != installedKernel.arch() )
- continue;
+ // we directly handle all noarch packages that export multiversion(kernel)
+ if ( installedKrnlPck.arch() == Arch_noarch ) {
- PoolItem devPi(krnlDevPck);
- _pimpl->removePackageAndCheck( devPi, validDevelRemovals );
+ MIL << "Handling package explicitely due to architecture (noarch)."<< std::endl;
+ addPackageToMap( GroupInfo::Sources, installedKrnlPck.name(), "", installedKrnlPck );
+
+ } else if ( str::smatch match; str::regex_match( installedKrnlPck.name(), match, explicitelyHandled ) ) {
+
+ // try to get the flavour from the name
+ // if we have a kernel-syms getting no flavour means we have the "default" one, otherwise we use the flavour
+ // getting no flavour for a kernel(-*)?-devel means we have the kernel-devel package otherwise the flavour specific one
+ // ...yes this is horrible
+ std::string flav;
+ if ( match.size() > 1 ) {
+ flav = match[2].substr(1);
+ } else if ( installedKrnlPck.name() == "kernel-syms" ) {
+ flav = "default";
}
+
+ MIL << "Handling package explicitely due to name match."<< std::endl;
+ addPackageToMap ( GroupInfo::RelatedBinaries, installedKrnlPck.name(), flav, installedKrnlPck );
+
+ } else {
+ MIL << "Package not explicitely handled" << std::endl;
}
}
- //try to remove the kernel-devel-flavour and kernel-source-flavour packages
- _pimpl->cleanDevelAndSrcPackages( validDevelRemovals, removedFlavourVersions, flavourMap.first );
- removedVersions.insert( removedFlavourVersions.begin(), removedFlavourVersions.end() );
+
}
- // clean the global -devel and -source packages
- _pimpl->cleanDevelAndSrcPackages( validDevelRemovals, removedVersions );
+ MIL << "Grouped packages: " << std::endl;
+ std::for_each( installedKrnlPackages.begin(), installedKrnlPackages.end(),[]( const auto &ident ){
+ MIL << "\tGroup ident: "<<ident.first<<std::endl;
+ MIL << "\t Group type: "<<ident.second.groupType<<std::endl;
+ MIL << "\t Group flav: "<<ident.second.groupFlavour<<std::endl;
+ std::for_each( ident.second.archToEdMap.begin(), ident.second.archToEdMap.end(), []( const auto &arch) {
+ MIL << "\t\tArch: "<<arch.first<<std::endl;
+ std::for_each( arch.second.begin(), arch.second.end(), []( const auto &edition) {
+ MIL << "\t\t\tEdition: "<<edition.first<<std::endl;
+ std::for_each( edition.second.begin(), edition.second.end(), []( const auto &packageId) {
+ MIL << "\t\t\t\t "<<sat::Solvable(packageId)<<std::endl;
+ });
+ });
+ });
+ });
+
+ _pimpl->fillKeepList( installedKrnlPackages, packagesToKeep, packagesToRemove );
+
+ for ( const auto id : packagesToRemove )
+ _pimpl->removePackageAndCheck( id, packagesToKeep, packagesToRemove );
}
void PurgeKernels::setUnameR( const std::string &val )
{
- _pimpl->_uname_r = val;
+ _pimpl->setUnameR( val );
}
std::string PurgeKernels::unameR() const
if ( ! (rawMirrorListUrl().asString().empty()) )
str << (_pimpl->_mirrorListForceMetalink ? "metalink=" : "mirrorlist=") << rawMirrorListUrl() << endl;
- str << "type=" << type().asString() << endl;
+ if ( type() != repo::RepoType::NONE )
+ str << "type=" << type().asString() << endl;
if ( priority() != defaultPriority() )
str << "priority=" << priority() << endl;
if ( repokind != probed )
{
repokind = probed;
- // Adjust the probed type in RepoInfo
- info.setProbedType( repokind ); // lazy init!
- //save probed type only for repos in system
+ // update probed type only for repos in system
for_( it, repoBegin(), repoEnd() )
{
if ( info.alias() == (*it).alias() )
{
RepoInfo modifiedrepo = *it;
modifiedrepo.setType( repokind );
- modifyRepository( info.alias(), modifiedrepo );
+ // don't modify .repo in refresh.
+ // modifyRepository( info.alias(), modifiedrepo );
break;
}
}
+ // Adjust the probed type in RepoInfo
+ info.setProbedType( repokind ); // lazy init!
}
+ // no need to continue with an unknown type
+ if ( repokind.toEnum() == RepoType::NONE_e )
+ ZYPP_THROW(RepoUnknownTypeException( info ));
}
Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
// Resolver interface forwarded to implementation
//
///////////////////////////////////////////////////////////////////
+ sat::detail::CSolver * Resolver::get() const
+ { return _pimpl->get(); }
+
bool Resolver::verifySystem ()
{ return _pimpl->verifySystem(); }
*/
solver::detail::ItemCapKindList installedSatisfied( const PoolItem & item );
+ public:
+ /** Expert backdoor. */
+ sat::detail::CSolver * get() const;
private:
friend std::ostream & operator<<( std::ostream & str, const Resolver & obj );
, const std::string &/*reason*/
, RpmLevel /*level*/
) {}
+
+ /** "rpmout/installpkg": Additional rpm output (sent immediately).
+ * Data:
+ * solvable : satSolvable processed
+ * line : std::reference_wrapper<const std::string>
+ * lineno : unsigned
+ */
+ static const UserData::ContentType contentRpmout;
};
// progress for removing a resolvable
, Error /*error*/
, const std::string &/*reason*/
) {}
+
+ /** "rpmout/removepkg": Additional rpm output (sent immediately).
+ * For data \see \ref InstallResolvableReport::contentRpmout
+ */
+ static const UserData::ContentType contentRpmout;
};
// progress for rebuilding the database
regfree(&m_preg);
}
-bool zypp::str::regex_match(const char * s, smatch& matches, const regex& regex)
+bool regex::matches( const char *s, smatch &matches, int flags ) const
{
- bool r = s && regex.m_valid && !regexec(®ex.m_preg, s, 12, &matches.pmatch[0], 0);
+ const auto possibleMatchCount = m_preg.re_nsub + 1;
+ matches.pmatch.resize( possibleMatchCount );
+ memset( matches.pmatch.data(), -1, sizeof( regmatch_t ) * ( possibleMatchCount ) );
+
+ bool r = s && m_valid && !regexec( &m_preg, s, matches.pmatch.size(), matches.pmatch.data(), flags );
if (r)
matches.match_str = s;
return r;
}
-bool zypp::str::regex_match(const char * s, const regex& regex)
+bool regex::matches( const char *s ) const
{
- return s && !regexec(®ex.m_preg, s, 0, NULL, 0);
+ return s && !regexec(&m_preg, s, 0, NULL, 0);
}
-smatch::smatch()
+bool zypp::str::regex_match(const char * s, smatch& matches, const regex& regex)
+{
+ return regex.matches( s, matches );
+}
+
+bool zypp::str::regex_match(const char * s, const regex& regex)
{
- memset(&pmatch, -1, sizeof(pmatch));
+ return regex.matches( s );
}
+smatch::smatch()
+{ }
+
std::string smatch::operator[](unsigned i) const
{
- if ( i < sizeof(pmatch)/sizeof(*pmatch) && pmatch[i].rm_so != -1 )
+ if ( i < pmatch.size() && pmatch[i].rm_so != -1 )
return match_str.substr( pmatch[i].rm_so, pmatch[i].rm_eo-pmatch[i].rm_so );
return std::string();
}
std::string::size_type smatch::begin( unsigned i ) const
-{ return( i < sizeof(pmatch)/sizeof(*pmatch) && pmatch[i].rm_so != -1 ? pmatch[i].rm_so : std::string::npos ); }
+{ return( i < pmatch.size() && pmatch[i].rm_so != -1 ? pmatch[i].rm_so : std::string::npos ); }
std::string::size_type smatch::end( unsigned i ) const
-{ return( i < sizeof(pmatch)/sizeof(*pmatch) && pmatch[i].rm_so != -1 ? pmatch[i].rm_eo : std::string::npos ); }
+{ return( i < pmatch.size() && pmatch[i].rm_so != -1 ? pmatch[i].rm_eo : std::string::npos ); }
std::string::size_type smatch::size( unsigned i ) const
-{ return( i < sizeof(pmatch)/sizeof(*pmatch) && pmatch[i].rm_so != -1 ? pmatch[i].rm_eo-pmatch[i].rm_so : std::string::npos ); }
+{ return( i < pmatch.size() && pmatch[i].rm_so != -1 ? pmatch[i].rm_eo-pmatch[i].rm_so : std::string::npos ); }
unsigned smatch::size() const
{
// Get highest (pmatch[i].rm_so != -1). Just looking for the 1st
// (pmatch[i].rm_so == -1) is wrong as optional mayches "()?"
// may be embeded.
- for ( unsigned i = 0; i < sizeof(pmatch)/sizeof(*pmatch); ++i )
+ for ( unsigned i = 0; i < pmatch.size(); ++i )
{
if ( pmatch[i].rm_so != -1 )
matches = i;
}
return ++matches;
}
+
+std::string zypp::str::regex_substitute( const std::string &s, const regex ®ex, const std::string &replacement, bool global )
+{
+ std::string result;
+ std::string::size_type off = 0;
+ int flags = regex::none;
+
+ while ( true ) {
+
+ smatch match;
+ if ( !regex.matches( s.data()+off, match, flags ) ) {
+ break;
+ }
+
+ if ( match.size() ) {
+ result += s.substr( off, match.begin(0) );
+ result += replacement;
+ off = match.end(0) + off;
+ }
+
+ if ( !global )
+ break;
+
+ // once we passed the beginning of the string we should not match ^ anymore, except the last character was
+ // actually a newline
+ if ( off > 0 && off < s.size() && s[ off - 1 ] == '\n' )
+ flags = regex::none;
+ else
+ flags = regex::not_bol;
+ }
+
+ result += s.substr( off );
+ return result;
+}
inline bool regex_match( const std::string & s, const regex & regex )
{ return regex_match( s.c_str(), regex ); }
+ /**
+ * Replaces the matched regex with the string passed in \a replacement.
+ * If \a global is set the search continues after the first match
+ *
+ * \note Using backreferences in the replacement string is NOT supported.
+ */
+ std::string regex_substitute ( const std::string & s, const regex & regex, const std::string &replacement, bool global = true );
+
//////////////////////////////////////////////////////////////////
/// \class regex
/// \brief Regular expression
icase = REG_ICASE, ///< Do not differentiate case
nosubs = REG_NOSUB, ///< Support for substring addressing of matches is not required
match_extended = REG_EXTENDED, ///< Use POSIX Extended Regular Expression syntax when interpreting regex.
+ newline = REG_NEWLINE ///< Match newline
+ };
+
+ enum MatchFlags {
+ none = 0,
+ not_bol = REG_NOTBOL ///< Do not match begin of line
};
regex();
std::string asString() const
{ return m_str; }
+ bool matches (const char * s, str::smatch& matches, int flags = none ) const;
+ bool matches ( const char * s ) const;
+
public:
/** Expert backdoor. Returns pointer to the compiled regex for direct use in regexec() */
regex_t * get()
private:
friend class smatch;
- friend bool regex_match(const char * s, str::smatch& matches, const regex& regex);
- friend bool regex_match(const char * s, const regex& regex);
std::string m_str;
int m_flags;
regex_t m_preg;
std::string::size_type size( unsigned i ) const;
std::string match_str;
- regmatch_t pmatch[12];
+ std::vector<regmatch_t> pmatch;
};
} // namespace str
int log_curl(CURL *curl, curl_infotype info,
char *ptr, size_t len, void *max_lvl)
{
- std::string pfx(" ");
- long lvl = 0;
- switch( info)
+ if ( max_lvl == nullptr )
+ return 0;
+
+ long maxlvl = *((long *)max_lvl);
+
+ char pfx = ' ';
+ switch( info )
{
- case CURLINFO_TEXT: lvl = 1; pfx = "*"; break;
- case CURLINFO_HEADER_IN: lvl = 2; pfx = "<"; break;
- case CURLINFO_HEADER_OUT: lvl = 2; pfx = ">"; break;
- default: break;
+ case CURLINFO_TEXT: if ( maxlvl < 1 ) return 0; pfx = '*'; break;
+ case CURLINFO_HEADER_IN: if ( maxlvl < 2 ) return 0; pfx = '<'; break;
+ case CURLINFO_HEADER_OUT: if ( maxlvl < 2 ) return 0; pfx = '>'; break;
+ default:
+ return 0;
}
- if( lvl > 0 && max_lvl != NULL && lvl <= *((long *)max_lvl))
+
+ std::vector<std::string> lines;
+ str::split( std::string(ptr,len), std::back_inserter(lines), "\r\n" );
+ for( const auto & line : lines )
{
- std::string msg(ptr, len);
- std::list<std::string> lines;
- std::list<std::string>::const_iterator line;
- zypp::str::split(msg, std::back_inserter(lines), "\r\n");
- for(line = lines.begin(); line != lines.end(); ++line)
- {
- DBG << pfx << " " << *line << std::endl;
+ if ( str::startsWith( line, "Authorization:" ) ) {
+ std::string::size_type pos { line.find( " ", 15 ) }; // Authorization: <type> <credentials>
+ if ( pos == std::string::npos )
+ pos = 15;
+ DBG << pfx << " " << line.substr( 0, pos ) << " <credentials removed>" << std::endl;
}
+ else
+ DBG << pfx << " " << line << std::endl;
}
return 0;
}
SET_OPTION(CURLOPT_USERAGENT, _settings.userAgentString().c_str() );
+ /* Fixes bsc#1174011 "auth=basic ignored in some cases"
+ * We should proactively add the password to the request if basic auth is configured
+ * and a password is available in the credentials but not in the URL.
+ *
+ * We will be a bit paranoid here and require that the URL has a user embedded, otherwise we go the default route
+ * and ask the server first about the auth method
+ */
+ if ( _settings.authType() == "basic"
+ && _settings.username().size()
+ && !_settings.password().size() ) {
+
+ CredentialManager cm(CredManagerOptions(ZConfig::instance().repoManagerRoot()));
+ const auto cred = cm.getCred( _url );
+ if ( cred && cred->valid() ) {
+ if ( !_settings.username().size() )
+ _settings.setUsername(cred->username());
+ _settings.setPassword(cred->password());
+ }
+ }
+
/*---------------------------------------------------------------*
CURLOPT_USERPWD: [user name]:[password]
return str;
}
-long CurlAuthData::auth_type_str2long(std::string & auth_type_str)
+long CurlAuthData::auth_type_str2long( std::string & auth_type_str )
+{
+ return auth_type_str2long( const_cast< const std::string &>(auth_type_str) );
+}
+
+long CurlAuthData::auth_type_str2long( const std::string & auth_type_str )
{
curl_version_info_data *curl_info = curl_version_info(CURLVERSION_NOW);
* \throws MediaException if an invalid authentication type name is
* encountered.
*/
- static long auth_type_str2long(std::string & auth_type_str);
+ static long auth_type_str2long( std::string & auth_type_str );
+ static long auth_type_str2long( const std::string &auth_type_str );
/**
* Converts a long of ORed CURLAUTH_* identifiers into a string of comma
delete _satResolver;
}
+sat::detail::CSolver * Resolver::get() const
+{ return _satResolver->get(); }
+
//---------------------------------------------------------------------------
// forward flags too SATResolver
ItemCapKindList satifiedByInstalled (const PoolItem & item );
ItemCapKindList installedSatisfied( const PoolItem & item );
+public:
+ /** Expert backdoor. */
+ sat::detail::CSolver * get() const;
};
///////////////////////////////////////////////////////////////////
sat::StringQueue autoInstalled() const;
sat::StringQueue userInstalled() const;
+
+public:
+ /** Expert backdoor. */
+ sat::detail::CSolver * get() const { return _satSolver; }
};
///////////////////////////////////////////////////////////////////
{
}
+ void RpmInstallPackageReceiver::report( const UserData & userData_r )
+ {
+ if ( ! userData_r.haskey( "solvable" ) )
+ userData_r.set( "solvable", _resolvable->satSolvable() );
+ _report->report( userData_r );
+ }
+
/** Start the operation */
void RpmInstallPackageReceiver::start( const Pathname & name )
{
}
/** Start the operation */
+ void RpmRemovePackageReceiver::report( const UserData & userData_r )
+ {
+ if ( ! userData_r.haskey( "solvable" ) )
+ userData_r.set( "solvable", _resolvable->satSolvable() );
+ _report->report( userData_r );
+ }
+
void RpmRemovePackageReceiver::start( const std::string & name )
{
_report->start( _resolvable );
virtual void reportend();
+ /** Forwards generic reports. */
+ void report( const UserData & userData_r ) override;
+
/** Start the operation */
virtual void start( const Pathname & name );
virtual void reportend();
/** Start the operation */
+ /** Forwards generic reports. */
+ void report( const UserData & userData_r ) override;
+
virtual void start( const std::string & name );
/**
{
bool IGotIt(); // in readonly-mode
}
+ namespace env
+ {
+ inline bool ZYPP_RPM_DEBUG()
+ {
+ static bool val = [](){
+ const char * env = getenv("ZYPP_RPM_DEBUG");
+ return( env && str::strToBool( env, true ) );
+ }();
+ return val;
+ }
+ } // namespace env
namespace target
{
namespace rpm
{
+ const callback::UserData::ContentType InstallResolvableReport::contentRpmout( "rpmout","installpkg" );
+ const callback::UserData::ContentType RemoveResolvableReport::contentRpmout( "rpmout","removepkg" );
+
namespace
{
#if 1 // No more need to escape whitespace since rpm-4.4.2.3
args.push_back(_root.asString().c_str());
args.push_back("--dbpath");
args.push_back(_dbPath.asString().c_str());
-
+ if ( env::ZYPP_RPM_DEBUG() )
+ args.push_back("-vv");
const char* argv[args.size() + opts.size() + 1];
const char** p = argv;
}
if ( ! ::ferror( inputfile ) || ::feof( inputfile ) )
+ {
+ if ( env::ZYPP_RPM_DEBUG() )
+ L_DBG("RPM_DEBUG") << line << endl;
return true; // complete line
+ }
}
clearerr( inputfile );
}
opts.push_back ( quotedFilename.c_str() );
run_rpm( opts, ExternalProgram::Stderr_To_Stdout );
+ // forward additional rpm output via report;
std::string line;
+ unsigned lineno = 0;
+ callback::UserData cmdout( InstallResolvableReport::contentRpmout );
+ // Key "solvable" injected by RpmInstallPackageReceiver
+ cmdout.set( "line", std::cref(line) );
+ cmdout.set( "lineno", lineno );
+
+ // LEGACY: collect and forward additional rpm output in finish
std::string rpmmsg; // TODO: immediately forward lines via Callback::report rather than collecting
std::vector<std::string> configwarnings; // TODO: immediately process lines rather than collecting
- unsigned linecnt = 0;
while ( systemReadLine( line ) )
{
if ( str::startsWith( line, "%%" ) )
report->progress( percent );
continue;
}
+ ++lineno;
+ cmdout.set( "lineno", lineno );
+ report->report( cmdout );
- if ( linecnt < MAXRPMMESSAGELINES )
- ++linecnt;
- else if ( line.find( " scriptlet failed, " ) == std::string::npos ) // always log %script errors
- continue;
+ if ( lineno >= MAXRPMMESSAGELINES ) {
+ if ( line.find( " scriptlet failed, " ) == std::string::npos ) // always log %script errors
+ continue;
+ }
rpmmsg += line+'\n';
if ( str::startsWith( line, "warning:" ) )
configwarnings.push_back(line);
}
- if ( linecnt >= MAXRPMMESSAGELINES )
+ if ( lineno >= MAXRPMMESSAGELINES )
rpmmsg += "[truncated]\n";
int rpm_status = systemStatus();
opts.push_back(name_r.c_str());
run_rpm (opts, ExternalProgram::Stderr_To_Stdout);
+ // forward additional rpm output via report;
std::string line;
+ unsigned lineno = 0;
+ callback::UserData cmdout( RemoveResolvableReport::contentRpmout );
+ // Key "solvable" injected by RpmInstallPackageReceiver
+ cmdout.set( "line", std::cref(line) );
+ cmdout.set( "lineno", lineno );
+
+
+ // LEGACY: collect and forward additional rpm output in finish
std::string rpmmsg; // TODO: immediately forward lines via Callback::report rather than collecting
// got no progress from command, so we fake it:
// 50 - command completed
// 100 if no error
report->progress( 5 );
- unsigned linecnt = 0;
while (systemReadLine(line))
{
- if ( linecnt < MAXRPMMESSAGELINES )
- ++linecnt;
- else if ( line.find( " scriptlet failed, " ) == std::string::npos ) // always log %script errors
- continue;
+ ++lineno;
+ cmdout.set( "lineno", lineno );
+ report->report( cmdout );
+
+ if ( lineno >= MAXRPMMESSAGELINES ) {
+ if ( line.find( " scriptlet failed, " ) == std::string::npos ) // always log %script errors
+ continue;
+ }
rpmmsg += line+'\n';
}
- if ( linecnt >= MAXRPMMESSAGELINES )
+ if ( lineno >= MAXRPMMESSAGELINES )
rpmmsg += "[truncated]\n";
report->progress( 50 );
int rpm_status = systemStatus();
internal::fillSettingsFromUrl( url, set );
if ( _transferSettings.proxy().empty() )
internal::fillSettingsSystemProxy( url, set );
+
+ /* Fixes bsc#1174011 "auth=basic ignored in some cases"
+ * We should proactively add the password to the request if basic auth is configured
+ * and a password is available in the credentials but not in the URL.
+ *
+ * We will be a bit paranoid here and require that the URL has a user embedded, otherwise we go the default route
+ * and ask the server first about the auth method
+ */
+ if ( set.authType() == "basic"
+ && set.username().size()
+ && !set.password().size() ) {
+ zypp::media::CredentialManager cm( zypp::media::CredManagerOptions( zypp::ZConfig::instance().repoManagerRoot()) );
+ const auto cred = cm.getCred( url );
+ if ( cred && cred->valid() ) {
+ if ( !set.username().size() )
+ set.setUsername(cred->username());
+ set.setPassword(cred->password());
+ }
+ }
+
} catch ( const zypp::media::MediaBadUrlException & e ) {
res = NetworkRequestErrorPrivate::customError( NetworkRequestError::MalformedURL, e.asString(), buildExtraInfo() );
} catch ( const zypp::media::MediaUnauthorizedException & e ) {