Correctly detect old-style GPG-signed interfaces.
[0publish.git] / 0publish
bloba85d2fe1ddb0797aef08c5b242af952aa3a37dc0
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.1'
11 parser = OptionParser(usage="usage: %prog [options] interface")
12 parser.add_option("--archive-url", help="add archive at this URL", action='store', metavar='URL')
13 parser.add_option("--archive-file", help="local copy of archive-url", action='store', metavar='FILE')
14 parser.add_option("--archive-extract", help="subdirectory of archive to extract", action='store', metavar='DIR')
15 parser.add_option("-k", "--key", help="key to use for signing")
16 parser.add_option("-e", "--edit", help="edit with $EDITOR", action='store_true')
17 parser.add_option("-l", "--local", help="create feed from local interface")
18 parser.add_option("--set-id", help="set implementation ID", action='store', metavar='DIGEST')
19 parser.add_option("--set-released", help="set release date", action='store', metavar='DATE')
20 parser.add_option("--set-stability", help="set stability", action='store', metavar='STABILITY')
21 parser.add_option("--set-version", help="set version number", action='store', metavar='VERSION')
22 parser.add_option("-x", "--xmlsign", help="add an XML signature block", action='store_true')
23 parser.add_option("-v", "--verbose", help="more verbose output", action='count')
24 parser.add_option("-V", "--version", help="display version information", action='store_true')
26 (options, args) = parser.parse_args()
28 force_save = False
30 if options.version:
31 print "0publish (zero-install) " + version
32 print "Copyright (C) 2005 Thomas Leonard"
33 print "This program comes with ABSOLUTELY NO WARRANTY,"
34 print "to the extent permitted by law."
35 print "You may redistribute copies of this program"
36 print "under the terms of the GNU General Public License."
37 print "For more information about these matters, see the file named COPYING."
38 sys.exit(0)
40 if options.verbose:
41 import logging
42 logger = logging.getLogger()
43 if options.verbose == 1:
44 logger.setLevel(logging.INFO)
45 else:
46 logger.setLevel(logging.DEBUG)
48 if len(args) != 1:
49 parser.print_help()
50 sys.exit(1)
51 interface = args[0]
53 def confirm(q):
54 while True:
55 ans = raw_input(q + " [Y/N] ").lower()
56 if ans in ('y', 'yes'): return True
57 if ans in ('n', 'no'): return False
59 # Load or create the starting data...
61 if os.path.exists(interface):
62 contents = file(interface).read()
63 data, sign_fn, key = signing.check_signature(interface)
64 elif options.local:
65 import create
66 if os.path.exists(options.local):
67 data = create.create_from_local(options.local)
68 sign_fn = signing.sign_unsigned
69 key = None
70 force_save = True
71 else:
72 raise Exception("File '%s' does not exist." % options.local)
73 else:
74 if confirm("Interface file '%s' does not exist. Create it?" % interface):
75 from create import create
76 data = create(interface)
77 sign_fn = signing.sign_unsigned
78 key = None
79 options.edit = True
80 else:
81 sys.exit(1)
83 debug("Original data: %s", data)
84 info("Original signing method: %s", sign_fn.__name__)
85 info("Original key: %s", key)
87 old_data = data
88 old_sign_fn = sign_fn
89 old_key = key
91 while True:
92 # Validate the input...
93 try:
94 validator.check(data)
95 break
96 except validator.InvalidInterface, ex:
97 print "Invalid interface: " + str(ex)
99 while True:
100 ans = raw_input("Interface is invalid. (E)dit or (A)bort?").lower()
101 if ans in ('e', 'edit'):
102 data = edit.edit(data)
103 options.edit = False # Don't edit twice
104 break
105 if ans in ('a', 'abort'): sys.exit(1)
107 # Process it...
108 if options.xmlsign:
109 sign_fn = signing.sign_xml
110 if options.key:
111 print "Changing key from '%s' to '%s'" % (key, options.key)
112 key = options.key
113 if options.set_id or options.set_version or options.set_released or options.set_stability:
114 import release
115 data = release.make_release(data, options.set_id,
116 options.set_version, options.set_released, options.set_stability)
117 if options.archive_url:
118 import archive
119 data = archive.add_archive(data, options.archive_url, options.archive_file, options.archive_extract)
120 elif options.archive_file or options.archive_extract:
121 raise Exception('Must use --archive-uri option')
122 if options.local:
123 import merge
124 data = merge.merge(data, options.local)
125 if options.edit:
126 data = edit.edit(data)
128 while True:
129 # Validate the result...
130 try:
131 validator.check(data)
132 break
133 except validator.InvalidInterface, ex:
134 print "Invalid interface: " + str(ex)
136 while True:
137 ans = raw_input("Interface is invalid. (E)dit or (A)bort?").lower()
138 if ans in ('e', 'edit'):
139 data = edit.edit(data)
140 break
141 if ans in ('a', 'abort'): sys.exit(1)
144 if (old_data == data and sign_fn == old_sign_fn and key == old_key) and not force_save:
145 print "Interface unchanged. Not writing."
146 sys.exit(1)
148 # Write it back out
149 if not data.endswith('\n'): data += '\n'
150 sign_fn(interface, data, key)
152 info("Wrote '%S'", interface)