| Home | Trees | Indices | Help |
|
|---|
|
|
1 """
2 The B{0launch} command-line interface.
3
4 This code is here, rather than in B{0launch} itself, simply so that it gets byte-compiled at
5 install time.
6 """
7
8 import os, sys
9 from optparse import OptionParser
10 import logging
11
12 from zeroinstall.injector import model, download, autopolicy, namespaces
13 from zeroinstall.injector.iface_cache import iface_cache
14
15 #def program_log(msg): os.access('MARK: 0launch: ' + msg, os.F_OK)
16 #import __main__
17 #__main__.__builtins__.program_log = program_log
18 #program_log('0launch ' + ' '.join((sys.argv[1:])))
19
21 if len(args) == 0:
22 matches = iface_cache.list_all_interfaces()
23 elif len(args) == 1:
24 match = args[0].lower()
25 matches = [i for i in iface_cache.list_all_interfaces() if match in i.lower()]
26 else:
27 raise UsageError()
28
29 matches.sort()
30 for i in matches:
31 print i
32
34 from zeroinstall.support import tasks
35 from zeroinstall.injector import gpg, handler, trust
36 from zeroinstall.injector.iface_cache import PendingFeed
37 from xml.dom import minidom
38 for x in args:
39 if not os.path.isfile(x):
40 raise model.SafeException("File '%s' does not exist" % x)
41 logging.info("Importing from file '%s'", x)
42 signed_data = file(x)
43 data, sigs = gpg.check_stream(signed_data)
44 doc = minidom.parseString(data.read())
45 uri = doc.documentElement.getAttribute('uri')
46 if not uri:
47 raise model.SafeException("Missing 'uri' attribute on root element in '%s'" % x)
48 iface = iface_cache.get_interface(uri)
49 logging.info("Importing information about interface %s", iface)
50 signed_data.seek(0)
51
52 pending = PendingFeed(uri, signed_data)
53
54 handler = handler.Handler()
55
56 def run():
57 keys_downloaded = tasks.Task(pending.download_keys(handler), "download keys")
58 yield keys_downloaded.finished
59 tasks.check(keys_downloaded.finished)
60 if not iface_cache.update_interface_if_trusted(iface, pending.sigs, pending.new_xml):
61 blocker = handler.confirm_trust_keys(iface, pending.sigs, pending.new_xml)
62 if blocker:
63 yield blocker
64 tasks.check(blocker)
65 if not iface_cache.update_interface_if_trusted(iface, pending.sigs, pending.new_xml):
66 raise SafeException("No signing keys trusted; not importing")
67
68 task = tasks.Task(run(), "import feed")
69
70 errors = handler.wait_for_blocker(task.finished)
71 if errors:
72 raise model.SafeException("Errors during download: " + '\n'.join(errors))
73
75 from zeroinstall.injector import writer
76 from zeroinstall.injector.handler import Handler
77 from zeroinstall.injector.policy import Policy
78 handler = Handler(dry_run = options.dry_run)
79 if not args: raise UsageError()
80 for x in args:
81 print "Feed '%s':\n" % x
82 x = model.canonical_iface_uri(x)
83 policy = Policy(x, handler)
84 if options.offline:
85 policy.network_use = model.network_offline
86
87 feed = iface_cache.get_feed(x)
88 if policy.network_use != model.network_offline and policy.is_stale(feed):
89 blocker = policy.fetcher.download_and_import_feed(x, iface_cache.iface_cache)
90 print "Downloading feed; please wait..."
91 handler.wait_for_blocker(blocker)
92 print "Done"
93
94 interfaces = policy.get_feed_targets(x)
95 for i in range(len(interfaces)):
96 feed = interfaces[i].get_feed(x)
97 if feed:
98 print "%d) Remove as feed for '%s'" % (i + 1, interfaces[i].uri)
99 else:
100 print "%d) Add as feed for '%s'" % (i + 1, interfaces[i].uri)
101 print
102 while True:
103 try:
104 i = raw_input('Enter a number, or CTRL-C to cancel [1]: ').strip()
105 except KeyboardInterrupt:
106 print
107 raise model.SafeException("Aborted at user request.")
108 if i == '':
109 i = 1
110 else:
111 try:
112 i = int(i)
113 except ValueError:
114 i = 0
115 if i > 0 and i <= len(interfaces):
116 break
117 print "Invalid number. Try again. (1 to %d)" % len(interfaces)
118 iface = interfaces[i - 1]
119 feed = iface.get_feed(x)
120 if feed:
121 iface.extra_feeds.remove(feed)
122 else:
123 iface.extra_feeds.append(model.Feed(x, arch = None, user_override = True))
124 writer.save_interface(iface)
125 print "\nFeed list for interface '%s' is now:" % iface.get_name()
126 if iface.feeds:
127 for f in iface.feeds:
128 print "- " + f.uri
129 else:
130 print "(no feeds)"
131
133 if len(args) < 1:
134 # You can use -g on its own to edit the GUI's own policy
135 # Otherwise, failing to give an interface is an error
136 if options.gui:
137 args = [namespaces.injector_gui_uri]
138 options.download_only = True
139 else:
140 raise UsageError()
141
142 iface_uri = model.canonical_iface_uri(args[0])
143 root_iface = iface_cache.get_interface(iface_uri)
144
145 policy = autopolicy.AutoPolicy(iface_uri,
146 download_only = bool(options.download_only),
147 dry_run = options.dry_run,
148 src = options.source)
149
150 if options.before or options.not_before:
151 policy.solver.extra_restrictions[root_iface] = [model.VersionRangeRestriction(model.parse_version(options.before),
152 model.parse_version(options.not_before))]
153
154 if options.offline:
155 policy.network_use = model.network_offline
156
157 if options.get_selections:
158 if len(args) > 1:
159 raise model.SafeException("Can't use arguments with --get-selections")
160 if options.main:
161 raise model.SafeException("Can't use --main with --get-selections")
162
163 # Note that need_download() triggers a solve
164 if options.refresh or options.gui:
165 # We could run immediately, but the user asked us not to
166 can_run_immediately = False
167 else:
168 can_run_immediately = (not policy.need_download()) and policy.ready
169
170 stale_feeds = [feed for feed in policy.solver.feeds_used if policy.is_stale(iface_cache.get_feed(feed))]
171
172 if options.download_only and stale_feeds:
173 can_run_immediately = False
174
175 if can_run_immediately:
176 if stale_feeds:
177 if policy.network_use == model.network_offline:
178 logging.debug("No doing background update because we are in off-line mode.")
179 else:
180 # There are feeds we should update, but we can run without them.
181 # Do the update in the background while the program is running.
182 import background
183 background.spawn_background_update(policy, options.verbose > 0)
184 if options.get_selections:
185 _get_selections(policy)
186 else:
187 if not options.download_only:
188 from zeroinstall.injector import run
189 run.execute(policy, args[1:], dry_run = options.dry_run, main = options.main, wrapper = options.wrapper)
190 else:
191 logging.info("Downloads done (download-only mode)")
192 assert options.dry_run or options.download_only
193 return
194
195 # If the user didn't say whether to use the GUI, choose for them.
196 if options.gui is None and os.environ.get('DISPLAY', None):
197 options.gui = True
198 # If we need to download anything, we might as well
199 # refresh all the interfaces first. Also, this triggers
200 # the 'checking for updates' box, which is non-interactive
201 # when there are no changes to the selection.
202 options.refresh = True
203 logging.info("Switching to GUI mode... (use --console to disable)")
204
205 prog_args = args[1:]
206
207 try:
208 if options.gui:
209 from zeroinstall.injector import run
210 gui_args = []
211 if options.download_only:
212 # Just changes the button's label
213 gui_args.append('--download-only')
214 if options.refresh:
215 gui_args.append('--refresh')
216 if options.not_before:
217 gui_args.insert(0, options.not_before)
218 gui_args.insert(0, '--not-before')
219 if options.before:
220 gui_args.insert(0, options.before)
221 gui_args.insert(0, '--before')
222 if options.source:
223 gui_args.insert(0, '--source')
224 if options.verbose:
225 gui_args.insert(0, '--verbose')
226 if options.verbose > 1:
227 gui_args.insert(0, '--verbose')
228 sels = _fork_gui(iface_uri, gui_args, prog_args, options)
229 if not sels:
230 sys.exit(1) # Aborted
231 if options.get_selections:
232 doc = sels.toDOM()
233 doc.writexml(sys.stdout)
234 sys.stdout.write('\n')
235 elif not options.download_only:
236 run.execute_selections(sels, prog_args, options.dry_run, options.main, options.wrapper)
237 else:
238 #program_log('download_and_execute ' + iface_uri)
239 policy.download_and_execute(prog_args, refresh = bool(options.refresh), main = options.main)
240 except autopolicy.NeedDownload, ex:
241 # This only happens for dry runs
242 print ex
243
245 """Run the GUI to get the selections.
246 prog_args and options are used only if the GUI requests a test.
247 """
248 from zeroinstall import helpers
249 def test_callback(sels):
250 from zeroinstall.injector import run
251 return run.test_selections(sels, prog_args,
252 bool(options and options.dry_run),
253 options and options.main)
254 return helpers.get_selections_gui(iface_uri, gui_args, test_callback)
255
257 from zeroinstall.injector import fetch
258 from zeroinstall.injector.handler import Handler
259 handler = Handler(dry_run = options.dry_run)
260 fetcher = fetch.Fetcher(handler)
261 blocker = sels.download_missing(iface_cache, fetcher)
262 if blocker:
263 logging.info("Waiting for selected implementations to be downloaded...")
264 handler.wait_for_blocker(blocker)
265
267 import selections
268 doc = selections.Selections(policy).toDOM()
269 doc.writexml(sys.stdout)
270 sys.stdout.write('\n')
271
273
275 """Act as if 0launch was run with the given arguments.
276 @arg command_args: array of arguments (e.g. C{sys.argv[1:]})
277 @type command_args: [str]
278 """
279 # Ensure stdin, stdout and stderr FDs exist, to avoid confusion
280 for std in (0, 1, 2):
281 try:
282 os.fstat(std)
283 except OSError:
284 fd = os.open('/dev/null', os.O_RDONLY)
285 if fd != std:
286 os.dup2(fd, std)
287 os.close(fd)
288
289 parser = OptionParser(usage="usage: %prog [options] interface [args]\n"
290 " %prog --list [search-term]\n"
291 " %prog --import [signed-interface-files]\n"
292 " %prog --feed [interface]")
293 parser.add_option("", "--before", help="choose a version before this", metavar='VERSION')
294 parser.add_option("-c", "--console"<