Added --unsign option to remove signatures.
[0publish.git] / 0publish
blob2f74e9d28c001b4e93b02a7cea8884426bb8d9b1
1 #!/usr/bin/env python
2 from zeroinstall.injector import gpg
3 from optparse import OptionParser
4 import os, sys
5 import signing
6 from logging import info, debug
7 import edit, validator
9 version = '0.3'
11 parser = OptionParser(usage="usage: %prog [options] interface")
12 parser.add_option("--add-version", help="add a new implementation", action='store', metavar='VERSION')
13 parser.add_option("--archive-url", help="add archive at this URL", action='store', metavar='URL')
14 parser.add_option("--archive-file", help="local copy of archive-url", action='store', metavar='FILE')
15 parser.add_option("--archive-extract", help="subdirectory of archive to extract", action='store', metavar='DIR')
16 parser.add_option("-e", "--edit", help="edit with $EDITOR", action='store_true')
17 parser.add_option("-g", "--gpgsign", help="add a GPG signature block", action='store_true')
18 parser.add_option("-k", "--key", help="key to use for signing")
19 parser.add_option("-l", "--local", help="create feed from local interface")
20 parser.add_option("--manifest-algorithm", help="select algorithm for manifests", action='store', metavar='ALG')
21 parser.add_option("--set-id", help="set implementation ID", action='store', metavar='DIGEST')
22 parser.add_option("--set-main", help="set main executable", action='store', metavar='EXEC')
23 parser.add_option("--set-arch", help="set architecture", action='store', metavar='ARCH')
24 parser.add_option("--set-released", help="set release date", action='store', metavar='DATE')
25 parser.add_option("--set-stability", help="set stability", action='store', metavar='STABILITY')
26 parser.add_option("--set-version", help="set version number", action='store', metavar='VERSION')
27 parser.add_option("-s", "--stable", help="mark testing version stable", action='store_true')
28 parser.add_option("-x", "--xmlsign", help="add an XML signature block", action='store_true')
29 parser.add_option("-u", "--unsign", help="remove any signature", action='store_true')
30 parser.add_option("-v", "--verbose", help="more verbose output", action='count')
31 parser.add_option("-V", "--version", help="display version information", action='store_true')
33 (options, args) = parser.parse_args()
35 force_save = False
37 if options.version:
38 print "0publish (zero-install) " + version
39 print "Copyright (C) 2005 Thomas Leonard"
40 print "This program comes with ABSOLUTELY NO WARRANTY,"
41 print "to the extent permitted by law."
42 print "You may redistribute copies of this program"
43 print "under the terms of the GNU General Public License."
44 print "For more information about these matters, see the file named COPYING."
45 sys.exit(0)
47 if options.verbose:
48 import logging
49 logger = logging.getLogger()
50 if options.verbose == 1:
51 logger.setLevel(logging.INFO)
52 else:
53 logger.setLevel(logging.DEBUG)
55 if len(args) != 1:
56 parser.print_help()
57 sys.exit(1)
58 interface = args[0]
60 def confirm(q):
61 while True:
62 ans = raw_input(q + " [Y/N] ").lower()
63 if ans in ('y', 'yes'): return True
64 if ans in ('n', 'no'): return False
66 # Load or create the starting data...
68 if os.path.exists(interface):
69 contents = file(interface).read()
70 data, sign_fn, key = signing.check_signature(interface)
71 elif options.local:
72 import create
73 if os.path.exists(options.local):
74 data = create.create_from_local(options.local)
75 sign_fn = signing.sign_unsigned
76 key = None
77 force_save = True
78 options.local = False
79 else:
80 raise Exception("File '%s' does not exist." % options.local)
81 else:
82 if confirm("Interface file '%s' does not exist. Create it?" % interface):
83 from create import create
84 data = create(interface)
85 sign_fn = signing.sign_unsigned
86 key = None
87 options.edit = True
88 else:
89 sys.exit(1)
91 debug("Original data: %s", data)
92 info("Original signing method: %s", sign_fn.__name__)
93 info("Original key: %s", key)
95 old_data = data
96 old_sign_fn = sign_fn
97 old_key = key
99 while True:
100 # Validate the input...
101 try:
102 validator.check(data)
103 break
104 except validator.InvalidInterface, ex:
105 print "Invalid interface: " + str(ex)
107 while True:
108 ans = raw_input("Interface is invalid. (E)dit or (A)bort?").lower()
109 if ans in ('e', 'edit'):
110 data = edit.edit(data)
111 options.edit = False # Don't edit twice
112 break
113 if ans in ('a', 'abort'): sys.exit(1)
115 # Process it...
116 if options.xmlsign:
117 sign_fn = signing.sign_xml
118 if options.unsign:
119 sign_fn = signing.sign_unsigned
120 if options.gpgsign:
121 sign_fn = signing.sign_plain
122 if options.key:
123 print "Changing key from '%s' to '%s'" % (key, options.key)
124 key = options.key
125 if options.add_version:
126 import release
127 data = release.add_version(data, options.add_version)
128 if options.set_id or options.set_version or options.set_released or \
129 options.set_stability or options.set_arch or options.set_main:
130 import release
131 data = release.make_release(data, options.set_id,
132 options.set_version, options.set_released, options.set_stability,
133 options.set_main, options.set_arch)
134 if options.stable:
135 import stable
136 data = stable.mark_stable(data)
137 if options.archive_url:
138 import archive
139 data = archive.add_archive(data, options.archive_url, options.archive_file, options.archive_extract, options.manifest_algorithm)
140 elif options.archive_file or options.archive_extract:
141 raise Exception('Must use --archive-uri option')
142 if options.local:
143 import merge
144 data = merge.merge(data, options.local)
145 if options.edit:
146 data = edit.edit(data)
148 while True:
149 # Validate the result...
150 try:
151 validator.check(data)
152 break
153 except validator.InvalidInterface, ex:
154 print "Invalid interface: " + str(ex)
156 while True:
157 ans = raw_input("Interface is invalid. (E)dit or (A)bort?").lower()
158 if ans in ('e', 'edit'):
159 data = edit.edit(data)
160 break
161 if ans in ('a', 'abort'): sys.exit(1)
164 if (old_data == data and sign_fn == old_sign_fn and key == old_key) and not force_save:
165 print "Interface unchanged. Not writing."
166 sys.exit(1)
168 # Write it back out
169 if not data.endswith('\n'): data += '\n'
170 sign_fn(interface, data, key)
172 info("Wrote '%S'", interface)