Added "0install select" sub-command
[zeroinstall.git] / zeroinstall / cmd / __init__.py
blob7094d2ac34f728373f15a07043e7f6c1d0642f40
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 zeroinstall import _
9 import os, sys
10 from optparse import OptionParser
11 import logging
13 from zeroinstall import SafeException, NeedDownload
14 from zeroinstall.injector import model, autopolicy, selections
15 from zeroinstall.injector.iface_cache import iface_cache
17 valid_commands = ['select', 'download', 'run', 'update',
18 'config', 'import', 'list', 'add-feed', 'remove-feed']
20 class UsageError(Exception): pass
22 def _ensure_standard_fds():
23 "Ensure stdin, stdout and stderr FDs exist, to avoid confusion."
24 for std in (0, 1, 2):
25 try:
26 os.fstat(std)
27 except OSError:
28 fd = os.open('/dev/null', os.O_RDONLY)
29 if fd != std:
30 os.dup2(fd, std)
31 os.close(fd)
33 def _no_command(command_args):
34 """Handle --help and --version"""
35 parser = OptionParser(usage=_("usage: %prog COMMAND\n\nTry --help with one of these:") +
36 "\n\n0install " + '\n0install '.join(valid_commands))
37 parser.add_option("-V", "--version", help=_("display version information"), action='store_true')
39 (options, args) = parser.parse_args(command_args)
40 if options.version:
41 import zeroinstall
42 print "0install (zero-install) " + zeroinstall.version
43 print "Copyright (C) 2011 Thomas Leonard"
44 print _("This program comes with ABSOLUTELY NO WARRANTY,"
45 "\nto the extent permitted by law."
46 "\nYou may redistribute copies of this program"
47 "\nunder the terms of the GNU Lesser General Public License."
48 "\nFor more information about these matters, see the file named COPYING.")
49 sys.exit(0)
50 parser.print_help()
51 sys.exit(2)
53 def main(command_args):
54 """Act as if 0install was run with the given arguments.
55 @arg command_args: array of arguments (e.g. C{sys.argv[1:]})
56 @type command_args: [str]
57 """
58 _ensure_standard_fds()
60 # The first non-option argument is the command name (or "help" if none is found).
61 command = None
62 for arg in command_args:
63 if not arg.startswith('-'):
64 command = arg
65 break
66 elif arg == '--':
67 break
69 verbose = False
70 try:
71 if command is None:
72 return _no_command(command_args)
74 if command not in valid_commands:
75 raise SafeException(_("Unknown sub-command '%s': try --help") % command)
77 # Configure a parser for the given command
78 cmd = __import__('zeroinstall.cmd.' + command, globals(), locals(), [command], 0)
79 parser = OptionParser(usage=_("usage: %%prog %s [OPTIONS] %s") % (command, cmd.syntax))
81 parser.add_option("-c", "--console", help=_("never use GUI"), action='store_false', dest='gui')
82 parser.add_option("-g", "--gui", help=_("show graphical policy editor"), action='store_true')
83 parser.add_option("-v", "--verbose", help=_("more verbose output"), action='count')
84 parser.add_option("", "--with-store", help=_("add an implementation cache"), action='append', metavar='DIR')
86 cmd.add_options(parser)
87 (options, args) = parser.parse_args(command_args)
88 assert args[0] == command
90 if options.verbose:
91 logger = logging.getLogger()
92 if options.verbose == 1:
93 logger.setLevel(logging.INFO)
94 else:
95 logger.setLevel(logging.DEBUG)
96 import zeroinstall
97 logging.info(_("Running 0install %(version)s %(args)s; Python %(python_version)s"), {'version': zeroinstall.version, 'args': repr(command_args), 'python_version': sys.version})
99 args = args[1:]
101 if options.with_store:
102 from zeroinstall import zerostore
103 for x in options.with_store:
104 iface_cache.stores.stores.append(zerostore.Store(os.path.abspath(x)))
105 logging.info(_("Stores search path is now %s"), iface_cache.stores.stores)
107 cmd.handle(options, args)
108 except UsageError:
109 parser.print_help()
110 sys.exit(1)
111 except SafeException, ex:
112 if verbose: raise
113 try:
114 print >>sys.stderr, unicode(ex)
115 except:
116 print >>sys.stderr, repr(ex)
117 sys.exit(1)
118 return