1 """
2 The B{0install select} command-line interface.
3 """
4
5
6
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
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
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
62
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
94 if options.refresh or options.gui:
95
96 can_run_immediately = False
97 else:
98 if select_only:
99
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
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
120
121 from zeroinstall.injector import background
122 background.spawn_background_update(driver, options.verbose)
123 return driver.solver.selections
124
125
126
127 options.refresh = True
128
129 if options.gui != False:
130
131 gui_args = driver.requirements.get_as_options()
132 if download_only:
133
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
152 elif sels is helpers.DontUseGUI:
153 sels = None
154 else:
155 sels = None
156
157 if sels is None:
158
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)
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
207 """@type sels: L{zeroinstall.injector.selections.Selections}"""
208 doc = sels.toDOM()
209 doc.writexml(sys.stdout)
210 sys.stdout.write('\n')
211
213 """@type sels: L{zeroinstall.injector.selections.Selections}
214 @type stores: L{zeroinstall.zerostore.Stores}"""
215 done = set()
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
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
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