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 from zeroinstall
.injector
import model
, download
, autopolicy
, namespaces
65 from zeroinstall
.injector
.iface_cache
import iface_cache
68 matches
= iface_cache
.list_all_interfaces()
70 match
= args
[0].lower()
71 matches
= [i
for i
in iface_cache
.list_all_interfaces() if match
in i
.lower()]
83 print "0launch (zero-install) " + zeroinstall
.version
84 print "Copyright (C) 2006 Thomas Leonard"
85 print "This program comes with ABSOLUTELY NO WARRANTY,"
86 print "to the extent permitted by law."
87 print "You may redistribute copies of this program"
88 print "under the terms of the GNU General Public License."
89 print "For more information about these matters, see the file named COPYING."
94 args
= [namespaces
.injector_gui_uri
]
95 options
.download_only
= True
101 if getattr(options
, 'import'):
102 from zeroinstall
.injector
import gpg
, handler
103 from zeroinstall
.injector
.iface_cache
import iface_cache
, PendingFeed
104 from xml
.dom
import minidom
106 if not os
.path
.isfile(x
):
107 raise model
.SafeException("File '%s' does not exist" % x
)
108 logging
.info("Importing from file '%s'", x
)
109 signed_data
= file(x
)
110 data
, sigs
= gpg
.check_stream(signed_data
)
111 doc
= minidom
.parseString(data
.read())
112 uri
= doc
.documentElement
.getAttribute('uri')
114 raise model
.SafeException("Missing 'uri' attribute on root element in '%s'" % x
)
115 iface
= iface_cache
.get_interface(uri
)
116 logging
.info("Importing information about interface %s", iface
)
118 pending
= PendingFeed(uri
, signed_data
)
119 iface_cache
.add_pending(pending
)
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
)
125 handler
= handler
.Handler()
126 pending
.begin_key_downloads(handler
, keys_ready
)
127 handler
.wait_for_downloads()
131 if getattr(options
, 'feed'):
132 from zeroinstall
.injector
import iface_cache
, writer
133 from xml
.dom
import minidom
135 print "Feed '%s':\n" % x
136 x
= model
.canonical_iface_uri(x
)
137 policy
= autopolicy
.AutoPolicy(x
, download_only
= True, dry_run
= options
.dry_run
)
139 policy
.network_use
= model
.network_offline
140 policy
.recalculate_with_dl()
141 interfaces
= policy
.get_feed_targets(policy
.root
)
142 for i
in range(len(interfaces
)):
143 feed
= interfaces
[i
].get_feed(x
)
145 print "%d) Remove as feed for '%s'" % (i
+ 1, interfaces
[i
].uri
)
147 print "%d) Add as feed for '%s'" % (i
+ 1, interfaces
[i
].uri
)
151 i
= raw_input('Enter a number, or CTRL-C to cancel [1]: ').strip()
152 except KeyboardInterrupt:
154 raise model
.SafeException("Aborted at user request.")
162 if i
> 0 and i
<= len(interfaces
):
164 print "Invalid number. Try again. (1 to %d)" % len(interfaces
)
165 iface
= interfaces
[i
- 1]
166 feed
= iface
.get_feed(x
)
168 iface
.feeds
.remove(feed
)
170 iface
.feeds
.append(model
.Feed(x
, arch
= None, user_override
= True))
171 writer
.save_interface(iface
)
172 print "\nFeed list for interface '%s' is now:" % iface
.get_name()
174 for f
in iface
.feeds
:
180 iface_uri
= model
.canonical_iface_uri(args
[0])
182 # Singleton instance used everywhere...
183 policy
= autopolicy
.AutoPolicy(iface_uri
,
184 download_only
= bool(options
.download_only
),
185 dry_run
= options
.dry_run
,
186 src
= options
.source
)
188 if options
.before
or options
.not_before
:
189 policy
.root_restrictions
.append(model
.Restriction(model
.parse_version(options
.before
),
190 model
.parse_version(options
.not_before
)))
193 policy
.network_use
= model
.network_offline
195 # Note that need_download() triggers a recalculate()
196 if options
.refresh
or options
.gui
:
197 # We could run immediately, but the user asked us not to
198 can_run_immediately
= False
200 can_run_immediately
= (not policy
.need_download()) and policy
.ready
202 if options
.download_only
and policy
.stale_feeds
:
203 can_run_immediately
= False
205 if can_run_immediately
:
206 if policy
.stale_feeds
:
207 # There are feeds we should update, but we can run without them.
208 # Do the update in the background while the program is running.
210 background
.spawn_background_update(policy
, options
.verbose
> 0)
211 policy
.execute(args
[1:], main
= options
.main
)
212 assert options
.dry_run
or options
.download_only
215 # If the user didn't say whether to use the GUI, choose for them.
216 if options
.gui
is None and os
.environ
.get('DISPLAY', None):
218 # If we need to download anything, we might as well
219 # refresh all the interfaces first. Also, this triggers
220 # the 'checking for updates' box, which is non-interactive
221 # when there are no changes to the selection.
222 options
.refresh
= True
223 logging
.info("Switching to GUI mode... (use --console to disable)")
224 except model
.SafeException
, ex
:
225 if options
.verbose
: raise
226 print >>sys
.stderr
, ex
230 policy
.set_root(namespaces
.injector_gui_uri
)
233 # Try to start the GUI without using the network.
234 # The GUI can refresh itself if it wants to.
236 policy
.network_use
= model
.network_offline
238 prog_args
= [iface_uri
] + args
[1:]
239 # Options apply to actual program, not GUI
240 if options
.download_only
:
241 policy
.download_only
= False
242 prog_args
.insert(0, '--download-only')
244 options
.refresh
= False
245 prog_args
.insert(0, '--refresh')
246 if options
.not_before
:
247 prog_args
.insert(0, options
.not_before
)
248 prog_args
.insert(0, '--not-before')
250 prog_args
.insert(0, options
.before
)
251 prog_args
.insert(0, '--before')
253 prog_args
.insert(0, '--source')
255 prog_args
= ['--main', options
.main
] + prog_args
257 del policy
.root_restrictions
[:]
262 #program_log('download_and_execute ' + iface_uri)
263 policy
.download_and_execute(prog_args
, refresh
= bool(options
.refresh
), main
= options
.main
)
264 except autopolicy
.NeedDownload
, ex
:
267 except model
.SafeException
, ex
:
268 if options
.verbose
: raise
269 print >>sys
.stderr
, ex