File: templates.py

package info (click to toggle)
pastescript 1.7.5-4
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 976 kB
  • ctags: 931
  • sloc: python: 6,114; makefile: 59; sh: 8
file content (295 lines) | stat: -rw-r--r-- 10,884 bytes parent folder | download | duplicates (3)
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
import sys
import os
import inspect
import copydir
import command
import re

from paste.util.template import paste_script_template_renderer

class Template(object):

    # Subclasses must define:
    # _template_dir (or template_dir())
    # summary

    # Variables this template uses (mostly for documentation now)
    # a list of instances of var()
    vars = []

    # Eggs that should be added as plugins:
    egg_plugins = []

    # Templates that must be applied first:
    required_templates = []

    # Use Cheetah for substituting templates:
    use_cheetah = False
    # If true, then read all the templates to find the variables:
    read_vars_from_templates = False

    # You can also give this function/method to use something other
    # than Cheetah or string.Template.  The function should be of the
    # signature template_renderer(content, vars, filename=filename).
    # Careful you don't turn this into a method by putting a function
    # here (without staticmethod)!
    template_renderer = None

    def __init__(self, name):
        self.name = name
        self._read_vars = None
    
    def module_dir(self):
        """Returns the module directory of this template."""
        mod = sys.modules[self.__class__.__module__]
        return os.path.dirname(mod.__file__)

    def _distro_dir(self, args):
        """Returns full path to template directory if it's found in
        /usr/local/share/paster_templates/ or /usr/share/paster_templates/"""

        tpldir_pattern = re.compile('[^/]*templates/')

        for d in ('/usr/local/share/paster_templates/', '/usr/share/paster_templates/'):
            directory = os.path.join(d, *args)
            if os.path.isdir(directory):
                return directory
            # remove .*templates directory if it's in the args and try again
            args_joined = os.path.join(*args)
            directory = os.path.abspath(os.path.join(d, tpldir_pattern.sub('./', args_joined)))
            if os.path.isdir(directory):
                return directory

    def template_dir(self):
        assert self._template_dir is not None, (
            "Template %r didn't set _template_dir" % self)
        if isinstance( self._template_dir, tuple):
            return self._distro_dir(self._template_dir) or self._template_dir
        else:
            return self._distro_dir((self._template_dir,)) or os.path.join(self.module_dir(), self._template_dir)

    def run(self, command, output_dir, vars):
        self.pre(command, output_dir, vars)
        self.write_files(command, output_dir, vars)
        self.post(command, output_dir, vars)

    def check_vars(self, vars, cmd):
        expect_vars = self.read_vars(cmd)
        if not expect_vars:
            # Assume that variables aren't defined
            return vars
        converted_vars = {}
        unused_vars = vars.copy()
        errors = []
        for var in expect_vars:
            if var.name not in unused_vars:
                if cmd.interactive:
                    prompt = 'Enter %s' % var.full_description()
                    response = cmd.challenge(prompt, var.default, var.should_echo)
                    converted_vars[var.name] = response
                elif var.default is command.NoDefault:
                    errors.append('Required variable missing: %s'
                                  % var.full_description())
                else:
                    converted_vars[var.name] = var.default
            else:
                converted_vars[var.name] = unused_vars.pop(var.name)
        if errors:
            raise command.BadCommand(
                'Errors in variables:\n%s' % '\n'.join(errors))
        converted_vars.update(unused_vars)
        vars.update(converted_vars)
        return converted_vars
        
    def read_vars(self, command=None):
        if self._read_vars is not None:
            return self._read_vars
        assert (not self.read_vars_from_templates
                or self.use_cheetah), (
            "You can only read variables from templates if using Cheetah")
        if not self.read_vars_from_templates:
            self._read_vars = self.vars
            return self.vars
        
        vars = self.vars[:]
        var_names = [var.name for var in self.vars]
        read_vars = find_args_in_dir(
            self.template_dir(),
            verbose=command and command.verbose > 1).items()
        read_vars.sort()
        for var_name, var in read_vars:
            if var_name not in var_names:
                vars.append(var)
        self._read_vars = vars
        return vars

    def write_files(self, command, output_dir, vars):
        template_dir = self.template_dir()
        if not os.path.exists(output_dir):
            print "Creating directory %s" % output_dir
            if not command.simulate:
                # Don't let copydir create this top-level directory,
                # since copydir will svn add it sometimes:
                os.makedirs(output_dir)
        copydir.copy_dir(template_dir, output_dir,
                         vars,
                         verbosity=command.verbose,
                         simulate=command.options.simulate,
                         interactive=command.interactive,
                         overwrite=command.options.overwrite,
                         indent=1,
                         use_cheetah=self.use_cheetah,
                         template_renderer=self.template_renderer)

    def print_vars(self, indent=0):
        vars = self.read_vars()
        var.print_vars(vars)
        
    def pre(self, command, output_dir, vars):
        """
        Called before template is applied.
        """
        pass

    def post(self, command, output_dir, vars):
        """
        Called after template is applied.
        """
        pass

NoDefault = command.NoDefault

class var(object):

    def __init__(self, name, description,
                 default='', should_echo=True):
        self.name = name
        self.description = description
        self.default = default
        self.should_echo = should_echo

    def __repr__(self):
        return '<%s %s default=%r should_echo=%s>' % (
            self.__class__.__name__,
            self.name, self.default, self.should_echo)

    def full_description(self):
        if self.description:
            return '%s (%s)' % (self.name, self.description)
        else:
            return self.name

    def print_vars(cls, vars, indent=0):
        max_name = max([len(v.name) for v in vars])
        for var in vars:
            if var.description:
                print '%s%s%s  %s' % (
                    ' '*indent,
                    var.name,
                    ' '*(max_name-len(var.name)),
                    var.description)
            else:
                print '  %s' % var.name
            if var.default is not command.NoDefault:
                print '      default: %r' % var.default
            if var.should_echo is True:
                print '      should_echo: %s' % var.should_echo
        print

    print_vars = classmethod(print_vars)

class BasicPackage(Template):

    _template_dir = '/usr/share/paster_templates/basic_package'
    summary = "A basic setuptools-enabled package"
    vars = [
        var('version', 'Version (like 0.1)'),
        var('description', 'One-line description of the package'),
        var('long_description', 'Multi-line description (in reST)'),
        var('keywords', 'Space-separated keywords/tags'),
        var('author', 'Author name'),
        var('author_email', 'Author email'),
        var('url', 'URL of homepage'),
        var('license_name', 'License name'),
        var('zip_safe', 'True/False: if the package can be distributed as a .zip file', default=False),
        ]

    template_renderer = staticmethod(paste_script_template_renderer)
    
_skip_variables = ['VFN', 'currentTime', 'self', 'VFFSL', 'dummyTrans',
                   'getmtime', 'trans']

def find_args_in_template(template):
    if isinstance(template, (str, unicode)):
        # Treat as filename:
        import Cheetah.Template
        template = Cheetah.Template.Template(file=template)
    if not hasattr(template, 'body'):
        # Don't know...
        return None
    method = template.body
    args, varargs, varkw, defaults = inspect.getargspec(method)
    defaults=list(defaults or [])
    vars = []
    while args:
        if len(args) == len(defaults):
            default = defaults.pop(0)
        else:
            default = command.NoDefault
        arg = args.pop(0)
        if arg in _skip_variables:
            continue
        # @@: No way to get description yet
        vars.append(
            var(arg, description=None,
                default=default))
    return vars

def find_args_in_dir(dir, verbose=False):
    all_vars = {}
    for fn in os.listdir(dir):
        if fn.startswith('.') or fn == 'CVS' or fn == '_darcs':
            continue
        full = os.path.join(dir, fn)
        if os.path.isdir(full):
            inner_vars = find_args_in_dir(full)
        elif full.endswith('_tmpl'):
            inner_vars = {}
            found = find_args_in_template(full)
            if found is None:
                # Couldn't read variables
                if verbose:
                    print 'Template %s has no parseable variables' % full
                continue
            for var in found:
                inner_vars[var.name] = var
        else:
            # Not a template, don't read it
            continue
        if verbose:
            print 'Found variable(s) %s in Template %s' % (
                ', '.join(inner_vars.keys()), full)
        for var_name, var in inner_vars.items():
            # Easy case:
            if var_name not in all_vars:
                all_vars[var_name] = var
                continue
            # Emit warnings if the variables don't match well:
            cur_var = all_vars[var_name]
            if not cur_var.description:
                cur_var.description = var.description
            elif (cur_var.description and var.description
                  and var.description != cur_var.description):
                print >> sys.stderr, (
                    "Variable descriptions do not match: %s: %s and %s"
                    % (var_name, cur_var.description, var.description))
            if (cur_var.default is not command.NoDefault
                and var.default is not command.NoDefault
                and cur_var.default != var.default):
                print >> sys.stderr, (
                    "Variable defaults do not match: %s: %r and %r"
                    % (var_name, cur_var.default, var.default))
    return all_vars