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