Package zeroinstall :: Package cmd :: Module select
[frames] | no frames]

Source Code for Module zeroinstall.cmd.select

  1  """ 
  2  The B{0install select} command-line interface. 
  3  """ 
  4   
  5  # Copyright (C) 2011, Thomas Leonard 
  6  # See the README file for details, or visit http://0install.net. 
  7   
  8  from __future__ import print_function 
  9   
 10  import sys 
 11   
 12  from zeroinstall import _, logger 
 13  from zeroinstall.cmd import UsageError 
 14  from zeroinstall.injector import model, selections 
 15  from zeroinstall.injector.requirements import Requirements 
 16  from zeroinstall.injector.driver import Driver 
 17  from zeroinstall.support import tasks 
 18   
 19  syntax = "URI" 
 20   
21 -def add_generic_select_options(parser):
22 """All options for selecting.""" 23 parser.add_option("", "--before", help=_("choose a version before this"), metavar='VERSION') 24 parser.add_option("", "--command", help=_("command to select"), metavar='COMMAND') 25 parser.add_option("", "--cpu", help=_("target CPU type"), metavar='CPU') 26 parser.add_option("", "--message", help=_("message to display when interacting with user")) 27 parser.add_option("", "--not-before", help=_("minimum version to choose"), metavar='VERSION') 28 parser.add_option("-o", "--offline", help=_("try to avoid using the network"), action='store_true') 29 parser.add_option("", "--os", help=_("target operation system type"), metavar='OS') 30 parser.add_option("-r", "--refresh", help=_("refresh all used interfaces"), action='store_true') 31 parser.add_option("-s", "--source", help=_("select source code"), action='store_true') 32 parser.add_option("", "--version", help=_("specify version constraint (e.g. '3' or '3..')"), metavar='RANGE') 33 parser.add_option("", "--version-for", help=_("set version constraints for a specific interface"), 34 nargs=2, metavar='URI RANGE', action='append')
35
36 -def add_options(parser):
37 """Options for 'select' and 'download' (but not 'run')""" 38 add_generic_select_options(parser) 39 parser.add_option("", "--xml", help=_("write selected versions as XML"), action='store_true')
40
41 -def get_selections(config, options, iface_uri, select_only, download_only, test_callback, requirements = None):
42 """Get selections for iface_uri, according to the options passed. 43 Will switch to GUI mode if necessary. 44 @type config: L{zeroinstall.injector.config.Config} 45 @param options: options from OptionParser 46 @param iface_uri: canonical URI of the interface 47 @type iface_uri: str 48 @param select_only: return immediately even if the selected versions aren't cached 49 @type select_only: bool 50 @param download_only: wait for stale feeds, and display GUI button as Download, not Run 51 @type download_only: bool 52 @param requirements: requirements to use; if None, requirements come from options (since 1.15) 53 @type requirements: Requirements 54 @return: the selected versions, or None if the user cancels 55 @rtype: L{selections.Selections} | None""" 56 if options.offline: 57 config.network_use = model.network_offline 58 59 iface_cache = config.iface_cache 60 61 # Try to load it as a feed. If it is a feed, it'll get cached. If not, it's a 62 # selections document and we return immediately. 63 maybe_selections = iface_cache.get_feed(iface_uri, selections_ok = True) 64 if isinstance(maybe_selections, selections.Selections): 65 if not select_only: 66 blocker = maybe_selections.download_missing(config) 67 if blocker: 68 logger.info(_("Waiting for selected implementations to be downloaded...")) 69 tasks.wait_for_blocker(blocker) 70 return maybe_selections 71 72 if requirements is None: 73 requirements = Requirements(iface_uri) 74 requirements.parse_options(options) 75 76 return get_selections_for(requirements, config, options, select_only, download_only, test_callback)
77
78 -def get_selections_for(requirements, config, options, select_only, download_only, test_callback):
79 """Get selections for given requirements. 80 @type requirements: L{Requirements} 81 @type config: L{zeroinstall.injector.config.Config} 82 @type select_only: bool 83 @type download_only: bool 84 @rtype: L{zeroinstall.injector.selections.Selections} 85 @since: 1.9""" 86 if options.offline: 87 config.network_use = model.network_offline 88 89 iface_cache = config.iface_cache 90 91 driver = Driver(config = config, requirements = requirements) 92 93 # Note that need_download() triggers a solve 94 if options.refresh or options.gui: 95 # We could run immediately, but the user asked us not to 96 can_run_immediately = False 97 else: 98 if select_only: 99 # --select-only: we only care that we've made a selection, not that we've cached the implementations 100 driver.need_download() 101 can_run_immediately = driver.solver.ready 102 else: 103 can_run_immediately = not driver.need_download() 104 105 stale_feeds = [feed for feed in driver.solver.feeds_used if 106 not feed.startswith('distribution:') and # Ignore (memory-only) PackageKit feeds 107 iface_cache.is_stale(feed, config.freshness)] 108 109 if download_only and stale_feeds: 110 can_run_immediately = False 111 112 if can_run_immediately: 113 if stale_feeds: 114 if config.network_use == model.network_offline: 115 logger.debug(_("No doing background update because we are in off-line mode.")) 116 elif options.dry_run: 117 print(_("[dry-run] would check for updates in the background")) 118 else: 119 # There are feeds we should update, but we can run without them. 120 # Do the update in the background while the program is running. 121 from zeroinstall.injector import background 122 background.spawn_background_update(driver, options.verbose) 123 return driver.solver.selections 124 125 # If we need to download anything, we might as well 126 # refresh all the feeds first. 127 options.refresh = True 128 129 if options.gui != False: 130 # If the user didn't say whether to use the GUI, choose for them. 131 gui_args = driver.requirements.get_as_options() 132 if download_only: 133 # Just changes the button's label 134 gui_args.append('--download-only') 135 if options.refresh: 136 gui_args.append('--refresh') 137 if options.verbose: 138 gui_args.insert(0, '--verbose') 139 if options.verbose > 1: 140 gui_args.insert(0, '--verbose') 141 if options.with_store: 142 for x in options.with_store: 143 gui_args += ['--with-store', x] 144 if select_only: 145 gui_args.append('--select-only') 146 147 from zeroinstall import helpers 148 sels = helpers.get_selections_gui(requirements.interface_uri, gui_args, test_callback, use_gui = options.gui) 149 150 if not sels: 151 return None # Aborted 152 elif sels is helpers.DontUseGUI: 153 sels = None 154 else: 155 sels = None 156 157 if sels is None: 158 # Note: --download-only also makes us stop and download stale feeds first. 159 downloaded = driver.solve_and_download_impls(refresh = options.refresh or download_only or False, 160 select_only = select_only) 161 if downloaded: 162 tasks.wait_for_blocker(downloaded) 163 sels = driver.solver.selections 164 165 return sels
166
167 -def handle(config, options, args):
168 """@type config: L{zeroinstall.injector.config.Config} 169 @type args: [str]""" 170 if len(args) != 1: 171 raise UsageError() 172 173 app = config.app_mgr.lookup_app(args[0], missing_ok = True) 174 if app is not None: 175 old_sels = app.get_selections() 176 177 requirements = app.get_requirements() 178 changes = requirements.parse_update_options(options) 179 iface_uri = old_sels.interface 180 181 if requirements.extra_restrictions and not options.xml: 182 print("User-provided restrictions in force:") 183 for uri, expr in requirements.extra_restrictions.items(): 184 print(" {uri}: {expr}".format(uri = uri, expr = expr)) 185 print() 186 else: 187 iface_uri = model.canonical_iface_uri(args[0]) 188 requirements = None 189 changes = False 190 191 sels = get_selections(config, options, iface_uri, 192 select_only = True, download_only = False, test_callback = None, requirements = requirements) 193 if not sels: 194 sys.exit(1) # Aborted by user 195 196 if options.xml: 197 show_xml(sels) 198 else: 199 show_human(sels, config.stores) 200 if app is not None: 201 from zeroinstall.cmd import whatchanged 202 changes = whatchanged.show_changes(old_sels.selections, sels.selections) or changes 203 if changes: 204 print(_("(note: use '0install update' instead to save the changes)"))
205
206 -def show_xml(sels):
207 """@type sels: L{zeroinstall.injector.selections.Selections}""" 208 doc = sels.toDOM() 209 doc.writexml(sys.stdout) 210 sys.stdout.write('\n')
211
212 -def show_human(sels, stores):
213 """@type sels: L{zeroinstall.injector.selections.Selections} 214 @type stores: L{zeroinstall.zerostore.Stores}""" 215 done = set() # detect cycles 216 def print_node(uri, commands, indent): 217 if uri in done: return 218 if done: print() 219 done.add(uri) 220 impl = sels.selections.get(uri, None) 221 print(indent + "- URI:", uri) 222 if impl: 223 print(indent + " Version:", impl.version) 224 #print indent + " Command:", command 225 if impl.id.startswith('package:'): 226 path = "(" + impl.id + ")" 227 else: 228 path = impl.get_path(stores, missing_ok = True) or _("(not cached)") 229 print(indent + " Path:", path) 230 indent += " " 231 232 deps = impl.dependencies 233 for c in commands: 234 deps += impl.get_command(c).requires 235 for child in deps: 236 print_node(child.interface, child.get_required_commands(), indent) 237 else: 238 print(indent + " No selected version")
239 240 241 if sels.command: 242 print_node(sels.interface, [sels.command], "") 243 else: 244 print_node(sels.interface, [], "") 245
246 -def complete(completion, args, cword):
247 """@type completion: L{zeroinstall.cmd._Completion} 248 @type args: [str] 249 @type cword: int""" 250 if len(args) != 1 or cword != 0: return 251 completion.expand_apps() 252 completion.expand_interfaces()
253