Package zeroinstall :: Package injector :: Module cli
[frames] | no frames]

Source Code for Module zeroinstall.injector.cli

  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   
20 -def _list_interfaces(args):
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
33 -def _import_feed(args):
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
74 -def _manage_feeds(options, args):
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
132 -def _normal_mode(options, args):
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
244 -def _fork_gui(iface_uri, gui_args, prog_args, options = None):
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
256 -def _download_missing_selections(options, sels):
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
266 -def _get_selections(policy):
267 import selections 268 doc = selections.Selections(policy).toDOM() 269 doc.writexml(sys.stdout) 270 sys.stdout.write('\n')
271
272 -class UsageError(Exception): pass
273
274 -def main(command_args):
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"<