source: tailor/vcpx/repository.py @ 790

Revision 790, 10.7 KB checked in by lele@…, 8 years ago (diff)

Whitespace

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
99            from os.path import isabs, exists, join
100            from vcpx.config import ConfigurationError
101
102            if isabs(self.EXECUTABLE):
103                ok = exists(self.EXECUTABLE)
104            else:
105                ok = False
106                for path in getenv('PATH').split(':'):
107                    if exists(join(path, self.EXECUTABLE)):
108                        ok = True
109                        break
110            if not ok:
111                raise ConfigurationError("The command %r used "
112                                         "by %r does not exist!" %
113                                         (self.EXECUTABLE, self.name))
114
115    def log_info(self, what):
116        """
117        Print some info on the log and, in verbose mode, to stdout as well.
118        """
119
120        self.project.log_info(what)
121
122    def log_error(self, what, exc=False):
123        """
124        Print an error message, possibly with an exception traceback,
125        to the log and to stdout as well.
126        """
127
128        self.project.log_error(what, exc)
129
130    def workingDir(self):
131        """
132        Return an instance of the specific WorkingDir for this kind of
133        repository.
134        """
135
136        from source import InvocationError
137
138        wdname = self.kind.capitalize() + 'WorkingDir'
139        modname = 'vcpx.' + self.kind
140        try:
141            wdmod = __import__(modname, globals(), locals(), [wdname])
142            workingdir = getattr(wdmod, wdname)
143        except (AttributeError, ImportError):
144            raise InvocationError("Unhandled source VCS kind: " + self.kind)
145
146        return workingdir(self)
147
148    def command(self, *args, **kwargs):
149        """
150        Return the base external command, a sequence suitable to be used
151        to init an ExternalCommand instance.
152
153        This return None if the backend uses a different way to execute
154        its actions.
155        """
156
157        executable = kwargs.get('executable', self.EXECUTABLE)
158        if executable:
159            cmd = [executable]
160            cmd.extend(args)
161            return cmd
162
163
164class ArxRepository(Repository):
165    METADIR = '_arx'
166
167    def _load(self, config):
168        Repository._load(self, config)
169        self.EXECUTABLE = config.get(self.name, 'arx-command', 'arx')
170
171
172class BzrRepository(Repository):
173    METADIR = '.bzr'
174
175    def _load(self, config):
176        Repository._load(self, config)
177        self.EXECUTABLE = config.get(self.name, 'bzr-command', 'bzr')
178
179
180class BzrngRepository(Repository):
181    METADIR = '.bzr'
182
183    def _load(self, config):
184        Repository._load(self, config)
185        ppath = config.get(self.name, 'python-path')
186        if ppath:
187            from sys import path
188
189            if ppath not in path:
190                path.insert(0, ppath)
191
192
193class CdvRepository(Repository):
194    METADIR = '.cdv'
195
196    def _load(self, config):
197        Repository._load(self, config)
198        self.EXECUTABLE = config.get(self.name, 'cdv-command', 'cdv')
199
200
201class CgRepository(Repository):
202    METADIR = '.git'
203
204    def _load(self, config):
205        Repository._load(self, config)
206        self.EXECUTABLE = config.get(self.name, 'cg-command', 'cg')
207
208
209class CvsRepository(Repository):
210    METADIR = 'CVS'
211
212    def _load(self, config):
213        Repository._load(self, config)
214        self.EXECUTABLE = config.get(self.name, 'cvs-command', 'cvs')
215        self.tag_entries = config.get(self.name, 'tag-entries', 'True')
216
217    def _validateConfiguration(self):
218        from os.path import split
219        from config import ConfigurationError
220
221        Repository._validateConfiguration(self)
222
223        if not self.module and self.repository:
224            self.module = split(self.repository)[1]
225
226        if not self.module:
227            raise ConfigurationError("Must specify a repository and maybe "
228                                     "a module also")
229
230
231class CvspsRepository(CvsRepository):
232    def command(self, *args, **kwargs):
233        if kwargs.get('cvsps', False):
234            kwargs['executable'] = self.__cvsps
235        return CvsRepository.command(self, *args, **kwargs)
236
237    def _load(self, config):
238        CvsRepository._load(self, config)
239        self.__cvsps = config.get(self.name, 'cvsps-command', 'cvsps')
240        self.tag_entries = config.get(self.name, 'tag-entries', 'True')
241
242
243class DarcsRepository(Repository):
244    METADIR = '_darcs'
245
246    def _load(self, config):
247        Repository._load(self, config)
248        self.EXECUTABLE = config.get(self.name, 'darcs-command', 'darcs')
249
250
251class GitRepository(Repository):
252    METADIR = '.git'
253
254    def _load(self, config):
255        Repository._load(self, config)
256        self.EXECUTABLE = config.get(self.name, 'git-command', 'git')
257
258
259class HgRepository(Repository):
260    METADIR = '.hg'
261
262    def _load(self, config):
263        Repository._load(self, config)
264        self.EXECUTABLE = config.get(self.name, 'hg-command', 'hg')
265
266
267class MonotoneRepository(Repository):
268    METADIR = 'MT'
269
270    def _load(self, config):
271        Repository._load(self, config)
272        self.EXECUTABLE = config.get(self.name, 'monotone-command', 'monotone')
273        self.keyid = config.get(self.name, 'keyid')
274        self.passphrase = config.get(self.name, 'passphrase')
275        self.keyfile = config.get(self.name, 'keyfile')
276
277
278class SvnRepository(Repository):
279    METADIR = '.svn'
280
281    def command(self, *args, **kwargs):
282        if kwargs.get('svnadmin', False):
283            kwargs['executable'] = self.__svnadmin
284        return Repository.command(self, *args, **kwargs)
285
286    def _load(self, config):
287        Repository._load(self, config)
288        self.EXECUTABLE = config.get(self.name, 'svn-command', 'svn')
289        self.__svnadmin = config.get(self.name, 'svnadmin-command', 'svnadmin')
290        self.use_propset = config.get(self.name, 'use-propset', False)
291
292    def _validateConfiguration(self):
293        from vcpx.config import ConfigurationError
294
295        Repository._validateConfiguration(self)
296
297        if not self.repository:
298            raise ConfigurationError("Must specify the root of the "
299                                     "Subversion repository used "
300                                     "as %s with the option "
301                                     "'repository'" % self.which)
302
303        if not self.module:
304            raise ConfigurationError("Must specify the path within the "
305                                     "Subversion repository as 'module'")
306
307        if not self.module.startswith('/'):
308            self.project.log_info("Prepending '/' to module")
309            self.module = '/' + self.module
310
311    def workingDir(self):
312        wd = Repository.workingDir(self)
313        wd.USE_PROPSET = self.use_propset
314        return wd
315
316
317class SvndumpRepository(Repository):
318
319    def _validateConfiguration(self):
320        Repository._validateConfiguration(self)
321
322        if self.module and self.module.startswith('/'):
323            self.project.log_info("Removing starting '/' from module")
324            self.module = self.module[1:]
325        if self.module and not self.module.endswith('/'):
326            self.module = self.module+'/'
327
328
329class TlaRepository(Repository):
330    METADIR = '{arch}'
331
332    def _load(self, config):
333        Repository._load(self, config)
334        self.EXECUTABLE = config.get(self.name, 'tla-command', 'tla')
335        self.IGNORE_IDS = config.get(self.name, 'ignore-ids', False)
336        if self.IGNORE_IDS:
337            self.EXTRA_METADIRS = ['.arch-ids']
338
339
340class BazRepository(TlaRepository):
341    def _load(self, config):
342        TlaRepository._load(self, config)
343        self.EXECUTABLE = config.get(self.name, 'baz-command', 'baz')
344
345    def command(self, *args, **kwargs):
346        if args:
347            if args[0] == 'tree-lint':
348                args[0] = 'lint'
349        return TlaRepository.command(self, *args, **kwargs)
Note: See TracBrowser for help on using the repository browser.