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
9 from optparse
import OptionParser
12 #def program_log(msg): os.access('MARK: 0launch: ' + msg, os.F_OK)
14 #__main__.__builtins__.program_log = program_log
15 #program_log('0launch ' + ' '.join((sys.argv[1:])))
17 def main(command_args
):
18 """Act as if 0launch was run with the given arguments.
19 @arg command_args: array of arguments (e.g. C{sys.argv[1:]})
20 @type command_args: [str]
22 # Ensure stdin, stdout and stderr FDs exist, to avoid confusion
27 fd
= os
.open('/dev/null', os
.O_RDONLY
)
32 parser
= OptionParser(usage
="usage: %prog [options] interface [args]\n"
33 " %prog --list [search-term]\n"
34 " %prog --import [signed-interface-files]\n"
35 " %prog --feed [interface]")
36 parser
.add_option("", "--before", help="choose a version before this", metavar
='VERSION')
37 parser
.add_option("-c", "--console", help="never use GUI", action
='store_false', dest
='gui')
38 parser
.add_option("-d", "--download-only", help="fetch but don't run", action
='store_true')
39 parser
.add_option("-D", "--dry-run", help="just print actions", action
='store_true')
40 parser
.add_option("-f", "--feed", help="add or remove a feed", action
='store_true')
41 parser
.add_option("-g", "--gui", help="show graphical policy editor", action
='store_true')
42 parser
.add_option("-i", "--import", help="import from files, not from the network", action
='store_true')
43 parser
.add_option("-l", "--list", help="list all known interfaces", action
='store_true')
44 parser
.add_option("-m", "--main", help="name of the file to execute")
45 parser
.add_option("", "--not-before", help="minimum version to choose", metavar
='VERSION')
46 parser
.add_option("-o", "--offline", help="try to avoid using the network", action
='store_true')
47 parser
.add_option("-r", "--refresh", help="refresh all used interfaces", action
='store_true')
48 parser
.add_option("-s", "--source", help="select source code", action
='store_true')
49 parser
.add_option("-v", "--verbose", help="more verbose output", action
='count')
50 parser
.add_option("-V", "--version", help="display version information", action
='store_true')
51 parser
.disable_interspersed_args()
53 (options
, args
) = parser
.parse_args(command_args
)
56 logger
= logging
.getLogger()
57 if options
.verbose
== 1:
58 logger
.setLevel(logging
.INFO
)
60 logger
.setLevel(logging
.DEBUG
)
62 logging
.info("Running 0launch %s %s; Python %s", zeroinstall
.version
, repr(args
), sys
.version
)
64 from zeroinstall
.injector
import model
, download
, autopolicy
, namespaces
67 from zeroinstall
.injector
.iface_cache
import iface_cache
70 matches
= iface_cache
.list_all_interfaces()
72 match
= args
[0].lower()
73 matches
= [i
for i
in iface_cache
.list_all_interfaces() if match
in i
.lower()]
85 print "0launch (zero-install) " + zeroinstall
.version
86 print "Copyright (C) 2006 Thomas Leonard"
87 print "This program comes with ABSOLUTELY NO WARRANTY,"
88 print "to the extent permitted by law."
89 print "You may redistribute copies of this program"
90 print "under the terms of the GNU General Public License."
91 print "For more information about these matters, see the file named COPYING."
96 args
= [namespaces
.injector_gui_uri
]
97 options
.download_only
= True
103 if getattr(options
, 'import'):
104 from zeroinstall
.injector
import gpg
, handler
, trust
105 from zeroinstall
.injector
.iface_cache
import iface_cache
, PendingFeed
106 from xml
.dom
import minidom
108 if not os
.path
.isfile(x
):
109 raise model
.SafeException("File '%s' does not exist" % x
)
110 logging
.info("Importing from file '%s'", x
)
111 signed_data
= file(x
)
112 data
, sigs
= gpg
.check_stream(signed_data
)
113 doc
= minidom
.parseString(data
.read())
114 uri
= doc
.documentElement
.getAttribute('uri')
116 raise model
.SafeException("Missing 'uri' attribute on root element in '%s'" % x
)
117 iface
= iface_cache
.get_interface(uri
)
118 logging
.info("Importing information about interface %s", iface
)
122 if not iface_cache
.update_interface_if_trusted(iface
, pending
.sigs
, pending
.new_xml
):
123 handler
.confirm_trust_keys(iface
, pending
.sigs
, pending
.new_xml
)
124 trust
.trust_db
.watchers
.append(lambda: keys_ready())
126 pending
= PendingFeed(uri
, signed_data
)
127 iface_cache
.add_pending(pending
)
129 handler
= handler
.Handler()
130 pending
.begin_key_downloads(handler
, keys_ready
)
131 handler
.wait_for_downloads()
135 if getattr(options
, 'feed'):
136 from zeroinstall
.injector
import iface_cache
, writer
137 from xml
.dom
import minidom
139 print "Feed '%s':\n" % x
140 x
= model
.canonical_iface_uri(x
)
141 policy
= autopolicy
.AutoPolicy(x
, download_only
= True, dry_run
= options
.dry_run
)
143 policy
.network_use
= model
.network_offline
144 policy
.recalculate_with_dl()
145 interfaces
= policy
.get_feed_targets(policy
.root
)
146 for i
in range(len(interfaces
)):
147 feed
= interfaces
[i
].get_feed(x
)
149 print "%d) Remove as feed for '%s'" % (i
+ 1, interfaces
[i
].uri
)
151 print "%d) Add as feed for '%s'" % (i
+ 1, interfaces
[i
].uri
)
155 i
= raw_input('Enter a number, or CTRL-C to cancel [1]: ').strip()
156 except KeyboardInterrupt:
158 raise model
.SafeException("Aborted at user request.")
166 if i
> 0 and i
<= len(interfaces
):
168 print "Invalid number. Try again. (1 to %d)" % len(interfaces
)
169 iface
= interfaces
[i
- 1]
170 feed
= iface
.get_feed(x
)
172 iface
.feeds
.remove(feed
)
174 iface
.feeds
.append(model
.Feed(x
, arch
= None, user_override
= True))
175 writer
.save_interface(iface
)
176 print "\nFeed list for interface '%s' is now:" % iface
.get_name()
178 for f
in iface
.feeds
:
184 iface_uri
= model
.canonical_iface_uri(args
[0])
186 # Singleton instance used everywhere...
187 policy
= autopolicy
.AutoPolicy(iface_uri
,
188 download_only
= bool(options
.download_only
),
189 dry_run
= options
.dry_run
,
190 src
= options
.source
)
192 if options
.before
or options
.not_before
:
193 policy
.root_restrictions
.append(model
.Restriction(model
.parse_version(options
.before
),
194 model
.parse_version(options
.not_before
)))
197 policy
.network_use
= model
.network_offline
199 # Note that need_download() triggers a recalculate()
200 if options
.refresh
or options
.gui
:
201 # We could run immediately, but the user asked us not to
202 can_run_immediately
= False
204 can_run_immediately
= (not policy
.need_download()) and policy
.ready
206 if options
.download_only
and policy
.stale_feeds
:
207 can_run_immediately
= False
209 if can_run_immediately
:
210 if policy
.stale_feeds
:
211 # There are feeds we should update, but we can run without them.
212 # Do the update in the background while the program is running.
214 background
.spawn_background_update(policy
, options
.verbose
> 0)
215 policy
.execute(args
[1:], main
= options
.main
)
216 assert options
.dry_run
or options
.download_only
219 # If the user didn't say whether to use the GUI, choose for them.
220 if options
.gui
is None and os
.environ
.get('DISPLAY', None):
222 # If we need to download anything, we might as well
223 # refresh all the interfaces first. Also, this triggers
224 # the 'checking for updates' box, which is non-interactive
225 # when there are no changes to the selection.
226 options
.refresh
= True
227 logging
.info("Switching to GUI mode... (use --console to disable)")
228 except model
.SafeException
, ex
:
229 if options
.verbose
: raise
230 print >>sys
.stderr
, ex
234 policy
.set_root(namespaces
.injector_gui_uri
)
237 # Try to start the GUI without using the network.
238 # The GUI can refresh itself if it wants to.
240 policy
.network_use
= model
.network_offline
242 prog_args
= [iface_uri
] + args
[1:]
243 # Options apply to actual program, not GUI
244 if options
.download_only
:
245 policy
.download_only
= False
246 prog_args
.insert(0, '--download-only')
248 options
.refresh
= False
249 prog_args
.insert(0, '--refresh')
250 if options
.not_before
:
251 prog_args
.insert(0, options
.not_before
)
252 prog_args
.insert(0, '--not-before')
254 prog_args
.insert(0, options
.before
)
255 prog_args
.insert(0, '--before')
257 prog_args
.insert(0, '--source')
259 prog_args
= ['--main', options
.main
] + prog_args
261 del policy
.root_restrictions
[:]
266 #program_log('download_and_execute ' + iface_uri)
267 policy
.download_and_execute(prog_args
, refresh
= bool(options
.refresh
), main
= options
.main
)
268 except autopolicy
.NeedDownload
, ex
:
271 except model
.SafeException
, ex
:
272 if options
.verbose
: raise
273 print >>sys
.stderr
, ex