Imported Upstream version 1.14.14 upstream/1.14.14
authorDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 22 Jan 2019 05:07:02 +0000 (14:07 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 22 Jan 2019 05:07:02 +0000 (14:07 +0900)
71 files changed:
VERSION.cmake
package/zypper.changes
po/de.po
po/pt_BR.po
src/CMakeLists.txt
src/Command.cc
src/PackageArgs.cc
src/Zypper.cc
src/Zypper.h
src/commands/basecommand.cc
src/commands/basecommand.h
src/commands/conditions.cc [new file with mode: 0644]
src/commands/conditions.h [new file with mode: 0644]
src/commands/locks.h
src/commands/locks/add.cc
src/commands/locks/add.h
src/commands/locks/clean.cc [new file with mode: 0644]
src/commands/locks/clean.h [new file with mode: 0644]
src/commands/locks/list.cc
src/commands/locks/list.h
src/commands/locks/remove.cc
src/commands/locks/remove.h
src/commands/ps.cc [new file with mode: 0644]
src/commands/ps.h [new file with mode: 0644]
src/commands/repos.h [new file with mode: 0644]
src/commands/repos/add.cc [new file with mode: 0644]
src/commands/repos/add.h [new file with mode: 0644]
src/commands/repos/clean.cc [new file with mode: 0644]
src/commands/repos/clean.h [new file with mode: 0644]
src/commands/repos/list.cc [new file with mode: 0644]
src/commands/repos/list.h [new file with mode: 0644]
src/commands/repos/modify.cc [new file with mode: 0644]
src/commands/repos/modify.h [new file with mode: 0644]
src/commands/repos/refresh.cc [new file with mode: 0644]
src/commands/repos/refresh.h [new file with mode: 0644]
src/commands/repos/remove.cc [new file with mode: 0644]
src/commands/repos/remove.h [new file with mode: 0644]
src/commands/repos/rename.cc [new file with mode: 0644]
src/commands/repos/rename.h [new file with mode: 0644]
src/commands/reposerviceoptionsets.cc [new file with mode: 0644]
src/commands/reposerviceoptionsets.h [new file with mode: 0644]
src/commands/services.h [new file with mode: 0644]
src/commands/services/add.cc [new file with mode: 0644]
src/commands/services/add.h [new file with mode: 0644]
src/commands/services/common.cc [new file with mode: 0644]
src/commands/services/common.h [new file with mode: 0644]
src/commands/services/list.cc [new file with mode: 0644]
src/commands/services/list.h [new file with mode: 0644]
src/commands/services/modify.cc [new file with mode: 0644]
src/commands/services/modify.h [new file with mode: 0644]
src/commands/services/refresh.cc [new file with mode: 0644]
src/commands/services/refresh.h [new file with mode: 0644]
src/commands/services/remove.cc [new file with mode: 0644]
src/commands/services/remove.h [new file with mode: 0644]
src/locks.cc [deleted file]
src/locks.h [deleted file]
src/ps.cc [deleted file]
src/ps.h [deleted file]
src/repos.cc
src/repos.h
src/source-download.cc
src/utils/flags/exceptions.cc
src/utils/flags/exceptions.h
src/utils/flags/flagtypes.cc
src/utils/flags/flagtypes.h
src/utils/flags/zyppflags.cc
src/utils/flags/zyppflags.h
src/utils/messages.cc
src/utils/messages.h
src/utils/misc.h
zypper.spec.cmake

index 35babde..1724bf4 100644 (file)
@@ -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
 #=======
index 3df7965..caee880 100644 (file)
@@ -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
index d7c826d..e8e6e4b 100644 (file)
--- 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 <ada.lovelace@gmx.de>\n"
-"Language-Team: German <https://l10n.opensuse.org/projects/zypper/master/de/"
-">\n"
+"Language-Team: German <https://l10n.opensuse.org/projects/zypper/master/de/>"
+"\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
index 49e8d37..d81b96e 100644 (file)
@@ -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 <rmsolucoeseminformatic4@gmail.com>\n"
-"Language-Team: Portuguese (Brazil) <https://l10n.opensuse.org/projects/"
-"zypper/master/pt_BR/>\n"
+"PO-Revision-Date: 2018-10-09 21:05+0000\n"
+"Last-Translator: Luiz Fernando Ranghetti <elchevive68@gmail.com>\n"
+"Language-Team: Portuguese (Brazil) "
+"<https://l10n.opensuse.org/projects/zypper/master/pt_BR/>\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 <FILE.repo>'. Do do not translate lowercase wordparts
 #: src/utils/flags/zyppflags.h:27
 msgid "DIR"
-msgstr ""
+msgstr "DIR"
 
 #. translator: Option argument like '--export <FILE.repo>'. Do do not translate lowercase wordparts
 #: src/utils/flags/zyppflags.h:29
 msgid "FILE"
-msgstr ""
+msgstr "ARQUIVO"
 
 #. translator: Option argument like '--export <FILE.repo>'. Do do not translate lowercase wordparts
 #: src/utils/flags/zyppflags.h:31
@@ -625,7 +625,7 @@ msgstr "arquivo.repo"
 #. translator: Option argument like '--export <FILE.repo>'. Do do not translate lowercase wordparts
 #: src/utils/flags/zyppflags.h:33
 msgid "FORMAT"
-msgstr ""
+msgstr "FORMATO"
 
 #. translator: Option argument like '--export <FILE.repo>'. Do do not translate lowercase wordparts
 #: src/utils/flags/zyppflags.h:35
@@ -635,7 +635,7 @@ msgstr "inteiro"
 #. translator: Option argument like '--export <FILE.repo>'. Do do not translate lowercase wordparts
 #: src/utils/flags/zyppflags.h:37
 msgid "PATH"
-msgstr ""
+msgstr "CAMINHO"
 
 #. translator: Option argument like '--export <FILE.repo>'. Do do not translate lowercase wordparts
 #: src/utils/flags/zyppflags.h:39
@@ -645,12 +645,12 @@ msgstr "gravidade"
 #. translator: Option argument like '--export <FILE.repo>'. Do do not translate lowercase wordparts
 #: src/utils/flags/zyppflags.h:41
 msgid "STRING"
-msgstr ""
+msgstr "TEXTO"
 
 #. translator: Option argument like '--export <FILE.repo>'. Do do not translate lowercase wordparts
 #: src/utils/flags/zyppflags.h:43
 msgid "TAG"
-msgstr ""
+msgstr "ETIQUETA"
 
 #. translator: Option argument like '--export <FILE.repo>'. Do do not translate lowercase wordparts
 #: src/utils/flags/zyppflags.h:45
@@ -2063,7 +2063,7 @@ msgstr ""
 #. translators: --plus-repo, -p <URI>
 #: src/Zypper.cc:760
 msgid "Use an additional repository."
-msgstr "Usar um repositório adicional"
+msgstr "Usar um repositório adicional."
 
 #. translators: --plus-content <TAG>
 #: 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] <apelido|#|URI>\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 <DIR>
 #: 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.
index 78e6ae0..634f7ef 100644 (file)
@@ -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}
 )
 
index 2bab4bc..0f21b3d 100644 (file)
@@ -6,6 +6,7 @@
 \*---------------------------------------------------------------------------*/
 
 #include <map>
+#include <functional>
 
 #include <zypp/base/NamedValue.h>
 #include <zypp/base/Exception.h>
@@ -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<typename T>
+  ZypperBaseCommandPtr commandFactory ( const std::vector<std::string> &aliases_r )
+  {
+    return std::make_shared<T> ( aliases_r );
+  }
+
+  struct CommandFactory {
+    std::vector<std::string> aliases;
+    std::function<ZypperBaseCommandPtr ( const std::vector<std::string> & )> constructor;
+
+    ZypperBaseCommandPtr operator ()()
+    {
+      return constructor( aliases );
+    }
+
+    template <typename T>
+    constexpr static CommandFactory make ( const std::vector<std::string> &aliases_r )
+    {
+      return CommandFactory { aliases_r, commandFactory<T>};
+    }
+  };
+
   //@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<ListLocksCmd>() }
+    static std::map< ZypperCommand::Command,  CommandFactory> table {
+      { ZypperCommand::LIST_LOCKS_e,  CommandFactory::make<ListLocksCmd>( { "locks",       "ll", "lock-list"          }) },
+      { ZypperCommand::ADD_LOCK_e,    CommandFactory::make<AddLocksCmd>({ "addlock",     "al", "lock-add",     "la" }) },
+      { ZypperCommand::REMOVE_LOCK_e, CommandFactory::make<RemoveLocksCmd>({ "removelock",  "rl", "lock-delete" , "ld" }) },
+      { ZypperCommand::CLEAN_LOCKS_e, CommandFactory::make<CleanLocksCmd> ({ "cleanlocks" , "cl", "lock-clean"         }) },
+
+      { ZypperCommand::LIST_SERVICES_e, CommandFactory::make<ListServicesCmd>( { "services", "ls", "service-list", "sl" } ) },
+      { ZypperCommand::REFRESH_SERVICES_e, CommandFactory::make<RefreshServicesCmd>( { "refresh-services", "refs" } ) },
+      { ZypperCommand::MODIFY_SERVICE_e, CommandFactory::make<ModifyServiceCmd>( { "modifyservice", "ms" } ) }, //<<
+      { ZypperCommand::REMOVE_SERVICE_e, CommandFactory::make<RemoveServiceCmd>( { "removeservice", "rs", "service-delete", "sd" } ) },
+      { ZypperCommand::ADD_SERVICE_e, CommandFactory::make<AddServiceCmd>( { "addservice", "as", "service-add", "sa" } ) },
+
+      { ZypperCommand::LIST_REPOS_e, CommandFactory::make<ListReposCmd>( {"repos", "lr", "catalogs","ca"} ) },
+      { ZypperCommand::ADD_REPO_e, CommandFactory::make<AddRepoCmd>( { "addrepo", "ar" } ) },
+      { ZypperCommand::REMOVE_REPO_e, CommandFactory::make<RemoveRepoCmd>( { "removerepo", "rr" } ) },
+      { ZypperCommand::RENAME_REPO_e, CommandFactory::make<RenameRepoCmd>( { "renamerepo", "nr" } ) },
+      { ZypperCommand::MODIFY_REPO_e, CommandFactory::make<ModifyRepoCmd>( { "modifyrepo", "mr" } ) },
+      { ZypperCommand::REFRESH_e, CommandFactory::make<RefreshRepoCmd>( { "refresh", "ref" } ) },
+      { ZypperCommand::CLEAN_e, CommandFactory::make<CleanRepoCmd>( { "clean", "cc", "clean-cache", "you-clean-cache", "yc" } ) },
+
+      { ZypperCommand::PS_e, CommandFactory::make<PSCommand>( { "ps" }) }
     };
     return table;
   }
 
-  static NamedValue<ZypperCommand::Command> & table()
+  static NamedValue<ZypperCommand::Command> & cmdTable()
   {
     static NamedValue<ZypperCommand::Command> _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
 {
index 96674c8..d12a0ac 100644 (file)
@@ -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;
index ec9a82e..5864c59 100644 (file)
@@ -18,9 +18,6 @@
 
 #include <unistd.h>
 #include <readline/history.h>
-#include <sys/vfs.h>
-#include <sys/statvfs.h>
-#include <linux/magic.h>
 
 #include <zypp/ZYppFactory.h>
 #include <zypp/zypp_detail/ZYppReadOnlyHack.h>
 #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"
 #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 <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] <URI> <ALIAS>")
-    )
-    .description(// translators: command description
-    _("Add a repository index service to the system.")
-    )
-    .optionSectionCommandOptions()
-    .option_SERVICE_PROP
-    .legacyOptionSection()
-    .option( "-t, --type <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] <ALIAS|#|URI>")
-    )
-    .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 <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) <OPTIONS> <ALIAS|#|URI>")
-    )
-    .synopsis( str::Format(    // translators: command synopsis; do not translate lowercase words
-    _("modifyservice (ms) <OPTIONS> <%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 <TYPE>",       _("Apply changes to services of specified type.") )
-    .gap()
-    .option( "-i, --ar-to-enable <ALIAS>",     _("Add a RIS service repository to enable.") )
-    .option( "-I, --ar-to-disable <ALIAS>",    _("Add a RIS service repository to disable.") )
-    .option( "-j, --rr-to-enable <ALIAS>",     _("Remove a RIS service repository to enable.") )
-    .option( "-J, --rr-to-disable <ALIAS>",    _("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] <URI> <ALIAS>")
-    )
-     .synopsis(        // translators: command synopsis; do not translate lowercase words
-    _("addrepo (ar) [OPTIONS] <FILE.repo>")
-    )
-    .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 <FILE.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 <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 <FILE.repo>",       // translators: -e, --export <FILE.repo>
-             _("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] <alias|#|URI>\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] <alias|#|URI>\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] <ALIAS|#|URI>")
-    )
-    .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] <ALIAS|#|URI> <NEW-ALIAS>")
-    )
-    .description(      // translators: command description
-    _("Assign new alias to the repository specified by alias, number or URI.")
-    )
-    .noOptionSection()
-    ;
 #if 0
     _command_help = _(
       "renamerepo (nr) [OPTIONS] <alias|#|URI> <new-alias>\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 <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) <OPTIONS> <ALIAS|#|URI>")
-    )
-    .synopsis( str::Format(    // translators: command synopsis; do not translate lowercase words
-    _("modifyrepo (mr) <OPTIONS> <%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 <ALIAS|#|URI>",       // translators: -r, --repo <ALIAS|#|URI>
-             _("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 <ALIAS|#|URI>",       // translators: -r, --repo <ALIAS|#|URI>
-             _("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] <PACKAGENAME> ...")
+    .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 <ALIAS|#|URI>",       // translators: -r, --repo <ALIAS|#|URI>
-            _("Restrict the lock to the specified repository.") )
-    .option( "-t, --type <TYPE>",      // translators: -t, --type <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] <LOCK-NUMBER|PACKAGENAME> ...")
+    .synopsis( // translators: command synopsis; do not translate lowercase words
+    _("versioncmp (vcmp) <VERSION1> <VERSION2>")
     )
-    .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 <ALIAS|#|URI>",       // translators: -r, --repo <ALIAS|#|URI>
-            _("Remove only locks with specified repository.") )
-    .option( "-t, --type <TYPE>",      // translators: -t, --type <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) <VERSION1> <VERSION2>")
-    )
-    .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) <version1> <version2>\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) <version1> <version2>\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<PsOptions> 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 <FORMAT>",       // translators: --print <FORMAT>
-            _("For each associated system service print <FORMAT> on the standard output, followed by a newline. Any '%s' directive in <FORMAT> is replaced by the system service name.") )
-    .option("-d, --debugFile <PATH>", // translators: -d, --debugFile <PATH>
-       _("Write debug output to file <PATH>."))
-    ;
-    break;
-  }
-
-
   case ZypperCommand::DOWNLOAD_e:
   {
     shared_ptr<DownloadOptions> 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<ServiceInfo>(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<RepoInfo,RepoInfoAliasComparator> 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<repo::RepoInfoBase_Ptr, ServiceAliasComparator> 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<RepoInfo>(*it);
-        if (repo_ptr)
-          remove_repo(*this, *repo_ptr);
-        else
-          remove_service(*this, *dynamic_pointer_cast<ServiceInfo>(*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<PsOptions> myOpts( assertCommandOptions<PsOptions>() );
-    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() )
index 73ef5e5..45752a6 100644 (file)
@@ -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.
  *
index a23b578..8dfec83 100644 (file)
@@ -3,9 +3,14 @@
 #include <boost/optional.hpp>
 #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<std::string> &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<std::string>{synopsis_r}, summary_r, description_r, systemInitFlags_r )
+{
+
+}
+
+ZypperBaseCommand::ZypperBaseCommand(const std::vector<std::string> &commandAliases_r, const std::vector<std::string> &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<std::string> ZypperBaseCommand::command() const
+{
+  return _commandAliases;
+}
+
+std::string ZypperBaseCommand::summary() const
+{
+  return _summary;
+}
+
+std::vector<std::string> 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<BaseCommandConditionPtr> ZypperBaseCommand::conditions() const
 {
   return std::vector<BaseCommandConditionPtr>();
 }
 
-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<std::string> &positionalArgs)
@@ -61,7 +154,7 @@ int ZypperBaseCommand::run(Zypper &zypp, const std::vector<std::string> &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<std::string> &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<std::string> &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<ZyppFlags::CommandGroup> opts = options();
+
+  //collect all deprecated options
+  std::vector<const ZyppFlags::CommandOption*> 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<ZyppFlags::CommandGroup> ZypperBaseCommand::options()
 {
   //first get the commands own options
-  std::vector<ZyppFlags::CommandGroup> allOpts {
-    { _("Options:"), cmdOptions() }
-  };
-
-  ZyppFlags::CommandOption helpOpt{
-      "help", 'h', ZyppFlags::NoArgument | ZyppFlags::Hidden, ZyppFlags::BoolType( &_helpRequested ), ""
+  std::vector<ZyppFlags::CommandGroup> 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<ZyppFlags::CommandGroup> 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;
 }
 
index c3c339d..2428bbb 100644 (file)
@@ -1,13 +1,15 @@
 #ifndef ZYPPER_COMMANDS_BASECOMMAND_INCLUDED
 #define ZYPPER_COMMANDS_BASECOMMAND_INCLUDED
 
-#include <list>
+#include <vector>
 #include <string>
 #include <memory>
 
 #include "zypp/base/Flags.h"
 #include "utils/flags/zyppflags.h"
 
+#include <zypp/ZYpp.h>
+
 class Zypper;
 class ZypperBaseCommand;
 
@@ -41,18 +43,25 @@ public:
 };
 using BaseCommandConditionPtr = std::shared_ptr<BaseCommandCondition>;
 
-
-/** 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<std::string> &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<std::string> &commandAliases_r,
+                      const std::vector<std::string> &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<std::string> command () const = 0;
+  virtual std::vector<std::string> 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<std::string> 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<zypp::ZyppFlags::CommandOption> 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<std::string> &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<BaseCommandOptionSet *> _registeredOptionSets;
   bool _helpRequested = false;
+  std::vector<std::string> _commandAliases;
+  std::vector<std::string> _synopsis;
+  std::string _summary;
+  std::string _description;
+  SetupSystemFlags _systemInitFlags;
 };
 
 using ZypperBaseCommandPtr = std::shared_ptr<ZypperBaseCommand> ;
diff --git a/src/commands/conditions.cc b/src/commands/conditions.cc
new file mode 100644 (file)
index 0000000..3e11f0f
--- /dev/null
@@ -0,0 +1,58 @@
+/*---------------------------------------------------------------------------*\
+                          ____  _ _ __ _ __  ___ _ _
+                         |_ / || | '_ \ '_ \/ -_) '_|
+                         /__|\_, | .__/ .__/\___|_|
+                             |__/|_|  |_|
+\*---------------------------------------------------------------------------*/
+#include "conditions.h"
+#include "Zypper.h"
+
+#include <sys/vfs.h>
+#include <sys/statvfs.h>
+#include <linux/magic.h>
+
+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 (file)
index 0000000..d4a1e77
--- /dev/null
@@ -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
index 1aa8349..7e921ee 100644 (file)
@@ -4,5 +4,6 @@
 #include "locks/add.h"
 #include "locks/remove.h"
 #include "locks/list.h"
+#include "locks/clean.h"
 
 #endif
index e69de29..84e8315 100644 (file)
@@ -0,0 +1,120 @@
+/*---------------------------------------------------------------------------*\
+                          ____  _ _ __ _ __  ___ _ _
+                         |_ / || | '_ \ '_ \/ -_) '_|
+                         /__|\_, | .__/ .__/\___|_|
+                             |__/|_|  |_|
+\*---------------------------------------------------------------------------*/
+#include "add.h"
+
+#include <iostream>
+
+#include <zypp/base/String.h>
+#include <zypp/base/Logger.h>
+#include <zypp/Locks.h>
+
+#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<std::string> &commandAliases_r ) :
+  ZypperBaseCommand (
+    commandAliases_r,
+    // translators: command synopsis; do not translate the command 'name (abbreviations)' or '-option' names
+    _("addlock (al) [OPTIONS] <PACKAGENAME> ..."),
+    // 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<AddLocksCmd *>(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<std::string> &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<BaseCommandConditionPtr> AddLocksCmd::conditions() const
+{
+  return {
+    std::make_shared<NeedsRootCondition>()
+  };
+}
index e69de29..e9cb7f1 100644 (file)
@@ -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 <zypp/ResKind.h>
+#include <set>
+
+class AddLocksCmd : public ZypperBaseCommand
+{
+public:
+  AddLocksCmd( const std::vector<std::string> &commandAliases_r );
+
+protected:
+  // ZypperBaseCommand interface
+  zypp::ZyppFlags::CommandGroup cmdOptions() const override;
+  void doReset() override;
+  int execute(Zypper &zypp_r, const std::vector<std::string> &positionalArgs_r) override;
+  std::vector<BaseCommandConditionPtr> conditions() const override;
+
+private:
+  std::set<zypp::ResKind> _kinds;
+  std::vector<std::string> _repos;
+};
+
+
+
+#endif
diff --git a/src/commands/locks/clean.cc b/src/commands/locks/clean.cc
new file mode 100644 (file)
index 0000000..9d78fab
--- /dev/null
@@ -0,0 +1,74 @@
+#include "clean.h"
+
+#include <zypp/Locks.h>
+
+#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<std::string> &commandAliases_r) :
+  ZypperBaseCommand (
+    commandAliases_r,
+    _("cleanlocks (cl)"),
+    // translators: command summary
+    _("Remove useless locks."),
+    std::string()
+  )
+{ }
+
+std::vector<BaseCommandConditionPtr> CleanLocksCmd::conditions() const
+{
+  return {
+    std::make_shared<NeedsRootCondition>()
+  };
+}
+
+ZyppFlags::CommandGroup CleanLocksCmd::cmdOptions() const
+{
+  auto that = const_cast<CleanLocksCmd *>(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<std::string> &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 (file)
index 0000000..d39b709
--- /dev/null
@@ -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 <zypp/ResKind.h>
+#include <set>
+
+class CleanLocksCmd : public ZypperBaseCommand
+{
+public:
+  CleanLocksCmd( const std::vector<std::string> &commandAliases_r );
+
+  // ZypperBaseCommand interface
+  std::string description() const override;
+
+protected:
+  std::vector<BaseCommandConditionPtr> conditions() const override;
+  zypp::ZyppFlags::CommandGroup cmdOptions() const override;
+  void doReset() override;
+  int execute(Zypper &zypp, const std::vector<std::string> &positionalArgs) override;
+private:
+  bool _onlyDuplicates = false;
+  bool _onlyEmpty = false;
+};
+
+
+
+#endif
index 4458919..1cc72d9 100644 (file)
@@ -1,3 +1,9 @@
+/*---------------------------------------------------------------------------*\
+                          ____  _ _ __ _ __  ___ _ _
+                         |_ / || | '_ \ '_ \/ -_) '_|
+                         /__|\_, | .__/ .__/\___|_|
+                             |__/|_|  |_|
+\*---------------------------------------------------------------------------*/
 #include "list.h"
 
 #include <iostream>
@@ -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<std::string> 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<std::string> &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<ZyppFlags::CommandOption> ListLocksCmd::cmdOptions() const
+ZyppFlags::CommandGroup ListLocksCmd::cmdOptions() const
 {
-  return {
+  return {{
     {
       { "matches", 'm', ZyppFlags::NoArgument, ZyppFlags::BoolType( const_cast<bool *>(&_matches), ZyppFlags::StoreTrue, _matches), _("Show the number of resolvables matched by each lock.") },
       { "solvables", 's', ZyppFlags::NoArgument, ZyppFlags::BoolType( const_cast<bool *>(&_solvables), ZyppFlags::StoreTrue, _solvables), _("List the resolvables matched by each lock.")}
     }
-  };
+  }};
 }
 
 int ListLocksCmd::execute(Zypper &zypper, const std::vector<std::string> &positionalArgs)
index 35aed36..eb02769 100644 (file)
@@ -1,3 +1,9 @@
+/*---------------------------------------------------------------------------*\
+                          ____  _ _ __ _ __  ___ _ _
+                         |_ / || | '_ \ '_ \/ -_) '_|
+                         /__|\_, | .__/ .__/\___|_|
+                             |__/|_|  |_|
+\*---------------------------------------------------------------------------*/
 #ifndef ZYPPER_COMMANDS_LOCKS_LIST_H_INCLUDED
 #define ZYPPER_COMMANDS_LOCKS_LIST_H_INCLUDED
 
 
 class ListLocksCmd : public ZypperBaseCommand
 {
-  // ZypperBaseCommand interface
 public:
-  std::list<std::string> command() const override;
-  std::string summary() const override;
-  std::string synopsis() const override;
+  ListLocksCmd( const std::vector<std::string> &commandAliases_r );
+
+  // ZypperBaseCommand interface
   std::string description() const override;
-  LoadSystemFlags needSystemSetup() const override;
 
 protected:
   int execute(Zypper &zypper, const std::vector<std::string> &positionalArgs) override;
-  std::vector<zypp::ZyppFlags::CommandOption> cmdOptions() const override;
+  zypp::ZyppFlags::CommandGroup cmdOptions() const override;
   void doReset() override;
+  int systemSetup(Zypper &zypp_r) override;
 
 private:
   bool _matches   = false;
index e69de29..a93faa9 100644 (file)
@@ -0,0 +1,139 @@
+/*---------------------------------------------------------------------------*\
+                          ____  _ _ __ _ __  ___ _ _
+                         |_ / || | '_ \ '_ \/ -_) '_|
+                         /__|\_, | .__/ .__/\___|_|
+                             |__/|_|  |_|
+\*---------------------------------------------------------------------------*/
+#include "remove.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include <zypp/base/String.h>
+#include <zypp/Locks.h>
+
+#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<std::string> &commandAliases_r)
+  : ZypperBaseCommand(
+      commandAliases_r,
+      _("removelock (rl) [OPTIONS] <LOCK-NUMBER|PACKAGENAME> ..."),
+      _("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<BaseCommandConditionPtr> RemoveLocksCmd::conditions() const
+{
+  return {
+    std::make_shared<NeedsRootCondition>()
+  };
+}
+
+ZyppFlags::CommandGroup RemoveLocksCmd::cmdOptions() const
+{
+  auto that = const_cast<RemoveLocksCmd *>(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<std::string> &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;
+}
index e69de29..3b8c12a 100644 (file)
@@ -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 <zypp/ResKind.h>
+#include <set>
+
+class RemoveLocksCmd : public ZypperBaseCommand
+{
+public:
+  RemoveLocksCmd( const std::vector<std::string> &commandAliases_r );
+
+  // ZypperBaseCommand interface
+protected:
+  std::vector<BaseCommandConditionPtr> conditions() const override;
+  zypp::ZyppFlags::CommandGroup cmdOptions() const override;
+  void doReset() override;
+  int execute(Zypper &zypp_r, const std::vector<std::string> &positionalArgs_r) override;
+
+private:
+  std::set<zypp::ResKind> _kinds;
+  std::vector<std::string> _repos;
+};
+
+
+
+#endif
diff --git a/src/commands/ps.cc b/src/commands/ps.cc
new file mode 100644 (file)
index 0000000..7d1d484
--- /dev/null
@@ -0,0 +1,204 @@
+/*---------------------------------------------------------------------------*\
+                          ____  _ _ __ _ __  ___ _ _
+                         |_ / || | '_ \ '_ \/ -_) '_|
+                         /__|\_, | .__/ .__/\___|_|
+                             |__/|_|  |_|
+\*---------------------------------------------------------------------------*/
+#include "ps.h"
+
+#include <iostream>
+
+#include <zypp/base/LogTools.h>
+#include <zypp/ExternalProgram.h>
+#include <zypp/misc/CheckAccessDeleted.h>
+
+#include "Zypper.h"
+#include "Table.h"
+#include "utils/messages.h"
+#include "utils/flags/flagtypes.h"
+
+using namespace zypp;
+
+PSCommand::PSCommand(const std::vector<std::string> &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<PSCommand *>(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<const char *>(), "FORMAT")
+            // translators: --print <format>
+          , _("For each associated system service print <format> on the standard output, followed by a newline. Any '%s' directive in <format> is replaced by the system service name.")
+    }, { "debugFile", 'd', ZyppFlags::RequiredArgument, ZyppFlags::StringType(&that->_debugFile, boost::optional<const char *>(), "PATH")
+            // translators: -d, --debugFile <path>
+          , _("Write debug output to file <path>.")
+    }
+  }};
+}
+
+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<std::string> 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<std::string> &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<std::string>::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 (file)
index 0000000..cbfeccc
--- /dev/null
@@ -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<std::string> &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<std::string> &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 (file)
index 0000000..26d62c1
--- /dev/null
@@ -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 (file)
index 0000000..0e7bc56
--- /dev/null
@@ -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 <zypp/repo/RepoException.h>
+
+using namespace zypp;
+
+AddRepoCmd::AddRepoCmd(const std::vector<std::string> &commandAliases_r) :
+  ZypperBaseCommand(
+    commandAliases_r,
+    std::vector<std::string>{ _("addrepo (ar) [OPTIONS] <URI> <ALIAS>"), _("addrepo (ar) [OPTIONS] <FILE.repo>") },
+    _("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<BaseCommandConditionPtr> AddRepoCmd::conditions() const
+{
+  return {
+    std::make_shared<NeedsRootCondition>()
+  };
+}
+
+zypp::ZyppFlags::CommandGroup AddRepoCmd::cmdOptions() const
+{
+  auto that = const_cast<AddRepoCmd *>(this);
+  return {{
+    { "repo", 'r', ZyppFlags::RequiredArgument, ZyppFlags::StringType( &that->_repoFile, boost::optional<const char *>(), 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<ZyppFlags::Value>() ),
+            _("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<std::string> &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 (file)
index 0000000..e29e886
--- /dev/null
@@ -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 <zypp/TriBool.h>
+
+#include <string>
+
+class AddRepoCmd : public ZypperBaseCommand
+{
+public:
+  AddRepoCmd( const std::vector<std::string> &commandAliases_r );
+
+  // ZypperBaseCommand interface
+protected:
+  std::vector<BaseCommandConditionPtr> conditions() const override;
+  zypp::ZyppFlags::CommandGroup cmdOptions() const override;
+  void doReset() override;
+  int execute(Zypper &zypp_r, const std::vector<std::string> &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 (file)
index 0000000..4985184
--- /dev/null
@@ -0,0 +1,74 @@
+/*---------------------------------------------------------------------------*\
+                          ____  _ _ __ _ __  ___ _ _
+                         |_ / || | '_ \ '_ \/ -_) '_|
+                         /__|\_, | .__/ .__/\___|_|
+                             |__/|_|  |_|
+\*---------------------------------------------------------------------------*/
+#include "clean.h"
+
+#include "commands/conditions.h"
+#include "utils/flags/flagtypes.h"
+#include "Zypper.h"
+
+CleanRepoCmd::CleanRepoCmd( const std::vector<std::string> &commandAliases_r ):
+  ZypperBaseCommand(
+    commandAliases_r,
+    _("clean (cc) [ALIAS|#|URI] ..."),
+    _("Clean local caches."),
+    _("Clean local caches."),
+    ResetRepoManager )
+{ }
+
+std::vector<BaseCommandConditionPtr> CleanRepoCmd::conditions() const
+{
+  return {
+    std::make_shared<NeedsRootCondition>()
+  };
+}
+
+zypp::ZyppFlags::CommandGroup CleanRepoCmd::cmdOptions() const
+{
+  auto that = const_cast<CleanRepoCmd *>(this);
+  return {{
+      {
+        "repo", 'r', ZyppFlags::RequiredArgument | ZyppFlags::Repeatable,
+            ZyppFlags::StringVectorType( &that->_repos, ARG_REOSITORY),
+            // translators: -r, --repo <ALIAS|#|URI>
+            _("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<std::string> &positionalArgs_r )
+{
+  // get the list of repos specified on the command line ...
+  std::vector<std::string> 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 (file)
index 0000000..3ef0c64
--- /dev/null
@@ -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 <string>
+#include <vector>
+
+class CleanRepoCmd : public ZypperBaseCommand
+{
+public:
+  CleanRepoCmd( const std::vector<std::string> &commandAliases_r );
+
+  // ZypperBaseCommand interface
+protected:
+  std::vector<BaseCommandConditionPtr> conditions() const override;
+  zypp::ZyppFlags::CommandGroup cmdOptions() const override;
+  void doReset() override;
+  int execute(Zypper &zypp_r, const std::vector<std::string> &positionalArgs_r) override;
+
+private:
+  std::vector<std::string> _repos;
+  CleanRepoFlags _flags;
+};
+
+#endif
diff --git a/src/commands/repos/list.cc b/src/commands/repos/list.cc
new file mode 100644 (file)
index 0000000..0f19374
--- /dev/null
@@ -0,0 +1,348 @@
+#include "list.h"
+#include "Zypper.h"
+#include "repos.h"
+#include "utils/messages.h"
+#include "utils/flags/flagtypes.h"
+
+#include <zypp/RepoManager.h>
+
+#include <fstream>
+
+using namespace zypp;
+
+namespace {
+
+void print_repos_to( const std::list<RepoInfo> & 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<RepoInfo> repos )
+{
+  cout << "<repo-list>" << endl;
+  for_( it, repos.begin(), repos.end() )
+    it->dumpAsXmlOn( cout );
+  cout << "</repo-list>" << endl;
+}
+
+void print_repo_details( Zypper & zypper, std::list<RepoInfo> & 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<std::string> &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<ListReposCmd *>(this);
+  return {{
+      { "export", 'e', ZyppFlags::RequiredArgument, ZyppFlags::StringType(&that->_exportFile, boost::optional<const char *>(), "FILE.repo"),
+            // translators: -e, --export <FILE.repo>
+            _("Export all defined repositories as a single local .repo file.") }
+  }};
+}
+
+void ListReposCmd::doReset()
+{
+  _exportFile.clear();
+}
+
+int ListReposCmd::execute( Zypper &zypp_r, const std::vector<std::string> &positionalArgs_r )
+{
+  checkIfToRefreshPluginServices( zypp_r );
+
+  RepoManager & manager = zypp_r.repoManager();
+  RuntimeData & gData = zypp_r.runtimeData();
+  std::list<RepoInfo> repos;
+  std::list<std::string> 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<RepoInfo> & 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 (file)
index 0000000..9df8f4c
--- /dev/null
@@ -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 <zypp/base/Flags.h>
+#include <zypp/RepoInfo.h>
+
+class ListReposCmd : public ZypperBaseCommand
+{
+public:
+  ListReposCmd( const std::vector<std::string> &commandAliases_r );
+
+  // ZypperBaseCommand interface
+protected:
+  zypp::ZyppFlags::CommandGroup cmdOptions() const override;
+  void doReset() override;
+  int execute(Zypper &zypp_r, const std::vector<std::string> &positionalArgs_r) override;
+  void printRepoList(Zypper &zypper, const std::list<zypp::RepoInfo> &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 (file)
index 0000000..a7d96c0
--- /dev/null
@@ -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<std::string> &commandAliases_r) :
+  ZypperBaseCommand (
+    commandAliases_r,
+    {
+      // translators: command synopsis; do not translate lowercase words
+      _("modifyrepo (mr) <OPTIONS> <ALIAS|#|URI>"),
+      // translators: command synopsis; do not translate lowercase words
+      str::Format( _("modifyrepo (mr) <OPTIONS> <%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<BaseCommandConditionPtr> ModifyRepoCmd::conditions() const
+{
+  return {
+    std::make_shared<NeedsRootCondition>()
+  };
+}
+
+zypp::ZyppFlags::CommandGroup ModifyRepoCmd::cmdOptions() const
+{
+  auto that = const_cast<ModifyRepoCmd *>(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<std::string> &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 (file)
index 0000000..9417d28
--- /dev/null
@@ -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<std::string> &commandAliases_r );
+
+  // ZypperBaseCommand interface
+  std::string help() override;
+
+protected:
+  std::vector<BaseCommandConditionPtr> conditions() const override;
+  zypp::ZyppFlags::CommandGroup cmdOptions() const override;
+  void doReset() override;
+  int execute(Zypper &zypp_r, const std::vector<std::string> &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 (file)
index 0000000..a07cb59
--- /dev/null
@@ -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<std::string> &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<BaseCommandConditionPtr> RefreshRepoCmd::conditions() const
+{
+  return {
+    std::make_shared<NeedsRootCondition>()
+  };
+}
+
+zypp::ZyppFlags::CommandGroup RefreshRepoCmd::cmdOptions() const
+{
+  auto that = const_cast<RefreshRepoCmd *>(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 <ALIAS|#|URI>
+            _("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<std::string> &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<std::string> 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<std::string> repos_r )
+{
+  RepoManager & manager( zypp_r.repoManager() );
+  const std::list<RepoInfo> & repos( manager.knownRepositories() );
+
+  // get the list of repos specified on the command line ...
+  std::list<RepoInfo> specified;
+  std::list<std::string> 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<RepoInfo> 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 (file)
index 0000000..f2c1869
--- /dev/null
@@ -0,0 +1,50 @@
+/*---------------------------------------------------------------------------*\
+                          ____  _ _ __ _ __  ___ _ _
+                         |_ / || | '_ \ '_ \/ -_) '_|
+                         /__|\_, | .__/ .__/\___|_|
+                             |__/|_|  |_|
+\*---------------------------------------------------------------------------*/
+#ifndef ZYPPER_COMMANDS_REPOS_REFRESH_H_INCLUDED
+#define ZYPPER_COMMANDS_REPOS_REFRESH_H_INCLUDED
+
+#include "commands/basecommand.h"
+
+#include <zypp/base/Flags.h>
+
+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<std::string> &commandAliases_r );
+
+  static int refreshRepositories ( Zypper &zypp_r, RefreshFlags flags_r = Default, const std::vector<std::string> repos_r = std::vector<std::string>() );
+
+  /** \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<BaseCommandConditionPtr> conditions() const override;
+  zypp::ZyppFlags::CommandGroup cmdOptions() const override;
+  void doReset() override;
+  int execute(Zypper &zypp_r, const std::vector<std::string> &positionalArgs) override;
+
+
+private:
+  RefreshFlags _flags;
+  std::vector<std::string> _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 (file)
index 0000000..043350c
--- /dev/null
@@ -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<std::string> &commandAliases_r ) :
+  ZypperBaseCommand (
+    commandAliases_r,
+    _("removerepo (rr) [OPTIONS] <ALIAS|#|URI>"),
+    _("Remove specified repository."),
+    _("Remove repository specified by alias, number or URI."),
+    ResetRepoManager
+    )
+{
+
+}
+
+std::vector<BaseCommandConditionPtr> RemoveRepoCmd::conditions() const
+{
+  return {
+    std::make_shared<NeedsRootCondition>()
+  };
+}
+
+zypp::ZyppFlags::CommandGroup RemoveRepoCmd::cmdOptions() const
+{
+  //@TODO merge into a OptionSet to share with RemoveServiceCommand ?
+  auto that = const_cast<RemoveRepoCmd *>(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<std::string> &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<RepoInfo,RepoInfoAliasComparator> 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 (file)
index 0000000..5aa40d3
--- /dev/null
@@ -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 <zypp/TriBool.h>
+
+#include <string>
+
+class RemoveRepoCmd : public ZypperBaseCommand
+{
+public:
+  RemoveRepoCmd( const std::vector<std::string> &commandAliases_r );
+
+  // ZypperBaseCommand interface
+protected:
+  std::vector<BaseCommandConditionPtr> conditions() const override;
+  zypp::ZyppFlags::CommandGroup cmdOptions() const override;
+  void doReset() override;
+  int execute(Zypper &zypp, const std::vector<std::string> &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 (file)
index 0000000..6ef9e65
--- /dev/null
@@ -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<std::string> &commandAliases_r) :
+  ZypperBaseCommand (
+    commandAliases_r,
+    // translators: command synopsis; do not translate lowercase words
+    _("renamerepo (nr) [OPTIONS] <ALIAS|#|URI> <NEW-ALIAS>"),
+    _("Rename specified repository."),
+    // translators: command description
+    _("Assign new alias to the repository specified by alias, number or URI."),
+    ResetRepoManager
+    )
+{ }
+
+std::vector<BaseCommandConditionPtr> RenameRepoCmd::conditions() const
+{
+  return {
+    std::make_shared<NeedsRootCondition>()
+  };
+}
+
+zypp::ZyppFlags::CommandGroup RenameRepoCmd::cmdOptions() const
+{
+  return {};
+}
+
+void RenameRepoCmd::doReset()
+{ }
+
+int RenameRepoCmd::execute( Zypper &zypp_r, const std::vector<std::string> &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 (file)
index 0000000..cfd8088
--- /dev/null
@@ -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 <zypp/TriBool.h>
+
+#include <string>
+
+class RenameRepoCmd : public ZypperBaseCommand
+{
+public:
+  RenameRepoCmd( const std::vector<std::string> &commandAliases_r );
+
+  // ZypperBaseCommand interface
+protected:
+  std::vector<BaseCommandConditionPtr> conditions() const override;
+  zypp::ZyppFlags::CommandGroup cmdOptions() const override;
+  void doReset() override;
+  int execute(Zypper &zypp_r, const std::vector<std::string> &positionalArgs_r) override;
+};
+
+#endif
diff --git a/src/commands/reposerviceoptionsets.cc b/src/commands/reposerviceoptionsets.cc
new file mode 100644 (file)
index 0000000..b9de403
--- /dev/null
@@ -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<unsigned> &defValue)
+{
+  return ZyppFlags::Value (
+        [defValue]() -> boost::optional<std::string>{
+          if(defValue) {
+            return std::to_string(*defValue);
+          } else
+            return boost::optional<std::string>();
+        },
+
+        [&target]( const ZyppFlags::CommandOption &opt, const boost::optional<std::string> &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<std::string> & ) {
+          target = valueIfSeen;
+        }
+  );
+}
+
+}
+
+RepoServiceCommonOptions::RepoServiceCommonOptions(OptCommandCtx ctx)
+  : _cmdContext(ctx)
+{ }
+
+RepoServiceCommonOptions::RepoServiceCommonOptions(OptCommandCtx ctx, ZypperBaseCommand &parent)
+  : BaseCommandOptionSet(parent),
+    _cmdContext(ctx)
+{ }
+
+std::vector<ZyppFlags::CommandGroup> RepoServiceCommonOptions::options()
+{
+  return {
+    {
+      {
+        {"name",   'n', ZyppFlags::RequiredArgument, ZyppFlags::StringType( &_name, boost::optional<const char *>(), "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<ZyppFlags::CommandGroup> 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<ZyppFlags::CommandGroup> 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<ZyppFlags::CommandGroup> RSCommonListOptions::options()
+{
+
+  std::vector<ZyppFlags::CommandGroup> 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 (file)
index 0000000..dda0a20
--- /dev/null
@@ -0,0 +1,128 @@
+/*---------------------------------------------------------------------------*\
+                          ____  _ _ __ _ __  ___ _ _
+                         |_ / || | '_ \ '_ \/ -_) '_|
+                         /__|\_, | .__/ .__/\___|_|
+                             |__/|_|  |_|
+\*---------------------------------------------------------------------------*/
+#ifndef ZYPPER_COMMANDS_REPO_SERVICE_OPTIONSET_H_INCLUDED
+#define ZYPPER_COMMANDS_REPO_SERVICE_OPTIONSET_H_INCLUDED
+
+#include "basecommand.h"
+
+#include <zypp/TriBool.h>
+#include <zypp/RepoInfo.h>
+#include <zypp/base/Flags.h>
+
+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<zypp::ZyppFlags::CommandGroup> 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<zypp::ZyppFlags::CommandGroup> options() override;
+  void reset() override;
+
+  //will be removed
+  void fillFromCopts (Zypper &zypper );
+
+  bool _all    = false;
+  bool _local  = false;
+  bool _remote = false;
+  std::vector<std::string> _mediumTypes;
+
+private:
+  OptCommandCtx _cmdContext = OptCommandCtx::RepoContext;
+};
+
+class RepoProperties : public BaseCommandOptionSet
+{
+public:
+  using BaseCommandOptionSet::BaseCommandOptionSet;
+
+  // BaseCommandOptionSet interface
+  std::vector<zypp::ZyppFlags::CommandGroup> 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<zypp::ZyppFlags::CommandGroup> 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 (file)
index 0000000..ce62fdf
--- /dev/null
@@ -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 (file)
index 0000000..dd39422
--- /dev/null
@@ -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 <zypp/repo/RepoException.h>
+#include <zypp/Url.h>
+
+using namespace zypp;
+
+namespace {
+ZyppFlags::Value CheckIsServiceTypeVal( bool &target )
+{
+  return ZyppFlags::Value (
+        []() -> boost::optional<std::string>{
+          return  boost::optional<std::string>();
+        },
+
+        [ &target ]( const ZyppFlags::CommandOption &opt, const boost::optional<std::string> &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<std::string> &commandAliases_r ) :
+  ZypperBaseCommand(
+    commandAliases_r,
+    // translators: command synopsis; do not translate lowercase words
+    _("addservice (as) [OPTIONS] <URI> <ALIAS>"),
+    _("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<bool&>(_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<std::string> &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<BaseCommandConditionPtr> AddServiceCmd::conditions() const
+{
+  return {
+    std::make_shared<NeedsRootCondition>()
+  };
+}
diff --git a/src/commands/services/add.h b/src/commands/services/add.h
new file mode 100644 (file)
index 0000000..d51de99
--- /dev/null
@@ -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 <zypp/base/Flags.h>
+#include <zypp/repo/ServiceType.h>
+
+class AddServiceCmd : public ZypperBaseCommand
+{
+public:
+  AddServiceCmd( const std::vector<std::string> &commandAliases_r );
+
+  // ZypperBaseCommand interface
+protected:
+  zypp::ZyppFlags::CommandGroup cmdOptions() const override;
+  void doReset() override;
+  int execute( Zypper &zypp_r, const std::vector<std::string> &positionalArgs_r ) override;
+  std::vector<BaseCommandConditionPtr> 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 (file)
index 0000000..c9efb64
--- /dev/null
@@ -0,0 +1,165 @@
+/*---------------------------------------------------------------------------*\
+                          ____  _ _ __ _ __  ___ _ _
+                         |_ / || | '_ \ '_ \/ -_) '_|
+                         /__|\_, | .__/ .__/\___|_|
+                             |__/|_|  |_|
+\*---------------------------------------------------------------------------*/
+
+#include "common.h"
+#include "repos.h"
+
+#include <zypp/media/MediaException.h>
+
+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<ServiceInfo>(*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<RepoInfo>(*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<RepoInfo>(*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 (file)
index 0000000..6d4b756
--- /dev/null
@@ -0,0 +1,37 @@
+/*---------------------------------------------------------------------------*\
+                          ____  _ _ __ _ __  ___ _ _
+                         |_ / || | '_ \ '_ \/ -_) '_|
+                         /__|\_, | .__/ .__/\___|_|
+                             |__/|_|  |_|
+\*---------------------------------------------------------------------------*/
+#ifndef ZYPPER_COMMANDS_SERVICES_COMMON_H_INCLUDED
+#define ZYPPER_COMMANDS_SERVICES_COMMON_H_INCLUDED
+
+#include "Zypper.h"
+
+#include <zypp/RepoInfo.h>
+#include <zypp/repo/RepoInfoBase.h>
+#include <zypp/RepoManager.h>
+
+#include <list>
+
+struct RepoCollector
+{
+  bool collect( const zypp::RepoInfo & repo )
+  {
+    repos.push_back( repo );
+    return true;
+  }
+  RepoInfoList repos;
+};
+
+typedef std::list<zypp::repo::RepoInfoBase_Ptr> 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 (file)
index 0000000..184da7a
--- /dev/null
@@ -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<ServiceInfo>(srv);
+  RepoInfo_Ptr repo;
+  if ( ! service )
+    repo = dynamic_pointer_cast<RepoInfo>(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<std::string> &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<ServiceInfo>(*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 << "<service-list>" << endl;
+
+  ServiceInfo_Ptr s_ptr;
+  for_( it, services.begin(), services.end() )
+  {
+    s_ptr = dynamic_pointer_cast<ServiceInfo>(*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 << "</service-list>" << endl;
+}
+
+ZyppFlags::CommandGroup ListServicesCmd::cmdOptions() const
+{
+  return ZyppFlags::CommandGroup();
+}
+
+void ListServicesCmd::doReset()
+{
+}
+
+int ListServicesCmd::execute( Zypper &zypp_r, const std::vector<std::string> &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 (file)
index 0000000..29b164e
--- /dev/null
@@ -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 <zypp/base/Flags.h>
+
+class ListServicesCmd : public ZypperBaseCommand
+{
+public:
+  ListServicesCmd ( const std::vector<std::string> &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<std::string> &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 (file)
index 0000000..1578f0a
--- /dev/null
@@ -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<std::string> &commandAliases_r )
+  : ZypperBaseCommand(
+    commandAliases_r,
+      {
+        // translators: command synopsis; do not translate lowercase words
+        _("modifyservice (ms) <OPTIONS> <ALIAS|#|URI>"),
+        // translators: command synopsis; do not translate lowercase words
+        str::Format( _("modifyservice (ms) <OPTIONS> <%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<BaseCommandConditionPtr> ModifyServiceCmd::conditions() const
+{
+  return {
+    std::make_shared<NeedsRootCondition>()
+  };
+}
+
+zypp::ZyppFlags::CommandGroup ModifyServiceCmd::cmdOptions() const
+{
+  auto that = const_cast<ModifyServiceCmd *>(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<std::string> &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<ServiceInfo>(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<std::string> artoenable;
+    std::set<std::string> artodisable;
+    std::set<std::string> rrtoenable;
+    std::set<std::string> 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<std::string> repos_to_modify;
+  std::set<std::string> services_to_modify;
+
+  if ( _selectOptions._all )
+  {
+    for_( it, known.begin(), known.end() )
+    {
+      ServiceInfo_Ptr sptr = dynamic_pointer_cast<ServiceInfo>(*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<std::string> schemes( _selectOptions._mediumTypes.begin(), _selectOptions._mediumTypes.end() );
+
+  for_( it, known.begin(), known.end() )
+  {
+    ServiceInfo_Ptr sptr = dynamic_pointer_cast<ServiceInfo>(*it);
+    Url url;
+    if ( sptr )
+      url = sptr->url();
+    else
+    {
+      RepoInfo_Ptr rptr = dynamic_pointer_cast<RepoInfo>(*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 (file)
index 0000000..0c55e01
--- /dev/null
@@ -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 <zypp/base/Flags.h>
+
+class ModifyServiceCmd : public ZypperBaseCommand
+{
+public:
+  ModifyServiceCmd( const std::vector<std::string> &commandAliases_r );
+
+  // ZypperBaseCommand interface
+  std::string help() override;
+
+protected:
+  std::vector<BaseCommandConditionPtr> conditions() const override;
+  zypp::ZyppFlags::CommandGroup cmdOptions() const override;
+  void doReset() override;
+  int execute(Zypper &zypp_r, const std::vector<std::string> &positionalArgs_r) override;
+
+private:
+  int modifyService( Zypper & zypper, const std::string & alias );
+  void modifyServicesByOption( Zypper & zypper );
+
+private:
+  std::vector<std::string> _arToEnable;
+  std::vector<std::string> _arToDisable;
+  std::vector<std::string> _rrToEnable;
+  std::vector<std::string> _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 (file)
index 0000000..c06a5c9
--- /dev/null
@@ -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 <zypp/repo/RepoInfoBase.h>
+#include <zypp/base/Iterator.h>
+#include <zypp/media/MediaException.h>
+
+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<typename T>
+void get_services( Zypper & zypper, const T & begin, const T & end,
+                  ServiceList & services, std::list<std::string> & 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<ServiceInfo>(*serv_it);
+      ServiceInfo_Ptr current_service_ptr = dynamic_pointer_cast<ServiceInfo>(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<RepoInfo>(service),
+                                    *dynamic_pointer_cast<RepoInfo>(*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<std::string> 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<std::string> &commandAliases_r ) :
+  ZypperBaseCommand(
+    commandAliases_r,
+    _("refresh-services (refs) [OPTIONS]"),
+    _("Refresh all services."),
+    _("Refresh defined repository index services."))
+{
+
+}
+
+std::vector<BaseCommandConditionPtr> RefreshServicesCmd::conditions() const
+{
+  return {
+    std::make_shared<NeedsRootCondition>()
+  };
+}
+
+ZyppFlags::CommandGroup RefreshServicesCmd::cmdOptions() const
+{
+  auto that  = const_cast<RefreshServicesCmd *>(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<std::string> &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<std::string> 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<ServiceInfo>(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<RepoInfo>(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 (file)
index 0000000..da4c286
--- /dev/null
@@ -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 <zypp/base/Flags.h>
+
+class RefreshServicesCmd : public ZypperBaseCommand
+{
+
+public:
+  RefreshServicesCmd ( const std::vector<std::string> &commandAliases_r );
+
+  int refreshServices ( Zypper &zypper );
+
+  void setForce(bool force);
+  void setWithRepos(bool withRepos);
+  void setRestoreStatus(bool restoreStatus);
+
+  // ZypperBaseCommand interface
+protected:
+  std::vector<BaseCommandConditionPtr> conditions() const override;
+  zypp::ZyppFlags::CommandGroup cmdOptions() const override;
+  void doReset() override;
+  int execute(Zypper &zypper, const std::vector<std::string> &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 (file)
index 0000000..228f8ac
--- /dev/null
@@ -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<std::string> &commandAliases_r)
+  : ZypperBaseCommand (
+    commandAliases_r,
+    _("removeservice (rs) [OPTIONS] <ALIAS|#|URI>"),
+    _("Remove specified service."),
+    _("Remove specified repository index service from the system."),
+    ResetRepoManager
+  )
+{ }
+
+std::vector<BaseCommandConditionPtr> RemoveServiceCmd::conditions() const
+{
+  return {
+    std::make_shared<NeedsRootCondition>()
+  };
+}
+
+zypp::ZyppFlags::CommandGroup RemoveServiceCmd::cmdOptions() const
+{
+  auto that = const_cast<RemoveServiceCmd *>(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<std::string> &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<repo::RepoInfoBase_Ptr, ServiceAliasComparator> 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<RepoInfo>(*it);
+    if (repo_ptr)
+      remove_repo(zypp, *repo_ptr);
+    else
+      remove_service(zypp, *dynamic_pointer_cast<ServiceInfo>(*it));
+  }
+  return ZYPPER_EXIT_OK;
+}
diff --git a/src/commands/services/remove.h b/src/commands/services/remove.h
new file mode 100644 (file)
index 0000000..7d50c48
--- /dev/null
@@ -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 <zypp/base/Flags.h>
+
+class RemoveServiceCmd : public ZypperBaseCommand
+{
+public:
+  RemoveServiceCmd( const std::vector<std::string> &commandAliases_r );
+  // ZypperBaseCommand interface
+protected:
+  std::vector<BaseCommandConditionPtr> conditions() const override;
+  zypp::ZyppFlags::CommandGroup cmdOptions() const override;
+  void doReset() override;
+  int execute(Zypper &zypp, const std::vector<std::string> &positionalArgs) override;
+
+private:
+  bool _looseAuth  = false;
+  bool _looseQuery = false;
+};
+
+#endif
diff --git a/src/locks.cc b/src/locks.cc
deleted file mode 100644 (file)
index b039177..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-#include <iostream>
-#include <boost/lexical_cast.hpp>
-
-#include <zypp/base/String.h>
-#include <zypp/base/Logger.h>
-#include <zypp/Locks.h>
-
-#include "output/Out.h"
-#include "main.h"
-#include "Table.h"
-#include "utils/misc.h"
-#include "locks.h"
-#include "repos.h"
-
-using namespace zypp;
-
-
-template <typename Target, typename Source>
-void safe_lexical_cast (Source s, Target &tr) {
-  try {
-    tr = boost::lexical_cast<Target> (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 (file)
index d4f4ab1..0000000
+++ /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 (file)
index 13cc763..0000000
--- a/src/ps.cc
+++ /dev/null
@@ -1,188 +0,0 @@
-/*---------------------------------------------------------------------------*\
-                          ____  _ _ __ _ __  ___ _ _
-                         |_ / || | '_ \ '_ \/ -_) '_|
-                         /__|\_, | .__/ .__/\___|_|
-                             |__/|_|  |_|
-\*---------------------------------------------------------------------------*/
-
-#include <iostream>
-
-#include <zypp/base/LogTools.h>
-#include <zypp/ExternalProgram.h>
-#include <zypp/misc/CheckAccessDeleted.h>
-
-#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<PsImpl,PsOptions>
-  {
-    typedef CommandBase<PsImpl,PsOptions> 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<std::string> 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<std::string>::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 (file)
index 6d806c6..0000000
--- a/src/ps.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*---------------------------------------------------------------------------*\
-                          ____  _ _ __ _ __  ___ _ _
-                         |_ / || | '_ \ '_ \/ -_) '_|
-                         /__|\_, | .__/ .__/\___|_|
-                             |__/|_|  |_|
-\*---------------------------------------------------------------------------*/
-#ifndef ZYPPER_PS_H
-#define ZYPPER_PS_H
-
-#include <string>
-class Zypper;
-
-/*
- ps ...
-*/
-
-/** ps specific options */
-struct PsOptions : public MixinOptions<ZypperCommand::PS>
-{
-  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
index afc7313..205466f 100644 (file)
@@ -10,8 +10,6 @@
 #include <iterator>
 #include <list>
 
-#include <boost/lexical_cast.hpp>
-
 #include <zypp/ZYpp.h>
 #include <zypp/base/Logger.h>
 #include <zypp/base/IOStream.h>
 #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<RepoInfoBase_Ptr> ServiceList;
 typedef std::set<RepoInfo, RepoInfoAliasComparator> 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 <typename Target, typename Source>
-void safe_lexical_cast( Source s, Target & tr )
-{
-  try
-  {
-    tr = boost::lexical_cast<Target>( 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<std::list<std::string>::const_iterator>( Zypper &,
                                                                 const std::list<std::string>::const_iterator &,
                                                                 std::list<RepoInfo> &, std::list<std::string> & );
 
+// Explicit instantiations required for other translation units:
+template void get_repos<std::vector<std::string>::const_iterator>( Zypper &,
+                                                                const std::vector<std::string>::const_iterator &,
+                                                                const std::vector<std::string>::const_iterator &,
+                                                                std::list<RepoInfo> &, std::list<std::string> & );
+
 // ---------------------------------------------------------------------------
 
-/**
- * Say "Repository %s not found" for all strings in \a not_found list.
- */
 void report_unknown_repos( Out & out, const std::list<std::string> & 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<RepoInfo> & 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<RepoInfo> & 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<RepoInfo> repos )
-{
-  cout << "<repo-list>" << endl;
-  for_( it, repos.begin(), repos.end() )
-    it->dumpAsXmlOn( cout );
-  cout << "</repo-list>" << endl;
-}
-
-// ----------------------------------------------------------------------------
-
-void print_repos_to( const std::list<RepoInfo> & repos, std::ostream & out )
+void clean_repos(Zypper & zypper , std::vector<std::string> 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<RepoInfo> repos;
-  std::list<std::string> 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<RepoInfo> & repos( manager.knownRepositories() );
 
-  // get the list of repos specified on the command line ...
+  // get the list of repos specified requested
   std::list<RepoInfo> specified;
   std::list<std::string> 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<RepoInfo> 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<RepoInfo> 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<RepoInfo> specified;
-  std::list<std::string> 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<RepoInfo> 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<typename T>
@@ -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<RepoInfo> & 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<std::function<bool (const RepoInfo &)>> 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<std::string> & pars = copts["medium-type"];
+      filterList.push_back([ &selectOpts ]( const RepoInfo &info ) {
+        const std::vector<std::string> & 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<ServiceInfo>(*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<RepoInfo>(*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<RepoInfo>(*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<std::string> 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<typename T>
-void get_services( Zypper & zypper, const T & begin, const T & end,
-                  ServiceList & services, std::list<std::string> & 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<ServiceInfo>(*serv_it);
-      ServiceInfo_Ptr current_service_ptr = dynamic_pointer_cast<ServiceInfo>(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<RepoInfo>(service),
-                                    *dynamic_pointer_cast<RepoInfo>(*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<ServiceInfo>(srv);
-  RepoInfo_Ptr repo;
-  if ( ! service )
-    repo = dynamic_pointer_cast<RepoInfo>(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<RepoInfoBase_Ptr> & 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<ServiceInfo>(*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<RepoInfoBase_Ptr> & services )
-{
-  cout << "<service-list>" << endl;
-
-  ServiceInfo_Ptr s_ptr;
-  for_( it, services.begin(), services.end() )
-  {
-    s_ptr = dynamic_pointer_cast<ServiceInfo>(*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 << "</service-list>" << 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<std::string> 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<ServiceInfo>(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<RepoInfo>(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<std::string> artoenable;
-    std::set<std::string> artodisable;
-    std::set<std::string> rrtoenable;
-    std::set<std::string> 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<std::string> repos_to_modify;
-  std::set<std::string> services_to_modify;
-
-  if ( copts.count("all") )
-  {
-    for_( it, known.begin(), known.end() )
-    {
-      ServiceInfo_Ptr sptr = dynamic_pointer_cast<ServiceInfo>(*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<std::string> pars = copts["medium-type"];
-  std::set<std::string> schemes(pars.begin(), pars.end());
-
-  for_( it, known.begin(), known.end() )
-  {
-    ServiceInfo_Ptr sptr = dynamic_pointer_cast<ServiceInfo>(*it);
-    Url url;
-    if ( sptr )
-      url = sptr->url();
-    else
-    {
-      RepoInfo_Ptr rptr = dynamic_pointer_cast<RepoInfo>(*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 );
-}
-
 // ---------------------------------------------------------------------------
 
 // ---------------------------------------------------------------------------
index 9a5e20c..74fe4b4 100644 (file)
 
 #include <list>
 
+#include <boost/lexical_cast.hpp>
+
 #include <zypp/TriBool.h>
 #include <zypp/Url.h>
 #include <zypp/RepoInfo.h>
 #include <zypp/ServiceInfo.h>
 
 #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.
  *
 template <typename Container>
 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<std::string> & not_found );
+
 template<typename T>
 void get_repos( Zypper & zypper, const T & begin, const T & end, std::list<RepoInfo> & repos, std::list<std::string> & not_found );
 
+template <typename Target, typename Source>
+void safe_lexical_cast( Source s, Target & tr )
+{
+  try
+  {
+    tr = boost::lexical_cast<Target>( s );
+  }
+  catch ( boost::bad_lexical_cast & )
+  {;}
+}
+
 void report_unknown_repos( Out & out, const std::list<std::string> & 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<std::string> 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++
index b445841..bd036a2 100644 (file)
@@ -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"),
index d086d8a..be8b6ce 100644 (file)
@@ -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 )
+{
+
+}
+
 }}
index 15dce86..56c9f9b 100644 (file)
@@ -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 );
+  };
 }}
 
 
index 04504a1..46574d3 100644 (file)
@@ -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<std::string> &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<std::string> noDefaultValue()
+{
+  return boost::optional<std::string>();
+}
+
 Value StringType(std::string *target, const boost::optional<const char *> &defValue, std::string hint) {
   return Value (
     [defValue]() ->  boost::optional<std::string>{
@@ -67,5 +88,89 @@ Value BoolType(bool *target, StoreFlag store, const boost::optional<bool> &defVa
   );
 }
 
+Value TriBoolType(TriBool &target, StoreFlag store, const boost::optional<TriBool> &defValue)
+{
+  return Value (
+    [defValue]() -> boost::optional<std::string>{
+      if (!defValue)
+        return boost::optional<std::string>();
+      return asString ( *defValue );
+    },
+   [&target, store]( const CommandOption &, const boost::optional<std::string> &){
+      target = TriBool(store == StoreTrue);
+    }
+  );
+}
+
+Value CounterType(int *target, const boost::optional<int> &defValue, const boost::optional<int> &maxValue)
+{
+  return Value (
+        [defValue]() -> boost::optional<std::string>{
+          if(defValue) {
+            return std::to_string(*defValue);
+          } else
+            return boost::optional<std::string>();
+        },
+
+        [target, maxValue]( const CommandOption &opt, const boost::optional<std::string> & ) {
+          *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<ResKind> *target) {
+  return Value (
+        noDefaultValue,
+        [target] ( const CommandOption &opt, const boost::optional<std::string> &in ) {
+            target->insert( parseKindArgument( opt, in ) );
+            return;
+          },
+          "TYPE"
+  );
+}
+
+Value StringVectorType(std::vector<std::string> *target, std::string hint) {
+  return Value (
+        noDefaultValue,
+        [target] ( const CommandOption &opt, const boost::optional<std::string> &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<std::string> & ) {
+          return;
+        }
+  );
+}
+
+Value WarnOptionVal(Out &out_r, const std::string &warning_r, Out::Verbosity verbosity_r, const boost::optional<Value> &val_r )
+{
+  return Value (
+        [ val_r ] () -> boost::optional<std::string> {
+          if ( val_r )
+            return val_r->defaultValue();
+          return boost::optional<std::string>();
+        },
+        [ &out_r, warning_r, val_r, verbosity_r ] ( const CommandOption &opt, const boost::optional<std::string> &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 );
+          }
+        }
+  );
+}
+
 }
 }
index 420a87e..02e1609 100644 (file)
@@ -9,8 +9,18 @@
 
 #include "zyppflags.h"
 #include "exceptions.h"
+#include "output/Out.h"
+
+#include <zypp/ResKind.h>
+#include <zypp/TriBool.h>
+#include <set>
+
+class Out;
 
 namespace zypp {
+
+class Kind;
+
 namespace ZyppFlags {
 
 /**
@@ -23,20 +33,20 @@ Value StringType ( std::string *target, const boost::optional<const char *> &def
  */
 Value IntType    ( int *target, const boost::optional<int> &defValue = boost::optional<int>()  );
 
+/**
+ * Returns a \sa ZyppFlags::Value instance counting how many times a parameter was seen
+ */
+Value CounterType    ( int *target, const boost::optional<int> &defValue = boost::optional<int>(), const boost::optional<int> &maxValue = boost::optional<int>()  );
 
-template <class Container>
-Value StringContainerType ( Container *target, std::string hint = ARG_STRING ) {
-  return Value (
-        []() -> boost::optional<std::string> { return boost::optional<std::string>(); },
-        [target] ( CommandOption *opt, const boost::optional<std::string> &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<ResKind> *target );
 
+/**
+ * Returns a \sa ZyppFlags::Value instance handling flags that fill a vector of strings
+ */
+Value StringVectorType (std::vector<std::string> *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<bool> &defValue = boost::optional<bool>()  );
 
+
+Value TriBoolType   ( TriBool &target, StoreFlag store = StoreTrue, const boost::optional<TriBool> &defValue = boost::optional<TriBool>()  );
+
+
+template <typename T, typename E = T>
+Value BitFieldType ( T& target, E flag , StoreFlag store = StoreTrue ) {
+  return Value (
+        [ &target, flag] () -> boost::optional<std::string> {
+          return target.testFlag ( flag ) ? std::string("true") : std::string("false");
+        },
+        [ &target, flag, store ] ( const CommandOption &, const boost::optional<std::string> & ) {
+          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<Value> &val_r = boost::optional<Value>());
+
+/**
+ * Helper function that just returns a empty default value
+ */
+boost::optional<std::string> noDefaultValue();
+
 }}
 
 #endif
index 7715f32..86a2faf 100644 (file)
@@ -5,15 +5,17 @@
                              |__/|_|  |_|
 \*---------------------------------------------------------------------------*/
 #include "zyppflags.h"
+#include "flagtypes.h"
+#include "exceptions.h"
+#include "utils/messages.h"
+#include "Zypper.h"
 
 #include <getopt.h>
-#include <map>
+#include <unordered_map>
 #include <exception>
 #include <utility>
 #include <string.h>
 
-#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<CommandGroup> &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<CommandGroup>
   // the set of long options
   std::vector<struct option> 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<CommandOption> allOpts;
-  std::map<std::string, int> longOptIndex;  //we do not actually need that index other than checking for dups
-  std::map<char, int>        shortOptIndex;
+  std::unordered_map<std::string, int> longOptIndex;  //we do not actually need that index other than checking for dups
+  std::unordered_map<char, int>        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 <insertnamehere>");
+          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 <insertnamehere>");
+          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<CommandGroup>
         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<CommandGroup>
             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<std::string> 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<CommandGroup> &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<CommandOption> &&options_r, ConflictingFlagsList &&conflictingOptions_r )
+  : name ( std::move(name_r) ),
+    options ( std::move(options_r) ),
+    conflictingOptions ( std::move(conflictingOptions_r) )
+{ }
+
+CommandGroup::CommandGroup( std::vector<CommandOption> &&options_r, ConflictingFlagsList &&conflictingOptions_r )
+  : CommandGroup (  _("Command options:"), std::move(options_r), std::move(conflictingOptions_r) )
+{ }
+
+CommandGroup::CommandGroup()
+  : CommandGroup ( std::vector<CommandOption>(), ConflictingFlagsList() )
+{ }
+
+
 }}
 
index 6ff9a57..94ae87d 100644 (file)
@@ -57,13 +57,14 @@ namespace ZyppFlags {
   using SetterFun   = std::function<void ( const CommandOption &, const boost::optional<std::string> &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<std::string> conflictingArguments;
   };
 
-  struct CommandGroup
+  using ConflictingFlagsList = std::vector< std::vector< std::string > >;
+
+  struct  CommandGroup
   {
-    const std::string name;
-    std::vector<CommandOption> options;
+    /**
+     * Creates a empty default group
+     */
+    CommandGroup ();
+
+    /**
+     * Creates the default command group with given options and conflicting flags
+     */
+    CommandGroup (  std::vector<CommandOption> &&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<CommandOption> &&options_r, ConflictingFlagsList &&conflictingOptions_r = ConflictingFlagsList() );
+
+    std::string name; //< The name of the command group
+    std::vector<CommandOption> 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
   };
 
   /**
index 8435ad7..6634bec 100644 (file)
@@ -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 );
+}
index 867d5b9..f343dc3 100644 (file)
@@ -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_*/
index ac5550d..ee682d5 100644 (file)
@@ -18,6 +18,7 @@
 #include <zypp/ResKind.h>
 #include <zypp/RepoInfo.h>
 #include <zypp/ZYppCommitPolicy.h>
+#include <zypp/base/Logger.h>
 
 class Zypper;
 class Table;
@@ -28,6 +29,7 @@ namespace zypp
   class Resolvable;
   class Product;
   class Pattern;
+  class Patch;
 }
 using namespace zypp;
 
index 5b19a1b..b07dca4 100644 (file)
@@ -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