Implement --set-selections using new 0install command
[zeroinstall/zeroinstall-afb.git] / zeroinstall / injector / cli.py
blob698be2cbf58ce872b588bcdee8b3cc79337e0d9b
1 """
2 The B{0launch} command-line interface.
4 This code is here, rather than in B{0launch} itself, simply so that it gets byte-compiled at
5 install time.
6 """
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
16 from zeroinstall.cmd import UsageError
18 #def program_log(msg): os.access('MARK: 0launch: ' + msg, os.F_OK)
19 #import __main__
20 #__main__.__builtins__.program_log = program_log
21 #program_log('0launch ' + ' '.join((sys.argv[1:])))
23 def _manage_feeds(options, args):
24 from zeroinstall.injector import writer
25 from zeroinstall.injector.handler import Handler
26 from zeroinstall.injector.policy import Policy
28 def find_feed_import(iface, feed_url):
29 for f in iface.extra_feeds:
30 if f.uri == feed_url:
31 return f
32 return None
34 handler = Handler(dry_run = options.dry_run)
35 if not args: raise UsageError()
36 for x in args:
37 print _("Feed '%s':") % x + '\n'
38 x = model.canonical_iface_uri(x)
39 policy = Policy(x, handler)
40 if options.offline:
41 policy.network_use = model.network_offline
43 feed = iface_cache.get_feed(x)
44 if policy.network_use != model.network_offline and policy.is_stale(feed):
45 blocker = policy.fetcher.download_and_import_feed(x, iface_cache.iface_cache)
46 print _("Downloading feed; please wait...")
47 handler.wait_for_blocker(blocker)
48 print _("Done")
50 interfaces = policy.get_feed_targets(x)
51 for i in range(len(interfaces)):
52 if find_feed_import(interfaces[i], x):
53 print _("%(index)d) Remove as feed for '%(uri)s'") % {'index': i + 1, 'uri': interfaces[i].uri}
54 else:
55 print _("%(index)d) Add as feed for '%(uri)s'") % {'index': i + 1, 'uri': interfaces[i].uri}
56 print
57 while True:
58 try:
59 i = raw_input(_('Enter a number, or CTRL-C to cancel [1]: ')).strip()
60 except KeyboardInterrupt:
61 print
62 raise SafeException(_("Aborted at user request."))
63 if i == '':
64 i = 1
65 else:
66 try:
67 i = int(i)
68 except ValueError:
69 i = 0
70 if i > 0 and i <= len(interfaces):
71 break
72 print _("Invalid number. Try again. (1 to %d)") % len(interfaces)
73 iface = interfaces[i - 1]
74 feed_import = find_feed_import(iface, x)
75 if feed_import:
76 iface.extra_feeds.remove(feed_import)
77 else:
78 iface.extra_feeds.append(model.Feed(x, arch = None, user_override = True))
79 writer.save_interface(iface)
80 print '\n' + _("Feed list for interface '%s' is now:") % iface.get_name()
81 if iface.extra_feeds:
82 for f in iface.extra_feeds:
83 print "- " + f.uri
84 else:
85 print _("(no feeds)")
87 def main(command_args):
88 """Act as if 0launch was run with the given arguments.
89 @arg command_args: array of arguments (e.g. C{sys.argv[1:]})
90 @type command_args: [str]
91 """
92 # Ensure stdin, stdout and stderr FDs exist, to avoid confusion
93 for std in (0, 1, 2):
94 try:
95 os.fstat(std)
96 except OSError:
97 fd = os.open('/dev/null', os.O_RDONLY)
98 if fd != std:
99 os.dup2(fd, std)
100 os.close(fd)
102 parser = OptionParser(usage=_("usage: %prog [options] interface [args]\n"
103 " %prog --list [search-term]\n"
104 " %prog --import [signed-interface-files]\n"
105 " %prog --feed [interface]"))
106 parser.add_option("", "--before", help=_("choose a version before this"), metavar='VERSION')
107 parser.add_option("", "--command", help=_("command to select"), metavar='COMMAND')
108 parser.add_option("-c", "--console", help=_("never use GUI"), action='store_false', dest='gui')
109 parser.add_option("", "--cpu", help=_("target CPU type"), metavar='CPU')
110 parser.add_option("-d", "--download-only", help=_("fetch but don't run"), action='store_true')
111 parser.add_option("-D", "--dry-run", help=_("just print actions"), action='store_true')
112 parser.add_option("-f", "--feed", help=_("add or remove a feed"), action='store_true')
113 parser.add_option("", "--get-selections", help=_("write selected versions as XML"), action='store_true', dest='xml')
114 parser.add_option("-g", "--gui", help=_("show graphical policy editor"), action='store_true')
115 parser.add_option("-i", "--import", help=_("import from files, not from the network"), action='store_true')
116 parser.add_option("-l", "--list", help=_("list all known interfaces"), action='store_true')
117 parser.add_option("-m", "--main", help=_("name of the file to execute"))
118 parser.add_option("", "--message", help=_("message to display when interacting with user"))
119 parser.add_option("", "--not-before", help=_("minimum version to choose"), metavar='VERSION')
120 parser.add_option("", "--os", help=_("target operation system type"), metavar='OS')
121 parser.add_option("-o", "--offline", help=_("try to avoid using the network"), action='store_true')
122 parser.add_option("-r", "--refresh", help=_("refresh all used interfaces"), action='store_true')
123 parser.add_option("", "--select-only", help=_("only download the feeds"), action='store_true')
124 parser.add_option("", "--set-selections", help=_("run versions specified in XML file"), metavar='FILE')
125 parser.add_option("", "--show", help=_("show where components are installed"), action='store_true')
126 parser.add_option("-s", "--source", help=_("select source code"), action='store_true')
127 parser.add_option("", "--systray", help=_("download in the background"), action='store_true')
128 parser.add_option("-v", "--verbose", help=_("more verbose output"), action='count')
129 parser.add_option("-V", "--version", help=_("display version information"), action='store_true')
130 parser.add_option("", "--with-store", help=_("add an implementation cache"), action='append', metavar='DIR')
131 parser.add_option("-w", "--wrapper", help=_("execute program using a debugger, etc"), metavar='COMMAND')
132 parser.disable_interspersed_args()
134 (options, args) = parser.parse_args(command_args)
136 if options.verbose:
137 logger = logging.getLogger()
138 if options.verbose == 1:
139 logger.setLevel(logging.INFO)
140 else:
141 logger.setLevel(logging.DEBUG)
142 import zeroinstall
143 logging.info(_("Running 0launch %(version)s %(args)s; Python %(python_version)s"), {'version': zeroinstall.version, 'args': repr(args), 'python_version': sys.version})
145 if options.select_only or options.show:
146 options.download_only = True
148 if options.with_store:
149 from zeroinstall import zerostore
150 for x in options.with_store:
151 iface_cache.stores.stores.append(zerostore.Store(os.path.abspath(x)))
152 logging.info(_("Stores search path is now %s"), iface_cache.stores.stores)
154 if options.set_selections:
155 args = [options.set_selections] + args
157 try:
158 if options.list:
159 from zeroinstall.cmd import list
160 list.handle(options, args)
161 elif options.version:
162 import zeroinstall
163 print "0launch (zero-install) " + zeroinstall.version
164 print "Copyright (C) 2010 Thomas Leonard"
165 print _("This program comes with ABSOLUTELY NO WARRANTY,"
166 "\nto the extent permitted by law."
167 "\nYou may redistribute copies of this program"
168 "\nunder the terms of the GNU Lesser General Public License."
169 "\nFor more information about these matters, see the file named COPYING.")
170 elif getattr(options, 'import'):
171 # (import is a keyword)
172 cmd = __import__('zeroinstall.cmd.import', globals(), locals(), ["import"], 0)
173 cmd.handle(options, args)
174 elif options.feed:
175 _manage_feeds(options, args)
176 elif options.select_only:
177 from zeroinstall.cmd import select
178 if not options.show:
179 options.quiet = True
180 select.handle(options, args)
181 elif options.download_only or options.xml or options.show:
182 from zeroinstall.cmd import download
183 download.handle(options, args)
184 else:
185 if len(args) < 1:
186 if options.gui:
187 from zeroinstall import helpers
188 return helpers.get_selections_gui(None, [])
189 else:
190 raise UsageError()
191 else:
192 from zeroinstall.cmd import run
193 run.handle(options, args)
194 except NeedDownload, ex:
195 # This only happens for dry runs
196 print ex
197 except UsageError:
198 parser.print_help()
199 sys.exit(1)
200 except SafeException, ex:
201 if options.verbose: raise
202 try:
203 print >>sys.stderr, unicode(ex)
204 except:
205 print >>sys.stderr, repr(ex)
206 sys.exit(1)