Added read-only 'arch' attribute to Feed (needed by writer).
[zeroinstall.git] / 0launch
blob0e74cbb67cfb0ec5cb1b6ed54f32165f8d572591
1 #!/usr/bin/env python
2 import os, sys
3 from optparse import OptionParser
4 import logging
6 parser = OptionParser(usage="usage: %prog [options] interface [args]\n"
7 " %prog --list [search-term]\n"
8 " %prog --import [signed-interface-files]\n"
9 " %prog --feed [interface]")
10 parser.add_option("-a", "--feed", help="add or remove a feed", action='store_true')
11 parser.add_option("-c", "--console", help="never use GUI", action='store_false', dest='gui')
12 parser.add_option("-d", "--download-only", help="fetch but don't run", action='store_true')
13 parser.add_option("-D", "--dry-run", help="just print actions", action='store_true')
14 parser.add_option("-g", "--gui", help="show graphical policy editor", action='store_true')
15 parser.add_option("-m", "--main", help="name of the file to execute")
16 parser.add_option("-i", "--import", help="import from files, not from the network", action='store_true')
17 parser.add_option("-l", "--list", help="list all known interfaces", action='store_true')
18 parser.add_option("-r", "--refresh", help="refresh all used interfaces", action='store_true')
19 parser.add_option("-v", "--verbose", help="more verbose output", action='count')
20 parser.add_option("-V", "--version", help="display version information", action='store_true')
21 parser.disable_interspersed_args()
23 (options, args) = parser.parse_args()
25 if options.verbose:
26 logger = logging.getLogger()
27 if options.verbose == 1:
28 logger.setLevel(logging.INFO)
29 else:
30 logger.setLevel(logging.DEBUG)
32 from zeroinstall.injector import model, download, autopolicy, namespaces
34 if options.list:
35 if len(args) == 0:
36 match = None
37 elif len(args) == 1:
38 match = args[0].lower()
39 else:
40 parser.print_help()
41 sys.exit(1)
42 from zeroinstall.injector.iface_cache import iface_cache
43 for i in iface_cache.list_all_interfaces():
44 if match and match not in i.lower(): continue
45 print i
46 sys.exit(0)
48 if options.version:
49 import zeroinstall
50 print "0launch (zero-install) " + zeroinstall.version
51 print "Copyright (C) 2005 Thomas Leonard"
52 print "This program comes with ABSOLUTELY NO WARRANTY,"
53 print "to the extent permitted by law."
54 print "You may redistribute copies of this program"
55 print "under the terms of the GNU General Public License."
56 print "For more information about these matters, see the file named COPYING."
57 sys.exit(0)
59 if len(args) < 1:
60 if options.gui:
61 args = [namespaces.injector_gui_uri]
62 options.download_only = True
63 else:
64 parser.print_help()
65 sys.exit(1)
67 try:
68 if getattr(options, 'import'):
69 from zeroinstall.injector import gpg, handler
70 from zeroinstall.injector.iface_cache import iface_cache
71 from xml.dom import minidom
72 for x in args:
73 if not os.path.isfile(x):
74 raise model.SafeException("File '%s' does not exist" % x)
75 logging.info("Importing from file '%s'", x)
76 signed_data = file(x)
77 data, sigs = gpg.check_stream(signed_data)
78 doc = minidom.parseString(data.read())
79 uri = doc.documentElement.getAttribute('uri')
80 assert uri
81 iface = iface_cache.get_interface(uri)
82 logging.info("Importing information about interface %s", iface)
83 signed_data.seek(0)
84 iface_cache.check_signed_data(iface, signed_data, handler.Handler())
85 sys.exit(0)
87 if getattr(options, 'feed'):
88 from zeroinstall.injector import iface_cache, writer
89 from xml.dom import minidom
90 for x in args:
91 print "Feed '%s':\n" % x
92 x = model.canonical_iface_uri(x)
93 policy = autopolicy.AutoPolicy(x, download_only = True, dry_run = options.dry_run)
94 policy.recalculate_with_dl()
95 interfaces = policy.get_feed_targets(policy.root)
96 for i in range(len(interfaces)):
97 feed = interfaces[i].get_feed(x)
98 if feed:
99 print "%d) Remove as feed for '%s'" % (i + 1, interfaces[i].uri)
100 else:
101 print "%d) Add as feed for '%s'" % (i + 1, interfaces[i].uri)
102 print
103 while True:
104 try:
105 i = raw_input('Enter a number, or CTRL-C to cancel [1]: ').strip()
106 except KeyboardInterrupt:
107 print
108 raise model.SafeException("Aborted at user request.")
109 if i == '':
110 i = 1
111 else:
112 try:
113 i = int(i)
114 except ValueError:
115 i = 0
116 if i > 0 and i <= len(interfaces):
117 break
118 print "Invalid number. Try again. (1 to %d)" % len(interfaces)
119 iface = interfaces[i - 1]
120 feed = iface.get_feed(x)
121 if feed:
122 iface.feeds.remove(feed)
123 else:
124 iface.feeds.append(model.Feed(x, arch = None, user_override = True))
125 writer.save_interface(iface)
126 print "\nFeed list for interface '%s' is now:" % iface.get_name()
127 if iface.feeds:
128 for f in iface.feeds:
129 print "- " + f.uri
130 else:
131 print "(no feeds)"
132 sys.exit(0)
134 iface_uri = model.canonical_iface_uri(args[0])
136 # Singleton instance used everywhere...
137 policy = autopolicy.AutoPolicy(iface_uri,
138 download_only = bool(options.download_only),
139 dry_run = options.dry_run)
141 if options.gui is None and os.environ.get('DISPLAY', None):
142 if options.refresh:
143 options.gui = True
144 else:
145 options.gui = policy.need_download()
146 if options.gui:
147 # If we need to download anything, we might as well
148 # refresh all the interfaces first. Also, this triggers
149 # the 'checking for updates' box, which is non-interactive
150 # when there are no changes to the selection.
151 options.refresh = True
152 logging.info("Need to download; switching to GUI mode")
153 except model.SafeException, ex:
154 print >>sys.stderr, ex
155 sys.exit(1)
157 if options.gui:
158 policy.set_root(namespaces.injector_gui_uri)
160 # Try to start the GUI without using the network.
161 # The GUI can refresh itself if it wants to.
162 policy.freshness = 0
163 policy.network_use = model.network_minimal
165 prog_args = [iface_uri] + args[1:]
166 # Options apply to actual program, not GUI
167 if options.download_only:
168 policy.download_only = False
169 prog_args.insert(0, '--download-only')
170 if options.refresh:
171 options.refresh = False
172 prog_args.insert(0, '--refresh')
173 if options.main:
174 prog_args = ['--main', options.main] + prog_args
175 options.main = None
176 else:
177 prog_args = args[1:]
179 try:
180 policy.download_and_execute(prog_args, refresh = bool(options.refresh), main = options.main)
181 except autopolicy.NeedDownload, ex:
182 print ex
183 sys.exit(0)
184 except model.SafeException, ex:
185 print >>sys.stderr, ex
186 sys.exit(1)