1# install.py 2# Install CLI command. 3# 4# Copyright (C) 2014-2016 Red Hat, Inc. 5# 6# This copyrighted material is made available to anyone wishing to use, 7# modify, copy, or redistribute it subject to the terms and conditions of 8# the GNU General Public License v.2, or (at your option) any later version. 9# This program is distributed in the hope that it will be useful, but WITHOUT 10# ANY WARRANTY expressed or implied, including the implied warranties of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 12# Public License for more details. You should have received a copy of the 13# GNU General Public License along with this program; if not, write to the 14# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 15# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the 16# source code or documentation are not subject to the GNU General Public 17# License and may only be used or replicated with the express permission of 18# Red Hat, Inc. 19# 20 21from __future__ import absolute_import 22from __future__ import unicode_literals 23 24import logging 25from itertools import chain 26 27import hawkey 28 29import dnf.exceptions 30from dnf.cli import commands 31from dnf.cli.option_parser import OptionParser 32from dnf.i18n import _ 33 34logger = logging.getLogger('dnf') 35 36 37class InstallCommand(commands.Command): 38 """A class containing methods needed by the cli to execute the 39 install command. 40 """ 41 nevra_forms = {'install-n': hawkey.FORM_NAME, 42 'install-na': hawkey.FORM_NA, 43 'install-nevra': hawkey.FORM_NEVRA} 44 alternatives_provide = 'alternative-for({})' 45 46 aliases = ('install', 'localinstall', 'in') + tuple(nevra_forms.keys()) 47 summary = _('install a package or packages on your system') 48 49 @staticmethod 50 def set_argparser(parser): 51 parser.add_argument('package', nargs='+', metavar=_('PACKAGE'), 52 action=OptionParser.ParseSpecGroupFileCallback, 53 help=_('Package to install')) 54 55 def configure(self): 56 """Verify that conditions are met so that this command can run. 57 That there are enabled repositories with gpg keys, and that 58 this command is called with appropriate arguments. 59 """ 60 demands = self.cli.demands 61 demands.sack_activation = True 62 demands.available_repos = True 63 demands.resolving = True 64 demands.root_user = True 65 commands._checkGPGKey(self.base, self.cli) 66 if not self.opts.filenames: 67 commands._checkEnabledRepo(self.base) 68 69 def run(self): 70 err_pkgs = [] 71 errs = [] 72 error_module_specs = [] 73 74 nevra_forms = self._get_nevra_forms_from_command() 75 76 self.cli._populate_update_security_filter(self.opts) 77 if self.opts.command == 'localinstall' and (self.opts.grp_specs or self.opts.pkg_specs): 78 self._log_not_valid_rpm_file_paths(self.opts.grp_specs) 79 if self.base.conf.strict: 80 raise dnf.exceptions.Error(_('Nothing to do.')) 81 skipped_grp_specs = [] 82 if self.opts.grp_specs and self.opts.command != 'localinstall': 83 if dnf.base.WITH_MODULES: 84 try: 85 module_base = dnf.module.module_base.ModuleBase(self.base) 86 module_base.install(self.opts.grp_specs, strict=self.base.conf.strict) 87 except dnf.exceptions.MarkingErrors as e: 88 if e.no_match_group_specs: 89 for e_spec in e.no_match_group_specs: 90 skipped_grp_specs.append(e_spec) 91 if e.error_group_specs: 92 for e_spec in e.error_group_specs: 93 error_module_specs.append("@" + e_spec) 94 module_depsolv_errors = e.module_depsolv_errors 95 if module_depsolv_errors: 96 logger.error(dnf.module.module_base.format_modular_solver_errors( 97 module_depsolv_errors[0])) 98 else: 99 skipped_grp_specs = self.opts.grp_specs 100 if self.opts.filenames and nevra_forms: 101 self._inform_not_a_valid_combination(self.opts.filenames) 102 if self.base.conf.strict: 103 raise dnf.exceptions.Error(_('Nothing to do.')) 104 else: 105 err_pkgs = self._install_files() 106 107 if skipped_grp_specs and nevra_forms: 108 self._inform_not_a_valid_combination(skipped_grp_specs) 109 if self.base.conf.strict: 110 raise dnf.exceptions.Error(_('Nothing to do.')) 111 elif skipped_grp_specs and self.opts.command != 'localinstall': 112 self._install_groups(skipped_grp_specs) 113 114 if self.opts.command != 'localinstall': 115 errs = self._install_packages(nevra_forms) 116 117 if (len(errs) != 0 or len(err_pkgs) != 0 or error_module_specs) and self.base.conf.strict: 118 raise dnf.exceptions.PackagesNotAvailableError(_("Unable to find a match"), 119 pkg_spec=' '.join(errs), 120 packages=err_pkgs) 121 122 def _get_nevra_forms_from_command(self): 123 if self.opts.command in self.nevra_forms: 124 return [self.nevra_forms[self.opts.command]] 125 else: 126 return [] 127 128 def _log_not_valid_rpm_file_paths(self, grp_specs): 129 group_names = map(lambda g: '@' + g, grp_specs) 130 for pkg in chain(self.opts.pkg_specs, group_names): 131 msg = _('Not a valid rpm file path: %s') 132 logger.info(msg, self.base.output.term.bold(pkg)) 133 134 def _inform_not_a_valid_combination(self, forms): 135 for form in forms: 136 msg = _('Not a valid form: %s') 137 logger.warning(msg, self.base.output.term.bold(form)) 138 139 def _install_files(self): 140 err_pkgs = [] 141 strict = self.base.conf.strict 142 for pkg in self.base.add_remote_rpms(self.opts.filenames, strict=strict, 143 progress=self.base.output.progress): 144 try: 145 self.base.package_install(pkg, strict=strict) 146 except dnf.exceptions.MarkingError: 147 msg = _('No match for argument: %s') 148 logger.info(msg, self.base.output.term.bold(pkg.location)) 149 err_pkgs.append(pkg) 150 151 return err_pkgs 152 153 def _install_groups(self, grp_specs): 154 try: 155 self.base.env_group_install(grp_specs, 156 tuple(self.base.conf.group_package_types), 157 strict=self.base.conf.strict) 158 except dnf.exceptions.Error: 159 if self.base.conf.strict: 160 raise 161 162 def _report_alternatives(self, pkg_spec): 163 query = self.base.sack.query().filterm( 164 provides=self.alternatives_provide.format(pkg_spec)) 165 if query: 166 msg = _('There are following alternatives for "{0}": {1}') 167 logger.info(msg.format( 168 pkg_spec, 169 ', '.join(sorted(set([alt.name for alt in query]))))) 170 171 def _install_packages(self, nevra_forms): 172 errs = [] 173 strict = self.base.conf.strict 174 for pkg_spec in self.opts.pkg_specs: 175 try: 176 self.base.install(pkg_spec, strict=strict, forms=nevra_forms) 177 except dnf.exceptions.MarkingError as e: 178 msg = '{}: {}'.format(e.value, self.base.output.term.bold(pkg_spec)) 179 logger.info(msg) 180 self.base._report_icase_hint(pkg_spec) 181 self._report_alternatives(pkg_spec) 182 errs.append(pkg_spec) 183 184 return errs 185