/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to commit.py

  • Committer: John Arbash Meinel
  • Date: 2010-01-12 22:51:31 UTC
  • mto: This revision was merged to the branch mainline in revision 4955.
  • Revision ID: john@arbash-meinel.com-20100112225131-he8h411p6aeeb947
Delay grabbing an output stream until we actually go to show a diff.

This makes the test suite happy, but it also seems to be reasonable.
If we aren't going to write anything, we don't need to hold an
output stream open.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2009-2010 Jelmer Vernooij <jelmer@samba.org>
2
 
#
3
 
# This program is free software; you can redistribute it and/or modify
4
 
# it under the terms of the GNU General Public License as published by
5
 
# the Free Software Foundation; either version 2 of the License, or
6
 
# (at your option) any later version.
7
 
#
8
 
# This program is distributed in the hope that it will be useful,
9
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
# GNU General Public License for more details.
12
 
#
13
 
# You should have received a copy of the GNU General Public License
14
 
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
 
 
17
 
 
18
 
"""Support for committing in native Git working trees."""
19
 
 
20
 
 
21
 
from dulwich.index import (
22
 
    commit_tree,
23
 
    )
24
 
import stat
25
 
 
26
 
from bzrlib import (
27
 
    revision as _mod_revision,
28
 
    )
29
 
from bzrlib.errors import (
30
 
    RootMissing,
31
 
    )
32
 
from bzrlib.repository import (
33
 
    CommitBuilder,
34
 
    )
35
 
 
36
 
from dulwich.objects import (
37
 
    S_IFGITLINK,
38
 
    Blob,
39
 
    Commit,
40
 
    )
41
 
 
42
 
 
43
 
from bzrlib.plugins.git.mapping import (
44
 
    entry_mode,
45
 
    )
46
 
from bzrlib.plugins.git.roundtrip import (
47
 
    CommitSupplement,
48
 
    inject_bzr_metadata,
49
 
    )
50
 
 
51
 
 
52
 
class GitCommitBuilder(CommitBuilder):
53
 
    """Commit builder for Git repositories."""
54
 
 
55
 
    supports_record_entry_contents = False
56
 
 
57
 
    def __init__(self, *args, **kwargs):
58
 
        super(GitCommitBuilder, self).__init__(*args, **kwargs)
59
 
        self._validate_revprops(self._revprops)
60
 
        self.store = self.repository._git.object_store
61
 
        self._blobs = {}
62
 
        self._any_changes = False
63
 
        self._will_record_deletes = False
64
 
        self._override_fileids = {}
65
 
        self._mapping = self.repository.get_mapping()
66
 
 
67
 
    def any_changes(self):
68
 
        return self._any_changes
69
 
 
70
 
    def record_entry_contents(self, ie, parent_invs, path, tree,
71
 
        content_summary):
72
 
        raise NotImplementedError(self.record_entry_contents)
73
 
 
74
 
    def record_delete(self, path, file_id):
75
 
        self._override_fileids[path] = None
76
 
        self._blobs[path] = None
77
 
        self._any_changes = True
78
 
 
79
 
    def record_iter_changes(self, workingtree, basis_revid, iter_changes):
80
 
        index = getattr(workingtree, "index", None)
81
 
        if index is not None:
82
 
            def index_sha1(path, file_id):
83
 
                return index.get_sha1(path.encode("utf-8"))
84
 
            text_sha1 = link_sha1 = index_sha1
85
 
        else:
86
 
            def link_sha1(path, file_id):
87
 
                blob = Blob()
88
 
                blob.data = workingtree.get_symlink_target(file_id, path)
89
 
                return blob.id
90
 
            def text_sha1(path, file_id):
91
 
                blob = Blob()
92
 
                blob.data = workingtree.get_file_text(file_id, path)
93
 
                return blob.id
94
 
        seen_root = False
95
 
        for (file_id, path, changed_content, versioned, parent, name, kind,
96
 
             executable) in iter_changes:
97
 
            if kind[1] in ("directory",):
98
 
                if kind[0] in ("file", "symlink"):
99
 
                    self.record_delete(path[0], file_id)
100
 
                if path[1] == "":
101
 
                    seen_root = True
102
 
                continue
103
 
            if path[1] is None:
104
 
                self.record_delete(path[0], file_id)
105
 
                continue
106
 
            if kind[1] == "file":
107
 
                mode = stat.S_IFREG
108
 
                sha = text_sha1(path[1], file_id)
109
 
            elif kind[1] == "symlink":
110
 
                mode = stat.S_IFLNK
111
 
                sha = link_sha1(path[1], file_id)
112
 
            elif kind[1] == "tree-reference":
113
 
                mode = S_IFGITLINK
114
 
                sha = "FIXME" # FIXME
115
 
            else:
116
 
                raise AssertionError("Unknown kind %r" % kind[1])
117
 
            if executable[1]:
118
 
                mode |= 0111
119
 
            self._any_changes = True
120
 
            self._blobs[path[1].encode("utf-8")] = (mode, sha)
121
 
            file_sha1 = workingtree.get_file_sha1(file_id, path[1])
122
 
            if file_sha1 is None:
123
 
                # File no longer exists
124
 
                if path[0] is not None:
125
 
                    self.record_delete(path[0], file_id)
126
 
                continue
127
 
            _, st = workingtree.get_file_with_stat(file_id, path[1])
128
 
            yield file_id, path[1], (file_sha1, st)
129
 
            self._override_fileids[path[1]] = file_id
130
 
        if not seen_root and len(self.parents) == 0:
131
 
            raise RootMissing()
132
 
        if getattr(workingtree, "basis_tree", False):
133
 
            basis_tree = workingtree.basis_tree()
134
 
        else:
135
 
            if len(self.parents) == 0:
136
 
                basis_revid = _mod_revision.NULL_REVISION
137
 
            else:
138
 
                basis_revid = self.parents[0]
139
 
            basis_tree = self.repository.revision_tree(basis_revid)
140
 
        # Fill in entries that were not changed
141
 
        for path, entry in basis_tree.iter_entries_by_dir():
142
 
            if entry.kind not in ("file", "symlink"):
143
 
                continue
144
 
            if not path in self._blobs:
145
 
                blob = Blob()
146
 
                if entry.kind == "symlink":
147
 
                    blob.data = basis_tree.get_symlink_target(entry.file_id,
148
 
                        path)
149
 
                else:
150
 
                    blob.data = basis_tree.get_file_text(entry.file_id, path)
151
 
                self._blobs[path.encode("utf-8")] = (entry_mode(entry), blob.id)
152
 
        if not self._lossy and self._mapping.BZR_FILE_IDS_FILE is not None:
153
 
            try:
154
 
                fileid_map = dict(basis_tree._fileid_map.file_ids)
155
 
            except AttributeError:
156
 
                fileid_map = {}
157
 
            fileid_map.update(self._override_fileids)
158
 
            if fileid_map:
159
 
                fileid_blob = self._mapping.export_fileid_map(fileid_map)
160
 
                self.store.add_object(fileid_blob)
161
 
                self._blobs[self._mapping.BZR_FILE_IDS_FILE] = (stat.S_IFREG | 0644, fileid_blob.id)
162
 
            else:
163
 
                self._blobs[self._mapping.BZR_FILE_IDS_FILE] = None
164
 
        self.new_inventory = None
165
 
 
166
 
    def get_basis_delta(self):
167
 
        if not self._will_record_deletes:
168
 
            raise AssertionError
169
 
        # FIXME
170
 
        return []
171
 
 
172
 
    def finish_inventory(self):
173
 
        # eliminate blobs that were removed
174
 
        for path, entry in iter(self._blobs.items()):
175
 
            if entry is None:
176
 
                del self._blobs[path]
177
 
 
178
 
    def _iterblobs(self):
179
 
        return ((path, sha, mode) for (path, (mode, sha)) in self._blobs.iteritems())
180
 
 
181
 
    def commit(self, message):
182
 
        self._validate_unicode_text(message, 'commit message')
183
 
        c = Commit()
184
 
        c.parents = [self.repository.lookup_bzr_revision_id(revid)[0] for revid in self.parents]
185
 
        c.tree = commit_tree(self.store, self._iterblobs())
186
 
        c.committer = self._committer
187
 
        c.author = self._revprops.get('author', self._committer)
188
 
        if c.author != c.committer:
189
 
            self._revprops.remove("author")
190
 
        c.commit_time = int(self._timestamp)
191
 
        c.author_time = int(self._timestamp)
192
 
        c.commit_timezone = self._timezone
193
 
        c.author_timezone = self._timezone
194
 
        c.encoding = 'utf-8'
195
 
        c.message = message.encode("utf-8")
196
 
        if not self._lossy:
197
 
            commit_supplement = CommitSupplement()
198
 
            commit_supplement.revision_id = self._new_revision_id
199
 
            commit_supplement.properties = self._revprops
200
 
            commit_supplement.explicit_parent_ids = self.parents
201
 
            if commit_supplement:
202
 
                c.message = inject_bzr_metadata(c.message, commit_supplement, "utf-8")
203
 
 
204
 
        assert len(c.id) == 40
205
 
        if self._new_revision_id is None:
206
 
            self._new_revision_id = self.mapping.revision_id_foreign_to_bzr(c.id)
207
 
        self.store.add_object(c)
208
 
        self.repository.commit_write_group()
209
 
        return self._new_revision_id
210
 
 
211
 
    def abort(self):
212
 
        self.repository.abort_write_group()
213
 
 
214
 
    def will_record_deletes(self):
215
 
        self._will_record_deletes = True
216
 
 
217
 
    def revision_tree(self):
218
 
        return self.repository.revision_tree(self._new_revision_id)