1 """Command for converting Kid to Genshi templates.
2
3 Currently only converts the Kid namespace and simple py:extend directives.
4
5 """
6
7 import optparse
8 import os
9 import re
10
11 from turbogears.util import get_package_name
12
13
15 """Convert Kid to Genshi templates."""
16
17 desc = "Convert all Kid templates in the project to Genshi"
18
19 engines = ('Kid', 'Genshi')
20 extensions = ('.kid', '.html')
21 xmlns = ('http://purl.org/kid/ns#', 'http://genshi.edgewall.org/')
22
23 need_project = True
24
26 parser = optparse.OptionParser(
27 usage="%prog kid2genshi [options]",
28 version="%prog " + version)
29 parser.add_option("-f", "--force",
30 help="overwrite existing templates",
31 action='store_true', dest="force")
32 parser.add_option("-k", "--keep",
33 help="keep the original templates",
34 action='store_true', dest="keep")
35 parser.add_option("-r", "--reverse",
36 help="convert Genshi to Kid",
37 action='store_true', dest="reverse")
38 self.parser = parser
39
41 extensions = self.extensions
42 from_index, to_index = self.from_index, self.to_index
43 if not force and os.path.exists(filename + extensions[to_index]):
44 return
45 f = open(filename + extensions[from_index], 'rb')
46 try:
47 try:
48 old = f.read()
49 finally:
50 f.close()
51 except IOError:
52 print "Could not open", filename
53 return False
54 new = old
55 for n, r in enumerate(self.re_convert):
56 new = r[0].sub(r[1], new, 1)
57 if not n and new == old:
58 return
59 print "Converting", filename, "..."
60 f = open(filename + extensions[to_index], 'wb')
61 try:
62 f.write(new)
63 finally:
64 f.close()
65 if not keep:
66 os.unlink(filename + extensions[from_index])
67 if self.engines[from_index] == 'Kid':
68 try:
69 os.unlink(filename + '.pyc')
70 except OSError:
71 pass
72 try:
73 os.unlink(filename + '.pyo')
74 except OSError:
75 pass
76 return True
77
79 f = open(filename, 'rb')
80 try:
81 try:
82 old = f.read()
83 finally:
84 f.close()
85 except IOError:
86 print "Could not open", filename
87 return False
88 new_defaultview = r'\1%s\2' % self.engines[self.to_index].lower()
89 new = self.re_defaultview.sub(new_defaultview, old, 1)
90 if new == old:
91 return
92 print "Changing", filename, "..."
93 f = open(filename, 'wb')
94 try:
95 f.write(new)
96 finally:
97 f.close()
98 return True
99
101 options, args = self.parser.parse_args()
102 force, keep, reverse = options.force, options.keep, options.reverse
103 from_index, to_index = 0, 1
104 if reverse:
105 from_index, to_index = to_index, from_index
106 self.from_index, self.to_index = from_index, to_index
107 engines, extensions, xmlns = self.engines, self.extensions, self.xmlns
108 package_name = get_package_name()
109 convert = [(r'<([a-z]+)\b([^<]*\bxmlns:py\s*=\s*[\'"])'
110 r'%s([\'"][^<]*>.*</\1)>' % xmlns[from_index],
111 r"<\1\2%s\3>" % self.xmlns[to_index])]
112 if reverse:
113 convert.append((r'<([a-z]+)\b([^<]*)\b'
114 r'xmlns:xi(\s*=\s*")http://www.w3.org/2001/XInclude'
115 r'("[^<]*>)\s*<xi:include\s+href=[\'"]'
116 r'([^\'"]*)\.html[\'"]/>(.*</\1)>',
117 r"<\1\2py:extends\3'\5.kid'\4\6>"))
118 else:
119 convert.append((r'<([a-z]+)\b([^<]*)\b'
120 r'py:extends(\s*=\s*")\'([^\'"]*)\.kid\'("[^<]*>)(.*</\1)>',
121 r'<\1\2xmlns:xi\3http://www.w3.org/2001/XInclude\5'
122 r'<xi:include href="\4.html"/>\6>'))
123
124 self.re_convert = [(re.compile(r[0], re.S), r[1]) for r in convert]
125 self.re_defaultview = re.compile(
126 r'^(\s*tg.defaultview\s*=\s*[\'"])(?:%s)([\'"]\s*(?:#.*)?)$'
127 % engines[from_index].lower(), re.M)
128 print "Converting all %s to %s templates in package %s" % (
129 engines[from_index], engines[to_index], package_name)
130 print "(the %s templates will be %s) ..." % (engines[from_index],
131 keep and 'kept' or 'removed')
132 n = 0
133 for dirpath, dirnames, filenames in os.walk(package_name):
134 i = 0
135 while i < len(dirnames):
136 dirname = dirnames[i]
137 if dirname.startswith('.') or dirname.endswith('~'):
138 del dirnames[i]
139 else:
140 i += 1
141 for filename in filenames:
142 if filename.endswith('~'):
143 continue
144 name, ext = os.path.splitext(filename)
145 if ext == extensions[from_index]:
146 filename = os.path.join(dirpath, name)
147 if self.convert_template(filename, force, keep):
148 n += 1
149 if n:
150 if n > 1:
151 print "%d %s templates have been converted to %s." % (
152 n, engines[from_index], engines[to_index])
153 print "Changing the configuration of package %s ..." % package_name
154 if not self.change_config(
155 os.path.join(package_name, 'config', 'app.cfg')):
156 print "Application config with defaultview setting not found."
157 elif force:
158 print "No %s templates were found in the current project." % (
159 engines[from_index])
160 else:
161 print "No %s templates needed to be converted in this project." % (
162 engines[from_index])
163