source: tailor/vcpx/repository/darcs/target.py @ 1326

Revision 1326, 7.9 KB checked in by John Goerzen <jgoerzen@…>, 6 years ago (diff)

Add new parameter tags to _commit
This was necessary so that the committing process could tell the difference
between an empty changeset and a changeset that only added a tag

RevLine 
[1221]1# -*- mode: python; coding: utf-8 -*-
2# :Progetto: Tailor -- Darcs peculiarities when used as a target
3# :Creato:   lun 10 lug 2006 00:12:15 CEST
4# :Autore:   Lele Gaifax <lele@nautilus.homeip.net>
5# :Licenza:  GNU General Public License
6#
7
8"""
9This module contains the target specific bits of the darcs backend.
10"""
11
12__docformat__ = 'reStructuredText'
13
14import re
15
16from vcpx.shwrap import ExternalCommand, PIPE, STDOUT
17from vcpx.source import ChangesetApplicationFailure
18from vcpx.target import SynchronizableTargetWorkingDir
19from vcpx.tzinfo import UTC
20
21
22MOTD = """\
23Tailorized equivalent of
24%s
25"""
26
27
28class DarcsTargetWorkingDir(SynchronizableTargetWorkingDir):
29    """
30    A target working directory under ``darcs``.
31    """
32
33    def _addPathnames(self, names):
34        """
35        Add some new filesystem objects.
36        """
37
38        cmd = self.repository.command("add", "--case-ok", "--not-recursive",
39                                      "--quiet")
40        ExternalCommand(cwd=self.repository.basedir, command=cmd).execute(names)
41
42    def _addSubtree(self, subdir):
43        """
44        Use the --recursive variant of ``darcs add`` to add a subtree.
45        """
46
47        cmd = self.repository.command("add", "--case-ok", "--recursive",
48                                      "--quiet")
49        ExternalCommand(cwd=self.repository.basedir, command=cmd).execute(subdir)
50
[1326]51    def _commit(self, date, author, patchname, changelog=None, entries=None,
52                tags = []):
[1221]53        """
54        Commit the changeset.
55        """
56
57        logmessage = []
58
59        logmessage.append(date.astimezone(UTC).strftime('%Y/%m/%d %H:%M:%S UTC'))
60        logmessage.append(author)
61        if patchname:
62            logmessage.append(patchname)
63        if changelog:
64            logmessage.append(changelog)
65        if not patchname and not changelog:
66            logmessage.append('Unnamed patch')
67
68        cmd = self.repository.command("record", "--all", "--pipe")
69        if not entries:
70            entries = ['.']
71
72        record = ExternalCommand(cwd=self.repository.basedir, command=cmd)
73        record.execute(input=self.repository.encode('\n'.join(logmessage)))
74
75        if record.exit_status:
76            raise ChangesetApplicationFailure(
77                "%s returned status %d" % (str(record), record.exit_status))
78
79    def _removePathnames(self, names):
80        """
81        Remove some filesystem object.
82        """
83
84        from os.path import join, exists
85
86        # darcs raises status 512 when it does not find the entry,
87        # removed by source. Since sometime a directory is left there
88        # because it's not empty, darcs fails. So, do an explicit
89        # remove on items that are still there.
90
91        c = ExternalCommand(cwd=self.repository.basedir,
92                            command=self.repository.command("remove"))
93        existing = [n for n in names if exists(join(self.repository.basedir, n))]
94        if existing:
95            c.execute(existing)
96
97    def _renamePathname(self, oldname, newname):
98        """
99        Rename a filesystem object.
100        """
101
102        cmd = self.repository.command("mv")
103        ExternalCommand(cwd=self.repository.basedir, command=cmd).execute(oldname, newname)
104
105    def _prepareTargetRepository(self):
106        """
107        Create the base directory if it doesn't exist, and execute
108        ``darcs initialize`` if needed.
109        """
110
111        from os.path import join, exists
112
113        metadir = join(self.repository.basedir, '_darcs')
114
115        if not exists(metadir):
116            self.repository.create()
117
118        prefsdir = join(metadir, 'prefs')
119        prefsname = join(prefsdir, 'prefs')
120        boringname = join(prefsdir, 'boring')
121        if exists(prefsname):
122            for pref in open(prefsname, 'rU'):
123                if pref:
124                    pname, pvalue = pref.split(' ', 1)
125                    if pname == 'boringfile':
126                        boringname = join(self.repository.basedir, pvalue[:-1])
127
128        boring = open(boringname, 'rU')
129        ignored = boring.read().rstrip().split('\n')
130        boring.close()
131
132        # Build a list of compiled regular expressions, that will be
133        # used later to filter the entries.
134        self.__unwanted_entries = [re.compile(rx) for rx in ignored
135                                   if rx and not rx.startswith('#')]
136
137    def _prepareWorkingDirectory(self, source_repo):
138        """
139        Tweak the default settings of the repository.
140        """
141
142        from os.path import join
143
144        motd = open(join(self.repository.basedir, '_darcs/prefs/motd'), 'w')
145        motd.write(MOTD % str(source_repo))
146        motd.close()
147
148    def _adaptEntries(self, changeset):
149        """
150        Filter out boring files.
151        """
152
153        from copy import copy
154
155        adapted = SynchronizableTargetWorkingDir._adaptEntries(self, changeset)
156
157        # If there are no entries or no rules, there's nothing to do
158        if not adapted or not adapted.entries or not self.__unwanted_entries:
159            return adapted
160
161        entries = []
162        skipped = False
163        for e in adapted.entries:
164            skip = False
165            for rx in self.__unwanted_entries:
166                if rx.search(e.name):
167                    skip = True
168                    break
169            if skip:
170                self.log.info('Entry "%s" skipped per boring rules', e.name)
171                skipped = True
172            else:
173                entries.append(e)
174
175        # All entries are gone, don't commit this changeset
176        if not entries:
177            self.log.info('All entries ignored, skipping whole '
178                          'changeset "%s"', changeset.revision)
179            return None
180
181        if skipped:
182            adapted = copy(adapted)
183            adapted.entries = entries
184
185        return adapted
186
187    def _tag(self, tag):
188        """
189        Apply the given tag to the repository, unless it has already
190        been applied to the current state. (If it has been applied to
191        an earlier state, do apply it; the later tag overrides the
192        earlier one.
193        """
194        if tag not in self._currentTags():
195            cmd = self.repository.command("tag", "--author", "Unknown tagger")
196            ExternalCommand(cwd=self.repository.basedir, command=cmd).execute(tag)
197
198    def _currentTags(self):
199        """
200        Return a list of tags that refer to the repository's current
201        state.  Does not consider tags themselves to be part of the
202        state, so if the repo was tagged with T1 and then T2, then
203        both T1 and T2 are considered to refer to the current state,
204        even though 'darcs get --tag=T1' and 'darcs get --tag=T2'
205        would have different results (the latter creates a repo that
206        contains tag T2, but the former does not).
207
208        This function assumes that a tag depends on all patches that
209        precede it in the "darcs changes" list.  This assumption is
210        valid if tags only come into the repository via tailor; if the
211        user applies a tag by hand in the hybrid repository, or pulls
212        in a tag from another darcs repository, then the assumption
213        could be violated and mistagging could result.
214        """
[1244]215
216        from vcpx.repository.darcs.source import changesets_from_darcschanges_unsafe
217
[1221]218        cmd = self.repository.command("changes",
219                                      "--from-match", "not name ^TAG",
220                                      "--xml-output", "--reverse")
221        changes =  ExternalCommand(cwd=self.repository.basedir, command=cmd)
222        output = changes.execute(stdout=PIPE, stderr=STDOUT)[0]
223        if changes.exit_status:
224            raise ChangesetApplicationFailure(
225                "%s returned status %d saying\n%s" %
226                (str(changes), changes.exit_status, output.read()))
227
228        tags = []
229        for cs in changesets_from_darcschanges_unsafe(output):
230            for tag in cs.tags:
231                if tag not in tags:
232                    tags.append(tag)
233        return tags
Note: See TracBrowser for help on using the repository browser.