source: yum/trunk/shell.py@ 1569

Last change on this file since 1569 was 516, checked in by Yuri Dario, 11 years ago

yum: update trunk to 3.4.3.

  • Property svn:eol-style set to native
File size: 12.8 KB
Line 
1#! /usr/bin/python -tt
2# This program is free software; you can redistribute it and/or modify
3# it under the terms of the GNU General Public License as published by
4# the Free Software Foundation; either version 2 of the License, or
5# (at your option) any later version.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU Library General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program; if not, write to the Free Software
14# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15# Copyright 2005 Duke University
16
17"""
18A shell implementation for the yum command line interface.
19"""
20
21import sys
22import cmd
23import shlex
24import logging
25
26from yum import Errors
27from yum.constants import *
28import yum.logginglevels as logginglevels
29
30
31class YumShell(cmd.Cmd):
32
33 """
34 Interactive yum shell.
35 """
36
37 def __init__(self, base):
38 cmd.Cmd.__init__(self)
39 self.base = base
40 self.prompt = '> '
41 self.result = 0
42 self.identchars += '-'
43 self.from_file = False # if we're running from a file, set this
44 self.resultmsgs = ['Leaving Shell']
45 if (len(base.extcmds)) > 0:
46 self.file = base.extcmds[0]
47 self.shell_specific_commands = ['repo', 'repository', 'exit', 'quit',
48 'run', 'ts', 'transaction', 'config']
49
50 self.commandlist = self.shell_specific_commands + self.base.yum_cli_commands.keys()
51 self.logger = logging.getLogger("yum.cli")
52 self.verbose_logger = logging.getLogger("yum.verbose.cli")
53
54 # NOTE: This is shared with self.base ... so don't reassign.
55 self._shell_history_cmds = []
56
57 def _shell_history_add_cmds(self, cmds):
58 if not self.base.conf.history_record:
59 return
60
61 self._shell_history_cmds.append(cmds)
62
63 def _shlex_split(self, input_string):
64 """split the input using shlex rules, and error or exit accordingly"""
65
66 inputs = []
67 if input_string is None: # apparently shlex.split() doesn't like None as its input :)
68 return inputs
69
70 try:
71 inputs = shlex.split(input_string)
72 except ValueError, e:
73 self.logger.critical('Script Error: %s', e)
74 if self.from_file:
75 raise Errors.YumBaseError, "Fatal error in script, exiting"
76
77 return inputs
78
79 def script(self):
80 try:
81 fd = open(self.file, 'r')
82 except IOError:
83 sys.exit("Error: Cannot open %s for reading" % self.file)
84 lines = fd.readlines()
85 fd.close()
86 self.from_file = True
87 for line in lines:
88 self.onecmd(line)
89 self.onecmd('EOF')
90 return True
91
92 def default(self, line):
93 if len(line) > 0 and line.strip()[0] == '#':
94 pass
95 else:
96 (cmd, args, line) = self.parseline(line)
97 if cmd not in self.commandlist:
98 xargs = [cmd]
99 self.base.plugins.run('args', args=xargs)
100 if xargs[0] == cmd:
101 self.do_help('')
102 return False
103 if cmd == 'shell':
104 return
105 self.base.cmdstring = line
106 self.base.cmdstring = self.base.cmdstring.replace('\n', '')
107 self.base.cmds = self._shlex_split(self.base.cmdstring)
108 self.base.plugins.run('args', args=self.base.cmds)
109
110 self._shell_history_add_cmds(self.base.cmds)
111
112 try:
113 self.base.parseCommands()
114 except Errors.YumBaseError:
115 pass
116 else:
117 self.base.doCommands()
118
119 def emptyline(self):
120 pass
121
122 def completenames(self, text, line, begidx, endidx):
123 ret = cmd.Cmd.completenames(self, text, line, begidx, endidx)
124 for command in self.base.yum_cli_commands:
125 if command.startswith(text) and command != "shell":
126 ret.append(command)
127 return ret
128
129 def do_help(self, arg):
130 msg = """
131 Shell specific arguments:
132 config - set config options
133 repository (or repo) - enable/disable/list repositories
134 transaction (or ts) - list, reset or run the transaction set
135 run - run the transaction set
136 exit or quit - exit the shell
137 """
138
139 if arg in ['transaction', 'ts']:
140 msg = """
141 %s arg
142 list: lists the contents of the transaction
143 reset: reset (zero-out) the transaction
144 solve: run the dependency solver on the transaction
145 run: run the transaction
146 """ % arg
147 elif arg in ['repo', 'repository']:
148 msg = """
149 %s arg [option]
150 list: lists repositories and their status. option = [all] name/id glob
151 enable: enable repositories. option = repository id
152 disable: disable repositories. option = repository id
153 """ % arg
154
155 elif arg == 'config':
156 msg = """
157 %s arg [value]
158 args: debuglevel, errorlevel, obsoletes, gpgcheck, assumeyes, exclude
159 If no value is given it prints the current value.
160 If value is given it sets that value.
161 """ % arg
162
163 else:
164 self.base.shellUsage()
165
166 self.verbose_logger.info(msg)
167
168 def do_EOF(self, line):
169 self.resultmsgs = ['Leaving Shell']
170 return True
171
172 def do_quit(self, line):
173 self.resultmsgs = ['Leaving Shell']
174 return True
175
176 def do_exit(self, line):
177 self.resultmsgs = ['Leaving Shell']
178 return True
179
180 def do_ts(self, line):
181 self.do_transaction(line)
182
183 def do_transaction(self, line):
184 (cmd, args, line) = self.parseline(line)
185 if cmd in ['list', None]:
186 self.verbose_logger.log(logginglevels.INFO_2,
187 self.base.listTransaction())
188
189 elif cmd == 'reset':
190 self.base.closeRpmDB()
191
192 elif cmd == 'solve':
193 try:
194 (code, msgs) = self.base.buildTransaction()
195 except Errors.YumBaseError, e:
196 self.logger.critical('Error building transaction: %s', e)
197 return False
198
199 if code == 1:
200 for msg in msgs:
201 self.logger.critical('Error: %s', msg)
202 else:
203 self.verbose_logger.log(logginglevels.INFO_2,
204 'Success resolving dependencies')
205
206 elif cmd == 'run':
207 return self.do_run('')
208
209 else:
210 self.do_help('transaction')
211
212 def do_config(self, line):
213 (cmd, args, line) = self.parseline(line)
214 # logs
215 if cmd in ['debuglevel', 'errorlevel']:
216 opts = self._shlex_split(args)
217 if not opts:
218 self.verbose_logger.log(logginglevels.INFO_2, '%s: %s', cmd,
219 getattr(self.base.conf, cmd))
220 else:
221 val = opts[0]
222 try:
223 val = int(val)
224 except ValueError:
225 self.logger.critical('Value %s for %s cannot be made to an int', val, cmd)
226 return
227 setattr(self.base.conf, cmd, val)
228 if cmd == 'debuglevel':
229 logginglevels.setDebugLevel(val)
230 elif cmd == 'errorlevel':
231 logginglevels.setErrorLevel(val)
232 # bools
233 elif cmd in ['gpgcheck', 'repo_gpgcheck', 'obsoletes', 'assumeyes']:
234 opts = self._shlex_split(args)
235 if not opts:
236 self.verbose_logger.log(logginglevels.INFO_2, '%s: %s', cmd,
237 getattr(self.base.conf, cmd))
238 else:
239 value = opts[0]
240 if value.lower() not in BOOLEAN_STATES:
241 self.logger.critical('Value %s for %s is not a Boolean', value, cmd)
242 return False
243 value = BOOLEAN_STATES[value.lower()]
244 setattr(self.base.conf, cmd, value)
245 if cmd == 'obsoletes':
246 self.base.up = None
247
248 elif cmd in ['exclude']:
249 args = args.replace(',', ' ')
250 opts = self._shlex_split(args)
251 if not opts:
252 msg = '%s: ' % cmd
253 msg = msg + ' '.join(getattr(self.base.conf, cmd))
254 self.verbose_logger.log(logginglevels.INFO_2, msg)
255 return False
256 else:
257 setattr(self.base.conf, cmd, opts)
258 if self.base.pkgSack: # kill the pkgSack
259 self.base.pkgSack = None
260 self.base.up = None # reset the updates
261 # reset the transaction set, we have to or we shall surely die!
262 self.base.closeRpmDB()
263 else:
264 self.do_help('config')
265
266 def do_repository(self, line):
267 self.do_repo(line)
268
269 def do_repo(self, line):
270 (cmd, args, line) = self.parseline(line)
271 if cmd in ['list', None]:
272 # Munge things to run the repolist command
273 cmds = self._shlex_split(args)
274
275 if not cmds:
276 cmds = ['enabled']
277 cmds.insert(0, 'repolist')
278 self.base.cmds = cmds
279
280 self._shell_history_add_cmds(self.base.cmds)
281
282 try:
283 self.base.parseCommands()
284 except Errors.YumBaseError:
285 pass
286 else:
287 self.base.doCommands()
288
289 elif cmd == 'enable':
290 repos = self._shlex_split(args)
291 for repo in repos:
292 try:
293 # Setup the sacks/repos, we need this because we are about
294 # to setup the enabled one. And having some setup is bad.
295 self.base.pkgSack
296 changed = self.base.repos.enableRepo(repo)
297 except Errors.ConfigError, e:
298 self.logger.critical(e)
299 except Errors.RepoError, e:
300 self.logger.critical(e)
301
302 else:
303 for repo in changed:
304 try:
305 self.base.doRepoSetup(thisrepo=repo)
306 except Errors.RepoError, e:
307 self.logger.critical('Disabling Repository')
308 self.base.repos.disableRepo(repo)
309 return False
310
311 self.base.up = None
312
313 elif cmd == 'disable':
314 repos = self._shlex_split(args)
315 for repo in repos:
316 try:
317 offrepos = self.base.repos.disableRepo(repo)
318 except Errors.ConfigError, e:
319 self.logger.critical(e)
320 except Errors.RepoError, e:
321 self.logger.critical(e)
322
323 else:
324 # close the repos, too
325 for repoid in offrepos:
326 thisrepo = self.base.repos.repos[repoid]
327 thisrepo.close() # kill the pkgSack
328 # rebuild the indexes to be sure we cleaned up
329 self.base.pkgSack.buildIndexes()
330
331 else:
332 self.do_help('repo')
333
334 def do_test(self, line):
335 (cmd, args, line) = self.parseline(line)
336 print cmd
337 print args
338 print line
339
340 def do_run(self, line):
341 if len(self.base.tsInfo) > 0:
342 try:
343 (code, msgs) = self.base.buildTransaction()
344 if code == 1:
345 for msg in msgs:
346 self.logger.critical('Error: %s', msg)
347 return False
348
349 returnval = self.base.doTransaction()
350 except Errors.YumBaseError, e:
351 self.logger.critical('Error: %s', e)
352 except KeyboardInterrupt, e:
353 self.logger.critical('\n\nExiting on user cancel')
354 except IOError, e:
355 if e.errno == 32:
356 self.logger.critical('\n\nExiting on Broken Pipe')
357 else:
358 if returnval not in [0,1,-1]:
359 self.verbose_logger.info('Transaction encountered a serious error.')
360 else:
361 if returnval == 1:
362 self.verbose_logger.info('There were non-fatal errors in the transaction')
363 elif returnval == -1:
364 self.verbose_logger.info("Transaction didn't start")
365 self.verbose_logger.log(logginglevels.INFO_2,
366 'Finished Transaction')
367 self.base.closeRpmDB()
368
369
Note: See TracBrowser for help on using the repository browser.