From 54cf728a19e2a118a45f16c4fb5852d3d9cf4e27 Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Tue, 22 Jan 2019 14:07:02 +0900 Subject: [PATCH] Imported Upstream version 1.14.14 --- VERSION.cmake | 4 +- package/zypper.changes | 10 + po/de.po | 9 +- po/pt_BR.po | 72 +- src/CMakeLists.txt | 40 +- src/Command.cc | 96 +- src/PackageArgs.cc | 1 + src/Zypper.cc | 1615 +++------------------------ src/Zypper.h | 12 + src/commands/basecommand.cc | 230 +++- src/commands/basecommand.h | 83 +- src/commands/conditions.cc | 58 + src/commands/conditions.h | 26 + src/commands/locks.h | 1 + src/commands/locks/add.cc | 120 +++ src/commands/locks/add.h | 35 + src/commands/locks/clean.cc | 74 ++ src/commands/locks/clean.h | 36 + src/commands/locks/list.cc | 44 +- src/commands/locks/list.h | 17 +- src/commands/locks/remove.cc | 139 +++ src/commands/locks/remove.h | 35 + src/commands/ps.cc | 204 ++++ src/commands/ps.h | 39 + src/commands/repos.h | 12 + src/commands/repos/add.cc | 138 +++ src/commands/repos/add.h | 37 + src/commands/repos/clean.cc | 74 ++ src/commands/repos/clean.h | 33 + src/commands/repos/list.cc | 348 ++++++ src/commands/repos/list.h | 34 + src/commands/repos/modify.cc | 112 ++ src/commands/repos/modify.h | 33 + src/commands/repos/refresh.cc | 307 ++++++ src/commands/repos/refresh.h | 50 + src/commands/repos/remove.cc | 106 ++ src/commands/repos/remove.h | 35 + src/commands/repos/rename.cc | 125 +++ src/commands/repos/rename.h | 30 + src/commands/reposerviceoptionsets.cc | 278 +++++ src/commands/reposerviceoptionsets.h | 128 +++ src/commands/services.h | 10 + src/commands/services/add.cc | 166 +++ src/commands/services/add.h | 34 + src/commands/services/common.cc | 165 +++ src/commands/services/common.h | 37 + src/commands/services/list.cc | 247 +++++ src/commands/services/list.h | 36 + src/commands/services/modify.cc | 373 +++++++ src/commands/services/modify.h | 45 + src/commands/services/refresh.cc | 289 +++++ src/commands/services/refresh.h | 41 + src/commands/services/remove.cc | 89 ++ src/commands/services/remove.h | 31 + src/locks.cc | 163 --- src/locks.h | 9 - src/ps.cc | 188 ---- src/ps.h | 38 - src/repos.cc | 1920 ++++----------------------------- src/repos.h | 127 ++- src/source-download.cc | 2 +- src/utils/flags/exceptions.cc | 8 +- src/utils/flags/exceptions.h | 6 + src/utils/flags/flagtypes.cc | 105 ++ src/utils/flags/flagtypes.h | 70 +- src/utils/flags/zyppflags.cc | 84 +- src/utils/flags/zyppflags.h | 45 +- src/utils/messages.cc | 40 + src/utils/messages.h | 13 + src/utils/misc.h | 2 + zypper.spec.cmake | 2 +- 71 files changed, 5491 insertions(+), 3774 deletions(-) create mode 100644 src/commands/conditions.cc create mode 100644 src/commands/conditions.h create mode 100644 src/commands/locks/clean.cc create mode 100644 src/commands/locks/clean.h create mode 100644 src/commands/ps.cc create mode 100644 src/commands/ps.h create mode 100644 src/commands/repos.h create mode 100644 src/commands/repos/add.cc create mode 100644 src/commands/repos/add.h create mode 100644 src/commands/repos/clean.cc create mode 100644 src/commands/repos/clean.h create mode 100644 src/commands/repos/list.cc create mode 100644 src/commands/repos/list.h create mode 100644 src/commands/repos/modify.cc create mode 100644 src/commands/repos/modify.h create mode 100644 src/commands/repos/refresh.cc create mode 100644 src/commands/repos/refresh.h create mode 100644 src/commands/repos/remove.cc create mode 100644 src/commands/repos/remove.h create mode 100644 src/commands/repos/rename.cc create mode 100644 src/commands/repos/rename.h create mode 100644 src/commands/reposerviceoptionsets.cc create mode 100644 src/commands/reposerviceoptionsets.h create mode 100644 src/commands/services.h create mode 100644 src/commands/services/add.cc create mode 100644 src/commands/services/add.h create mode 100644 src/commands/services/common.cc create mode 100644 src/commands/services/common.h create mode 100644 src/commands/services/list.cc create mode 100644 src/commands/services/list.h create mode 100644 src/commands/services/modify.cc create mode 100644 src/commands/services/modify.h create mode 100644 src/commands/services/refresh.cc create mode 100644 src/commands/services/refresh.h create mode 100644 src/commands/services/remove.cc create mode 100644 src/commands/services/remove.h delete mode 100644 src/locks.cc delete mode 100644 src/locks.h delete mode 100644 src/ps.cc delete mode 100644 src/ps.h diff --git a/VERSION.cmake b/VERSION.cmake index 35babde..1724bf4 100644 --- a/VERSION.cmake +++ b/VERSION.cmake @@ -34,7 +34,7 @@ # SET(VERSION_MAJOR "1") SET(VERSION_MINOR "14") -SET(VERSION_PATCH "13") +SET(VERSION_PATCH "14") -# LAST RELEASED: 1.14.13 +# LAST RELEASED: 1.14.14 #======= diff --git a/package/zypper.changes b/package/zypper.changes index 3df7965..caee880 100644 --- a/package/zypper.changes +++ b/package/zypper.changes @@ -1,4 +1,14 @@ ------------------------------------------------------------------- +Fri Oct 12 14:05:47 CEST 2018 - ma@suse.de + +- BuildRequires: libzypp-devel >= 17.8.0 (for fate#326451) +- Introduce new zypper command framefork. Migrated commands so far: + addlock addrepo addservice clean cleanlocks modifyrepo modifyservice + ps refresh refresh-services removelock removerepo removeservice + renamerepo repos services +- version 1.14.14 + +------------------------------------------------------------------- Tue Oct 9 17:30:45 CEST 2018 - ma@suse.de - MediaChangeReport: fix https URLs causing 2 prompts on error diff --git a/po/de.po b/po/de.po index d7c826d..e8e6e4b 100644 --- a/po/de.po +++ b/po/de.po @@ -17,10 +17,10 @@ msgstr "" "Project-Id-Version: zypper.de\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-09-21 12:17+0200\n" -"PO-Revision-Date: 2018-08-30 21:02+0000\n" +"PO-Revision-Date: 2018-10-09 23:02+0000\n" "Last-Translator: Sarah Kriesch \n" -"Language-Team: German \n" +"Language-Team: German " +"\n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -6253,9 +6253,8 @@ msgid " Default: %1%" msgstr "" #: src/commands/basecommand.cc:134 -#, fuzzy msgid "Options:" -msgstr "optional" +msgstr "Optionen:" #. translators: property name; short; used like "Name: value" #. translators: Table column header diff --git a/po/pt_BR.po b/po/pt_BR.po index 49e8d37..d81b96e 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -11,10 +11,10 @@ msgstr "" "Project-Id-Version: zypper\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-09-21 12:17+0200\n" -"PO-Revision-Date: 2018-08-30 19:09+0000\n" -"Last-Translator: Rodrigo Macedo \n" -"Language-Team: Portuguese (Brazil) \n" +"PO-Revision-Date: 2018-10-09 21:05+0000\n" +"Last-Translator: Luiz Fernando Ranghetti \n" +"Language-Team: Portuguese (Brazil) " +"\n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -610,12 +610,12 @@ msgstr "categoria" #. translator: Option argument like '--export '. Do do not translate lowercase wordparts #: src/utils/flags/zyppflags.h:27 msgid "DIR" -msgstr "" +msgstr "DIR" #. translator: Option argument like '--export '. Do do not translate lowercase wordparts #: src/utils/flags/zyppflags.h:29 msgid "FILE" -msgstr "" +msgstr "ARQUIVO" #. translator: Option argument like '--export '. Do do not translate lowercase wordparts #: src/utils/flags/zyppflags.h:31 @@ -625,7 +625,7 @@ msgstr "arquivo.repo" #. translator: Option argument like '--export '. Do do not translate lowercase wordparts #: src/utils/flags/zyppflags.h:33 msgid "FORMAT" -msgstr "" +msgstr "FORMATO" #. translator: Option argument like '--export '. Do do not translate lowercase wordparts #: src/utils/flags/zyppflags.h:35 @@ -635,7 +635,7 @@ msgstr "inteiro" #. translator: Option argument like '--export '. Do do not translate lowercase wordparts #: src/utils/flags/zyppflags.h:37 msgid "PATH" -msgstr "" +msgstr "CAMINHO" #. translator: Option argument like '--export '. Do do not translate lowercase wordparts #: src/utils/flags/zyppflags.h:39 @@ -645,12 +645,12 @@ msgstr "gravidade" #. translator: Option argument like '--export '. Do do not translate lowercase wordparts #: src/utils/flags/zyppflags.h:41 msgid "STRING" -msgstr "" +msgstr "TEXTO" #. translator: Option argument like '--export '. Do do not translate lowercase wordparts #: src/utils/flags/zyppflags.h:43 msgid "TAG" -msgstr "" +msgstr "ETIQUETA" #. translator: Option argument like '--export '. Do do not translate lowercase wordparts #: src/utils/flags/zyppflags.h:45 @@ -2063,7 +2063,7 @@ msgstr "" #. translators: --plus-repo, -p #: src/Zypper.cc:760 msgid "Use an additional repository." -msgstr "Usar um repositório adicional" +msgstr "Usar um repositório adicional." #. translators: --plus-content #: src/Zypper.cc:762 @@ -2356,7 +2356,7 @@ msgstr "Outros comandos:" #. translators: command summary: versioncmp, vcmp #: src/Zypper.cc:878 msgid "Compare two version strings." -msgstr "Comparar textos de duas versões" +msgstr "Comparar textos de duas versões." #. translators: command summary: targetos, tos #: src/Zypper.cc:880 @@ -3332,6 +3332,13 @@ msgid "" " --loose-auth Ignore user authentication data in the URI.\n" " --loose-query Ignore query string in the URI.\n" msgstr "" +"removeservice (rs) [OPÇÕES] \n" +"\n" +"Remove o serviço de indexação de repositório especificado do sistema.\n" +"\n" +" Opções do comando:\n" +" --loose-auth Ignora os dados de autenticação do usuário na URI.\n" +" --loose-query Ignora o texto de consulta na URI.\n" #. translators: %s is "--all" and "--all" #: src/Zypper.cc:2463 @@ -4155,23 +4162,25 @@ msgstr "" #. translators: command synopsis; do not translate lowercase words #: src/Zypper.cc:3113 msgid "update (up) [OPTIONS] [PACKAGENAME] ..." -msgstr "" +msgstr "update (up) [OPÇÕES] [NOME_DO_PACOTE] ..." #. translators: command description #: src/Zypper.cc:3116 msgid "" "Update all or specified installed packages with newer versions, if possible." msgstr "" +"Atualiza todos os pacotes instalados ou os especificados com versões mais " +"recentes, se possível." #. translators: --skip-interactive #: src/Zypper.cc:3124 msgid "Skip interactive updates." -msgstr "" +msgstr "Ignora as atualizações interativas." #. translators: --with-interactive #: src/Zypper.cc:3126 msgid "Do not skip interactive updates." -msgstr "" +msgstr "Não ignorar as atualizações interativas." #. translators: -l, --auto-agree-with-licenses #: src/Zypper.cc:3128 src/Zypper.cc:3233 src/Zypper.cc:3394 @@ -4508,7 +4517,7 @@ msgstr "Restringir a atualização ao repositório especificado." #. translators: -D, --dry-run #: src/Zypper.cc:3398 msgid "Test the upgrade, do not actually upgrade" -msgstr "Testar a atualização, não atualizar realmente." +msgstr "Testar a atualização, não atualizar realmente" #: src/Zypper.cc:3451 msgid "" @@ -5199,7 +5208,7 @@ msgstr "" #. translators: command synopsis; do not translate lowercase words #: src/Zypper.cc:4006 msgid "moo" -msgstr "" +msgstr "moo" #. translators: command description #: src/Zypper.cc:4009 @@ -5265,7 +5274,7 @@ msgstr "Remover apenas os bloqueios do repositório especificado." #. translators: command synopsis; do not translate the command 'name (abbreviations)' or '-option' names #: src/Zypper.cc:4095 msgid "cleanlocks (cl)" -msgstr "" +msgstr "cleanlocks (cl)" #. translators: command description #: src/Zypper.cc:4098 @@ -5353,7 +5362,7 @@ msgstr "" #. translators: command synopsis; do not translate lowercase words #: src/Zypper.cc:4186 msgid "licenses" -msgstr "" +msgstr "licenses" #. translators: command description #: src/Zypper.cc:4189 @@ -5507,7 +5516,7 @@ msgstr "" #. translators: command synopsis; do not translate lowercase words #: src/Zypper.cc:4309 msgid "source-download" -msgstr "" +msgstr "source-download" #. translators: -d, --directory #: src/Zypper.cc:4316 @@ -5570,7 +5579,7 @@ msgstr "" #. translators: command synopsis; do not translate lowercase words #: src/Zypper.cc:4355 msgid "quit (exit, ^D)" -msgstr "" +msgstr "quit (exit, ^D)" #. translators: command description #: src/Zypper.cc:4358 @@ -5594,7 +5603,7 @@ msgstr "" #. translators: command synopsis; do not translate lowercase words #: src/Zypper.cc:4383 msgid "shell (sh)" -msgstr "" +msgstr "shell (sh)" #. translators: command description #: src/Zypper.cc:4386 @@ -6164,12 +6173,11 @@ msgstr "Senha" #: src/commands/basecommand.cc:121 #, boost-format msgid " Default: %1%" -msgstr "" +msgstr " Padrão: %1%" #: src/commands/basecommand.cc:134 -#, fuzzy msgid "Options:" -msgstr "opcional" +msgstr "Opções:" #. translators: property name; short; used like "Name: value" #. translators: Table column header @@ -8340,30 +8348,30 @@ msgstr "Erro ao analisar zypper.conf:" #: src/utils/flags/exceptions.cc:21 #, boost-format msgid "The flag %1% is not known." -msgstr "" +msgstr "O indicador %1% não é conhecido." #: src/utils/flags/exceptions.cc:27 msgid "The flag %1% is not compatible with argument %2% (%2)." -msgstr "" +msgstr "O indicador %1% não é compatível com o argumento %2% (%2)." #: src/utils/flags/exceptions.cc:33 -#, fuzzy, boost-format +#, boost-format msgid "The flag %1% requires a argument." -msgstr "O nome do pacote fonte é um argumento necessário." +msgstr "O indicador %1% requer um argumento." #: src/utils/flags/exceptions.cc:39 #, boost-format msgid "The flag %1% can only be used once." -msgstr "" +msgstr "O indicador %1% só pode ser usado uma vez." #: src/utils/flags/flagtypes.cc:48 msgid "Out of range" -msgstr "" +msgstr "Fora do alcance" #: src/utils/flags/flagtypes.cc:50 #, boost-format msgid "Unknown error while assigning the value %1% to flag %2%." -msgstr "" +msgstr "Erro desconhecido ao atribuir o valor %1% ao indicador %2%." #. For '-garbage' argument, with 'a', 'b', and 'e' as known options, #. getopt_long reports 'a', 'b', and 'e' as known options. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 78e6ae0..634f7ef 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -21,7 +21,6 @@ SET (zypper_HEADERS search.h info.h Table.h - locks.h update.h download.h source-download.h @@ -29,7 +28,6 @@ SET (zypper_HEADERS configtest.h solve-commit.h PackageArgs.h - ps.h SolverRequester.h Summary.h callbacks/keyring.h @@ -38,11 +36,30 @@ SET (zypper_HEADERS callbacks/repo.h callbacks/job.h commands/commandhelpformatter.h + commands/conditions.h commands/basecommand.h commands/locks.h commands/locks/add.h + commands/locks/clean.h commands/locks/list.h commands/locks/remove.h + commands/services.h + commands/services/common.h + commands/services/list.h + commands/services/refresh.h + commands/services/add.h + commands/services/modify.h + commands/services/remove.h + commands/repos.h + commands/repos/list.h + commands/repos/add.h + commands/repos/clean.h + commands/repos/remove.h + commands/repos/rename.h + commands/repos/modify.h + commands/repos/refresh.h + commands/reposerviceoptionsets.h + commands/ps.h ) SET( zypper_SRCS @@ -54,7 +71,6 @@ SET( zypper_SRCS search.cc info.cc Table.cc - locks.cc update.cc download.cc source-download.cc @@ -62,16 +78,32 @@ SET( zypper_SRCS configtest.cc solve-commit.cc PackageArgs.cc - ps.cc RequestFeedback.cc SolverRequester.cc Summary.cc callbacks/media.cc commands/commandhelpformatter.cc + commands/conditions.cc commands/basecommand.cc commands/locks/add.cc + commands/locks/clean.cc commands/locks/list.cc commands/locks/remove.cc + commands/services/common.cc + commands/services/list.cc + commands/services/refresh.cc + commands/services/add.cc + commands/services/modify.cc + commands/services/remove.cc + commands/repos/list.cc + commands/repos/add.cc + commands/repos/clean.cc + commands/repos/remove.cc + commands/repos/rename.cc + commands/repos/modify.cc + commands/repos/refresh.cc + commands/reposerviceoptionsets.cc + commands/ps.cc ${zypper_HEADERS} ) diff --git a/src/Command.cc b/src/Command.cc index 2bab4bc..0f21b3d 100644 --- a/src/Command.cc +++ b/src/Command.cc @@ -6,6 +6,7 @@ \*---------------------------------------------------------------------------*/ #include +#include #include #include @@ -15,6 +16,9 @@ #include "Command.h" #include "commands/locks.h" +#include "commands/services.h" +#include "commands/repos.h" +#include "commands/ps.h" using namespace zypp; @@ -27,17 +31,59 @@ using namespace zypp; /////////////////////////////////////////////////////////////////// namespace { + + template + ZypperBaseCommandPtr commandFactory ( const std::vector &aliases_r ) + { + return std::make_shared ( aliases_r ); + } + + struct CommandFactory { + std::vector aliases; + std::function & )> constructor; + + ZypperBaseCommandPtr operator ()() + { + return constructor( aliases ); + } + + template + constexpr static CommandFactory make ( const std::vector &aliases_r ) + { + return CommandFactory { aliases_r, commandFactory}; + } + }; + //@TODO hack for now, this should be migrated to be part of Zypper class directly instead of a //singleton - static std::map< ZypperCommand::Command, ZypperBaseCommandPtr > &newStyleCommands () + static std::map< ZypperCommand::Command, CommandFactory > &newStyleCommands () { - static std::map< ZypperCommand::Command, ZypperBaseCommandPtr > table { - { ZypperCommand::LIST_LOCKS_e, std::make_shared() } + static std::map< ZypperCommand::Command, CommandFactory> table { + { ZypperCommand::LIST_LOCKS_e, CommandFactory::make( { "locks", "ll", "lock-list" }) }, + { ZypperCommand::ADD_LOCK_e, CommandFactory::make({ "addlock", "al", "lock-add", "la" }) }, + { ZypperCommand::REMOVE_LOCK_e, CommandFactory::make({ "removelock", "rl", "lock-delete" , "ld" }) }, + { ZypperCommand::CLEAN_LOCKS_e, CommandFactory::make ({ "cleanlocks" , "cl", "lock-clean" }) }, + + { ZypperCommand::LIST_SERVICES_e, CommandFactory::make( { "services", "ls", "service-list", "sl" } ) }, + { ZypperCommand::REFRESH_SERVICES_e, CommandFactory::make( { "refresh-services", "refs" } ) }, + { ZypperCommand::MODIFY_SERVICE_e, CommandFactory::make( { "modifyservice", "ms" } ) }, //<< + { ZypperCommand::REMOVE_SERVICE_e, CommandFactory::make( { "removeservice", "rs", "service-delete", "sd" } ) }, + { ZypperCommand::ADD_SERVICE_e, CommandFactory::make( { "addservice", "as", "service-add", "sa" } ) }, + + { ZypperCommand::LIST_REPOS_e, CommandFactory::make( {"repos", "lr", "catalogs","ca"} ) }, + { ZypperCommand::ADD_REPO_e, CommandFactory::make( { "addrepo", "ar" } ) }, + { ZypperCommand::REMOVE_REPO_e, CommandFactory::make( { "removerepo", "rr" } ) }, + { ZypperCommand::RENAME_REPO_e, CommandFactory::make( { "renamerepo", "nr" } ) }, + { ZypperCommand::MODIFY_REPO_e, CommandFactory::make( { "modifyrepo", "mr" } ) }, + { ZypperCommand::REFRESH_e, CommandFactory::make( { "refresh", "ref" } ) }, + { ZypperCommand::CLEAN_e, CommandFactory::make( { "clean", "cc", "clean-cache", "you-clean-cache", "yc" } ) }, + + { ZypperCommand::PS_e, CommandFactory::make( { "ps" }) } }; return table; } - static NamedValue & table() + static NamedValue & cmdTable() { static NamedValue _table; if ( _table.empty() ) @@ -46,19 +92,19 @@ namespace _t( NONE_e ) | "NONE" | "none" | ""; _t( SUBCOMMAND_e) | "subcommand"; - _t( ADD_SERVICE_e ) | "addservice" | "as" | "service-add" | "sa"; - _t( REMOVE_SERVICE_e ) | "removeservice" | "rs" | "service-delete" | "sd"; - _t( MODIFY_SERVICE_e ) | "modifyservice" | "ms"; - _t( LIST_SERVICES_e ) | "services" | "ls" | "service-list" | "sl"; - _t( REFRESH_SERVICES_e ) | "refresh-services" | "refs"; + //_t( ADD_SERVICE_e ) | "addservice" | "as" | "service-add" | "sa"; + //_t( REMOVE_SERVICE_e ) | "removeservice" | "rs" | "service-delete" | "sd"; + //_t( MODIFY_SERVICE_e ) | "modifyservice" | "ms"; + //_t( LIST_SERVICES_e ) | "services" | "ls" | "service-list" | "sl"; + //_t( REFRESH_SERVICES_e ) | "refresh-services" | "refs"; - _t( ADD_REPO_e ) | "addrepo" | "ar"; - _t( REMOVE_REPO_e ) | "removerepo" | "rr"; - _t( RENAME_REPO_e ) | "renamerepo" | "nr"; - _t( MODIFY_REPO_e ) | "modifyrepo" | "mr"; - _t( LIST_REPOS_e ) | "repos" | "lr" | "catalogs" | "ca"; - _t( REFRESH_e ) | "refresh" | "ref"; - _t( CLEAN_e ) | "clean" | "cc" | "clean-cache" | "you-clean-cache" | "yc"; + //_t( ADD_REPO_e ) | "addrepo" | "ar"; + //_t( REMOVE_REPO_e ) | "removerepo" | "rr"; + //_t( RENAME_REPO_e ) | "renamerepo" | "nr"; + //_t( MODIFY_REPO_e ) | "modifyrepo" | "mr"; + //_t( LIST_REPOS_e ) | "repos" | "lr" | "catalogs" | "ca"; + //_t( REFRESH_e ) | "refresh" | "ref"; + //_t( CLEAN_e ) | "clean" | "cc" | "clean-cache" | "you-clean-cache" | "yc"; _t( INSTALL_e ) | "install" | "in"; _t( REMOVE_e ) | "remove" | "rm"; @@ -84,15 +130,15 @@ namespace //_t( WHAT_REQUIRES_e ) | "what-requires" | "wr"; //_t( WHAT_CONFLICTS_e ) | "what-conflicts" | "wc"; - _t( ADD_LOCK_e ) | "addlock" | "al" | "lock-add" | "la"; - _t( REMOVE_LOCK_e ) | "removelock" | "rl" | "lock-delete" | "ld"; - //_t( LIST_LOCKS_e ) | "locks" | "ll" | "lock-list"; - _t( CLEAN_LOCKS_e ) | "cleanlocks" | "cl" | "lock-clean"; + // _t( ADD_LOCK_e ) | "addlock" | "al" | "lock-add" | "la"; + // _t( REMOVE_LOCK_e ) | "removelock" | "rl" | "lock-delete" | "ld"; + // _t( LIST_LOCKS_e ) | "locks" | "ll" | "lock-list"; + // _t( CLEAN_LOCKS_e ) | "cleanlocks" | "cl" | "lock-clean"; _t( TARGET_OS_e ) | "targetos" | "tos"; _t( VERSION_CMP_e ) | "versioncmp" | "vcmp"; _t( LICENSES_e ) | "licenses"; - _t( PS_e ) | "ps"; + // _t( PS_e ) | "ps"; _t( DOWNLOAD_e ) | "download"; _t( SOURCE_DOWNLOAD_e ) | "source-download"; @@ -113,7 +159,7 @@ namespace // patch the table to contain all new style commands for ( const auto &cmd : newStyleCommands() ) { auto entry = _table(cmd.first); - for ( const std::string &alias : cmd.second->command()) + for ( const std::string &alias : cmd.second.aliases) entry | alias; } } @@ -195,7 +241,7 @@ ZypperCommand::ZypperCommand(ZypperCommand::Command command) : _command(command) //set the command object if the passed enum represents a new style cmd auto &newCmds = newStyleCommands(); if ( newCmds.find( _command ) != newCmds.end() ) { - _newStyleCmdObj = newCmds[_command]; + _newStyleCmdObj = newCmds[_command](); } } @@ -206,7 +252,7 @@ ZypperCommand::ZypperCommand( const std::string & strval_r ) ZypperCommand::Command ZypperCommand::parse( const std::string & strval_r ) const { ZypperCommand::Command cmd = SUBCOMMAND_e; // Exception if not true - if ( ! table().getValue( strval_r, cmd ) ) + if ( ! cmdTable().getValue( strval_r, cmd ) ) { bool isSubcommand( const std::string & strval_r ); // in subcommand.cc @@ -219,7 +265,7 @@ ZypperCommand::Command ZypperCommand::parse( const std::string & strval_r ) cons } const std::string & ZypperCommand::asString() const -{ return table().getName( _command ); } +{ return cmdTable().getName( _command ); } ZypperBaseCommandPtr ZypperCommand::commandObject() const { diff --git a/src/PackageArgs.cc b/src/PackageArgs.cc index 96674c8..d12a0ac 100644 --- a/src/PackageArgs.cc +++ b/src/PackageArgs.cc @@ -182,6 +182,7 @@ void PackageArgs::argsToCaps( const ResKind & kind ) while ( pos != std::string::npos && arg.find_first_of( "(=" ) > pos ) { repo = arg.substr( 0, pos ); + if ( match_repo( zypper, repo ) ) { hasRepo = true; diff --git a/src/Zypper.cc b/src/Zypper.cc index ec9a82e..5864c59 100644 --- a/src/Zypper.cc +++ b/src/Zypper.cc @@ -18,9 +18,6 @@ #include #include -#include -#include -#include #include #include @@ -54,10 +51,8 @@ #include "update.h" #include "solve-commit.h" #include "misc.h" -#include "locks.h" #include "search.h" #include "info.h" -#include "ps.h" #include "download.h" #include "source-download.h" #include "configtest.h" @@ -72,6 +67,11 @@ #include "commands/commandhelpformatter.h" #include "commands/locks.h" +#include "commands/services/common.h" +#include "commands/services/refresh.h" +#include "commands/conditions.h" +#include "commands/reposerviceoptionsets.h" +#include "commands/repos/refresh.h" using namespace zypp; bool sigExitOnce = true; // Flag to prevent nested calls to Zypper::immediateExit @@ -296,6 +296,7 @@ namespace cli } // namespace cli /////////////////////////////////////////////////////////////////// + ZYpp::Ptr God = NULL; void Zypper::assertZYppPtrGod() { @@ -445,33 +446,7 @@ namespace { return mayuse; } - enum LegacyCLIMsgType { - Local, - Global, - Ignored - }; - - inline std::string legacyCLIStr( const std::string & old_r, const std::string & new_r, LegacyCLIMsgType type_r ) - { - switch (type_r) { - case Local: - case Global: - return str::Format( type_r == Global - ? _("Legacy commandline option %1% detected. Please use global option %2% instead.") - : _("Legacy commandline option %1% detected. Please use %2% instead.") ) - % NEGATIVEString(dashdash(old_r)) - % POSITIVEString(dashdash(new_r)); - break; - case Ignored: - return str::Format( - _("Legacy commandline option %1% detected. This option is ignored.")) - % NEGATIVEString(dashdash(old_r)); - break; - } - return std::string(); - } - - inline void legacyCLITranslate( parsed_opts & copts_r, const std::string & old_r, const std::string & new_r, Out::Verbosity verbosity_r = Out::NORMAL, LegacyCLIMsgType type = Local ) + inline void legacyCLITranslate( parsed_opts & copts_r, const std::string & old_r, const std::string & new_r, Out::Verbosity verbosity_r = Out::NORMAL, LegacyCLIMsgType type = LegacyCLIMsgType::Local ) { if ( copts_r.count( old_r ) ) { @@ -516,36 +491,12 @@ namespace { case ZypperCommand::REMOVE_SERVICE_e: case ZypperCommand::MODIFY_SERVICE_e: #endif - { - - if ( zypper.cOpts().count("dry-run") ) - return true; - - struct statfs fsinfo; - memset( &fsinfo, 0, sizeof(struct statfs) ); - - int err = 0; - do { - err = statfs( gopts_r.root_dir.c_str(), &fsinfo ); - } while ( err == -1 && errno == EINTR ); - - if ( !err ) { - if ( fsinfo.f_flags & ST_RDONLY ) { - - bool isTransactionalServer = ( fsinfo.f_type == BTRFS_SUPER_MAGIC && PathInfo( "/usr/sbin/transactional-update" ).isFile() ); - - std::string msg; - if ( isTransactionalServer && !gopts_r.changedRoot ) { - msg = _("This is a transactional-server, please use transactional-update to update or modify the system."); - } else { - msg = _("The target filesystem is mounted as read-only. Please make sure the target filesystem is writeable."); - } - zypper.out().errorPar( msg ); - ERR << msg << endl; - return false; - } - } else { - WAR << "Checking if " << gopts_r.root_dir << " is mounted read only failed with errno : " << errno << std::endl; + { + std::string msg; + NeedsWritableRoot rt; + if ( rt.check( msg ) != ZYPPER_EXIT_OK ) { + zypper.out().errorPar( msg ); + return false; } break; } @@ -1092,13 +1043,14 @@ void print_command_help_hint( Zypper & zypper ) int Zypper::defaultLoadSystem( LoadSystemFlags flags_r ) { DBG << "FLAGS:" << flags_r << endl; - if ( ! flags_r.testFlag( NO_POOL ) ) + + if ( ! flags_r.testFlag( NoPool ) ) { init_target( *this ); if ( exitCode() != ZYPPER_EXIT_OK ) return exitCode(); - if ( ! flags_r.testFlag( NO_REPOS ) ) + if ( ! flags_r.testFlag( NoRepos ) ) { init_repos(*this); if ( exitCode() != ZYPPER_EXIT_OK ) @@ -1106,7 +1058,7 @@ int Zypper::defaultLoadSystem( LoadSystemFlags flags_r ) } DtorReset _tmp( _gopts.disable_system_resolvables ); - if ( flags_r.testFlag( NO_TARGET ) ) + if ( flags_r.testFlag( NoTarget ) ) { _gopts.disable_system_resolvables = true; } @@ -1114,7 +1066,7 @@ int Zypper::defaultLoadSystem( LoadSystemFlags flags_r ) if ( exitCode() != ZYPPER_EXIT_OK ) return exitCode(); - if ( ! ( flags_r & NO_POOL ) ) + if ( ! ( flags_r & NoPool ) ) { // have REPOS and TARGET // compute status of PPP @@ -1913,6 +1865,10 @@ void Zypper::processCommandOptions() ZypperBaseCommandPtr newStyleCmd = command().commandObject(); if ( newStyleCmd ) { + //reset the command to default + newStyleCmd->reset(); + + //get command help _command_help = newStyleCmd->help(); MIL << "Found new style command << " << newStyleCmd->command().front() << endl; @@ -1923,9 +1879,6 @@ void Zypper::processCommandOptions() // parse command options try { - //reset the command to default - newStyleCmd->reset(); - int nextArg = ZyppFlags::parseCLI( argc(), argv(), newStyleCmd->options(), optind ); MIL << "Parsed new style arguments" << endl; @@ -2367,14 +2320,6 @@ void Zypper::processCommandOptions() break; } - case ZypperCommand::ADD_SERVICE_e: - { - static struct option service_add_options[] = { - {"type", required_argument, 0, 't'}, - {"help", no_argument, 0, 'h'}, - ARG_SERVICE_PROP, - {0, 0, 0, 0} - }; #if 0 _( // translators: the %s = "ris" (the only service type currently supported) @@ -2388,44 +2333,6 @@ void Zypper::processCommandOptions() "-n, --name Specify descriptive name for the service.\n" ) #endif - specific_options = service_add_options; - _command_help = CommandHelpFormater() - .synopsis( // translators: command synopsis; do not translate lowercase words - _("addservice (as) [OPTIONS] ") - ) - .description(// translators: command description - _("Add a repository index service to the system.") - ) - .optionSectionCommandOptions() - .option_SERVICE_PROP - .legacyOptionSection() - .option( "-t, --type ", ( str::Format(_("The type of service is always autodetected. This option is ignored.") ) ).str() ) // FIXME: leagcy, actually autodetected but check libzypp - ; - break; - } - - case ZypperCommand::REMOVE_SERVICE_e: - { - static struct option options[] = { - {"help", no_argument, 0, 'h'}, - {"loose-auth", no_argument, 0, 0}, - {"loose-query", no_argument, 0, 0}, - {0, 0, 0, 0} - }; - specific_options = options; - _command_help = CommandHelpFormater() - .synopsis( // translators: command synopsis; do not translate lowercase words - _("removeservice (rs) [OPTIONS] ") - ) - .description( // translators: command description - _("Remove specified repository index service from the system.") - ) - .optionSectionCommandOptions() - .option( "--loose-auth", // translators: --loose-auth - _("Ignore user authentication data in the URI.") ) - .option( "--loose-query", // translators: --loose-query - _("Ignore query string in the URI.") ) - ; #if 0 _command_help = _( // TranslatorExplanation the %s = "yast2, rpm-md, plaindir" @@ -2438,25 +2345,7 @@ void Zypper::processCommandOptions() " --loose-query Ignore query string in the URI.\n" ); #endif - break; - } - case ZypperCommand::MODIFY_SERVICE_e: - { - static struct option service_modify_options[] = { - {"help", no_argument, 0, 'h'}, - ARG_SERVICE_PROP, - /* LEGACY(ARG_SERVICE_PROP) prefers -f */ {"refresh", no_argument, 0, 'r'}, - /* LEGACY(ARG_SERVICE_PROP) prefers -F */ {"no-refresh", no_argument, 0, 'R'}, - ARG_REPO_SERVICE_COMMON_AGGREGATE, - {"ar-to-enable", required_argument, 0, 'i'}, - {"ar-to-disable", required_argument, 0, 'I'}, - {"rr-to-enable", required_argument, 0, 'j'}, - {"rr-to-disable", required_argument, 0, 'J'}, - {"cl-to-enable", no_argument, 0, 'k'}, - {"cl-to-disable", no_argument, 0, 'K'}, - {0, 0, 0, 0} - }; #if 0 _( // translators: %s is "--all" and "--all" @@ -2485,83 +2374,8 @@ void Zypper::processCommandOptions() "-t, --remote Apply changes to all remote services.\n" "-m, --medium-type Apply changes to services of specified type.\n" ) -#endif - specific_options = service_modify_options; - _command_help = CommandHelpFormater() - .synopsis( // translators: command synopsis; do not translate lowercase words - _("modifyservice (ms) ") - ) - .synopsis( str::Format( // translators: command synopsis; do not translate lowercase words - _("modifyservice (ms) <%1%>") ) % "--all|--remote|--local|--medium-type" - ) - .description( str::Format(// translators: command description - _("Modify properties of services specified by alias, number, or URI, or by the '%1%' aggregate options.") ) % "--all, --remote, --local, --medium-type" - ) - .optionSectionCommandOptions() - .option_SERVICE_PROP - .gap() - .option( "-a, --all", _("Apply changes to all services.") ) - .option( "-l, --local", _("Apply changes to all local services.") ) - .option( "-t, --remote", _("Apply changes to all remote services.") ) - .option( "-m, --medium-type ", _("Apply changes to services of specified type.") ) - .gap() - .option( "-i, --ar-to-enable ", _("Add a RIS service repository to enable.") ) - .option( "-I, --ar-to-disable ", _("Add a RIS service repository to disable.") ) - .option( "-j, --rr-to-enable ", _("Remove a RIS service repository to enable.") ) - .option( "-J, --rr-to-disable ", _("Remove a RIS service repository to disable.") ) - .option( "-k, --cl-to-enable", _("Clear the list of RIS repositories to enable.") ) - .option( "-K, --cl-to-disable", _("Clear the list of RIS repositories to disable.") ) - // Legacy Options: - .legacyOptionSection() - .legacyOption( "-r", "-f" ) - .legacyOption( "-R", "-F" ) - ; - break; - } - case ZypperCommand::LIST_SERVICES_e: - { - static struct option options[] = - { - {"help", no_argument, 0, 'h'}, - {"uri", no_argument, 0, 'u'}, - {"url", no_argument, 0, 0 }, - {"priority", no_argument, 0, 'p'}, - {"details", no_argument, 0, 'd'}, - {"with-repos", no_argument, 0, 'r'}, - {"show-enabled-only", no_argument, 0, 'E'}, - {"sort-by-uri", no_argument, 0, 'U'}, - {"sort-by-name", no_argument, 0, 'N'}, - {"sort-by-priority", no_argument, 0, 'P'}, - {0, 0, 0, 0} - }; - specific_options = options; - _command_help = CommandHelpFormater() - .synopsis( // translators: command synopsis; do not translate lowercase words - _("services (ls) [OPTIONS]") - ) - .description( // translators: command description - _("List defined services.") - ) - .optionSectionCommandOptions() - .option( "-u, --uri", // translators: -u, --uri - _("Show also base URI of repositories.") ) - .option( "-p, --priority", // translators: -p, --priority - _("Show also repository priority.") ) - .option( "-d, --details", // translators: -d, --details - _("Show more information like URI, priority, type.") ) - .option( "-r, --with-repos", // translators: -r, --with-repos - _("Show also repositories belonging to the services.") ) - .option( "-E, --show-enabled-only", // translators: -E, --show-enabled-only - _("Show enabled repos only.") ) - .option( "-P, --sort-by-priority", // translators: -P, --sort-by-priority - _("Sort the list by repository priority.") ) - .option( "-U, --sort-by-uri", // translators: -U, --sort-by-uri - _("Sort the list by URI.") ) - .option( "-N, --sort-by-name", // translators: -N, --sort-by-name - _("Sort the list by name.") ) - ; -#if 0 + ZypperCommand::LIST_SERVICES_e: _command_help = _( "services (ls) [OPTIONS]\n" "\n" @@ -2577,36 +2391,8 @@ void Zypper::processCommandOptions() "-U, --sort-by-uri Sort the list by URI.\n" "-N, --sort-by-name Sort the list by name.\n" ); -#endif - break; - } - case ZypperCommand::REFRESH_SERVICES_e: - { - static struct option options[] = { - {"force", no_argument, 0, 'f'}, - {"help", no_argument, 0, 'h'}, - {"with-repos", no_argument, 0, 'r'}, - {"restore-status", no_argument, 0, 'R'}, - {0, 0, 0, 0} - }; - specific_options = options; - _command_help = CommandHelpFormater() - .synopsis( // translators: command synopsis; do not translate lowercase words - _("refresh-services (refs) [OPTIONS]") - ) - .description( // translators: command description - _("Refresh defined repository index services.") - ) - .optionSectionCommandOptions() - .option( "-f, --force", // translators: -f, --force - _("Force a complete refresh.") ) - .option( "-r, --with-repos", // translators: -r, --with-repos - _("Refresh also the service repositories.") ) - .option( "-R, --restore-status", // translators: -R, --restore-status - _("Also restore service repositories enabled/disabled state.") ) - ; -#if 0 + //ZypperCommand::REFRESH_SERVICES_e _command_help = _( "refresh-services (refs) [OPTIONS]\n" "\n" @@ -2618,20 +2404,7 @@ void Zypper::processCommandOptions() "-R, --restore-status Also restore service repositories enabled/disabled state.\n" ); #endif - break; - } - case ZypperCommand::ADD_REPO_e: - { - static struct option service_add_options[] = { - {"type", required_argument, 0, 't'}, - {"repo", required_argument, 0, 'r'}, // :( conflicted with '-r --refresh', so ARG_REPO_PROP now uses -f/F - {"help", no_argument, 0, 'h'}, - {"check", no_argument, 0, 'c'}, - {"no-check", no_argument, 0, 'C'}, - ARG_REPO_PROP, - {0, 0, 0, 0} - }; #if 0 _( // translators: the %s = "yast2, rpm-md, plaindir" @@ -2654,85 +2427,7 @@ void Zypper::processCommandOptions() "-f, --refresh Enable autorefresh of the repository.\n" ) #endif - specific_options = service_add_options; - _command_help = CommandHelpFormater() - .synopsis( // translators: command synopsis; do not translate lowercase words - _("addrepo (ar) [OPTIONS] ") - ) - .synopsis( // translators: command synopsis; do not translate lowercase words - _("addrepo (ar) [OPTIONS] ") - ) - .description(// translators: command description - _("Add a repository to the system. The repository can be specified by its URI or can be read from specified .repo file (even remote).") - ) - .optionSectionCommandOptions() - .option( "-r, --repo ", _("Just another means to specify a .repo file to read.") ) - .option( "-c, --check", _("Probe URI.") ) - .option( "-C, --no-check", _("Don't probe URI, probe later during refresh.") ) - .gap() - .option_REPO_PROP - .legacyOptionSection() - .option( "-t, --type ", str::Format(_("The repository type is always autodetected. This option is ignored.") ) ) - ; - break; - } - case ZypperCommand::LIST_REPOS_e: - { - static struct option service_list_options[] = { - {"export", required_argument, 0, 'e'}, - {"alias", no_argument, 0, 'a'}, - {"name", no_argument, 0, 'n'}, - {"refresh", no_argument, 0, 'r'}, - {"uri", no_argument, 0, 'u'}, - {"url", no_argument, 0, 0 }, - {"priority", no_argument, 0, 'p'}, - {"details", no_argument, 0, 'd'}, - {"show-enabled-only", no_argument, 0, 'E'}, - {"sort-by-priority", no_argument, 0, 'P'}, - {"sort-by-uri", no_argument, 0, 'U'}, - {"sort-by-alias", no_argument, 0, 'A'}, - {"sort-by-name", no_argument, 0, 'N'}, - {"service", no_argument, 0, 's'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0} - }; - specific_options = service_list_options; - _command_help = CommandHelpFormater() - .synopsis( // translators: command synopsis; do not translate lowercase words - _("repos (lr) [OPTIONS] [REPO] ...") - ) - .description( // translators: command description - _("List all defined repositories.") - ) - .optionSectionCommandOptions() - .option( "-e, --export ", // translators: -e, --export - _("Export all defined repositories as a single local .repo file.") ) - .option( "-a, --alias", // translators: -a, --alias - _("Show also repository alias.") ) - .option( "-n, --name", // translators: -n, --name - _("Show also repository name.") ) - .option( "-u, --uri", // translators: -u, --uri - _("Show also base URI of repositories.") ) - .option( "-p, --priority", // translators: -p, --priority - _("Show also repository priority.") ) - .option( "-r, --refresh", // translators: -r, --refresh - _("Show also the autorefresh flag.") ) - .option( "-d, --details", // translators: -d, --details - _("Show more information like URI, priority, type.") ) - .option( "-s, --service", // translators: -s, --service - _("Show also alias of parent service.") ) - .option( "-E, --show-enabled-only", // translators: -E, --show-enabled-only - _("Show enabled repos only.") ) - .option( "-U, --sort-by-uri", // translators: -U, --sort-by-uri - _("Sort the list by URI.") ) - .option( "-P, --sort-by-priority", // translators: -P, --sort-by-priority - _("Sort the list by repository priority.") ) - .option( "-A, --sort-by-alias", // translators: -A, --sort-by-alias - _("Sort the list by alias.") ) - .option( "-N, --sort-by-name", // translators: -N, --sort-by-name - _("Sort the list by name.") ) - ; #if 0 _command_help = _( "repos (lr) [OPTIONS] [repo] ...\n" @@ -2755,63 +2450,19 @@ void Zypper::processCommandOptions() "-N, --sort-by-name Sort the list by name.\n" ); #endif - break; - } - case ZypperCommand::REMOVE_REPO_e: - { - static struct option service_delete_options[] = { - {"help", no_argument, 0, 'h'}, - {"loose-auth", no_argument, 0, 0}, - {"loose-query", no_argument, 0, 0}, - ARG_REPO_SERVICE_COMMON_AGGREGATE, - {0, 0, 0, 0} - }; - specific_options = service_delete_options; #if 0 - _command_help = ( CommandHelpFormater() << _( - "removerepo (rr) [OPTIONS] \n" - "\n" - "Remove repository specified by alias, number or URI.\n" - "\n" - " Command options:\n" - " --loose-auth Ignore user authentication data in the URI.\n" - " --loose-query Ignore query string in the URI.\n" - )) + _command_help = ( CommandHelpFormater() << _( + "removerepo (rr) [OPTIONS] \n" + "\n" + "Remove repository specified by alias, number or URI.\n" + "\n" + " Command options:\n" + " --loose-auth Ignore user authentication data in the URI.\n" + " --loose-query Ignore query string in the URI.\n" + )) #endif - _command_help = CommandHelpFormater() - .synopsis( // translators: command synopsis; do not translate lowercase words - _("removerepo (rr) [OPTIONS] ") - ) - .description( // translators: command description - _("Remove repository specified by alias, number or URI.") - ) - .optionSectionCommandOptions() - .option( "--loose-auth", // translators: --loose-auth - _("Ignore user authentication data in the URI.") ) - .option( "--loose-query", // translators: --loose-query - _("Ignore query string in the URI.") ) - .gap() - .option_REPO_AGGREGATES; - break; - } - case ZypperCommand::RENAME_REPO_e: - { - static struct option service_rename_options[] = { - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0} - }; - specific_options = service_rename_options; - _command_help = CommandHelpFormater() - .synopsis( // translators: command synopsis; do not translate lowercase words - _("renamerepo (nr) [OPTIONS] ") - ) - .description( // translators: command description - _("Assign new alias to the repository specified by alias, number or URI.") - ) - .noOptionSection() - ; #if 0 _command_help = _( "renamerepo (nr) [OPTIONS] \n" @@ -2821,19 +2472,7 @@ void Zypper::processCommandOptions() "This command has no additional options.\n" ); #endif - break; - } - case ZypperCommand::MODIFY_REPO_e: - { - static struct option service_modify_options[] = { - {"help", no_argument, 0, 'h'}, - ARG_REPO_PROP, - /* LEGACY(ARG_REPO_PROP) prefers -f */ {"refresh", no_argument, 0, 'r'}, - /* LEGACY(ARG_REPO_PROP) prefers -F */ {"no-refresh", no_argument, 0, 'R'}, - ARG_REPO_SERVICE_COMMON_AGGREGATE, - {0, 0, 0, 0} - }; #if 0 _( // translators: %s is "--all|--remote|--local|--medium-type" @@ -2861,66 +2500,7 @@ void Zypper::processCommandOptions() "-m, --medium-type Apply changes to repositories of specified type.\n" ) #endif - specific_options = service_modify_options; - _command_help = CommandHelpFormater() - .synopsis( // translators: command synopsis; do not translate lowercase words - _("modifyrepo (mr) ") - ) - .synopsis( str::Format( // translators: command synopsis; do not translate lowercase words - _("modifyrepo (mr) <%1%>") ) % "--all|--remote|--local|--medium-type" - ) - .description( str::Format( // translators: command description - _("Modify properties of repositories specified by alias, number, or URI, or by the '%1%' aggregate options.") ) % "--all, --remote, --local, --medium-type" - ) - .optionSectionCommandOptions() - .option_REPO_PROP - .gap() - .option_REPO_AGGREGATES - // Legacy Options: - .legacyOptionSection() - .legacyOption( "-r", "-f" ) - .legacyOption( "-R", "-F" ) - ; - break; - } - case ZypperCommand::REFRESH_e: - { - static struct option refresh_options[] = { - {"force", no_argument, 0, 'f'}, - {"force-build", no_argument, 0, 'b'}, - {"force-download", no_argument, 0, 'd'}, - {"build-only", no_argument, 0, 'B'}, - {"download-only", no_argument, 0, 'D'}, - {"repo", required_argument, 0, 'r'}, - {"services", no_argument, 0, 's'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0} - }; - specific_options = refresh_options; - _command_help = CommandHelpFormater() - .synopsis( // translators: command synopsis; do not translate lowercase words - _("refresh (ref) [ALIAS|#|URI] ...") - ) - .description( // translators: command description - _("Refresh repositories specified by their alias, number or URI. If none are specified, all enabled repositories will be refreshed.") - ) - .optionSectionCommandOptions() - .option( "-f, --force", // translators: -f, --force - _("Force a complete refresh.") ) - .option( "-b, --force-build", // translators: -b, --force-build - _("Force rebuild of the database.") ) - .option( "-d, --force-download", // translators: -d, --force-download - _("Force download of raw metadata.") ) - .option( "-B, --build-only", // translators: -B, --build-only - _("Only build the database, don't download metadata.") ) - .option( "-D, --download-only", // translators: -D, --download-only - _("Only download raw metadata, don't build the database.") ) - .option( "-r, --repo ", // translators: -r, --repo - _("Refresh only specified repositories.") ) - .option( "-s, --services", // translators: -s, --services - _("Refresh also services before refreshing repos.") ) - ; #if 0 _command_help = _( "refresh (ref) [alias|#|URI] ...\n" @@ -2938,37 +2518,6 @@ void Zypper::processCommandOptions() "-s, --services Refresh also services before refreshing repos.\n" ); #endif - break; - } - - case ZypperCommand::CLEAN_e: - { - static struct option service_list_options[] = { - {"help", no_argument, 0, 'h'}, - {"repo", required_argument, 0, 'r'}, - {"metadata", no_argument, 0, 'm'}, - {"raw-metadata", no_argument, 0, 'M'}, - {"all", no_argument, 0, 'a'}, - {0, 0, 0, 0} - }; - specific_options = service_list_options; - _command_help = CommandHelpFormater() - .synopsis( // translators: command synopsis; do not translate lowercase words - _("clean (cc) [ALIAS|#|URI] ...") - ) - .description( // translators: command description - _("Clean local caches.") - ) - .optionSectionCommandOptions() - .option( "-r, --repo ", // translators: -r, --repo - _("Clean only specified repositories.") ) - .option( "-m, --metadata", // translators: -m, --metadata - _("Clean metadata cache.") ) - .option( "-M, --raw-metadata", // translators: -M, --raw-metadata - _("Clean raw metadata cache.") ) - .option( "-a, --all", // translators: -a, --all - _("Clean both metadata and package caches.") ) - ; #if 0 _command_help = _( "clean (cc) [alias|#|URI] ...\n" @@ -2982,8 +2531,6 @@ void Zypper::processCommandOptions() "-a, --all Clean both metadata and package caches.\n" ); #endif - break; - } case ZypperCommand::LIST_UPDATES_e: { @@ -4022,154 +3569,70 @@ void Zypper::processCommandOptions() break; } - case ZypperCommand::ADD_LOCK_e: + case ZypperCommand::TARGET_OS_e: { static struct option options[] = { - {"type", required_argument, 0, 't'}, - {"repo", required_argument, 0, 'r'}, - // rug compatibility (although rug does not seem to support this) - {"catalog", required_argument, 0, 'c'}, - {"help", no_argument, 0, 'h'}, + {"help", no_argument, 0, 'h'}, + {"label", no_argument, 0, 'l'}, {0, 0, 0, 0} }; specific_options = options; _command_help = CommandHelpFormater() - .synopsis( // translators: command synopsis; do not translate the command 'name (abbreviations)' or '-option' names - _("addlock (al) [OPTIONS] ...") + .synopsis( // translators: command synopsis; do not translate lowercase words + _("targetos (tos) [OPTIONS]") ) .description( // translators: command description - _("Add a package lock. Specify packages to lock by exact name or by a glob pattern using '*' and '?' wildcard characters.") + _("Show various information about the target operating system. By default, an ID string is shown.") ) .optionSectionCommandOptions() - .option( "-r, --repo ", // translators: -r, --repo - _("Restrict the lock to the specified repository.") ) - .option( "-t, --type ", // translators: -t, --type - str::Format(_("Type of package (%1%).") ) % "package, patch, pattern, product" ) - // NOTE: Original help text had a ' Default: %s", "package" appended. + .option( "-l, --label", // translators: -l, --label + _("Show the operating system label.") ) ; +#if 0 + _command_help = _( + "targetos (tos) [OPTIONS]\n" + "\n" + "Show various information about the target operating system.\n" + "By default, an ID string is shown.\n" + "\n" + " Command options:\n" + "-l, --label Show the operating system label.\n" + ); +#endif break; } - case ZypperCommand::REMOVE_LOCK_e: + case ZypperCommand::VERSION_CMP_e: { static struct option options[] = { - {"type", required_argument, 0, 't'}, - {"repo", required_argument, 0, 'r'}, - // rug compatibility (although rug does not seem to support this) - {"catalog", required_argument, 0, 'c'}, {"help", no_argument, 0, 'h'}, + {"match", no_argument, 0, 'm'}, {0, 0, 0, 0} }; specific_options = options; _command_help = CommandHelpFormater() - .synopsis( // translators: command synopsis; do not translate the command 'name (abbreviations)' or '-option' names - _("removelock (rl) [OPTIONS] ...") + .synopsis( // translators: command synopsis; do not translate lowercase words + _("versioncmp (vcmp) ") ) - .description( // translators: command description; %1% is acoomand like 'zypper locks' - str::Format(_("Remove a package lock. Specify the lock to remove by its number obtained with '%1%' or by package name.") ) % "zypper locks" + .description( // translators: command description + _("Compare the versions supplied as arguments.") ) .optionSectionCommandOptions() - .option( "-r, --repo ", // translators: -r, --repo - _("Remove only locks with specified repository.") ) - .option( "-t, --type ", // translators: -t, --type - str::Format(_("Type of package (%1%).") ) % "package, patch, pattern, product" ) - // NOTE: Original help text had a ' Default: %s", "package" appended. + .option( "-m, --match", // translators: -m, --match + _("Takes missing release number as any release.") ) ; - break; - } - - case ZypperCommand::CLEAN_LOCKS_e: - { - static struct option options[] = - { - {"help", no_argument, 0, 'h'}, - {"only-duplicates", no_argument, 0, 'd' }, - {"only-empty", no_argument, 0, 'e' }, - {0, 0, 0, 0} - }; - specific_options = options; - _command_help = CommandHelpFormater() - .synopsis( // translators: command synopsis; do not translate the command 'name (abbreviations)' or '-option' names - _("cleanlocks (cl)") - ) - .description( // translators: command description - _("Remove useless locks.") - ) - .optionSectionCommandOptions() - .option( "-d, --only-duplicates", // translators: -d, --only-duplicates - _("Clean only duplicate locks.") ) - .option( "-e, --only-empty", // translators: -e, --only-empty - _("Clean only locks which doesn't lock anything.") ) - ; - break; - } - - case ZypperCommand::TARGET_OS_e: - { - static struct option options[] = - { - {"help", no_argument, 0, 'h'}, - {"label", no_argument, 0, 'l'}, - {0, 0, 0, 0} - }; - specific_options = options; - _command_help = CommandHelpFormater() - .synopsis( // translators: command synopsis; do not translate lowercase words - _("targetos (tos) [OPTIONS]") - ) - .description( // translators: command description - _("Show various information about the target operating system. By default, an ID string is shown.") - ) - .optionSectionCommandOptions() - .option( "-l, --label", // translators: -l, --label - _("Show the operating system label.") ) - ; -#if 0 - _command_help = _( - "targetos (tos) [OPTIONS]\n" - "\n" - "Show various information about the target operating system.\n" - "By default, an ID string is shown.\n" - "\n" - " Command options:\n" - "-l, --label Show the operating system label.\n" - ); -#endif - break; - } - - case ZypperCommand::VERSION_CMP_e: - { - static struct option options[] = - { - {"help", no_argument, 0, 'h'}, - {"match", no_argument, 0, 'm'}, - {0, 0, 0, 0} - }; - specific_options = options; - _command_help = CommandHelpFormater() - .synopsis( // translators: command synopsis; do not translate lowercase words - _("versioncmp (vcmp) ") - ) - .description( // translators: command description - _("Compare the versions supplied as arguments.") - ) - .optionSectionCommandOptions() - .option( "-m, --match", // translators: -m, --match - _("Takes missing release number as any release.") ) - ; -#if 0 - _command_help = _( - "versioncmp (vcmp) \n" - "\n" - "Compare the versions supplied as arguments.\n" - "\n" - " Command options:\n" - "-m, --match Takes missing release number as any release.\n" - ); -#endif +#if 0 + _command_help = _( + "versioncmp (vcmp) \n" + "\n" + "Compare the versions supplied as arguments.\n" + "\n" + " Command options:\n" + "-m, --match Takes missing release number as any release.\n" + ); +#endif break; } @@ -4202,39 +3665,6 @@ void Zypper::processCommandOptions() break; } - - case ZypperCommand::PS_e: - { - shared_ptr myOpts( new PsOptions() ); - _commandOptions = myOpts; - static struct option options[] = - { - {"help", no_argument, 0, 'h'}, - {"short", no_argument, 0, 's'}, - {"print", required_argument, 0, 0 }, - {"debugFile", required_argument, 0, 'd' }, - {0, 0, 0, 0} - }; - specific_options = options; - _command_help = CommandHelpFormater() - .synopsis( // translators: command synopsis; do not translate the command 'name (abbreviations)' or '-option' names - _("ps [OPTIONS]") - ) - .description( // translators: command description - _("List running processes which might still use files and libraries deleted by recent upgrades.") - ) - .optionSectionCommandOptions() - .option( "-s, --short", // translators: -s, --short - _("Create a short table not showing the deleted files. Given twice, show only processes which are associated with a system service. Given three times, list the associated system service names only.") ) - .option( "--print ", // translators: --print - _("For each associated system service print on the standard output, followed by a newline. Any '%s' directive in is replaced by the system service name.") ) - .option("-d, --debugFile ", // translators: -d, --debugFile - _("Write debug output to file .")) - ; - break; - } - - case ZypperCommand::DOWNLOAD_e: { shared_ptr myOpts( new DownloadOptions() ); @@ -4492,696 +3922,133 @@ void Zypper::processCommandOptions() } default: - { - if ( runningHelp() ) - break; - - ERR << "Unknown or unexpected command" << endl; - out().error(_("Unexpected program flow.")); - report_a_bug( out() ); - } - } - - // no need to parse command options if we already know we just want help - if ( runningHelp() ) - return; - - // parse command options - _copts = parse_options( argc(), argv(), specific_options ); - if ( _copts.count("_unknown") || _copts.count("_missing_arg") ) - { - setExitCode( ZYPPER_EXIT_ERR_SYNTAX ); - ERR << "Unknown option or missing argument, returning." << endl; - return; - } - - // Leagcy cli translations (mostly from rug to zypper) - legacyCLITranslate( _copts, "agree-to-third-party-licenses", "auto-agree-with-licenses" ); - legacyCLITranslate( _copts, "sort-by-catalog", "sort-by-repo" ); - legacyCLITranslate( _copts, "uninstalled-only", "not-installed-only", Out::HIGH ); // bsc#972997: Prefer --not-installed-only over misleading --uninstalled-only - - if ( command().toEnum() == ZypperCommand::ADD_REPO_e || command().toEnum() == ZypperCommand::ADD_SERVICE_e ) { - legacyCLITranslate( _copts, "type", "", Out::NORMAL, LegacyCLIMsgType::Ignored); - } - - // bsc#957862: pkg/apt/yum user convenience: no-confirm ==> --non-interactive - if ( _copts.count("no-confirm") ) - { - if ( ! _gopts.non_interactive ) - { - out().info(_("Entering non-interactive mode."), Out::HIGH ); - MIL << "Entering non-interactive mode" << endl; - _gopts.non_interactive = true; - } - } - - ::copts = _copts; - MIL << "Done parsing options." << endl; - - // treat --help command option like global --help option from now on - // i.e. when used together with command to print command specific help - setRunningHelp( runningHelp() || copts.count("help") ); - - if ( optind < argc() ) - { - std::ostringstream s; - s << _("Non-option program arguments: "); - while ( optind < argc() ) - { - std::string argument = argv()[optind++]; - s << "'" << argument << "' "; - _arguments.push_back( argument ); - } - out().info( s.str(), Out::HIGH ); - } - - MIL << "Done " << endl; -} - -/// process one command from the OS shell or the zypper shell -void Zypper::doCommand() -{ - // help check is common to all commands - if ( runningHelp() ) - { - out().info( _command_help, Out::QUIET ); - if ( command() == ZypperCommand::SEARCH ) - SLE15_SearchPackagesHintHack( *this ); - return; - } - - // === ZYpp lock === - switch ( command().toEnum() ) - { - case ZypperCommand::PS_e: - case ZypperCommand::SUBCOMMAND_e: - // bnc#703598: Quick fix as few commands do not need a zypp lock - break; - - default: - if ( _gopts.changedRoot && _gopts.root_dir != "/" ) - { - // bnc#575096: Quick fix - ::setenv( "ZYPP_LOCKFILE_ROOT", _gopts.root_dir.c_str(), 0 ); - } - { - const char *roh = getenv( "ZYPP_READONLY_HACK" ); - if ( roh != NULL && roh[0] == '1' ) - zypp_readonly_hack::IWantIt (); - - else if ( command() == ZypperCommand::LIST_REPOS - || command() == ZypperCommand::LIST_SERVICES - || command() == ZypperCommand::VERSION_CMP - || command() == ZypperCommand::TARGET_OS ) - zypp_readonly_hack::IWantIt (); // #247001, #302152 - } - assertZYppPtrGod(); - } - // === execute command === - - if ( !checkRequiredCapabilities( *this, _gopts ) ) { - setExitCode( ZYPPER_EXIT_ERR_PRIVILEGES ); - return; - } - - MIL << "Going to process command " << command() << endl; - - //handle new style commands - ZypperBaseCommandPtr newStyleCmd = command().commandObject(); - if ( newStyleCmd ) { - int exitCode = defaultLoadSystem( newStyleCmd->needSystemSetup() ); - if ( ZYPPER_EXIT_OK != exitCode ) { - setExitCode( exitCode ); - return; - } - - setExitCode( newStyleCmd->run(*this, _arguments) ); - return; - } - - ResObject::Kind kind; - switch( command().toEnum() ) - { - - // --------------------------( moo )---------------------------------------- - - case ZypperCommand::MOO_e: - { - // TranslatorExplanation this is a hedgehog, paint another animal, if you want - out().info(_(" \\\\\\\\\\\n \\\\\\\\\\\\\\__o\n__\\\\\\\\\\\\\\'/_")); - break; - } - - // --------------------------( service list )------------------------------- - - case ZypperCommand::LIST_SERVICES_e: - { - initRepoManager(); - if ( copts.count( "with-repos" ) ) - checkIfToRefreshPluginServices( *this ); - list_services( *this ); - - break; - } - - // --------------------------( service refresh )----------------------------- - - case ZypperCommand::REFRESH_SERVICES_e: - { - // check root user - if ( geteuid() != 0 && !globalOpts().changedRoot ) - { - out().error(_("Root privileges are required for refreshing services.") ); - setExitCode( ZYPPER_EXIT_ERR_PRIVILEGES ); - return; - } - - // needed to be able to retrieve target distribution - init_target(*this); - _gopts.rm_options.servicesTargetDistro = - God->target()->targetDistribution(); - - initRepoManager(); - - refresh_services( *this ); - - break; - } - - // --------------------------( add service )--------------------------------- - - case ZypperCommand::ADD_SERVICE_e: - { - // check root user - if ( geteuid() != 0 && !globalOpts().changedRoot ) - { - out().error(_("Root privileges are required for modifying system services.") ); - setExitCode( ZYPPER_EXIT_ERR_PRIVILEGES ); - return; - } - - // too many arguments - if ( _arguments.size() > 2 ) - { - report_too_many_arguments( _command_help ); - setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - return; - } - - // missing arguments - if ( _arguments.size() < 2 ) - { - report_required_arg_missing( out(), _command_help ); - setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - return; - } - - Url url = make_url( _arguments[0] ); - if ( !url.isValid() ) - { - setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - return; - } - - initRepoManager(); - // force specific repository type. - std::string type = copts.count("type") ? copts["type"].front() : ""; - - // check for valid service type - bool isservice = false; - if ( type.empty() ) - { - // zypper does not access net when adding repos/services, thus for zypper - // the URI is always service unless --type is explicitely specified. - isservice = true; - } - else - { - try - { - repo::ServiceType stype(type); - isservice = true; - } - catch ( const repo::RepoUnknownTypeException & e ) - {} - } - - if ( isservice ) - add_service_by_url( *this, url, _arguments[1] ); - else - { - try - { - add_repo_by_url( *this, url, _arguments[1]); - } - catch ( const repo::RepoUnknownTypeException & e ) - { - ZYPP_CAUGHT( e ); - out().error( - str::form(_("'%s' is not a valid service type."), type.c_str()), - str::form( - _("See '%s' or '%s' to get a list of known service types."), - "zypper help addservice", "man zypper")); - setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - } - } - - break; - } - - case ZypperCommand::MODIFY_SERVICE_e: - { - // check root user - if ( geteuid() != 0 && !globalOpts().changedRoot ) - { - out().error(_("Root privileges are required for modifying system services.") ); - setExitCode( ZYPPER_EXIT_ERR_PRIVILEGES ); - return; - } - - bool non_alias = copts.count("all") || copts.count("local") || copts.count("remote") || copts.count("medium-type"); - - if ( _arguments.size() < 1 && !non_alias ) - { - // translators: aggregate option is e.g. "--all". This message will be - // followed by ms command help text which will explain it - out().error(_("Alias or an aggregate option is required.")); - ERR << "No alias argument given." << endl; - out().info( _command_help ); - setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - return; - } - // too many arguments - if ( _arguments.size() > 1 || ( _arguments.size() > 0 && non_alias ) ) - { - report_too_many_arguments( _command_help ); - setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - return; - } - - initRepoManager(); - - if ( non_alias ) - { - modify_services_by_option( *this ); - } - else - { - repo::RepoInfoBase_Ptr srv; - if ( match_service( *this, _arguments[0], srv ) ) - { - if ( dynamic_pointer_cast(srv) ) - modify_service( *this, srv->alias() ); - else - modify_repo( *this, srv->alias() ); - } - else - { - out().error( str::Format(_("Service '%s' not found.")) % _arguments[0] ); - ERR << "Service " << _arguments[0] << " not found" << endl; - } - } - - break; - } - - // --------------------------( repo list )---------------------------------- - - case ZypperCommand::LIST_REPOS_e: - { - initRepoManager(); - checkIfToRefreshPluginServices( *this ); - list_repos( *this ); - - break; - } - - // --------------------------( addrepo )------------------------------------ - - case ZypperCommand::ADD_REPO_e: - { - // check root user - if ( geteuid() != 0 && !globalOpts().changedRoot ) - { - out().error( _("Root privileges are required for modifying system repositories.") ); - setExitCode( ZYPPER_EXIT_ERR_PRIVILEGES ); - return; - } - - // too many arguments - if ( _arguments.size() > 2 ) - { - report_too_many_arguments( _command_help ); - setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - return; - } - - try - { - // add repository specified in .repo file - if ( copts.count("repo") ) - { - add_repo_from_file( *this,copts["repo"].front() ); - return; - } - - switch ( _arguments.size() ) - { - // display help message if insufficient info was given - case 0: - out().error(_("Too few arguments.")); - ERR << "Too few arguments." << endl; - out().info( _command_help ); - setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - return; - case 1: - if( !isRepoFile( _arguments[0] ) ) - { - out().error(_("If only one argument is used, it must be a URI pointing to a .repo file.")); - ERR << "Not a repo file." << endl; - out().info( _command_help ); - setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - return; - } - else - { - initRepoManager(); - add_repo_from_file( *this,_arguments[0] ); - break; - } - case 2: - Url url; - if ( _arguments[0].find("obs") == 0 ) - url = make_obs_url( _arguments[0], config().obs_baseUrl, config().obs_platform ); - else - url = make_url( _arguments[0] ); - if ( !url.isValid() ) - { - setExitCode(ZYPPER_EXIT_ERR_INVALID_ARGS); - return; - } - - if ( copts.count("check") ) - { - if ( !copts.count("no-check") ) - _gopts.rm_options.probe = true; - else - out().warning(str::form( - _("Cannot use %s together with %s. Using the %s setting."), - "--check", "--no-check", "zypp.conf") - ,Out::QUIET ); - } - else if ( copts.count("no-check") ) - _gopts.rm_options.probe = false; - - initRepoManager(); - - // load gpg keys - init_target( *this ); - - add_repo_by_url( *this, url, _arguments[1]/*alias*/ ); - return; - } - } - catch ( const repo::RepoUnknownTypeException & e ) - { - ZYPP_CAUGHT( e ); - out().error( e, _("Specified type is not a valid repository type:"), - str::form( _("See '%s' or '%s' to get a list of known repository types."), - "zypper help addrepo", "man zypper" ) ); - setExitCode(ZYPPER_EXIT_ERR_INVALID_ARGS); - } - - break; - } - - // --------------------------( delete repo )-------------------------------- - - case ZypperCommand::REMOVE_SERVICE_e: - case ZypperCommand::REMOVE_REPO_e: - { - // check root user - if (geteuid() != 0 && !globalOpts().changedRoot) - { - out().error( - command() == ZypperCommand::REMOVE_REPO ? - _("Root privileges are required for modifying system repositories.") : - _("Root privileges are required for modifying system services.") ); - setExitCode(ZYPPER_EXIT_ERR_PRIVILEGES); - return; - } - - if (command() == ZypperCommand::REMOVE_REPO) - { - bool aggregate = copts.count("all") || copts.count("local") || copts.count("remote") || copts.count("medium-type"); - - if ( _arguments.size() < 1 && !aggregate ) - { - report_alias_or_aggregate_required ( out(), _command_help ); - ERR << "No alias argument given." << endl; - setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - return; - } - - // too many arguments - if ( _arguments.size() && aggregate ) - { - report_too_many_arguments( out(), _command_help ); - setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - return; - } - - initRepoManager(); - if ( aggregate ) - { - remove_repos_by_option( *this ); - } - else - { - // must store repository before remove to ensure correct match number - std::set repo_to_remove; - for_(it, _arguments.begin(), _arguments.end()) - { - RepoInfo repo; - if (match_repo(*this,*it,&repo)) - { - repo_to_remove.insert(repo); - } - else - { - MIL << "Repository not found by given alias, number or URI." << endl; - // translators: %s is the supplied command line argument which - // for which no repository counterpart was found - out().error( str::Format(_("Repository '%s' not found by alias, number or URI.")) % *it ); - } - } - - for_(it, repo_to_remove.begin(), repo_to_remove.end()) - remove_repo(*this,*it); - } - } - else - { - if (_arguments.size() < 1) - { - ERR << "Required argument missing." << endl; - report_required_arg_missing( out(), _command_help ); - setExitCode(ZYPPER_EXIT_ERR_INVALID_ARGS); - return; - } - - initRepoManager(); - - std::set to_remove; - for_(it, _arguments.begin(), _arguments.end()) - { - repo::RepoInfoBase_Ptr s; - if (match_service(*this, *it, s)) - { - to_remove.insert(s); - } - else - { - MIL << "Service not found by given alias, number or URI." << endl; - // translators: %s is the supplied command line argument which - // for which no service counterpart was found - out().error( str::Format(_("Service '%s' not found by alias, number or URI.")) % *it ); - } - } - - for_(it, to_remove.begin(), to_remove.end()) - { - RepoInfo_Ptr repo_ptr = dynamic_pointer_cast(*it); - if (repo_ptr) - remove_repo(*this, *repo_ptr); - else - remove_service(*this, *dynamic_pointer_cast(*it)); - } - } - - break; - } - - // --------------------------( rename repo )-------------------------------- - - case ZypperCommand::RENAME_REPO_e: - { - // check root user - if ( geteuid() != 0 && !globalOpts().changedRoot ) - { - out().error(_("Root privileges are required for modifying system repositories.") ); - setExitCode( ZYPPER_EXIT_ERR_PRIVILEGES ); - return; - } - - if ( _arguments.size() < 2 ) - { - out().error(_("Too few arguments. At least URI and alias are required.") ); - ERR << "Too few arguments. At least URI and alias are required." << endl; - out().info( _command_help ); - setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - return; - } - // too many arguments - else if ( _arguments.size() > 2 ) - { - report_too_many_arguments( _command_help ); - setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - return; - } - - initRepoManager(); - try - { - RepoInfo repo; - if ( match_repo( *this,_arguments[0], &repo )) - { - rename_repo( *this, repo.alias(), _arguments[1] ); - } - else - { - out().error( str::Format(_("Repository '%s' not found.")) % _arguments[0] ); - ERR << "Repo " << _arguments[0] << " not found" << endl; - } - } - catch ( const Exception & excpt_r ) - { - out().error( excpt_r.asUserString() ); - setExitCode( ZYPPER_EXIT_ERR_ZYPP ); - return; - } + { + if ( runningHelp() ) + break; - return; + ERR << "Unknown or unexpected command" << endl; + out().error(_("Unexpected program flow.")); + report_a_bug( out() ); + } } - // --------------------------( modify repo )-------------------------------- + // no need to parse command options if we already know we just want help + if ( runningHelp() ) + return; - case ZypperCommand::MODIFY_REPO_e: + // parse command options + _copts = parse_options( argc(), argv(), specific_options ); + if ( _copts.count("_unknown") || _copts.count("_missing_arg") ) { - // check root user - if ( geteuid() != 0 && !globalOpts().changedRoot ) - { - out().error(_("Root privileges are required for modifying system repositories.") ); - setExitCode( ZYPPER_EXIT_ERR_PRIVILEGES ); - return; - } + setExitCode( ZYPPER_EXIT_ERR_SYNTAX ); + ERR << "Unknown option or missing argument, returning." << endl; + return; + } - bool aggregate = copts.count("all") || copts.count("local") || copts.count("remote") || copts.count("medium-type"); + // Leagcy cli translations (mostly from rug to zypper) + legacyCLITranslate( _copts, "agree-to-third-party-licenses", "auto-agree-with-licenses" ); + legacyCLITranslate( _copts, "sort-by-catalog", "sort-by-repo" ); + legacyCLITranslate( _copts, "uninstalled-only", "not-installed-only", Out::HIGH ); // bsc#972997: Prefer --not-installed-only over misleading --uninstalled-only - if ( _arguments.size() < 1 && !aggregate ) + // bsc#957862: pkg/apt/yum user convenience: no-confirm ==> --non-interactive + if ( _copts.count("no-confirm") ) + { + if ( ! _gopts.non_interactive ) { - report_alias_or_aggregate_required ( out(), _command_help ); - ERR << "No alias argument given." << endl; - setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - return; + out().info(_("Entering non-interactive mode."), Out::HIGH ); + MIL << "Entering non-interactive mode" << endl; + _gopts.non_interactive = true; } + } - // too many arguments - if ( _arguments.size() && aggregate ) - { - report_too_many_arguments( _command_help ); - setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - return; - } + ::copts = _copts; + MIL << "Done parsing options." << endl; - initRepoManager(); - if ( aggregate ) - { - modify_repos_by_option( *this ); - } - else + // treat --help command option like global --help option from now on + // i.e. when used together with command to print command specific help + setRunningHelp( runningHelp() || copts.count("help") ); + + if ( optind < argc() ) + { + std::ostringstream s; + s << _("Non-option program arguments: "); + while ( optind < argc() ) { - for_( arg,_arguments.begin(),_arguments.end() ) - { - RepoInfo r; - if ( match_repo(*this,*arg,&r) ) - { - modify_repo( *this, r.alias() ); - } - else - { - out().error( str::Format(_("Repository %s not found.")) % *arg ); - ERR << "Repo " << *arg << " not found" << endl; - setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - } - } + std::string argument = argv()[optind++]; + s << "'" << argument << "' "; + _arguments.push_back( argument ); } - - break; + out().info( s.str(), Out::HIGH ); } - // --------------------------( refresh )------------------------------------ + MIL << "Done " << endl; +} - case ZypperCommand::REFRESH_e: +/// process one command from the OS shell or the zypper shell +void Zypper::doCommand() +{ + // help check is common to all commands + if ( runningHelp() ) { - // check root user - if ( geteuid() != 0 && !globalOpts().changedRoot ) - { - out().error(_("Root privileges are required for refreshing system repositories.") ); - setExitCode( ZYPPER_EXIT_ERR_PRIVILEGES ); - return; - } + out().info( _command_help, Out::QUIET ); + if ( command() == ZypperCommand::SEARCH ) + SLE15_SearchPackagesHintHack( *this ); + return; + } - if ( globalOpts().no_refresh ) - out().warning( str::Format(_("The '%s' global option has no effect here.")) % "--no-refresh" ); + // === ZYpp lock === + switch ( command().toEnum() ) + { + case ZypperCommand::PS_e: + case ZypperCommand::SUBCOMMAND_e: + // bnc#703598: Quick fix as few commands do not need a zypp lock + break; - // by default refresh only repositories - initRepoManager(); - if ( copts.count("services") ) - { - if ( !_arguments.empty() ) + default: + if ( _gopts.changedRoot && _gopts.root_dir != "/" ) { - out().error(str::form(_("Arguments are not allowed if '%s' is used."), "--services")); - setExitCode( ZYPPER_EXIT_ERR_PRIVILEGES ); - return; + // bnc#575096: Quick fix + ::setenv( "ZYPP_LOCKFILE_ROOT", _gopts.root_dir.c_str(), 0 ); } - // needed to be able to retrieve target distribution - init_target( *this ); - _gopts.rm_options.servicesTargetDistro = God->target()->targetDistribution(); - refresh_services( *this ); - } - else - { - checkIfToRefreshPluginServices( *this ); - } - refresh_repos( *this ); - break; + { + const char *roh = getenv( "ZYPP_READONLY_HACK" ); + if ( roh != NULL && roh[0] == '1' ) + zypp_readonly_hack::IWantIt (); + + else if ( command() == ZypperCommand::LIST_REPOS + || command() == ZypperCommand::LIST_SERVICES + || command() == ZypperCommand::VERSION_CMP + || command() == ZypperCommand::TARGET_OS ) + zypp_readonly_hack::IWantIt (); // #247001, #302152 + } + assertZYppPtrGod(); + } + // === execute command === + + if ( !checkRequiredCapabilities( *this, _gopts ) ) { + setExitCode( ZYPPER_EXIT_ERR_PRIVILEGES ); + return; } - // --------------------------( clean )------------------------------------ + MIL << "Going to process command " << command() << endl; + + //handle new style commands + ZypperBaseCommandPtr newStyleCmd = command().commandObject(); + if ( newStyleCmd ) { + setExitCode( newStyleCmd->run(*this, _arguments) ); + return; + } - case ZypperCommand::CLEAN_e: + ResObject::Kind kind; + switch( command().toEnum() ) { - // check root user - if ( geteuid() != 0 && !globalOpts().changedRoot ) - { - out().error(_("Root privileges are required for cleaning local caches.") ); - setExitCode( ZYPPER_EXIT_ERR_PRIVILEGES ); - return; - } - initRepoManager(); - clean_repos( *this ); + // --------------------------( moo )---------------------------------------- + + case ZypperCommand::MOO_e: + { + // TranslatorExplanation this is a hedgehog, paint another animal, if you want + out().info(_(" \\\\\\\\\\\n \\\\\\\\\\\\\\__o\n__\\\\\\\\\\\\\\'/_")); break; } @@ -5335,7 +4202,7 @@ void Zypper::doCommand() // shut up zypper SCOPED_VERBOSITY( out(), Out::QUIET ); - refresh_repo( *this, repo ); + RefreshRepoCmd::refreshRepository( *this, repo ); runtimeData().temporary_repos.push_back( repo ); } // no rpms and no other arguments either @@ -6226,113 +5093,6 @@ void Zypper::doCommand() return; } - // -----------------------------( locks )------------------------------------ - - case ZypperCommand::ADD_LOCK_e: - { - // check root user - if ( geteuid() != 0 && !globalOpts().changedRoot ) - { - out().error(_("Root privileges are required for adding of package locks.") ); - setExitCode( ZYPPER_EXIT_ERR_PRIVILEGES ); - return; - } - - // too few arguments - if ( _arguments.empty() ) - { - report_required_arg_missing( out(), _command_help ); - setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - return; - } - - ResKindSet kinds; - if ( copts.count("type") ) - { - for_( it, copts["type"].begin(), copts["type"].end() ) - { - kind = string_to_kind( *it ); - if ( kind == ResObject::Kind() ) - { - out().error( str::Format(_("Unknown package type '%s'.")) % *it ); - setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - return; - } - kinds.insert( kind ); - } - } - //else - // let add_locks determine the appropriate type (bnc #551956) - - add_locks( *this, _arguments, kinds ); - - break; - } - - case ZypperCommand::REMOVE_LOCK_e: - { - // check root user - if ( geteuid() != 0 && !globalOpts().changedRoot ) - { - out().error(_("Root privileges are required for adding of package locks.") ); - setExitCode( ZYPPER_EXIT_ERR_PRIVILEGES ); - return; - } - - if ( _arguments.empty() ) - { - report_required_arg_missing( out(), _command_help ); - setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - return; - } - - ResKindSet kinds; - if ( copts.count("type") ) - { - for_( it, copts["type"].begin(), copts["type"].end() ) - { - kind = string_to_kind( *it ); - if ( kind == ResObject::Kind() ) - { - out().error( str::Format(_("Unknown package type '%s'.")) % *it ); - setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - return; - } - kinds.insert( kind ); - } - } - //else - // let remove_locks determine the appropriate type - - remove_locks( *this, _arguments, kinds ); - - break; - } - - case ZypperCommand::CLEAN_LOCKS_e: - { - initRepoManager(); - init_target( *this ); - init_repos( *this ); - if ( exitCode() != ZYPPER_EXIT_OK ) - return; - load_resolvables( *this ); - - Locks::instance().read(); - Locks::size_type start = Locks::instance().size(); - if ( !copts.count("only-duplicate") ) - Locks::instance().removeEmpty(); - if ( !copts.count("only-empty") ) - Locks::instance().removeDuplicates(); - - Locks::instance().save(); - - Locks::size_type diff = start - Locks::instance().size(); - out().info( str::form( PL_("Removed %lu lock.","Removed %lu locks.", diff), (long unsigned)diff ) ); - - break; - } - // ----------------------------(utils/others)-------------------------------- case ZypperCommand::TARGET_OS_e: @@ -6427,37 +5187,6 @@ void Zypper::doCommand() break; } - - case ZypperCommand::PS_e: - { - if ( !_arguments.empty() ) - { - report_too_many_arguments( _command_help ); - setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - return; - } - - shared_ptr myOpts( assertCommandOptions() ); - if ( _copts.count( "print" ) ) - { - // implies -sss - myOpts->_shortness = 3; - myOpts->_format = _copts["print"].back(); // last wins - } - else if ( _copts.count( "short" ) ) - { - myOpts->_shortness = _copts["short"].size(); - } - else if ( _copts.count( "debugFile" ) ) - { - myOpts->_debugFile = _copts["debugFile"].front(); - } - - ps( *this ); - break; - } - - case ZypperCommand::DOWNLOAD_e: { if ( _arguments.empty() ) diff --git a/src/Zypper.h b/src/Zypper.h index 73ef5e5..45752a6 100644 --- a/src/Zypper.h +++ b/src/Zypper.h @@ -60,6 +60,18 @@ namespace cli } // namespace cli /////////////////////////////////////////////////////////////////// +/** Flags for tuning \ref Zypper::defaultLoadSystem. */ +enum LoadSystemBits +{ + NoTarget = (1 << 0), //< don't load target to pool + NoRepos = (1 << 1), //< don't load repos to pool + NoPool = NoTarget | NoRepos //< no pool at all +}; +ZYPP_DECLARE_FLAGS( LoadSystemFlags, LoadSystemBits ); + +/** \relates LoadSystemFlags */ +ZYPP_DECLARE_OPERATORS_FOR_FLAGS( LoadSystemFlags ); + /** * Structure for holding global options. * diff --git a/src/commands/basecommand.cc b/src/commands/basecommand.cc index a23b578..8dfec83 100644 --- a/src/commands/basecommand.cc +++ b/src/commands/basecommand.cc @@ -3,9 +3,14 @@ #include #include "utils/flags/flagtypes.h" #include "commandhelpformatter.h" +#include "solve-commit.h" + +#include "src/repos.h" using namespace zypp; +extern ZYpp::Ptr God; + BaseCommandOptionSet::BaseCommandOptionSet() { } @@ -24,6 +29,26 @@ BaseCommandCondition::~BaseCommandCondition() } +ZypperBaseCommand::ZypperBaseCommand(const std::vector &commandAliases_r, const std::string &synopsis_r, + const std::string &summary_r, const std::string &description_r, + SetupSystemFlags systemInitFlags_r) + : ZypperBaseCommand( commandAliases_r, std::vector{synopsis_r}, summary_r, description_r, systemInitFlags_r ) +{ + +} + +ZypperBaseCommand::ZypperBaseCommand(const std::vector &commandAliases_r, const std::vector &synopsis_r, + const std::string &summary_r, const std::string &description_r, + SetupSystemFlags systemInitFlags_r) + : _commandAliases ( commandAliases_r ), + _synopsis ( synopsis_r ), + _summary ( summary_r ), + _description ( description_r ), + _systemInitFlags ( systemInitFlags_r ) +{ + +} + ZypperBaseCommand::~ZypperBaseCommand() { } @@ -40,20 +65,88 @@ void ZypperBaseCommand::reset() doReset(); } +std::vector ZypperBaseCommand::command() const +{ + return _commandAliases; +} + +std::string ZypperBaseCommand::summary() const +{ + return _summary; +} + +std::vector ZypperBaseCommand::synopsis() const +{ + return _synopsis; +} + +std::string ZypperBaseCommand::description() const +{ + return _description; +} + bool ZypperBaseCommand::helpRequested() const { return _helpRequested; } +SetupSystemFlags ZypperBaseCommand::setupSystemFlags() const +{ + return _systemInitFlags; +} + +ZYpp::Ptr ZypperBaseCommand::zyppApi() const +{ + return God; +} + std::vector ZypperBaseCommand::conditions() const { return std::vector(); } -LoadSystemFlags ZypperBaseCommand::needSystemSetup() const +int ZypperBaseCommand::systemSetup( Zypper &zypp_r ) +{ + return defaultSystemSetup ( zypp_r, _systemInitFlags ); +} + +int ZypperBaseCommand::defaultSystemSetup( Zypper &zypp_r, SetupSystemFlags flags_r ) { - //we want all by default - return LoadSystemFlags(); + DBG << "FLAGS:" << flags_r << endl; + + if ( flags_r.testFlag( ResetRepoManager ) ) + zypp_r.initRepoManager(); + + if ( flags_r.testFlag( InitTarget ) ) { + init_target( zypp_r ); + if ( zypp_r.exitCode() != ZYPPER_EXIT_OK ) + return zypp_r.exitCode(); + } + + if ( flags_r.testFlag( InitRepos ) ) { + init_repos( zypp_r ); + if ( zypp_r.exitCode() != ZYPPER_EXIT_OK ) + return zypp_r.exitCode(); + } + + DtorReset _tmp( zypp_r.globalOptsNoConst().disable_system_resolvables ); + if ( flags_r.testFlag( LoadResolvables ) ) { + if ( flags_r.testFlag( NoSystemResolvables ) ) { + zypp_r.globalOptsNoConst().disable_system_resolvables = true; + } + + load_resolvables( zypp_r ); + if ( zypp_r.exitCode() != ZYPPER_EXIT_OK ) + return zypp_r.exitCode(); + } + + if ( flags_r.testFlag ( Resolve ) ) { + // have REPOS and TARGET + // compute status of PPP + resolve( zypp_r ); + } + + return zypp_r.exitCode(); } int ZypperBaseCommand::run(Zypper &zypp, const std::vector &positionalArgs) @@ -61,7 +154,7 @@ int ZypperBaseCommand::run(Zypper &zypp, const std::vector &positio MIL << "run: " << command().front() << endl; try { - for ( const BaseCommandConditionPtr cond : conditions() ) { + for ( const BaseCommandConditionPtr &cond : conditions() ) { std::string error; int code = cond->check( error ); if ( code != 0 ) { @@ -70,6 +163,10 @@ int ZypperBaseCommand::run(Zypper &zypp, const std::vector &positio } } + int code = systemSetup( zypp ); + if ( code != ZYPPER_EXIT_OK ) + return code; + return execute( zypp, positionalArgs ); } catch ( const Out::Error & error_r ) @@ -85,61 +182,105 @@ int ZypperBaseCommand::run(Zypper &zypp, const std::vector &positio std::string ZypperBaseCommand::help() { CommandHelpFormater help; - help.synopsis(synopsis()) - .description(description()); + for ( const std::string &syn : synopsis() ) + help.synopsis(syn); + help.description(description()); + + auto renderOption = [&help]( const ZyppFlags::CommandOption &opt ) { + std::string optTxt; + if ( opt.shortName ) + optTxt.append( str::Format("-%1%, ") % opt.shortName); + optTxt.append("--").append(opt.name); + + std::string argSyntax = opt.value.argHint(); + if ( argSyntax.length() ) { + if ( opt.flags & ZyppFlags::OptionalArgument ) + optTxt.append("[="); + else + optTxt.append(" <"); + optTxt.append(argSyntax); + if ( opt.flags & ZyppFlags::OptionalArgument ) + optTxt.append("]"); + else + optTxt.append(">"); + } + + std::string optHelpTxt = opt.help; + auto defVal = opt.value.defaultValue(); + if ( defVal ) + optHelpTxt.append(" ").append(str::Format(("Default: %1%")) %*defVal ); + help.option(optTxt, optHelpTxt); + }; + + //all the options we have + std::vector opts = options(); + + //collect all deprecated options + std::vector legacyOptions; bool hadOptions = false; - for ( const ZyppFlags::CommandGroup &grp : options() ) { + for ( const ZyppFlags::CommandGroup &grp : opts ) { if ( grp.options.size() ) { - hadOptions = true; - help.optionSection( grp.name ); + bool wroteSectionHdr = false; for ( const ZyppFlags::CommandOption &opt : grp.options ) { if ( opt.flags & ZyppFlags::Hidden ) continue; - - std::string optTxt; - if ( opt.shortName ) - optTxt.append( str::Format("-%1%, ") % opt.shortName); - optTxt.append("--").append(opt.name); - - std::string argSyntax = opt.value.argHint(); - if ( argSyntax.length() ) { - if ( opt.flags & ZyppFlags::OptionalArgument ) - optTxt.append("[="); - else - optTxt.append(" <"); - optTxt.append(argSyntax); - if ( opt.flags & ZyppFlags::OptionalArgument ) - optTxt.append("]"); - else - optTxt.append(">"); + if ( opt.flags & ZyppFlags::Deprecated ) { + legacyOptions.push_back( &opt ); + continue; } - - std::string optHelpTxt = opt.help; - auto defVal = opt.value.defaultValue(); - if ( defVal ) - optHelpTxt.append(str::Format(_(" Default: %1%")) %*defVal ); - help.option(optTxt, optHelpTxt); + //write the section header only if we actuall have entries + if ( !wroteSectionHdr ) { + wroteSectionHdr = true; + help.optionSection( grp.name ); + } + hadOptions = true; + renderOption(opt); } } } + if ( legacyOptions.size() ) { + help.legacyOptionSection(); + for ( const ZyppFlags::CommandOption *legacyOption : legacyOptions ) { + renderOption(*legacyOption); + } + } + + if ( !hadOptions ) { + help.noOptionSection(); + } + return help; } std::vector ZypperBaseCommand::options() { //first get the commands own options - std::vector allOpts { - { _("Options:"), cmdOptions() } - }; - - ZyppFlags::CommandOption helpOpt{ - "help", 'h', ZyppFlags::NoArgument | ZyppFlags::Hidden, ZyppFlags::BoolType( &_helpRequested ), "" + std::vector allOpts; + + //merges a group into + auto mergeGroup = [ &allOpts ] ( ZyppFlags::CommandGroup &&grp ) { + bool foundCmdGroup = false; + for ( ZyppFlags::CommandGroup &cmdGroup : allOpts ) { + if ( grp.name == cmdGroup.name ) { + foundCmdGroup = true; + std::move( grp.options.begin(), grp.options.end(), std::back_inserter(cmdGroup.options) ); + std::move( grp.conflictingOptions.begin(), grp.conflictingOptions.end(), std::back_inserter(cmdGroup.conflictingOptions) ); + } + } + if ( !foundCmdGroup ) + allOpts.push_back( std::move(grp) ); }; //inject a help option at the beginning, we always want help - allOpts.front().options.insert( allOpts.front().options.end(), std::move(helpOpt)); + //this will also make sure that the default command group is at the beginning + mergeGroup ( ZyppFlags::CommandGroup {{ + { "help", 'h', ZyppFlags::NoArgument | ZyppFlags::Hidden, ZyppFlags::BoolType( &_helpRequested ), "" } + }}); + + // now add the commands own options + mergeGroup ( cmdOptions() ); //now collect all options from registered option sets for ( BaseCommandOptionSet *set : _registeredOptionSets ) { @@ -148,18 +289,9 @@ std::vector ZypperBaseCommand::options() //merge the set into the other options for ( ZyppFlags::CommandGroup &grp : setOpts ) { - bool foundCmdGroup = false; - for ( ZyppFlags::CommandGroup &cmdGroup : allOpts ) { - if ( grp.name == cmdGroup.name ) { - foundCmdGroup = true; - std::move(grp.options.begin(), grp.options.end(), std::back_inserter(cmdGroup.options)); - } - } - if ( !foundCmdGroup ) - allOpts.push_back( grp ); + mergeGroup ( std::move(grp) ); } } - return allOpts; } diff --git a/src/commands/basecommand.h b/src/commands/basecommand.h index c3c339d..2428bbb 100644 --- a/src/commands/basecommand.h +++ b/src/commands/basecommand.h @@ -1,13 +1,15 @@ #ifndef ZYPPER_COMMANDS_BASECOMMAND_INCLUDED #define ZYPPER_COMMANDS_BASECOMMAND_INCLUDED -#include +#include #include #include #include "zypp/base/Flags.h" #include "utils/flags/zyppflags.h" +#include + class Zypper; class ZypperBaseCommand; @@ -41,18 +43,25 @@ public: }; using BaseCommandConditionPtr = std::shared_ptr; - -/** Flags for tuning \ref Zypper::defaultLoadSystem. */ -enum LoadSystemBits +/** Flags for tuning \ref ZypperBaseCommand::defaultSystemSetup. */ +enum SetupSystemBits { - NO_TARGET = (1 << 0), //< don't load target to pool - NO_REPOS = (1 << 1), //< don't load repos to pool - NO_POOL = NO_TARGET | NO_REPOS //< no pool at all + DisableAll = 0, + ResetRepoManager = (1 << 1), //< explicitely reset the repomanager before calling the cmd + InitTarget = (1 << 2), //< Initialize the target + InitRepos = (1 << 3), //< Initialize repositories + NoSystemResolvables = (1 << 4), //< Disable the loading of system resolvables + LoadResolvables = (1 << 5), //< Load resolvables + Resolve = (1 << 6), //< compute status of PPP + DefaultSetup = ResetRepoManager | InitTarget | InitRepos | LoadResolvables | Resolve }; -ZYPP_DECLARE_FLAGS( LoadSystemFlags, LoadSystemBits ); +ZYPP_DECLARE_FLAGS( SetupSystemFlags, SetupSystemBits ); /** \relates LoadSystemFlags */ -ZYPP_DECLARE_OPERATORS_FOR_FLAGS( LoadSystemFlags ); +ZYPP_DECLARE_OPERATORS_FOR_FLAGS( SetupSystemFlags ); + + + /** * All Zypper commands should derive from this type. It automatically @@ -64,6 +73,20 @@ class ZypperBaseCommand public: friend class BaseCommandOptionSet; + ZypperBaseCommand ( const std::vector &commandAliases_r, + const std::string &synopsis_r, + const std::string &summary_r = std::string(), + const std::string &description_r = std::string(), + SetupSystemFlags systemInitFlags_r = DefaultSetup + ); + + ZypperBaseCommand ( const std::vector &commandAliases_r, + const std::vector &synopsis_r, + const std::string &summary_r = std::string(), + const std::string &description_r = std::string(), + SetupSystemFlags systemInitFlags_r = DefaultSetup + ); + virtual ~ZypperBaseCommand(); /** @@ -78,35 +101,28 @@ public: * Returns a list of command aliases that are accepted * on the command line */ - virtual std::list command () const = 0; + virtual std::vector command () const; /** * Returns the command summary, a one line description * of what it does. Used in "zypper help" command overview. * \sa help */ - virtual std::string summary () const = 0; + virtual std::string summary () const; /** * Returns the synopsis of how the command is to be called. * \example "list (ll) [options]" * \sa help */ - virtual std::string synopsis () const = 0; + virtual std::vector synopsis () const; /** * Returns a short description of what the command does, this is * used in the commands help page. * \sa help */ - virtual std::string description () const = 0; - - /** - * Specifies what part of the system need to be initialized before - * executing the command. - * \sa LoadSystemBits - */ - virtual LoadSystemFlags needSystemSetup () const; + virtual std::string description () const; /** * Prepares the command to be executed and checks all conditions before @@ -132,6 +148,15 @@ public: */ bool helpRequested () const; + /** + * Returns the system setup flags set by the constructor + * \sa systemSetup + * \sa defaultSystemSetup + */ + SetupSystemFlags setupSystemFlags () const; + + zypp::ZYpp::Ptr zyppApi () const; + protected: /** * Registers a option set to be supported on command line @@ -148,7 +173,7 @@ protected: /** * Reimplement to return the commands own options. */ - virtual std::vector cmdOptions () const = 0; + virtual zypp::ZyppFlags::CommandGroup cmdOptions () const = 0; /** * Reimplement to reset all options to the default @@ -161,9 +186,25 @@ protected: */ virtual int execute ( Zypper &zypp, const std::vector &positionalArgs ) = 0; + /** + * Sets up the system before the command is executed, reimplement to change default behaviour. + * The default implementation calls \sa defaultSystemSetup + */ + virtual int systemSetup ( Zypper &zypp_r ); + + /** + * Initializes the system according to bits set in \a flags + */ + int defaultSystemSetup(Zypper &zypp_r, SetupSystemFlags flags_r = DefaultSetup ); + private: std::vector _registeredOptionSets; bool _helpRequested = false; + std::vector _commandAliases; + std::vector _synopsis; + std::string _summary; + std::string _description; + SetupSystemFlags _systemInitFlags; }; using ZypperBaseCommandPtr = std::shared_ptr ; diff --git a/src/commands/conditions.cc b/src/commands/conditions.cc new file mode 100644 index 0000000..3e11f0f --- /dev/null +++ b/src/commands/conditions.cc @@ -0,0 +1,58 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#include "conditions.h" +#include "Zypper.h" + +#include +#include +#include + +int NeedsRootCondition::check(std::string &err) +{ + if ( geteuid() != 0 && !Zypper::instance().globalOpts().changedRoot ) + { + err = _("Root privileges are required to run this command."); + return ZYPPER_EXIT_ERR_PRIVILEGES; + } + return ZYPPER_EXIT_OK; +} + +int NeedsWritableRoot::check(std::string &err_r) +{ + Zypper &zypper = Zypper::instance(); + const GlobalOptions &gopts = zypper.globalOpts(); + + if ( zypper.cOpts().count("dry-run") ) + return ZYPPER_EXIT_OK; + + struct statfs fsinfo; + memset( &fsinfo, 0, sizeof(struct statfs) ); + + int errCode = 0; + do { + errCode = statfs( gopts.root_dir.c_str(), &fsinfo ); + } while ( errCode == -1 && errno == EINTR ); + + if ( !errCode ) { + if ( fsinfo.f_flags & ST_RDONLY ) { + + bool isTransactionalServer = ( fsinfo.f_type == BTRFS_SUPER_MAGIC && PathInfo( "/usr/sbin/transactional-update" ).isFile() ); + + if ( isTransactionalServer && !gopts.changedRoot ) { + err_r = _("This is a transactional-server, please use transactional-update to update or modify the system."); + } else { + err_r = _("The target filesystem is mounted as read-only. Please make sure the target filesystem is writeable."); + } + + ERR << err_r << endl; + return ZYPPER_EXIT_ERR_PRIVILEGES; + } + } else { + WAR << "Checking if " << gopts.root_dir << " is mounted read only failed with errno : " << errno << std::endl; + } + return ZYPPER_EXIT_OK; +} diff --git a/src/commands/conditions.h b/src/commands/conditions.h new file mode 100644 index 0000000..d4a1e77 --- /dev/null +++ b/src/commands/conditions.h @@ -0,0 +1,26 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#ifndef ZYPPER_COMMANDS_CONDITIONS_H_INCLUDED +#define ZYPPER_COMMANDS_CONDITIONS_H_INCLUDED + +#include "basecommand.h" + +class NeedsRootCondition : public BaseCommandCondition +{ +public: + // BaseCommandCondition interface + int check(std::string &err) override; +}; + +class NeedsWritableRoot : public BaseCommandCondition +{ +public: + // BaseCommandCondition interface + int check(std::string &err_r) override; +}; + +#endif diff --git a/src/commands/locks.h b/src/commands/locks.h index 1aa8349..7e921ee 100644 --- a/src/commands/locks.h +++ b/src/commands/locks.h @@ -4,5 +4,6 @@ #include "locks/add.h" #include "locks/remove.h" #include "locks/list.h" +#include "locks/clean.h" #endif diff --git a/src/commands/locks/add.cc b/src/commands/locks/add.cc index e69de29..84e8315 100644 --- a/src/commands/locks/add.cc +++ b/src/commands/locks/add.cc @@ -0,0 +1,120 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#include "add.h" + +#include + +#include +#include +#include + +#include "utils/flags/flagtypes.h" + +#include "Zypper.h" +#include "repos.h" +#include "utils/messages.h" +#include "commands/conditions.h" + +using namespace zypp; + +AddLocksCmd::AddLocksCmd( const std::vector &commandAliases_r ) : + ZypperBaseCommand ( + commandAliases_r, + // translators: command synopsis; do not translate the command 'name (abbreviations)' or '-option' names + _("addlock (al) [OPTIONS] ..."), + // translators: command summary + _("Add a package lock."), + // translators: command description + _("Add a package lock. Specify packages to lock by exact name or by a glob pattern using '*' and '?' wildcard characters."), + DisableAll ) +{ } + +ZyppFlags::CommandGroup AddLocksCmd::cmdOptions() const +{ + auto that = const_cast(this); + return {{ + { "type", 't', ZyppFlags::RequiredArgument, ZyppFlags::KindSetType ( &that->_kinds ) , str::Format(_("Type of package (%1%).") ) % "package, patch, pattern, product" }, + { "repo", 'r', ZyppFlags::RequiredArgument | ZyppFlags::Repeatable, ZyppFlags::StringVectorType ( &that->_repos, "ALIAS|#|URI" ), _("Restrict the lock to the specified repository.")}, + { "catalog", 'c', ZyppFlags::RequiredArgument | ZyppFlags::Repeatable | ZyppFlags::Hidden, ZyppFlags::StringVectorType ( &that->_repos, "ALIAS|#|URI"), "Alias for --repo" } + }}; +} + +void AddLocksCmd::doReset() +{ + _kinds.clear(); + _repos.clear(); +} + +int AddLocksCmd::execute(Zypper &zypp_r, const std::vector &positionalArgs_r) +{ + // too few arguments + if ( positionalArgs_r.empty() ) + { + report_required_arg_missing( zypp_r.out(), help() ); + return ZYPPER_EXIT_ERR_INVALID_ARGS; + } + + try + { + Locks & locks = Locks::instance(); + locks.read(Pathname::assertprefix + (zypp_r.globalOpts().root_dir, ZConfig::instance().locksFile())); + Locks::size_type start = locks.size(); + for_(it,positionalArgs_r.begin(),positionalArgs_r.end()) + { + PoolQuery q; + if ( _kinds.empty() ) // derive it from the name + { + sat::Solvable::SplitIdent split( *it ); + q.addAttribute( sat::SolvAttr::name, split.name().asString() ); + q.addKind( split.kind() ); + } + else + { + q.addAttribute(sat::SolvAttr::name, *it); + for_(itk, _kinds.begin(), _kinds.end()) { + q.addKind(*itk); + } + } + q.setMatchGlob(); + parsed_opts::const_iterator itr; + //TODO rug compatibility for more arguments with version restrict + for_(it_repo, _repos.begin(), _repos.end()) + { + RepoInfo info; + if( match_repo( zypp_r, *it_repo, &info)) + q.addRepo(info.alias()); + else //TODO some error handling + WAR << "unknown repository" << *it_repo << endl; + } + q.setCaseSensitive(); + + locks.addLock(q); + } + locks.save(Pathname::assertprefix + (zypp_r.globalOpts().root_dir, ZConfig::instance().locksFile())); + if ( start != Locks::instance().size() ) + zypp_r.out().info(PL_( + "Specified lock has been successfully added.", + "Specified locks have been successfully added.", + Locks::instance().size() - start)); + } + catch(const Exception & e) + { + ZYPP_CAUGHT(e); + zypp_r.out().error(e, _("Problem adding the package lock:")); + return ZYPPER_EXIT_ERR_ZYPP; + } + return ZYPPER_EXIT_OK; +} + +std::vector AddLocksCmd::conditions() const +{ + return { + std::make_shared() + }; +} diff --git a/src/commands/locks/add.h b/src/commands/locks/add.h index e69de29..e9cb7f1 100644 --- a/src/commands/locks/add.h +++ b/src/commands/locks/add.h @@ -0,0 +1,35 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#ifndef ZYPPER_COMMANDS_LOCKS_ADD_H_INCLUDED +#define ZYPPER_COMMANDS_LOCKS_ADD_H_INCLUDED + +#include "commands/basecommand.h" +#include "utils/flags/zyppflags.h" + +#include +#include + +class AddLocksCmd : public ZypperBaseCommand +{ +public: + AddLocksCmd( const std::vector &commandAliases_r ); + +protected: + // ZypperBaseCommand interface + zypp::ZyppFlags::CommandGroup cmdOptions() const override; + void doReset() override; + int execute(Zypper &zypp_r, const std::vector &positionalArgs_r) override; + std::vector conditions() const override; + +private: + std::set _kinds; + std::vector _repos; +}; + + + +#endif diff --git a/src/commands/locks/clean.cc b/src/commands/locks/clean.cc new file mode 100644 index 0000000..9d78fab --- /dev/null +++ b/src/commands/locks/clean.cc @@ -0,0 +1,74 @@ +#include "clean.h" + +#include + +#include "main.h" +#include "Zypper.h" +#include "commands/conditions.h" +#include "utils/flags/flagtypes.h" +#include "utils/messages.h" + +using namespace zypp; + +CleanLocksCmd::CleanLocksCmd(const std::vector &commandAliases_r) : + ZypperBaseCommand ( + commandAliases_r, + _("cleanlocks (cl)"), + // translators: command summary + _("Remove useless locks."), + std::string() + ) +{ } + +std::vector CleanLocksCmd::conditions() const +{ + return { + std::make_shared() + }; +} + +ZyppFlags::CommandGroup CleanLocksCmd::cmdOptions() const +{ + auto that = const_cast(this); + return {{ + {"only-duplicates", 'd', ZyppFlags::NoArgument, ZyppFlags::BoolType(&that->_onlyDuplicates, ZyppFlags::StoreTrue, _onlyDuplicates), + // translators: -d, --only-duplicates + _("Clean only duplicate locks.")}, + {"only-empty", 'e', ZyppFlags::NoArgument, ZyppFlags::BoolType(&that->_onlyEmpty, ZyppFlags::StoreTrue, _onlyEmpty), + // translators: -e, --only-empty + _("Clean only locks which doesn't lock anything.") }, + }}; +} + +void CleanLocksCmd::doReset() +{ + _onlyDuplicates = false; + _onlyEmpty = false; +} + +int CleanLocksCmd::execute(Zypper &zypp_r, const std::vector &positionalArgs_r) +{ + if ( !positionalArgs_r.empty() ) { + report_too_many_arguments( help() ); + return ZYPPER_EXIT_ERR_INVALID_ARGS; + } + + Locks::instance().read(); + Locks::size_type start = Locks::instance().size(); + if ( !_onlyDuplicates ) + Locks::instance().removeEmpty(); + if ( !_onlyEmpty ) + Locks::instance().removeDuplicates(); + + Locks::instance().save(); + + Locks::size_type diff = start - Locks::instance().size(); + zypp_r.out().info( str::form( PL_("Removed %lu lock.","Removed %lu locks.", diff), (long unsigned)diff ) ); + + return ZYPPER_EXIT_OK; +} + +std::string CleanLocksCmd::description() const +{ + return summary(); +} diff --git a/src/commands/locks/clean.h b/src/commands/locks/clean.h new file mode 100644 index 0000000..d39b709 --- /dev/null +++ b/src/commands/locks/clean.h @@ -0,0 +1,36 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#ifndef ZYPPER_COMMANDS_LOCKS_CLEAN_H_INCLUDED +#define ZYPPER_COMMANDS_LOCKS_CLEAN_H_INCLUDED + +#include "commands/basecommand.h" +#include "utils/flags/zyppflags.h" + +#include +#include + +class CleanLocksCmd : public ZypperBaseCommand +{ +public: + CleanLocksCmd( const std::vector &commandAliases_r ); + + // ZypperBaseCommand interface + std::string description() const override; + +protected: + std::vector conditions() const override; + zypp::ZyppFlags::CommandGroup cmdOptions() const override; + void doReset() override; + int execute(Zypper &zypp, const std::vector &positionalArgs) override; +private: + bool _onlyDuplicates = false; + bool _onlyEmpty = false; +}; + + + +#endif diff --git a/src/commands/locks/list.cc b/src/commands/locks/list.cc index 4458919..1cc72d9 100644 --- a/src/commands/locks/list.cc +++ b/src/commands/locks/list.cc @@ -1,3 +1,9 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ #include "list.h" #include @@ -11,7 +17,6 @@ #include "main.h" #include "Table.h" #include "utils/misc.h" -#include "locks.h" #include "repos.h" @@ -214,32 +219,27 @@ private: }; } -std::list ListLocksCmd::command() const -{ - return { "locks", "ll", "lock-list" }; -} - -std::string ListLocksCmd::summary() const -{ - return _("List current package locks."); -} - -std::string ListLocksCmd::synopsis() const -{ - // translators: command synopsis; do not translate lowercase words - return _("locks (ll) [OPTIONS]"); -} +ListLocksCmd::ListLocksCmd(const std::vector &commandAliases_r) : + ZypperBaseCommand ( + commandAliases_r, + // translators: command synopsis; do not translate the command 'name (abbreviations)' or '-option' names + _("locks (ll) [OPTIONS]"), + _("List current package locks.") + ) +{} std::string ListLocksCmd::description() const { return summary(); } -LoadSystemFlags ListLocksCmd::needSystemSetup() const + +int ListLocksCmd::systemSetup(Zypper &zypp_r) { + SetupSystemFlags flags = DisableAll; if ( _matches || _solvables ) - return LoadSystemFlags(); - return NO_POOL; + flags.setFlag( DefaultSetup ); + return defaultSystemSetup( zypp_r, flags ); } void ListLocksCmd::doReset() @@ -248,14 +248,14 @@ void ListLocksCmd::doReset() _solvables = false; } -std::vector ListLocksCmd::cmdOptions() const +ZyppFlags::CommandGroup ListLocksCmd::cmdOptions() const { - return { + return {{ { { "matches", 'm', ZyppFlags::NoArgument, ZyppFlags::BoolType( const_cast(&_matches), ZyppFlags::StoreTrue, _matches), _("Show the number of resolvables matched by each lock.") }, { "solvables", 's', ZyppFlags::NoArgument, ZyppFlags::BoolType( const_cast(&_solvables), ZyppFlags::StoreTrue, _solvables), _("List the resolvables matched by each lock.")} } - }; + }}; } int ListLocksCmd::execute(Zypper &zypper, const std::vector &positionalArgs) diff --git a/src/commands/locks/list.h b/src/commands/locks/list.h index 35aed36..eb02769 100644 --- a/src/commands/locks/list.h +++ b/src/commands/locks/list.h @@ -1,3 +1,9 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ #ifndef ZYPPER_COMMANDS_LOCKS_LIST_H_INCLUDED #define ZYPPER_COMMANDS_LOCKS_LIST_H_INCLUDED @@ -6,18 +12,17 @@ class ListLocksCmd : public ZypperBaseCommand { - // ZypperBaseCommand interface public: - std::list command() const override; - std::string summary() const override; - std::string synopsis() const override; + ListLocksCmd( const std::vector &commandAliases_r ); + + // ZypperBaseCommand interface std::string description() const override; - LoadSystemFlags needSystemSetup() const override; protected: int execute(Zypper &zypper, const std::vector &positionalArgs) override; - std::vector cmdOptions() const override; + zypp::ZyppFlags::CommandGroup cmdOptions() const override; void doReset() override; + int systemSetup(Zypper &zypp_r) override; private: bool _matches = false; diff --git a/src/commands/locks/remove.cc b/src/commands/locks/remove.cc index e69de29..a93faa9 100644 --- a/src/commands/locks/remove.cc +++ b/src/commands/locks/remove.cc @@ -0,0 +1,139 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#include "remove.h" + +#include + +#include +#include + +#include "main.h" +#include "utils/messages.h" +#include "repos.h" +#include "Zypper.h" +#include "utils/flags/flagtypes.h" +#include "commands/conditions.h" + +using namespace zypp; + +RemoveLocksCmd::RemoveLocksCmd(const std::vector &commandAliases_r) + : ZypperBaseCommand( + commandAliases_r, + _("removelock (rl) [OPTIONS] ..."), + _("Remove a package lock."), + // translators: command description; %1% is acoomand like 'zypper locks' + str::Format(_("Remove a package lock. Specify the lock to remove by its number obtained with '%1%' or by package name.") ) % "zypper locks", + DisableAll + ) +{ } + +std::vector RemoveLocksCmd::conditions() const +{ + return { + std::make_shared() + }; +} + +ZyppFlags::CommandGroup RemoveLocksCmd::cmdOptions() const +{ + auto that = const_cast(this); + return {{ + { "type", 't', ZyppFlags::RequiredArgument, ZyppFlags::KindSetType ( &that->_kinds ) , str::Format(_("Type of package (%1%).") ) % "package, patch, pattern, product" }, + { "repo", 'r', ZyppFlags::RequiredArgument | ZyppFlags::Repeatable, ZyppFlags::StringVectorType ( &that->_repos, "ALIAS|#|URI" ), _("Remove only locks with specified repository.") }, + { "catalog", 'c', ZyppFlags::RequiredArgument | ZyppFlags::Repeatable | ZyppFlags::Hidden, ZyppFlags::StringVectorType ( &that->_repos, "ALIAS|#|URI"), "Alias for --repo" } + }}; +} + +void RemoveLocksCmd::doReset() +{ + _kinds.clear(); + _repos.clear(); +} + +int RemoveLocksCmd::execute(Zypper &zypp_r, const std::vector &positionalArgs_r) +{ + // too few arguments + if ( positionalArgs_r.empty() ) + { + report_required_arg_missing( zypp_r.out(), help() ); + return ZYPPER_EXIT_ERR_INVALID_ARGS; + } + + try + { + Locks & locks = Locks::instance(); + locks.read(Pathname::assertprefix + (zypp_r.globalOpts().root_dir, ZConfig::instance().locksFile())); + Locks::size_type start = locks.size(); + for_( args_it, positionalArgs_r.begin(), positionalArgs_r.end() ) + { + Locks::const_iterator it = locks.begin(); + Locks::LockList::size_type i = 0; + safe_lexical_cast(*args_it, i); + if (i > 0 && i <= locks.size()) + { + advance(it, i-1); + locks.removeLock(*it); + + zypp_r.out().info(_("Specified lock has been successfully removed.")); + } + else //package name + { + //TODO fill query in one method to have consistent add/remove + //TODO what to do with repo and _kinds? + PoolQuery q; + if ( _kinds.empty() ) // derive it from the name + { + // derive kind from the name: (rl should also support -t) + sat::Solvable::SplitIdent split( *args_it ); + q.addAttribute( sat::SolvAttr::name, split.name().asString() ); + q.addKind( split.kind() ); + } + else + { + q.addAttribute(sat::SolvAttr::name, *args_it); + for_(itk, _kinds.begin(), _kinds.end()) { + q.addKind(*itk); + } + } + q.setMatchGlob(); + parsed_opts::const_iterator itr; + for_(it_repo, _repos.begin(), _repos.end()) + { + RepoInfo info; + if( match_repo( zypp_r, *it_repo, &info)) + q.addRepo(info.alias()); + else //TODO some error handling + WAR << "unknown repository" << *it_repo << endl; + } + q.setCaseSensitive(); + + locks.removeLock(q); + } + } + + locks.save(Pathname::assertprefix + (zypp_r.globalOpts().root_dir, ZConfig::instance().locksFile())); + + // nothing removed + if (start == locks.size()) + zypp_r.out().info(_("No lock has been removed.")); + //removed something + else + zypp_r.out().info(str::form(PL_( + "%zu lock has been successfully removed.", + "%zu locks have been successfully removed.", + start - locks.size()), start - locks.size())); + } + catch(const Exception & e) + { + ZYPP_CAUGHT(e); + zypp_r.out().error(e, _("Problem removing the package lock:")); + return ZYPPER_EXIT_ERR_ZYPP; + } + return ZYPPER_EXIT_OK; +} diff --git a/src/commands/locks/remove.h b/src/commands/locks/remove.h index e69de29..3b8c12a 100644 --- a/src/commands/locks/remove.h +++ b/src/commands/locks/remove.h @@ -0,0 +1,35 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#ifndef ZYPPER_COMMANDS_LOCKS_REMOVE_H_INCLUDED +#define ZYPPER_COMMANDS_LOCKS_REMOVE_H_INCLUDED + +#include "commands/basecommand.h" +#include "utils/flags/zyppflags.h" + +#include +#include + +class RemoveLocksCmd : public ZypperBaseCommand +{ +public: + RemoveLocksCmd( const std::vector &commandAliases_r ); + + // ZypperBaseCommand interface +protected: + std::vector conditions() const override; + zypp::ZyppFlags::CommandGroup cmdOptions() const override; + void doReset() override; + int execute(Zypper &zypp_r, const std::vector &positionalArgs_r) override; + +private: + std::set _kinds; + std::vector _repos; +}; + + + +#endif diff --git a/src/commands/ps.cc b/src/commands/ps.cc new file mode 100644 index 0000000..7d1d484 --- /dev/null +++ b/src/commands/ps.cc @@ -0,0 +1,204 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#include "ps.h" + +#include + +#include +#include +#include + +#include "Zypper.h" +#include "Table.h" +#include "utils/messages.h" +#include "utils/flags/flagtypes.h" + +using namespace zypp; + +PSCommand::PSCommand(const std::vector &commandAliases_r) : + ZypperBaseCommand ( + commandAliases_r, + // translators: command synopsis; do not translate the command 'name (abbreviations)' or '-option' names + _("ps [OPTIONS]"), + // translators: command description + _("List running processes which might still use files and libraries deleted by recent upgrades."), + std::string(), + DisableAll + ) +{ } + +std::string PSCommand::description() const +{ + return summary(); +} + +ZyppFlags::CommandGroup PSCommand::cmdOptions() const +{ + auto that = const_cast(this); + return {{ + { "short", 's', ZyppFlags::NoArgument | ZyppFlags::Repeatable, ZyppFlags::CounterType( &that->_shortness, _shortness, 3) + // translators: -s, --short + , _("Create a short table not showing the deleted files. Given twice, show only processes which are associated with a system service. Given three times, list the associated system service names only.") + }, { "print", '\0', ZyppFlags::RequiredArgument, ZyppFlags::StringType(&that->_format, boost::optional(), "FORMAT") + // translators: --print + , _("For each associated system service print on the standard output, followed by a newline. Any '%s' directive in is replaced by the system service name.") + }, { "debugFile", 'd', ZyppFlags::RequiredArgument, ZyppFlags::StringType(&that->_debugFile, boost::optional(), "PATH") + // translators: -d, --debugFile + , _("Write debug output to file .") + } + }}; +} + +void PSCommand::doReset() +{ + _shortness = 0; + _debugFile.clear(); + _format.clear(); +} + +inline void loadData( CheckAccessDeleted & checker_r ) +{ + try + { + checker_r.check(); + } + catch ( const Exception & ex ) + { + throw( Out::Error( ZYPPER_EXIT_ERR_ZYPP, _("Check failed:"), ex ) ); + } +} + +void PSCommand::printServiceNamesOnly() +{ + CheckAccessDeleted checker( false ); // wait for explicit call to check() + loadData( checker ); + + std::set services; + for ( const auto & procInfo : checker ) + { + std::string service( procInfo.service() ); + if ( ! service.empty() ) + services.insert( std::move(service) ); + } + + const std::string & format( _format ); + if ( format.empty() || format == "%s" ) + { + for ( const auto & service : services ) + { cout << service << endl; } + } + else + { + for ( const auto & service : services ) + { cout << str::gsub( format, "%s", service ) << endl; } + } +} + +/** + * fate #300763 + * Used by 'zypper ps' to show running processes that use + * libraries or other files that have been removed since their execution. + * This is particularly useful after 'zypper remove' or 'zypper update'. + */ +int PSCommand::execute( Zypper &zypp, const std::vector &positionalArgs ) +{ + if ( !positionalArgs.empty() ) + { + report_too_many_arguments( help() ); + return ZYPPER_EXIT_ERR_INVALID_ARGS; + } + + // implies -sss + if ( !_format.empty() ) + _shortness = 3; + + if ( printServiceNamesOnlyEnabled() ) { + // non table output of service names only + printServiceNamesOnly(); + return ZYPPER_EXIT_OK; + } + + // Here: Table output + zypp.out().info(_("Checking for running processes using deleted libraries..."), Out::HIGH ); + CheckAccessDeleted checker( false ); // wait for explicit call to check() + + if(debugEnabled()) + checker.setDebugOutputFile(_debugFile); + + loadData( checker ); + + Table t; + bool tableWithFiles = tableWithFilesEnabled(); + bool tableWithNonServiceProcs = tableWithNonServiceProcsEnabled(); + t.allowAbbrev(6); + { + TableHeader th; + // process ID + th << _("PID") + // parent process ID + << _("PPID") + // process user ID + << _("UID") + // process login name + << _("User") + // process command name + << _("Command") + // "/etc/init.d/ script that might be used to restart the command (guessed) + << _("Service"); + if ( tableWithFiles ) + { + // "list of deleted files or libraries accessed" + th << _("Files"); + } + t << std::move(th); + } + + for ( const auto & procInfo : checker ) + { + std::string service( procInfo.service() ); + if ( ! tableWithNonServiceProcs && service.empty() ) + continue; + + TableRow tr; + tr << procInfo.pid << procInfo.ppid << procInfo.puid << procInfo.login << procInfo.command << std::move(service); + + if ( tableWithFiles ) + { + std::vector::const_iterator fit = procInfo.files.begin(); + tr << (fit != procInfo.files.end() ? *fit : ""); + t << std::move(tr); + + for ( ++fit; fit != procInfo.files.end(); ++fit ) + { t << ( TableRow() << "" << "" << "" << "" << "" << "" << *fit ); } + } + else + { + t << std::move(tr); + } + } + + if ( t.empty() ) + { + zypp.out().info(_("No processes using deleted files found.") ); + } + else + { + zypp.out().info(_("The following running processes use deleted files:") ); + cout << endl; + cout << t << endl; + zypp.out().info(_("You may wish to restart these processes.") ); + zypp.out().info( str::form( _("See '%s' for information about the meaning of values in the above table."), + "man zypper" ) ); + } + + if ( geteuid() != 0 ) + { + zypp.out().info(""); + zypp.out().info(_("Note: Not running as root you are limited to searching for files you have permission to examine with the system stat(2) function. The result might be incomplete.")); + } + return ZYPPER_EXIT_OK; +} diff --git a/src/commands/ps.h b/src/commands/ps.h new file mode 100644 index 0000000..cbfeccc --- /dev/null +++ b/src/commands/ps.h @@ -0,0 +1,39 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#ifndef ZYPPER_COMMANDS_PS_INCLUDED +#define ZYPPER_COMMANDS_PS_INCLUDED + +#include "commands/basecommand.h" +#include "utils/flags/zyppflags.h" + +class PSCommand : public ZypperBaseCommand +{ +public: + PSCommand( const std::vector &commandAliases_r ); + + // ZypperBaseCommand interface + std::string description() const override; + +protected: + zypp::ZyppFlags::CommandGroup cmdOptions() const override; + void doReset() override; + int execute(Zypper &zypp, const std::vector &positionalArgs) override; + + void printServiceNamesOnly(); + bool tableWithFilesEnabled() const { return _shortness < 1; } + bool tableWithNonServiceProcsEnabled() const { return _shortness < 2; } + bool printServiceNamesOnlyEnabled() const { return _shortness >= 3; } + bool debugEnabled() const {return (!_debugFile.empty());} + +private: + int _shortness = 0; + std::string _format; + std::string _debugFile; +}; + + +#endif diff --git a/src/commands/repos.h b/src/commands/repos.h new file mode 100644 index 0000000..26d62c1 --- /dev/null +++ b/src/commands/repos.h @@ -0,0 +1,12 @@ +#ifndef ZYPPER_COMMANDS_REPOS_H_INCLUDED +#define ZYPPER_COMMANDS_REPOS_H_INCLUDED + +#include "repos/list.h" +#include "repos/add.h" +#include "repos/remove.h" +#include "repos/rename.h" +#include "repos/modify.h" +#include "repos/refresh.h" +#include "repos/clean.h" + +#endif diff --git a/src/commands/repos/add.cc b/src/commands/repos/add.cc new file mode 100644 index 0000000..0e7bc56 --- /dev/null +++ b/src/commands/repos/add.cc @@ -0,0 +1,138 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#include "add.h" +#include "repos.h" + +#include "commands/conditions.h" +#include "utils/flags/flagtypes.h" +#include "utils/messages.h" +#include "utils/misc.h" +#include "Zypper.h" + +#include + +using namespace zypp; + +AddRepoCmd::AddRepoCmd(const std::vector &commandAliases_r) : + ZypperBaseCommand( + commandAliases_r, + std::vector{ _("addrepo (ar) [OPTIONS] "), _("addrepo (ar) [OPTIONS] ") }, + _("Add a new repository."), + _("Add a repository to the system. The repository can be specified by its URI or can be read from specified .repo file (even remote)."), + ResetRepoManager ) +{ } + +std::vector AddRepoCmd::conditions() const +{ + return { + std::make_shared() + }; +} + +zypp::ZyppFlags::CommandGroup AddRepoCmd::cmdOptions() const +{ + auto that = const_cast(this); + return {{ + { "repo", 'r', ZyppFlags::RequiredArgument, ZyppFlags::StringType( &that->_repoFile, boost::optional(), ARG_FILE_repo), _("Just another means to specify a .repo file to read.") }, + { "check", 'c', ZyppFlags::NoArgument, ZyppFlags::BoolType( &that->_enableCheck, ZyppFlags::StoreTrue ), _("Probe URI.") }, + { "no-check", 'C', ZyppFlags::NoArgument, ZyppFlags::BoolType( &that->_disableCheck, ZyppFlags::StoreTrue ), _("Don't probe URI, probe later during refresh.") }, + { "type", 't', + ZyppFlags::RequiredArgument | ZyppFlags::Deprecated, + ZyppFlags::WarnOptionVal( Zypper::instance().out(), legacyCLIStr( "type", "", LegacyCLIMsgType::Ignored ), Out::NORMAL, boost::optional() ), + _("The repository type is always autodetected. This option is ignored.") } + }}; +} + +void AddRepoCmd::doReset() +{ + _repoFile.clear(); + _enableCheck = false; + _disableCheck = false; +} + +int AddRepoCmd::execute(Zypper &zypp_r, const std::vector &positionalArgs_r) +{ + + // too many arguments + if ( positionalArgs_r.size() > 2 ) + { + report_too_many_arguments( zypp_r.out(), help() ); + return ( ZYPPER_EXIT_ERR_INVALID_ARGS ); + } + + if ( _enableCheck && _disableCheck ) + { + zypp_r.out().warning(str::form( + _("Cannot use %s together with %s. Using the %s setting."), + "--check", "--no-check", "zypp.conf") + ,Out::QUIET ); + } + + try + { + // add repository specified in .repo file + if ( ! _repoFile.empty() ) + { + add_repo_from_file( zypp_r, _repoFile, _commonProperties, _repoProperties, _disableCheck ); + return zypp_r.exitCode(); + } + + switch ( positionalArgs_r.size() ) + { + // display help message if insufficient info was given + case 0: + report_too_few_arguments( zypp_r.out(), help() ); + return( ZYPPER_EXIT_ERR_INVALID_ARGS ); + case 1: + if( !isRepoFile( positionalArgs_r[0] ) ) + { + zypp_r.out().error(_("If only one argument is used, it must be a URI pointing to a .repo file.")); + ERR << "Not a repo file." << endl; + zypp_r.out().info( help() ); + return ( ZYPPER_EXIT_ERR_INVALID_ARGS ); + } + else + { + add_repo_from_file( zypp_r, positionalArgs_r[0], _commonProperties, _repoProperties, _disableCheck ); + break; + } + case 2: + Url url; + if ( positionalArgs_r[0].find("obs") == 0 ) + url = make_obs_url( positionalArgs_r[0], zypp_r.config().obs_baseUrl, zypp_r.config().obs_platform ); + else + url = make_url( positionalArgs_r[0] ); + if ( !url.isValid() ) + { + return (ZYPPER_EXIT_ERR_INVALID_ARGS); + } + + if ( _enableCheck ) + zypp_r.globalOptsNoConst().rm_options.probe = true; + else if ( _disableCheck ) + zypp_r.globalOptsNoConst().rm_options.probe = false; + + // load gpg keys + int code = defaultSystemSetup( zypp_r, InitTarget ); + if ( code != ZYPPER_EXIT_OK ) + return code; + + add_repo_by_url( zypp_r, url, positionalArgs_r[1]/*alias*/, _commonProperties, _repoProperties, _disableCheck ); + } + } + catch ( const repo::RepoUnknownTypeException & e ) + { + ZYPP_CAUGHT( e ); + zypp_r.out().error( e, _("Specified type is not a valid repository type:"), + str::form( _("See '%s' or '%s' to get a list of known repository types."), + "zypper help addrepo", "man zypper" ) ); + return ZYPPER_EXIT_ERR_INVALID_ARGS; + } + + + return zypp_r.exitCode();; +} diff --git a/src/commands/repos/add.h b/src/commands/repos/add.h new file mode 100644 index 0000000..e29e886 --- /dev/null +++ b/src/commands/repos/add.h @@ -0,0 +1,37 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#ifndef ZYPPER_COMMANDS_REPOS_ADD_H_INCLUDED +#define ZYPPER_COMMANDS_REPOS_ADD_H_INCLUDED + +#include "commands/basecommand.h" +#include "commands/reposerviceoptionsets.h" + +#include + +#include + +class AddRepoCmd : public ZypperBaseCommand +{ +public: + AddRepoCmd( const std::vector &commandAliases_r ); + + // ZypperBaseCommand interface +protected: + std::vector conditions() const override; + zypp::ZyppFlags::CommandGroup cmdOptions() const override; + void doReset() override; + int execute(Zypper &zypp_r, const std::vector &positionalArgs_r) override; + +private: + RepoProperties _repoProperties{*this}; + RepoServiceCommonOptions _commonProperties{OptCommandCtx::RepoContext, *this}; + std::string _repoFile; + bool _enableCheck = false; + bool _disableCheck = false; +}; + +#endif diff --git a/src/commands/repos/clean.cc b/src/commands/repos/clean.cc new file mode 100644 index 0000000..4985184 --- /dev/null +++ b/src/commands/repos/clean.cc @@ -0,0 +1,74 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#include "clean.h" + +#include "commands/conditions.h" +#include "utils/flags/flagtypes.h" +#include "Zypper.h" + +CleanRepoCmd::CleanRepoCmd( const std::vector &commandAliases_r ): + ZypperBaseCommand( + commandAliases_r, + _("clean (cc) [ALIAS|#|URI] ..."), + _("Clean local caches."), + _("Clean local caches."), + ResetRepoManager ) +{ } + +std::vector CleanRepoCmd::conditions() const +{ + return { + std::make_shared() + }; +} + +zypp::ZyppFlags::CommandGroup CleanRepoCmd::cmdOptions() const +{ + auto that = const_cast(this); + return {{ + { + "repo", 'r', ZyppFlags::RequiredArgument | ZyppFlags::Repeatable, + ZyppFlags::StringVectorType( &that->_repos, ARG_REOSITORY), + // translators: -r, --repo + _("Clean only specified repositories.") + },{ + "metadata", 'm', ZyppFlags::NoArgument, + ZyppFlags::BitFieldType ( that->_flags, CleanRepoBits::CleanMetaData), + // translators: -m, --metadata + _("Clean metadata cache.") + + },{ + "raw-metadata", 'M', ZyppFlags::NoArgument, + ZyppFlags::BitFieldType ( that->_flags, CleanRepoBits::CleanRawMetaData), + // translators: -M, --raw-metadata + _("Clean raw metadata cache.") + },{ + "all", 'a', ZyppFlags::NoArgument, + ZyppFlags::BitFieldType ( that->_flags, CleanRepoBits::CleanAll), + // translators: -a, --all + _("Clean both metadata and package caches.") + } + }}; +} + +void CleanRepoCmd::doReset() +{ + _repos.clear(); + _flags = CleanRepoBits::Default; +} + +int CleanRepoCmd::execute( Zypper &zypp_r, const std::vector &positionalArgs_r ) +{ + // get the list of repos specified on the command line ... + std::vector specifiedRepos = _repos; + for ( const std::string &repoFromCLI : positionalArgs_r ) + specifiedRepos.push_back(repoFromCLI); + + clean_repos( zypp_r, specifiedRepos, _flags ); + + return zypp_r.exitCode(); +} diff --git a/src/commands/repos/clean.h b/src/commands/repos/clean.h new file mode 100644 index 0000000..3ef0c64 --- /dev/null +++ b/src/commands/repos/clean.h @@ -0,0 +1,33 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#ifndef ZYPPER_COMMANDS_REPOS_CLEAN_H_INCLUDED +#define ZYPPER_COMMANDS_REPOS_CLEAN_H_INCLUDED + +#include "commands/basecommand.h" +#include "repos.h" + +#include +#include + +class CleanRepoCmd : public ZypperBaseCommand +{ +public: + CleanRepoCmd( const std::vector &commandAliases_r ); + + // ZypperBaseCommand interface +protected: + std::vector conditions() const override; + zypp::ZyppFlags::CommandGroup cmdOptions() const override; + void doReset() override; + int execute(Zypper &zypp_r, const std::vector &positionalArgs_r) override; + +private: + std::vector _repos; + CleanRepoFlags _flags; +}; + +#endif diff --git a/src/commands/repos/list.cc b/src/commands/repos/list.cc new file mode 100644 index 0000000..0f19374 --- /dev/null +++ b/src/commands/repos/list.cc @@ -0,0 +1,348 @@ +#include "list.h" +#include "Zypper.h" +#include "repos.h" +#include "utils/messages.h" +#include "utils/flags/flagtypes.h" + +#include + +#include + +using namespace zypp; + +namespace { + +void print_repos_to( const std::list & repos, std::ostream & out ) +{ + for_( it, repos.begin(), repos.end() ) + it->dumpAsIniOn( out ) << endl; +} + +/** Repo list as xml */ +void print_xml_repo_list( Zypper & zypper, std::list repos ) +{ + cout << "" << endl; + for_( it, repos.begin(), repos.end() ) + it->dumpAsXmlOn( cout ); + cout << "" << endl; +} + +void print_repo_details( Zypper & zypper, std::list & repos ) +{ + bool first = true; + for_( it, repos.begin(), repos.end() ) + { + const RepoInfo & repo( *it ); + + PropertyTable p; + RepoGpgCheckStrings repoGpgCheck( repo ); + + p.add( _("Alias"), repo.alias() ); + p.add( _("Name"), repo.name() ); + p.add( _("URI"), (repo.baseUrlSet() + ? repo.url().asString() + : (repo.mirrorListUrl().asString().empty() + ? "n/a" + : repo.mirrorListUrl().asString())) ); + p.add( _("Enabled"), repoGpgCheck._enabledYN.str() ); + p.add( _("GPG Check"), repoGpgCheck._gpgCheckYN.str() ); + p.add( _("Priority"), repoPriorityNumberAnnotated( repo.priority() ) ); + p.add( _("Autorefresh"), (repo.autorefresh() ? _("On") : _("Off")) ); + p.add( _("Keep Packages"), (repo.keepPackages() ? _("On") : _("Off")) ); + p.add( _("Type"), repo.type().asString() ); + p.add( _("GPG Key URI"), repo.gpgKeyUrl() ); + p.add( _("Path Prefix"), repo.path() ); + p.add( _("Parent Service"), repo.service() ); + p.lst( _("Keywords"), repo.contentKeywords() ); + p.add( _("Repo Info Path"), repo.filepath() ); + p.add( _("MD Cache Path"), repo.metadataPath() ); + + + if ( first ) + first = false; + else + cout << endl; + cout << p; + } +} + +} + +ListReposCmd::ListReposCmd(const std::vector &commandAliases_r) + : ZypperBaseCommand( + commandAliases_r, + _("repos (lr) [OPTIONS] [REPO] ..."), + _("List all defined repositories."), + _("List all defined repositories."), + ResetRepoManager + ) +{ } + +zypp::ZyppFlags::CommandGroup ListReposCmd::cmdOptions() const +{ + auto that = const_cast(this); + return {{ + { "export", 'e', ZyppFlags::RequiredArgument, ZyppFlags::StringType(&that->_exportFile, boost::optional(), "FILE.repo"), + // translators: -e, --export + _("Export all defined repositories as a single local .repo file.") } + }}; +} + +void ListReposCmd::doReset() +{ + _exportFile.clear(); +} + +int ListReposCmd::execute( Zypper &zypp_r, const std::vector &positionalArgs_r ) +{ + checkIfToRefreshPluginServices( zypp_r ); + + RepoManager & manager = zypp_r.repoManager(); + RuntimeData & gData = zypp_r.runtimeData(); + std::list repos; + std::list not_found; + + try + { + if ( positionalArgs_r.empty() ) + repos.insert( repos.end(), manager.repoBegin(), manager.repoEnd() ); + else + { + get_repos( zypp_r, positionalArgs_r.begin(),positionalArgs_r.end(), repos, not_found ); + report_unknown_repos( zypp_r.out(), not_found ); + } + } + catch ( const Exception & e ) + { + ZYPP_CAUGHT( e ); + zypp_r.out().error( e, _("Error reading repositories:") ); + return ( ZYPPER_EXIT_ERR_ZYPP ); + } + + // add the temporary repos specified with the --plus-repo to the list + if ( !gData.temporary_repos.empty() ) + repos.insert( repos.end(), gData.temporary_repos.begin(), gData.temporary_repos.end() ); + + // export to file or stdout in repo file format + /// \todo dedup writing code in list_services + if ( !_exportFile.empty() ) + { + std::string filename_str = _exportFile; + if ( filename_str == "-" ) + { + print_repos_to(repos, cout); + } + else + { + if ( filename_str.rfind(".repo") == std::string::npos ) + filename_str += ".repo"; + + Pathname file( filename_str ); + std::ofstream stream( file.c_str() ); + if ( !stream ) + { + zypp_r.out().error( str::Format(_("Can't open %s for writing.")) % file.asString(), + _("Maybe you do not have write permissions?") ); + return ( ZYPPER_EXIT_ERR_INVALID_ARGS ); + } + else + { + print_repos_to( repos, stream ); + zypp_r.out().info( str::Format(_("Repositories have been successfully exported to %s.")) % file, + Out::QUIET ); + } + } + } + // print repo list as xml + else if ( zypp_r.out().type() == Out::TYPE_XML ) + print_xml_repo_list( zypp_r, repos ); + else if ( !zypp_r.arguments().empty() ) + print_repo_details( zypp_r, repos ); + // print repo list as table + else + printRepoList( zypp_r, repos ); + + if ( !not_found.empty() ) { + return ( ZYPPER_EXIT_ERR_INVALID_ARGS ); + } else if ( repos.empty() ) { + return ( ZYPPER_EXIT_NO_REPOS ); + } + + return ZYPPER_EXIT_OK; +} + +void ListReposCmd::printRepoList( Zypper & zypper, const std::list & repos ) +{ + Table tbl; + bool all = _listOptions._flags.testFlag( RSCommonListOptions::ListRepoShowAll ); + std::string list_cols = zypper.config().repo_list_columns; + + bool showalias = _listOptions._flags.testFlag( RSCommonListOptions::ShowAlias ) + || list_cols.find_first_of("aA") != std::string::npos; + bool showname = _listOptions._flags.testFlag( RSCommonListOptions::ShowName ) + || list_cols.find_first_of("nN") != std::string::npos; + bool showrefresh = _listOptions._flags.testFlag( RSCommonListOptions::ShowRefresh ) + || list_cols.find_first_of("rR") != std::string::npos; + bool showuri = _listOptions._flags.testFlag( RSCommonListOptions::ShowURI ) + || list_cols.find_first_of("uU") != std::string::npos; + bool showprio = _listOptions._flags.testFlag( RSCommonListOptions::ShowPriority ) + || list_cols.find_first_of("pP") != std::string::npos; + bool showservice = _listOptions._flags.testFlag( RSCommonListOptions::ShowWithService ); + bool sort_override = _listOptions._flags.testFlag( RSCommonListOptions::SortByURI ) + || _listOptions._flags.testFlag( RSCommonListOptions::SortByPrio ) + || _listOptions._flags.testFlag( RSCommonListOptions::SortByAlias ) + || _listOptions._flags.testFlag( RSCommonListOptions::SortByName ); + bool show_enabled_only = _listOptions._flags.testFlag( RSCommonListOptions::ShowEnabledOnly ); + + + // header + TableHeader th; + // keep count of columns so that we know which one to sort + // TODO might be worth to improve Table to allow named columns so this can be avoided + unsigned index = 0; + // number of the column to sort by + unsigned sort_index = 0; + + // repo number + th << "#"; + + // alias + if ( all || showalias ) + { + th << _("Alias"); + ++index; + // if (zypper.cOpts().count("sort-by-alias") + // || (list_cols.find("A") != std::string::npos && !sort_override)) + // sort by alias by default + sort_index = index; + } + + // name + if ( all || showname ) + { + th << _("Name"); + ++index; + if ( _listOptions._flags.testFlag( RSCommonListOptions::SortByName ) || ( list_cols.find("N") != std::string::npos && !sort_override ) ) + sort_index = index; + } + + // 'enabled' flag + th << _("Enabled"); + ++index; + + // GPG Check + th << _("GPG Check"); + ++index; + + // 'autorefresh' flag + if ( all || showrefresh ) + { + // translators: 'zypper repos' column - whether autorefresh is enabled + // for the repository + th << _("Refresh"); + ++index; + if ( list_cols.find("R") != std::string::npos && !sort_override ) + sort_index = index; + } + + // priority + if ( all || showprio ) + { + // translators: repository priority (in zypper repos -p or -d) + th << _("Priority"); + ++index; + if ( _listOptions._flags.testFlag( RSCommonListOptions::SortByPrio ) || ( list_cols.find("P") != std::string::npos && !sort_override ) ) + sort_index = Table::UserData; + } + + // type + if ( all ) + { + th << _("Type"); + ++index; + } + + // URI + if ( all || showuri ) + { + th << _("URI"); + ++index; + if ( _listOptions._flags.testFlag( RSCommonListOptions::SortByURI ) || ( list_cols.find("U") != std::string::npos && !sort_override ) ) + sort_index = index; + } + + // service alias + if ( all || showservice ) + { + th << _("Service"); + ++index; + } + + tbl << th; + + // table data + int i = 0; + unsigned nindent = repos.size() > 9 ? repos.size() > 99 ? 3 : 2 : 1; + for_( it, repos.begin(), repos.end() ) + { + ++i; // continuous numbering including skipped ones + RepoInfo repo = *it; + + if ( show_enabled_only && !repo.enabled() ) + continue; + + TableRow tr( index ); + RepoGpgCheckStrings repoGpgCheck( repo ); // color strings for tag/enabled/gpgcheck + + // number + tr << ColorString( repoGpgCheck._tagColor, str::numstring( i, nindent ) ).str(); + // alias + if ( all || showalias ) tr << repo.alias(); + // name + if ( all || showname ) tr << repo.name(); + // enabled? + tr << repoGpgCheck._enabledYN.str(); + // GPG Check + tr << repoGpgCheck._gpgCheckYN.str(); + // autorefresh? + if ( all || showrefresh ) + tr << repoAutorefreshStr( repo ); + // priority + if ( all || showprio ) + // output flush right; use custom sort index as coloring will break lex. sort + ( tr << repoPriorityNumber( repo.priority(), 4 ) ).userData( repo.priority() ); + // type + if ( all ) + tr << repo.type().asString(); + // url + /** + * \todo properly handle multiple baseurls - show "(multiple)" + */ + if ( all || showuri ) + tr << (repo.baseUrlSet() ? repo.url().asString() : (repo.mirrorListUrl().asString().empty() ? "n/a" : repo.mirrorListUrl().asString()) ); + + if ( all || showservice ) + tr << repo.service(); + + tbl << tr; + } + + if ( tbl.empty() ) + { + zypper.out().warning(_("No repositories defined.") ); + zypper.out().info(_("Use the 'zypper addrepo' command to add one or more repositories.") ); + } + else + { + if ( !showprio ) + { + repoPrioSummary( zypper ); + zypper.out().gap(); + } + // sort + tbl.sort( sort_index ); + // print + cout << tbl; + } +} + diff --git a/src/commands/repos/list.h b/src/commands/repos/list.h new file mode 100644 index 0000000..9df8f4c --- /dev/null +++ b/src/commands/repos/list.h @@ -0,0 +1,34 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#ifndef ZYPPER_COMMANDS_REPOS_LIST_H_INCLUDED +#define ZYPPER_COMMANDS_REPOS_LIST_H_INCLUDED + +#include "commands/basecommand.h" +#include "commands/reposerviceoptionsets.h" +#include "utils/flags/zyppflags.h" + +#include +#include + +class ListReposCmd : public ZypperBaseCommand +{ +public: + ListReposCmd( const std::vector &commandAliases_r ); + + // ZypperBaseCommand interface +protected: + zypp::ZyppFlags::CommandGroup cmdOptions() const override; + void doReset() override; + int execute(Zypper &zypp_r, const std::vector &positionalArgs_r) override; + void printRepoList(Zypper &zypper, const std::list &repos); + +private: + std::string _exportFile; + RSCommonListOptions _listOptions{ OptCommandCtx::RepoContext, *this }; +}; + +#endif diff --git a/src/commands/repos/modify.cc b/src/commands/repos/modify.cc new file mode 100644 index 0000000..a7d96c0 --- /dev/null +++ b/src/commands/repos/modify.cc @@ -0,0 +1,112 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#include "modify.h" +#include "repos.h" + +#include "commands/conditions.h" +#include "commands/commandhelpformatter.h" + +#include "utils/messages.h" +#include "utils/flags/flagtypes.h" + +using namespace zypp; + + +ModifyRepoCmd::ModifyRepoCmd(const std::vector &commandAliases_r) : + ZypperBaseCommand ( + commandAliases_r, + { + // translators: command synopsis; do not translate lowercase words + _("modifyrepo (mr) "), + // translators: command synopsis; do not translate lowercase words + str::Format( _("modifyrepo (mr) <%1%>") ) % "--all|--remote|--local|--medium-type" + }, + // translators: command summary + _("Modify specified repository."), + // translators: command description + str::Format( _("Modify properties of repositories specified by alias, number, or URI, or by the '%1%' aggregate options.") ) % "--all, --remote, --local, --medium-type", + ResetRepoManager + ) +{ } + +std::vector ModifyRepoCmd::conditions() const +{ + return { + std::make_shared() + }; +} + +zypp::ZyppFlags::CommandGroup ModifyRepoCmd::cmdOptions() const +{ + auto that = const_cast(this); + return {{ + //some legacy options + {"legacy-refresh", 'r', ZyppFlags::NoArgument | ZyppFlags::Hidden, ZyppFlags::TriBoolType( that->_commonProps._enableAutoRefresh, ZyppFlags::StoreTrue ), "" }, + {"legacy-no-refresh", 'R', ZyppFlags::NoArgument | ZyppFlags::Hidden, ZyppFlags::TriBoolType( that->_commonProps._enableAutoRefresh, ZyppFlags::StoreFalse), "" } + }}; +} + +void ModifyRepoCmd::doReset() +{ } + +int ModifyRepoCmd::execute(Zypper &zypp_r, const std::vector &positionalArgs_r ) +{ + bool aggregate = _selections._all || _selections._local || _selections._remote || _selections._mediumTypes.size(); + + if ( positionalArgs_r.size() < 1 && !aggregate ) + { + report_alias_or_aggregate_required (zypp_r.out(), help() ); + ERR << "No alias argument given." << endl; + return ( ZYPPER_EXIT_ERR_INVALID_ARGS ); + } + + // too many arguments + if ( positionalArgs_r.size() && aggregate ) + { + report_too_many_arguments( help() ); + return ( ZYPPER_EXIT_ERR_INVALID_ARGS ); + } + + if ( aggregate ) + { + modify_repos_by_option( zypp_r, _selections, _commonProps, _repoProps ); + } + else + { + for_( arg,positionalArgs_r.begin(),positionalArgs_r.end() ) + { + RepoInfo r; + if ( match_repo(zypp_r,*arg,&r) ) + { + modify_repo( zypp_r, r.alias(), _commonProps, _repoProps ); + } + else + { + zypp_r.out().error( str::Format(_("Repository %s not found.")) % *arg ); + ERR << "Repo " << *arg << " not found" << endl; + return ( ZYPPER_EXIT_ERR_INVALID_ARGS ); + } + } + } + + return ZYPPER_EXIT_OK; +} + + +std::string ModifyRepoCmd::help() +{ + CommandHelpFormater formatter; + + formatter << ZypperBaseCommand::help(); + + formatter + .legacyOptionSection() + .legacyOption( "-r", "-f" ) + .legacyOption( "-R", "-F" ); + + return formatter; +} diff --git a/src/commands/repos/modify.h b/src/commands/repos/modify.h new file mode 100644 index 0000000..9417d28 --- /dev/null +++ b/src/commands/repos/modify.h @@ -0,0 +1,33 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#ifndef ZYPPER_COMMANDS_REPOS_MODIFY_H_INCLUDED +#define ZYPPER_COMMANDS_REPOS_MODIFY_H_INCLUDED + +#include "commands/basecommand.h" +#include "commands/reposerviceoptionsets.h" + +class ModifyRepoCmd : public ZypperBaseCommand +{ +public: + ModifyRepoCmd( const std::vector &commandAliases_r ); + + // ZypperBaseCommand interface + std::string help() override; + +protected: + std::vector conditions() const override; + zypp::ZyppFlags::CommandGroup cmdOptions() const override; + void doReset() override; + int execute(Zypper &zypp_r, const std::vector &positionalArgs_r) override; + +private: + RepoServiceCommonOptions _commonProps{OptCommandCtx::RepoContext, *this}; + RepoProperties _repoProps{*this}; + RepoServiceCommonSelectOptions _selections{OptCommandCtx::RepoContext, *this}; +}; + +#endif diff --git a/src/commands/repos/refresh.cc b/src/commands/repos/refresh.cc new file mode 100644 index 0000000..a07cb59 --- /dev/null +++ b/src/commands/repos/refresh.cc @@ -0,0 +1,307 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#include "refresh.h" +#include "repos.h" +#include "commands/conditions.h" +#include "commands/services/refresh.h" + + +#include "utils/messages.h" +#include "utils/flags/flagtypes.h" +#include "Zypper.h" + +using namespace zypp; + +extern ZYpp::Ptr God; + +RefreshRepoCmd::RefreshRepoCmd( const std::vector &commandAliases_r ) + : ZypperBaseCommand ( + commandAliases_r, + _("refresh (ref) [ALIAS|#|URI] ..."), + // translators: command summary: refresh, ref + _("Refresh all repositories."), + // translators: command description + _("Refresh repositories specified by their alias, number or URI. If none are specified, all enabled repositories will be refreshed."), + ResetRepoManager + ) +{ + +} + +std::vector RefreshRepoCmd::conditions() const +{ + return { + std::make_shared() + }; +} + +zypp::ZyppFlags::CommandGroup RefreshRepoCmd::cmdOptions() const +{ + auto that = const_cast(this); + return {{ + {"force",'f', ZyppFlags::NoArgument, + ZyppFlags::BitFieldType( that->_flags, Force ), + // translators: -f, --force + _("Force a complete refresh.") + }, + {"force-build", 'b', ZyppFlags::NoArgument, + ZyppFlags::BitFieldType( that->_flags, ForceBuild ), + // translators: -b, --force-build + _("Force rebuild of the database.") + }, + {"force-download", 'd', ZyppFlags::NoArgument, + ZyppFlags::BitFieldType( that->_flags, ForceDownload ), + // translators: -d, --force-download + _("Force download of raw metadata.") + }, + {"build-only", 'B', ZyppFlags::NoArgument, + ZyppFlags::BitFieldType( that->_flags, BuildOnly ), + // translators: -B, --build-only + _("Only build the database, don't download metadata.") + }, + {"download-only", 'D', ZyppFlags::NoArgument, + ZyppFlags::BitFieldType( that->_flags, DownloadOnly ), + // translators: -D, --download-only + _("Only download raw metadata, don't build the database.") + }, + {"repo", 'r', ZyppFlags::RequiredArgument | ZyppFlags::Repeatable, + ZyppFlags::StringVectorType( &that->_repos, ARG_REOSITORY), + // translators: -r, --repo + _("Refresh only specified repositories.") + } + , + {"services", 's', ZyppFlags::NoArgument, + ZyppFlags::BoolType( &that->_services, ZyppFlags::StoreTrue, false ), + // translators: -s, --services + _("Refresh also services before refreshing repos.") + }, + }}; +} + +void RefreshRepoCmd::doReset() +{ + _flags = Default; + _repos.clear(); + _services = false; +} + +int RefreshRepoCmd::execute( Zypper &zypp_r , const std::vector &positionalArgs_r ) +{ + if ( zypp_r.globalOpts().no_refresh ) + zypp_r.out().warning( str::Format(_("The '%s' global option has no effect here.")) % "--no-refresh" ); + + bool force = _flags.testFlag(Force); + + if ( _services ) + { + if ( !positionalArgs_r.empty() ) + { + zypp_r.out().error(str::form(_("Arguments are not allowed if '%s' is used."), "--services")); + return ( ZYPPER_EXIT_ERR_PRIVILEGES ); + } + + RefreshServicesCmd refServiceCmd( {} ); + refServiceCmd.setForce( force ); + refServiceCmd.setRestoreStatus( false ); + refServiceCmd.setWithRepos( false ); + + // needed to be able to retrieve target distribution + int code = defaultSystemSetup ( zypp_r, InitTarget ); + if ( code != ZYPPER_EXIT_OK ) + return code; + + zypp_r.globalOptsNoConst().rm_options.servicesTargetDistro = God->target()->targetDistribution(); + + code = refServiceCmd.refreshServices( zypp_r ); + if ( code != ZYPPER_EXIT_OK ) + return code; + } + else + { + RepoManager::RefreshServiceOptions opts; + if ( force ) + opts |= RepoManager::RefreshService_forceRefresh; + + checkIfToRefreshPluginServices( zypp_r, opts ); + } + + MIL << "going to refresh repositories" << endl; + // need gpg keys when downloading (#304672) + int code = defaultSystemSetup ( zypp_r, InitTarget ); + if ( code != ZYPPER_EXIT_OK ) + return code; + + std::vector specifiedRepos = _repos; + for ( const std::string &repoFromCLI : positionalArgs_r ) + specifiedRepos.push_back(repoFromCLI); + + return refreshRepositories ( zypp_r, _flags, specifiedRepos ); +} + +bool RefreshRepoCmd::refreshRepository(Zypper &zypper, const RepoInfo &repo, RefreshFlags flags_r) +{ + MIL << "going to refresh repo '" << repo.alias() << "'" << endl; + + // raw metadata refresh + bool error = false; + if ( !flags_r.testFlag(BuildOnly) ) + { + bool force_download = flags_r.testFlag(Force) || flags_r.testFlag(ForceDownload); + MIL << "calling refreshMetadata" << (force_download ? ", forced" : "") << endl; + error = refresh_raw_metadata( zypper, repo, force_download ); + } + + // db rebuild + if ( !( error || flags_r.testFlag(DownloadOnly) ) ) + { + bool force_build = flags_r.testFlag(Force) || flags_r.testFlag(ForceBuild);; + MIL << "calling buildCache" << (force_build ? ", forced" : "") << endl; + error = build_cache( zypper, repo, force_build ); + } + + return error; +} + +int RefreshRepoCmd::refreshRepositories( Zypper &zypp_r, RefreshFlags flags_r, const std::vector repos_r ) +{ + RepoManager & manager( zypp_r.repoManager() ); + const std::list & repos( manager.knownRepositories() ); + + // get the list of repos specified on the command line ... + std::list specified; + std::list not_found; + get_repos( zypp_r, repos_r.begin(),repos_r.end(), specified, not_found ); + report_unknown_repos( zypp_r.out(), not_found ); + + // --plus-content: It either specifies a known repo (by #, alias or URL) + // or we need to also refresh all disabled repos to get their content + // keywords. + std::set plusContent; + bool doContentCheck = false; + for ( const std::string & spec : zypp_r.runtimeData().plusContentRepos ) + { + RepoInfo r; + if ( match_repo( zypp_r, spec, &r ) ) + plusContent.insert( r ); // specific repo: add to plusContent + else if ( ! doContentCheck ) + doContentCheck = true; // keyword: need to scan all disabled repos + } + + std::ostringstream s; + s << _("Specified repositories: "); + for_( it, specified.begin(), specified.end() ) + s << it->alias() << " "; + zypp_r.out().info( s.str(), Out::HIGH ); + + unsigned error_count = 0; + unsigned enabled_repo_count = repos.size(); + + if ( !specified.empty() || not_found.empty() ) + { + for_( rit, repos.begin(), repos.end() ) + { + const RepoInfo & repo( *rit ); + + if ( repo.enabled() ) + { + // enabled: Refreshed unless restricted by CLI args or mentioned in + // --plus-content as specific repo. + if ( !specified.empty() && std::find( specified.begin(), specified.end(), repo ) == specified.end() ) + { + if ( plusContent.count( repo ) ) + { + MIL << "[--plus-content] check " << repo.alias() << endl; + zypp_r.out().info( str::Format(_("Refreshing repository '%s'.")) % repo.asUserString(), + " [--plus-content]" ); + } + else + { + DBG << repo.alias() << "(#" << ") not specified," << " skipping." << endl; + enabled_repo_count--; + continue; + } + } + } + else + { + // disabled: No refresh unless mentioned in --plus-content (specific or content check). + // CLI args reffering to disabled repos are reported as error. + if ( doContentCheck || plusContent.count( repo ) ) + { + MIL << "[--plus-content] check " << repo.alias() << endl; + zypp_r.out().info( str::Format(_("Scanning content of disabled repository '%s'.")) % repo.asUserString(), + " [--plus-content]" ); + } + else + { + if ( !specified.empty() && std::find( specified.begin(), specified.end(), repo ) == specified.end() ) + { + DBG << repo.alias() << "(#" << ") not specified," << " skipping." << endl; + } + else + { + std::string msg( str::Format(_("Skipping disabled repository '%s'")) % repo.asUserString() ); + + if ( specified.empty() ) + zypp_r.out().info( msg, Out::HIGH ); + else + zypp_r.out().error( msg ); + } + enabled_repo_count--; + continue; + } + } + + // do the refresh + if ( refreshRepository( zypp_r, repo, flags_r ) ) + { + zypp_r.out().error( str::Format(_("Skipping repository '%s' because of the above error.")) % repo.asUserString() ); + ERR << "Skipping repository '" << repo.alias() << "' because of the above error." << endl; + error_count++; + } + } + } + else + enabled_repo_count = 0; + + // print the result message + if ( !not_found.empty() ) + { + zypp_r.out().error(_("Some of the repositories have not been refreshed because they were not known.") ); + return ZYPPER_EXIT_ERR_INVALID_ARGS; + } + else if ( enabled_repo_count == 0 ) + { + int code = ZYPPER_EXIT_OK; + if ( !specified.empty() ) + zypp_r.out().warning(_("Specified repositories are not enabled or defined.") ); + else { + zypp_r.out().warning(_("There are no enabled repositories defined.") ); + code = ( ZYPPER_EXIT_NO_REPOS ); + } + + zypp_r.out().info( str::form(_("Use '%s' or '%s' commands to add or enable repositories."), + "zypper addrepo", "zypper modifyrepo" ) ); + return code; + } + else if ( error_count == enabled_repo_count ) + { + zypp_r.out().error(_("Could not refresh the repositories because of errors.") ); + return ( ZYPPER_EXIT_ERR_ZYPP ); + } + else if ( error_count ) + { + zypp_r.out().error(_("Some of the repositories have not been refreshed because of an error.") ); + return ( ZYPPER_EXIT_ERR_ZYPP ); + } + else if ( !specified.empty() ) + zypp_r.out().info(_("Specified repositories have been refreshed.") ); + else + zypp_r.out().info(_("All repositories have been refreshed.") ); + + return ZYPPER_EXIT_OK; +} diff --git a/src/commands/repos/refresh.h b/src/commands/repos/refresh.h new file mode 100644 index 0000000..f2c1869 --- /dev/null +++ b/src/commands/repos/refresh.h @@ -0,0 +1,50 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#ifndef ZYPPER_COMMANDS_REPOS_REFRESH_H_INCLUDED +#define ZYPPER_COMMANDS_REPOS_REFRESH_H_INCLUDED + +#include "commands/basecommand.h" + +#include + +class RefreshRepoCmd : public ZypperBaseCommand +{ +public: + + enum RefreshFlagsBits { + Default = 0, + Force = 1, + ForceBuild = 1 << 1, + ForceDownload = 1 << 2, + BuildOnly = 1 << 3, + DownloadOnly = 1 << 4 + }; + ZYPP_DECLARE_FLAGS(RefreshFlags,RefreshFlagsBits); + + RefreshRepoCmd( const std::vector &commandAliases_r ); + + static int refreshRepositories ( Zypper &zypp_r, RefreshFlags flags_r = Default, const std::vector repos_r = std::vector() ); + + /** \return false on success, true on error */ + static bool refreshRepository ( Zypper & zypper, const zypp::RepoInfo & repo, RefreshFlags flags_r = Default ); + + // ZypperBaseCommand interface +protected: + std::vector conditions() const override; + zypp::ZyppFlags::CommandGroup cmdOptions() const override; + void doReset() override; + int execute(Zypper &zypp_r, const std::vector &positionalArgs) override; + + +private: + RefreshFlags _flags; + std::vector _repos; + bool _services = false; +}; +ZYPP_DECLARE_OPERATORS_FOR_FLAGS(RefreshRepoCmd::RefreshFlags); + +#endif diff --git a/src/commands/repos/remove.cc b/src/commands/repos/remove.cc new file mode 100644 index 0000000..043350c --- /dev/null +++ b/src/commands/repos/remove.cc @@ -0,0 +1,106 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#include "remove.h" +#include "repos.h" + +#include "commands/conditions.h" +#include "utils/flags/flagtypes.h" +#include "utils/messages.h" +#include "utils/misc.h" +#include "Zypper.h" + +using namespace zypp; + +RemoveRepoCmd::RemoveRepoCmd( const std::vector &commandAliases_r ) : + ZypperBaseCommand ( + commandAliases_r, + _("removerepo (rr) [OPTIONS] "), + _("Remove specified repository."), + _("Remove repository specified by alias, number or URI."), + ResetRepoManager + ) +{ + +} + +std::vector RemoveRepoCmd::conditions() const +{ + return { + std::make_shared() + }; +} + +zypp::ZyppFlags::CommandGroup RemoveRepoCmd::cmdOptions() const +{ + //@TODO merge into a OptionSet to share with RemoveServiceCommand ? + auto that = const_cast(this); + return {{{ + { "loose-auth", '\0', ZyppFlags::NoArgument, ZyppFlags::BoolType( &that->_looseAuth, ZyppFlags::StoreTrue), + // translators: --loose-auth + _("Ignore user authentication data in the URI.") + },{ "loose-query", '\0', ZyppFlags::NoArgument, ZyppFlags::BoolType( &that->_looseQuery, ZyppFlags::StoreTrue), + // translators: --loose-query + _("Ignore query string in the URI.") + } + }}}; +} + +void RemoveRepoCmd::doReset() +{ + _looseAuth = false; + _looseQuery = false; +} + +int RemoveRepoCmd::execute( Zypper &zypp_r, const std::vector &positionalArgs_r ) +{ + bool aggregate = _selections._all || _selections._local || _selections._remote || _selections._mediumTypes.size(); + + if ( positionalArgs_r.size() < 1 && !aggregate ) + { + report_alias_or_aggregate_required ( zypp_r.out(), help() ); + ERR << "No alias argument given." << endl; + return( ZYPPER_EXIT_ERR_INVALID_ARGS ); + } + + // too many arguments + if ( positionalArgs_r.size() && aggregate ) + { + report_too_many_arguments( zypp_r.out(), help() ); + return ( ZYPPER_EXIT_ERR_INVALID_ARGS ); + } + + if ( aggregate ) + { + remove_repos_by_option( zypp_r, _selections ); + } + else + { + // must store repository before remove to ensure correct match number + std::set repo_to_remove; + for_(it, positionalArgs_r.begin(), positionalArgs_r.end()) + { + RepoInfo repo; + if ( match_repo( zypp_r ,*it,&repo, _looseQuery, _looseAuth ) ) + { + repo_to_remove.insert(repo); + } + else + { + MIL << "Repository not found by given alias, number or URI." << endl; + // translators: %s is the supplied command line argument which + // for which no repository counterpart was found + zypp_r.out().error( str::Format(_("Repository '%s' not found by alias, number or URI.")) % *it ); + } + } + + for_(it, repo_to_remove.begin(), repo_to_remove.end()) + remove_repo( zypp_r, *it ); + } + + return ZYPPER_EXIT_OK; +} + diff --git a/src/commands/repos/remove.h b/src/commands/repos/remove.h new file mode 100644 index 0000000..5aa40d3 --- /dev/null +++ b/src/commands/repos/remove.h @@ -0,0 +1,35 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#ifndef ZYPPER_COMMANDS_REPOS_REMOVE_H_INCLUDED +#define ZYPPER_COMMANDS_REPOS_REMOVE_H_INCLUDED + +#include "commands/basecommand.h" +#include "commands/reposerviceoptionsets.h" + +#include + +#include + +class RemoveRepoCmd : public ZypperBaseCommand +{ +public: + RemoveRepoCmd( const std::vector &commandAliases_r ); + + // ZypperBaseCommand interface +protected: + std::vector conditions() const override; + zypp::ZyppFlags::CommandGroup cmdOptions() const override; + void doReset() override; + int execute(Zypper &zypp, const std::vector &positionalArgs) override; + +private: + bool _looseAuth = false; + bool _looseQuery = false; + RepoServiceCommonSelectOptions _selections{OptCommandCtx::RepoContext, *this}; +}; + +#endif diff --git a/src/commands/repos/rename.cc b/src/commands/repos/rename.cc new file mode 100644 index 0000000..6ef9e65 --- /dev/null +++ b/src/commands/repos/rename.cc @@ -0,0 +1,125 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#include "rename.h" +#include "repos.h" + +#include "commands/conditions.h" +#include "utils/messages.h" + +#include "Zypper.h" + +using namespace zypp; + +namespace { + +/** + * Rename repository specified by \a alias to \a newalias. + */ +int rename_repo( Zypper & zypper, const std::string & alias, const std::string & newalias ) +{ + RepoManager & manager( zypper.repoManager() ); + + try + { + RepoInfo repo( manager.getRepositoryInfo( alias ) ); + + if ( !repo.service().empty() ) + { + zypper.out().error(str::form( + _("Cannot change alias of '%s' repository. The repository" + " belongs to service '%s' which is responsible for setting its alias."), + alias.c_str(), repo.service().c_str())); + return ZYPPER_EXIT_ERR_ZYPP; + } + + repo.setAlias( newalias ); + manager.modifyRepository( alias, repo ); + + MIL << "Repository '" << alias << "' renamed to '" << repo.alias() << "'" << endl; + zypper.out().info( str::Format(_("Repository '%s' renamed to '%s'.")) % alias % repo.alias() ); + } + catch ( const repo::RepoAlreadyExistsException & ex ) + { + zypper.out().error( str::Format(_("Repository named '%s' already exists. Please use another alias.")) % newalias ); + } + catch ( const Exception & ex ) + { + ERR << "Error while modifying the repository " << ex.asUserString() << endl; + zypper.out().error( ex, _("Error while modifying the repository:"), + str::Format(_("Leaving repository '%s' unchanged.")) % alias ); + } + return ZYPPER_EXIT_OK; +} + +} + +RenameRepoCmd::RenameRepoCmd(const std::vector &commandAliases_r) : + ZypperBaseCommand ( + commandAliases_r, + // translators: command synopsis; do not translate lowercase words + _("renamerepo (nr) [OPTIONS] "), + _("Rename specified repository."), + // translators: command description + _("Assign new alias to the repository specified by alias, number or URI."), + ResetRepoManager + ) +{ } + +std::vector RenameRepoCmd::conditions() const +{ + return { + std::make_shared() + }; +} + +zypp::ZyppFlags::CommandGroup RenameRepoCmd::cmdOptions() const +{ + return {}; +} + +void RenameRepoCmd::doReset() +{ } + +int RenameRepoCmd::execute( Zypper &zypp_r, const std::vector &positionalArgs_r ) +{ + + if ( positionalArgs_r.size() < 2 ) + { + zypp_r.out().error(_("Too few arguments. At least URI and alias are required.") ); + ERR << "Too few arguments. At least URI and alias are required." << endl; + zypp_r.out().info( help() ); + return ( ZYPPER_EXIT_ERR_INVALID_ARGS ); + } + // too many arguments + else if ( positionalArgs_r.size() > 2 ) + { + report_too_many_arguments( help() ); + return ( ZYPPER_EXIT_ERR_INVALID_ARGS ); + } + + try + { + RepoInfo repo; + if ( match_repo( zypp_r,positionalArgs_r[0], &repo )) + { + int code = rename_repo( zypp_r, repo.alias(), positionalArgs_r[1] ); + return code; + } + else + { + zypp_r.out().error( str::Format(_("Repository '%s' not found.")) % positionalArgs_r[0] ); + ERR << "Repo " << positionalArgs_r[0] << " not found" << endl; + } + } + catch ( const Exception & excpt_r ) + { + zypp_r.out().error( excpt_r.asUserString() ); + return ( ZYPPER_EXIT_ERR_ZYPP ); + } + + return ZYPPER_EXIT_OK; +} diff --git a/src/commands/repos/rename.h b/src/commands/repos/rename.h new file mode 100644 index 0000000..cfd8088 --- /dev/null +++ b/src/commands/repos/rename.h @@ -0,0 +1,30 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#ifndef ZYPPER_COMMANDS_REPOS_RENAME_H_INCLUDED +#define ZYPPER_COMMANDS_REPOS_RENAME_H_INCLUDED + +#include "commands/basecommand.h" +#include "commands/reposerviceoptionsets.h" + +#include + +#include + +class RenameRepoCmd : public ZypperBaseCommand +{ +public: + RenameRepoCmd( const std::vector &commandAliases_r ); + + // ZypperBaseCommand interface +protected: + std::vector conditions() const override; + zypp::ZyppFlags::CommandGroup cmdOptions() const override; + void doReset() override; + int execute(Zypper &zypp_r, const std::vector &positionalArgs_r) override; +}; + +#endif diff --git a/src/commands/reposerviceoptionsets.cc b/src/commands/reposerviceoptionsets.cc new file mode 100644 index 0000000..b9de403 --- /dev/null +++ b/src/commands/reposerviceoptionsets.cc @@ -0,0 +1,278 @@ +#include "reposerviceoptionsets.h" +#include "utils/flags/flagtypes.h" +#include "utils/flags/zyppflags.h" +#include "src/repos.h" +#include "main.h" + +#include "utils/getopt.h" +#include "Zypper.h" + +using namespace zypp; + +namespace { +ZyppFlags::Value PriorityType(unsigned &target, const boost::optional &defValue) +{ + return ZyppFlags::Value ( + [defValue]() -> boost::optional{ + if(defValue) { + return std::to_string(*defValue); + } else + return boost::optional(); + }, + + [&target]( const ZyppFlags::CommandOption &opt, const boost::optional &in ) { + if (!in) + ZYPP_THROW(ZyppFlags::MissingArgumentException(opt.name)); + + int prio = -1; + safe_lexical_cast( *in, prio ); // try to make an int out of the string + + if ( prio < 0 ) + { + ZYPP_THROW(ZyppFlags::InvalidValueException( + opt.name, + *in, + str::Format(_("Invalid priority '%s'. Use a positive integer number. The greater the number, the lower the priority.")) % *in)); + } + + target = ( prio ? unsigned(prio) : RepoInfo::defaultPriority() ); + }, + "PRIORITY" + ); +} + +ZyppFlags::Value GPGCheckType(RepoInfo::GpgCheck &target, RepoInfo::GpgCheck valueIfSeen) +{ + return ZyppFlags::Value ( + ZyppFlags::noDefaultValue, + [&target, valueIfSeen]( const ZyppFlags::CommandOption &, const boost::optional & ) { + target = valueIfSeen; + } + ); +} + +} + +RepoServiceCommonOptions::RepoServiceCommonOptions(OptCommandCtx ctx) + : _cmdContext(ctx) +{ } + +RepoServiceCommonOptions::RepoServiceCommonOptions(OptCommandCtx ctx, ZypperBaseCommand &parent) + : BaseCommandOptionSet(parent), + _cmdContext(ctx) +{ } + +std::vector RepoServiceCommonOptions::options() +{ + return { + { + { + {"name", 'n', ZyppFlags::RequiredArgument, ZyppFlags::StringType( &_name, boost::optional(), "NAME"), + _cmdContext == OptCommandCtx::ServiceContext ? _("Set a descriptive name for the service.") : _("Set a descriptive name for the repository.") + }, + {"enable", 'e', ZyppFlags::NoArgument, ZyppFlags::TriBoolType( _enable, ZyppFlags::StoreTrue, TriBool( true ) ), + _cmdContext == OptCommandCtx::ServiceContext ? _("Enable a disabled service.") : _("Enable a disabled repository.") + }, + {"disable", 'd', ZyppFlags::NoArgument, ZyppFlags::TriBoolType(_enable, ZyppFlags::StoreFalse, TriBool( false ) ), + _cmdContext == OptCommandCtx::ServiceContext ? _("Disable the service (but don't remove it).") : _("Disable the repository (but don't remove it).") + }, + {"refresh", 'f', ZyppFlags::NoArgument, ZyppFlags::TriBoolType( _enableAutoRefresh, ZyppFlags::StoreTrue, TriBool( true ) ), + _cmdContext == OptCommandCtx::ServiceContext ? _("Enable auto-refresh of the service.") : _("Enable auto-refresh of the repository.") + }, + {"no-refresh", 'F', ZyppFlags::NoArgument, ZyppFlags::TriBoolType( _enableAutoRefresh, ZyppFlags::StoreFalse, TriBool( false ) ), + _cmdContext == OptCommandCtx::ServiceContext ? _("Disable auto-refresh of the service.") : _("Disable auto-refresh of the repository.") + } + } + } + }; +} + +void RepoServiceCommonOptions::reset() +{ + _name.clear(); + _enable = indeterminate; + _enableAutoRefresh = indeterminate; +} + +void RepoServiceCommonOptions::fillFromCopts( Zypper &zypper ) +{ + reset(); + parsed_opts::const_iterator it = zypper.cOpts().find("name"); + if ( it != zypper.cOpts().end() ) + _name = it->second.front(); + + _enable = get_boolean_option( zypper, "enable", "disable" ); + _enableAutoRefresh = get_boolean_option( zypper, "refresh", "no-refresh" ); +} + +RepoServiceCommonSelectOptions::RepoServiceCommonSelectOptions(OptCommandCtx ctx) + : _cmdContext(ctx) +{ } + +RepoServiceCommonSelectOptions::RepoServiceCommonSelectOptions(OptCommandCtx ctx, ZypperBaseCommand &parent) + : BaseCommandOptionSet(parent), + _cmdContext(ctx) +{ } + +std::vector RepoServiceCommonSelectOptions::options() +{ + return {{{ + {"all", 'a', ZyppFlags::NoArgument, ZyppFlags::BoolType( &_all, ZyppFlags::StoreTrue, _all), + _cmdContext == OptCommandCtx::ServiceContext ? _("Apply changes to all services.") : _("Apply changes to all repositories.") + }, + {"local", 'l', ZyppFlags::NoArgument, ZyppFlags::BoolType( &_local, ZyppFlags::StoreTrue, _local), + _cmdContext == OptCommandCtx::ServiceContext ? _("Apply changes to all local services.") : _("Apply changes to all local repositories.") + }, + {"remote", 't', ZyppFlags::NoArgument, ZyppFlags::BoolType( &_remote, ZyppFlags::StoreTrue, _remote), + _cmdContext == OptCommandCtx::ServiceContext ? _("Apply changes to all remote services.") : _("Apply changes to all remote repositories.") + }, + {"medium-type", 'm', ZyppFlags::RequiredArgument | ZyppFlags::Repeatable, ZyppFlags::StringVectorType( &_mediumTypes, "TYPE"), + _cmdContext == OptCommandCtx::ServiceContext ? _("Apply changes to services of specified type.") : _("Apply changes to repositories of specified type.") + } + }}}; +} + +void RepoServiceCommonSelectOptions::reset() +{ + _all = false; + _local = false; + _remote = false; + _mediumTypes.clear(); +} + +void RepoServiceCommonSelectOptions::fillFromCopts(Zypper &zypper) +{ + reset(); + _all = copts.count("all"); + _local = copts.count("local"); + _remote = copts.count("remote"); + _mediumTypes.insert( _mediumTypes.begin(), copts["medium-type"].begin(), copts["medium-type"].end()); +} + + +std::vector RepoProperties::options() +{ + return {{{ + { "priority", 'p', ZyppFlags::RequiredArgument, PriorityType( _priority, _priority ), _("Set priority of the repository.") }, + { "keep-packages", 'k', ZyppFlags::NoArgument, ZyppFlags::TriBoolType( _keepPackages, ZyppFlags::StoreTrue, TriBool( true ) ), _("Enable RPM files caching.") }, + { "no-keep-packages", 'K', ZyppFlags::NoArgument, ZyppFlags::TriBoolType( _keepPackages, ZyppFlags::StoreFalse, TriBool( false ) ), _("Disable RPM files caching.") }, + { "gpgcheck", 'g', ZyppFlags::NoArgument, GPGCheckType( _gpgCheck, RepoInfo::GpgCheck::On ), _("Enable GPG check for this repository.") }, + { "gpgcheck-strict", '\0', ZyppFlags::NoArgument, GPGCheckType( _gpgCheck, RepoInfo::GpgCheck::Strict ), _("Enable strict GPG check for this repository.") }, + { "gpgcheck-allow-unsigned", '\0', ZyppFlags::NoArgument, GPGCheckType( _gpgCheck, RepoInfo::GpgCheck::AllowUnsigned ), str::Format(_("Short hand for '%1%'.") ) % "--gpgcheck-allow-unsigned-repo --gpgcheck-allow-unsigned-package" }, + { "gpgcheck-allow-unsigned-repo", '\0', ZyppFlags::NoArgument, GPGCheckType( _gpgCheck, RepoInfo::GpgCheck::AllowUnsignedRepo ), _("Enable GPG check but allow the repository metadata to be unsigned.") }, + { "gpgcheck-allow-unsigned-package", '\0', ZyppFlags::NoArgument, GPGCheckType( _gpgCheck, RepoInfo::GpgCheck::AllowUnsignedPackage ), _("Enable GPG check but allow installing unsigned packages from this repository.") }, + { "no-gpgcheck", 'G', ZyppFlags::NoArgument, GPGCheckType( _gpgCheck, RepoInfo::GpgCheck::Off ), _("Disable GPG check for this repository.") }, + { "default-gpgcheck", '\0', ZyppFlags::NoArgument, GPGCheckType( _gpgCheck, RepoInfo::GpgCheck::Default ), _("Use the global GPG check setting defined in /etc/zypp/zypp.conf. This is the default.") } + },{ + //conflicting arguments + { "gpgcheck", "gpgcheck-strict", "gpgcheck-allow-unsigned", "gpgcheck-allow-unsigned-repo", "gpgcheck-allow-unsigned-package", "no-gpgcheck", "default-gpgcheck"} + }}}; +} + +void RepoProperties::reset() +{ + _priority = 0U; + _keepPackages = zypp::indeterminate; + _gpgCheck = zypp::RepoInfo::GpgCheck::indeterminate; +} + +void RepoProperties::fillFromCopts(Zypper &zypper) +{ + reset(); + _keepPackages = get_boolean_option( zypper, "keep-packages", "no-keep-packages" ); + _gpgCheck = cli::gpgCheck( zypper ); + _priority = priority_from_copts( zypper ); +} + + +RSCommonListOptions::RSCommonListOptions(OptCommandCtx ctx) + : _cmdContext ( ctx ) +{ } + +RSCommonListOptions::RSCommonListOptions(OptCommandCtx ctx, ZypperBaseCommand &parent) + : BaseCommandOptionSet ( parent ), + _cmdContext ( ctx ) +{ } + +std::vector RSCommonListOptions::options() +{ + + std::vector opts; + + RSCommonListFlags showAllFlag = ListServiceShowAll; + + if ( _cmdContext == OptCommandCtx::RepoContext ) { + + opts.push_back ( {{ + { "alias", 'a', ZyppFlags::NoArgument, ZyppFlags::BitFieldType( _flags, ShowAlias ), + // translators: -a, --alias + _("Show also repository alias.")}, + { "name", 'n', ZyppFlags::NoArgument, ZyppFlags::BitFieldType( _flags, ShowName ), + // translators: -n, --name + _("Show also repository name.")}, + { "refresh", 'r', ZyppFlags::NoArgument, ZyppFlags::BitFieldType( _flags, ShowRefresh ), + // translators: -r, --refresh + _("Show also the autorefresh flag.")} + }} ); + + showAllFlag = ListRepoShowAll; + } + + opts.push_back( + {{ + { "uri", 'u', ZyppFlags::NoArgument, ZyppFlags::BitFieldType( _flags, ShowURI ), + // translators: -u, --uri + _("Show also base URI of repositories.")}, + { "url", '\0', ZyppFlags::NoArgument | ZyppFlags::Hidden, ZyppFlags::BitFieldType( _flags, ShowURI ), "" }, + { "priority", 'p', ZyppFlags::NoArgument, ZyppFlags::BitFieldType( _flags, ShowPriority ), + // translators: -p, --priority + _("Show also repository priority.") }, + { "details", 'd', ZyppFlags::NoArgument, ZyppFlags::BitFieldType( _flags, showAllFlag ), + // translators: -d, --details + _("Show more information like URI, priority, type.") } + }} + ); + + if ( _cmdContext == OptCommandCtx::ServiceContext ) { + //@NOTE attention -r clashes with --refresh in case of merging the options + opts.back().options.push_back( + { "with-repos", 'r', ZyppFlags::NoArgument, ZyppFlags::BitFieldType( _flags, ShowWithRepos), _("Show also repositories belonging to the services.") } + ); + } else { + opts.back().options.push_back( + { "service", 's', ZyppFlags::NoArgument, ZyppFlags::BitFieldType( _flags, ShowWithService), + // translators: -s, --service + _("Show also alias of parent service.") } + ); + } + + opts.push_back({{ + { "show-enabled-only", 'E', ZyppFlags::NoArgument, ZyppFlags::BitFieldType( _flags, ShowEnabledOnly ), + // translators: -E, --show-enabled-only + _("Show enabled repos only.") }, + { "sort-by-uri", 'U', ZyppFlags::NoArgument, ZyppFlags::BitFieldType( _flags, RSCommonListFlags( ShowURI ) | SortByURI ), + // translators: -U, --sort-by-uri + _("Sort the list by URI.") }, + { "sort-by-name", 'N', ZyppFlags::NoArgument, ZyppFlags::BitFieldType( _flags, SortByName ), + // translators: -N, --sort-by-name + _("Sort the list by name.") }, + { "sort-by-priority", 'P', ZyppFlags::NoArgument, ZyppFlags::BitFieldType( _flags, RSCommonListFlags( ShowPriority ) | SortByPrio ), + // translators: -P, --sort-by-priority + _("Sort the list by repository priority.") } + }}); + + if ( _cmdContext == OptCommandCtx::RepoContext ) { + opts.back().options.push_back( + { "sort-by-alias", 'A', ZyppFlags::NoArgument, ZyppFlags::BitFieldType( _flags, RSCommonListFlags( ShowAlias ) | SortByAlias ), + // translators: -A, --sort-by-alias + _("Show also alias of parent service.") } + ); + } + + return opts; +} + +void RSCommonListOptions::reset() +{ + _flags.unsetFlag( _flags.all() ); +} diff --git a/src/commands/reposerviceoptionsets.h b/src/commands/reposerviceoptionsets.h new file mode 100644 index 0000000..dda0a20 --- /dev/null +++ b/src/commands/reposerviceoptionsets.h @@ -0,0 +1,128 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#ifndef ZYPPER_COMMANDS_REPO_SERVICE_OPTIONSET_H_INCLUDED +#define ZYPPER_COMMANDS_REPO_SERVICE_OPTIONSET_H_INCLUDED + +#include "basecommand.h" + +#include +#include +#include + +enum class OptCommandCtx +{ + ServiceContext, + RepoContext +}; + +// Common Repo/Service properties (argdef only) +// LEGACY: --refresh short option was -f in ADD_REPO, -r in all other Repo/Service commands. +// Unfortunately -r is already --repo in ADD_REPO, so switching all Repo/Service commands +// to prefer -f/F. +class RepoServiceCommonOptions : public BaseCommandOptionSet +{ +public: + RepoServiceCommonOptions( OptCommandCtx ctx ); + RepoServiceCommonOptions( OptCommandCtx ctx, ZypperBaseCommand &parent ); + + // BaseCommandOptionSet interface + std::vector options() override; + void reset() override; + + //will be removed + void fillFromCopts (Zypper &zypper ); + + std::string _name; + zypp::TriBool _enable = zypp::indeterminate; + zypp::TriBool _enableAutoRefresh = zypp::indeterminate; + +private: + OptCommandCtx _cmdContext = OptCommandCtx::RepoContext; +}; + +// Common modify Repo/Service aggregate options (argdef only) +class RepoServiceCommonSelectOptions : public BaseCommandOptionSet +{ +public: + RepoServiceCommonSelectOptions( OptCommandCtx ctx ); + RepoServiceCommonSelectOptions( OptCommandCtx ctx, ZypperBaseCommand &parent ); + + // BaseCommandOptionSet interface + std::vector options() override; + void reset() override; + + //will be removed + void fillFromCopts (Zypper &zypper ); + + bool _all = false; + bool _local = false; + bool _remote = false; + std::vector _mediumTypes; + +private: + OptCommandCtx _cmdContext = OptCommandCtx::RepoContext; +}; + +class RepoProperties : public BaseCommandOptionSet +{ +public: + using BaseCommandOptionSet::BaseCommandOptionSet; + + // BaseCommandOptionSet interface + std::vector options() override; + void reset() override; + + //will be removed + void fillFromCopts (Zypper &zypper ); + + unsigned _priority = 0U; + zypp::TriBool _keepPackages = zypp::indeterminate; + zypp::RepoInfo::GpgCheck _gpgCheck = zypp::RepoInfo::GpgCheck::indeterminate; +}; + +class RSCommonListOptions : public BaseCommandOptionSet +{ +public: + + RSCommonListOptions( OptCommandCtx ctx ); + RSCommonListOptions( OptCommandCtx ctx, ZypperBaseCommand &parent ); + + + enum RSCommonListFlagsBits + { + ShowAlias = 1, //< only supported in list repos + ShowName = 1 << 1, //< only supported in list repos + ShowRefresh = 1 << 2, //< only supported in list repos + ShowURI = 1 << 3, //< supported in service and repos + ShowPriority = 1 << 4, //< supported in service and repos + ShowWithRepos = 1 << 5, //< only supported in list services + ShowWithService = 1 << 6, //< only supported in list repos + ListServiceShowAll = ShowURI | ShowPriority | ShowWithRepos, + ListRepoShowAll = ShowAlias | ShowName | ShowRefresh | ShowURI | ShowPriority | ShowWithService, + ShowEnabledOnly = 1 << 7, //< supported in service and repos + SortByURI = 1 << 8, //< supported in service and repos + SortByAlias = 1 << 9, //< only supported in list repos + SortByName = 1 << 10, //< supported in service and repos + SortByPrio = 1 << 11, //< supported in service and repos + ServiceRepo = 1 << 15 //< special value used in list services + }; + ZYPP_DECLARE_FLAGS( RSCommonListFlags, RSCommonListFlagsBits ); + + // BaseCommandOptionSet interface + std::vector options() override; + void reset() override; + + RSCommonListFlags _flags; + +private: + OptCommandCtx _cmdContext = OptCommandCtx::RepoContext; +}; + +ZYPP_DECLARE_OPERATORS_FOR_FLAGS( RSCommonListOptions::RSCommonListFlags ) + + +#endif diff --git a/src/commands/services.h b/src/commands/services.h new file mode 100644 index 0000000..ce62fdf --- /dev/null +++ b/src/commands/services.h @@ -0,0 +1,10 @@ +#ifndef ZYPPER_COMMANDS_SERVICES_H_INCLUDED +#define ZYPPER_COMMANDS_SERVICES_H_INCLUDED + +#include "services/list.h" +#include "services/refresh.h" +#include "services/add.h" +#include "services/modify.h" +#include "services/remove.h" + +#endif diff --git a/src/commands/services/add.cc b/src/commands/services/add.cc new file mode 100644 index 0000000..dd39422 --- /dev/null +++ b/src/commands/services/add.cc @@ -0,0 +1,166 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#include "add.h" +#include "main.h" +#include "repos.h" +#include "Zypper.h" +#include "commands/conditions.h" +#include "utils/messages.h" +#include "utils/misc.h" +#include "utils/flags/flagtypes.h" + +#include +#include + +using namespace zypp; + +namespace { +ZyppFlags::Value CheckIsServiceTypeVal( bool &target ) +{ + return ZyppFlags::Value ( + []() -> boost::optional{ + return boost::optional(); + }, + + [ &target ]( const ZyppFlags::CommandOption &opt, const boost::optional &in ) { + if (!in) + ZYPP_THROW(ZyppFlags::MissingArgumentException(opt.name)); + + target = false; + try { + repo::ServiceType t ( *in ); + target = true; + } catch ( const repo::RepoUnknownTypeException & e ) + { } + } + ); +} + +void add_service( Zypper & zypper, const ServiceInfo & service ) +{ + RepoManager manager( zypper.globalOpts().rm_options ); + + try + { + manager.addService( service ); + } + catch ( const repo::RepoAlreadyExistsException & e ) + { + ZYPP_CAUGHT( e ); + ERR << "Service aliased '" << service.alias() << "' already exists." << endl; + zypper.out().error( str::Format(_("Service aliased '%s' already exists. Please use another alias.")) % service.alias() ); + zypper.setExitCode( ZYPPER_EXIT_ERR_ZYPP ); + return; + } + catch ( const Exception & e ) + { + ZYPP_CAUGHT( e ); + zypper.out().error( str::Format(_("Error occurred while adding service '%s'.")) % service.alias() ); + zypper.setExitCode( ZYPPER_EXIT_ERR_ZYPP ); + return; + } + + MIL << "Service '" << service.alias() << "' has been added." << endl; + zypper.out().info( str::Format(_("Service '%s' has been successfully added.")) % service.asUserString() ); +} + +// --------------------------------------------------------------------------- + +void add_service_by_url( Zypper & zypper, + const Url & url, + const std::string & alias, + const RepoServiceCommonOptions &props ) +{ + MIL << "going to add service by url (alias=" << alias << ", url=" << url << ")" << endl; + + ServiceInfo service; + + service.setAlias( alias.empty() ? timestamp() : alias ); + parsed_opts::const_iterator it = zypper.cOpts().find("name"); + if ( !props._name.empty() ) + service.setName( props._name ); + service.setUrl( url ); + + std::cout << "Setting new service " << alias << asString(props._enable) << " " << asString(props._enableAutoRefresh) << endl; + + service.setEnabled( indeterminate( props._enable ) ? true : bool(props._enable) ); + service.setAutorefresh( indeterminate( props._enableAutoRefresh ) ? true : bool(props._enableAutoRefresh) ); + + add_service( zypper, service ); +} + + +} + +AddServiceCmd::AddServiceCmd( const std::vector &commandAliases_r ) : + ZypperBaseCommand( + commandAliases_r, + // translators: command synopsis; do not translate lowercase words + _("addservice (as) [OPTIONS] "), + _("Add a new service."), + _("Add a repository index service to the system."), + ResetRepoManager + ) +{ + +} + +zypp::ZyppFlags::CommandGroup AddServiceCmd::cmdOptions() const +{ + return {{ + { "type", + 't', + ZyppFlags::RequiredArgument | ZyppFlags::Deprecated, + ZyppFlags::WarnOptionVal( Zypper::instance().out(), legacyCLIStr( "type", "", LegacyCLIMsgType::Ignored ), Out::NORMAL, CheckIsServiceTypeVal(const_cast(_isService))), + _("The type of service is always autodetected. This option is ignored.") + } + }}; +} + +void AddServiceCmd::doReset() +{ + _isService = true; +} + +int AddServiceCmd::execute( Zypper &zypp_r, const std::vector &positionalArgs_r ) +{ + // too many arguments + if ( positionalArgs_r.size() > 2 ) + { + report_too_many_arguments( help() ); + return ( ZYPPER_EXIT_ERR_INVALID_ARGS ); + } + + // missing arguments + if ( positionalArgs_r.size() < 2 ) + { + report_required_arg_missing( zypp_r.out(), help() ); + return ( ZYPPER_EXIT_ERR_INVALID_ARGS ); + } + + Url url = make_url( positionalArgs_r[0] ); + if ( !url.isValid() ) { + return( ZYPPER_EXIT_ERR_INVALID_ARGS ); + } + + if ( _isService ) + add_service_by_url( zypp_r, url, positionalArgs_r[1], _commonProps ); + else { + //legacy behaviour + add_repo_by_url( zypp_r, url, positionalArgs_r[1], _commonProps, RepoProperties(), false); + } + + return zypp_r.exitCode(); +} + + +std::vector AddServiceCmd::conditions() const +{ + return { + std::make_shared() + }; +} diff --git a/src/commands/services/add.h b/src/commands/services/add.h new file mode 100644 index 0000000..d51de99 --- /dev/null +++ b/src/commands/services/add.h @@ -0,0 +1,34 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#ifndef ZYPPER_COMMANDS_SERVICES_ADD_H_INCLUDED +#define ZYPPER_COMMANDS_SERVICES_ADD_H_INCLUDED + +#include "commands/basecommand.h" +#include "commands/reposerviceoptionsets.h" +#include "utils/flags/zyppflags.h" + +#include +#include + +class AddServiceCmd : public ZypperBaseCommand +{ +public: + AddServiceCmd( const std::vector &commandAliases_r ); + + // ZypperBaseCommand interface +protected: + zypp::ZyppFlags::CommandGroup cmdOptions() const override; + void doReset() override; + int execute( Zypper &zypp_r, const std::vector &positionalArgs_r ) override; + std::vector conditions() const override; + +private: + bool _isService = true; + RepoServiceCommonOptions _commonProps{ OptCommandCtx::ServiceContext, *this}; +}; + +#endif diff --git a/src/commands/services/common.cc b/src/commands/services/common.cc new file mode 100644 index 0000000..c9efb64 --- /dev/null +++ b/src/commands/services/common.cc @@ -0,0 +1,165 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ + +#include "common.h" +#include "repos.h" + +#include + +ServiceList get_all_services( Zypper & zypper ) +{ + RepoManager & manager( zypper.repoManager() ); + ServiceList services; + + try + { + // RIS type services + for_( it, manager.serviceBegin(), manager.serviceEnd() ) + { + services.insert( services.end(), ServiceInfo_Ptr( new ServiceInfo( *it ) ) ); // copy needed? + } + + // non-services repos + for_( it, manager.repoBegin(), manager.repoEnd() ) + { + if ( !it->service().empty() ) + continue; + services.insert( services.end(), RepoInfo_Ptr( new RepoInfo( *it ) ) ); // copy needed? + } + } + catch ( const Exception &e ) + { + ZYPP_CAUGHT(e); + zypper.out().error( e, _("Error reading services:") ); + exit( ZYPPER_EXIT_ERR_ZYPP ); + } + + return services; +} + +bool match_service( Zypper & zypper, std::string str, repo::RepoInfoBase_Ptr & service_ptr, bool looseAuth, bool looseQuery ) +{ + ServiceList known = get_all_services( zypper ); + bool found = false; + + unsigned number = 0; // service number start with 1 + for_( known_it, known.begin(), known.end() ) + { + ++number; + unsigned tmp = 0; + safe_lexical_cast( str, tmp ); // try to make an int out of the string + + try + { + // match by alias or number + found = (*known_it)->alias() == str || tmp == number; + + // match by URL + if ( !found ) + { + url::ViewOption urlview = url::ViewOption::DEFAULTS + url::ViewOption::WITH_PASSWORD; + if ( looseAuth )//zypper.cOpts().count("loose-auth") ) + { + urlview = urlview - url::ViewOptions::WITH_PASSWORD - url::ViewOptions::WITH_USERNAME; + } + if ( looseQuery ) //zypper.cOpts().count("loose-query") ) + urlview = urlview - url::ViewOptions::WITH_QUERY_STR; + + ServiceInfo_Ptr s_ptr = dynamic_pointer_cast(*known_it); + + if ( !( urlview.has(url::ViewOptions::WITH_PASSWORD) && urlview.has(url::ViewOptions::WITH_QUERY_STR) ) ) + { + if ( s_ptr ) + found = Url(str).asString(urlview) == s_ptr->url().asString(urlview); + else + { + RepoInfo_Ptr r_ptr = dynamic_pointer_cast(*known_it); + if ( !r_ptr->baseUrlsEmpty() ) + { + for_( urlit, r_ptr->baseUrlsBegin(), r_ptr->baseUrlsEnd() ) + if ( urlit->asString(urlview) == Url(str).asString(urlview) ) + { + found = true; + break; + } + } + } + } + else + { + if ( s_ptr ) + found = ( Url(str) == s_ptr->url() ); + else + { + RepoInfo_Ptr r_ptr = dynamic_pointer_cast(*known_it); + if ( !r_ptr->baseUrlsEmpty() ) + { + found = find( r_ptr->baseUrlsBegin(), r_ptr->baseUrlsEnd(), Url(str) ) != r_ptr->baseUrlsEnd(); + } + } + } + } + if ( found ) + { + service_ptr = *known_it; + break; + } + } + catch( const url::UrlException & ) + {} + + } // END for all known services + + return found; +} + +bool refresh_service(Zypper & zypper, const ServiceInfo & service, RepoManager::RefreshServiceFlags flags_r) +{ + MIL << "going to refresh service '" << service.alias() << "'" << endl; + init_target( zypper ); // need targetDistribution for service refresh + RepoManager & manager( zypper.repoManager() ); + + bool error = true; + try + { + zypper.out().info( str::form(_("Refreshing service '%s'."), service.asUserString().c_str() ) ); + manager.refreshService( service, flags_r ); + error = false; + } + catch ( const repo::ServicePluginInformalException & e ) + { + ZYPP_CAUGHT( e ); + zypper.out().error( e, str::form(_("Problem retrieving the repository index file for service '%s':"), + service.asUserString().c_str())); + zypper.out().warning( str::form( _("Skipping service '%s' because of the above error."), + service.asUserString().c_str())); + // this is just an informal note. The service will be used as is (usually empty) + error = false; + } + catch ( const media::MediaException & e ) + { + ZYPP_CAUGHT( e ); + zypper.out().error( e, str::form(_("Problem retrieving the repository index file for service '%s':"), + service.asUserString().c_str() ), + _("Check if the URI is valid and accessible.") ); + zypper.setExitCode( ZYPPER_EXIT_ERR_ZYPP ); + } + + return error; +} + +void remove_service( Zypper & zypper, const ServiceInfo & service ) +{ + RepoManager & manager( zypper.repoManager() ); + + zypper.out().info( str::Format(_("Removing service '%s':")) % service.asUserString() ); + manager.removeService( service ); + MIL << "Service '" << service.alias() << "' has been removed." << endl; + zypper.out().info( str::Format(_("Service '%s' has been removed.")) % service.asUserString() ); +} + + diff --git a/src/commands/services/common.h b/src/commands/services/common.h new file mode 100644 index 0000000..6d4b756 --- /dev/null +++ b/src/commands/services/common.h @@ -0,0 +1,37 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#ifndef ZYPPER_COMMANDS_SERVICES_COMMON_H_INCLUDED +#define ZYPPER_COMMANDS_SERVICES_COMMON_H_INCLUDED + +#include "Zypper.h" + +#include +#include +#include + +#include + +struct RepoCollector +{ + bool collect( const zypp::RepoInfo & repo ) + { + repos.push_back( repo ); + return true; + } + RepoInfoList repos; +}; + +typedef std::list ServiceList; + +ServiceList get_all_services( Zypper & zypper ); + +bool match_service( Zypper & zypper, std::string str, repo::RepoInfoBase_Ptr & service_ptr, bool looseAuth, bool looseQuery ); +bool refresh_service(Zypper & zypper, const ServiceInfo & service, RepoManager::RefreshServiceFlags flags_r = RepoManager::RefreshServiceFlags() ); +void remove_service( Zypper & zypper, const ServiceInfo & service ); + + +#endif diff --git a/src/commands/services/list.cc b/src/commands/services/list.cc new file mode 100644 index 0000000..184da7a --- /dev/null +++ b/src/commands/services/list.cc @@ -0,0 +1,247 @@ +#include "list.h" +#include "main.h" +#include "repos.h" +#include "common.h" + +#include "utils/flags/flagtypes.h" + +using namespace zypp; + +namespace { + +void service_list_tr( Zypper & zypper, + Table & tbl, + const repo::RepoInfoBase_Ptr & srv, + unsigned reponumber, + const RSCommonListOptions::RSCommonListFlags & flags ) +{ + ServiceInfo_Ptr service = dynamic_pointer_cast(srv); + RepoInfo_Ptr repo; + if ( ! service ) + repo = dynamic_pointer_cast(srv); + + RepoGpgCheckStrings repoGpgCheck( service ? RepoGpgCheckStrings(*service) : RepoGpgCheckStrings(*repo) ); + + TableRow tr( 8 ); + + // number + if ( flags & RSCommonListOptions::ServiceRepo ) + { + if ( repo && ! repo->enabled() ) + tr << ColorString( repoGpgCheck._tagColor, "-" ).str(); + else + tr << ""; + } + else + tr << ColorString( repoGpgCheck._tagColor, str::numstring(reponumber) ).str(); + + // alias + tr << srv->alias(); + // name + tr << srv->name(); + // enabled? + tr << repoGpgCheck._enabledYN.str(); + // GPG Check + tr << repoGpgCheck._gpgCheckYN.str(); + // autorefresh? + tr << repoAutorefreshStr( *srv ); + + // priority + if ( flags & RSCommonListOptions::ShowPriority ) + { + if ( service ) + tr << ""; + else + tr << repoPriorityNumber( repo->priority(), 4 ); + } + + // type + if ( service ) + tr << service->type().asString(); + else + tr << repo->type().asString(); + + // url + if ( flags & RSCommonListOptions::ShowURI ) + { + if ( service ) + tr << service->url().asString(); + else + tr << repo->url().asString(); + } + + tbl << tr; +} + +} + +ListServicesCmd::ListServicesCmd(const std::vector &commandAliases_r) + : ZypperBaseCommand ( + commandAliases_r, + _("services (ls) [OPTIONS]"), + _("List all defined services."), + _("List defined services."), + ResetRepoManager + ) +{ + +} + +void ListServicesCmd::printServiceList( Zypper &zypp_r ) +{ + ServiceList services = get_all_services( zypp_r ); + + Table tbl; + + bool with_repos = _listOptions._flags.testFlag( RSCommonListOptions::ShowWithRepos ); + //! \todo string type = zypper.cOpts().count("type"); + + // header + { + TableHeader th; + // fixed 'zypper services' columns + th << "#" + << _("Alias") + << _("Name") + << _("Enabled") + << _("GPG Check") + // translators: 'zypper repos' column - whether autorefresh is enabled for the repository + << _("Refresh"); + // optional columns + if ( _listOptions._flags.testFlag( RSCommonListOptions::ShowPriority ) ) + // translators: repository priority (in zypper repos -p or -d) + th << _("Priority"); + th << _("Type"); + if ( _listOptions._flags.testFlag( RSCommonListOptions::ShowURI ) ) + th << _("URI"); + tbl << std::move(th); + } + + bool show_enabled_only = _listOptions._flags.testFlag( RSCommonListOptions::ShowEnabledOnly ); + + int i = 0; + for_( it, services.begin(), services.end() ) + { + ++i; // continuous numbering including skipped ones + + bool servicePrinted = false; + // Unconditionally print the service before the 1st repo is + // printed. Undesired, but possible, that a disabled service + // owns (manually) enabled repos. + if ( with_repos && dynamic_pointer_cast(*it) ) + { + RepoCollector collector; + RepoManager & rm( zypp_r.repoManager() ); + + rm.getRepositoriesInService( (*it)->alias(), + make_function_output_iterator( bind( &RepoCollector::collect, &collector, _1 ) ) ); + + for_( repoit, collector.repos.begin(), collector.repos.end() ) + { + repo::RepoInfoBase_Ptr ptr( new RepoInfo(*repoit) ); // copy needed? + + if ( show_enabled_only && !repoit->enabled() ) + continue; + + if ( !servicePrinted ) + { + service_list_tr( zypp_r, tbl, *it, i, _listOptions._flags ); + servicePrinted = true; + } + // ServiceRepo: we print repos of the current service + service_list_tr( zypp_r, tbl, ptr, i, _listOptions._flags | RSCommonListOptions::ServiceRepo ); + } + } + if ( servicePrinted ) + continue; + + // Here: No repo enforced printing the service, so do so if + // necessary. + if ( show_enabled_only && !(*it)->enabled() ) + continue; + + service_list_tr( zypp_r, tbl, *it, i, _listOptions._flags ); + } + + if ( tbl.empty() ) + zypp_r.out().info( str::form(_("No services defined. Use the '%s' command to add one or more services."), + "zypper addservice" ) ); + else + { + // sort + if ( _listOptions._flags.testFlag( RSCommonListOptions::SortByURI ) ) + { + if ( _listOptions._flags.testFlag( RSCommonListOptions::ListServiceShowAll ) ) + tbl.sort( 7 ); + else if ( _listOptions._flags.testFlag( RSCommonListOptions::ShowPriority ) ) + tbl.sort( 7 ); + else + tbl.sort( 6 ); + } +#if 0 + //BUG? This option did not exist + else if ( zypper.cOpts().count("sort-by-alias") ) + tbl.sort( 1 ); +#endif + else if ( _listOptions._flags.testFlag( RSCommonListOptions::SortByName ) ) + tbl.sort( 2 ); + else if ( _listOptions._flags.testFlag( RSCommonListOptions::SortByPrio) ) + tbl.sort( 5 ); + + // print + cout << tbl; + } +} + +void ListServicesCmd::printXMLServiceList( Zypper &zypp_r ) +{ + ServiceList services = get_all_services( zypp_r ); + + cout << "" << endl; + + ServiceInfo_Ptr s_ptr; + for_( it, services.begin(), services.end() ) + { + s_ptr = dynamic_pointer_cast(*it); + // print also service's repos + if ( s_ptr ) + { + RepoCollector collector; + RepoManager & rm( zypp_r.repoManager() ); + rm.getRepositoriesInService( (*it)->alias(), + make_function_output_iterator( bind( &RepoCollector::collect, &collector, _1 ) ) ); + std::ostringstream sout; + for_( repoit, collector.repos.begin(), collector.repos.end() ) + repoit->dumpAsXmlOn( sout ); + (*it)->dumpAsXmlOn( cout, sout.str() ); + continue; + } + + (*it)->dumpAsXmlOn( cout ); + } + + cout << "" << endl; +} + +ZyppFlags::CommandGroup ListServicesCmd::cmdOptions() const +{ + return ZyppFlags::CommandGroup(); +} + +void ListServicesCmd::doReset() +{ +} + +int ListServicesCmd::execute( Zypper &zypp_r, const std::vector &positionalArgs_r ) +{ + if ( _listOptions._flags.testFlag( RSCommonListOptions::ShowWithRepos) ) + checkIfToRefreshPluginServices( zypp_r ); + + if ( zypp_r.out().type() == Out::TYPE_XML ) { + printXMLServiceList( zypp_r ); + return ZYPPER_EXIT_OK; + } + + printServiceList( zypp_r ); + return ZYPPER_EXIT_OK; +} diff --git a/src/commands/services/list.h b/src/commands/services/list.h new file mode 100644 index 0000000..29b164e --- /dev/null +++ b/src/commands/services/list.h @@ -0,0 +1,36 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#ifndef ZYPPER_COMMANDS_SERVICES_LIST_H_INCLUDED +#define ZYPPER_COMMANDS_SERVICES_LIST_H_INCLUDED + +#include "commands/basecommand.h" +#include "commands/reposerviceoptionsets.h" +#include "utils/flags/zyppflags.h" + +#include + +class ListServicesCmd : public ZypperBaseCommand +{ +public: + ListServicesCmd ( const std::vector &commandAliases_r ); + +private: + void printServiceList ( Zypper &zypp_r ); + void printXMLServiceList ( Zypper &zypp_r ); + + // ZypperBaseCommand interface +protected: + zypp::ZyppFlags::CommandGroup cmdOptions() const override; + void doReset() override; + int execute(Zypper &zypp_r, const std::vector &positionalArgs_r) override; + +private: + RSCommonListOptions _listOptions { OptCommandCtx::ServiceContext, *this }; +}; + + +#endif diff --git a/src/commands/services/modify.cc b/src/commands/services/modify.cc new file mode 100644 index 0000000..1578f0a --- /dev/null +++ b/src/commands/services/modify.cc @@ -0,0 +1,373 @@ +#include "modify.h" +#include "Zypper.h" +#include "utils/flags/flagtypes.h" +#include "utils/messages.h" + +#include "commands/commandhelpformatter.h" +#include "commands/conditions.h" +#include "commands/services/common.h" + +#include "repos.h" + + +ModifyServiceCmd::ModifyServiceCmd( const std::vector &commandAliases_r ) + : ZypperBaseCommand( + commandAliases_r, + { + // translators: command synopsis; do not translate lowercase words + _("modifyservice (ms) "), + // translators: command synopsis; do not translate lowercase words + str::Format( _("modifyservice (ms) <%1%>") ) % "--all|--remote|--local|--medium-type" + }, + _("Modify specified service."), + str::Format(_("Modify properties of services specified by alias, number, or URI, or by the '%1%' aggregate options.") ) % "--all, --remote, --local, --medium-type", + ResetRepoManager + ) +{ + +} + +std::vector ModifyServiceCmd::conditions() const +{ + return { + std::make_shared() + }; +} + +zypp::ZyppFlags::CommandGroup ModifyServiceCmd::cmdOptions() const +{ + auto that = const_cast(this); + return { + _("Advanced:"), + { + { "ar-to-enable", 'i', ZyppFlags::RequiredArgument | ZyppFlags::Repeatable, ZyppFlags::StringVectorType( &that->_arToEnable, "ALIAS"), _("Add a RIS service repository to enable.")}, + { "ar-to-disable", 'I', ZyppFlags::RequiredArgument | ZyppFlags::Repeatable, ZyppFlags::StringVectorType( &that->_arToDisable, "ALIAS"), _("Add a RIS service repository to disable.")}, + { "rr-to-enable", 'j', ZyppFlags::RequiredArgument | ZyppFlags::Repeatable, ZyppFlags::StringVectorType( &that->_rrToEnable, "ALIAS"), _("Remove a RIS service repository to enable.")}, + { "rr-to-disable", 'J', ZyppFlags::RequiredArgument | ZyppFlags::Repeatable, ZyppFlags::StringVectorType( &that->_rrToDisable, "ALIAS"), _("Remove a RIS service repository to disable.")}, + { "cl-to-enable", 'k', ZyppFlags::NoArgument, ZyppFlags::BoolType( &that->_clearToEnable, ZyppFlags::StoreTrue), _("Clear the list of RIS repositories to enable.")}, + { "cl-to-disable", 'K', ZyppFlags::NoArgument, ZyppFlags::BoolType( &that->_clearToDisable, ZyppFlags::StoreTrue), _("Clear the list of RIS repositories to disable.")}, + //some legacy options + {"legacy-refresh", 'r', ZyppFlags::NoArgument | ZyppFlags::Hidden, ZyppFlags::TriBoolType( that->_commonProperties._enableAutoRefresh, ZyppFlags::StoreTrue ), "" }, + {"legacy-no-refresh", 'R', ZyppFlags::NoArgument | ZyppFlags::Hidden, ZyppFlags::TriBoolType( that->_commonProperties._enableAutoRefresh, ZyppFlags::StoreFalse), "" } + }}; +} + +void ModifyServiceCmd::doReset() +{ + _arToEnable.clear(); + _arToDisable.clear(); + _rrToEnable.clear(); + _rrToDisable.clear(); + _clearToEnable = false; + _clearToDisable = false; +} + +int ModifyServiceCmd::execute(Zypper &zypp_r, const std::vector &positionalArgs_r) +{ + bool non_alias = _selectOptions._all || _selectOptions._local || _selectOptions._remote || (!_selectOptions._mediumTypes.empty()); + + if ( positionalArgs_r.size() < 1 && !non_alias ) + { + // translators: aggregate option is e.g. "--all". This message will be + // followed by ms command help text which will explain it + zypp_r.out().error(_("Alias or an aggregate option is required.")); + ERR << "No alias argument given." << endl; + zypp_r.out().info( help() ); + return ZYPPER_EXIT_ERR_INVALID_ARGS; + } + // too many arguments + if ( positionalArgs_r.size() > 1 || ( positionalArgs_r.size() > 0 && non_alias ) ) + { + report_too_many_arguments( help() ); + return ZYPPER_EXIT_ERR_INVALID_ARGS; + } + + if ( non_alias ) + { + modifyServicesByOption( zypp_r ); + } + else + { + repo::RepoInfoBase_Ptr srv; + if ( match_service( zypp_r, positionalArgs_r[0], srv, false, false ) ) + { + if ( dynamic_pointer_cast(srv) ) + modifyService( zypp_r, srv->alias() ); + else { + RepoProperties rProps; + rProps.reset(); + modify_repo( zypp_r, srv->alias(), _commonProperties, rProps ); + } + } + else + { + zypp_r.out().error( str::Format(_("Service '%s' not found.")) % positionalArgs_r[0] ); + ERR << "Service " << positionalArgs_r[0] << " not found" << endl; + } + } + return zypp_r.exitCode(); +} + + +std::string ModifyServiceCmd::help() +{ + CommandHelpFormater formatter; + + formatter << ZypperBaseCommand::help(); + + formatter + .legacyOptionSection() + .legacyOption( "-r", "-f" ) + .legacyOption( "-R", "-F" ); + + return formatter; +} + + +int ModifyServiceCmd::modifyService( Zypper & zypper, const std::string & alias ) +{ + // enable/disable repo + const TriBool &enable = _commonProperties._enable; + DBG << "enable = " << enable << endl; + + // autorefresh + const TriBool &autoref = _commonProperties._enableAutoRefresh; + DBG << "autoref = " << autoref << endl; + + try + { + RepoManager & manager = zypper.repoManager(); + ServiceInfo srv( manager.getService( alias ) ); + + bool changed_enabled = false; + bool changed_autoref = false; + + if ( !indeterminate(enable) ) + { + if ( enable != srv.enabled() ) + changed_enabled = true; + srv.setEnabled( enable ); + } + + if ( !indeterminate(autoref) ) + { + if ( autoref != srv.autorefresh() ) + changed_autoref = true; + srv.setAutorefresh( autoref ); + } + + const std::string &name = _commonProperties._name; + if ( ! name.empty() ) + srv.setName( name ); + + std::set artoenable; + std::set artodisable; + std::set rrtoenable; + std::set rrtodisable; + + // RIS repos to enable + if ( _clearToEnable ) + { + rrtoenable.insert( srv.reposToEnableBegin(), srv.reposToEnableEnd() ); + srv.clearReposToEnable(); + } + else + { + for_( rit, _arToEnable.begin(), _arToEnable.end() ) + { + if ( !srv.repoToEnableFind( *rit ) ) + { + srv.addRepoToEnable( *rit ); + artoenable.insert( *rit ); + } + } + + for_( rit, _rrToEnable.begin(), _rrToEnable.end() ) + { + if ( srv.repoToEnableFind( *rit ) ) + { + srv.delRepoToEnable( *rit ); + rrtoenable.insert( *rit ); + } + } + } + + // RIS repos to disable + if ( _clearToDisable ) + { + rrtodisable.insert( srv.reposToDisableBegin(), srv.reposToDisableEnd() ); + srv.clearReposToDisable(); + } + else + { + for_( rit, _arToDisable.begin(), _arToDisable.end() ) + { + if ( !srv.repoToDisableFind( *rit ) ) + { + srv.addRepoToDisable( *rit ); + artodisable.insert( *rit ); + } + } + + for_( rit, _rrToDisable.begin(), _rrToDisable.end() ) + { + if (srv.repoToDisableFind( *rit ) ) + { + srv.delRepoToDisable( *rit ); + rrtodisable.insert( *rit ); + } + } + } + + if ( changed_enabled + || changed_autoref + || !name.empty() + || !artoenable.empty() + || !artodisable.empty() + || !rrtoenable.empty() + || !rrtodisable.empty() ) + { + manager.modifyService( alias, srv ); + + if ( changed_enabled ) + { + if ( srv.enabled() ) + zypper.out().info( str::Format(_("Service '%s' has been successfully enabled.")) % alias ); + else + zypper.out().info( str::Format(_("Service '%s' has been successfully disabled.")) % alias ); + } + + if ( changed_autoref ) + { + if ( srv.autorefresh() ) + zypper.out().info( str::Format(_("Autorefresh has been enabled for service '%s'.")) % alias ); + else + zypper.out().info( str::Format(_("Autorefresh has been disabled for service '%s'.")) % alias ); + } + + if ( !name.empty() ) + { + zypper.out().info( str::Format(_("Name of service '%s' has been set to '%s'.")) % alias % name ); + } + + if ( !artoenable.empty() ) + { + zypper.out().info( str::Format(PL_("Repository '%s' has been added to enabled repositories of service '%s'", + "Repositories '%s' have been added to enabled repositories of service '%s'", + artoenable.size())) + % str::join( artoenable.begin(), artoenable.end(), ", " ) % alias ); + } + if ( !artodisable.empty() ) + { + zypper.out().info( str::Format(PL_("Repository '%s' has been added to disabled repositories of service '%s'", + "Repositories '%s' have been added to disabled repositories of service '%s'", + artodisable.size())) + % str::join( artodisable.begin(), artodisable.end(), ", " ) % alias ); + } + if ( !rrtoenable.empty() ) + { + zypper.out().info( str::Format(PL_("Repository '%s' has been removed from enabled repositories of service '%s'", + "Repositories '%s' have been removed from enabled repositories of service '%s'", + rrtoenable.size())) + % str::join( rrtoenable.begin(), rrtoenable.end(), ", " ) % alias ); + } + if ( !rrtodisable.empty()) + { + zypper.out().info( str::Format(PL_("Repository '%s' has been removed from disabled repositories of service '%s'", + "Repositories '%s' have been removed from disabled repositories of service '%s'", + rrtodisable.size())) + % str::join( rrtodisable.begin(), rrtodisable.end(), ", " ) % alias ); + } + } + else + { + MIL << "Nothing to modify in '" << alias << "':" << srv << endl; + zypper.out().info( str::Format(_("Nothing to change for service '%s'.")) % alias ); + } + } + catch ( const Exception & ex ) + { + ERR << "Error while modifying the service:" << ex.asUserString() << endl; + zypper.out().error( ex, _("Error while modifying the service:"), + str::Format(_("Leaving service %s unchanged.")) % alias ); + return ZYPPER_EXIT_ERR_ZYPP; + } + + return ZYPPER_EXIT_OK; +} + +// --------------------------------------------------------------------------- + +void ModifyServiceCmd::modifyServicesByOption( Zypper & zypper ) +{ + ServiceList known = get_all_services( zypper ); + std::set repos_to_modify; + std::set services_to_modify; + + if ( _selectOptions._all ) + { + for_( it, known.begin(), known.end() ) + { + ServiceInfo_Ptr sptr = dynamic_pointer_cast(*it); + if ( sptr ) + modifyService( zypper, sptr->alias() ); + else { + RepoProperties rProps; + rProps.reset(); + modify_repo( zypper, (*it)->alias(), _commonProperties, rProps ); + } + } + return; + } + + bool local = _selectOptions._local; + bool remote = _selectOptions._remote; + + std::set schemes( _selectOptions._mediumTypes.begin(), _selectOptions._mediumTypes.end() ); + + for_( it, known.begin(), known.end() ) + { + ServiceInfo_Ptr sptr = dynamic_pointer_cast(*it); + Url url; + if ( sptr ) + url = sptr->url(); + else + { + RepoInfo_Ptr rptr = dynamic_pointer_cast(*it); + if ( !rptr->baseUrlsEmpty() ) + url = rptr->url(); + } + + if ( url.isValid() ) + { + bool modify = false; + if ( local && ! url.schemeIsDownloading() ) + modify = true; + + if ( !modify && remote && url.schemeIsDownloading() ) + modify = true; + + if ( !modify && schemes.find(url.getScheme()) != schemes.end() ) + modify = true; + + if ( modify ) + { + std::string alias = (*it)->alias(); + if ( sptr ) + services_to_modify.insert( alias ); + else + repos_to_modify.insert( alias ); + } + } + else + WAR << "got invalid url: " << url.asString() << endl; + } + + for_( it, services_to_modify.begin(), services_to_modify.end() ) + modifyService( zypper, *it ); + + RepoProperties rProps; + rProps.reset(); + for_( it, repos_to_modify.begin(), repos_to_modify.end() ) + modify_repo( zypper, *it, _commonProperties, rProps ); +} diff --git a/src/commands/services/modify.h b/src/commands/services/modify.h new file mode 100644 index 0000000..0c55e01 --- /dev/null +++ b/src/commands/services/modify.h @@ -0,0 +1,45 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#ifndef ZYPPER_COMMANDS_SERVICES_MODIFY_H_INCLUDED +#define ZYPPER_COMMANDS_SERVICES_MODIFY_H_INCLUDED + +#include "commands/basecommand.h" +#include "commands/reposerviceoptionsets.h" +#include "utils/flags/zyppflags.h" + +#include + +class ModifyServiceCmd : public ZypperBaseCommand +{ +public: + ModifyServiceCmd( const std::vector &commandAliases_r ); + + // ZypperBaseCommand interface + std::string help() override; + +protected: + std::vector conditions() const override; + zypp::ZyppFlags::CommandGroup cmdOptions() const override; + void doReset() override; + int execute(Zypper &zypp_r, const std::vector &positionalArgs_r) override; + +private: + int modifyService( Zypper & zypper, const std::string & alias ); + void modifyServicesByOption( Zypper & zypper ); + +private: + std::vector _arToEnable; + std::vector _arToDisable; + std::vector _rrToEnable; + std::vector _rrToDisable; + bool _clearToEnable = false; + bool _clearToDisable = false; + RepoServiceCommonOptions _commonProperties { OptCommandCtx::ServiceContext, *this }; + RepoServiceCommonSelectOptions _selectOptions { OptCommandCtx::ServiceContext, *this }; +}; + +#endif diff --git a/src/commands/services/refresh.cc b/src/commands/services/refresh.cc new file mode 100644 index 0000000..c06a5c9 --- /dev/null +++ b/src/commands/services/refresh.cc @@ -0,0 +1,289 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#include "refresh.h" +#include "main.h" +#include "Zypper.h" +#include "repos.h" + +#include "common.h" +#include "utils/flags/flagtypes.h" +#include "commands/repos/refresh.h" +#include "commands/conditions.h" + +#include +#include +#include + +using namespace zypp; + +/** + * Try to find ServiceInfo or RepoInfo counterparts among known services by alias, number, + * or URI, based on the list of strings given as the iterator range \a begin and + * \a end. Matching objects will be added to \a services (as RepoInfoBase_Ptr) and those + * with no match will be added to \a not_found. + */ +template +void get_services( Zypper & zypper, const T & begin, const T & end, + ServiceList & services, std::list & not_found ) +{ + for_( it, begin, end ) + { + repo::RepoInfoBase_Ptr service; + + if ( !match_service( zypper, *it, service, false, false ) ) + { + not_found.push_back( *it ); + continue; + } + + // service found + // is it a duplicate? compare by alias and URIs + //! \todo operator== in RepoInfo? + bool duplicate = false; + for_( serv_it, services.begin(), services.end() ) + { + ServiceInfo_Ptr s_ptr = dynamic_pointer_cast(*serv_it); + ServiceInfo_Ptr current_service_ptr = dynamic_pointer_cast(service); + + // one is a service, the other is a repo + if ( s_ptr && !current_service_ptr ) + continue; + + // service + if ( s_ptr ) + { + if ( s_ptr->alias() == current_service_ptr->alias() + && s_ptr->url() == current_service_ptr->url() ) + { + duplicate = true; + break; + } + } + // repo + else if ( repo_cmp_alias_urls( *dynamic_pointer_cast(service), + *dynamic_pointer_cast(*serv_it) ) ) + { + duplicate = true; + break; + } + } // END for all found so far + + if ( !duplicate ) + services.push_back( service ); + } +} + +/** + * Say "Service %s not found" for all strings in \a not_found list. + */ +static void report_unknown_services( Out & out, std::list not_found ) +{ + for_( it, not_found.begin(), not_found.end() ) + out.error( str::Format(_("Service '%s' not found by its alias, number, or URI.")) % *it ); + + if ( !not_found.empty() ) + out.info( str::Format(_("Use '%s' to get the list of defined services.")) % "zypper repos" ); +} + +RefreshServicesCmd::RefreshServicesCmd( const std::vector &commandAliases_r ) : + ZypperBaseCommand( + commandAliases_r, + _("refresh-services (refs) [OPTIONS]"), + _("Refresh all services."), + _("Refresh defined repository index services.")) +{ + +} + +std::vector RefreshServicesCmd::conditions() const +{ + return { + std::make_shared() + }; +} + +ZyppFlags::CommandGroup RefreshServicesCmd::cmdOptions() const +{ + auto that = const_cast(this); + return {{ + { "force", 'f', ZyppFlags::NoArgument, ZyppFlags::BoolType( &that->_force, ZyppFlags::StoreTrue, _force), _("Force a complete refresh.") }, + { "with-repos", 'r', ZyppFlags::NoArgument, ZyppFlags::BoolType( &that->_withRepos, ZyppFlags::StoreTrue, _withRepos), _("Refresh also the service repositories.") }, + { "restore-status", 'R', ZyppFlags::NoArgument, ZyppFlags::BoolType( &that->_restoreStatus, ZyppFlags::StoreTrue, _restoreStatus), _("Also restore service repositories enabled/disabled state.") } + }}; +} + +void RefreshServicesCmd::doReset() +{ + _force = false; + _withRepos = false; + _restoreStatus = false; +} + +int RefreshServicesCmd::execute( Zypper &zypper, const std::vector &positionalArgs ) +{ + return refreshServices( zypper ); +} + +int RefreshServicesCmd::refreshServices( Zypper &zypper ) +{ + MIL << "going to refresh services" << endl; + + ServiceList services = get_all_services( zypper ); + + // get the list of repos specified on the command line ... + ServiceList specified; + std::list not_found; + // ...as command arguments + get_services( zypper, zypper.arguments().begin(), zypper.arguments().end(), specified, not_found ); + report_unknown_services( zypper.out(), not_found ) ; + + unsigned error_count = 0; + unsigned enabled_service_count = services.size(); + + if ( !specified.empty() || not_found.empty() ) + { + unsigned number = 0; + for_( sit, services.begin(), services.end() ) + { + ++number; + repo::RepoInfoBase_Ptr service_ptr( *sit ); + + // skip services not specified on the command line + if ( !specified.empty() ) + { + bool found = false; + for_( it, specified.begin(), specified.end() ) + if ( (*it)->alias() == service_ptr->alias() ) + { + found = true; + break; + } + + if ( !found ) + { + DBG << service_ptr->alias() << "(#" << number << ") not specified," << " skipping." << endl; + --enabled_service_count; + continue; + } + } + + // skip disabled services + if ( !service_ptr->enabled() ) + { + DBG << "skipping disabled service '" << service_ptr->alias() << "'" << endl; + + std::string msg = str::Format(_("Skipping disabled service '%s'")) % service_ptr->asUserString(); + if ( specified.empty() ) + zypper.out().info( msg, Out::HIGH ); + else + zypper.out().error( msg ); + + --enabled_service_count; + continue; + } + + // do the refresh + bool error = false; + ServiceInfo_Ptr s = dynamic_pointer_cast(service_ptr); + if ( s ) + { + RepoManager::RefreshServiceOptions opts; + if ( _restoreStatus ) + opts |= RepoManager::RefreshService_restoreStatus; + if ( _force ) + opts |= RepoManager::RefreshService_forceRefresh; + + error = refresh_service( zypper, *s, opts ); + + // refresh also service's repos + if ( _withRepos ) + { + RepoCollector collector; + RepoManager & rm = zypper.repoManager(); + rm.getRepositoriesInService( s->alias(), + make_function_output_iterator( bind( &RepoCollector::collect, &collector, _1 ) ) ); + for_( repoit, collector.repos.begin(), collector.repos.end() ) + RefreshRepoCmd::refreshRepository( zypper, *repoit, _force ? RefreshRepoCmd::Force : RefreshRepoCmd::Default ); + } + } + else + { + if ( !_withRepos ) + { + DBG << "Skipping non-index service '" << service_ptr->asUserString() << "' because '--no-repos' is used."; + continue; + } + error = RefreshRepoCmd::refreshRepository( zypper, *dynamic_pointer_cast(service_ptr), _force ? RefreshRepoCmd::Force : RefreshRepoCmd::Default ); + } + + if ( error ) + { + ERR << "Skipping service '" << service_ptr->alias() << "' because of the above error." << endl; + zypper.out().error( str::Format(_("Skipping service '%s' because of the above error.")) % service_ptr->asUserString().c_str() ); + ++error_count; + } + } + } + else + enabled_service_count = 0; + + // print the result message + if ( enabled_service_count == 0 ) + { + std::string hint = str::form(_("Use '%s' or '%s' commands to add or enable services."), + "zypper addservice", "zypper modifyservice" ); + if ( !specified.empty() || !not_found.empty() ) + zypper.out().error(_("Specified services are not enabled or defined."), hint); + else + zypper.out().error(_("There are no enabled services defined."), hint); + } + else if ( error_count == enabled_service_count ) + { + zypper.out().error(_("Could not refresh the services because of errors.") ); + return ZYPPER_EXIT_ERR_ZYPP; + } + else if ( error_count ) + { + zypper.out().error(_("Some of the services have not been refreshed because of an error.") ); + return ZYPPER_EXIT_ERR_ZYPP; + } + else if ( !specified.empty() ) + zypper.out().info(_("Specified services have been refreshed.") ); + else + zypper.out().info(_("All services have been refreshed.") ); + + MIL << "DONE"; + return ZYPPER_EXIT_OK; +} + + +int RefreshServicesCmd::systemSetup(Zypper &zypp_r) +{ + int code = defaultSystemSetup( zypp_r, InitTarget ); + if ( code != ZYPPER_EXIT_OK ) + return code; + + zypp_r.globalOptsNoConst().rm_options.servicesTargetDistro = + zyppApi()->target()->targetDistribution(); + + return defaultSystemSetup( zypp_r, ResetRepoManager ); +} + +void RefreshServicesCmd::setRestoreStatus(bool restoreStatus) +{ + _restoreStatus = restoreStatus; +} + +void RefreshServicesCmd::setWithRepos(bool withRepos) +{ + _withRepos = withRepos; +} + +void RefreshServicesCmd::setForce(bool force) +{ + _force = force; +} diff --git a/src/commands/services/refresh.h b/src/commands/services/refresh.h new file mode 100644 index 0000000..da4c286 --- /dev/null +++ b/src/commands/services/refresh.h @@ -0,0 +1,41 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#ifndef ZYPPER_COMMANDS_SERVICES_REFRESH_H_INCLUDED +#define ZYPPER_COMMANDS_SERVICES_REFRESH_H_INCLUDED + +#include "commands/basecommand.h" +#include "utils/flags/zyppflags.h" + +#include + +class RefreshServicesCmd : public ZypperBaseCommand +{ + +public: + RefreshServicesCmd ( const std::vector &commandAliases_r ); + + int refreshServices ( Zypper &zypper ); + + void setForce(bool force); + void setWithRepos(bool withRepos); + void setRestoreStatus(bool restoreStatus); + + // ZypperBaseCommand interface +protected: + std::vector conditions() const override; + zypp::ZyppFlags::CommandGroup cmdOptions() const override; + void doReset() override; + int execute(Zypper &zypper, const std::vector &positionalArgs) override; + int systemSetup(Zypper &zypp_r) override; + +private: + bool _force = false; + bool _withRepos = false; + bool _restoreStatus = false; +}; + +#endif diff --git a/src/commands/services/remove.cc b/src/commands/services/remove.cc new file mode 100644 index 0000000..228f8ac --- /dev/null +++ b/src/commands/services/remove.cc @@ -0,0 +1,89 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#include "remove.h" +#include "repos.h" + +#include "commands/conditions.h" +#include "commands/services/common.h" + +#include "utils/misc.h" +#include "utils/messages.h" +#include "utils/flags/flagtypes.h" + +RemoveServiceCmd::RemoveServiceCmd(const std::vector &commandAliases_r) + : ZypperBaseCommand ( + commandAliases_r, + _("removeservice (rs) [OPTIONS] "), + _("Remove specified service."), + _("Remove specified repository index service from the system."), + ResetRepoManager + ) +{ } + +std::vector RemoveServiceCmd::conditions() const +{ + return { + std::make_shared() + }; +} + +zypp::ZyppFlags::CommandGroup RemoveServiceCmd::cmdOptions() const +{ + auto that = const_cast(this); + return {{{ + { "loose-auth", '\0', ZyppFlags::NoArgument, ZyppFlags::BoolType( &that->_looseAuth, ZyppFlags::StoreTrue), + // translators: --loose-auth + _("Ignore user authentication data in the URI.") + },{ "loose-query", '\0', ZyppFlags::NoArgument, ZyppFlags::BoolType( &that->_looseQuery, ZyppFlags::StoreTrue), + // translators: --loose-query + _("Ignore query string in the URI.") + } + }}}; +} + +void RemoveServiceCmd::doReset() +{ + _looseAuth = false; + _looseQuery = false; +} + +int RemoveServiceCmd::execute(Zypper &zypp, const std::vector &positionalArgs) +{ + if ( positionalArgs.size() < 1) + { + ERR << "Required argument missing." << endl; + report_required_arg_missing( zypp.out(), help() ); + return ZYPPER_EXIT_ERR_INVALID_ARGS; + } + + std::set to_remove; + for_(it, positionalArgs.begin(), positionalArgs.end()) + { + repo::RepoInfoBase_Ptr s; + if (match_service( zypp, *it, s, _looseAuth, _looseQuery)) + { + to_remove.insert(s); + } + else + { + MIL << "Service not found by given alias, number or URI." << endl; + // translators: %s is the supplied command line argument which + // for which no service counterpart was found + zypp.out().error( str::Format(_("Service '%s' not found by alias, number or URI.")) % *it ); + } + } + + for_(it, to_remove.begin(), to_remove.end()) + { + RepoInfo_Ptr repo_ptr = dynamic_pointer_cast(*it); + if (repo_ptr) + remove_repo(zypp, *repo_ptr); + else + remove_service(zypp, *dynamic_pointer_cast(*it)); + } + return ZYPPER_EXIT_OK; +} diff --git a/src/commands/services/remove.h b/src/commands/services/remove.h new file mode 100644 index 0000000..7d50c48 --- /dev/null +++ b/src/commands/services/remove.h @@ -0,0 +1,31 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#ifndef ZYPPER_COMMANDS_SERVICES_REMOVE_H_INCLUDED +#define ZYPPER_COMMANDS_SERVICES_REMOVE_H_INCLUDED + +#include "commands/basecommand.h" +#include "utils/flags/zyppflags.h" + +#include + +class RemoveServiceCmd : public ZypperBaseCommand +{ +public: + RemoveServiceCmd( const std::vector &commandAliases_r ); + // ZypperBaseCommand interface +protected: + std::vector conditions() const override; + zypp::ZyppFlags::CommandGroup cmdOptions() const override; + void doReset() override; + int execute(Zypper &zypp, const std::vector &positionalArgs) override; + +private: + bool _looseAuth = false; + bool _looseQuery = false; +}; + +#endif diff --git a/src/locks.cc b/src/locks.cc deleted file mode 100644 index b039177..0000000 --- a/src/locks.cc +++ /dev/null @@ -1,163 +0,0 @@ -#include -#include - -#include -#include -#include - -#include "output/Out.h" -#include "main.h" -#include "Table.h" -#include "utils/misc.h" -#include "locks.h" -#include "repos.h" - -using namespace zypp; - - -template -void safe_lexical_cast (Source s, Target &tr) { - try { - tr = boost::lexical_cast (s); - } - catch (boost::bad_lexical_cast &) { - } -} - -void add_locks(Zypper & zypper, const Zypper::ArgList & args, const ResKindSet & kinds) -{ - try - { - Locks & locks = Locks::instance(); - locks.read(Pathname::assertprefix - (zypper.globalOpts().root_dir, ZConfig::instance().locksFile())); - Locks::size_type start = locks.size(); - for_(it,args.begin(),args.end()) - { - PoolQuery q; - if ( kinds.empty() ) // derive it from the name - { - sat::Solvable::SplitIdent split( *it ); - q.addAttribute( sat::SolvAttr::name, split.name().asString() ); - q.addKind( split.kind() ); - } - else - { - q.addAttribute(sat::SolvAttr::name, *it); - for_(itk, kinds.begin(), kinds.end()) { - q.addKind(*itk); - } - } - q.setMatchGlob(); - parsed_opts::const_iterator itr; - //TODO rug compatibility for more arguments with version restrict - if ((itr = copts.find("repo")) != copts.end()) - { - for_(it_repo,itr->second.begin(), itr->second.end()) - { - RepoInfo info; - if( match_repo( zypper, *it_repo, &info)) - q.addRepo(info.alias()); - else //TODO some error handling - WAR << "unknown repository" << *it_repo << endl; - } - } - q.setCaseSensitive(); - - locks.addLock(q); - } - locks.save(Pathname::assertprefix - (zypper.globalOpts().root_dir, ZConfig::instance().locksFile())); - if ( start != Locks::instance().size() ) - zypper.out().info(PL_( - "Specified lock has been successfully added.", - "Specified locks have been successfully added.", - Locks::instance().size() - start)); - } - catch(const Exception & e) - { - ZYPP_CAUGHT(e); - zypper.out().error(e, _("Problem adding the package lock:")); - zypper.setExitCode(ZYPPER_EXIT_ERR_ZYPP); - } -} - - -void remove_locks(Zypper & zypper, const Zypper::ArgList & args, const ResKindSet & kinds) -{ - try - { - Locks & locks = Locks::instance(); - locks.read(Pathname::assertprefix - (zypper.globalOpts().root_dir, ZConfig::instance().locksFile())); - Locks::size_type start = locks.size(); - for_( args_it, args.begin(), args.end() ) - { - Locks::const_iterator it = locks.begin(); - Locks::LockList::size_type i = 0; - safe_lexical_cast(*args_it, i); - if (i > 0 && i <= locks.size()) - { - advance(it, i-1); - locks.removeLock(*it); - - zypper.out().info(_("Specified lock has been successfully removed.")); - } - else //package name - { - //TODO fill query in one method to have consistent add/remove - //TODO what to do with repo and kinds? - PoolQuery q; - if ( kinds.empty() ) // derive it from the name - { - // derive kind from the name: (rl should also support -t) - sat::Solvable::SplitIdent split( *args_it ); - q.addAttribute( sat::SolvAttr::name, split.name().asString() ); - q.addKind( split.kind() ); - } - else - { - q.addAttribute(sat::SolvAttr::name, *args_it); - for_(itk, kinds.begin(), kinds.end()) { - q.addKind(*itk); - } - } - q.setMatchGlob(); - parsed_opts::const_iterator itr; - if ((itr = copts.find("repo")) != copts.end()) - { - for_(it_repo,itr->second.begin(), itr->second.end()) - { - RepoInfo info; - if( match_repo( zypper, *it_repo, &info)) - q.addRepo(info.alias()); - else //TODO some error handling - WAR << "unknown repository" << *it_repo << endl; - } - } - q.setCaseSensitive(); - - locks.removeLock(q); - } - } - - locks.save(Pathname::assertprefix - (zypper.globalOpts().root_dir, ZConfig::instance().locksFile())); - - // nothing removed - if (start == locks.size()) - zypper.out().info(_("No lock has been removed.")); - //removed something - else - zypper.out().info(str::form(PL_( - "%zu lock has been successfully removed.", - "%zu locks have been successfully removed.", - start - locks.size()), start - locks.size())); - } - catch(const Exception & e) - { - ZYPP_CAUGHT(e); - zypper.out().error(e, _("Problem removing the package lock:")); - zypper.setExitCode(ZYPPER_EXIT_ERR_ZYPP); - } -} diff --git a/src/locks.h b/src/locks.h deleted file mode 100644 index d4f4ab1..0000000 --- a/src/locks.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef ZYPPERLOCKS_H_ -#define ZYPPERLOCKS_H_ - -#include "Zypper.h" - -void add_locks(Zypper & zypper, const Zypper::ArgList & args, const ResKindSet & kinds); -void remove_locks(Zypper & zypper, const Zypper::ArgList & args, const ResKindSet & kinds); - -#endif /*ZYPPERLOCKS_H_*/ diff --git a/src/ps.cc b/src/ps.cc deleted file mode 100644 index 13cc763..0000000 --- a/src/ps.cc +++ /dev/null @@ -1,188 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ____ _ _ __ _ __ ___ _ _ - |_ / || | '_ \ '_ \/ -_) '_| - /__|\_, | .__/ .__/\___|_| - |__/|_| |_| -\*---------------------------------------------------------------------------*/ - -#include - -#include -#include -#include - -#include "Zypper.h" -#include "Table.h" -#include "ps.h" - -/////////////////////////////////////////////////////////////////// -// PsOptions -/////////////////////////////////////////////////////////////////// - -inline std::ostream & operator<<( std::ostream & str, const PsOptions & obj ) -{ return str << "PsOptions"; } - -/////////////////////////////////////////////////////////////////// -namespace -{ - /////////////////////////////////////////////////////////////////// - /// \class PsImpl - /// \brief Implementation of ps - /////////////////////////////////////////////////////////////////// - class PsImpl : public CommandBase - { - typedef CommandBase CommandBase; - public: - PsImpl( Zypper & zypper_r ) : CommandBase( zypper_r ) {} - // CommandBase::_zypper - // CommandBase::options; // access/manip command options - // CommandBase::run; // action + catch and repost Out::Error - // CommandBase::execute; // run + final "Done"/"Finished with error" message - // CommandBase::showHelp; // Show user help on command - public: - /** default action */ - void action(); - - private: - void printServiceNamesOnly(); - }; - /////////////////////////////////////////////////////////////////// - - inline void loadData( CheckAccessDeleted & checker_r ) - { - try - { - checker_r.check(); - } - catch ( const Exception & ex ) - { - throw( Out::Error( ZYPPER_EXIT_ERR_ZYPP, _("Check failed:"), ex ) ); - } - } - - void PsImpl::printServiceNamesOnly() - { - CheckAccessDeleted checker( false ); // wait for explicit call to check() - loadData( checker ); - - std::set services; - for ( const auto & procInfo : checker ) - { - std::string service( procInfo.service() ); - if ( ! service.empty() ) - services.insert( std::move(service) ); - } - - const std::string & format( options()._format ); - if ( format.empty() || format == "%s" ) - { - for ( const auto & service : services ) - { cout << service << endl; } - } - else - { - for ( const auto & service : services ) - { cout << str::gsub( format, "%s", service ) << endl; } - } - } - - /** - * fate #300763 - * Used by 'zypper ps' to show running processes that use - * libraries or other files that have been removed since their execution. - * This is particularly useful after 'zypper remove' or 'zypper update'. - */ - void PsImpl::action() - { - if ( options().printServiceNamesOnly() ) - { - // non table output of service names only - return printServiceNamesOnly(); - } - - // Here: Table output - _zypper.out().info(_("Checking for running processes using deleted libraries..."), Out::HIGH ); - CheckAccessDeleted checker( false ); // wait for explicit call to check() - - if(options().debugEnabled()) - checker.setDebugOutputFile(options()._debugFile); - - loadData( checker ); - - Table t; - bool tableWithFiles = options().tableWithFiles(); - bool tableWithNonServiceProcs = options().tableWithNonServiceProcs(); - t.allowAbbrev(6); - { - TableHeader th; - // process ID - th << _("PID") - // parent process ID - << _("PPID") - // process user ID - << _("UID") - // process login name - << _("User") - // process command name - << _("Command") - // "/etc/init.d/ script that might be used to restart the command (guessed) - << _("Service"); - if ( tableWithFiles ) - { - // "list of deleted files or libraries accessed" - th << _("Files"); - } - t << std::move(th); - } - - for ( const auto & procInfo : checker ) - { - std::string service( procInfo.service() ); - if ( ! tableWithNonServiceProcs && service.empty() ) - continue; - - TableRow tr; - tr << procInfo.pid << procInfo.ppid << procInfo.puid << procInfo.login << procInfo.command << std::move(service); - - if ( tableWithFiles ) - { - std::vector::const_iterator fit = procInfo.files.begin(); - tr << (fit != procInfo.files.end() ? *fit : ""); - t << std::move(tr); - - for ( ++fit; fit != procInfo.files.end(); ++fit ) - { t << ( TableRow() << "" << "" << "" << "" << "" << "" << *fit ); } - } - else - { - t << std::move(tr); - } - } - - if ( t.empty() ) - { - _zypper.out().info(_("No processes using deleted files found.") ); - } - else - { - _zypper.out().info(_("The following running processes use deleted files:") ); - cout << endl; - cout << t << endl; - _zypper.out().info(_("You may wish to restart these processes.") ); - _zypper.out().info( str::form( _("See '%s' for information about the meaning of values in the above table."), - "man zypper" ) ); - } - - if ( geteuid() != 0 ) - { - _zypper.out().info(""); - _zypper.out().info(_("Note: Not running as root you are limited to searching for files you have permission to examine with the system stat(2) function. The result might be incomplete.")); - } - } -} // namespace -/////////////////////////////////////////////////////////////////// - -int ps( Zypper & zypper_r ) -{ - return PsImpl( zypper_r ).run(); // no final "Done"/"Finished with error." message! -} diff --git a/src/ps.h b/src/ps.h deleted file mode 100644 index 6d806c6..0000000 --- a/src/ps.h +++ /dev/null @@ -1,38 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ____ _ _ __ _ __ ___ _ _ - |_ / || | '_ \ '_ \/ -_) '_| - /__|\_, | .__/ .__/\___|_| - |__/|_| |_| -\*---------------------------------------------------------------------------*/ -#ifndef ZYPPER_PS_H -#define ZYPPER_PS_H - -#include -class Zypper; - -/* - ps ... -*/ - -/** ps specific options */ -struct PsOptions : public MixinOptions -{ - PsOptions() - : _shortness( 0 ) - {} - - unsigned _shortness; //< 1:wo file, 2:only proc with services, 3:service names only - std::string _format; //< format string for --print / shortness 3 - std::string _debugFile; //< file name for the --debugFile switch - - bool tableWithFiles() const { return _shortness < 1; } - bool tableWithNonServiceProcs() const { return _shortness < 2; } - bool printServiceNamesOnly() const { return _shortness >= 3; } - bool debugEnabled() const {return (!_debugFile.empty());} -}; - -/** Execute ps. - */ -int ps( Zypper & zypper_r ); - -#endif // ZYPPER_PS_H diff --git a/src/repos.cc b/src/repos.cc index afc7313..205466f 100644 --- a/src/repos.cc +++ b/src/repos.cc @@ -10,8 +10,6 @@ #include #include -#include - #include #include #include @@ -32,14 +30,17 @@ #include "utils/misc.h" #include "repos.h" +//@TODO REMOVEME +#include "commands/services/common.h" + extern ZYpp::Ptr God; namespace zypp { using repo::RepoInfoBase_Ptr; } typedef std::list ServiceList; typedef std::set RepoInfoSet; -static bool refresh_service( Zypper & zypper, const ServiceInfo & service ); -static RepoInfoSet collect_repos_by_option( Zypper & zypper ); +static RepoInfoSet collect_repos_by_option( Zypper & zypper, const RepoServiceCommonSelectOptions &selectOpts ); + // ---------------------------------------------------------------------------- @@ -72,15 +73,15 @@ inline std::string repoPriorityAnnotationStr( unsigned prio_r ) return( prio_r < RepoInfo::defaultPriority() ? _("raised priority") : _("lowered priority") ); } -inline ColorString repoPriorityNumber( unsigned prio_r, int width_r = 0 ) +ColorString repoPriorityNumber( unsigned prio_r, int width_r ) { return ColorString( repoPriorityColor( prio_r ), str::numstring( prio_r, width_r ) ); } -inline ColorString repoPriorityNumberAnnotated( unsigned prio_r, int width_r = 0 ) +ColorString repoPriorityNumberAnnotated( unsigned prio_r, int width_r ) { return repoPriorityNumber( prio_r, width_r ) << " (" << repoPriorityAnnotationStr( prio_r ) << ")"; } // ---------------------------------------------------------------------------- -inline const char * repoAutorefreshStr( const repo::RepoInfoBase & repo_r ) +const char * repoAutorefreshStr( const repo::RepoInfoBase & repo_r ) { static std::string dashes( LOWLIGHTString( "----" ).str() ); return( repo_r.enabled() ? asYesNo( repo_r.autorefresh() ) : dashes.c_str() ); @@ -88,101 +89,76 @@ inline const char * repoAutorefreshStr( const repo::RepoInfoBase & repo_r ) // ---------------------------------------------------------------------------- -template -void safe_lexical_cast( Source s, Target & tr ) -{ - try - { - tr = boost::lexical_cast( s ); - } - catch ( boost::bad_lexical_cast & ) - {;} -} - -unsigned parse_priority( Zypper & zypper ) +unsigned parse_priority( const std::string &prio_r, std::string &error_r ) { //! \todo use some preset priorities (high, medium, low, ...) unsigned ret = 0U; - parsed_opts::const_iterator cArg = zypper.cOpts().find( "priority" ); - if ( cArg == zypper.cOpts().end() ) + + if ( prio_r.empty() ) return ret; // 0: no --priority arg int prio = -1; - std::string prio_str = *cArg->second.begin(); - safe_lexical_cast( prio_str, prio ); // try to make an int out of the string + safe_lexical_cast( prio_r, prio ); // try to make an int out of the string if ( prio < 0 ) { - zypper.out().error( + error_r = str::Format(_("Invalid priority '%s'. Use a positive integer number. The greater the number, the lower the priority.")) - % prio_str - ); - zypper.setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - ZYPP_THROW( ExitRequestException("Invalid priority.") ); + % prio_r; + ZYPP_THROW( Exception("Invalid priority.") ); } ret = ( prio ? unsigned(prio) : RepoInfo::defaultPriority() ); return ret; } -// | Enabled | GPG Check | Colored strings for enabled and GPG Check status -// +---------+-----------+ -// | Yes | ( ) No | -// | Yes | (rp) Yes | -// | No | ---- | -struct RepoGpgCheckStrings -{ - RepoGpgCheckStrings() +RepoGpgCheckStrings::RepoGpgCheckStrings() : _tagColor( ColorContext::DEFAULT ) - {} +{} - RepoGpgCheckStrings( const ServiceInfo & service_r ) +RepoGpgCheckStrings::RepoGpgCheckStrings(const ServiceInfo &service_r) +{ + if ( service_r.enabled() ) { - if ( service_r.enabled() ) - { - _tagColor = ColorContext::DEFAULT; - _enabledYN = ColorString( _tagColor, _("Yes") ); - _gpgCheckYN = ColorString( _tagColor, "----" ); - } - else - { - _tagColor = ColorContext::LOWLIGHT; - _enabledYN = ColorString( _tagColor, _("No") ); - _gpgCheckYN = ColorString( _tagColor, "----" ); - } + _tagColor = ColorContext::DEFAULT; + _enabledYN = ColorString( _tagColor, _("Yes") ); + _gpgCheckYN = ColorString( _tagColor, "----" ); + } + else + { + _tagColor = ColorContext::LOWLIGHT; + _enabledYN = ColorString( _tagColor, _("No") ); + _gpgCheckYN = ColorString( _tagColor, "----" ); } +} - RepoGpgCheckStrings( const RepoInfo & repo_r ) +RepoGpgCheckStrings::RepoGpgCheckStrings(const RepoInfo &repo_r) +{ + if ( repo_r.enabled() ) { - if ( repo_r.enabled() ) + bool gpgOK = false; + std::string tagStr( "( ) " ); + if ( repo_r.validRepoSignature() ) // is TriBool! { - bool gpgOK = false; - std::string tagStr( "( ) " ); - if ( repo_r.validRepoSignature() ) // is TriBool! - { - gpgOK = true; - tagStr[1] = 'r'; - } - if ( repo_r.pkgGpgCheck() ) - { - gpgOK = true; - tagStr[2] = 'p'; - } - _tagColor = gpgOK ? ColorContext::DEFAULT : ColorContext::NEGATIVE; - _enabledYN = ColorString( ColorContext::DEFAULT, _("Yes") ); - _gpgCheckYN = ColorString( _tagColor, tagStr+asYesNo(gpgOK) ); + gpgOK = true; + tagStr[1] = 'r'; } - else + if ( repo_r.pkgGpgCheck() ) { - _tagColor = ColorContext::LOWLIGHT; - _enabledYN = ColorString( _tagColor, _("No") ); - _gpgCheckYN = ColorString( _tagColor, "----" ); + gpgOK = true; + tagStr[2] = 'p'; } + _tagColor = gpgOK ? ColorContext::DEFAULT : ColorContext::NEGATIVE; + _enabledYN = ColorString( ColorContext::DEFAULT, _("Yes") ); + _gpgCheckYN = ColorString( _tagColor, tagStr+asYesNo(gpgOK) ); } - ColorContext _tagColor; ///< color according to enabled and GPG Check status - ColorString _enabledYN; ///< colored enabled Yes/No - ColorString _gpgCheckYN; ///< colored GPG Check status if enabled else "----" -}; + else + { + _tagColor = ColorContext::LOWLIGHT; + _enabledYN = ColorString( _tagColor, _("No") ); + _gpgCheckYN = ColorString( _tagColor, "----" ); + } +} void repoPrioSummary( Zypper & zypper ) { @@ -220,7 +196,7 @@ void repoPrioSummary( Zypper & zypper ) // ---------------------------------------------------------------------------- -static bool refresh_raw_metadata( Zypper & zypper, const RepoInfo & repo, bool force_download ) +bool refresh_raw_metadata( Zypper & zypper, const RepoInfo & repo, bool force_download ) { RuntimeData & gData( zypper.runtimeData() ); gData.current_repo = repo; @@ -423,7 +399,7 @@ static bool refresh_raw_metadata( Zypper & zypper, const RepoInfo & repo, bool f // --------------------------------------------------------------------------- -static bool build_cache( Zypper & zypper, const RepoInfo & repo, bool force_build ) +bool build_cache( Zypper & zypper, const RepoInfo & repo, bool force_build ) { if ( force_build ) zypper.out().info(_("Forcing building of repository cache") ); @@ -478,7 +454,7 @@ static bool build_cache( Zypper & zypper, const RepoInfo & repo, bool force_buil // --------------------------------------------------------------------------- -bool match_repo( Zypper & zypper, std::string str, RepoInfo *repo ) +bool match_repo( Zypper & zypper, std::string str, RepoInfo *repo, bool looseQuery_r, bool looseAuth_r ) { RepoManager & manager( zypper.repoManager() ); @@ -534,13 +510,13 @@ bool match_repo( Zypper & zypper, std::string str, RepoInfo *repo ) url::ViewOption urlview = url::ViewOption::DEFAULTS + url::ViewOption::WITH_PASSWORD; - if ( zypper.cOpts().count("loose-auth") ) + if ( looseAuth_r ) // ( zypper.cOpts().count("loose-auth") ) { urlview = urlview - url::ViewOptions::WITH_PASSWORD - url::ViewOptions::WITH_USERNAME; } - if ( zypper.cOpts().count("loose-query") ) + if ( looseQuery_r ) // ( zypper.cOpts().count("loose-query") ) urlview = urlview - url::ViewOptions::WITH_QUERY_STR; // need to do asString(withurlview) comparison here because the user-given @@ -597,8 +573,7 @@ bool match_repo( Zypper & zypper, std::string str, RepoInfo *repo ) // --------------------------------------------------------------------------- -/** \return true if aliases are equal, and all lhs urls can be found in rhs */ -static bool repo_cmp_alias_urls( const RepoInfo & lhs, const RepoInfo & rhs ) +bool repo_cmp_alias_urls(const RepoInfo &lhs, const RepoInfo &rhs) { bool equals = true; @@ -617,7 +592,7 @@ static bool repo_cmp_alias_urls( const RepoInfo & lhs, const RepoInfo & rhs ) { if ( std::find( rhs.baseUrlsBegin(), rhs.baseUrlsEnd(), Url(*urlit) ) != rhs.baseUrlsEnd() ) urlfound = true; - if ( !urlfound ) + if ( !urlfound ) { equals = false; break; @@ -676,11 +651,14 @@ template void get_repos::const_iterator>( Zypper &, const std::list::const_iterator &, std::list &, std::list & ); +// Explicit instantiations required for other translation units: +template void get_repos::const_iterator>( Zypper &, + const std::vector::const_iterator &, + const std::vector::const_iterator &, + std::list &, std::list & ); + // --------------------------------------------------------------------------- -/** - * Say "Repository %s not found" for all strings in \a not_found list. - */ void report_unknown_repos( Out & out, const std::list & not_found ) { if ( not_found.empty() ) @@ -739,7 +717,8 @@ void do_init_repos( Zypper & zypper, const Container & container ) { if ( s->enabled() && s->autorefresh() ) { - refresh_service(zypper, *s); + //@TODO MICHAEL is this correct? + refresh_service( zypper, *s ); } } } @@ -1015,363 +994,45 @@ void init_target( Zypper & zypper ) } } -// ---------------------------------------------------------------------------- - -static void print_repo_list( Zypper & zypper, const std::list & repos ) -{ - Table tbl; - bool all = zypper.cOpts().count("details"); - std::string list_cols = zypper.config().repo_list_columns; - bool showalias = zypper.cOpts().count("alias") - || zypper.cOpts().count("sort-by-alias") - || list_cols.find_first_of("aA") != std::string::npos; - bool showname = zypper.cOpts().count("name") - || zypper.cOpts().count("sort-by-name") - || list_cols.find_first_of("nN") != std::string::npos; - bool showrefresh = zypper.cOpts().count("refresh") - || list_cols.find_first_of("rR") != std::string::npos; - bool showuri = zypper.cOpts().count("uri") || zypper.cOpts().count("url") - || zypper.cOpts().count("sort-by-uri") - || list_cols.find_first_of("uU") != std::string::npos; - bool showprio = zypper.cOpts().count("priority") - || zypper.cOpts().count("sort-by-priority") - || list_cols.find_first_of("pP") != std::string::npos; - bool showservice = zypper.cOpts().count("service"); - bool sort_override = zypper.cOpts().count("sort-by-uri") - || zypper.cOpts().count("sort-by-priority") - || zypper.cOpts().count("sort-by-alias") - || zypper.cOpts().count("sort-by-name"); - bool show_enabled_only = zypper.cOpts().count("show-enabled-only"); - - - // header - TableHeader th; - // keep count of columns so that we know which one to sort - // TODO might be worth to improve Table to allow named columns so this can be avoided - unsigned index = 0; - // number of the column to sort by - unsigned sort_index = 0; - - // repo number - th << "#"; - - // alias - if ( all || showalias ) - { - th << _("Alias"); - ++index; - // if (zypper.cOpts().count("sort-by-alias") - // || (list_cols.find("A") != std::string::npos && !sort_override)) - // sort by alias by default - sort_index = index; - } - - // name - if ( all || showname ) - { - th << _("Name"); - ++index; - if ( zypper.cOpts().count("sort-by-name") || ( list_cols.find("N") != std::string::npos && !sort_override ) ) - sort_index = index; - } - - // 'enabled' flag - th << _("Enabled"); - ++index; - - // GPG Check - th << _("GPG Check"); - ++index; - - // 'autorefresh' flag - if ( all || showrefresh ) - { - // translators: 'zypper repos' column - whether autorefresh is enabled - // for the repository - th << _("Refresh"); - ++index; - if ( list_cols.find("R") != std::string::npos && !sort_override ) - sort_index = index; - } - - // priority - if ( all || showprio ) - { - // translators: repository priority (in zypper repos -p or -d) - th << _("Priority"); - ++index; - if ( zypper.cOpts().count("sort-by-priority") || ( list_cols.find("P") != std::string::npos && !sort_override ) ) - sort_index = Table::UserData; - } - - // type - if ( all ) - { - th << _("Type"); - ++index; - } - - // URI - if ( all || showuri ) - { - th << _("URI"); - ++index; - if ( zypper.cOpts().count("sort-by-uri") || ( list_cols.find("U") != std::string::npos && !sort_override ) ) - sort_index = index; - } - - // service alias - if ( all || showservice ) - { - th << _("Service"); - ++index; - } - - tbl << th; - - // table data - int i = 0; - unsigned nindent = repos.size() > 9 ? repos.size() > 99 ? 3 : 2 : 1; - for_( it, repos.begin(), repos.end() ) - { - ++i; // continuous numbering including skipped ones - RepoInfo repo = *it; - - if ( show_enabled_only && !repo.enabled() ) - continue; - - TableRow tr( index ); - RepoGpgCheckStrings repoGpgCheck( repo ); // color strings for tag/enabled/gpgcheck - - // number - tr << ColorString( repoGpgCheck._tagColor, str::numstring( i, nindent ) ).str(); - // alias - if ( all || showalias ) tr << repo.alias(); - // name - if ( all || showname ) tr << repo.name(); - // enabled? - tr << repoGpgCheck._enabledYN.str(); - // GPG Check - tr << repoGpgCheck._gpgCheckYN.str(); - // autorefresh? - if ( all || showrefresh ) - tr << repoAutorefreshStr( repo ); - // priority - if ( all || showprio ) - // output flush right; use custom sort index as coloring will break lex. sort - ( tr << repoPriorityNumber( repo.priority(), 4 ) ).userData( repo.priority() ); - // type - if ( all ) - tr << repo.type().asString(); - // url - /** - * \todo properly handle multiple baseurls - show "(multiple)" - */ - if ( all || showuri ) - tr << (repo.baseUrlSet() ? repo.url().asString() : (repo.mirrorListUrl().asString().empty() ? "n/a" : repo.mirrorListUrl().asString()) ); - - if ( all || showservice ) - tr << repo.service(); - - tbl << tr; - } - - if ( tbl.empty() ) - { - zypper.out().warning(_("No repositories defined.") ); - zypper.out().info(_("Use the 'zypper addrepo' command to add one or more repositories.") ); - } - else - { - if ( !showprio ) - { - repoPrioSummary( zypper ); - zypper.out().gap(); - } - // sort - tbl.sort( sort_index ); - // print - cout << tbl; - } -} - -// ---------------------------------------------------------------------------- - -static void print_repo_details( Zypper & zypper, std::list & repos ) -{ - bool first = true; - for_( it, repos.begin(), repos.end() ) - { - const RepoInfo & repo( *it ); - - PropertyTable p; - RepoGpgCheckStrings repoGpgCheck( repo ); - - p.add( _("Alias"), repo.alias() ); - p.add( _("Name"), repo.name() ); - p.add( _("URI"), (repo.baseUrlSet() - ? repo.url().asString() - : (repo.mirrorListUrl().asString().empty() - ? "n/a" - : repo.mirrorListUrl().asString())) ); - p.add( _("Enabled"), repoGpgCheck._enabledYN.str() ); - p.add( _("GPG Check"), repoGpgCheck._gpgCheckYN.str() ); - p.add( _("Priority"), repoPriorityNumberAnnotated( repo.priority() ) ); - p.add( _("Autorefresh"), (repo.autorefresh() ? _("On") : _("Off")) ); - p.add( _("Keep Packages"), (repo.keepPackages() ? _("On") : _("Off")) ); - p.add( _("Type"), repo.type().asString() ); - p.add( _("GPG Key URI"), repo.gpgKeyUrl() ); - p.add( _("Path Prefix"), repo.path() ); - p.add( _("Parent Service"), repo.service() ); - p.lst( _("Keywords"), repo.contentKeywords() ); - p.add( _("Repo Info Path"), repo.filepath() ); - p.add( _("MD Cache Path"), repo.metadataPath() ); - - - if ( first ) - first = false; - else - cout << endl; - cout << p; - } -} - -// ---------------------------------------------------------------------------- - -/** Repo list as xml */ -static void print_xml_repo_list( Zypper & zypper, std::list repos ) -{ - cout << "" << endl; - for_( it, repos.begin(), repos.end() ) - it->dumpAsXmlOn( cout ); - cout << "" << endl; -} - -// ---------------------------------------------------------------------------- - -void print_repos_to( const std::list & repos, std::ostream & out ) +void clean_repos(Zypper & zypper , std::vector specificRepos, CleanRepoFlags flags) { - for_( it, repos.begin(), repos.end() ) - it->dumpAsIniOn( out ) << endl; -} - -// ---------------------------------------------------------------------------- + RepoManager & manager( zypper.repoManager() ); -void list_repos( Zypper & zypper ) -{ - RepoManager & manager = zypper.repoManager(); - RuntimeData & gData = zypper.runtimeData(); std::list repos; - std::list not_found; - try { - if ( zypper.arguments().empty() ) - repos.insert( repos.end(), manager.repoBegin(), manager.repoEnd() ); - else - { - get_repos( zypper, zypper.arguments().begin(), zypper.arguments().end(), repos, not_found ); - report_unknown_repos( zypper.out(), not_found ); - } + repos.insert( repos.end(), manager.repoBegin(), manager.repoEnd() ); } catch ( const Exception & e ) { ZYPP_CAUGHT( e ); zypper.out().error( e, _("Error reading repositories:") ); - exit( ZYPPER_EXIT_ERR_ZYPP ); - } - - // add the temporary repos specified with the --plus-repo to the list - if ( !gData.temporary_repos.empty() ) - repos.insert( repos.end(), gData.temporary_repos.begin(), gData.temporary_repos.end() ); - - // export to file or stdout in repo file format - /// \todo dedup writing code in list_services - if ( copts.count("export") ) - { - std::string filename_str = copts["export"].front(); - if ( filename_str == "-" ) - { - print_repos_to(repos, cout); - } - else - { - if ( filename_str.rfind(".repo") == std::string::npos ) - filename_str += ".repo"; - - Pathname file( filename_str ); - std::ofstream stream( file.c_str() ); - if ( !stream ) - { - zypper.out().error( str::Format(_("Can't open %s for writing.")) % file.asString(), - _("Maybe you do not have write permissions?") ); - exit( ZYPPER_EXIT_ERR_INVALID_ARGS ); - } - else - { - print_repos_to( repos, stream ); - zypper.out().info( str::Format(_("Repositories have been successfully exported to %s.")) % file, - Out::QUIET ); - } - } - } - // print repo list as xml - else if ( zypper.out().type() == Out::TYPE_XML ) - print_xml_repo_list( zypper, repos ); - else if ( !zypper.arguments().empty() ) - print_repo_details( zypper, repos ); - // print repo list as table - else - print_repo_list( zypper, repos ); - - if ( !not_found.empty() ) { - zypper.setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - } else if ( repos.empty() ) { - zypper.setExitCode( ZYPPER_EXIT_NO_REPOS ); + zypper.setExitCode( ZYPPER_EXIT_ERR_ZYPP ); + return; } -} - -// ---------------------------------------------------------------------------- - -void refresh_repos( Zypper & zypper ) -{ - MIL << "going to refresh repositories" << endl; - // need gpg keys when downloading (#304672) - init_target( zypper ); - RepoManager & manager( zypper.repoManager() ); - const std::list & repos( manager.knownRepositories() ); - // get the list of repos specified on the command line ... + // get the list of repos specified requested std::list specified; std::list not_found; - // ...as command arguments - get_repos( zypper, zypper.arguments().begin(), zypper.arguments().end(), specified, not_found ); - // ...as --repo options - parsed_opts::const_iterator tmp1( copts.find("repo") ); - if ( tmp1 != copts.end() ) - get_repos( zypper, tmp1->second.begin(), tmp1->second.end(), specified, not_found ); + get_repos( zypper, specificRepos.begin(), specificRepos.end(), specified, not_found ); report_unknown_repos( zypper.out(), not_found ); - // --plus-content: It either specifies a known repo (by #, alias or URL) - // or we need to also refresh all disabled repos to get their content - // keywords. - std::set plusContent; - bool doContentCheck = false; - for ( const std::string & spec : zypper.runtimeData().plusContentRepos ) - { - RepoInfo r; - if ( match_repo( zypper, spec, &r ) ) - plusContent.insert( r ); // specific repo: add to plusContent - else if ( ! doContentCheck ) - doContentCheck = true; // keyword: need to scan all disabled repos - } - std::ostringstream s; s << _("Specified repositories: "); for_( it, specified.begin(), specified.end() ) s << it->alias() << " "; zypper.out().info( s.str(), Out::HIGH ); + // should we clean packages or metadata ? + bool clean_all = flags.testFlag( CleanRepoBits::CleanAll ); + bool clean_metadata = ( clean_all || flags.testFlag( CleanRepoBits::CleanMetaData ) ); + bool clean_raw_metadata = ( clean_all || flags.testFlag( CleanRepoBits::CleanRawMetaData ) ); + bool clean_packages = ( clean_all || !( clean_metadata || clean_raw_metadata ) ); + + DBG << "Metadata will be cleaned: " << clean_metadata << endl; + DBG << "Raw metadata will be cleaned: " << clean_raw_metadata << endl; + DBG << "Packages will be cleaned: " << clean_packages << endl; + unsigned error_count = 0; unsigned enabled_repo_count = repos.size(); @@ -1381,61 +1042,58 @@ void refresh_repos( Zypper & zypper ) { const RepoInfo & repo( *rit ); - if ( repo.enabled() ) + if ( !specified.empty() ) { - // enabled: Refreshed unless restricted by CLI args or mentioned in - // --plus-content as specific repo. - if ( !specified.empty() && std::find( specified.begin(), specified.end(), repo ) == specified.end() ) - { - if ( plusContent.count( repo ) ) - { - MIL << "[--plus-content] check " << repo.alias() << endl; - zypper.out().info( str::Format(_("Refreshing repository '%s'.")) % repo.asUserString(), - " [--plus-content]" ); - } - else - { - DBG << repo.alias() << "(#" << ") not specified," << " skipping." << endl; - enabled_repo_count--; - continue; - } - } + bool found = false; + for_( it, specified.begin(), specified.end() ) + if ( it->alias() == repo.alias() ) + { + found = true; + break; + } + + if ( !found ) + { + DBG << repo.alias() << "(#" << ") not specified," << " skipping." << endl; + enabled_repo_count--; + continue; + } } - else + + try { - // disabled: No refresh unless mentioned in --plus-content (specific or content check). - // CLI args reffering to disabled repos are reported as error. - if ( doContentCheck || plusContent.count( repo ) ) + if( clean_metadata ) { - MIL << "[--plus-content] check " << repo.alias() << endl; - zypper.out().info( str::Format(_("Scanning content of disabled repository '%s'.")) % repo.asUserString(), - " [--plus-content]" ); + zypper.out().info( str::Format(_("Cleaning metadata cache for '%s'.")) % repo.asUserString(), + Out::HIGH ); + manager.cleanCache( repo ); } - else + if( clean_raw_metadata ) + { + if ( ! repo.url().schemeIsVolatile() ) // cd/dvd + { + zypper.out().info( str::Format(_("Cleaning raw metadata cache for '%s'.")) % repo.asUserString(), + Out::HIGH ); + manager.cleanMetadata( repo ); + } + else + { + zypper.out().info( str::Format(_("Keeping raw metadata cache for %s '%s'.")) % repo.url().getScheme() % repo.asUserString(), + Out::HIGH ); + } + } + if( clean_packages ) { - if ( !specified.empty() && std::find( specified.begin(), specified.end(), repo ) == specified.end() ) - { - DBG << repo.alias() << "(#" << ") not specified," << " skipping." << endl; - } - else - { - std::string msg( str::Format(_("Skipping disabled repository '%s'")) % repo.asUserString() ); - - if ( specified.empty() ) - zypper.out().info( msg, Out::HIGH ); - else - zypper.out().error( msg ); - } - enabled_repo_count--; - continue; + // translators: meaning the cached rpm files + zypper.out().info( str::Format(_("Cleaning packages for '%s'.")) % repo.asUserString(), + Out::HIGH ); + manager.cleanPackages( repo ); } } - - // do the refresh - if ( refresh_repo( zypper, repo ) ) + catch(...) { - zypper.out().error( str::Format(_("Skipping repository '%s' because of the above error.")) % repo.asUserString() ); - ERR << "Skipping repository '" << repo.alias() << "' because of the above error." << endl; + ERR << "Cannot clean repository '" << repo.alias() << "' because of an error." << endl; + zypper.out().error( str::Format(_("Cannot clean repository '%s' because of an error.")) % repo.asUserString() ); error_count++; } } @@ -1443,210 +1101,32 @@ void refresh_repos( Zypper & zypper ) else enabled_repo_count = 0; - // print the result message - if ( !not_found.empty() ) - { - zypper.out().error(_("Some of the repositories have not been refreshed because they were not known.") ); - zypper.setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); - return; - } - else if ( enabled_repo_count == 0 ) + // clean the target system cache + if( clean_metadata ) { - if ( !specified.empty() ) - zypper.out().warning(_("Specified repositories are not enabled or defined.") ); - else { - zypper.out().warning(_("There are no enabled repositories defined.") ); - zypper.setExitCode( ZYPPER_EXIT_NO_REPOS ); + zypper.out().info(_("Cleaning installed packages cache."), Out::HIGH ); + try + { + init_target( zypper ); + God->target()->cleanCache(); + } + catch (...) + { + ERR << "Couldn't clean @System cache" << endl; + zypper.out().error(_("Cannot clean installed packages cache because of an error.") ); + error_count++; } - - zypper.out().info( str::form(_("Use '%s' or '%s' commands to add or enable repositories."), - "zypper addrepo", "zypper modifyrepo" ) ); } - else if ( error_count == enabled_repo_count ) + + if ( specificRepos.empty() && clean_packages ) { - zypper.out().error(_("Could not refresh the repositories because of errors.") ); - zypper.setExitCode( ZYPPER_EXIT_ERR_ZYPP ); - return; - } - else if ( error_count ) - { - zypper.out().error(_("Some of the repositories have not been refreshed because of an error.") ); - zypper.setExitCode( ZYPPER_EXIT_ERR_ZYPP ); - return; - } - else if ( !specified.empty() ) - zypper.out().info(_("Specified repositories have been refreshed.") ); - else - zypper.out().info(_("All repositories have been refreshed.") ); -} - -// ---------------------------------------------------------------------------- - -/** \return false on success, true on error */ -bool refresh_repo( Zypper & zypper, const RepoInfo & repo ) -{ - MIL << "going to refresh repo '" << repo.alias() << "'" << endl; - - // raw metadata refresh - bool error = false; - if ( !zypper.cOpts().count("build-only") ) - { - bool force_download = zypper.cOpts().count("force") || zypper.cOpts().count("force-download"); - MIL << "calling refreshMetadata" << (force_download ? ", forced" : "") << endl; - error = refresh_raw_metadata( zypper, repo, force_download ); - } - - // db rebuild - if ( !( error || zypper.cOpts().count("download-only") ) ) - { - bool force_build = zypper.cOpts().count("force") || zypper.cOpts().count("force-build"); - MIL << "calling buildCache" << (force_build ? ", forced" : "") << endl; - error = build_cache( zypper, repo, force_build ); - } - - return error; -} - -// ---------------------------------------------------------------------------- - -void clean_repos( Zypper & zypper ) -{ - RepoManager & manager( zypper.repoManager() ); - - std::list repos; - try - { - repos.insert( repos.end(), manager.repoBegin(), manager.repoEnd() ); - } - catch ( const Exception & e ) - { - ZYPP_CAUGHT( e ); - zypper.out().error( e, _("Error reading repositories:") ); - zypper.setExitCode( ZYPPER_EXIT_ERR_ZYPP ); - return; - } - - // get the list of repos specified on the command line ... - std::list specified; - std::list not_found; - // ...as command arguments - get_repos( zypper, zypper.arguments().begin(), zypper.arguments().end(), specified, not_found ); - // ...as --repo options - parsed_opts::const_iterator tmp1; - if ( (tmp1 = copts.find("repo")) != copts.end() ) - get_repos( zypper, tmp1->second.begin(), tmp1->second.end(), specified, not_found ); - report_unknown_repos( zypper.out(), not_found ); - - std::ostringstream s; - s << _("Specified repositories: "); - for_( it, specified.begin(), specified.end() ) - s << it->alias() << " "; - zypper.out().info( s.str(), Out::HIGH ); - - // should we clean packages or metadata ? - bool clean_all = copts.find("all") != copts.end(); - bool clean_metadata = ( clean_all || copts.find("metadata") != copts.end() ); - bool clean_raw_metadata = ( clean_all || copts.find("raw-metadata") != copts.end() ); - bool clean_packages = ( clean_all || !( clean_metadata || clean_raw_metadata ) ); - - DBG << "Metadata will be cleaned: " << clean_metadata << endl; - DBG << "Raw metadata will be cleaned: " << clean_raw_metadata << endl; - DBG << "Packages will be cleaned: " << clean_packages << endl; - - unsigned error_count = 0; - unsigned enabled_repo_count = repos.size(); - - if ( !specified.empty() || not_found.empty() ) - { - for_( rit, repos.begin(), repos.end() ) - { - const RepoInfo & repo( *rit ); - - if ( !specified.empty() ) - { - bool found = false; - for_( it, specified.begin(), specified.end() ) - if ( it->alias() == repo.alias() ) - { - found = true; - break; - } - - if ( !found ) - { - DBG << repo.alias() << "(#" << ") not specified," << " skipping." << endl; - enabled_repo_count--; - continue; - } - } - - try - { - if( clean_metadata ) - { - zypper.out().info( str::Format(_("Cleaning metadata cache for '%s'.")) % repo.asUserString(), - Out::HIGH ); - manager.cleanCache( repo ); - } - if( clean_raw_metadata ) - { - if ( ! repo.url().schemeIsVolatile() ) // cd/dvd - { - zypper.out().info( str::Format(_("Cleaning raw metadata cache for '%s'.")) % repo.asUserString(), - Out::HIGH ); - manager.cleanMetadata( repo ); - } - else - { - zypper.out().info( str::Format(_("Keeping raw metadata cache for %s '%s'.")) % repo.url().getScheme() % repo.asUserString(), - Out::HIGH ); - } - } - if( clean_packages ) - { - // translators: meaning the cached rpm files - zypper.out().info( str::Format(_("Cleaning packages for '%s'.")) % repo.asUserString(), - Out::HIGH ); - manager.cleanPackages( repo ); - } - } - catch(...) - { - ERR << "Cannot clean repository '" << repo.alias() << "' because of an error." << endl; - zypper.out().error( str::Format(_("Cannot clean repository '%s' because of an error.")) % repo.asUserString() ); - error_count++; - } - } - } - else - enabled_repo_count = 0; - - // clean the target system cache - if( clean_metadata ) - { - zypper.out().info(_("Cleaning installed packages cache."), Out::HIGH ); - try - { - init_target( zypper ); - God->target()->cleanCache(); - } - catch (...) - { - ERR << "Couldn't clean @System cache" << endl; - zypper.out().error(_("Cannot clean installed packages cache because of an error.") ); - error_count++; - } - } - - if ( zypper.arguments().empty() && clean_packages ) - { - // clean up garbage - // this could also be done with a special option or on each 'clean' - // regardless of the options used ... - manager.cleanCacheDirGarbage(); - // clean zypper's cache - // this could also be done with a special option - filesystem::recursive_rmdir( Pathname::assertprefix( zypper.globalOpts().root_dir, ZYPPER_RPM_CACHE_DIR ) ); + // clean up garbage + // this could also be done with a special option or on each 'clean' + // regardless of the options used ... + manager.cleanCacheDirGarbage(); + // clean zypper's cache + // this could also be done with a special option + filesystem::recursive_rmdir( Pathname::assertprefix( zypper.globalOpts().root_dir, ZYPPER_RPM_CACHE_DIR ) ); } if ( enabled_repo_count > 0 && error_count >= enabled_repo_count ) @@ -1669,12 +1149,7 @@ void clean_repos( Zypper & zypper ) // ---------------------------------------------------------------------------- -inline std::string timestamp() -{ return Date::now().form("%Y%m%d-%H%M%S"); } - -// ---------------------------------------------------------------------------- - -bool add_repo( Zypper & zypper, RepoInfo & repo ) +bool add_repo( Zypper & zypper, RepoInfo & repo, bool noCheck ) { RepoManager & manager = zypper.repoManager(); RuntimeData & gData = zypper.runtimeData(); @@ -1790,7 +1265,7 @@ bool add_repo( Zypper & zypper, RepoInfo & repo ) if ( is_cd ) { - if ( ! copts.count("no-check") ) + if ( ! noCheck ) { zypper.out().info( str::Format(_("Reading data from '%s' media")) % repo.asUserString() ); bool error = refresh_raw_metadata( zypper, repo, false ); @@ -1817,7 +1292,10 @@ bool add_repo( Zypper & zypper, RepoInfo & repo ) /// \todo merge common code with add_repo_from_file void add_repo_by_url( Zypper & zypper, const Url & url, - const std::string & alias ) + const std::string & alias, + const RepoServiceCommonOptions &opts, + const RepoProperties &repoProps, + bool noCheck ) { MIL << "going to add repository by url (alias=" << alias << ", url=" << url << ")" << endl; @@ -1827,36 +1305,33 @@ void add_repo_by_url( Zypper & zypper, repo.addBaseUrl( url ); - parsed_opts::const_iterator it = zypper.cOpts().find("name"); - if ( it != zypper.cOpts().end() ) - repo.setName( it->second.front() ); + if ( !opts._name.empty() ) + repo.setName( opts._name ); - TriBool bopt = get_boolean_option( zypper, "enable", "disable" ); - repo.setEnabled( indeterminate(bopt) ? true : bool(bopt) ); + repo.setEnabled( indeterminate( opts._enable ) ? true : bool(opts._enable) ); + repo.setAutorefresh( indeterminate( opts._enableAutoRefresh ) ? false : bool( opts._enableAutoRefresh ) ); // wouldn't true be the better default? - bopt = get_boolean_option( zypper, "refresh", "no-refresh" ); - repo.setAutorefresh( indeterminate(bopt) ? false : bool(bopt) ); // wouldn't true be the better default? + if ( repoProps._priority >= 1 ) + repo.setPriority( repoProps._priority ); - unsigned prio = parse_priority( zypper ); - if ( prio >= 1 ) - repo.setPriority( prio ); + if ( !indeterminate( repoProps._keepPackages ) ) + repo.setKeepPackages( repoProps._keepPackages ); - bopt = get_boolean_option( zypper, "keep-packages", "no-keep-packages" ); - if ( !indeterminate(bopt) ) - repo.setKeepPackages( bopt ); - - RepoInfo::GpgCheck gpgCheck( cli::gpgCheck( zypper ) ); + RepoInfo::GpgCheck gpgCheck = repoProps._gpgCheck; if ( gpgCheck != RepoInfo::GpgCheck::indeterminate ) repo.setGpgCheck( gpgCheck ); - if ( add_repo( zypper, repo ) ) + if ( add_repo( zypper, repo, noCheck ) ) repoPrioSummary( zypper ); } // ---------------------------------------------------------------------------- /// \todo merge common code with add_repo_by_url void add_repo_from_file( Zypper & zypper, - const std::string & repo_file_url ) + const std::string & repo_file_url, + const RepoServiceCommonOptions &opts, + const RepoProperties &repoProps, + bool noCheck ) { Url url = make_url( repo_file_url ); if ( !url.isValid() ) @@ -1865,15 +1340,7 @@ void add_repo_from_file( Zypper & zypper, return; } - std::string name; - if ( zypper.cOpts().count("name") ) - name = zypper.cOpts().find("name")->second.front(); - - TriBool enabled = get_boolean_option( zypper, "enable", "disable" ); - TriBool autorefresh = get_boolean_option( zypper, "refresh", "no-refresh" ); - unsigned prio = parse_priority( zypper ); - TriBool keepPackages = get_boolean_option( zypper, "keep-packages", "no-keep-packages" ); - RepoInfo::GpgCheck gpgCheck( cli::gpgCheck( zypper ) ); + RepoInfo::GpgCheck gpgCheck = repoProps._gpgCheck; std::list repos; @@ -1923,25 +1390,25 @@ void add_repo_from_file( Zypper & zypper, continue; } - if ( ! name.empty() ) - repo.setName( name ); + if ( ! opts._name.empty() ) + repo.setName( opts._name ); - if ( !indeterminate(enabled) ) - repo.setEnabled( enabled ); + if ( !indeterminate(opts._enable) ) + repo.setEnabled( opts._enable ); - if ( !indeterminate(autorefresh) ) - repo.setAutorefresh( autorefresh ); + if ( !indeterminate( opts._enableAutoRefresh) ) + repo.setAutorefresh( opts._enableAutoRefresh ); - if ( !indeterminate(keepPackages) ) - repo.setKeepPackages( keepPackages ); + if ( !indeterminate( repoProps._keepPackages ) ) + repo.setKeepPackages( repoProps._keepPackages ); if ( gpgCheck != RepoInfo::GpgCheck::indeterminate ) repo.setGpgCheck( gpgCheck ); - if ( prio >= 1 ) - repo.setPriority( prio ); + if ( repoProps._priority >= 1 ) + repo.setPriority( repoProps._priority ); - if ( add_repo( zypper, repo ) ) + if ( add_repo( zypper, repo, noCheck ) ) addedAtLeastOneRepository = true; } @@ -1950,6 +1417,23 @@ void add_repo_from_file( Zypper & zypper, return; } +unsigned priority_from_copts( Zypper &zypper ) +{ + unsigned prio = 0U; + parsed_opts::const_iterator cArg = zypper.cOpts().find( "priority" ); + if ( cArg != zypper.cOpts().end() ) { + std::string err; + try { + prio = parse_priority( *cArg->second.begin(), err ); + } catch ( const Exception &e ) { + zypper.out().error( err ); + zypper.setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); + ZYPP_THROW( ExitRequestException( e.asString() ) ); + } + } + return prio; +} + // ---------------------------------------------------------------------------- template @@ -1977,62 +1461,29 @@ void remove_repo( Zypper & zypper, const RepoInfo & repoinfo ) } // ---------------------------------------------------------------------------- -void remove_repos_by_option(Zypper &zypper) +void remove_repos_by_option( Zypper &zypper_r, const RepoServiceCommonSelectOptions selOpts_r ) { - RepoInfoSet repos = collect_repos_by_option( zypper ); + RepoInfoSet repos = collect_repos_by_option( zypper_r, selOpts_r ); for ( const RepoInfo &repo : repos ) { - remove_repo( zypper, repo ); + remove_repo( zypper_r, repo ); } } // ---------------------------------------------------------------------------- -void rename_repo( Zypper & zypper, const std::string & alias, const std::string & newalias ) -{ - RepoManager & manager( zypper.repoManager() ); - - try - { - RepoInfo repo( manager.getRepositoryInfo( alias ) ); - - if ( !repo.service().empty() ) - { - zypper.out().error(str::form( - _("Cannot change alias of '%s' repository. The repository" - " belongs to service '%s' which is responsible for setting its alias."), - alias.c_str(), repo.service().c_str())); - zypper.setExitCode( ZYPPER_EXIT_ERR_ZYPP ); - return; - } - - repo.setAlias( newalias ); - manager.modifyRepository( alias, repo ); - MIL << "Repository '" << alias << "' renamed to '" << repo.alias() << "'" << endl; - zypper.out().info( str::Format(_("Repository '%s' renamed to '%s'.")) % alias % repo.alias() ); - } - catch ( const repo::RepoAlreadyExistsException & ex ) - { - zypper.out().error( str::Format(_("Repository named '%s' already exists. Please use another alias.")) % newalias ); - } - catch ( const Exception & ex ) - { - ERR << "Error while modifying the repository " << ex.asUserString() << endl; - zypper.out().error( ex, _("Error while modifying the repository:"), - str::Format(_("Leaving repository '%s' unchanged.")) % alias ); - } -} // ---------------------------------------------------------------------------- -RepoInfoSet collect_repos_by_option( Zypper & zypper ) + +RepoInfoSet collect_repos_by_option( Zypper & zypper, const RepoServiceCommonSelectOptions &selectOpts ) { RepoManager & manager( zypper.repoManager() ); const std::list & repos( manager.knownRepositories() ); RepoInfoSet toModify; - if ( copts.count("all") ) + if ( selectOpts._all ) { std::for_each( repos.begin(), repos.end(), [&toModify] (const RepoInfo &info) { toModify.insert( info ); } ); } @@ -2040,24 +1491,24 @@ RepoInfoSet collect_repos_by_option( Zypper & zypper ) { std::list> filterList; - if ( copts.count("local") ) + if ( selectOpts._local ) { filterList.push_back([]( const RepoInfo &info ) { return ( !info.baseUrlsEmpty() && !info.url().schemeIsDownloading() ); }); } - if ( copts.count("remote") ) + if ( selectOpts._remote ) { filterList.push_back([]( const RepoInfo &info ) { return ( !info.baseUrlsEmpty() && info.url().schemeIsDownloading() ); }); } - if ( copts.count("medium-type") ) + if ( selectOpts._mediumTypes.size() ) { - filterList.push_back([]( const RepoInfo &info ) { - const std::list & pars = copts["medium-type"]; + filterList.push_back([ &selectOpts ]( const RepoInfo &info ) { + const std::vector & pars = selectOpts._mediumTypes; return ( !info.baseUrlsEmpty() && std::find( pars.begin(), pars.end(), info.url().getScheme() ) != pars.end() ); }); } @@ -2077,34 +1528,36 @@ RepoInfoSet collect_repos_by_option( Zypper & zypper ) return toModify; } -void modify_repos_by_option( Zypper & zypper ) +void modify_repos_by_option( Zypper & zypper, const RepoServiceCommonSelectOptions &selectOpts, const RepoServiceCommonOptions &commonOpts, const RepoProperties &repoProps ) { - RepoInfoSet toModify = collect_repos_by_option( zypper ); + RepoInfoSet toModify = collect_repos_by_option( zypper, selectOpts ); for_( it, toModify.begin(), toModify.end() ) { - modify_repo( zypper, it->alias() ); + modify_repo( zypper, it->alias(), commonOpts, repoProps ); } } // ---------------------------------------------------------------------------- -void modify_repo( Zypper & zypper, const std::string & alias ) + + +void modify_repo( Zypper & zypper, const std::string & alias, const RepoServiceCommonOptions &commonOpts, const RepoProperties &repoProps ) { // enable/disable repo - TriBool enable = get_boolean_option( zypper, "enable", "disable" ); + const TriBool &enable = commonOpts._enable; DBG << "enable = " << enable << endl; // autorefresh - TriBool autoref = get_boolean_option( zypper, "refresh", "no-refresh" ); + const TriBool &autoref = commonOpts._enableAutoRefresh; DBG << "autoref = " << autoref << endl; - TriBool keepPackages = get_boolean_option( zypper, "keep-packages", "no-keep-packages" ); + const TriBool &keepPackages = repoProps._keepPackages; DBG << "keepPackages = " << keepPackages << endl; - RepoInfo::GpgCheck gpgCheck( cli::gpgCheck( zypper ) ); + const RepoInfo::GpgCheck &gpgCheck = repoProps._gpgCheck; - unsigned prio = parse_priority( zypper ); + unsigned prio = repoProps._priority; try { @@ -2154,14 +1607,9 @@ void modify_repo( Zypper & zypper, const std::string & alias ) } } - std::string name; - parsed_opts::const_iterator tmp1; - if ( (tmp1 = zypper.cOpts().find("name")) != zypper.cOpts().end() ) - { - name = *tmp1->second.begin(); - if ( !name.empty() ) - repo.setName( name ); - } + const std::string &name = commonOpts._name; + if ( !name.empty() ) + repo.setName( name ); if ( changed_enabled || changed_autoref || changed_prio || changed_keeppackages || changed_gpgcheck || !name.empty() ) @@ -2251,676 +1699,30 @@ void modify_repo( Zypper & zypper, const std::string & alias ) // Service Handling // --------------------------------------------------------------------------- -static ServiceList get_all_services( Zypper & zypper ) -{ - RepoManager & manager( zypper.repoManager() ); - ServiceList services; - - try - { - // RIS type services - for_( it, manager.serviceBegin(), manager.serviceEnd() ) - { - services.insert( services.end(), ServiceInfo_Ptr( new ServiceInfo( *it ) ) ); // copy needed? - } - - // non-services repos - for_( it, manager.repoBegin(), manager.repoEnd() ) - { - if ( !it->service().empty() ) - continue; - services.insert( services.end(), RepoInfo_Ptr( new RepoInfo( *it ) ) ); // copy needed? - } - } - catch ( const Exception &e ) - { - ZYPP_CAUGHT(e); - zypper.out().error( e, _("Error reading services:") ); - exit( ZYPPER_EXIT_ERR_ZYPP ); - } - return services; -} +// --------------------------------------------------------------------------- -bool match_service( Zypper & zypper, std::string str, RepoInfoBase_Ptr & service_ptr ) -{ - ServiceList known = get_all_services( zypper ); - bool found = false; - unsigned number = 0; // service number start with 1 - for_( known_it, known.begin(), known.end() ) - { - ++number; - unsigned tmp = 0; - safe_lexical_cast( str, tmp ); // try to make an int out of the string - try - { - // match by alias or number - found = (*known_it)->alias() == str || tmp == number; +// --------------------------------------------------------------------------- - // match by URL - if ( !found ) - { - url::ViewOption urlview = url::ViewOption::DEFAULTS + url::ViewOption::WITH_PASSWORD; - if ( zypper.cOpts().count("loose-auth") ) - { - urlview = urlview - url::ViewOptions::WITH_PASSWORD - url::ViewOptions::WITH_USERNAME; - } - if ( zypper.cOpts().count("loose-query") ) - urlview = urlview - url::ViewOptions::WITH_QUERY_STR; +enum ServiceListFlagsBits +{ + SF_SHOW_ALL = 7, + SF_SHOW_URI = 1, + SF_SHOW_PRIO = 1 << 1, + SF_SHOW_WITH_REPOS = 1 << 2, + SF_SERVICE_REPO = 1 << 15 +}; +ZYPP_DECLARE_FLAGS( ServiceListFlags,ServiceListFlagsBits ); +ZYPP_DECLARE_OPERATORS_FOR_FLAGS( ServiceListFlags ); - ServiceInfo_Ptr s_ptr = dynamic_pointer_cast(*known_it); - if ( !( urlview.has(url::ViewOptions::WITH_PASSWORD) && urlview.has(url::ViewOptions::WITH_QUERY_STR) ) ) - { - if ( s_ptr ) - found = Url(str).asString(urlview) == s_ptr->url().asString(urlview); - else - { - RepoInfo_Ptr r_ptr = dynamic_pointer_cast(*known_it); - if ( !r_ptr->baseUrlsEmpty() ) - { - for_( urlit, r_ptr->baseUrlsBegin(), r_ptr->baseUrlsEnd() ) - if ( urlit->asString(urlview) == Url(str).asString(urlview) ) - { - found = true; - break; - } - } - } - } - else - { - if ( s_ptr ) - found = ( Url(str) == s_ptr->url() ); - else - { - RepoInfo_Ptr r_ptr = dynamic_pointer_cast(*known_it); - if ( !r_ptr->baseUrlsEmpty() ) - { - found = find( r_ptr->baseUrlsBegin(), r_ptr->baseUrlsEnd(), Url(str) ) != r_ptr->baseUrlsEnd(); - } - } - } - } - if ( found ) - { - service_ptr = *known_it; - break; - } - } - catch( const url::UrlException & ) - {} +// --------------------------------------------------------------------------- - } // END for all known services - return found; -} -/** - * Say "Service %s not found" for all strings in \a not_found list. - */ -static void report_unknown_services( Out & out, std::list not_found ) -{ - for_( it, not_found.begin(), not_found.end() ) - out.error( str::Format(_("Service '%s' not found by its alias, number, or URI.")) % *it ); - - if ( !not_found.empty() ) - out.info( str::Format(_("Use '%s' to get the list of defined services.")) % "zypper repos" ); -} - -/** - * Try to find ServiceInfo or RepoInfo counterparts among known services by alias, number, - * or URI, based on the list of strings given as the iterator range \a begin and - * \a end. Matching objects will be added to \a services (as RepoInfoBase_Ptr) and those - * with no match will be added to \a not_found. - */ -template -void get_services( Zypper & zypper, const T & begin, const T & end, - ServiceList & services, std::list & not_found ) -{ - for_( it, begin, end ) - { - RepoInfoBase_Ptr service; - - if ( !match_service( zypper, *it, service ) ) - { - not_found.push_back( *it ); - continue; - } - - // service found - // is it a duplicate? compare by alias and URIs - //! \todo operator== in RepoInfo? - bool duplicate = false; - for_( serv_it, services.begin(), services.end() ) - { - ServiceInfo_Ptr s_ptr = dynamic_pointer_cast(*serv_it); - ServiceInfo_Ptr current_service_ptr = dynamic_pointer_cast(service); - - // one is a service, the other is a repo - if ( s_ptr && !current_service_ptr ) - continue; - - // service - if ( s_ptr ) - { - if ( s_ptr->alias() == current_service_ptr->alias() - && s_ptr->url() == current_service_ptr->url() ) - { - duplicate = true; - break; - } - } - // repo - else if ( repo_cmp_alias_urls( *dynamic_pointer_cast(service), - *dynamic_pointer_cast(*serv_it) ) ) - { - duplicate = true; - break; - } - } // END for all found so far - - if ( !duplicate ) - services.push_back( service ); - } -} - -// --------------------------------------------------------------------------- - -struct RepoCollector -{ - bool collect( const RepoInfo & repo ) - { - repos.push_back( repo ); - return true; - } - RepoInfoList repos; -}; - -// --------------------------------------------------------------------------- - -enum ServiceListFlagsBits -{ - SF_SHOW_ALL = 7, - SF_SHOW_URI = 1, - SF_SHOW_PRIO = 1 << 1, - SF_SHOW_WITH_REPOS = 1 << 2, - SF_SERVICE_REPO = 1 << 15 -}; -ZYPP_DECLARE_FLAGS( ServiceListFlags,ServiceListFlagsBits ); -ZYPP_DECLARE_OPERATORS_FOR_FLAGS( ServiceListFlags ); - -static void service_list_tr( Zypper & zypper, - Table & tbl, - const RepoInfoBase_Ptr & srv, - unsigned reponumber, - const ServiceListFlags & flags ) -{ - ServiceInfo_Ptr service = dynamic_pointer_cast(srv); - RepoInfo_Ptr repo; - if ( ! service ) - repo = dynamic_pointer_cast(srv); - - RepoGpgCheckStrings repoGpgCheck( service ? RepoGpgCheckStrings(*service) : RepoGpgCheckStrings(*repo) ); - - TableRow tr( 8 ); - - // number - if ( flags & SF_SERVICE_REPO ) - { - if ( repo && ! repo->enabled() ) - tr << ColorString( repoGpgCheck._tagColor, "-" ).str(); - else - tr << ""; - } - else - tr << ColorString( repoGpgCheck._tagColor, str::numstring(reponumber) ).str(); - - // alias - tr << srv->alias(); - // name - tr << srv->name(); - // enabled? - tr << repoGpgCheck._enabledYN.str(); - // GPG Check - tr << repoGpgCheck._gpgCheckYN.str(); - // autorefresh? - tr << repoAutorefreshStr( *srv ); - - // priority - if ( flags & SF_SHOW_PRIO ) - { - if ( service ) - tr << ""; - else - tr << repoPriorityNumber( repo->priority(), 4 ); - } - - // type - if ( service ) - tr << service->type().asString(); - else - tr << repo->type().asString(); - - // url - if ( flags & SF_SHOW_URI ) - { - if ( service ) - tr << service->url().asString(); - else - tr << repo->url().asString(); - } - - tbl << tr; -} - -// --------------------------------------------------------------------------- - -static void print_service_list( Zypper & zypper, const std::list & services ) -{ - Table tbl; - - // flags - - ServiceListFlags flags( 0 ); - if ( zypper.cOpts().count("details") ) - flags |= SF_SHOW_ALL; - else - { - if ( zypper.cOpts().count("uri") - || zypper.cOpts().count("url") - || zypper.cOpts().count("sort-by-uri") ) - flags |= SF_SHOW_URI; - if ( zypper.cOpts().count("priority") - || zypper.cOpts().count("sort-by-priority") ) - flags |= SF_SHOW_PRIO; - } - - bool with_repos = zypper.cOpts().count("with-repos"); - //! \todo string type = zypper.cOpts().count("type"); - - // header - { - TableHeader th; - // fixed 'zypper services' columns - th << "#" - << _("Alias") - << _("Name") - << _("Enabled") - << _("GPG Check") - // translators: 'zypper repos' column - whether autorefresh is enabled for the repository - << _("Refresh"); - // optional columns - if ( flags.testFlag( SF_SHOW_PRIO ) ) - // translators: repository priority (in zypper repos -p or -d) - th << _("Priority"); - th << _("Type"); - if ( flags.testFlag( SF_SHOW_URI ) ) - th << _("URI"); - tbl << std::move(th); - } - - bool show_enabled_only = zypper.cOpts().count("show-enabled-only"); - - int i = 0; - for_( it, services.begin(), services.end() ) - { - ++i; // continuous numbering including skipped ones - - bool servicePrinted = false; - // Unconditionally print the service before the 1st repo is - // printed. Undesired, but possible, that a disabled service - // owns (manually) enabled repos. - if ( with_repos && dynamic_pointer_cast(*it) ) - { - RepoCollector collector; - RepoManager & rm( zypper.repoManager() ); - - rm.getRepositoriesInService( (*it)->alias(), - make_function_output_iterator( bind( &RepoCollector::collect, &collector, _1 ) ) ); - - for_( repoit, collector.repos.begin(), collector.repos.end() ) - { - RepoInfoBase_Ptr ptr( new RepoInfo(*repoit) ); // copy needed? - - if ( show_enabled_only && !repoit->enabled() ) - continue; - - if ( !servicePrinted ) - { - service_list_tr( zypper, tbl, *it, i, flags ); - servicePrinted = true; - } - // SF_SERVICE_REPO: we print repos of the current service - service_list_tr( zypper, tbl, ptr, i, flags|SF_SERVICE_REPO ); - } - } - if ( servicePrinted ) - continue; - - // Here: No repo enforced printing the service, so do so if - // necessary. - if ( show_enabled_only && !(*it)->enabled() ) - continue; - - service_list_tr( zypper, tbl, *it, i, flags ); - } - - if ( tbl.empty() ) - zypper.out().info( str::form(_("No services defined. Use the '%s' command to add one or more services."), - "zypper addservice" ) ); - else - { - // sort - if ( zypper.cOpts().count("sort-by-uri") ) - { - if ( flags.testFlag( SF_SHOW_ALL ) ) - tbl.sort( 7 ); - else if ( flags.testFlag( SF_SHOW_PRIO ) ) - tbl.sort( 7 ); - else - tbl.sort( 6 ); - } - else if ( zypper.cOpts().count("sort-by-alias") ) - tbl.sort( 1 ); - else if ( zypper.cOpts().count("sort-by-name") ) - tbl.sort( 2 ); - else if ( zypper.cOpts().count("sort-by-priority") ) - tbl.sort( 5 ); - - // print - cout << tbl; - } -} - -// ---------------------------------------------------------------------------- - -static void print_xml_service_list( Zypper & zypper, const std::list & services ) -{ - cout << "" << endl; - - ServiceInfo_Ptr s_ptr; - for_( it, services.begin(), services.end() ) - { - s_ptr = dynamic_pointer_cast(*it); - // print also service's repos - if ( s_ptr ) - { - RepoCollector collector; - RepoManager & rm( zypper.repoManager() ); - rm.getRepositoriesInService( (*it)->alias(), - make_function_output_iterator( bind( &RepoCollector::collect, &collector, _1 ) ) ); - std::ostringstream sout; - for_( repoit, collector.repos.begin(), collector.repos.end() ) - repoit->dumpAsXmlOn( sout ); - (*it)->dumpAsXmlOn( cout, sout.str() ); - continue; - } - - (*it)->dumpAsXmlOn( cout ); - } - - cout << "" << endl; -} - -// --------------------------------------------------------------------------- - -void list_services( Zypper & zypper ) -{ - ServiceList services = get_all_services( zypper ); - - // print repo list as xml - if (zypper.out().type() == Out::TYPE_XML) - print_xml_service_list( zypper, services ); - else - print_service_list( zypper, services ); -} - -// --------------------------------------------------------------------------- - -void add_service( Zypper & zypper, const ServiceInfo & service ) -{ - RepoManager manager( zypper.globalOpts().rm_options ); - - try - { - manager.addService( service ); - } - catch ( const repo::RepoAlreadyExistsException & e ) - { - ZYPP_CAUGHT( e ); - ERR << "Service aliased '" << service.alias() << "' already exists." << endl; - zypper.out().error( str::Format(_("Service aliased '%s' already exists. Please use another alias.")) % service.alias() ); - zypper.setExitCode( ZYPPER_EXIT_ERR_ZYPP ); - return; - } - catch ( const Exception & e ) - { - ZYPP_CAUGHT( e ); - zypper.out().error( str::Format(_("Error occurred while adding service '%s'.")) % service.alias() ); - zypper.setExitCode( ZYPPER_EXIT_ERR_ZYPP ); - return; - } - - MIL << "Service '" << service.alias() << "' has been added." << endl; - zypper.out().info( str::Format(_("Service '%s' has been successfully added.")) % service.asUserString() ); -} - -// --------------------------------------------------------------------------- - -void add_service_by_url( Zypper & zypper, - const Url & url, - const std::string & alias) -{ - MIL << "going to add service by url (alias=" << alias << ", url=" << url << ")" << endl; - - ServiceInfo service; - - service.setAlias( alias.empty() ? timestamp() : alias ); - parsed_opts::const_iterator it = zypper.cOpts().find("name"); - if ( it != zypper.cOpts().end() ) - service.setName( it->second.front() ); - service.setUrl( url ); - - TriBool bopt = get_boolean_option( zypper, "enable", "disable" ); - service.setEnabled( indeterminate(bopt) ? true : bool(bopt) ); - - bopt = get_boolean_option( zypper, "refresh", "no-refresh" ); - service.setAutorefresh( indeterminate(bopt) ? true : bool(bopt) ); - - add_service( zypper, service ); -} - - -// --------------------------------------------------------------------------- - -void remove_service( Zypper & zypper, const ServiceInfo & service ) -{ - RepoManager & manager( zypper.repoManager() ); - - zypper.out().info( str::Format(_("Removing service '%s':")) % service.asUserString() ); - manager.removeService( service ); - MIL << "Service '" << service.alias() << "' has been removed." << endl; - zypper.out().info( str::Format(_("Service '%s' has been removed.")) % service.asUserString() ); -} - -// --------------------------------------------------------------------------- - -static bool refresh_service( Zypper & zypper, const ServiceInfo & service ) -{ - MIL << "going to refresh service '" << service.alias() << "'" << endl; - init_target( zypper ); // need targetDistribution for service refresh - RepoManager & manager( zypper.repoManager() ); - - bool error = true; - try - { - zypper.out().info( str::form(_("Refreshing service '%s'."), service.asUserString().c_str() ) ); - - RepoManager::RefreshServiceOptions opts; - if ( zypper.cOpts().count("restore-status") ) - opts |= RepoManager::RefreshService_restoreStatus; - if ( zypper.cOpts().count("force") - && ( zypper.command() == ZypperCommand::REFRESH || zypper.command() == ZypperCommand::REFRESH_SERVICES ) ) - opts |= RepoManager::RefreshService_forceRefresh; - - manager.refreshService( service, opts ); - error = false; - } - catch ( const repo::ServicePluginInformalException & e ) - { - ZYPP_CAUGHT( e ); - zypper.out().error( e, str::form(_("Problem retrieving the repository index file for service '%s':"), - service.asUserString().c_str())); - zypper.out().warning( str::form( _("Skipping service '%s' because of the above error."), - service.asUserString().c_str())); - // this is just an informal note. The service will be used as is (usually empty) - error = false; - } - catch ( const media::MediaException & e ) - { - ZYPP_CAUGHT( e ); - zypper.out().error( e, str::form(_("Problem retrieving the repository index file for service '%s':"), - service.asUserString().c_str() ), - _("Check if the URI is valid and accessible.") ); - zypper.setExitCode( ZYPPER_EXIT_ERR_ZYPP ); - } - - return error; -} - -// --------------------------------------------------------------------------- - -void refresh_services( Zypper & zypper ) -{ - MIL << "going to refresh services" << endl; - - ServiceList services = get_all_services( zypper ); - - // get the list of repos specified on the command line ... - ServiceList specified; - std::list not_found; - // ...as command arguments - get_services( zypper, zypper.arguments().begin(), zypper.arguments().end(), specified, not_found ); - report_unknown_services( zypper.out(), not_found ) ; - - unsigned error_count = 0; - unsigned enabled_service_count = services.size(); - - if ( !specified.empty() || not_found.empty() ) - { - unsigned number = 0; - for_( sit, services.begin(), services.end() ) - { - ++number; - RepoInfoBase_Ptr service_ptr( *sit ); - - // skip services not specified on the command line - if ( !specified.empty() ) - { - bool found = false; - for_( it, specified.begin(), specified.end() ) - if ( (*it)->alias() == service_ptr->alias() ) - { - found = true; - break; - } - - if ( !found ) - { - DBG << service_ptr->alias() << "(#" << number << ") not specified," << " skipping." << endl; - --enabled_service_count; - continue; - } - } - - // skip disabled services - if ( !service_ptr->enabled() ) - { - DBG << "skipping disabled service '" << service_ptr->alias() << "'" << endl; - - std::string msg = str::Format(_("Skipping disabled service '%s'")) % service_ptr->asUserString(); - if ( specified.empty() ) - zypper.out().info( msg, Out::HIGH ); - else - zypper.out().error( msg ); - - --enabled_service_count; - continue; - } - - // do the refresh - bool error = false; - ServiceInfo_Ptr s = dynamic_pointer_cast(service_ptr); - if ( s ) - { - error = refresh_service( zypper, *s ); - - // refresh also service's repos - if ( zypper.cOpts().count("with-repos") ) - { - RepoCollector collector; - RepoManager & rm = zypper.repoManager(); - rm.getRepositoriesInService( s->alias(), - make_function_output_iterator( bind( &RepoCollector::collect, &collector, _1 ) ) ); - for_( repoit, collector.repos.begin(), collector.repos.end() ) - refresh_repo( zypper, *repoit ); - } - } - else - { - if ( !zypper.cOpts().count("with-repos") ) - { - DBG << "Skipping non-index service '" << service_ptr->asUserString() << "' because '--no-repos' is used."; - continue; - } - error = refresh_repo( zypper, *dynamic_pointer_cast(service_ptr) ); - } - - if ( error ) - { - ERR << "Skipping service '" << service_ptr->alias() << "' because of the above error." << endl; - zypper.out().error( str::Format(_("Skipping service '%s' because of the above error.")) % service_ptr->asUserString().c_str() ); - ++error_count; - } - } - } - else - enabled_service_count = 0; - - // print the result message - if ( enabled_service_count == 0 ) - { - std::string hint = str::form(_("Use '%s' or '%s' commands to add or enable services."), - "zypper addservice", "zypper modifyservice" ); - if ( !specified.empty() || !not_found.empty() ) - zypper.out().error(_("Specified services are not enabled or defined."), hint); - else - zypper.out().error(_("There are no enabled services defined."), hint); - } - else if ( error_count == enabled_service_count ) - { - zypper.out().error(_("Could not refresh the services because of errors.") ); - zypper.setExitCode( ZYPPER_EXIT_ERR_ZYPP ); - return; - } - else if ( error_count ) - { - zypper.out().error(_("Some of the services have not been refreshed because of an error.") ); - zypper.setExitCode( ZYPPER_EXIT_ERR_ZYPP ); - return; - } - else if ( !specified.empty() ) - zypper.out().info(_("Specified services have been refreshed.") ); - else - zypper.out().info(_("All services have been refreshed.") ); - - MIL << "DONE"; -} - -void checkIfToRefreshPluginServices( Zypper & zypper ) +void checkIfToRefreshPluginServices(Zypper & zypper, RepoManager::RefreshServiceFlags flags_r) { // check root user if ( geteuid() != 0 ) @@ -2936,7 +1738,7 @@ void checkIfToRefreshPluginServices( Zypper & zypper ) if ( ! service.autorefresh() ) continue; - bool error = refresh_service( zypper, service ); + bool error = refresh_service( zypper, service, flags_r ); if (error) { ERR << "Skipping service '" << service.alias() << "' because of the above error." << endl; @@ -2945,256 +1747,8 @@ void checkIfToRefreshPluginServices( Zypper & zypper ) } } - -// --------------------------------------------------------------------------- - -void modify_service( Zypper & zypper, const std::string & alias ) -{ - // enable/disable repo - TriBool enable = get_boolean_option( zypper,"enable", "disable" ); - DBG << "enable = " << enable << endl; - - // autorefresh - TriBool autoref = get_boolean_option( zypper,"refresh", "no-refresh" ); - DBG << "autoref = " << autoref << endl; - - try - { - RepoManager & manager = zypper.repoManager(); - ServiceInfo srv( manager.getService( alias ) ); - - bool changed_enabled = false; - bool changed_autoref = false; - - if ( !indeterminate(enable) ) - { - if ( enable != srv.enabled() ) - changed_enabled = true; - srv.setEnabled( enable ); - } - - if ( !indeterminate(autoref) ) - { - if ( autoref != srv.autorefresh() ) - changed_autoref = true; - srv.setAutorefresh( autoref ); - } - - std::string name; - parsed_opts::const_iterator tmp1; - if ( (tmp1 = zypper.cOpts().find("name")) != zypper.cOpts().end() ) - { - name = *tmp1->second.begin(); - srv.setName( name ); - } - - std::set artoenable; - std::set artodisable; - std::set rrtoenable; - std::set rrtodisable; - - // RIS repos to enable - if ( zypper.cOpts().count("cl-to-enable") ) - { - rrtoenable.insert( srv.reposToEnableBegin(), srv.reposToEnableEnd() ); - srv.clearReposToEnable(); - } - else - { - if ( (tmp1 = zypper.cOpts().find("ar-to-enable")) != zypper.cOpts().end() ) - for_( rit, tmp1->second.begin(), tmp1->second.end() ) - { - if ( !srv.repoToEnableFind( *rit ) ) - { - srv.addRepoToEnable( *rit ); - artoenable.insert( *rit ); - } - } - if ( (tmp1 = zypper.cOpts().find("rr-to-enable")) != zypper.cOpts().end() ) - for_( rit, tmp1->second.begin(), tmp1->second.end() ) - { - if ( srv.repoToEnableFind( *rit ) ) - { - srv.delRepoToEnable( *rit ); - rrtoenable.insert( *rit ); - } - } - } - - // RIS repos to disable - if ( zypper.cOpts().count("cl-to-disable") ) - { - rrtodisable.insert( srv.reposToDisableBegin(), srv.reposToDisableEnd() ); - srv.clearReposToDisable(); - } - else - { - if ( (tmp1 = zypper.cOpts().find("ar-to-disable")) != zypper.cOpts().end() ) - for_( rit, tmp1->second.begin(), tmp1->second.end() ) - { - if ( !srv.repoToDisableFind( *rit ) ) - { - srv.addRepoToDisable( *rit ); - artodisable.insert( *rit ); - } - } - if ( (tmp1 = zypper.cOpts().find("rr-to-disable")) != zypper.cOpts().end() ) - for_( rit, tmp1->second.begin(), tmp1->second.end() ) - { - if (srv.repoToDisableFind( *rit ) ) - { - srv.delRepoToDisable( *rit ); - rrtodisable.insert( *rit ); - } - } - } - - if ( changed_enabled - || changed_autoref - || !name.empty() - || !artoenable.empty() - || !artodisable.empty() - || !rrtoenable.empty() - || !rrtodisable.empty() ) - { - manager.modifyService( alias, srv ); - - if ( changed_enabled ) - { - if ( srv.enabled() ) - zypper.out().info( str::Format(_("Service '%s' has been successfully enabled.")) % alias ); - else - zypper.out().info( str::Format(_("Service '%s' has been successfully disabled.")) % alias ); - } - - if ( changed_autoref ) - { - if ( srv.autorefresh() ) - zypper.out().info( str::Format(_("Autorefresh has been enabled for service '%s'.")) % alias ); - else - zypper.out().info( str::Format(_("Autorefresh has been disabled for service '%s'.")) % alias ); - } - - if ( !name.empty() ) - { - zypper.out().info( str::Format(_("Name of service '%s' has been set to '%s'.")) % alias % name ); - } - - if ( !artoenable.empty() ) - { - zypper.out().info( str::Format(PL_("Repository '%s' has been added to enabled repositories of service '%s'", - "Repositories '%s' have been added to enabled repositories of service '%s'", - artoenable.size())) - % str::join( artoenable.begin(), artoenable.end(), ", " ) % alias ); - } - if ( !artodisable.empty() ) - { - zypper.out().info( str::Format(PL_("Repository '%s' has been added to disabled repositories of service '%s'", - "Repositories '%s' have been added to disabled repositories of service '%s'", - artodisable.size())) - % str::join( artodisable.begin(), artodisable.end(), ", " ) % alias ); - } - if ( !rrtoenable.empty() ) - { - zypper.out().info( str::Format(PL_("Repository '%s' has been removed from enabled repositories of service '%s'", - "Repositories '%s' have been removed from enabled repositories of service '%s'", - rrtoenable.size())) - % str::join( rrtoenable.begin(), rrtoenable.end(), ", " ) % alias ); - } - if ( !rrtodisable.empty()) - { - zypper.out().info( str::Format(PL_("Repository '%s' has been removed from disabled repositories of service '%s'", - "Repositories '%s' have been removed from disabled repositories of service '%s'", - rrtodisable.size())) - % str::join( rrtodisable.begin(), rrtodisable.end(), ", " ) % alias ); - } - } - else - { - MIL << "Nothing to modify in '" << alias << "':" << srv << endl; - zypper.out().info( str::Format(_("Nothing to change for service '%s'.")) % alias ); - } - } - catch ( const Exception & ex ) - { - ERR << "Error while modifying the service:" << ex.asUserString() << endl; - zypper.out().error( ex, _("Error while modifying the service:"), - str::Format(_("Leaving service %s unchanged.")) % alias ); - zypper.setExitCode( ZYPPER_EXIT_ERR_ZYPP ); - } -} - // --------------------------------------------------------------------------- -void modify_services_by_option( Zypper & zypper ) -{ - ServiceList known = get_all_services( zypper ); - std::set repos_to_modify; - std::set services_to_modify; - - if ( copts.count("all") ) - { - for_( it, known.begin(), known.end() ) - { - ServiceInfo_Ptr sptr = dynamic_pointer_cast(*it); - if ( sptr ) - modify_service( zypper, sptr->alias() ); - else - modify_repo( zypper, (*it)->alias() ); - } - return; - } - - bool local = copts.count("local"); - bool remote = copts.count("remote"); - std::list pars = copts["medium-type"]; - std::set schemes(pars.begin(), pars.end()); - - for_( it, known.begin(), known.end() ) - { - ServiceInfo_Ptr sptr = dynamic_pointer_cast(*it); - Url url; - if ( sptr ) - url = sptr->url(); - else - { - RepoInfo_Ptr rptr = dynamic_pointer_cast(*it); - if ( !rptr->baseUrlsEmpty() ) - url = rptr->url(); - } - - if ( url.isValid() ) - { - bool modify = false; - if ( local && ! url.schemeIsDownloading() ) - modify = true; - - if ( !modify && remote && url.schemeIsDownloading() ) - modify = true; - - if ( !modify && schemes.find(url.getScheme()) != schemes.end() ) - modify = true; - - if ( modify ) - { - std::string alias = (*it)->alias(); - if ( sptr ) - services_to_modify.insert( alias ); - else - repos_to_modify.insert( alias ); - } - } - else - WAR << "got invalid url: " << url.asString() << endl; - } - - for_( it, services_to_modify.begin(), services_to_modify.end() ) - modify_service( zypper, *it ); - - for_( it, repos_to_modify.begin(), repos_to_modify.end() ) - modify_repo( zypper, *it ); -} - // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- diff --git a/src/repos.h b/src/repos.h index 9a5e20c..74fe4b4 100644 --- a/src/repos.h +++ b/src/repos.h @@ -10,15 +10,38 @@ #include +#include + #include #include #include #include #include "Zypper.h" +#include "commands/reposerviceoptionsets.h" #define TMP_RPM_REPO_ALIAS "_tmpRPMcache_" +// | Enabled | GPG Check | Colored strings for enabled and GPG Check status +// +---------+-----------+ +// | Yes | ( ) No | +// | Yes | (rp) Yes | +// | No | ---- | +struct RepoGpgCheckStrings +{ + RepoGpgCheckStrings(); + + RepoGpgCheckStrings( const ServiceInfo & service_r ); + RepoGpgCheckStrings( const RepoInfo & repo_r ); + + ColorContext _tagColor; ///< color according to enabled and GPG Check status + ColorString _enabledYN; ///< colored enabled Yes/No + ColorString _gpgCheckYN; ///< colored GPG Check status if enabled else "----" +}; + +inline std::string timestamp() +{ return Date::now().form("%Y%m%d-%H%M%S"); } + /** * The same as \ref init_repos(), but allows to specify repos to initialize. * @@ -28,9 +51,25 @@ template void init_repos( Zypper & zypper, const Container & container = Container() ); +/** + * Say "Repository %s not found" for all strings in \a not_found list. + */ +void report_unknown_repos( Out & out, const std::list & not_found ); + template void get_repos( Zypper & zypper, const T & begin, const T & end, std::list & repos, std::list & not_found ); +template +void safe_lexical_cast( Source s, Target & tr ) +{ + try + { + tr = boost::lexical_cast( s ); + } + catch ( boost::bad_lexical_cast & ) + {;} +} + void report_unknown_repos( Out & out, const std::list & not_found ); /** @@ -67,31 +106,27 @@ void init_repos( Zypper & zypper ); void list_repos( Zypper & zypper ); /** - * Refresh all enabled repositories. - */ -void refresh_repos( Zypper & zypper ); - -/** - * Refresh a single repository. - * \return true on error, false otherwise - */ -bool refresh_repo( Zypper & zypper, const RepoInfo & repo ); - - -/** * Clean caches for all (specified) repositories. */ -void clean_repos( Zypper & zypper ); +enum class CleanRepoBits { + Default = 0, + CleanMetaData = 1, + CleanRawMetaData = 2, + CleanAll = CleanMetaData | CleanRawMetaData +}; +ZYPP_DECLARE_FLAGS_AND_OPERATORS(CleanRepoFlags, CleanRepoBits) +void clean_repos(Zypper & zypper, std::vector specificRepos, CleanRepoFlags flags ); /** * Try match given string with any known repository. * * \param str string to match * \param repo pointer to fill with found repository + * \param looseQuery_r Ignore query string in the URI if true. + * \param looseAuth_r Ignore user authentication data in the URI if true. * \return success if respository is found */ -bool match_repo( Zypper & zypper, const std::string str, RepoInfo *repo = 0 ); - +bool match_repo( Zypper & zypper, const std::string str, RepoInfo *repo = 0 , bool looseQuery_r = false, bool looseAuth_r = false ); /** * Add repository specified by \url to system repositories. @@ -103,7 +138,9 @@ bool match_repo( Zypper & zypper, const std::string str, RepoInfo *repo = 0 ); */ void add_repo_by_url(Zypper & zypper, const Url & url, - const std::string & alias); + const std::string & alias, + const RepoServiceCommonOptions &opts, + const RepoProperties &repoProps, bool noCheck); /** * Add repository specified in given repo file on \a repo_file_url. All repos @@ -114,13 +151,14 @@ void add_repo_by_url(Zypper & zypper, * \param enabled Whether the repo should be enabled * \param autorefresh Whether the repo should have autorefresh turned on */ -void add_repo_from_file( Zypper & zypper, - const std::string & repo_file_url ); +void add_repo_from_file(Zypper & zypper, + const std::string & repo_file_url , const RepoServiceCommonOptions &opts, const RepoProperties &repoProps, bool noCheck); /** * Add repository specified by \repo to system repositories. */ -bool add_repo( Zypper & zypper, RepoInfo & repo ); +bool add_repo(Zypper & zypper, RepoInfo & repo , bool noCheck); + /** * Remove repository specified by \a alias. @@ -131,51 +169,27 @@ void remove_repo( Zypper & zypper, const RepoInfo & repoinfo ); * Remove repositories which is matching filter options * like all, local, remote or medium-type */ -void remove_repos_by_option( Zypper & zypper ); - -/** - * Rename repository specified by \a alias to \a newalias. - */ -void rename_repo( Zypper & zypper, const std::string & alias, const std::string & newalias ); +void remove_repos_by_option(Zypper & zypper_r , const RepoServiceCommonSelectOptions selOpts_r); /** * Modify repository properties. * * \param alias repository alias */ -void modify_repo( Zypper & zypper, const std::string & alias ); - -/** - * Modify all repositories properties. - * - */ -void modify_all_repos( Zypper & zypper ); +void modify_repo( Zypper & zypper, const std::string & alias, const RepoServiceCommonOptions &commonOpts, const RepoProperties &repoProps ); /** * Modify repositories which is matching filter options * like all, local, remote or medium-type */ -void modify_repos_by_option( Zypper & zypper ); - - -void list_services( Zypper & zypper ); - -void add_service( Zypper & zypper, const ServiceInfo & service ); - -void add_service_by_url(Zypper & zypper, - const Url & url, - const std::string & alias); +void modify_repos_by_option( Zypper & zypper, const RepoServiceCommonSelectOptions &selectOpts, const RepoServiceCommonOptions &commonOpts, const RepoProperties &repoProps ); void remove_service( Zypper & zypper, const ServiceInfo & service ); void modify_service( Zypper & zypper, const std::string & alias ); -void refresh_services( Zypper & zypper ); - /** If root, refresh any plugin services before lr/ls/ref (bnc#893294) */ -void checkIfToRefreshPluginServices( Zypper & zypper ); - -bool match_service( Zypper & zypper, std::string str, repo::RepoInfoBase_Ptr & service_ptr ); +void checkIfToRefreshPluginServices( Zypper & zypper, RepoManager::RefreshServiceFlags flags_r = RepoManager::RefreshServiceFlags() ); void modify_services_by_option( Zypper & zypper ); @@ -203,6 +217,25 @@ void load_target_resolvables( Zypper & zypper ); */ void load_repo_resolvables( Zypper & zypper ); +ColorString repoPriorityNumber( unsigned prio_r, int width_r = 0 ); +ColorString repoPriorityNumberAnnotated( unsigned prio_r, int width_r = 0 ); + +const char * repoAutorefreshStr( const repo::RepoInfoBase & repo_r ); + +/** \return true if aliases are equal, and all lhs urls can be found in rhs */ +bool repo_cmp_alias_urls( const RepoInfo & lhs, const RepoInfo & rhs ); + +/** + * @TODO remove me with copts + */ +unsigned priority_from_copts( Zypper &zypper ); + +void repoPrioSummary( Zypper & zypper ); + +bool refresh_raw_metadata( Zypper & zypper, const RepoInfo & repo, bool force_download ); + +bool build_cache( Zypper & zypper, const RepoInfo & repo, bool force_build ); + #endif // Local Variables: // mode: c++ diff --git a/src/source-download.cc b/src/source-download.cc index b445841..bd036a2 100644 --- a/src/source-download.cc +++ b/src/source-download.cc @@ -256,7 +256,7 @@ namespace // scan installed packages to manifest { - if ( _zypper.defaultLoadSystem( _options->_dryrun ? NO_REPOS : LoadSystemFlags() ) != ZYPPER_EXIT_OK ) + if ( _zypper.defaultLoadSystem( _options->_dryrun ? NoRepos : LoadSystemFlags() ) != ZYPPER_EXIT_OK ) { ERR << "Startup returns " << _zypper.exitCode() << endl; throw( Out::Error(_("Failed to read download directory"), diff --git a/src/utils/flags/exceptions.cc b/src/utils/flags/exceptions.cc index d086d8a..be8b6ce 100644 --- a/src/utils/flags/exceptions.cc +++ b/src/utils/flags/exceptions.cc @@ -24,7 +24,7 @@ UnknownFlagException::UnknownFlagException(const std::string &flag) } InvalidValueException::InvalidValueException(const std::string &flag, const std::string &invalidValue, const std::string &reason) - : ZyppFlagsException( str::Format(_("The flag %1% is not compatible with argument %2% (%2).")) % flag % invalidValue % reason ) + : ZyppFlagsException( str::Format(_("The flag %1% is not compatible with argument %2% (%3%).")) % flag % invalidValue % reason ) { } @@ -41,4 +41,10 @@ FlagRepeatedException::FlagRepeatedException(const std::string &flag) } +ConflictingFlagsException::ConflictingFlagsException(const std::string &flag, const std::string &flag2) + : ZyppFlagsException( str::Format( _("%s used together with %s, which contradict each other.") ) % flag % flag2 ) +{ + +} + }} diff --git a/src/utils/flags/exceptions.h b/src/utils/flags/exceptions.h index 15dce86..56c9f9b 100644 --- a/src/utils/flags/exceptions.h +++ b/src/utils/flags/exceptions.h @@ -53,6 +53,12 @@ namespace ZyppFlags { public: FlagRepeatedException ( const std::string &flag ); }; + + class ConflictingFlagsException : public ZyppFlagsException + { + public: + ConflictingFlagsException ( const std::string &flag, const std::string &flag2 ); + }; }} diff --git a/src/utils/flags/flagtypes.cc b/src/utils/flags/flagtypes.cc index 04504a1..46574d3 100644 --- a/src/utils/flags/flagtypes.cc +++ b/src/utils/flags/flagtypes.cc @@ -6,10 +6,31 @@ \*---------------------------------------------------------------------------*/ #include "flagtypes.h" #include "main.h" +#include "utils/messages.h" +#include "utils/misc.h" namespace zypp { namespace ZyppFlags { +namespace { + +ResKind parseKindArgument( const CommandOption &opt, const boost::optional &in) +{ + if (!in) ZYPP_THROW(MissingArgumentException(opt.name)); //value required + ResKind knd = string_to_kind(*in); + if ( knd == ResKind::nokind ) + ZYPP_THROW(InvalidValueException( opt.name, *in, _("Unknown package type"))); + + return knd; +} + +} + +boost::optional noDefaultValue() +{ + return boost::optional(); +} + Value StringType(std::string *target, const boost::optional &defValue, std::string hint) { return Value ( [defValue]() -> boost::optional{ @@ -67,5 +88,89 @@ Value BoolType(bool *target, StoreFlag store, const boost::optional &defVa ); } +Value TriBoolType(TriBool &target, StoreFlag store, const boost::optional &defValue) +{ + return Value ( + [defValue]() -> boost::optional{ + if (!defValue) + return boost::optional(); + return asString ( *defValue ); + }, + [&target, store]( const CommandOption &, const boost::optional &){ + target = TriBool(store == StoreTrue); + } + ); +} + +Value CounterType(int *target, const boost::optional &defValue, const boost::optional &maxValue) +{ + return Value ( + [defValue]() -> boost::optional{ + if(defValue) { + return std::to_string(*defValue); + } else + return boost::optional(); + }, + + [target, maxValue]( const CommandOption &opt, const boost::optional & ) { + *target += 1; + if ( maxValue && *target > *maxValue) + ZYPP_THROW(ZyppFlagsException(str::Format(_("The flag '%1%' can only be used a maximum of %2% times.")) % opt.name % *maxValue)); + } + ); +} + + +Value KindSetType(std::set *target) { + return Value ( + noDefaultValue, + [target] ( const CommandOption &opt, const boost::optional &in ) { + target->insert( parseKindArgument( opt, in ) ); + return; + }, + "TYPE" + ); +} + +Value StringVectorType(std::vector *target, std::string hint) { + return Value ( + noDefaultValue, + [target] ( const CommandOption &opt, const boost::optional &in ) { + if ( !in || in->empty() ) ZYPP_THROW(MissingArgumentException(opt.name)); //value required + target->push_back(*in); + return; + }, + std::move(hint) + ); +} + +Value NoValue() +{ + return Value ( + noDefaultValue, + []( const CommandOption &, const boost::optional & ) { + return; + } + ); +} + +Value WarnOptionVal(Out &out_r, const std::string &warning_r, Out::Verbosity verbosity_r, const boost::optional &val_r ) +{ + return Value ( + [ val_r ] () -> boost::optional { + if ( val_r ) + return val_r->defaultValue(); + return boost::optional(); + }, + [ &out_r, warning_r, val_r, verbosity_r ] ( const CommandOption &opt, const boost::optional &in ) { + out_r.warning( warning_r, verbosity_r ); + if ( val_r ) { + Value val = *val_r; // C++ forces us to copy by value again + val.set ( opt, in ); + } + } + ); +} + } } diff --git a/src/utils/flags/flagtypes.h b/src/utils/flags/flagtypes.h index 420a87e..02e1609 100644 --- a/src/utils/flags/flagtypes.h +++ b/src/utils/flags/flagtypes.h @@ -9,8 +9,18 @@ #include "zyppflags.h" #include "exceptions.h" +#include "output/Out.h" + +#include +#include +#include + +class Out; namespace zypp { + +class Kind; + namespace ZyppFlags { /** @@ -23,20 +33,20 @@ Value StringType ( std::string *target, const boost::optional &def */ Value IntType ( int *target, const boost::optional &defValue = boost::optional() ); +/** + * Returns a \sa ZyppFlags::Value instance counting how many times a parameter was seen + */ +Value CounterType ( int *target, const boost::optional &defValue = boost::optional(), const boost::optional &maxValue = boost::optional() ); -template -Value StringContainerType ( Container *target, std::string hint = ARG_STRING ) { - return Value ( - []() -> boost::optional { return boost::optional(); }, - [target] ( CommandOption *opt, const boost::optional &in ) { - if (!in) ZYPP_THROW(MissingArgumentException(opt->name)); //value required - target->push_back(*in); - return; - }, - std::move(hint) - ); -} +/** + * Returns a \sa ZyppFlags::Value instance handling flags taking package or ressource types + */ +Value KindSetType ( std::set *target ); +/** + * Returns a \sa ZyppFlags::Value instance handling flags that fill a vector of strings + */ +Value StringVectorType (std::vector *target, std::string hint = "STRING" ); /** * Specifies how to handle when a boolean flag was seen on commandline @@ -52,6 +62,42 @@ enum StoreFlag : int{ */ Value BoolType ( bool *target, StoreFlag store = StoreTrue, const boost::optional &defValue = boost::optional() ); + +Value TriBoolType ( TriBool &target, StoreFlag store = StoreTrue, const boost::optional &defValue = boost::optional() ); + + +template +Value BitFieldType ( T& target, E flag , StoreFlag store = StoreTrue ) { + return Value ( + [ &target, flag] () -> boost::optional { + return target.testFlag ( flag ) ? std::string("true") : std::string("false"); + }, + [ &target, flag, store ] ( const CommandOption &, const boost::optional & ) { + if ( store == StoreTrue ) + target.setFlag ( flag ); + else + target.unsetFlag ( flag ); + } + ); +} + +/** + * Creates a null type, calling the setter or default value getter for this type will do nothing. + * Use this to have a ignored deprecated flag + */ +Value NoValue (); + +/** + * Creates a value that emits a warning when set, if \a val_r is valid the calls are forwarded to it after + * emitting the warning. + */ +Value WarnOptionVal (Out &out_r , const std::string &warning_r, Out::Verbosity verbosity_r = Out::NORMAL, const boost::optional &val_r = boost::optional()); + +/** + * Helper function that just returns a empty default value + */ +boost::optional noDefaultValue(); + }} #endif diff --git a/src/utils/flags/zyppflags.cc b/src/utils/flags/zyppflags.cc index 7715f32..86a2faf 100644 --- a/src/utils/flags/zyppflags.cc +++ b/src/utils/flags/zyppflags.cc @@ -5,15 +5,17 @@ |__/|_| |_| \*---------------------------------------------------------------------------*/ #include "zyppflags.h" +#include "flagtypes.h" +#include "exceptions.h" +#include "utils/messages.h" +#include "Zypper.h" #include -#include +#include #include #include #include -#include "exceptions.h" - namespace zypp { @@ -53,6 +55,8 @@ namespace { case OptionalArgument: has_arg = optional_argument; break; + default: + throw ZyppFlagsException( str::Format("Invalid opt.flags value for option: %1%") % opt.name ); } //we do not use the flag and val types, instead we use optind to figure out what happend @@ -101,6 +105,11 @@ std::string Value::argHint() const return _argHint; } +bool Value::wasSet() const +{ + return _wasSet; +} + int parseCLI(const int argc, char * const *argv, const std::vector &options, const int firstOpt) { // the short options string as used int getopt @@ -111,36 +120,41 @@ int parseCLI(const int argc, char * const *argv, const std::vector // the set of long options std::vector longopts; + // the set of all conflicting options + ConflictingFlagsList conflictingFlags; + //build a complete list and a long and short option index so we can //easily get to the CommandOption std::vector allOpts; - std::map longOptIndex; //we do not actually need that index other than checking for dups - std::map shortOptIndex; + std::unordered_map longOptIndex; //we do not actually need that index other than checking for dups + std::unordered_map shortOptIndex; for ( const CommandGroup &grp : options ) { for ( const CommandOption &currOpt : grp.options ) { allOpts.push_back( currOpt ); int allOptIndex = allOpts.size() - 1; + int flags = currOpt.flags; - if ( currOpt.flags & RequiredArgument && currOpt.flags & OptionalArgument ) { + if ( flags & RequiredArgument && flags & OptionalArgument ) { throw ZyppFlagsException("Argument can either be Required or Optional"); } if ( !currOpt.name.empty() ) { if ( !longOptIndex.insert( { currOpt.name, allOptIndex } ).second) { - throw ZyppFlagsException("Duplicate long option "); + throw ZyppFlagsException( str::Format("Duplicate long option ''%1%") % currOpt.name ); } appendToLongOptions( currOpt, longopts ); } if ( currOpt.shortName ) { if ( !shortOptIndex.insert( { currOpt.shortName, allOptIndex } ).second) { - throw ZyppFlagsException("Duplicate short option "); + throw ZyppFlagsException( str::Format("Duplicate short option %1%") % currOpt.shortName ); } appendToOptString( currOpt, shortopts ); } - allOptIndex++; + + conflictingFlags.insert( conflictingFlags.end(), grp.conflictingOptions.begin(), grp.conflictingOptions.end() ); } } @@ -167,7 +181,7 @@ int parseCLI(const int argc, char * const *argv, const std::vector if ( option_index == -1 && optopt) ZYPP_THROW(UnknownFlagException( std::string(1, optopt)) ); else - ZYPP_THROW(argv[optind - 1]); + ZYPP_THROW(UnknownFlagException( std::string(argv[optind - 1]) ) ); break; } case ':': { @@ -195,9 +209,32 @@ int parseCLI(const int argc, char * const *argv, const std::vector arg = std::string(optarg); } - allOpts[index].value.set( allOpts[index], arg); - } + CommandOption &opt = allOpts[index]; + // check if a conflicting option was used before + std::vector conflictingList; + for ( const auto &flagSet : conflictingFlags ) { + if ( std::find( flagSet.begin(), flagSet.end(), opt.name ) != flagSet.end() ) { + std::copy_if( flagSet.begin(), flagSet.end(), std::back_inserter(conflictingList), [ &opt ]( const std::string &val ) { + return val != opt.name; + }); + } + } + + if ( !conflictingList.empty() ) { + for ( const std::string conflicting : conflictingList ){ + auto it = longOptIndex.find( conflicting ); + if ( it == longOptIndex.end() ) { + WAR << "Ignoring unknown option " << conflicting << " specified as conflicting flag for " << opt.name << endl; + } else { + if ( allOpts[it->second].value.wasSet() ) { + throw ConflictingFlagsException( opt.name, conflicting ); + } + } + } + } + opt.value.set( allOpts[index], arg ); + } break; } } @@ -247,5 +284,28 @@ void renderHelp(const std::vector &options) } } +CommandOption::CommandOption( std::string &&name_r, char shortName_r, int flags_r, Value &&value_r, std::string &&help_r ) + : name ( std::move(name_r) ), + shortName ( shortName_r ), + flags ( flags_r ), + value ( std::move(value_r) ), + help ( std::move(help_r) ) +{ } + +CommandGroup::CommandGroup(std::string &&name_r, std::vector &&options_r, ConflictingFlagsList &&conflictingOptions_r ) + : name ( std::move(name_r) ), + options ( std::move(options_r) ), + conflictingOptions ( std::move(conflictingOptions_r) ) +{ } + +CommandGroup::CommandGroup( std::vector &&options_r, ConflictingFlagsList &&conflictingOptions_r ) + : CommandGroup ( _("Command options:"), std::move(options_r), std::move(conflictingOptions_r) ) +{ } + +CommandGroup::CommandGroup() + : CommandGroup ( std::vector(), ConflictingFlagsList() ) +{ } + + }} diff --git a/src/utils/flags/zyppflags.h b/src/utils/flags/zyppflags.h index 6ff9a57..94ae87d 100644 --- a/src/utils/flags/zyppflags.h +++ b/src/utils/flags/zyppflags.h @@ -57,13 +57,14 @@ namespace ZyppFlags { using SetterFun = std::function &in)>; enum ArgFlags : int { - NoArgument = 0x00, - RequiredArgument = 0x01, - OptionalArgument = 0x02, - ArgumentTypeMask = 0x0F, - - Repeatable = 0x10, // < the argument can be repeated - Hidden = 0x20 // < command is hidden in help + NoArgument = 0x00, + RequiredArgument = 0x01, + OptionalArgument = 0x02, + ArgumentTypeMask = 0x0F, + + Repeatable = 0x10, // < the argument can be repeated + Hidden = 0x20, // < command is hidden in help + Deprecated = 0x40 // < the option is about to be removed in the future }; /** @@ -99,6 +100,9 @@ namespace ZyppFlags { */ std::string argHint () const; + + bool wasSet () const; + private: bool _wasSet = false; DefValueFun _defaultVal; @@ -108,17 +112,38 @@ namespace ZyppFlags { struct CommandOption { + CommandOption ( std::string &&name_r, char shortName_r, int flags_r, Value &&value_r, std::string &&help_r = std::string()); + std::string name; char shortName; int flags; Value value; std::string help; + std::vector conflictingArguments; }; - struct CommandGroup + using ConflictingFlagsList = std::vector< std::vector< std::string > >; + + struct CommandGroup { - const std::string name; - std::vector options; + /** + * Creates a empty default group + */ + CommandGroup (); + + /** + * Creates the default command group with given options and conflicting flags + */ + CommandGroup ( std::vector &&options_r, ConflictingFlagsList &&conflictingOptions_r = ConflictingFlagsList() ); + + /** + * Creates the command group with given options, conflicting flags and the custom \a name_r + */ + CommandGroup ( std::string &&name_r, std::vector &&options_r, ConflictingFlagsList &&conflictingOptions_r = ConflictingFlagsList() ); + + std::string name; //< The name of the command group + std::vector options; //< The flags the command group supports + ConflictingFlagsList conflictingOptions; //< A list of conflicting flag pairs, each element specifies two flags that can't be used together }; /** diff --git a/src/utils/messages.cc b/src/utils/messages.cc index 8435ad7..6634bec 100644 --- a/src/utils/messages.cc +++ b/src/utils/messages.cc @@ -40,6 +40,21 @@ void report_too_many_arguments( Out & out, const std::string & specific_help ) // ---------------------------------------------------------------------------- +void report_too_few_arguments( const std::string & specific_help ) +{ + report_too_few_arguments( Zypper::instance().out(), specific_help ); +} + +void report_too_few_arguments( Out & out, const std::string & specific_help ) +{ + //! \todo make this more explanatory, e.g. "Ingoring arg1 arg2. This command does not take arguments. See %s for more information." + std::ostringstream s; + s << _("Usage") << ':' << endl << specific_help; + out.error(_("Too few arguments."), s.str() ); +} + +// ---------------------------------------------------------------------------- + void report_alias_or_aggregate_required ( Out & out, const std::string & specific_help ) { // translators: aggregate option is e.g. "--all". This message will be @@ -86,3 +101,28 @@ void print_verify_hint( Out & out ) " It is recommended to run '%s' after the operation has finished."), "zypper verify")); } + +std::string legacyCLIStr( const std::string & old_r, const std::string & new_r, LegacyCLIMsgType type_r ) +{ + switch (type_r) { + case LegacyCLIMsgType::Local: + case LegacyCLIMsgType::Global: + return str::Format( type_r == LegacyCLIMsgType::Global + ? _("Legacy commandline option %1% detected. Please use global option %2% instead.") + : _("Legacy commandline option %1% detected. Please use %2% instead.") ) + % NEGATIVEString(dashdash(old_r)) + % POSITIVEString(dashdash(new_r)); + break; + case LegacyCLIMsgType::Ignored: + return str::Format( + _("Legacy commandline option %1% detected. This option is ignored.")) + % NEGATIVEString(dashdash(old_r)); + break; + } + return std::string(); +} + +void print_legacyCLIStr( Out & out, const std::string & old_r, const std::string & new_r, Out::Verbosity verbosity_r, LegacyCLIMsgType type_r ) +{ + out.warning( legacyCLIStr( old_r, new_r, type_r), verbosity_r ); +} diff --git a/src/utils/messages.h b/src/utils/messages.h index 867d5b9..f343dc3 100644 --- a/src/utils/messages.h +++ b/src/utils/messages.h @@ -18,6 +18,10 @@ void report_a_bug (Out & out); void report_too_many_arguments(const std::string & specific_help); // deprecated void report_too_many_arguments(Out & out, const std::string & specific_help); +/** Say that too few arguments have been specified */ +void report_too_few_arguments( const std::string & specific_help ); +void report_too_few_arguments( Out & out, const std::string & specific_help ); + /** Say the that either a aggregate option or a alias is required */ void report_alias_or_aggregate_required ( Out & out, const std::string & specific_help ); @@ -31,5 +35,14 @@ void print_usage(Out & out, const std::string & command_help); void print_verify_hint(Out & out); +enum class LegacyCLIMsgType { + Local, + Global, + Ignored +}; +std::string legacyCLIStr( const std::string & old_r, const std::string & new_r, LegacyCLIMsgType type_r ); +void print_legacyCLIStr(Out & out, const std::string & old_r, const std::string & new_r, Out::Verbosity verbosity_r = Out::NORMAL, LegacyCLIMsgType type_r = LegacyCLIMsgType::Local ); + + #endif /*MESSAGES_H_*/ diff --git a/src/utils/misc.h b/src/utils/misc.h index ac5550d..ee682d5 100644 --- a/src/utils/misc.h +++ b/src/utils/misc.h @@ -18,6 +18,7 @@ #include #include #include +#include class Zypper; class Table; @@ -28,6 +29,7 @@ namespace zypp class Resolvable; class Product; class Pattern; + class Patch; } using namespace zypp; diff --git a/zypper.spec.cmake b/zypper.spec.cmake index 5b19a1b..b07dca4 100644 --- a/zypper.spec.cmake +++ b/zypper.spec.cmake @@ -26,7 +26,7 @@ BuildRequires: boost-devel >= 1.33.1 BuildRequires: cmake >= 2.4.6 BuildRequires: gcc-c++ >= 4.7 BuildRequires: gettext-devel >= 0.15 -BuildRequires: libzypp-devel >= 17.7.0 +BuildRequires: libzypp-devel >= 17.8.0 BuildRequires: readline-devel >= 5.1 BuildRequires: libxml2-devel Requires: procps -- 2.7.4