2 The B{0launch} command-line interface.
4 This code is here, rather than in B{0launch} itself, simply so that it gets byte-compiled at
8 from zeroinstall
import _
10 from optparse
import OptionParser
13 from zeroinstall
import SafeException
, NeedDownload
14 from zeroinstall
.injector
import model
, autopolicy
, selections
15 from zeroinstall
.injector
.iface_cache
import iface_cache
16 from zeroinstall
.cmd
import UsageError
18 #def program_log(msg): os.access('MARK: 0launch: ' + msg, os.F_OK)
20 #__main__.__builtins__.program_log = program_log
21 #program_log('0launch ' + ' '.join((sys.argv[1:])))
23 def _manage_feeds(options
, args
):
24 from zeroinstall
.injector
import writer
25 from zeroinstall
.injector
.handler
import Handler
26 from zeroinstall
.injector
.policy
import Policy
28 def find_feed_import(iface
, feed_url
):
29 for f
in iface
.extra_feeds
:
34 handler
= Handler(dry_run
= options
.dry_run
)
35 if not args
: raise UsageError()
37 print _("Feed '%s':") % x
+ '\n'
38 x
= model
.canonical_iface_uri(x
)
39 policy
= Policy(x
, handler
)
41 policy
.network_use
= model
.network_offline
43 feed
= iface_cache
.get_feed(x
)
44 if policy
.network_use
!= model
.network_offline
and policy
.is_stale(feed
):
45 blocker
= policy
.fetcher
.download_and_import_feed(x
, iface_cache
.iface_cache
)
46 print _("Downloading feed; please wait...")
47 handler
.wait_for_blocker(blocker
)
50 interfaces
= policy
.get_feed_targets(x
)
51 for i
in range(len(interfaces
)):
52 if find_feed_import(interfaces
[i
], x
):
53 print _("%(index)d) Remove as feed for '%(uri)s'") % {'index': i
+ 1, 'uri': interfaces
[i
].uri
}
55 print _("%(index)d) Add as feed for '%(uri)s'") % {'index': i
+ 1, 'uri': interfaces
[i
].uri
}
59 i
= raw_input(_('Enter a number, or CTRL-C to cancel [1]: ')).strip()
60 except KeyboardInterrupt:
62 raise SafeException(_("Aborted at user request."))
70 if i
> 0 and i
<= len(interfaces
):
72 print _("Invalid number. Try again. (1 to %d)") % len(interfaces
)
73 iface
= interfaces
[i
- 1]
74 feed_import
= find_feed_import(iface
, x
)
76 iface
.extra_feeds
.remove(feed_import
)
78 iface
.extra_feeds
.append(model
.Feed(x
, arch
= None, user_override
= True))
79 writer
.save_interface(iface
)
80 print '\n' + _("Feed list for interface '%s' is now:") % iface
.get_name()
82 for f
in iface
.extra_feeds
:
87 def _download_missing_selections(options
, sels
):
88 from zeroinstall
.injector
import fetch
89 from zeroinstall
.injector
.handler
import Handler
90 handler
= Handler(dry_run
= options
.dry_run
)
91 fetcher
= fetch
.Fetcher(handler
)
92 blocker
= sels
.download_missing(iface_cache
, fetcher
)
94 logging
.info(_("Waiting for selected implementations to be downloaded..."))
95 handler
.wait_for_blocker(blocker
)
97 def _get_selections(sels
, options
):
99 from zeroinstall
import zerostore
100 done
= set() # detect cycles
101 def print_node(uri
, command
, indent
):
102 if uri
in done
: return
104 impl
= sels
.selections
.get(uri
, None)
105 print indent
+ "- URI:", uri
107 print indent
+ " Version:", impl
.version
109 if impl
.id.startswith('package:'):
110 path
= "(" + impl
.id + ")"
112 path
= impl
.local_path
or iface_cache
.stores
.lookup_any(impl
.digests
)
113 except zerostore
.NotStored
:
114 path
= "(not cached)"
115 print indent
+ " Path:", path
117 deps
= impl
.dependencies
118 if command
is not None:
119 deps
+= sels
.commands
[command
].requires
121 if isinstance(child
, model
.InterfaceDependency
):
122 if child
.qdom
.name
== 'runner':
123 child_command
= command
+ 1
126 print_node(child
.interface
, child_command
, indent
)
128 print indent
+ " No selected version"
132 print_node(sels
.interface
, 0, "")
134 print_node(sels
.interface
, None, "")
138 doc
.writexml(sys
.stdout
)
139 sys
.stdout
.write('\n')
141 def main(command_args
):
142 """Act as if 0launch was run with the given arguments.
143 @arg command_args: array of arguments (e.g. C{sys.argv[1:]})
144 @type command_args: [str]
146 # Ensure stdin, stdout and stderr FDs exist, to avoid confusion
147 for std
in (0, 1, 2):
151 fd
= os
.open('/dev/null', os
.O_RDONLY
)
156 parser
= OptionParser(usage
=_("usage: %prog [options] interface [args]\n"
157 " %prog --list [search-term]\n"
158 " %prog --import [signed-interface-files]\n"
159 " %prog --feed [interface]"))
160 parser
.add_option("", "--before", help=_("choose a version before this"), metavar
='VERSION')
161 parser
.add_option("", "--command", help=_("command to select"), metavar
='COMMAND')
162 parser
.add_option("-c", "--console", help=_("never use GUI"), action
='store_false', dest
='gui')
163 parser
.add_option("", "--cpu", help=_("target CPU type"), metavar
='CPU')
164 parser
.add_option("-d", "--download-only", help=_("fetch but don't run"), action
='store_true')
165 parser
.add_option("-D", "--dry-run", help=_("just print actions"), action
='store_true')
166 parser
.add_option("-f", "--feed", help=_("add or remove a feed"), action
='store_true')
167 parser
.add_option("", "--get-selections", help=_("write selected versions as XML"), action
='store_true', dest
='xml')
168 parser
.add_option("-g", "--gui", help=_("show graphical policy editor"), action
='store_true')
169 parser
.add_option("-i", "--import", help=_("import from files, not from the network"), action
='store_true')
170 parser
.add_option("-l", "--list", help=_("list all known interfaces"), action
='store_true')
171 parser
.add_option("-m", "--main", help=_("name of the file to execute"))
172 parser
.add_option("", "--message", help=_("message to display when interacting with user"))
173 parser
.add_option("", "--not-before", help=_("minimum version to choose"), metavar
='VERSION')
174 parser
.add_option("", "--os", help=_("target operation system type"), metavar
='OS')
175 parser
.add_option("-o", "--offline", help=_("try to avoid using the network"), action
='store_true')
176 parser
.add_option("-r", "--refresh", help=_("refresh all used interfaces"), action
='store_true')
177 parser
.add_option("", "--select-only", help=_("only download the feeds"), action
='store_true')
178 parser
.add_option("", "--set-selections", help=_("run versions specified in XML file"), metavar
='FILE')
179 parser
.add_option("", "--show", help=_("show where components are installed"), action
='store_true')
180 parser
.add_option("-s", "--source", help=_("select source code"), action
='store_true')
181 parser
.add_option("", "--systray", help=_("download in the background"), action
='store_true')
182 parser
.add_option("-v", "--verbose", help=_("more verbose output"), action
='count')
183 parser
.add_option("-V", "--version", help=_("display version information"), action
='store_true')
184 parser
.add_option("", "--with-store", help=_("add an implementation cache"), action
='append', metavar
='DIR')
185 parser
.add_option("-w", "--wrapper", help=_("execute program using a debugger, etc"), metavar
='COMMAND')
186 parser
.disable_interspersed_args()
188 (options
, args
) = parser
.parse_args(command_args
)
191 logger
= logging
.getLogger()
192 if options
.verbose
== 1:
193 logger
.setLevel(logging
.INFO
)
195 logger
.setLevel(logging
.DEBUG
)
197 logging
.info(_("Running 0launch %(version)s %(args)s; Python %(python_version)s"), {'version': zeroinstall
.version
, 'args': repr(args
), 'python_version': sys
.version
})
199 if options
.select_only
or options
.show
:
200 options
.download_only
= True
202 if options
.with_store
:
203 from zeroinstall
import zerostore
204 for x
in options
.with_store
:
205 iface_cache
.stores
.stores
.append(zerostore
.Store(os
.path
.abspath(x
)))
206 logging
.info(_("Stores search path is now %s"), iface_cache
.stores
.stores
)
210 from zeroinstall
.cmd
import list
211 list.handle(options
, args
)
212 elif options
.version
:
214 print "0launch (zero-install) " + zeroinstall
.version
215 print "Copyright (C) 2010 Thomas Leonard"
216 print _("This program comes with ABSOLUTELY NO WARRANTY,"
217 "\nto the extent permitted by law."
218 "\nYou may redistribute copies of this program"
219 "\nunder the terms of the GNU Lesser General Public License."
220 "\nFor more information about these matters, see the file named COPYING.")
221 elif options
.set_selections
:
222 from zeroinstall
.injector
import qdom
, run
223 sels
= selections
.Selections(qdom
.parse(file(options
.set_selections
)))
224 _download_missing_selections(options
, sels
)
226 _get_selections(sels
, options
)
227 elif not options
.download_only
:
228 run
.execute_selections(sels
, args
, options
.dry_run
, options
.main
, options
.wrapper
)
229 elif getattr(options
, 'import'):
230 # (import is a keyword)
231 cmd
= __import__('zeroinstall.cmd.import', globals(), locals(), ["import"], 0)
232 cmd
.handle(options
, args
)
234 _manage_feeds(options
, args
)
235 elif options
.select_only
:
236 from zeroinstall
.cmd
import select
239 select
.handle(options
, args
)
240 elif options
.download_only
or options
.xml
or options
.show
:
241 from zeroinstall
.cmd
import download
242 download
.handle(options
, args
)
246 from zeroinstall
import helpers
247 return helpers
.get_selections_gui(None, [])
251 from zeroinstall
.cmd
import run
252 run
.handle(options
, args
)
253 except NeedDownload
, ex
:
254 # This only happens for dry runs
259 except SafeException
, ex
:
260 if options
.verbose
: raise
262 print >>sys
.stderr
, unicode(ex
)
264 print >>sys
.stderr
, repr(ex
)