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("--add-types", help="add missing MIME-type attributes", action
='store_true')
14 parser
.add_option("--add-version", help="add a new implementation", action
='store', metavar
='VERSION')
15 parser
.add_option("--archive-url", help="add archive at this URL", action
='store', metavar
='URL')
16 parser
.add_option("--archive-file", help="local copy of archive-url", action
='store', metavar
='FILE')
17 parser
.add_option("--archive-extract", help="subdirectory of archive to extract", action
='store', metavar
='DIR')
18 parser
.add_option("-c", "--create", help="create file if nonexistant", action
='store_true')
19 parser
.add_option("-d", "--add-digest", help="add extra digests", action
='store', metavar
='ALG')
20 parser
.add_option("-e", "--edit", help="edit with $EDITOR", action
='store_true')
21 parser
.add_option("-g", "--gpgsign", help="add a GPG signature block", action
='store_true')
22 parser
.add_option("-k", "--key", help="key to use for signing")
23 parser
.add_option("-l", "--local", help="create feed from local interface")
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
)
79 if os
.path
.exists(options
.local
):
80 data
= create
.create_from_local(options
.local
)
81 sign_fn
= signing
.sign_unsigned
86 raise Exception("File '%s' does not exist." % options
.local
)
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 sign_fn
= signing
.sign_plain
131 print "Changing key from '%s' to '%s'" % (key
, options
.key
)
133 if options
.set_interface_uri
:
135 data
= release
.set_interface_uri(data
, options
.set_interface_uri
)
136 if options
.add_version
:
138 data
= release
.add_version(data
, options
.add_version
)
139 if options
.set_id
or options
.set_version
or options
.set_released
or \
140 options
.set_stability
or options
.set_arch
or options
.set_main
:
142 data
= release
.set_attributes(data
, options
.select_version
,
144 version
= options
.set_version
,
145 released
= options
.set_released
,
146 stability
= options
.set_stability
,
147 main
= options
.set_main
,
148 arch
= options
.set_arch
)
150 assert not options
.select_version
, "Use --set-stability=stable --select-version=... instead"
152 data
= stable
.mark_stable(data
)
153 if options
.archive_url
:
155 algs
= options
.manifest_algorithm
159 if hasattr(hashlib
, 'sha256'):
160 algs
.append('sha256')
161 data
= archive
.add_archive(data
, options
.archive_url
, options
.archive_file
, options
.archive_extract
, algs
)
162 elif options
.archive_file
or options
.archive_extract
:
163 raise Exception('Must use --archive-uri option')
166 data
= merge
.merge(data
, options
.local
)
167 if options
.add_digest
:
169 data
= digest
.add_digests(data
, alg
= options
.add_digest
)
170 if options
.add_types
:
172 data
= mimetypes
.add_types(data
)
174 data
= edit
.edit(data
)
177 # Validate the result...
179 validator
.check(data
)
181 except validator
.InvalidInterface
, ex
:
182 print "Invalid interface: " + str(ex
)
185 ans
= raw_input("Interface is invalid. (E)dit or (A)bort?").lower()
186 if ans
in ('e', 'edit'):
187 data
= edit
.edit(data
)
189 if ans
in ('a', 'abort'): sys
.exit(1)
191 if (old_data
== data
and sign_fn
== old_sign_fn
and key
== old_key
) and not force_save
:
192 print "Interface unchanged. Not writing."
196 doc
= minidom
.parseString(data
)
197 data
= create
.xml_header
+ doc
.documentElement
.toxml('utf-8')
200 if not data
.endswith('\n'): data
+= '\n'
201 sign_fn(interface
, data
, key
)
203 info("Wrote '%s'", interface
)
205 if sign_fn
!= signing
.sign_unsigned
:
206 # Read it back in to find out what key we signed it with
207 # and ensure that the key has been exported
208 contents
= file(interface
).read()
209 saved_data
, saved_sign_fn
, saved_key
= signing
.check_signature(interface
)
210 assert saved_data
== data
211 assert saved_sign_fn
== sign_fn
212 signing
.export_key(os
.path
.dirname(interface
), saved_key
)
213 except KeyboardInterrupt, ex
:
214 print >>sys
.stderr
, "Aborted at user's request"
216 except SafeException
, ex
:
217 if options
.verbose
: raise
218 print >>sys
.stderr
, ex