1 import os
2 import sys
3 import shutil
4 import time
5 from glob import glob
6 from setuptools import Command
7 import pkg_resources
8 pkg_resources.require("Kid >= 0.6.4")
9 import kid
10 import re
11 from distutils import log
12
14 "setuptools command to generate the TurboGears website"
15
16 user_options = [
17 ("srcdirs=", "s", "directories containing the source files (default: docs)"),
18 ("destdir=", "d", "destination output directory (default: dist/site)"),
19 ("encoding=", "e", "encoding for output (default: utf8)"),
20 ("force", "f", "regenerate all files"),
21 ("ignoredirs=", "i", "directories to ignore (default: ['.svn', '.cvs'])"),
22 ("ignorefiles=", "x", "files to ignore (default: ['.*\\.pyc', '.DS_Store'])"),
23 ("nodelete=", "l", "directories to leave alone rather than delete"),
24 ("templates=", "t", "mapping of templates to load (format: name=templatefile,name=templatefile)"),
25 ("copydirs=", "c", "copy files from these directories without template proc. (destdir=srcdir,...)"),
26 ("noprintable", "N", "don't make printable version of tutorials"),
27 ("eggdir=", "g", "which directory has the eggs in it (default: '../thirdparty/eggs')")
28 ]
29
30 boolean_options=["force"]
31
32 srcdirs = None
33 destdir = "dist/site"
34 encoding = "utf8"
35 force = False
36 ignoredirs = None
37 ignorefiles = None
38 nodelete = None
39 templates = None
40 copydirs = None
41 eggdir = "../thirdparty/eggs"
42 noprintable = False
43
46
48 if self.srcdirs is None:
49 self.srcdirs = ["docs"]
50 if self.srcdirs == "":
51 self.srcdirs = []
52 self.ensure_string_list("srcdirs")
53 self.ensure_string("destdir", "dist/site")
54 self.ensure_string("encoding", "utf8")
55 if self.ignoredirs is None:
56 self.ignoredirs = [".svn", ".cvs"]
57 self.ensure_string_list("ignoredirs")
58 if self.ignorefiles is None:
59 self.ignorefiles = ['.*\\.pyc', '.DS_Store']
60 if self.nodelete is None:
61 self.nodelete = ["dist/site/preview"]
62 self.ensure_string_list("nodelete")
63 self.ensure_string_list("ignorefiles")
64
65 regexes = []
66 for pat in self.ignorefiles:
67 regexes.append(re.compile(pat))
68 self.ignorepatterns = regexes
69
70 self.templates, self.templates_order = self._split_mapping(self.templates, True)
71 self.copydirs = self._split_mapping(self.copydirs)
72
74 mapping = {}
75 order = []
76 if valToSplit and isinstance(valToSplit, basestring):
77 pairs = re.split(",\s*", valToSplit)
78 for pair in pairs:
79 name, filename = re.split("\s*=\s*", pair)
80 mapping[name] = os.path.abspath(filename)
81 order.append(name)
82 if preserve_order:
83 return mapping, order
84 return mapping
85
87 srcmtime = os.path.getmtime(src)
88 if os.path.exists(dest):
89 destmtime = os.path.getmtime(dest)
90 else:
91 destmtime = 0
92 return srcmtime > destmtime
93
100
102 if not self.force and not self.check_if_newer(src, dest):
103 return
104 if not self.dry_run:
105 log.info("rendering %s" % dest)
106 else:
107 log.info("skipping rendering %s" % dest)
108 return
109
110 template = kid.load_template(src, cache=False)
111 template.Template.serializer = self.serializer
112 toroot = "../" * depth
113 destfile = dest[len(self.destdir)+1:]
114 updated = time.strftime("%b %d, %Y", time.localtime(os.path.getmtime(src)))
115 output = template.serialize(encoding=self.encoding, root=toroot, updated=updated,
116 destfile=destfile, eggs=self.eggs)
117 output = output.replace("$$", "$")
118 destfile = open(dest, "w")
119 destfile.write(output)
120 destfile.close()
121
123 if not destroot:
124 destroot = self.destdir
125 for root, dirs, files in os.walk(srcdir):
126 if root != srcdir:
127 fromroot = root[len(srcdir)+1:]
128 segments = fromroot.split(os.sep)
129 if set(segments).intersection(self.ignoredirs):
130 continue
131 depth = len(segments)
132 else:
133 fromroot = ""
134 depth = 0
135 destdir = os.path.join(destroot, fromroot)
136 if not os.path.exists(destdir):
137 if not self.dry_run:
138 log.info("creating directory %s" % (destdir))
139 os.makedirs(destdir)
140 else:
141 log.info("skipping creating directory %s" % (destdir))
142
143 for file in files:
144 ignore = False
145 abs = os.path.abspath(file)
146 for pat in self.ignorepatterns:
147 if pat.match(file):
148 ignore = True
149 break
150 if ignore:
151 continue
152
153 for tempfile in self.templates.values():
154 if tempfile == abs:
155 ignore = True
156 break
157 if ignore:
158 continue
159
160 ext = os.path.splitext(file)[1]
161 dest = os.path.join(destdir, file)
162 self.currentfiles.add(dest)
163 if not processTemplates or ext != ".html":
164 self.copy_if_newer(os.path.join(root, file),
165 dest)
166 else:
167 self.render_template(os.path.join(root, file),
168 dest, depth)
169
171 for root, dirs, files in os.walk(self.destdir):
172 leavealone = False
173 for dirname in self.nodelete:
174 if root.startswith(dirname):
175 leavealone = True
176 break
177 if leavealone:
178 continue
179 for file in files:
180 dest = os.path.join(root, file)
181 if dest not in self.currentfiles:
182 if not self.dry_run:
183 log.info("deleting %s" % dest)
184 os.unlink(dest)
185 else:
186 log.info("skipping deleting %s" % dest)
187