- 'licenses' command added (fate #303703)
authorJan Kupec <jkupec@suse.cz>
Fri, 19 Sep 2008 20:44:38 +0000 (20:44 +0000)
committerJan Kupec <jkupec@suse.cz>
Fri, 19 Sep 2008 20:44:38 +0000 (20:44 +0000)
doc/zypper.8
src/Command.cc
src/Command.h
src/Zypper.cc
src/misc.cc
src/misc.h

index 1c70c57..1b56d91 100644 (file)
@@ -925,6 +925,23 @@ Shows the ID string of the target operating system. The string has a form of
 is read from <current-rootdir>/etc/products.d/baseproduct and the architecture
 is determined from uname and CPU flags.
 
+.TP
+.B licenses
+Prints a report about \fBlicenses\fR and \fBEULA\fRs of installed packages
+to standard output.
+
+First, a list of all packages and their licenses and/or EULAs is shown.
+This is followed by a summary, including the total number of installed
+packages, the number of installed
+packages with EULAs that required a confirmation from the user. Since the
+EULAs are not stored on the system and can only be read from repository
+metadata, the summary includes also the number of installed packages
+that have their counterpart in repositories. The report ends with a list
+of all licenses uses by the installed packages.
+
+This command can be useful for companies redistributiong a custom
+distribution (like appliances) to figure out what licenses they are bound by.
+
 
 .SH "GLOBAL OPTIONS"
 
index 80cb777..78f0fc6 100644 (file)
@@ -63,6 +63,7 @@ const ZypperCommand ZypperCommand::CLEAN_LOCKS(ZypperCommand::CLEAN_LOCKS_e);
 
 const ZypperCommand ZypperCommand::TARGET_OS(ZypperCommand::TARGET_OS_e);
 const ZypperCommand ZypperCommand::VERSION_CMP(ZypperCommand::VERSION_CMP_e);
+const ZypperCommand ZypperCommand::LICENSES(ZypperCommand::LICENSES_e);
 
 const ZypperCommand ZypperCommand::HELP(ZypperCommand::HELP_e);
 const ZypperCommand ZypperCommand::SHELL(ZypperCommand::SHELL_e);
@@ -134,6 +135,7 @@ ZypperCommand::Command ZypperCommand::parse(const std::string & strval_r)
 
     _table["targetos"] = _table["tos"] = ZypperCommand::TARGET_OS_e;
     _table["versioncmp"] = _table["vcmp"] = ZypperCommand::VERSION_CMP_e;
+    _table["licenses"] = ZypperCommand::LICENSES_e;
 
     _table["help"] = _table["?"] = ZypperCommand::HELP_e;
     _table["shell"] = _table["sh"] = ZypperCommand::SHELL_e;
index f96b98e..3a6dbae 100644 (file)
@@ -59,6 +59,7 @@ struct ZypperCommand
   // utils/others
   static const ZypperCommand TARGET_OS;
   static const ZypperCommand VERSION_CMP;
+  static const ZypperCommand LICENSES;
 
   static const ZypperCommand HELP;
   static const ZypperCommand SHELL;
@@ -126,6 +127,7 @@ struct ZypperCommand
 
     TARGET_OS_e,
     VERSION_CMP_e,
+    LICENSES_e,
 
     HELP_e,
     SHELL_e,
index 8cf6636..c644596 100644 (file)
@@ -239,6 +239,7 @@ void print_main_help(Zypper & zypper)
   static string help_other_commands = _("\tOther Commands:\n"
     "\tversioncmp, vcmp\tCompare two version strings.\n"
     "\ttargetos, tos\t\tPrint the target operating system ID string.\n"
+    "\tlicenses\t\tPrint report about licenses and EULAs of installed packages.\n"
   );
 
   static string help_usage = _(
@@ -1949,6 +1950,24 @@ void Zypper::processCommandOptions()
     break;
   }
 
+  case ZypperCommand::LICENSES_e:
+  {
+    static struct option options[] =
+    {
+      {"help", no_argument, 0, 'h'},
+      {0, 0, 0, 0}
+    };
+    specific_options = options;
+    _command_help = _(
+      "licenses\n"
+      "\n"
+      "Report Licenses and EULA of currently installed software packages.\n"
+      "\n"
+      "This command has no additional options.\n"
+    );
+    break;
+  }
+
   case ZypperCommand::SHELL_QUIT_e:
   {
     static struct option quit_options[] = {
@@ -3002,10 +3021,10 @@ void Zypper::doCommand()
     if (command() == ZypperCommand::RUG_PATCH_SEARCH)
       _gopts.is_rug_compatible = true;
 
-    zypp::PoolQuery query;
-
     if (runningHelp()) { out().info(_command_help, Out::QUIET); return; }
 
+    zypp::PoolQuery query;
+
     TriBool inst_notinst = indeterminate;
     if (globalOpts().disable_system_resolvables || copts.count("uninstalled-only"))
     {
@@ -3698,6 +3717,31 @@ void Zypper::doCommand()
     break;
   }
 
+  case ZypperCommand::LICENSES_e:
+  {
+    if (runningHelp()) { out().info(_command_help, Out::QUIET); return; }
+
+    if (!_arguments.empty())
+    {
+      report_too_many_arguments(_command_help);
+      setExitCode(ZYPPER_EXIT_ERR_INVALID_ARGS);
+      return;
+    }
+
+    init_repos(*this);
+    if (exitCode() != ZYPPER_EXIT_OK)
+      return;
+    init_target(*this);
+    // now load resolvables:
+    load_resolvables(*this);
+    // needed to compute status of PPP
+    resolve(*this);
+
+    report_licenses(*this);
+
+    break;
+  }
+
   // -----------------------------( shell )------------------------------------
 
   case ZypperCommand::SHELL_QUIT_e:
index ed23a7f..cd49379 100644 (file)
@@ -5,6 +5,7 @@
                              |__/|_|  |_|
 \*---------------------------------------------------------------------------*/
 
+#include <iostream>
 #include <sstream>
 #include <boost/format.hpp>
 
 #include "zypp/base/Logger.h"
 
 #include "zypp/SrcPackage.h"
+#include "zypp/Package.h"
 #include "zypp/Capabilities.h"
 
+
 #include "zypp/RepoInfo.h"
 
+#include "zypp/PoolQuery.h"
+
 #include "main.h"
 #include "utils/misc.h"
 #include "utils/pager.h"
@@ -207,6 +212,86 @@ bool confirm_licenses(Zypper & zypper)
   return confirmed;
 }
 
+// ----------------------------------------------------------------------------
+
+void report_licenses(Zypper & zypper)
+{
+  PoolQuery q;
+
+  ui::Selectable::constPtr s;
+  PoolItem inst;
+  PoolItem inst_with_repo;
+
+  unsigned count_installed = 0, count_installed_repo = 0, count_installed_eula = 0;
+  set<string> unique_licenses;
+
+  for_(pit, q.selectableBegin(), q.selectableEnd())
+  {
+    s = *pit;
+    if (!s)  // FIXME this must not be necessary!
+      continue;
+
+    for_(iit, s->installedBegin(), s->installedEnd())
+    {
+      inst = *iit;
+      ++count_installed;
+
+      cout
+        << s->name() << "-" << inst.resolvable()->edition()
+        << " (" << kind_to_string_localized(s->kind(), 1) << ")"
+        << endl;
+
+      if (s->kind() == ResKind::package)
+      {
+        cout
+          << _("License") << ": "
+          << asKind<Package>(inst.resolvable())->license()
+          << endl;
+        unique_licenses.insert(asKind<Package>(inst.resolvable())->license());
+      }
+
+      for_(it, s->availableBegin(), s->availableEnd())
+      {
+        if (equalNVRA(*it->resolvable(), *inst.resolvable()))
+        {
+          inst_with_repo = *it;
+          ++count_installed_repo;
+          break;
+        }
+      }
+
+      if (inst_with_repo && !inst_with_repo.resolvable()->licenseToConfirm().empty())
+      {
+        cout << _("EULA") << ":" << endl;
+
+        const string & licenseText =
+          inst_with_repo.resolvable()->licenseToConfirm();
+        if (licenseText.find("DT:Rich")==licenseText.npos)
+          cout << licenseText;
+        else
+          cout << processRichText(licenseText);
+        cout << endl;
+
+        ++count_installed_eula;
+      }
+      else if (!inst.resolvable()->licenseToConfirm().empty())
+        cout << "look! got an installed-only item and it has EULA! he?" << inst << endl;
+      cout << "-" << endl;
+    }
+  }
+
+  cout << endl << _("SUMMARY") << endl << endl;
+  cout << _("Installed packages: ") << count_installed << endl;
+  cout << _("Installed packages with counterparts in repositories: ") << count_installed_repo << endl;
+  cout << _("Installed packages with EULAs: ") << count_installed_eula << endl;
+
+  cout << str::form("Package licenses (%u):", (unsigned int) unique_licenses.size()) << endl;
+  for_(it, unique_licenses.begin(), unique_licenses.end())
+    cout << "* " << *it << endl;
+}
+
+// ----------------------------------------------------------------------------
+
 static SrcPackage::constPtr source_find( const string & arg )
 {
    /*
index fb7cc2b..2a83dd6 100644 (file)
  */
 bool confirm_licenses(Zypper & zypper);
 
+/**
+ * Prints a report about licenses and EULAs of installed packages to stdout.
+ */
+void report_licenses(Zypper & zypper);
+
 zypp::ResKind string_to_kind (const std::string & skind);
 
 /**