1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
import sys
import os
import re
import pkg_resources
from string import Template
from pecan.compat import native_, bytes_
DEFAULT_SCAFFOLD = 'base'
_bad_chars_re = re.compile('[^a-zA-Z0-9_]')
class PecanScaffold(object):
"""
A base Pecan scaffold. New scaffolded implementations should extend this
class and define a ``_scaffold_dir`` attribute, e.g.,
class CoolAddOnScaffold(PecanScaffold):
_scaffold_dir = ('package', os.path.join('scaffolds', 'scaffold_name'))
...where...
pkg_resources.resource_listdir(_scaffold_dir[0], _scaffold_dir[1]))
...points to some scaffold directory root.
"""
def normalize_output_dir(self, dest):
return os.path.abspath(os.path.normpath(dest))
def normalize_pkg_name(self, dest):
return _bad_chars_re.sub('', dest.lower())
def copy_to(self, dest):
output_dir = self.normalize_output_dir(dest)
pkg_name = self.normalize_pkg_name(dest)
copy_dir(self._scaffold_dir, output_dir, {'package': pkg_name})
class BaseScaffold(PecanScaffold):
_scaffold_dir = ('pecan', os.path.join('scaffolds', 'base'))
def copy_dir(source, dest, variables, out_=sys.stdout, i=0):
"""
Copies the ``source`` directory to the ``dest`` directory, where
``source`` is some tuple representing an installed package and a
subdirectory in the package, e.g.,
('pecan', os.path.join('scaffolds', 'base'))
('pecan_extension', os.path.join('scaffolds', 'scaffold_name'))
``variables``: A dictionary of variables to use in any substitutions.
Substitution is performed via ``string.Template``.
``out_``: File object to write to (default is sys.stdout).
"""
def out(msg):
out_.write('%s%s' % (' ' * (i * 2), msg))
out_.write('\n')
out_.flush()
names = sorted(pkg_resources.resource_listdir(source[0], source[1]))
if not os.path.exists(dest):
out('Creating %s' % dest)
makedirs(dest)
else:
out('%s already exists' % dest)
return
for name in names:
full = '/'.join([source[1], name])
dest_full = os.path.join(dest, substitute_filename(name, variables))
sub_file = False
if dest_full.endswith('_tmpl'):
dest_full = dest_full[:-5]
sub_file = True
if pkg_resources.resource_isdir(source[0], full):
out('Recursing into %s' % os.path.basename(full))
copy_dir((source[0], full), dest_full, variables, out_, i + 1)
continue
else:
content = pkg_resources.resource_string(source[0], full)
if sub_file:
content = render_template(content, variables)
if content is None:
continue # pragma: no cover
out('Copying %s to %s' % (full, dest_full))
f = open(dest_full, 'wb')
f.write(content)
f.close()
def makedirs(directory):
""" Resursively create a named directory. """
parent = os.path.dirname(os.path.abspath(directory))
if not os.path.exists(parent):
makedirs(parent)
os.mkdir(directory)
def substitute_filename(fn, variables):
""" Substitute +variables+ in file directory names. """
for var, value in variables.items():
fn = fn.replace('+%s+' % var, str(value))
return fn
def render_template(content, variables):
"""
Return a bytestring representing a templated file based on the
input (content) and the variable names defined (vars).
"""
fsenc = sys.getfilesystemencoding()
content = native_(content, fsenc)
return bytes_(Template(content).substitute(variables), fsenc)
|