2 from zeroinstall
import SafeException
3 from xml
.dom
import minidom
4 from optparse
import OptionParser
7 from logging
import info
, debug
8 import edit
, validator
, create
12 parser
= OptionParser(usage
="usage: %prog [options] interface")
13 parser
.add_option("-a", "--add-from", help="add implementations from FEED", metavar
='FEED')
14 parser
.add_option("--add-types", help="add missing MIME-type attributes", action
='store_true')
15 parser
.add_option("--add-version", help="add a new implementation", action
='store', metavar
='VERSION')
16 parser
.add_option("--archive-url", help="add archive at this URL", action
='store', metavar
='URL')
17 parser
.add_option("--archive-file", help="local copy of archive-url", action
='store', metavar
='FILE')
18 parser
.add_option("--archive-extract", help="subdirectory of archive to extract", action
='store', metavar
='DIR')
19 parser
.add_option("-c", "--create", help="create file if nonexistant", action
='store_true')
20 parser
.add_option("-d", "--add-digest", help="add extra digests", action
='store', metavar
='ALG')
21 parser
.add_option("-e", "--edit", help="edit with $EDITOR", action
='store_true')
22 parser
.add_option("-k", "--key", help="key to use for signing")
23 parser
.add_option("-l", "--local", help="deprecated; use --add-from instead", dest
='add_from', metavar
='LOCAL')
24 parser
.add_option("--manifest-algorithm", help="select algorithm for manifests", action
='append', metavar
='ALG')
25 parser
.add_option("--set-interface-uri", help="set interface URI", action
='store', metavar
='URI')
26 parser
.add_option("--set-id", help="set implementation ID", action
='store', metavar
='DIGEST')
27 parser
.add_option("--set-main", help="set main executable", action
='store', metavar
='EXEC')
28 parser
.add_option("--set-arch", help="set architecture", action
='store', metavar
='ARCH')
29 parser
.add_option("--set-released", help="set release date", action
='store', metavar
='DATE')
30 parser
.add_option("--set-stability", help="set stability", action
='store', metavar
='STABILITY')
31 parser
.add_option("--set-version", help="set version number", action
='store', metavar
='VERSION')
32 parser
.add_option("-s", "--stable", help="mark testing version stable", action
='store_true')
33 parser
.add_option("", "--select-version", help="select version to use in --set-* commands", action
='store', metavar
='VERSION')
34 parser
.add_option("-x", "--xmlsign", help="add an XML signature block", action
='store_true')
35 parser
.add_option("-u", "--unsign", help="remove any signature", action
='store_true')
36 parser
.add_option("-v", "--verbose", help="more verbose output", action
='count')
37 parser
.add_option("-V", "--version", help="display version information", action
='store_true')
39 (options
, args
) = parser
.parse_args()
41 force_save
= options
.create
44 print "0publish (zero-install) " + version
45 print "Copyright (C) 2005-2010 Thomas Leonard"
46 print "This program comes with ABSOLUTELY NO WARRANTY,"
47 print "to the extent permitted by law."
48 print "You may redistribute copies of this program"
49 print "under the terms of the GNU General Public License."
50 print "For more information about these matters, see the file named COPYING."
55 logger
= logging
.getLogger()
56 if options
.verbose
== 1:
57 logger
.setLevel(logging
.INFO
)
59 logger
.setLevel(logging
.DEBUG
)
68 ans
= raw_input(q
+ " [Y/N] ").lower()
69 if ans
in ('y', 'yes'): return True
70 if ans
in ('n', 'no'): return False
73 # Load or create the starting data...
75 if os
.path
.exists(interface
):
76 contents
= file(interface
).read()
77 data
, sign_fn
, key
= signing
.check_signature(interface
)
78 elif options
.add_from
:
79 if os
.path
.exists(options
.add_from
):
80 data
= create
.create_from_local(options
.add_from
)
81 sign_fn
= signing
.sign_unsigned
84 options
.add_from
= False
86 raise Exception("File '%s' does not exist." % options
.add_from
)
88 if options
.create
or confirm("Interface file '%s' does not exist. Create it?" % interface
):
89 data
= create
.create(interface
)
90 sign_fn
= signing
.sign_unsigned
92 options
.edit
= not options
.create
96 debug("Original data: %s", data
)
97 info("Original signing method: %s", sign_fn
.__name
__)
98 info("Original key: %s", key
)
101 old_sign_fn
= sign_fn
104 if sign_fn
is signing
.sign_unsigned
and options
.key
:
105 sign_fn
= signing
.sign_xml
108 # Validate the input...
110 validator
.check(data
, warnings
= False) # Don't warn on load AND save!
112 except validator
.InvalidInterface
, ex
:
113 print "Invalid interface: " + str(ex
)
116 ans
= raw_input("Interface is invalid. (E)dit or (A)bort?").lower()
117 if ans
in ('e', 'edit'):
118 data
= edit
.edit(data
)
119 options
.edit
= False # Don't edit twice
121 if ans
in ('a', 'abort'): sys
.exit(1)
125 sign_fn
= signing
.sign_xml
127 sign_fn
= signing
.sign_unsigned
129 print "Changing key from '%s' to '%s'" % (key
, options
.key
)
131 if options
.set_interface_uri
:
133 data
= release
.set_interface_uri(data
, options
.set_interface_uri
)
134 if options
.add_version
:
136 data
= release
.add_version(data
, options
.add_version
)
137 if options
.set_id
or options
.set_version
or options
.set_released
or \
138 options
.set_stability
or options
.set_arch
or options
.set_main
:
140 data
= release
.set_attributes(data
, options
.select_version
,
142 version
= options
.set_version
,
143 released
= options
.set_released
,
144 stability
= options
.set_stability
,
145 main
= options
.set_main
,
146 arch
= options
.set_arch
)
148 assert not options
.select_version
, "Use --set-stability=stable --select-version=... instead"
150 data
= stable
.mark_stable(data
)
151 if options
.archive_url
:
153 algs
= options
.manifest_algorithm
157 if hasattr(hashlib
, 'sha256'):
158 algs
.append('sha256')
159 data
= archive
.add_archive(data
, options
.archive_url
, options
.archive_file
, options
.archive_extract
, algs
)
160 elif options
.archive_file
or options
.archive_extract
:
161 raise Exception('Must use --archive-uri option')
164 data
= merge
.merge(data
, options
.add_from
)
165 if options
.add_digest
:
167 data
= digest
.add_digests(data
, alg
= options
.add_digest
)
168 if options
.add_types
:
170 data
= mimetypes
.add_types(data
)
172 data
= edit
.edit(data
)
175 # Validate the result...
177 validator
.check(data
)
179 except validator
.InvalidInterface
, ex
:
180 print "Invalid interface: " + str(ex
)
183 ans
= raw_input("Interface is invalid. (E)dit or (A)bort?").lower()
184 if ans
in ('e', 'edit'):
185 data
= edit
.edit(data
)
187 if ans
in ('a', 'abort'): sys
.exit(1)
189 if (old_data
== data
and sign_fn
== old_sign_fn
and key
== old_key
) and not force_save
:
190 print "Interface unchanged. Not writing."
194 doc
= minidom
.parseString(data
)
195 data
= create
.xml_header
+ doc
.documentElement
.toxml('utf-8')
198 if not data
.endswith('\n'): data
+= '\n'
199 sign_fn(interface
, data
, key
)
201 info("Wrote '%s'", interface
)
203 if sign_fn
!= signing
.sign_unsigned
:
204 # Read it back in to find out what key we signed it with
205 # and ensure that the key has been exported
206 contents
= file(interface
).read()
207 saved_data
, saved_sign_fn
, saved_key
= signing
.check_signature(interface
)
208 assert saved_data
== data
209 assert saved_sign_fn
== sign_fn
210 signing
.export_key(os
.path
.dirname(interface
), saved_key
)
211 except KeyboardInterrupt, ex
:
212 print >>sys
.stderr
, "Aborted at user's request"
214 except SafeException
, ex
:
215 if options
.verbose
: raise
216 print >>sys
.stderr
, ex