/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 workingtree.py

  • Committer: Vincent Ladeuil
  • Date: 2010-01-25 15:55:48 UTC
  • mto: (4985.1.4 add-attr-cleanup)
  • mto: This revision was merged to the branch mainline in revision 4988.
  • Revision ID: v.ladeuil+lp@free.fr-20100125155548-0l352pujvt5bzl5e
Deploy addAttrCleanup on the whole test suite.

Several use case worth mentioning:

- setting a module or any other object attribute is the majority
by far. In some cases the setting itself is deferred but most of
the time we want to set at the same time we add the cleanup.

- there multiple occurrences of protecting hooks or ui factory
which are now useless (the test framework takes care of that now),

- there was some lambda uses that can now be avoided.

That first cleanup already simplifies things a lot.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2008 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
 
"""An adapter between a Git index and a Bazaar Working Tree"""
19
 
 
20
 
 
21
 
from cStringIO import (
22
 
    StringIO,
23
 
    )
24
 
import errno
25
 
from dulwich.objects import (
26
 
    Blob,
27
 
    )
28
 
from dulwich.protocol import (
29
 
    ZERO_SHA,
30
 
    )
31
 
import os
32
 
import stat
33
 
 
34
 
from bzrlib import (
35
 
    errors,
36
 
    ignores,
37
 
    lockable_files,
38
 
    lockdir,
39
 
    osutils,
40
 
    transport,
41
 
    tree,
42
 
    workingtree,
43
 
    )
44
 
from bzrlib.decorators import (
45
 
    needs_read_lock,
46
 
    )
47
 
 
48
 
 
49
 
from bzrlib.plugins.git.inventory import (
50
 
    GitIndexInventory,
51
 
    )
52
 
from bzrlib.plugins.git.tree import (
53
 
    changes_from_git_changes,
54
 
    tree_delta_from_git_changes,
55
 
    )
56
 
from bzrlib.plugins.git.mapping import (
57
 
    GitFileIdMap,
58
 
    )
59
 
 
60
 
IGNORE_FILENAME = ".gitignore"
61
 
 
62
 
 
63
 
class GitWorkingTree(workingtree.WorkingTree):
64
 
    """A Git working tree."""
65
 
 
66
 
    def __init__(self, bzrdir, repo, branch, index):
67
 
        self.basedir = bzrdir.root_transport.local_abspath('.')
68
 
        self.bzrdir = bzrdir
69
 
        self.repository = repo
70
 
        self.mapping = self.repository.get_mapping()
71
 
        self._branch = branch
72
 
        self._transport = bzrdir.transport
73
 
 
74
 
        self.controldir = self.bzrdir.transport.local_abspath('bzr')
75
 
 
76
 
        try:
77
 
            os.makedirs(self.controldir)
78
 
            os.makedirs(os.path.join(self.controldir, 'lock'))
79
 
        except OSError:
80
 
            pass
81
 
 
82
 
        self._control_files = lockable_files.LockableFiles(
83
 
            transport.get_transport(self.controldir), 'lock', lockdir.LockDir)
84
 
        self._format = GitWorkingTreeFormat()
85
 
        self.index = index
86
 
        self.views = self._make_views()
87
 
        self._detect_case_handling()
88
 
 
89
 
    def extras(self):
90
 
        """Yield all unversioned files in this WorkingTree.
91
 
        """
92
 
        for (dirpath, dirnames, filenames) in os.walk(self.basedir):
93
 
            if self.bzrdir.is_control_filename(dirpath[len(self.basedir):].strip("/")):
94
 
                continue
95
 
            for filename in filenames:
96
 
                relpath = os.path.join(dirpath[len(self.basedir):].strip("/"), filename)
97
 
                if not relpath in self.index:
98
 
                    yield relpath
99
 
 
100
 
 
101
 
    def unlock(self):
102
 
        # non-implementation specific cleanup
103
 
        self._cleanup()
104
 
 
105
 
        # reverse order of locking.
106
 
        try:
107
 
            return self._control_files.unlock()
108
 
        finally:
109
 
            self.branch.unlock()
110
 
 
111
 
    def is_control_filename(self, path):
112
 
        return os.path.basename(path) == ".git"
113
 
 
114
 
    def _rewrite_index(self):
115
 
        self.index.clear()
116
 
        for path, entry in self._inventory.iter_entries():
117
 
            if entry.kind == "directory":
118
 
                # Git indexes don't contain directories
119
 
                continue
120
 
            if entry.kind == "file":
121
 
                blob = Blob()
122
 
                try:
123
 
                    file, stat_val = self.get_file_with_stat(entry.file_id, path)
124
 
                except (errors.NoSuchFile, IOError):
125
 
                    # TODO: Rather than come up with something here, use the old index
126
 
                    file = StringIO()
127
 
                    from posix import stat_result
128
 
                    stat_val = stat_result((stat.S_IFREG | 0644, 0, 0, 0, 0, 0, 0, 0, 0, 0))
129
 
                blob.set_raw_string(file.read())
130
 
            elif entry.kind == "symlink":
131
 
                blob = Blob()
132
 
                try:
133
 
                    stat_val = os.lstat(self.abspath(path))
134
 
                except (errors.NoSuchFile, OSError):
135
 
                    # TODO: Rather than come up with something here, use the 
136
 
                    # old index
137
 
                    from posix import stat_result
138
 
                    stat_val = stat_result((stat.S_IFLNK, 0, 0, 0, 0, 0, 0, 0, 0, 0))
139
 
                blob.set_raw_string(entry.symlink_target)
140
 
            else:
141
 
                raise AssertionError("unknown kind '%s'" % entry.kind)
142
 
            # Add object to the repository if it didn't exist yet
143
 
            if not blob.id in self.repository._git.object_store:
144
 
                self.repository._git.object_store.add_object(blob)
145
 
            # Add an entry to the index or update the existing entry
146
 
            flags = 0 # FIXME
147
 
            self.index[path.encode("utf-8")] = (stat_val.st_ctime, stat_val.st_mtime, stat_val.st_dev, stat_val.st_ino, stat_val.st_mode, stat_val.st_uid, stat_val.st_gid, stat_val.st_size, blob.id, flags)
148
 
 
149
 
    def flush(self):
150
 
        # TODO: Maybe this should only write on dirty ?
151
 
        if self._control_files._lock_mode != 'w':
152
 
            raise errors.NotWriteLocked(self)
153
 
        self._rewrite_index()
154
 
        self.index.write()
155
 
        self._inventory_is_modified = False
156
 
 
157
 
    def get_ignore_list(self):
158
 
        ignoreset = getattr(self, '_ignoreset', None)
159
 
        if ignoreset is not None:
160
 
            return ignoreset
161
 
 
162
 
        ignore_globs = set()
163
 
        ignore_globs.update(ignores.get_runtime_ignores())
164
 
        ignore_globs.update(ignores.get_user_ignores())
165
 
        if self.has_filename(IGNORE_FILENAME):
166
 
            f = self.get_file_byname(IGNORE_FILENAME)
167
 
            try:
168
 
                ignore_globs.update(ignores.parse_ignore_file(f))
169
 
            finally:
170
 
                f.close()
171
 
        self._ignoreset = ignore_globs
172
 
        return ignore_globs
173
 
 
174
 
    def set_last_revision(self, revid):
175
 
        self._change_last_revision(revid)
176
 
 
177
 
    def _reset_data(self):
178
 
        self._inventory_is_modified = False
179
 
        try:
180
 
            head = self.repository._git.head()
181
 
        except KeyError, name:
182
 
            raise errors.NotBranchError("branch %s at %s" % (name, self.repository.base))
183
 
        basis_inv = self.repository.get_inventory(self.branch.lookup_foreign_revision_id(head))
184
 
        store = self.repository._git.object_store
185
 
        if head == ZERO_SHA:
186
 
            fileid_map = GitFileIdMap({}, self.mapping)
187
 
            basis_inv = None
188
 
        else:
189
 
            fileid_map = self.mapping.get_fileid_map(store.__getitem__,
190
 
                store[head].tree)
191
 
        result = GitIndexInventory(basis_inv, fileid_map, self.index, store)
192
 
        self._set_inventory(result, dirty=False)
193
 
 
194
 
    @needs_read_lock
195
 
    def get_file_sha1(self, file_id, path=None, stat_value=None):
196
 
        if not path:
197
 
            path = self._inventory.id2path(file_id)
198
 
        try:
199
 
            return osutils.sha_file_by_name(self.abspath(path).encode(osutils._fs_enc))
200
 
        except OSError, (num, msg):
201
 
            if num in (errno.EISDIR, errno.ENOENT):
202
 
                return None
203
 
            raise
204
 
 
205
 
    def revision_tree(self, revid):
206
 
        return self.repository.revision_tree(revid)
207
 
 
208
 
    @needs_read_lock
209
 
    def conflicts(self):
210
 
        # FIXME:
211
 
        return []
212
 
 
213
 
 
214
 
class GitWorkingTreeFormat(workingtree.WorkingTreeFormat):
215
 
 
216
 
    @property
217
 
    def _matchingbzrdir(self):
218
 
        from bzrlib.plugins.git import LocalGitControlDirFormat
219
 
        return LocalGitControlDirFormat()
220
 
 
221
 
    def get_format_description(self):
222
 
        return "Git Working Tree"
223
 
 
224
 
 
225
 
class InterIndexGitTree(tree.InterTree):
226
 
    """InterTree that works between a Git revision tree and an index."""
227
 
 
228
 
    def __init__(self, source, target):
229
 
        super(InterIndexGitTree, self).__init__(source, target)
230
 
        self._index = target.index
231
 
 
232
 
    @classmethod
233
 
    def is_compatible(cls, source, target):
234
 
        from bzrlib.plugins.git.repository import GitRevisionTree
235
 
        return (isinstance(source, GitRevisionTree) and 
236
 
                isinstance(target, GitWorkingTree))
237
 
 
238
 
    def compare(self, want_unchanged=False, specific_files=None,
239
 
                extra_trees=None, require_versioned=False, include_root=False,
240
 
                want_unversioned=False):
241
 
        changes = self._index.changes_from_tree(
242
 
            self.source._repository._git.object_store, self.source.tree, 
243
 
            want_unchanged=want_unchanged)
244
 
        source_fileid_map = self.source.mapping.get_fileid_map(
245
 
            self.source._repository._git.object_store.__getitem__,
246
 
            self.source.tree)
247
 
        if self.target.mapping.BZR_FILE_IDS_FILE is not None:
248
 
            file_id = self.target.path2id(
249
 
                self.target.mapping.BZR_FILE_IDS_FILE)
250
 
            if file_id is None:
251
 
                target_fileid_map = {}
252
 
            else:
253
 
                target_fileid_map = self.target.mapping.import_fileid_map(Blob.from_string(self.target.get_file_text(file_id)))
254
 
        else:
255
 
            target_fileid_map = {}
256
 
        target_fileid_map = GitFileIdMap(target_fileid_map, self.target.mapping)
257
 
        ret = tree_delta_from_git_changes(changes, self.target.mapping,
258
 
            (source_fileid_map, target_fileid_map),
259
 
            specific_file=specific_files, require_versioned=require_versioned)
260
 
        if want_unversioned:
261
 
            for e in self.target.extras():
262
 
                ret.unversioned.append((e, None, osutils.file_kind(self.target.abspath(e))))
263
 
        return ret
264
 
 
265
 
    def iter_changes(self, include_unchanged=False, specific_files=None,
266
 
        pb=None, extra_trees=[], require_versioned=True, want_unversioned=False):
267
 
        changes = self._index.changes_from_tree(
268
 
            self.source._repository._git.object_store, self.source.tree, 
269
 
            want_unchanged=include_unchanged)
270
 
        # FIXME: Handle want_unversioned
271
 
        return changes_from_git_changes(changes, self.target.mapping, 
272
 
            specific_file=specific_files)
273
 
 
274
 
tree.InterTree.register_optimiser(InterIndexGitTree)