source: tailor/vcpx/repository/__init__.py @ 1190

Revision 1190, 6.8 KB checked in by ydirson@…, 7 years ago (diff)

Initialize logger in repository before loading the project

This makes the loader available to backend-specific _load() methods.

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        from vcpx import TailorException
33
34        kind = name[:name.index(':')]
35        subclass = klass
36        subclassname = kind.capitalize() + 'Repository'
37        modname = 'vcpx.repository.' + kind
38        try:
39            concrete = __import__(modname, globals(), locals(), [kind])
40            subclass = getattr(concrete, subclassname, klass)
41        except SyntaxError, e:
42            raise TailorException("Cannot import %r: %s" % (kind, e))
43        except (AttributeError, ImportError, AssertionError), e:
44            raise TailorException("%r is not a known VCS kind: %s" % (kind, e))
45        instance = super(Repository, klass).__new__(subclass, name,
46                                                    project, which)
47        instance.kind = kind
48        return instance
49
50    def __init__(self, name, project, which):
51        """
52        Initialize a new instance of Repository, with a `name` and
53        associated to given `project`; `which` is either "source"
54        or "target".
55        """
56
57        from logging import getLogger
58        from weakref import ref
59
60        self.name = name
61        self.which = which
62        self.projectref = ref(project)
63        self.log = getLogger('tailor.vcpx.%s.%s' % (self.__class__.__name__,
64                                                    which))
65        self._load(project)
66        self._validateConfiguration()
67
68    def __str__(self):
69
70        s = REPO_DESCRIPTION % (self.repository, self.kind)
71        if self.module:
72            s += "\n     Module: %s" % self.module
73        return s
74
75    def _load(self, project):
76        """
77        Load the configuration for this repository.
78
79        The two main and mandatory attributes, ``repository`` and ``module``
80        can be specified either on the specific slot in the config file, or
81        as ``source-repository`` (or ``target-repository``) in its [DEFAULT]
82        section.
83
84        If the configuration does not specify a specific ``root-directory``
85        take the one from the project.
86        """
87
88        from os.path import expanduser
89        from locale import getpreferredencoding
90
91        cget = project.config.get
92        self.repository = cget(self.name, 'repository') or \
93                          cget(self.name, '%s-repository' % self.which)
94        if self.repository:
95            self.repository = expanduser(self.repository)
96        self.module = cget(self.name, 'module') or \
97                      cget(self.name, '%s-module' % self.which)
98        self.rootdir = cget(self.name, 'root-directory',
99                            vars={'root-directory': project.rootdir})
100        self.subdir = cget(self.name, 'subdir',
101                           vars={'subdir': project.subdir})
102        self.delay_before_apply = cget(self.name, 'delay-before-apply')
103        if self.delay_before_apply:
104            self.delay_before_apply = float(self.delay_before_apply)
105        self.encoding = cget(self.name, 'encoding')
106        if not self.encoding:
107            self.encoding = getpreferredencoding()
108        self.encoding_errors_policy = cget(self.name,
109                                           'encoding-errors-policy', 'strict')
110
111    def _validateConfiguration(self):
112        """
113        Validate the configuration, possibly altering/completing it.
114        """
115
116        if self.EXECUTABLE:
117            from os import getenv, pathsep
118            from os.path import isabs, exists, join
119            from sys import platform
120            from vcpx.config import ConfigurationError
121
122            if isabs(self.EXECUTABLE):
123                ok = exists(self.EXECUTABLE)
124            else:
125                ok = False
126                mswindows = (platform == "win32")
127                for path in getenv('PATH').split(pathsep):
128                    if exists(join(path, self.EXECUTABLE)):
129                        ok = True
130                    elif mswindows:
131                        for ext in ['.exe', '.bat']:
132                            if exists(join(path, self.EXECUTABLE + ext)):
133                                self.EXECUTABLE += ext
134                                ok = True
135                                break
136                    if ok:
137                        break
138            if not ok:
139                self.log.critical("Cannot find external command %r",
140                                  self.EXECUTABLE)
141                raise ConfigurationError("The command %r used "
142                                         "by %r does not exist in %r!" %
143                                         (self.EXECUTABLE, self.name,
144                                          getenv('PATH')))
145
146    def encode(self, s):
147        """
148        If `s` is an unicode object, encode it in the the right charset.
149        Return a standard Python string.
150        """
151
152        if isinstance(s, unicode):
153            return s.encode(self.encoding, self.encoding_errors_policy)
154        else:
155            return s
156
157    def workingDir(self):
158        """
159        Return an instance of the specific WorkingDir for this kind of
160        repository.
161        """
162
163        from vcpx import TailorException
164
165        wdname = self.kind.capitalize() + 'WorkingDir'
166        modname = 'vcpx.repository.' + self.kind
167        try:
168            wdmod = __import__(modname, globals(), locals(), [wdname])
169            workingdir = getattr(wdmod, wdname)
170        except SyntaxError, e:
171            self.log.exception("Cannot import %r from %r", wdname, modname)
172            raise TailorException("Cannot import %r: %s" % (wdname, e))
173        except (AttributeError, ImportError), e:
174            self.log.critical("Cannot import %r from %r", wdname, modname)
175            raise TailorException("%r is not a known VCS kind: %s" %
176                                  (self.kind, e))
177
178        return workingdir(self)
179
180    def command(self, *args, **kwargs):
181        """
182        Return the base external command, a sequence suitable to be used
183        to init an ExternalCommand instance.
184
185        This return None if the backend uses a different way to execute
186        its actions.
187        """
188
189        executable = kwargs.get('executable', self.EXECUTABLE)
190        if executable:
191            cmd = [executable]
192            cmd.extend(args)
193            return cmd
Note: See TracBrowser for help on using the repository browser.