source: tailor/vcpx/repository.py @ 1037

Revision 1037, 13.1 KB checked in by Brendan Cully <brendan@…>, 7 years ago (diff)

Add .hgtags to hg EXTRA_METADIRS

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        from logging import getLogger
50        from weakref import ref
51
52        self.name = name
53        self.which = which
54        self.projectref = ref(project)
55        self._load(project)
56        self.log = getLogger('tailor.vcpx.%s.%s' % (self.__class__.__name__,
57                                                    which))
58        self._validateConfiguration()
59
60    def __str__(self):
61
62        s = REPO_DESCRIPTION % (self.repository, self.kind)
63        if self.module:
64            s += "\n     Module: %s" % self.module
65        return s
66
67    def _load(self, project):
68        """
69        Load the configuration for this repository.
70
71        The two main and mandatory attributes, ``repository`` and ``module``
72        can be specified either on the specific slot in the config file, or
73        as ``source-repository`` (or ``target-repository``) in its [DEFAULT]
74        section.
75
76        If the configuration does not specify a specific ``root-directory``
77        take the one from the project.
78        """
79
80        from os.path import split, expanduser
81        from locale import getpreferredencoding
82
83        cget = project.config.get
84        self.repository = cget(self.name, 'repository') or \
85                          cget(self.name, '%s-repository' % self.which)
86        if self.repository:
87            self.repository = expanduser(self.repository)
88        self.module = cget(self.name, 'module') or \
89                      cget(self.name, '%s-module' % self.which)
90        self.rootdir = cget(self.name, 'root-directory',
91                            vars={'root-directory': project.rootdir})
92        self.subdir = cget(self.name, 'subdir',
93                           vars={'subdir': project.subdir})
94        self.delay_before_apply = cget(self.name, 'delay-before-apply')
95        self.encoding = cget(self.name, 'encoding')
96        if not self.encoding:
97            self.encoding = getpreferredencoding()
98        self.encoding_errors_policy = cget(self.name,
99                                           'encoding-errors-policy', 'strict')
100
101    def _validateConfiguration(self):
102        """
103        Validate the configuration, possibly altering/completing it.
104        """
105
106        if self.EXECUTABLE:
107            from os import getenv, pathsep
108            from os.path import isabs, exists, join
109            from vcpx.config import ConfigurationError
110            from sys import platform
111
112            if isabs(self.EXECUTABLE):
113                ok = exists(self.EXECUTABLE)
114            else:
115                ok = False
116                mswindows = (platform == "win32")
117                for path in getenv('PATH').split(pathsep):
118                    if exists(join(path, self.EXECUTABLE)):
119                        ok = True
120                    elif mswindows:
121                        for ext in ['.exe', '.bat']:
122                            if exists(join(path, self.EXECUTABLE + ext)):
123                                self.EXECUTABLE += ext
124                                ok = True
125                                break
126                    if ok:
127                        break
128            if not ok:
129                self.log.critical("Cannot find external command %r",
130                                  self.EXECUTABLE)
131                raise ConfigurationError("The command %r used "
132                                         "by %r does not exist in %r!" %
133                                         (self.EXECUTABLE, self.name,
134                                          getenv('PATH')))
135
136    def encode(self, s):
137        """
138        If `s` is an unicode object, encode it in the the right charset.
139        Return a standard Python string.
140        """
141
142        if isinstance(s, unicode):
143            return s.encode(self.encoding, self.encoding_errors_policy)
144        else:
145            return s
146
147    def workingDir(self):
148        """
149        Return an instance of the specific WorkingDir for this kind of
150        repository.
151        """
152
153        from source import InvocationError
154
155        wdname = self.kind.capitalize() + 'WorkingDir'
156        modname = 'vcpx.' + self.kind
157        try:
158            wdmod = __import__(modname, globals(), locals(), [wdname])
159            workingdir = getattr(wdmod, wdname)
160        except SyntaxError, e:
161            self.log.exception("Cannot import %r from %r", wdname, modname)
162            raise InvocationError("Cannot import %r: %s" % (wdname, e))
163        except (AttributeError, ImportError), e:
164            self.log.critical("Cannot import %r from %r", wdname, modname)
165            if self.kind == 'bzr':
166                from sys import version_info
167                if version_info < (2,4):
168                    self.log.warning("Bazaar-NG backend requires Python 2.4")
169            raise InvocationError("%r is not a known VCS kind: %s" %
170                                  (self.kind, e))
171
172        return workingdir(self)
173
174    def command(self, *args, **kwargs):
175        """
176        Return the base external command, a sequence suitable to be used
177        to init an ExternalCommand instance.
178
179        This return None if the backend uses a different way to execute
180        its actions.
181        """
182
183        executable = kwargs.get('executable', self.EXECUTABLE)
184        if executable:
185            cmd = [executable]
186            cmd.extend(args)
187            return cmd
188
189
190class ArxRepository(Repository):
191    METADIR = '_arx'
192
193    def _load(self, project):
194        Repository._load(self, project)
195        self.EXECUTABLE = project.config.get(self.name, 'arx-command', 'arx')
196
197
198class BzrRepository(Repository):
199    METADIR = '.bzr'
200
201    def _load(self, project):
202        Repository._load(self, project)
203        ppath = project.config.get(self.name, 'python-path')
204        if ppath:
205            from sys import path
206
207            if ppath not in path:
208                path.insert(0, ppath)
209
210class CdvRepository(Repository):
211    METADIR = '.cdv'
212
213    def _load(self, project):
214        Repository._load(self, project)
215        self.EXECUTABLE = project.config.get(self.name, 'cdv-command', 'cdv')
216
217
218class CgRepository(Repository):
219    METADIR = '.git'
220
221    def _load(self, project):
222        Repository._load(self, project)
223        self.EXECUTABLE = project.config.get(self.name, 'cg-command', 'cg')
224
225
226class CvsRepository(Repository):
227    METADIR = 'CVS'
228
229    def _load(self, project):
230        Repository._load(self, project)
231        self.EXECUTABLE = project.config.get(self.name, 'cvs-command', 'cvs')
232        self.tag_entries = project.config.get(self.name, 'tag-entries', 'True')
233
234    def _validateConfiguration(self):
235        from os.path import split
236        from config import ConfigurationError
237
238        Repository._validateConfiguration(self)
239
240        if not self.module and self.repository:
241            self.module = split(self.repository)[1]
242
243        if not self.module:
244            self.log.critical('Missing module information')
245            raise ConfigurationError("Must specify a repository and maybe "
246                                     "a module also")
247
248
249class CvspsRepository(CvsRepository):
250    def command(self, *args, **kwargs):
251        if kwargs.get('cvsps', False):
252            kwargs['executable'] = self.__cvsps
253        return CvsRepository.command(self, *args, **kwargs)
254
255    def _load(self, project):
256        CvsRepository._load(self, project)
257        self.__cvsps = project.config.get(self.name, 'cvsps-command', 'cvsps')
258        self.tag_entries = project.config.get(self.name, 'tag-entries', 'True')
259
260
261class DarcsRepository(Repository):
262    METADIR = '_darcs'
263
264    def _load(self, project):
265        Repository._load(self, project)
266        self.EXECUTABLE = project.config.get(self.name, 'darcs-command', 'darcs')
267
268
269class GitRepository(Repository):
270    METADIR = '.git'
271
272    def _load(self, project):
273        Repository._load(self, project)
274        self.EXECUTABLE = project.config.get(self.name, 'git-command', 'git')
275
276
277class HgRepository(Repository):
278    METADIR = '.hg'
279
280    def _load(self, project):
281        Repository._load(self, project)
282        self.EXECUTABLE = project.config.get(self.name, 'hg-command', 'hg')
283        self.EXTRA_METADIRS = ['.hgtags']
284
285
286class HglibRepository(Repository):
287    METADIR = '.hg'
288
289    def _load(self, project):
290        Repository._load(self, project)
291        ppath = project.config.get(self.name, 'python-path')
292        if ppath:
293            from sys import path
294
295            if ppath not in path:
296                path.insert(0, ppath)
297        self.EXTRA_METADIRS = ['.hgtags']
298
299
300class MonotoneRepository(Repository):
301    METADIR = 'MT'
302
303    def _load(self, project):
304        Repository._load(self, project)
305        cget = project.config.get
306        self.EXECUTABLE = cget(self.name, 'monotone-command', 'monotone')
307        self.keyid = cget(self.name, 'keyid')
308        self.passphrase = cget(self.name, 'passphrase')
309        self.keyfile = cget(self.name, 'keyfile')
310        self.keygenid = cget(self.name, 'keygenid')
311        self.custom_lua = cget(self.name, 'custom_lua')
312
313class SvnRepository(Repository):
314    METADIR = '.svn'
315
316    def command(self, *args, **kwargs):
317        if kwargs.get('svnadmin', False):
318            kwargs['executable'] = self.__svnadmin
319        return Repository.command(self, *args, **kwargs)
320
321    def _load(self, project):
322        Repository._load(self, project)
323        cget = project.config.get
324        self.EXECUTABLE = cget(self.name, 'svn-command', 'svn')
325        self.__svnadmin = cget(self.name, 'svnadmin-command', 'svnadmin')
326        self.use_propset = cget(self.name, 'use-propset', False)
327        self.filter_badchars = cget(self.name, 'filter-badchars', False)
328        self.use_limit = cget(self.name, 'use-limit', True)
329        self.trust_root = cget(self.name, 'trust-root', False)
330
331    def _validateConfiguration(self):
332        from vcpx.config import ConfigurationError
333
334        Repository._validateConfiguration(self)
335
336        if not self.repository:
337            self.log.critical('Missing repository information')
338            raise ConfigurationError("Must specify the root of the "
339                                     "Subversion repository used "
340                                     "as %s with the option "
341                                     "'repository'" % self.which)
342
343        if not self.module:
344            self.log.critical('Missing module information')
345            raise ConfigurationError("Must specify the path within the "
346                                     "Subversion repository as 'module'")
347
348        if self.module == '.':
349            self.log.warning("Replacing '.' with '/' in module name")
350            self.module = '/'
351        elif not self.module.startswith('/'):
352            self.log.debug("Prepending '/' to module %r", self.module)
353            self.module = '/' + self.module
354
355    def workingDir(self):
356        wd = Repository.workingDir(self)
357        wd.USE_PROPSET = self.use_propset
358        return wd
359
360
361class SvndumpRepository(Repository):
362
363    def _validateConfiguration(self):
364        Repository._validateConfiguration(self)
365
366        if self.module and self.module.startswith('/'):
367            self.log.debug("Removing starting '/' from module %r", self.module)
368            self.module = self.module[1:]
369        if self.module and not self.module.endswith('/'):
370            self.module = self.module+'/'
371
372
373class TlaRepository(Repository):
374    METADIR = '{arch}'
375
376    def _load(self, project):
377        Repository._load(self, project)
378        self.EXECUTABLE = project.config.get(self.name, 'tla-command', 'tla')
379        self.IGNORE_IDS = project.config.get(self.name, 'ignore-ids', False)
380        if self.IGNORE_IDS:
381            self.EXTRA_METADIRS = ['.arch-ids']
382
383
384class BazRepository(TlaRepository):
385    def _load(self, project):
386        TlaRepository._load(self, project)
387        self.EXECUTABLE = project.config.get(self.name, 'baz-command', 'baz')
388
389    def command(self, *args, **kwargs):
390        if args:
391            if args[0] == 'tree-lint':
392                args[0] = 'lint'
393        return TlaRepository.command(self, *args, **kwargs)
Note: See TracBrowser for help on using the repository browser.