Fixed some minor error reporting bugs
[zeroinstall/solver.git] / zeroinstall / cmd / __init__.py
blob3005673c5f1867def0d568563c57e94c16c31dd1
1 """
2 The B{0install} command-line interface.
3 """
5 # Copyright (C) 2011, Thomas Leonard
6 # See the README file for details, or visit http://0install.net.
8 from __future__ import print_function
10 from zeroinstall import _
11 import os, sys
12 from optparse import OptionParser
13 import logging
15 from zeroinstall import SafeException
17 valid_commands = ['add', 'select', 'download', 'run', 'update', 'whatchanged', 'destroy',
18 'config', 'import', 'list', 'add-feed', 'remove-feed', 'list-feeds',
19 'digest']
21 class UsageError(Exception): pass
23 def _ensure_standard_fds():
24 "Ensure stdin, stdout and stderr FDs exist, to avoid confusion."
25 for std in (0, 1, 2):
26 try:
27 os.fstat(std)
28 except OSError:
29 fd = os.open(os.devnull, os.O_RDONLY)
30 if fd != std:
31 os.dup2(fd, std)
32 os.close(fd)
34 def _no_command(command_args):
35 """Handle --help and --version"""
36 parser = OptionParser(usage=_("usage: %prog COMMAND\n\nTry --help with one of these:") +
37 "\n\n0install " + '\n0install '.join(valid_commands))
38 parser.add_option("-V", "--version", help=_("display version information"), action='store_true')
40 (options, args) = parser.parse_args(command_args)
41 if options.version:
42 import zeroinstall
43 print("0install (zero-install) " + zeroinstall.version)
44 print("Copyright (C) 2011 Thomas Leonard")
45 print(_("This program comes with ABSOLUTELY NO WARRANTY,"
46 "\nto the extent permitted by law."
47 "\nYou may redistribute copies of this program"
48 "\nunder the terms of the GNU Lesser General Public License."
49 "\nFor more information about these matters, see the file named COPYING."))
50 sys.exit(0)
51 parser.print_help()
52 sys.exit(2)
54 def main(command_args, config = None):
55 """Act as if 0install was run with the given arguments.
56 @arg command_args: array of arguments (e.g. C{sys.argv[1:]})
57 @type command_args: [str]
58 """
59 _ensure_standard_fds()
61 if config is None:
62 from zeroinstall.injector.config import load_config
63 config = load_config()
65 # The first non-option argument is the command name (or "help" if none is found).
66 command = None
67 for i, arg in enumerate(command_args):
68 if not arg.startswith('-'):
69 command = arg
70 del command_args[i]
71 break
72 elif arg == '--':
73 break
75 verbose = False
76 try:
77 if command is None:
78 return _no_command(command_args)
80 if command not in valid_commands:
81 raise SafeException(_("Unknown sub-command '%s': try --help") % command)
83 # Configure a parser for the given command
84 module_name = command.replace('-', '_')
85 cmd = __import__('zeroinstall.cmd.' + module_name, globals(), locals(), [module_name], 0)
86 parser = OptionParser(usage=_("usage: %%prog %s [OPTIONS] %s") % (command, cmd.syntax))
88 parser.add_option("-c", "--console", help=_("never use GUI"), action='store_false', dest='gui')
89 parser.add_option("", "--dry-run", help=_("just print what would be executed"), action='store_true')
90 parser.add_option("-g", "--gui", help=_("show graphical policy editor"), action='store_true')
91 parser.add_option("-v", "--verbose", help=_("more verbose output"), action='count')
92 parser.add_option("", "--with-store", help=_("add an implementation cache"), action='append', metavar='DIR')
94 cmd.add_options(parser)
95 (options, args) = parser.parse_args(command_args)
96 verbose = options.verbose
98 if options.verbose:
99 logger = logging.getLogger()
100 if options.verbose == 1:
101 logger.setLevel(logging.INFO)
102 else:
103 logger.setLevel(logging.DEBUG)
104 import zeroinstall
105 logging.info(_("Running 0install %(version)s %(args)s; Python %(python_version)s"), {'version': zeroinstall.version, 'args': repr(command_args), 'python_version': sys.version})
107 if options.with_store:
108 from zeroinstall import zerostore
109 for x in options.with_store:
110 config.stores.stores.append(zerostore.Store(os.path.abspath(x)))
111 logging.info(_("Stores search path is now %s"), config.stores.stores)
113 config.handler.dry_run = bool(options.dry_run)
115 cmd.handle(config, options, args)
116 except KeyboardInterrupt:
117 logging.info("KeyboardInterrupt")
118 sys.exit(1)
119 except UsageError:
120 parser.print_help()
121 sys.exit(1)
122 except SafeException as ex:
123 if verbose: raise
124 try:
125 from zeroinstall.support import unicode
126 print(unicode(ex), file=sys.stderr)
127 except:
128 print(repr(ex), file=sys.stderr)
129 sys.exit(1)
130 return