source: tailor/vcpx/repository.py @ 792

Revision 792, 11.1 KB checked in by lele@…, 8 years ago (diff)

Under win32 try also .bat and .exe for external tools

Line 
1# -*- mode: python; coding: utf-8 -*-
2# :Progetto: vcpx -- Configuration details about known repository kinds
3# :Creato:   gio 04 ago 2005 13:32:55 CEST
4# :Autore:   Lele Gaifax <lele@nautilus.homeip.net>
5# :Licenza:  GNU General Public License
6#
7
8"""
9This module holds a simple abstraction of what a repository is for
10Tailor purposes.
11"""
12
13__docformat__ = 'reStructuredText'
14
15REPO_DESCRIPTION = """\
16 Repository: %s
17       Kind: %s"""
18
19class Repository(object):
20    """
21    Collector for the configuration of a single repository.
22    """
23    METADIR = None
24    EXTRA_METADIRS = []
25    EXECUTABLE = None
26
27    def __new__(klass, name, project, which):
28        """
29        Return the right subclass for kind, if it exists.
30        """
31
32        kind = name[:name.index(':')]
33        subclass = klass
34        subclassname = kind.capitalize() + 'Repository'
35        if subclassname in globals():
36            subclass = globals()[subclassname]
37        instance = super(Repository, klass).__new__(subclass, name,
38                                                    project, which)
39        instance.kind = kind
40        return instance
41
42    def __init__(self, name, project, which):
43        """
44        Initialize a new instance of Repository, with a `name` and
45        associated to given `project`; `which` is either "source"
46        or "target".
47        """
48
49        self.name = name
50        self.project = project
51        self.which = which
52        self._load(project.config)
53        self._validateConfiguration()
54
55    def __str__(self):
56
57        s = REPO_DESCRIPTION % (self.repository, self.kind)
58        if self.module:
59            s += "\n     Module: %s" % self.module
60        return s
61
62    def _load(self, config):
63        """
64        Load the configuration for this repository.
65
66        The two main and mandatory attributes, ``repository`` and ``module``
67        can be specified either on the specific slot in the config file, or
68        as ``source-repository`` (or ``target-repository``) in its [DEFAULT]
69        section.
70
71        If the configuration does not specify a specific ``root-directory``
72        take the one from the project.
73        """
74
75        from os.path import split, expanduser
76        from sys import getdefaultencoding
77
78        self.repository = config.get(self.name, 'repository') or \
79                          config.get(self.name, '%s-repository' % self.which)
80        if self.repository:
81            self.repository = expanduser(self.repository)
82        self.module = config.get(self.name, 'module') or \
83                      config.get(self.name, '%s-module' % self.which)
84        self.rootdir = config.get(self.name, 'root-directory',
85                                  vars={'root-directory': self.project.rootdir})
86        self.subdir = config.get(self.name, 'subdir',
87                                 vars={'subdir': self.project.subdir})
88        self.encoding = config.get(self.name, 'encoding')
89        if self.encoding is None:
90            self.encoding = getdefaultencoding()
91
92    def _validateConfiguration(self):
93        """
94        Validate the configuration, possibly altering/completing it.
95        """
96
97        if self.EXECUTABLE:
98            from os import getenv, pathsep
99            from os.path import isabs, exists, join
100            from vcpx.config import ConfigurationError
101            from sys import platform
102
103            if isabs(self.EXECUTABLE):
104                ok = exists(self.EXECUTABLE)
105            else:
106                ok = False
107                mswindows = (platform == "win32")
108                for path in getenv('PATH').split(pathsep):
109                    if exists(join(path, self.EXECUTABLE)):
110                        ok = True
111                    elif mswindows:
112                        for ext in ['.exe', '.bat']:
113                            if exists(join(path, self.EXECUTABLE + ext)):
114                                self.EXECUTABLE += ext
115                                ok = True
116                                break
117                    if ok:
118                        break
119            if not ok:
120                raise ConfigurationError("The command %r used "
121                                         "by %r does not exist!" %
122                                         (self.EXECUTABLE, self.name))
123
124    def log_info(self, what):
125        """
126        Print some info on the log and, in verbose mode, to stdout as well.
127        """
128
129        self.project.log_info(what)
130
131    def log_error(self, what, exc=False):
132        """
133        Print an error message, possibly with an exception traceback,
134        to the log and to stdout as well.
135        """
136
137        self.project.log_error(what, exc)
138
139    def workingDir(self):
140        """
141        Return an instance of the specific WorkingDir for this kind of
142        repository.
143        """
144
145        from source import InvocationError
146
147        wdname = self.kind.capitalize() + 'WorkingDir'
148        modname = 'vcpx.' + self.kind
149        try:
150            wdmod = __import__(modname, globals(), locals(), [wdname])
151            workingdir = getattr(wdmod, wdname)
152        except (AttributeError, ImportError):
153            raise InvocationError("Unhandled source VCS kind: " + self.kind)
154
155        return workingdir(self)
156
157    def command(self, *args, **kwargs):
158        """
159        Return the base external command, a sequence suitable to be used
160        to init an ExternalCommand instance.
161
162        This return None if the backend uses a different way to execute
163        its actions.
164        """
165
166        executable = kwargs.get('executable', self.EXECUTABLE)
167        if executable:
168            cmd = [executable]
169            cmd.extend(args)
170            return cmd
171
172
173class ArxRepository(Repository):
174    METADIR = '_arx'
175
176    def _load(self, config):
177        Repository._load(self, config)
178        self.EXECUTABLE = config.get(self.name, 'arx-command', 'arx')
179
180
181class BzrRepository(Repository):
182    METADIR = '.bzr'
183
184    def _load(self, config):
185        Repository._load(self, config)
186        self.EXECUTABLE = config.get(self.name, 'bzr-command', 'bzr')
187
188
189class BzrngRepository(Repository):
190    METADIR = '.bzr'
191
192    def _load(self, config):
193        Repository._load(self, config)
194        ppath = config.get(self.name, 'python-path')
195        if ppath:
196            from sys import path
197
198            if ppath not in path:
199                path.insert(0, ppath)
200
201
202class CdvRepository(Repository):
203    METADIR = '.cdv'
204
205    def _load(self, config):
206        Repository._load(self, config)
207        self.EXECUTABLE = config.get(self.name, 'cdv-command', 'cdv')
208
209
210class CgRepository(Repository):
211    METADIR = '.git'
212
213    def _load(self, config):
214        Repository._load(self, config)
215        self.EXECUTABLE = config.get(self.name, 'cg-command', 'cg')
216
217
218class CvsRepository(Repository):
219    METADIR = 'CVS'
220
221    def _load(self, config):
222        Repository._load(self, config)
223        self.EXECUTABLE = config.get(self.name, 'cvs-command', 'cvs')
224        self.tag_entries = config.get(self.name, 'tag-entries', 'True')
225
226    def _validateConfiguration(self):
227        from os.path import split
228        from config import ConfigurationError
229
230        Repository._validateConfiguration(self)
231
232        if not self.module and self.repository:
233            self.module = split(self.repository)[1]
234
235        if not self.module:
236            raise ConfigurationError("Must specify a repository and maybe "
237                                     "a module also")
238
239
240class CvspsRepository(CvsRepository):
241    def command(self, *args, **kwargs):
242        if kwargs.get('cvsps', False):
243            kwargs['executable'] = self.__cvsps
244        return CvsRepository.command(self, *args, **kwargs)
245
246    def _load(self, config):
247        CvsRepository._load(self, config)
248        self.__cvsps = config.get(self.name, 'cvsps-command', 'cvsps')
249        self.tag_entries = config.get(self.name, 'tag-entries', 'True')
250
251
252class DarcsRepository(Repository):
253    METADIR = '_darcs'
254
255    def _load(self, config):
256        Repository._load(self, config)
257        self.EXECUTABLE = config.get(self.name, 'darcs-command', 'darcs')
258
259
260class GitRepository(Repository):
261    METADIR = '.git'
262
263    def _load(self, config):
264        Repository._load(self, config)
265        self.EXECUTABLE = config.get(self.name, 'git-command', 'git')
266
267
268class HgRepository(Repository):
269    METADIR = '.hg'
270
271    def _load(self, config):
272        Repository._load(self, config)
273        self.EXECUTABLE = config.get(self.name, 'hg-command', 'hg')
274
275
276class MonotoneRepository(Repository):
277    METADIR = 'MT'
278
279    def _load(self, config):
280        Repository._load(self, config)
281        self.EXECUTABLE = config.get(self.name, 'monotone-command', 'monotone')
282        self.keyid = config.get(self.name, 'keyid')
283        self.passphrase = config.get(self.name, 'passphrase')
284        self.keyfile = config.get(self.name, 'keyfile')
285
286
287class SvnRepository(Repository):
288    METADIR = '.svn'
289
290    def command(self, *args, **kwargs):
291        if kwargs.get('svnadmin', False):
292            kwargs['executable'] = self.__svnadmin
293        return Repository.command(self, *args, **kwargs)
294
295    def _load(self, config):
296        Repository._load(self, config)
297        self.EXECUTABLE = config.get(self.name, 'svn-command', 'svn')
298        self.__svnadmin = config.get(self.name, 'svnadmin-command', 'svnadmin')
299        self.use_propset = config.get(self.name, 'use-propset', False)
300
301    def _validateConfiguration(self):
302        from vcpx.config import ConfigurationError
303
304        Repository._validateConfiguration(self)
305
306        if not self.repository:
307            raise ConfigurationError("Must specify the root of the "
308                                     "Subversion repository used "
309                                     "as %s with the option "
310                                     "'repository'" % self.which)
311
312        if not self.module:
313            raise ConfigurationError("Must specify the path within the "
314                                     "Subversion repository as 'module'")
315
316        if not self.module.startswith('/'):
317            self.project.log_info("Prepending '/' to module")
318            self.module = '/' + self.module
319
320    def workingDir(self):
321        wd = Repository.workingDir(self)
322        wd.USE_PROPSET = self.use_propset
323        return wd
324
325
326class SvndumpRepository(Repository):
327
328    def _validateConfiguration(self):
329        Repository._validateConfiguration(self)
330
331        if self.module and self.module.startswith('/'):
332            self.project.log_info("Removing starting '/' from module")
333            self.module = self.module[1:]
334        if self.module and not self.module.endswith('/'):
335            self.module = self.module+'/'
336
337
338class TlaRepository(Repository):
339    METADIR = '{arch}'
340
341    def _load(self, config):
342        Repository._load(self, config)
343        self.EXECUTABLE = config.get(self.name, 'tla-command', 'tla')
344        self.IGNORE_IDS = config.get(self.name, 'ignore-ids', False)
345        if self.IGNORE_IDS:
346            self.EXTRA_METADIRS = ['.arch-ids']
347
348
349class BazRepository(TlaRepository):
350    def _load(self, config):
351        TlaRepository._load(self, config)
352        self.EXECUTABLE = config.get(self.name, 'baz-command', 'baz')
353
354    def command(self, *args, **kwargs):
355        if args:
356            if args[0] == 'tree-lint':
357                args[0] = 'lint'
358        return TlaRepository.command(self, *args, **kwargs)
Note: See TracBrowser for help on using the repository browser.