root/galaxy-central/eggs/PasteScript-1.7.3-py2.6.egg/paste/script/filemaker.py

リビジョン 3, 13.4 KB (コミッタ: kohda, 14 年 前)

Install Unix tools  http://hannonlab.cshl.edu/galaxy_unix_tools/galaxy.html

行番号 
1# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
2# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
3import os
4import glob
5import pkg_resources
6from paste.script import pluginlib, copydir
7from paste.script.command import BadCommand
8difflib = None
9try:
10    import subprocess
11except ImportError:
12    from paste.script.util import subprocess24 as subprocess
13
14class FileOp(object):
15    """
16    Enhance the ease of file copying/processing from a package into a target
17    project
18    """
19   
20    def __init__(self, simulate=False,
21                       verbose=True,
22                       interactive=True,
23                       source_dir=None,
24                       template_vars=None):
25        """
26        Initialize our File operation helper object
27       
28        source_dir
29            Should refer to the directory within the package
30            that contains the templates to be used for the other copy
31            operations. It is assumed that packages will keep all their
32            templates under a hierarchy starting here.
33         
34            This should be an absolute path passed in, for example::
35         
36                FileOp(source_dir=os.path.dirname(__file__) + '/templates')
37        """
38        self.simulate = simulate
39        self.verbose = verbose
40        self.interactive = interactive
41        if template_vars is None:
42            template_vars = {}
43        self.template_vars = template_vars
44        self.source_dir = source_dir
45        self.use_pkg_resources = isinstance(source_dir, tuple)
46   
47    def copy_file(self, template, dest, filename=None, add_py=True, package=True,
48                  template_renderer=None):
49        """
50        Copy a file from the source location to somewhere in the
51        destination.
52       
53        template
54            The filename underneath self.source_dir to copy/process
55        dest
56            The destination directory in the project relative to where
57            this command is being run
58        filename
59            What to name the file in the target project, use the same name
60            as the template if not provided
61        add_py
62            Add a .py extension to all files copied
63        package
64            Whether or not this file is part of a Python package, and any
65            directories created should contain a __init__.py file as well.
66        template_renderer
67            An optional template renderer
68       
69        """
70        if not filename:
71            filename = template.split('/')[0]
72            if filename.endswith('_tmpl'):
73                filename = filename[:-5]
74        base_package, cdir = self.find_dir(dest, package)
75        self.template_vars['base_package'] = base_package
76        content = self.load_content(base_package, cdir, filename, template,
77                                    template_renderer=template_renderer)
78        if add_py:
79            # @@: Why is it a default to add a .py extension?
80            filename = '%s.py' % filename
81        dest = os.path.join(cdir, filename)
82        self.ensure_file(dest, content, package)
83   
84    def copy_dir(self, template_dir, dest, destname=None, package=True):
85        """
86        Copy a directory recursively, processing any files within it
87        that need to be processed (end in _tmpl).
88       
89        template_dir
90            Directory under self.source_dir to copy/process
91        dest
92            Destination directory into which this directory will be copied
93            to.
94        destname
95            Use this name instead of the original template_dir name for
96            creating the directory
97        package
98            This directory will be a Python package and needs to have a
99            __init__.py file.
100        """
101        # @@: This should actually be implemented
102        raise NotImplementedError
103
104    def load_content(self, base_package, base, name, template,
105                     template_renderer=None):
106        blank = os.path.join(base, name + '.py')
107        read_content = True
108        if not os.path.exists(blank):
109            if self.use_pkg_resources:
110                fullpath = '/'.join([self.source_dir[1], template])
111                content = pkg_resources.resource_string(
112                    self.source_dir[0], fullpath)
113                read_content = False
114                blank = fullpath
115            else:
116                blank = os.path.join(self.source_dir,
117                                     template)
118        if read_content:
119            f = open(blank, 'r')
120            content = f.read()
121            f.close()
122        if blank.endswith('_tmpl'):
123            content = copydir.substitute_content(
124                content, self.template_vars, filename=blank,
125                template_renderer=template_renderer)
126        return content
127
128    def find_dir(self, dirname, package=False):
129        egg_info = pluginlib.find_egg_info_dir(os.getcwd())
130        # @@: Should give error about egg_info when top_level.txt missing
131        f = open(os.path.join(egg_info, 'top_level.txt'))
132        packages = [l.strip() for l in f.readlines()
133                    if l.strip() and not l.strip().startswith('#')]
134        f.close()
135        if not len(packages):
136            raise BadCommand("No top level dir found for %s" % dirname)
137        # @@: This doesn't support deeper servlet directories,
138        # or packages not kept at the top level.
139        base = os.path.dirname(egg_info)
140        possible = []
141        for pkg in packages:
142            d = os.path.join(base, pkg, dirname)
143            if os.path.exists(d):
144                possible.append((pkg, d))
145        if not possible:
146            self.ensure_dir(os.path.join(base, packages[0], dirname),
147                            package=package)
148            return self.find_dir(dirname)
149        if len(possible) > 1:
150            raise BadCommand(
151                "Multiple %s dirs found (%s)" % (dirname, possible))
152        return possible[0]
153   
154    def parse_path_name_args(self, name):
155        """
156        Given the name, assume that the first argument is a path/filename
157        combination. Return the name and dir of this. If the name ends with
158        '.py' that will be erased.
159       
160        Examples:
161            comments             ->          comments, ''
162            admin/comments       ->          comments, 'admin'
163            h/ab/fred            ->          fred, 'h/ab'
164        """
165        if name.endswith('.py'):
166            # Erase extensions
167            name = name[:-3]
168        if '.' in name:
169            # Turn into directory name:
170            name = name.replace('.', os.path.sep)
171        if '/' != os.path.sep:
172            name = name.replace('/', os.path.sep)
173        parts = name.split(os.path.sep)
174        name = parts[-1]
175        if not parts[:-1]:
176            dir = ''
177        elif len(parts[:-1]) == 1:
178            dir = parts[0]
179        else:
180            dir = os.path.join(*parts[:-1])
181        return name, dir
182   
183    def ensure_dir(self, dir, svn_add=True, package=False):
184        """
185        Ensure that the directory exists, creating it if necessary.
186        Respects verbosity and simulation.
187
188        Adds directory to subversion if ``.svn/`` directory exists in
189        parent, and directory was created.
190       
191        package
192            If package is True, any directories created will contain a
193            __init__.py file.
194       
195        """
196        dir = dir.rstrip(os.sep)
197        if not dir:
198            # we either reached the parent-most directory, or we got
199            # a relative directory
200            # @@: Should we make sure we resolve relative directories
201            # first?  Though presumably the current directory always
202            # exists.
203            return
204        if not os.path.exists(dir):
205            self.ensure_dir(os.path.dirname(dir), svn_add=svn_add, package=package)
206            if self.verbose:
207                print 'Creating %s' % self.shorten(dir)
208            if not self.simulate:
209                os.mkdir(dir)
210            if (svn_add and
211                os.path.exists(os.path.join(os.path.dirname(dir), '.svn'))):
212                self.svn_command('add', dir)
213            if package:
214                initfile = os.path.join(dir, '__init__.py')
215                f = open(initfile, 'wb')
216                f.write("#\n")
217                f.close()
218                print 'Creating %s' % self.shorten(initfile)
219                if (svn_add and
220                    os.path.exists(os.path.join(os.path.dirname(dir), '.svn'))):
221                    self.svn_command('add', initfile)
222        else:
223            if self.verbose > 1:
224                print "Directory already exists: %s" % self.shorten(dir)
225
226    def ensure_file(self, filename, content, svn_add=True, package=False):
227        """
228        Ensure a file named ``filename`` exists with the given
229        content.  If ``--interactive`` has been enabled, this will ask
230        the user what to do if a file exists with different content.
231        """
232        global difflib
233        self.ensure_dir(os.path.dirname(filename), svn_add=svn_add, package=package)
234        if not os.path.exists(filename):
235            if self.verbose:
236                print 'Creating %s' % filename
237            if not self.simulate:
238                f = open(filename, 'wb')
239                f.write(content)
240                f.close()
241            if svn_add and os.path.exists(os.path.join(os.path.dirname(filename), '.svn')):
242                self.svn_command('add', filename)
243            return
244        f = open(filename, 'rb')
245        old_content = f.read()
246        f.close()
247        if content == old_content:
248            if self.verbose > 1:
249                print 'File %s matches expected content' % filename
250            return
251        if self.interactive:
252            print 'Warning: file %s does not match expected content' % filename
253            if difflib is None:
254                import difflib
255            diff = difflib.context_diff(
256                content.splitlines(),
257                old_content.splitlines(),
258                'expected ' + filename,
259                filename)
260            print '\n'.join(diff)
261            if self.interactive:
262                while 1:
263                    s = raw_input(
264                        'Overwrite file with new content? [y/N] ').strip().lower()
265                    if not s:
266                        s = 'n'
267                    if s.startswith('y'):
268                        break
269                    if s.startswith('n'):
270                        return
271                    print 'Unknown response; Y or N please'
272            else:
273                return
274                   
275        if self.verbose:
276            print 'Overwriting %s with new content' % filename
277        if not self.simulate:
278            f = open(filename, 'wb')
279            f.write(content)
280            f.close()
281
282    def shorten(self, fn, *paths):
283        """
284        Return a shorted form of the filename (relative to the current
285        directory), typically for displaying in messages.  If
286        ``*paths`` are present, then use os.path.join to create the
287        full filename before shortening.
288        """
289        if paths:
290            fn = os.path.join(fn, *paths)
291        if fn.startswith(os.getcwd()):
292            return fn[len(os.getcwd()):].lstrip(os.path.sep)
293        else:
294            return fn
295
296    _svn_failed = False
297
298    def svn_command(self, *args, **kw):
299        """
300        Run an svn command, but don't raise an exception if it fails.
301        """
302        try:
303            return self.run_command('svn', *args, **kw)
304        except OSError, e:
305            if not self._svn_failed:
306                print 'Unable to run svn command (%s); proceeding anyway' % e
307                self._svn_failed = True
308
309    def run_command(self, cmd, *args, **kw):
310        """
311        Runs the command, respecting verbosity and simulation.
312        Returns stdout, or None if simulating.
313        """
314        cwd = popdefault(kw, 'cwd', os.getcwd())
315        capture_stderr = popdefault(kw, 'capture_stderr', False)
316        expect_returncode = popdefault(kw, 'expect_returncode', False)
317        assert not kw, ("Arguments not expected: %s" % kw)
318        if capture_stderr:
319            stderr_pipe = subprocess.STDOUT
320        else:
321            stderr_pipe = subprocess.PIPE
322        try:
323            proc = subprocess.Popen([cmd] + list(args),
324                                    cwd=cwd,
325                                    stderr=stderr_pipe,
326                                    stdout=subprocess.PIPE)
327        except OSError, e:
328            if e.errno != 2:
329                # File not found
330                raise
331            raise OSError(
332                "The expected executable %s was not found (%s)"
333                % (cmd, e))
334        if self.verbose:
335            print 'Running %s %s' % (cmd, ' '.join(args))
336        if self.simulate:
337            return None
338        stdout, stderr = proc.communicate()
339        if proc.returncode and not expect_returncode:
340            if not self.verbose:
341                print 'Running %s %s' % (cmd, ' '.join(args))
342            print 'Error (exit code: %s)' % proc.returncode
343            if stderr:
344                print stderr
345            raise OSError("Error executing command %s" % cmd)
346        if self.verbose > 2:
347            if stderr:
348                print 'Command error output:'
349                print stderr
350            if stdout:
351                print 'Command output:'
352                print stdout
353        return stdout
354
355def popdefault(dict, name, default=None):
356    if name not in dict:
357        return default
358    else:
359        v = dict[name]
360        del dict[name]
361        return v
362
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。