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