2 The B{0install select} command-line interface.
5 # Copyright (C) 2011, Thomas Leonard
6 # See the README file for details, or visit http://0install.net.
8 from optparse
import OptionParser
12 from zeroinstall
import cmd
, SafeException
, _
13 from zeroinstall
.cmd
import UsageError
14 from zeroinstall
.injector
import model
, autopolicy
, selections
, handler
15 from zeroinstall
.injector
.iface_cache
import iface_cache
19 def add_options(parser
):
20 parser
.add_option("", "--before", help=_("choose a version before this"), metavar
='VERSION')
21 parser
.add_option("", "--command", help=_("command to select"), metavar
='COMMAND')
22 parser
.add_option("", "--cpu", help=_("target CPU type"), metavar
='CPU')
23 parser
.add_option("", "--message", help=_("message to display when interacting with user"))
24 parser
.add_option("", "--not-before", help=_("minimum version to choose"), metavar
='VERSION')
25 parser
.add_option("-o", "--offline", help=_("try to avoid using the network"), action
='store_true')
26 parser
.add_option("", "--os", help=_("target operation system type"), metavar
='OS')
27 parser
.add_option("-r", "--refresh", help=_("refresh all used interfaces"), action
='store_true')
28 parser
.add_option("-s", "--source", help=_("select source code"), action
='store_true')
29 parser
.add_option("", "--xml", help=_("write selected versions as XML"), action
='store_true')
31 def get_selections(options
, iface_uri
, select_only
, download_only
, test_callback
):
32 """Get selections for iface_uri, according to the options passed.
33 Will switch to GUI mode if necessary.
34 @param options: options from OptionParser
35 @param iface_uri: canonical URI of the interface
36 @param select_only: return immediately even if the selected versions aren't cached
37 @param download_only: wait for stale feeds, and display GUI button as Download, not Run
38 @return: the selected versions, or None if the user cancels
39 @rtype: L{selections.Selections} | None
41 root_iface
= iface_cache
.get_interface(iface_uri
)
44 h
= handler
.ConsoleHandler()
48 command_name
= options
.command
49 if command_name
is None:
51 elif command_name
== '':
53 policy
= autopolicy
.AutoPolicy(iface_uri
,
55 download_only
= True, # unused?
57 command
= command_name
)
59 if options
.before
or options
.not_before
:
60 policy
.solver
.extra_restrictions
[root_iface
] = [
61 model
.VersionRangeRestriction(model
.parse_version(options
.before
),
62 model
.parse_version(options
.not_before
))]
64 if options
.os
or options
.cpu
:
65 from zeroinstall
.injector
import arch
66 policy
.target_arch
= arch
.get_architecture(options
.os
, options
.cpu
)
69 policy
.network_use
= model
.network_offline
71 # Note that need_download() triggers a solve
72 if options
.refresh
or options
.gui
:
73 # We could run immediately, but the user asked us not to
74 can_run_immediately
= False
77 # --select-only: we only care that we've made a selection, not that we've cached the implementations
78 policy
.need_download()
79 can_run_immediately
= policy
.ready
81 can_run_immediately
= not policy
.need_download()
83 stale_feeds
= [feed
for feed
in policy
.solver
.feeds_used
if
84 not feed
.startswith('distribution:') and # Ignore (memory-only) PackageKit feeds
85 policy
.is_stale(iface_cache
.get_feed(feed
))]
87 if download_only
and stale_feeds
:
88 can_run_immediately
= False
90 if can_run_immediately
:
92 if policy
.network_use
== model
.network_offline
:
93 logging
.debug(_("No doing background update because we are in off-line mode."))
95 # There are feeds we should update, but we can run without them.
96 # Do the update in the background while the program is running.
97 from zeroinstall
.injector
import background
98 background
.spawn_background_update(policy
, options
.verbose
> 0)
99 return policy
.solver
.selections
101 # If the user didn't say whether to use the GUI, choose for them.
102 if options
.gui
is None and os
.environ
.get('DISPLAY', None):
104 # If we need to download anything, we might as well
105 # refresh all the feeds first.
106 options
.refresh
= True
107 logging
.info(_("Switching to GUI mode... (use --console to disable)"))
112 # Just changes the button's label
113 gui_args
.append('--download-only')
115 gui_args
.append('--refresh')
116 if options
.not_before
:
117 gui_args
.insert(0, options
.not_before
)
118 gui_args
.insert(0, '--not-before')
120 gui_args
.insert(0, options
.before
)
121 gui_args
.insert(0, '--before')
123 gui_args
.insert(0, '--source')
125 gui_args
.insert(0, options
.message
)
126 gui_args
.insert(0, '--message')
128 gui_args
.insert(0, '--verbose')
129 if options
.verbose
> 1:
130 gui_args
.insert(0, '--verbose')
132 gui_args
.insert(0, options
.cpu
)
133 gui_args
.insert(0, '--cpu')
135 gui_args
.insert(0, options
.os
)
136 gui_args
.insert(0, '--os')
137 if options
.with_store
:
138 for x
in options
.with_store
:
139 gui_args
+= ['--with-store', x
]
141 gui_args
.append('--select-only')
142 if command_name
is not None:
143 gui_args
.append('--command')
144 gui_args
.append(command_name
)
146 from zeroinstall
import helpers
147 sels
= helpers
.get_selections_gui(iface_uri
, gui_args
, test_callback
)
150 return None # Aborted
152 # Note: --download-only also makes us stop and download stale feeds first.
153 downloaded
= policy
.solve_and_download_impls(refresh
= options
.refresh
or download_only
or False,
154 select_only
= select_only
)
156 policy
.handler
.wait_for_blocker(downloaded
)
157 sels
= selections
.Selections(policy
)
161 def handle(options
, args
):
165 iface_uri
= model
.canonical_iface_uri(args
[0])
167 sels
= get_selections(options
, iface_uri
,
168 select_only
= True, download_only
= False, test_callback
= None)
170 sys
.exit(1) # Aborted by user
179 doc
.writexml(sys
.stdout
)
180 sys
.stdout
.write('\n')
182 def show_human(sels
):
183 from zeroinstall
import zerostore
184 done
= set() # detect cycles
185 def print_node(uri
, command
, indent
):
186 if uri
in done
: return
188 impl
= sels
.selections
.get(uri
, None)
189 print indent
+ "- URI:", uri
191 print indent
+ " Version:", impl
.version
193 if impl
.id.startswith('package:'):
194 path
= "(" + impl
.id + ")"
196 path
= impl
.local_path
or iface_cache
.stores
.lookup_any(impl
.digests
)
197 except zerostore
.NotStored
:
198 path
= "(not cached)"
199 print indent
+ " Path:", path
201 deps
= impl
.dependencies
202 if command
is not None:
203 deps
+= sels
.commands
[command
].requires
205 if isinstance(child
, model
.InterfaceDependency
):
206 if child
.qdom
.name
== 'runner':
207 child_command
= command
+ 1
210 print_node(child
.interface
, child_command
, indent
)
212 print indent
+ " No selected version"
216 print_node(sels
.interface
, 0, "")
218 print_node(sels
.interface
, None, "")