source: tailor/vcpx/git.py @ 788

Revision 788, 5.9 KB checked in by Todd Mokros <tmokros@…>, 8 years ago (diff)

Update git backend for external command name move

Line 
1# -*- mode: python; coding: utf-8 -*-
2# :Progetto: vcpx -- Git target (using git-core)
3# :Creato:   Thu  1 Sep 2005 04:01:37 EDT
4# :Autore:   Todd Mokros <tmokros@tmokros.net>
5# :Licenza:  GNU General Public License
6#
7
8"""
9This module implements the backend for Git using git-core.
10"""
11
12__docformat__ = 'reStructuredText'
13
14from shwrap import ExternalCommand, ReopenableNamedTemporaryFile, PIPE
15from target import SyncronizableTargetWorkingDir, TargetInitializationFailure
16from source import ChangesetApplicationFailure
17
18class GitWorkingDir(SyncronizableTargetWorkingDir):
19
20    ## SyncronizableTargetWorkingDir
21
22    def _addPathnames(self, names):
23        """
24        Add some new filesystem objects.
25        """
26
27        from os.path import join, isdir
28
29        # Currently git does not handle directories at all, so filter
30        # them out.
31
32        notdirs = [n for n in names if not isdir(join(self.basedir, n))]
33        if notdirs:
34            cmd = self.repository.command("add")
35            ExternalCommand(cwd=self.basedir, command=cmd).execute(notdirs)
36
37    def __parse_author(self, author):
38        """
39        Parse the author field, returning (name, email)
40        """
41        from email.Utils import parseaddr
42        from target import AUTHOR, HOST
43
44        if author.find('@') > -1:
45            name, email = parseaddr(author)
46        else:
47            name, email = author, ''
48        name = name.strip()
49        email = email.strip()
50        if not name:
51            name = AUTHOR
52        if not email:
53            email = "%s@%s" % (AUTHOR, HOST)
54        return (name, email)
55
56    def _commit(self, date, author, patchname, changelog=None, entries=None):
57        """
58        Commit the changeset.
59        """
60
61        from time import mktime
62        from sys import getdefaultencoding
63        from os import environ
64
65        encoding = ExternalCommand.FORCE_ENCODING or getdefaultencoding()
66
67        logmessage = []
68        if patchname:
69            logmessage.append(patchname.encode(encoding))
70        if changelog:
71            logmessage.append(changelog.encode(encoding))
72
73        env = {}
74        env.update(environ)
75
76        (name, email) = self.__parse_author(author)
77        if name:
78            env['GIT_AUTHOR_NAME']=name
79        if email:
80            env['GIT_AUTHOR_EMAIL']=email
81        if date:
82            env['GIT_AUTHOR_DATE']=str(date)
83        # '-f' flag means we can get empty commits, which
84        # shouldn't be a problem.
85        cmd = self.repository.command("commit", "-a", "-F", "-")
86        c = ExternalCommand(cwd=self.basedir, command=cmd)
87
88        (out, _) = c.execute(stdout=PIPE, env=env, input='\n'.join(logmessage))
89        if c.exit_status:
90            if out is None or out.readline().strip() != 'nothing to commit':
91                raise ChangesetApplicationFailure("%s returned status %d" %
92                                                  (str(c), c.exit_status))
93            else:
94                # empty changeset, which git-core doesn't support
95                pass
96
97    def _removePathnames(self, names):
98        """
99        Remove some filesystem object.
100        git commit -a will automatically handle files deleted on the
101        filesystem, which should have already been done by the source
102        or rsync.
103        """
104        pass
105
106    def _renamePathname(self, oldname, newname):
107        """
108        Rename a filesystem object.
109        """
110        # In the future, we may want to switch to using
111        # git rename, in case renames ever get more support
112        # in git.  It currently just does and add and remove.
113        from os.path import join, isdir
114        from os import walk
115        from dualwd import IGNORED_METADIRS
116
117        if isdir(join(self.basedir, newname)):
118            # Given lack of support for directories in current Git,
119            # loop over all files under the new directory and
120            # do a add/remove on them.
121            skip = len(self.basedir)+len(newname)+2
122            for dir, subdirs, files in walk(join(self.basedir, newname)):
123                prefix = dir[skip:]
124
125                for excd in IGNORED_METADIRS:
126                    if excd in subdirs:
127                        subdirs.remove(excd)
128
129                for f in files:
130                    self._removePathnames([join(oldname, prefix, f)])
131                    self._addPathnames([join(newname, prefix, f)])
132        else:
133            self._removePathnames([oldname])
134            self._addPathnames([newname])
135
136    def _prepareTargetRepository(self):
137        """
138        Execute ``git init-db``.
139        """
140
141        from os.path import join, exists
142
143        if not exists(join(self.basedir, self.repository.METADIR)):
144            init = ExternalCommand(cwd=self.basedir,
145                                   command=self.repository.command("init-db"))
146            init.execute()
147
148            if init.exit_status:
149                raise TargetInitializationFailure(
150                    "%s returned status %s" % (str(init), init.exit_status))
151
152    def _prepareWorkingDirectory(self, source_repo):
153        """
154        Create the .git/info/exclude.
155        """
156
157        from os.path import join
158        from re import escape
159        from dualwd import IGNORED_METADIRS
160
161        # Create the .git/info/exclude file, that contains an
162        # fnmatch per line with metadirs to be skipped.
163        ignore = open(join(self.basedir, self.repository.METADIR,
164                           'info', 'exclude'), 'a')
165        ignore.write('\n')
166        ignore.write('\n'.join(['%s' % md
167                                for md in IGNORED_METADIRS]))
168        ignore.write('\n')
169        if self.logfile.startswith(self.basedir):
170            ignore.write(self.logfile[len(self.basedir)+1:])
171            ignore.write('\n')
172        if self.state_file.filename.startswith(self.basedir):
173            sfrelname = self.state_file.filename[len(self.basedir)+1:]
174            ignore.write(sfrelname)
175            ignore.write('\n')
176            ignore.write(sfrelname+'.journal')
177            ignore.write('\n')
178        ignore.close()
179
Note: See TracBrowser for help on using the repository browser.