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("-g", "--gpgsign", help="add a GPG signature block", action
='store_true')
23 parser
.add_option("-k", "--key", help="key to use for signing")
24 parser
.add_option("-l", "--local", help="deprecated; use --add-from instead", dest
='add_from', metavar
='LOCAL')
25 parser
.add_option("--manifest-algorithm", help="select algorithm for manifests", action
='append', metavar
='ALG')
26 parser
.add_option("--set-interface-uri", help="set interface URI", action
='store', metavar
='URI')
27 parser
.add_option("--set-id", help="set implementation ID", action
='store', metavar
='DIGEST')
28 parser
.add_option("--set-main", help="set main executable", action
='store', metavar
='EXEC')
29 parser
.add_option("--set-arch", help="set architecture", action
='store', metavar
='ARCH')
30 parser
.add_option("--set-released", help="set release date", action
='store', metavar
='DATE')
31 parser
.add_option("--set-stability", help="set stability", action
='store', metavar
='STABILITY')
32 parser
.add_option("--set-version", help="set version number", action
='store', metavar
='VERSION')
33 parser
.add_option("-s", "--stable", help="mark testing version stable", action
='store_true')
34 parser
.add_option("", "--select-version", help="select version to use in --set-* commands", action
='store', metavar
='VERSION')
35 parser
.add_option("-x", "--xmlsign", help="add an XML signature block", action
='store_true')
36 parser
.add_option("-u", "--unsign", help="remove any signature", action
='store_true')
37 parser
.add_option("-v", "--verbose", help="more verbose output", action
='count')
38 parser
.add_option("-V", "--version", help="display version information", action
='store_true')
40 (options
, args
) = parser
.parse_args()
42 force_save
= options
.create
45 print "0publish (zero-install) " + version
46 print "Copyright (C) 2005-2010 Thomas Leonard"
47 print "This program comes with ABSOLUTELY NO WARRANTY,"
48 print "to the extent permitted by law."
49 print "You may redistribute copies of this program"
50 print "under the terms of the GNU General Public License."
51 print "For more information about these matters, see the file named COPYING."
56 logger
= logging
.getLogger()
57 if options
.verbose
== 1:
58 logger
.setLevel(logging
.INFO
)
60 logger
.setLevel(logging
.DEBUG
)
69 ans
= raw_input(q
+ " [Y/N] ").lower()
70 if ans
in ('y', 'yes'): return True
71 if ans
in ('n', 'no'): return False
74 # Load or create the starting data...
76 if os
.path
.exists(interface
):
77 contents
= file(interface
).read()
78 data
, sign_fn
, key
= signing
.check_signature(interface
)
79 elif options
.add_from
:
80 if os
.path
.exists(options
.add_from
):
81 data
= create
.create_from_local(options
.add_from
)
82 sign_fn
= signing
.sign_unsigned
85 options
.add_from
= False
87 raise Exception("File '%s' does not exist." % options
.add_from
)
89 if options
.create
or confirm("Interface file '%s' does not exist. Create it?" % interface
):
90 data
= create
.create(interface
)
91 sign_fn
= signing
.sign_unsigned
93 options
.edit
= not options
.create
97 debug("Original data: %s", data
)
98 info("Original signing method: %s", sign_fn
.__name
__)
99 info("Original key: %s", key
)
102 old_sign_fn
= sign_fn
105 if sign_fn
is signing
.sign_unsigned
and options
.key
:
106 sign_fn
= signing
.sign_xml
109 # Validate the input...
111 validator
.check(data
, warnings
= False) # Don't warn on load AND save!
113 except validator
.InvalidInterface
, ex
:
114 print "Invalid interface: " + str(ex
)
117 ans
= raw_input("Interface is invalid. (E)dit or (A)bort?").lower()
118 if ans
in ('e', 'edit'):
119 data
= edit
.edit(data
)
120 options
.edit
= False # Don't edit twice
122 if ans
in ('a', 'abort'): sys
.exit(1)
126 sign_fn
= signing
.sign_xml
128 sign_fn
= signing
.sign_unsigned
130 sign_fn
= signing
.sign_plain
132 print "Changing key from '%s' to '%s'" % (key
, options
.key
)
134 if options
.set_interface_uri
:
136 data
= release
.set_interface_uri(data
, options
.set_interface_uri
)
137 if options
.add_version
:
139 data
= release
.add_version(data
, options
.add_version
)
140 if options
.set_id
or options
.set_version
or options
.set_released
or \
141 options
.set_stability
or options
.set_arch
or options
.set_main
:
143 data
= release
.set_attributes(data
, options
.select_version
,
145 version
= options
.set_version
,
146 released
= options
.set_released
,
147 stability
= options
.set_stability
,
148 main
= options
.set_main
,
149 arch
= options
.set_arch
)
151 assert not options
.select_version
, "Use --set-stability=stable --select-version=... instead"
153 data
= stable
.mark_stable(data
)
154 if options
.archive_url
:
156 algs
= options
.manifest_algorithm
160 if hasattr(hashlib
, 'sha256'):
161 algs
.append('sha256')
162 data
= archive
.add_archive(data
, options
.archive_url
, options
.archive_file
, options
.archive_extract
, algs
)
163 elif options
.archive_file
or options
.archive_extract
:
164 raise Exception('Must use --archive-uri option')
167 data
= merge
.merge(data
, options
.add_from
)
168 if options
.add_digest
:
170 data
= digest
.add_digests(data
, alg
= options
.add_digest
)
171 if options
.add_types
:
173 data
= mimetypes
.add_types(data
)
175 data
= edit
.edit(data
)
178 # Validate the result...
180 validator
.check(data
)
182 except validator
.InvalidInterface
, ex
:
183 print "Invalid interface: " + str(ex
)
186 ans
= raw_input("Interface is invalid. (E)dit or (A)bort?").lower()
187 if ans
in ('e', 'edit'):
188 data
= edit
.edit(data
)
190 if ans
in ('a', 'abort'): sys
.exit(1)
192 if (old_data
== data
and sign_fn
== old_sign_fn
and key
== old_key
) and not force_save
:
193 print "Interface unchanged. Not writing."
197 doc
= minidom
.parseString(data
)
198 data
= create
.xml_header
+ doc
.documentElement
.toxml('utf-8')
201 if not data
.endswith('\n'): data
+= '\n'
202 sign_fn(interface
, data
, key
)
204 info("Wrote '%s'", interface
)
206 if sign_fn
!= signing
.sign_unsigned
:
207 # Read it back in to find out what key we signed it with
208 # and ensure that the key has been exported
209 contents
= file(interface
).read()
210 saved_data
, saved_sign_fn
, saved_key
= signing
.check_signature(interface
)
211 assert saved_data
== data
212 assert saved_sign_fn
== sign_fn
213 signing
.export_key(os
.path
.dirname(interface
), saved_key
)
214 except KeyboardInterrupt, ex
:
215 print >>sys
.stderr
, "Aborted at user's request"
217 except SafeException
, ex
:
218 if options
.verbose
: raise
219 print >>sys
.stderr
, ex