/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.264.10 by Jelmer Vernooij
Yield inventory entries.
1
# Copyright (C) 2008-2011 Jelmer Vernooij <jelmer@samba.org>
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
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
0.200.381 by Jelmer Vernooij
Support working trees properly, status and ls.
17
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
18
"""An adapter between a Git index and a Bazaar Working Tree"""
19
0.200.1594 by Jelmer Vernooij
Use absolute_import everywhere.
20
from __future__ import absolute_import
0.200.381 by Jelmer Vernooij
Support working trees properly, status and ls.
21
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
22
import itertools
0.200.385 by Jelmer Vernooij
Cope with removed files.
23
from cStringIO import (
24
    StringIO,
25
    )
0.200.1210 by Jelmer Vernooij
Implement GitWorkingTree._walkdirs.
26
from collections import defaultdict
0.239.4 by Jelmer Vernooij
Cope with nonexistent files and directories in get_file_sha1.
27
import errno
0.200.1538 by Jelmer Vernooij
More work on tree-reference support.
28
from dulwich.errors import NotGitRepository
0.200.1655 by Jelmer Vernooij
Basic support for git ignores.
29
from dulwich.ignore import (
0.200.1658 by Jelmer Vernooij
Fix handling of ignores - return patterns that matched.
30
    IgnoreFilterManager,
0.200.1655 by Jelmer Vernooij
Basic support for git ignores.
31
    )
0.200.1096 by Jelmer Vernooij
Implement GitWorkingTreeFormat.initialize.
32
from dulwich.index import (
33
    Index,
0.200.1531 by Jelmer Vernooij
Don't trust index contents - verify against file timestamps.
34
    changes_from_tree,
35
    cleanup_mode,
0.200.1754 by Jelmer Vernooij
Avoid updating index when just comparing trees.
36
    commit_tree,
0.200.1531 by Jelmer Vernooij
Don't trust index contents - verify against file timestamps.
37
    index_entry_from_stat,
0.200.1754 by Jelmer Vernooij
Avoid updating index when just comparing trees.
38
    iter_fresh_blobs,
0.323.1 by Jelmer Vernooij
Fix iter_changes of untracked changes.
39
    blob_from_path_and_stat,
0.200.1096 by Jelmer Vernooij
Implement GitWorkingTreeFormat.initialize.
40
    )
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
41
from dulwich.object_store import (
42
    tree_lookup_path,
43
    )
0.200.383 by Jelmer Vernooij
Simplify, support rewriting index based on inventory.
44
from dulwich.objects import (
45
    Blob,
0.200.1538 by Jelmer Vernooij
More work on tree-reference support.
46
    S_IFGITLINK,
0.200.948 by Jelmer Vernooij
Cope with empty inventories.
47
    ZERO_SHA,
48
    )
0.200.1538 by Jelmer Vernooij
More work on tree-reference support.
49
from dulwich.repo import Repo
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
50
import os
0.264.10 by Jelmer Vernooij
Yield inventory entries.
51
import posixpath
0.200.1655 by Jelmer Vernooij
Basic support for git ignores.
52
import re
0.200.384 by Jelmer Vernooij
Fix reading of inventory from index.
53
import stat
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
54
import sys
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
55
0.200.1641 by Jelmer Vernooij
Use relative imports where possible.
56
from ... import (
0.200.382 by Jelmer Vernooij
Support flushing index.
57
    errors,
0.262.1 by Jelmer Vernooij
Fix WorkingTree.conflicts().
58
    conflicts as _mod_conflicts,
0.200.1752 by Jelmer Vernooij
Don't traverse nested trees in WorkingTree.smart_add.
59
    controldir as _mod_controldir,
0.200.1655 by Jelmer Vernooij
Basic support for git ignores.
60
    globbing,
0.200.409 by Jelmer Vernooij
Support parsing .gitignore.
61
    ignores,
0.200.1476 by Jelmer Vernooij
Cope with working tree refactoring.
62
    lock,
0.200.381 by Jelmer Vernooij
Support working trees properly, status and ls.
63
    osutils,
0.200.1720 by Jelmer Vernooij
Fix handling of pending merges.
64
    revision as _mod_revision,
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
65
    trace,
0.200.1752 by Jelmer Vernooij
Don't traverse nested trees in WorkingTree.smart_add.
66
    transport as _mod_transport,
0.200.519 by Jelmer Vernooij
Move imports down, might not be available in older bzr-git versions.
67
    tree,
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
68
    workingtree,
69
    )
0.200.1648 by Jelmer Vernooij
Fix compatibility with newer versions of breezy.
70
from ...bzr import (
71
    inventory,
72
    )
0.200.1680 by Jelmer Vernooij
Fix repo locks.
73
from ...mutabletree import (
74
    MutableTree,
75
    )
0.200.1641 by Jelmer Vernooij
Use relative imports where possible.
76
77
78
from .dir import (
0.200.1096 by Jelmer Vernooij
Implement GitWorkingTreeFormat.initialize.
79
    LocalGitDir,
80
    )
0.200.1641 by Jelmer Vernooij
Use relative imports where possible.
81
from .tree import (
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
82
    changes_from_git_changes,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
83
    tree_delta_from_git_changes,
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
84
    InterGitTrees,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
85
    )
0.200.1641 by Jelmer Vernooij
Use relative imports where possible.
86
from .mapping import (
0.200.971 by Chadrik
Fix 'bzr status' after 'bzr add' in native git working trees.
87
    GitFileIdMap,
0.264.10 by Jelmer Vernooij
Yield inventory entries.
88
    mode_kind,
0.200.971 by Chadrik
Fix 'bzr status' after 'bzr add' in native git working trees.
89
    )
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
90
0.200.409 by Jelmer Vernooij
Support parsing .gitignore.
91
IGNORE_FILENAME = ".gitignore"
92
93
0.200.1768 by Jelmer Vernooij
Fix handling of normalized filenames.
94
def ensure_normalized_path(path):
95
    """Check whether path is normalized.
96
97
    :raises InvalidNormalization: When path is not normalized, and cannot be
98
        accessed on this platform by the normalized path.
99
    :return: The NFC normalised version of path.
100
    """
101
    norm_path, can_access = osutils.normalized_filename(path)
102
    if norm_path != path:
103
        if can_access:
104
            return norm_path
105
        else:
106
            raise errors.InvalidNormalization(path)
107
    return path
108
109
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
110
class GitWorkingTree(workingtree.WorkingTree):
111
    """A Git working tree."""
112
0.200.1648 by Jelmer Vernooij
Fix compatibility with newer versions of breezy.
113
    def __init__(self, controldir, repo, branch, index):
0.200.1741 by Jelmer Vernooij
Fix opentree tests.
114
        basedir = controldir.root_transport.local_abspath('.')
115
        self.basedir = osutils.realpath(basedir)
0.200.1648 by Jelmer Vernooij
Fix compatibility with newer versions of breezy.
116
        self.controldir = controldir
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
117
        self.repository = repo
0.200.1205 by Jelmer Vernooij
Implement GitWorkingTree.stored_kind.
118
        self.store = self.repository._git.object_store
0.200.384 by Jelmer Vernooij
Fix reading of inventory from index.
119
        self.mapping = self.repository.get_mapping()
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
120
        self._branch = branch
0.200.1648 by Jelmer Vernooij
Fix compatibility with newer versions of breezy.
121
        self._transport = controldir.transport
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
122
        self._format = GitWorkingTreeFormat()
0.200.803 by Jelmer Vernooij
Default to non-bare repositories when initializing a control directory.
123
        self.index = index
0.200.1242 by Jelmer Vernooij
Support directories better.
124
        self._versioned_dirs = None
0.200.239 by Jelmer Vernooij
Provide views.
125
        self.views = self._make_views()
0.200.1173 by Jelmer Vernooij
Provide GitWorkingTree._rules_searcher.
126
        self._rules_searcher = None
0.200.381 by Jelmer Vernooij
Support working trees properly, status and ls.
127
        self._detect_case_handling()
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
128
        self._reset_data()
129
        self._fileid_map = self._basis_fileid_map.copy()
0.200.1476 by Jelmer Vernooij
Cope with working tree refactoring.
130
        self._lock_mode = None
131
        self._lock_count = 0
132
0.200.1650 by Jelmer Vernooij
Implement GitWorkingTree.supports_tree_reference.
133
    def supports_tree_reference(self):
134
        return False
135
0.200.1476 by Jelmer Vernooij
Cope with working tree refactoring.
136
    def lock_read(self):
137
        """Lock the repository for read operations.
138
0.200.1646 by Jelmer Vernooij
Rename bzrlib to breezy.
139
        :return: A breezy.lock.LogicalLockResult.
0.200.1476 by Jelmer Vernooij
Cope with working tree refactoring.
140
        """
141
        if not self._lock_mode:
142
            self._lock_mode = 'r'
143
            self._lock_count = 1
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
144
            self.index.read()
0.200.1476 by Jelmer Vernooij
Cope with working tree refactoring.
145
        else:
146
            self._lock_count += 1
147
        self.branch.lock_read()
148
        return lock.LogicalLockResult(self.unlock)
149
0.200.1477 by Jelmer Vernooij
Implement GitWorkingTree.lock_tree_write.
150
    def lock_tree_write(self):
151
        if not self._lock_mode:
152
            self._lock_mode = 'w'
153
            self._lock_count = 1
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
154
            self.index.read()
0.200.1477 by Jelmer Vernooij
Implement GitWorkingTree.lock_tree_write.
155
        elif self._lock_mode == 'r':
156
            raise errors.ReadOnlyError(self)
157
        else:
158
            self._lock_count +=1
159
        self.branch.lock_read()
160
        return lock.LogicalLockResult(self.unlock)
161
0.200.1476 by Jelmer Vernooij
Cope with working tree refactoring.
162
    def lock_write(self, token=None):
163
        if not self._lock_mode:
164
            self._lock_mode = 'w'
165
            self._lock_count = 1
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
166
            self.index.read()
0.200.1476 by Jelmer Vernooij
Cope with working tree refactoring.
167
        elif self._lock_mode == 'r':
168
            raise errors.ReadOnlyError(self)
169
        else:
170
            self._lock_count +=1
171
        self.branch.lock_write()
172
        return lock.LogicalLockResult(self.unlock)
173
174
    def is_locked(self):
175
        return self._lock_count >= 1
176
177
    def get_physical_lock_status(self):
178
        return False
179
180
    def unlock(self):
181
        if not self._lock_count:
182
            return lock.cant_unlock_not_held(self)
0.200.1530 by Jelmer Vernooij
Fix lock order.
183
        self.branch.unlock()
0.200.1476 by Jelmer Vernooij
Cope with working tree refactoring.
184
        self._cleanup()
185
        self._lock_count -= 1
186
        if self._lock_count > 0:
187
            return
188
        self._lock_mode = None
0.200.173 by Jelmer Vernooij
Merge changes, open index.
189
0.200.1658 by Jelmer Vernooij
Fix handling of ignores - return patterns that matched.
190
    def _cleanup(self):
191
        pass
192
0.200.1322 by Jelmer Vernooij
Add case detection.
193
    def _detect_case_handling(self):
194
        try:
195
            self._transport.stat(".git/cOnFiG")
196
        except errors.NoSuchFile:
197
            self.case_sensitive = True
198
        else:
199
            self.case_sensitive = False
200
0.200.1315 by Jelmer Vernooij
Implement WorkingTree.merge_modified.
201
    def merge_modified(self):
202
        return {}
203
0.200.1696 by Jelmer Vernooij
Fix set_merge_modified.
204
    def set_merge_modified(self, modified_hashes):
0.298.1 by Jelmer Vernooij
mark GitWorkngTree.set_merge_modified as unsupported.
205
        raise errors.UnsupportedOperation(self.set_merge_modified, self)
0.200.1690 by Jelmer Vernooij
Implement WorkingTree.set_merge_modified.
206
0.200.1220 by Jelmer Vernooij
Support set_parent_trees.
207
    def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
208
        self.set_parent_ids([p for p, t in parents_list])
209
0.305.1 by Jelmer Vernooij
Reset RHS parents after commit.
210
    def _set_merges_from_parent_ids(self, rhs_parent_ids):
0.200.1779 by Jelmer Vernooij
Actually store git revision ids rather than bzr revision ids.
211
        try:
0.305.1 by Jelmer Vernooij
Reset RHS parents after commit.
212
            merges = [self.branch.lookup_bzr_revision_id(revid)[0] for revid in rhs_parent_ids]
0.200.1779 by Jelmer Vernooij
Actually store git revision ids rather than bzr revision ids.
213
        except errors.NoSuchRevision as e:
214
            raise errors.GhostRevisionUnusableHere(e.revision)
0.304.1 by Jelmer Vernooij
Delete MERGE_HEAD if there are no parent ids.
215
        if merges:
216
            self.control_transport.put_bytes('MERGE_HEAD', '\n'.join(merges),
217
                mode=self.controldir._get_file_mode())
218
        else:
219
            try:
220
                self.control_transport.delete('MERGE_HEAD')
221
            except errors.NoSuchFile:
222
                pass
0.200.1720 by Jelmer Vernooij
Fix handling of pending merges.
223
224
    def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
225
        """Set the parent ids to revision_ids.
226
227
        See also set_parent_trees. This api will try to retrieve the tree data
228
        for each element of revision_ids from the trees repository. If you have
229
        tree data already available, it is more efficient to use
230
        set_parent_trees rather than set_parent_ids. set_parent_ids is however
231
        an easier API to use.
232
233
        :param revision_ids: The revision_ids to set as the parent ids of this
234
            working tree. Any of these may be ghosts.
235
        """
236
        with self.lock_tree_write():
237
            self._check_parents_for_ghosts(revision_ids,
238
                allow_leftmost_as_ghost=allow_leftmost_as_ghost)
239
            for revision_id in revision_ids:
240
                _mod_revision.check_not_reserved_id(revision_id)
241
242
            revision_ids = self._filter_parent_ids_by_ancestry(revision_ids)
243
244
            if len(revision_ids) > 0:
245
                self.set_last_revision(revision_ids[0])
246
            else:
247
                self.set_last_revision(_mod_revision.NULL_REVISION)
248
0.305.1 by Jelmer Vernooij
Reset RHS parents after commit.
249
            self._set_merges_from_parent_ids(revision_ids[1:])
0.200.1720 by Jelmer Vernooij
Fix handling of pending merges.
250
251
    def get_parent_ids(self):
252
        """See Tree.get_parent_ids.
253
254
        This implementation reads the pending merges list and last_revision
255
        value and uses that to decide what the parents list should be.
256
        """
257
        last_rev = _mod_revision.ensure_null(self._last_revision())
258
        if _mod_revision.NULL_REVISION == last_rev:
259
            parents = []
260
        else:
261
            parents = [last_rev]
262
        try:
263
            merges_bytes = self.control_transport.get_bytes('MERGE_HEAD')
264
        except errors.NoSuchFile:
265
            pass
266
        else:
267
            for l in osutils.split_lines(merges_bytes):
268
                revision_id = l.rstrip('\n')
0.200.1779 by Jelmer Vernooij
Actually store git revision ids rather than bzr revision ids.
269
                parents.append(self.branch.lookup_foreign_revision_id(revision_id))
0.200.1720 by Jelmer Vernooij
Fix handling of pending merges.
270
        return parents
271
0.200.1599 by Jelmer Vernooij
Implement GitWorkingTree.iter_children.
272
    def iter_children(self, file_id):
273
        dpath = self.id2path(file_id) + "/"
274
        if dpath in self.index:
275
            return
276
        for path in self.index:
277
            if not path.startswith(dpath):
278
                continue
279
            if "/" in path[len(dpath):]:
280
                # Not a direct child but something further down
281
                continue
282
            yield self.path2id(path)
283
0.316.2 by Jelmer Vernooij
Flush after modifying index.
284
    def _index_add_entry(self, path, kind, flags=0):
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
285
        assert self._lock_mode is not None
0.200.1206 by Jelmer Vernooij
Implement GitWorkingTree.all_file_ids.
286
        assert isinstance(path, basestring)
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
287
        if kind == "directory":
288
            # Git indexes don't contain directories
289
            return
290
        if kind == "file":
291
            blob = Blob()
292
            try:
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
293
                file, stat_val = self.get_file_with_stat(path)
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
294
            except (errors.NoSuchFile, IOError):
295
                # TODO: Rather than come up with something here, use the old index
296
                file = StringIO()
0.265.1 by Martin
Don't import posix module, the os wrapper exists for portability
297
                stat_val = os.stat_result(
298
                    (stat.S_IFREG | 0644, 0, 0, 0, 0, 0, 0, 0, 0, 0))
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
299
            blob.set_raw_string(file.read())
300
        elif kind == "symlink":
301
            blob = Blob()
302
            try:
303
                stat_val = os.lstat(self.abspath(path))
304
            except (errors.NoSuchFile, OSError):
0.200.1636 by Jelmer Vernooij
Some formatting fixes.
305
                # TODO: Rather than come up with something here, use the
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
306
                # old index
0.265.1 by Martin
Don't import posix module, the os wrapper exists for portability
307
                stat_val = os.stat_result(
308
                    (stat.S_IFLNK, 0, 0, 0, 0, 0, 0, 0, 0, 0))
0.200.1321 by Jelmer Vernooij
More fixes for compatibility with bzr.dev testsuite.
309
            blob.set_raw_string(
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
310
                self.get_symlink_target(path).encode("utf-8"))
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
311
        else:
312
            raise AssertionError("unknown kind '%s'" % kind)
313
        # Add object to the repository if it didn't exist yet
0.200.1205 by Jelmer Vernooij
Implement GitWorkingTree.stored_kind.
314
        if not blob.id in self.store:
315
            self.store.add_object(blob)
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
316
        # Add an entry to the index or update the existing entry
0.200.1768 by Jelmer Vernooij
Fix handling of normalized filenames.
317
        ensure_normalized_path(path)
0.200.1242 by Jelmer Vernooij
Support directories better.
318
        encoded_path = path.encode("utf-8")
0.200.1770 by Jelmer Vernooij
Fix test for illegal characters in filenames.
319
        if b'\r' in encoded_path or b'\n' in encoded_path:
320
            # TODO(jelmer): Why do we need to do this?
321
            trace.mutter('ignoring path with invalid newline in it: %r', path)
322
            return
0.200.1531 by Jelmer Vernooij
Don't trust index contents - verify against file timestamps.
323
        self.index[encoded_path] = index_entry_from_stat(
324
            stat_val, blob.id, flags)
0.200.1242 by Jelmer Vernooij
Support directories better.
325
        if self._versioned_dirs is not None:
326
            self._ensure_versioned_dir(encoded_path)
327
328
    def _ensure_versioned_dir(self, dirname):
0.200.1249 by Jelmer Vernooij
Fix file id for tree root
329
        if dirname in self._versioned_dirs:
0.200.1242 by Jelmer Vernooij
Support directories better.
330
            return
0.200.1249 by Jelmer Vernooij
Fix file id for tree root
331
        if dirname != "":
332
            self._ensure_versioned_dir(posixpath.dirname(dirname))
0.200.1242 by Jelmer Vernooij
Support directories better.
333
        self._versioned_dirs.add(dirname)
334
335
    def _load_dirs(self):
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
336
        assert self._lock_mode is not None
0.200.1242 by Jelmer Vernooij
Support directories better.
337
        self._versioned_dirs = set()
338
        for p in self.index:
339
            self._ensure_versioned_dir(posixpath.dirname(p))
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
340
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
341
    def _unversion_path(self, path):
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
342
        assert self._lock_mode is not None
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
343
        encoded_path = path.encode("utf-8")
0.287.6 by Jelmer Vernooij
Fix some more tests.
344
        count = 0
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
345
        try:
346
            del self.index[encoded_path]
347
        except KeyError:
348
            # A directory, perhaps?
349
            for p in list(self.index):
0.200.1692 by Jelmer Vernooij
Mark three more tests as xfail.
350
                if p.startswith(encoded_path+b"/"):
0.287.6 by Jelmer Vernooij
Fix some more tests.
351
                    count += 1
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
352
                    del self.index[p]
0.287.6 by Jelmer Vernooij
Fix some more tests.
353
        else:
354
            count = 1
0.200.1772 by Jelmer Vernooij
Fix handling of unversioned file in get_file_sha1.
355
        self._versioned_dirs = None
0.287.6 by Jelmer Vernooij
Fix some more tests.
356
        return count
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
357
0.285.8 by Jelmer Vernooij
Fix more tests for swapped arguments.
358
    def unversion(self, paths, file_ids=None):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
359
        with self.lock_tree_write():
0.200.1690 by Jelmer Vernooij
Implement WorkingTree.set_merge_modified.
360
            for path in paths:
0.200.1742 by Jelmer Vernooij
Fix some unversion tests.
361
                encoded_path = path.encode("utf-8")
362
                try:
363
                    del self.index[encoded_path]
364
                except KeyError:
365
                    if not self._has_dir(path):
366
                        raise errors.NoSuchFile(path)
0.200.1772 by Jelmer Vernooij
Fix handling of unversioned file in get_file_sha1.
367
            self._versioned_dirs = None
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
368
            self.flush()
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
369
0.200.1678 by Jelmer Vernooij
Fix tests.
370
    def update_basis_by_delta(self, revid, delta):
371
        # TODO(jelmer): This shouldn't be called, it's inventory specific.
0.316.2 by Jelmer Vernooij
Flush after modifying index.
372
        for (old_path, new_path, file_id, ie) in delta:
373
            if old_path is not None and old_path.encode('utf-8') in self.index:
374
                del self.index[old_path.encode('utf-8')]
375
                self._versioned_dirs = None
376
            if new_path is not None and ie.kind != 'directory':
377
                self._index_add_entry(new_path, ie.kind)
378
        self.flush()
379
        self._set_merges_from_parent_ids([])
0.200.1678 by Jelmer Vernooij
Fix tests.
380
0.200.1243 by Jelmer Vernooij
Implement WorkingTree.check_state.
381
    def check_state(self):
382
        """Check that the working state is/isn't valid."""
383
        pass
384
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
385
    def remove(self, files, verbose=False, to_file=None, keep_files=True,
386
        force=False):
387
        """Remove nominated files from the working tree metadata.
388
389
        :param files: File paths relative to the basedir.
390
        :param keep_files: If true, the files will also be kept.
391
        :param force: Delete files and directories, even if they are changed
392
            and even if the directories are not empty.
393
        """
394
        if isinstance(files, basestring):
395
            files = [files]
396
397
        if to_file is None:
398
            to_file = sys.stdout
399
0.200.1735 by Jelmer Vernooij
Fix remove tests.
400
        files = list(files)
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
401
402
        if len(files) == 0:
403
            return # nothing to do
404
405
        # Sort needed to first handle directory content before the directory
406
        files.sort(reverse=True)
407
408
        def backup(file_to_backup):
409
            abs_path = self.abspath(file_to_backup)
0.200.1648 by Jelmer Vernooij
Fix compatibility with newer versions of breezy.
410
            backup_name = self.controldir._available_backup_name(file_to_backup)
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
411
            osutils.rename(abs_path, self.abspath(backup_name))
412
            return "removed %s (but kept a copy: %s)" % (
413
                file_to_backup, backup_name)
414
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
415
        with self.lock_tree_write():
416
            for f in files:
0.200.1735 by Jelmer Vernooij
Fix remove tests.
417
                if f == '':
418
                    continue
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
419
                else:
420
                    abs_path = self.abspath(f)
421
                    if verbose:
422
                        # having removed it, it must be either ignored or unknown
423
                        if self.is_ignored(f):
424
                            new_status = 'I'
425
                        else:
426
                            new_status = '?'
427
                        # XXX: Really should be a more abstract reporter interface
0.287.6 by Jelmer Vernooij
Fix some more tests.
428
                        kind_ch = osutils.kind_marker(self.kind(f))
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
429
                        to_file.write(new_status + '       ' + f + kind_ch + '\n')
430
                    # Unversion file
0.287.6 by Jelmer Vernooij
Fix some more tests.
431
                    # TODO(jelmer): _unversion_path() is O(size-of-index) for directories
432
                    if self._unversion_path(f) == 0:
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
433
                        if (osutils.isdir(abs_path) and
0.287.6 by Jelmer Vernooij
Fix some more tests.
434
                            len(os.listdir(abs_path)) == 0):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
435
                            if not keep_files:
436
                                osutils.delete_any(abs_path)
0.287.6 by Jelmer Vernooij
Fix some more tests.
437
                            message = "removed %s" % (f,)
438
                        else:
439
                            message = "%s is not versioned." % (f,)
440
                    else:
441
                        message = "removed %s" % (f,)
442
                        if osutils.lexists(abs_path):
443
                            if (osutils.isdir(abs_path) and
444
                                len(os.listdir(abs_path)) > 0):
445
                                if force:
446
                                    osutils.rmtree(abs_path)
447
                                    message = "deleted %s" % (f,)
448
                                else:
449
                                    message = backup(f)
450
                            else:
451
                                if not keep_files:
452
                                    osutils.delete_any(abs_path)
453
                                    message = "deleted %s" % (f,)
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
454
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
455
                # print only one message (if any) per file.
456
                if message is not None:
457
                    trace.note(message)
458
            self.flush()
0.200.1192 by Jelmer Vernooij
Implement path2id.
459
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
460
    def _add(self, files, ids, kinds):
461
        for (path, file_id, kind) in zip(files, ids, kinds):
0.200.1201 by Jelmer Vernooij
Implement _set_root_id.
462
            if file_id is not None:
0.200.1663 by Jelmer Vernooij
Raise SettingFileIdUnsupported
463
                raise workingtree.SettingFileIdUnsupported()
464
            self._index_add_entry(path, kind)
0.200.1201 by Jelmer Vernooij
Implement _set_root_id.
465
0.200.1240 by Jelmer Vernooij
Implement GitWorkingTree.smart_add.
466
    def smart_add(self, file_list, recurse=True, action=None, save=True):
0.200.1771 by Jelmer Vernooij
Fix implicit tree unicode add test.
467
        if not file_list:
468
            file_list = [u'.']
0.200.1781 by Jelmer Vernooij
Support expanding symlinks.
469
470
        # expand any symlinks in the directory part, while leaving the
471
        # filename alone
472
        # only expanding if symlinks are supported avoids windows path bugs
473
        if osutils.has_symlinks():
474
            file_list = list(map(osutils.normalizepath, file_list))
475
0.200.1240 by Jelmer Vernooij
Implement GitWorkingTree.smart_add.
476
        added = []
477
        ignored = {}
478
        user_dirs = []
0.200.1733 by Jelmer Vernooij
Support handling of custom ids in smart_add.
479
        def call_action(filepath, kind):
480
            if action is not None:
481
                parent_path = posixpath.dirname(filepath)
482
                parent_id = self.path2id(parent_path)
483
                parent_ie = self._get_dir_ie(parent_path, parent_id)
484
                file_id = action(self, parent_ie, filepath, kind)
485
                if file_id is not None:
486
                    raise workingtree.SettingFileIdUnsupported()
487
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
488
        with self.lock_tree_write():
489
            for filepath in osutils.canonical_relpaths(self.basedir, file_list):
0.200.1768 by Jelmer Vernooij
Fix handling of normalized filenames.
490
                filepath = osutils.normalized_filename(filepath)[0]
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
491
                abspath = self.abspath(filepath)
0.200.1240 by Jelmer Vernooij
Implement GitWorkingTree.smart_add.
492
                kind = osutils.file_kind(abspath)
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
493
                if kind in ("file", "symlink"):
0.200.1733 by Jelmer Vernooij
Support handling of custom ids in smart_add.
494
                    call_action(filepath, kind)
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
495
                    if save:
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
496
                        self._index_add_entry(filepath, kind)
497
                    added.append(filepath)
498
                elif kind == "directory":
0.200.1733 by Jelmer Vernooij
Support handling of custom ids in smart_add.
499
                    call_action(filepath, kind)
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
500
                    if recurse:
501
                        user_dirs.append(filepath)
502
                else:
503
                    raise errors.BadFileKindError(filename=abspath, kind=kind)
504
            for user_dir in user_dirs:
505
                abs_user_dir = self.abspath(user_dir)
0.200.1752 by Jelmer Vernooij
Don't traverse nested trees in WorkingTree.smart_add.
506
                if user_dir != '':
507
                    try:
508
                        transport = _mod_transport.get_transport_from_path(abs_user_dir)
509
                        _mod_controldir.ControlDirFormat.find_format(transport)
510
                        subtree = True
511
                    except errors.NotBranchError:
512
                        subtree = False
513
                    except errors.UnsupportedFormatError:
514
                        subtree = False
515
                else:
516
                    subtree = False
517
                if subtree:
0.200.1769 by Jelmer Vernooij
Raise proper error when encountering nested trees.
518
                    trace.warning('skipping nested tree %r', abs_user_dir)
0.200.1752 by Jelmer Vernooij
Don't traverse nested trees in WorkingTree.smart_add.
519
                    continue
520
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
521
                for name in os.listdir(abs_user_dir):
522
                    subp = os.path.join(user_dir, name)
523
                    if self.is_control_filename(subp) or self.mapping.is_special_file(subp):
524
                        continue
525
                    ignore_glob = self.is_ignored(subp)
526
                    if ignore_glob is not None:
527
                        ignored.setdefault(ignore_glob, []).append(subp)
528
                        continue
529
                    abspath = self.abspath(subp)
530
                    kind = osutils.file_kind(abspath)
531
                    if kind == "directory":
532
                        user_dirs.append(subp)
533
                    else:
0.200.1733 by Jelmer Vernooij
Support handling of custom ids in smart_add.
534
                        call_action(filepath, kind)
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
535
                        if save:
536
                            self._index_add_entry(subp, kind)
0.200.1751 by Jelmer Vernooij
Fix smart_add return value.
537
                        added.append(subp)
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
538
            if added and save:
539
                self.flush()
540
            return added, ignored
0.200.1240 by Jelmer Vernooij
Implement GitWorkingTree.smart_add.
541
0.200.1201 by Jelmer Vernooij
Implement _set_root_id.
542
    def _set_root_id(self, file_id):
543
        self._fileid_map.set_file_id("", file_id)
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
544
0.200.1193 by Jelmer Vernooij
Implement GitWorkingTree.{move,rename_one}.
545
    def move(self, from_paths, to_dir=None, after=False):
546
        rename_tuples = []
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
547
        with self.lock_tree_write():
548
            to_abs = self.abspath(to_dir)
549
            if not os.path.isdir(to_abs):
550
                raise errors.BzrMoveFailedError('', to_dir,
551
                    errors.NotADirectory(to_abs))
552
553
            for from_rel in from_paths:
554
                from_tail = os.path.split(from_rel)[-1]
555
                to_rel = os.path.join(to_dir, from_tail)
556
                self.rename_one(from_rel, to_rel, after=after)
557
                rename_tuples.append((from_rel, to_rel))
558
            self.flush()
559
            return rename_tuples
560
0.200.1193 by Jelmer Vernooij
Implement GitWorkingTree.{move,rename_one}.
561
    def rename_one(self, from_rel, to_rel, after=False):
0.200.1203 by Jelmer Vernooij
Fix per_workingtree.test_rename_one.TestRenameOne.test_rename_after_non_existant_non_ascii
562
        from_path = from_rel.encode("utf-8")
0.200.1768 by Jelmer Vernooij
Fix handling of normalized filenames.
563
        ensure_normalized_path(to_rel)
0.200.1203 by Jelmer Vernooij
Fix per_workingtree.test_rename_one.TestRenameOne.test_rename_after_non_existant_non_ascii
564
        to_path = to_rel.encode("utf-8")
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
565
        with self.lock_tree_write():
0.200.1737 by Jelmer Vernooij
Fix rename tests.
566
            if not after:
567
                if not self.has_filename(from_rel):
568
                    raise errors.BzrMoveFailedError(from_rel, to_rel,
569
                        errors.NoSuchFile(from_rel))
570
            else:
571
                if not self.has_filename(to_rel):
572
                    raise errors.BzrMoveFailedError(from_rel, to_rel,
573
                        errors.NoSuchFile(to_rel))
574
0.200.1748 by Jelmer Vernooij
Fix rename test.
575
            kind = self.kind(from_rel)
576
            if not from_path in self.index and kind != 'directory':
577
                # It's not a file
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
578
                raise errors.BzrMoveFailedError(from_rel, to_rel,
579
                    errors.NotVersionedError(path=from_rel))
0.200.1737 by Jelmer Vernooij
Fix rename tests.
580
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
581
            if not after:
0.200.1737 by Jelmer Vernooij
Fix rename tests.
582
                try:
583
                    os.rename(self.abspath(from_rel), self.abspath(to_rel))
584
                except OSError as e:
585
                    if e.errno == errno.ENOENT:
586
                        raise errors.BzrMoveFailedError(from_rel, to_rel,
587
                            errors.NoSuchFile(to_rel))
588
                    raise
0.200.1748 by Jelmer Vernooij
Fix rename test.
589
            if kind != 'directory':
590
                self.index[to_path] = self.index[from_path]
591
                del self.index[from_path]
0.200.1772 by Jelmer Vernooij
Fix handling of unversioned file in get_file_sha1.
592
            self._versioned_dirs = None
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
593
            self.flush()
0.200.1193 by Jelmer Vernooij
Implement GitWorkingTree.{move,rename_one}.
594
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
595
    def get_root_id(self):
0.200.1192 by Jelmer Vernooij
Implement path2id.
596
        return self.path2id("")
597
0.200.1712 by Jelmer Vernooij
Add file_id prefix.
598
    def has_filename(self, filename):
599
        return osutils.lexists(self.abspath(filename))
600
0.200.1242 by Jelmer Vernooij
Support directories better.
601
    def _has_dir(self, path):
0.200.1368 by Jelmer Vernooij
There is always a tree root.
602
        if path == "":
603
            return True
0.200.1242 by Jelmer Vernooij
Support directories better.
604
        if self._versioned_dirs is None:
605
            self._load_dirs()
606
        return path in self._versioned_dirs
607
0.200.1192 by Jelmer Vernooij
Implement path2id.
608
    def path2id(self, path):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
609
        with self.lock_read():
0.200.1766 by Jelmer Vernooij
Fix another list_files test, integrate is_versioned.
610
            path = path.rstrip('/')
611
            if self.is_versioned(path.rstrip('/')):
612
                return self._fileid_map.lookup_file_id(path.encode("utf-8"))
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
613
            return None
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
614
0.200.1766 by Jelmer Vernooij
Fix another list_files test, integrate is_versioned.
615
    def _iter_files_recursive(self, from_dir=None, include_dirs=False):
0.200.1328 by Jelmer Vernooij
More test fixes.
616
        if from_dir is None:
617
            from_dir = ""
618
        for (dirpath, dirnames, filenames) in os.walk(self.abspath(from_dir)):
0.200.1302 by Jelmer Vernooij
Significantly improve performance of WorkingTree.extras().
619
            dir_relpath = dirpath[len(self.basedir):].strip("/")
0.200.1648 by Jelmer Vernooij
Fix compatibility with newer versions of breezy.
620
            if self.controldir.is_control_filename(dir_relpath):
0.200.605 by Jelmer Vernooij
Ignore directories in WorkingTree.extras().
621
                continue
0.200.1766 by Jelmer Vernooij
Fix another list_files test, integrate is_versioned.
622
            for name in list(dirnames):
623
                if self.controldir.is_control_filename(name):
624
                    dirnames.remove(name)
625
                    continue
626
                relpath = os.path.join(dir_relpath, name)
627
                if include_dirs:
628
                    yield relpath
629
                if not self._has_dir(relpath):
630
                    dirnames.remove(name)
631
            for name in filenames:
632
                if not self.mapping.is_special_file(name):
633
                    yield os.path.join(dir_relpath, name)
0.200.1327 by Jelmer Vernooij
Factor out all file browsing in extras.
634
635
    def extras(self):
636
        """Yield all unversioned files in this WorkingTree.
637
        """
0.200.1676 by Jelmer Vernooij
Fix typo.
638
        with self.lock_read():
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
639
            return set(self._iter_files_recursive()) - set(self.index)
0.200.605 by Jelmer Vernooij
Ignore directories in WorkingTree.extras().
640
0.200.382 by Jelmer Vernooij
Support flushing index.
641
    def flush(self):
0.287.6 by Jelmer Vernooij
Fix some more tests.
642
        # TODO: Maybe this should only write on dirty ?
643
        if self._lock_mode != 'w':
644
            raise errors.NotWriteLocked(self)
645
        self.index.write()
0.200.382 by Jelmer Vernooij
Support flushing index.
646
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
647
    def __iter__(self):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
648
        with self.lock_read():
649
            for path in self.index:
650
                yield self.path2id(path)
651
            self._load_dirs()
652
            for path in self._versioned_dirs:
653
                yield self.path2id(path)
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
654
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
655
    def has_or_had_id(self, file_id):
656
        if self.has_id(file_id):
657
            return True
658
        if self.had_id(file_id):
659
            return True
660
        return False
661
662
    def had_id(self, file_id):
663
        path = self._basis_fileid_map.lookup_file_id(file_id)
664
        try:
665
            head = self.repository._git.head()
666
        except KeyError:
667
            # Assume no if basis is not accessible
668
            return False
0.200.1205 by Jelmer Vernooij
Implement GitWorkingTree.stored_kind.
669
        if head == ZERO_SHA:
670
            return False
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
671
        root_tree = self.store[head].tree
672
        try:
673
            tree_lookup_path(self.store.__getitem__, root_tree, path)
674
        except KeyError:
675
            return False
676
        else:
677
            return True
678
0.200.1198 by Jelmer Vernooij
Implement GitWorkingTree.has_id.
679
    def has_id(self, file_id):
680
        try:
681
            self.id2path(file_id)
682
        except errors.NoSuchId:
683
            return False
684
        else:
685
            return True
686
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
687
    def id2path(self, file_id):
0.200.1532 by Jelmer Vernooij
Cope with float timestamps.
688
        assert type(file_id) is str, "file id not a string: %r" % file_id
0.200.1411 by Jelmer Vernooij
Fix control files.
689
        file_id = osutils.safe_utf8(file_id)
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
690
        with self.lock_read():
0.200.1712 by Jelmer Vernooij
Add file_id prefix.
691
            try:
692
                path = self._fileid_map.lookup_path(file_id)
693
            except ValueError:
694
                raise errors.NoSuchId(self, file_id)
0.200.1766 by Jelmer Vernooij
Fix another list_files test, integrate is_versioned.
695
            path = path.decode('utf-8')
696
            if self.is_versioned(path):
697
                return path
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
698
            raise errors.NoSuchId(self, file_id)
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
699
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
700
    def get_file_mtime(self, path, file_id=None):
0.200.1200 by Jelmer Vernooij
Support GitWorkingTree.get_file_mtime.
701
        """See Tree.get_file_mtime."""
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
702
        try:
703
            return os.lstat(self.abspath(path)).st_mtime
704
        except OSError, (num, msg):
705
            if num == errno.ENOENT:
706
                raise errors.NoSuchFile(path)
707
            raise
0.200.1200 by Jelmer Vernooij
Support GitWorkingTree.get_file_mtime.
708
0.200.1655 by Jelmer Vernooij
Basic support for git ignores.
709
    def is_ignored(self, filename):
710
        r"""Check whether the filename matches an ignore pattern.
711
712
        If the file is ignored, returns the pattern which caused it to
713
        be ignored, otherwise None.  So this can simply be used as a
714
        boolean if desired."""
715
        if getattr(self, '_global_ignoreglobster', None) is None:
716
            ignore_globs = set()
717
            ignore_globs.update(ignores.get_runtime_ignores())
718
            ignore_globs.update(ignores.get_user_ignores())
719
            self._global_ignoreglobster = globbing.ExceptionGlobster(ignore_globs)
0.200.1656 by Jelmer Vernooij
Report proper patterns, ignore files.
720
        match = self._global_ignoreglobster.match(filename)
721
        if match is not None:
722
            return match
0.200.1716 by Jelmer Vernooij
Fix some more tests.
723
        try:
724
            if self.kind(filename) == 'directory':
725
                filename += b'/'
726
        except errors.NoSuchFile:
727
            pass
728
        filename = filename.lstrip(b'/')
0.200.1658 by Jelmer Vernooij
Fix handling of ignores - return patterns that matched.
729
        ignore_manager = self._get_ignore_manager()
730
        ps = list(ignore_manager.find_matching(filename))
731
        if not ps:
732
            return None
733
        if not ps[-1].is_exclude:
734
            return None
735
        return bytes(ps[-1])
736
737
    def _get_ignore_manager(self):
738
        ignoremanager = getattr(self, '_ignoremanager', None)
739
        if ignoremanager is not None:
740
            return ignoremanager
741
742
        ignore_manager = IgnoreFilterManager.from_repo(self.repository._git)
743
        self._ignoremanager = ignore_manager
744
        return ignore_manager
0.200.409 by Jelmer Vernooij
Support parsing .gitignore.
745
0.200.1716 by Jelmer Vernooij
Fix some more tests.
746
    def _flush_ignore_list_cache(self):
747
        self._ignoremanager = None
748
0.200.508 by Jelmer Vernooij
Skip inventory caching bits.
749
    def set_last_revision(self, revid):
0.200.1720 by Jelmer Vernooij
Fix handling of pending merges.
750
        if _mod_revision.is_null(revid):
751
            self.branch.set_last_revision_info(0, revid)
752
            return False
753
        _mod_revision.check_not_reserved_id(revid)
754
        try:
755
            self.branch.generate_revision_history(revid)
756
        except errors.NoSuchRevision:
757
            raise errors.GhostRevisionUnusableHere(revid)
0.200.508 by Jelmer Vernooij
Skip inventory caching bits.
758
0.200.379 by Jelmer Vernooij
Re-enable working tree support.
759
    def _reset_data(self):
0.248.3 by Jelmer Vernooij
Handle working trees without valid HEAD branch.
760
        try:
761
            head = self.repository._git.head()
762
        except KeyError, name:
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
763
            self._basis_fileid_map = GitFileIdMap({}, self.mapping)
0.200.948 by Jelmer Vernooij
Cope with empty inventories.
764
        else:
0.310.9 by Jelmer Vernooij
Some controldir fixes.
765
            if head == ZERO_SHA:
766
                self._basis_fileid_map = GitFileIdMap({}, self.mapping)
767
            else:
768
                self._basis_fileid_map = self.mapping.get_fileid_map(
769
                    self.store.__getitem__, self.store[head].tree)
0.200.379 by Jelmer Vernooij
Re-enable working tree support.
770
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
771
    def get_file_verifier(self, path, file_id=None, stat_value=None):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
772
        with self.lock_read():
773
            try:
774
                return ("GIT", self.index[path][-2])
775
            except KeyError:
776
                if self._has_dir(path):
777
                    return ("GIT", None)
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
778
                raise errors.NoSuchFile(path)
0.200.1302 by Jelmer Vernooij
Significantly improve performance of WorkingTree.extras().
779
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
780
    def get_file_sha1(self, path, file_id=None, stat_value=None):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
781
        with self.lock_read():
0.200.1772 by Jelmer Vernooij
Fix handling of unversioned file in get_file_sha1.
782
            if not self.is_versioned(path):
783
                raise errors.NoSuchFile(path)
784
            abspath = self.abspath(path)
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
785
            try:
786
                return osutils.sha_file_by_name(abspath)
787
            except OSError, (num, msg):
788
                if num in (errno.EISDIR, errno.ENOENT):
0.200.1772 by Jelmer Vernooij
Fix handling of unversioned file in get_file_sha1.
789
                    return None
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
790
                raise
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
791
0.200.610 by Jelmer Vernooij
Support retrieving basis tree properly.
792
    def revision_tree(self, revid):
793
        return self.repository.revision_tree(revid)
794
0.200.1766 by Jelmer Vernooij
Fix another list_files test, integrate is_versioned.
795
    def is_versioned(self, path):
796
        with self.lock_read():
797
            path = path.rstrip('/').encode('utf-8')
798
            return (path in self.index or self._has_dir(path))
0.200.1242 by Jelmer Vernooij
Support directories better.
799
0.200.1239 by Jelmer Vernooij
Implement GitWorkingTree.filter_unversioned_files.
800
    def filter_unversioned_files(self, files):
0.200.1766 by Jelmer Vernooij
Fix another list_files test, integrate is_versioned.
801
        return set([p for p in files if not self.is_versioned(p)])
0.200.1239 by Jelmer Vernooij
Implement GitWorkingTree.filter_unversioned_files.
802
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
803
    def _get_dir_ie(self, path, parent_id):
0.200.1192 by Jelmer Vernooij
Implement path2id.
804
        file_id = self.path2id(path)
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
805
        return inventory.InventoryDirectory(file_id,
0.200.1190 by Jelmer Vernooij
Fix get_symlink_target call.
806
            posixpath.basename(path).strip("/"), parent_id)
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
807
808
    def _add_missing_parent_ids(self, path, dir_ids):
809
        if path in dir_ids:
810
            return []
811
        parent = posixpath.dirname(path).strip("/")
812
        ret = self._add_missing_parent_ids(parent, dir_ids)
813
        parent_id = dir_ids[parent]
814
        ie = self._get_dir_ie(path, parent_id)
815
        dir_ids[path] = ie.file_id
816
        ret.append((path, ie))
817
        return ret
818
0.200.1321 by Jelmer Vernooij
More fixes for compatibility with bzr.dev testsuite.
819
    def _get_file_ie(self, name, path, value, parent_id):
820
        assert isinstance(name, unicode)
0.200.1192 by Jelmer Vernooij
Implement path2id.
821
        assert isinstance(path, unicode)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
822
        assert isinstance(value, tuple) and len(value) == 10
823
        (ctime, mtime, dev, ino, mode, uid, gid, size, sha, flags) = value
0.200.1192 by Jelmer Vernooij
Implement path2id.
824
        file_id = self.path2id(path)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
825
        if type(file_id) != str:
826
            raise AssertionError
827
        kind = mode_kind(mode)
0.200.1321 by Jelmer Vernooij
More fixes for compatibility with bzr.dev testsuite.
828
        ie = inventory.entry_factory[kind](file_id, name, parent_id)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
829
        if kind == 'symlink':
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
830
            ie.symlink_target = self.get_symlink_target(path, file_id)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
831
        else:
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
832
            data = self.get_file_text(path, file_id)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
833
            ie.text_sha1 = osutils.sha_string(data)
834
            ie.text_size = len(data)
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
835
            ie.executable = self.is_executable(path, file_id)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
836
        ie.revision = None
837
        return ie
838
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
839
    def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
840
        mode = stat_result.st_mode
841
        return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
842
0.318.1 by Jelmer Vernooij
Fix executable test.
843
    def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
844
        return self.basis_tree().is_executable(path)
845
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
846
    def stored_kind(self, path, file_id=None):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
847
        with self.lock_read():
848
            try:
849
                return mode_kind(self.index[path.encode("utf-8")][4])
850
            except KeyError:
851
                # Maybe it's a directory?
852
                if self._has_dir(path):
853
                    return "directory"
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
854
                raise errors.NoSuchFile(path)
0.200.1205 by Jelmer Vernooij
Implement GitWorkingTree.stored_kind.
855
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
856
    def is_executable(self, path, file_id=None):
0.200.1539 by Jelmer Vernooij
Cope with new is_executable.
857
        if getattr(self, "_supports_executable", osutils.supports_executable)():
858
            mode = os.lstat(self.abspath(path)).st_mode
859
        else:
0.319.1 by Jelmer Vernooij
Support falling back on basis for executable bits.
860
            try:
861
                mode = self.index[path.encode('utf-8')].mode
862
            except KeyError:
863
                mode = 0
864
        return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
865
0.200.1539 by Jelmer Vernooij
Cope with new is_executable.
866
    def _is_executable_from_path_and_stat(self, path, stat_result):
867
        if getattr(self, "_supports_executable", osutils.supports_executable)():
868
            return self._is_executable_from_path_and_stat_from_stat(path, stat_result)
869
        else:
870
            return self._is_executable_from_path_and_stat_from_basis(path, stat_result)
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
871
0.264.10 by Jelmer Vernooij
Yield inventory entries.
872
    def list_files(self, include_root=False, from_dir=None, recursive=True):
0.200.1321 by Jelmer Vernooij
More fixes for compatibility with bzr.dev testsuite.
873
        if from_dir is None:
874
            from_dir = ""
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
875
        dir_ids = {}
0.200.1767 by Jelmer Vernooij
Fix references to Tree*.
876
        fk_entries = {'directory': tree.TreeDirectory,
877
                      'file': tree.TreeFile,
878
                      'symlink': tree.TreeLink}
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
879
        with self.lock_read():
880
            root_ie = self._get_dir_ie(u"", None)
881
            if include_root and not from_dir:
882
                yield "", "V", root_ie.kind, root_ie.file_id, root_ie
883
            dir_ids[u""] = root_ie.file_id
884
            if recursive:
0.200.1766 by Jelmer Vernooij
Fix another list_files test, integrate is_versioned.
885
                path_iterator = sorted(self._iter_files_recursive(from_dir, include_dirs=True))
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
886
            else:
887
                if from_dir is None:
888
                    start = self.basedir
889
                else:
890
                    start = os.path.join(self.basedir, from_dir)
891
                path_iterator = sorted([os.path.join(from_dir, name) for name in
892
                    os.listdir(start) if not self.controldir.is_control_filename(name)
893
                    and not self.mapping.is_special_file(name)])
894
            for path in path_iterator:
895
                try:
896
                    value = self.index[path]
897
                except KeyError:
898
                    value = None
899
                path = path.decode("utf-8")
0.200.1766 by Jelmer Vernooij
Fix another list_files test, integrate is_versioned.
900
                kind = osutils.file_kind(self.abspath(path))
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
901
                parent, name = posixpath.split(path)
902
                for dir_path, dir_ie in self._add_missing_parent_ids(parent, dir_ids):
0.200.1766 by Jelmer Vernooij
Fix another list_files test, integrate is_versioned.
903
                    pass
904
                if kind == 'directory':
905
                    if path != from_dir:
906
                        if self._has_dir(path):
907
                            ie = self._get_dir_ie(path, self.path2id(path))
908
                            status = "V"
909
                            file_id = ie.file_id
910
                        elif self.is_ignored(path):
911
                            status = "I"
912
                            ie = fk_entries[kind]()
913
                            file_id = None
914
                        else:
915
                            status = "?"
916
                            ie = fk_entries[kind]()
917
                            file_id = None
918
                        yield posixpath.relpath(path, from_dir), status, kind, file_id, ie
919
                    continue
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
920
                if value is not None:
921
                    ie = self._get_file_ie(name, path, value, dir_ids[parent])
0.200.1766 by Jelmer Vernooij
Fix another list_files test, integrate is_versioned.
922
                    yield posixpath.relpath(path, from_dir), "V", ie.kind, ie.file_id, ie
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
923
                else:
924
                    ie = fk_entries[kind]()
0.200.1766 by Jelmer Vernooij
Fix another list_files test, integrate is_versioned.
925
                    yield posixpath.relpath(path, from_dir), ("I" if self.is_ignored(path) else "?"), kind, None, ie
0.264.10 by Jelmer Vernooij
Yield inventory entries.
926
0.200.1206 by Jelmer Vernooij
Implement GitWorkingTree.all_file_ids.
927
    def all_file_ids(self):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
928
        with self.lock_read():
929
            ids = {u"": self.path2id("")}
930
            for path in self.index:
931
                if self.mapping.is_special_file(path):
932
                    continue
933
                path = path.decode("utf-8")
934
                parent = posixpath.dirname(path).strip("/")
935
                for e in self._add_missing_parent_ids(parent, ids):
936
                    pass
937
                ids[path] = self.path2id(path)
938
            return set(ids.values())
0.200.1206 by Jelmer Vernooij
Implement GitWorkingTree.all_file_ids.
939
0.200.1710 by Jelmer Vernooij
Regenerate xfail.
940
    def all_versioned_paths(self):
941
        with self.lock_read():
942
            paths = {u""}
943
            for path in self.index:
944
                if self.mapping.is_special_file(path):
945
                    continue
946
                path = path.decode("utf-8")
947
                paths.add(path)
948
                while path != "":
949
                    path = posixpath.dirname(path).strip("/")
950
                    if path in paths:
951
                        break
952
                    paths.add(path)
953
            return paths
954
0.200.1374 by Jelmer Vernooij
Implement GitWorkingTree._directory_is_tree_reference.
955
    def _directory_is_tree_reference(self, path):
956
        # FIXME: Check .gitsubmodules for path
957
        return False
958
0.200.1716 by Jelmer Vernooij
Fix some more tests.
959
    def iter_child_entries(self, path, file_id=None):
960
        encoded_path = path.encode('utf-8')
0.200.1739 by Jelmer Vernooij
Fix iteration order for iter_child_entries.
961
        parent_id = self.path2id(path)
0.200.1738 by Jelmer Vernooij
Fix test_does_not_exist.
962
        found_any = False
0.200.1739 by Jelmer Vernooij
Fix iteration order for iter_child_entries.
963
        seen_children = set()
0.200.1716 by Jelmer Vernooij
Fix some more tests.
964
        for item_path, value in self.index.iteritems():
965
            if self.mapping.is_special_file(item_path):
966
                continue
0.200.1739 by Jelmer Vernooij
Fix iteration order for iter_child_entries.
967
            if not osutils.is_inside(encoded_path, item_path):
0.200.1716 by Jelmer Vernooij
Fix some more tests.
968
                continue
0.200.1738 by Jelmer Vernooij
Fix test_does_not_exist.
969
            found_any = True
0.200.1739 by Jelmer Vernooij
Fix iteration order for iter_child_entries.
970
            subpath = posixpath.relpath(item_path, encoded_path)
0.200.1716 by Jelmer Vernooij
Fix some more tests.
971
            if b'/' in subpath:
0.200.1739 by Jelmer Vernooij
Fix iteration order for iter_child_entries.
972
                dirname = subpath.split(b'/', 1)[0]
973
                file_ie = self._get_dir_ie(posixpath.join(path, dirname), parent_id)
974
            else:
975
                (parent, name) = posixpath.split(item_path)
976
                try:
977
                    file_ie = self._get_file_ie(name, item_path, value, parent_id)
978
                except IOError:
979
                    continue
0.200.1716 by Jelmer Vernooij
Fix some more tests.
980
            yield file_ie
0.200.1738 by Jelmer Vernooij
Fix test_does_not_exist.
981
        if not found_any:
982
            raise errors.NoSuchFile(path)
0.200.1716 by Jelmer Vernooij
Fix some more tests.
983
0.264.9 by Jelmer Vernooij
Implement basic GitWorkingTree.iter_entries_by_dir.
984
    def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):
0.200.1252 by Jelmer Vernooij
Support specific_file_ids in GitWorkingTree.iter_entries_by_dir.
985
        if yield_parents:
986
            raise NotImplementedError(self.iter_entries_by_dir)
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
987
        with self.lock_read():
988
            if specific_file_ids is not None:
0.200.1712 by Jelmer Vernooij
Add file_id prefix.
989
                specific_paths = []
990
                for file_id in specific_file_ids:
0.315.1 by Jelmer Vernooij
Allow file ids passed to Tree.iter_entries_by_dir to be None.
991
                    if file_id is None:
992
                        continue
0.309.1 by Jelmer Vernooij
Allow file-ids to Tree.iter_entries_by_dir to be absent.
993
                    try:
994
                        specific_paths.append(self.id2path(file_id))
995
                    except errors.NoSuchId:
996
                        pass
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
997
                if specific_paths in ([u""], []):
998
                    specific_paths = None
999
                else:
1000
                    specific_paths = set(specific_paths)
1001
            else:
0.200.1252 by Jelmer Vernooij
Support specific_file_ids in GitWorkingTree.iter_entries_by_dir.
1002
                specific_paths = None
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
1003
            root_ie = self._get_dir_ie(u"", None)
0.200.1740 by Jelmer Vernooij
Fix iter_entries_by_dir order.
1004
            ret = {}
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
1005
            if specific_paths is None:
0.200.1740 by Jelmer Vernooij
Fix iter_entries_by_dir order.
1006
                ret[(None, u"")] = root_ie
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
1007
            dir_ids = {u"": root_ie.file_id}
1008
            for path, value in self.index.iteritems():
1009
                if self.mapping.is_special_file(path):
1010
                    continue
1011
                path = path.decode("utf-8")
1012
                if specific_paths is not None and not path in specific_paths:
1013
                    continue
1014
                (parent, name) = posixpath.split(path)
1015
                try:
1016
                    file_ie = self._get_file_ie(name, path, value, None)
0.319.1 by Jelmer Vernooij
Support falling back on basis for executable bits.
1017
                except errors.NoSuchFile:
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
1018
                    continue
0.200.1730 by Jelmer Vernooij
Fix test_is_executable_dir.
1019
                if yield_parents or specific_file_ids is None:
1020
                    for (dir_path, dir_ie) in self._add_missing_parent_ids(parent,
1021
                            dir_ids):
0.200.1740 by Jelmer Vernooij
Fix iter_entries_by_dir order.
1022
                        ret[(posixpath.dirname(dir_path), dir_path)] = dir_ie
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
1023
                file_ie.parent_id = self.path2id(parent)
0.200.1740 by Jelmer Vernooij
Fix iter_entries_by_dir order.
1024
                ret[(posixpath.dirname(path), path)] = file_ie
1025
            return ((path, ie) for ((_, path), ie) in sorted(ret.items()))
0.264.9 by Jelmer Vernooij
Implement basic GitWorkingTree.iter_entries_by_dir.
1026
0.200.619 by Jelmer Vernooij
Provide dummy WorkingTree.conflicts() implementation rather than spending a lot of time not finding any conflicts.
1027
    def conflicts(self):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
1028
        with self.lock_read():
1029
            # FIXME:
1030
            return _mod_conflicts.ConflictList()
0.200.619 by Jelmer Vernooij
Provide dummy WorkingTree.conflicts() implementation rather than spending a lot of time not finding any conflicts.
1031
0.200.1705 by Jelmer Vernooij
Fix walkdirs.
1032
    def walkdirs(self, prefix=""):
0.324.1 by Jelmer Vernooij
initial work fixing walkdirs.
1033
        """Walk the directories of this tree.
1034
1035
        returns a generator which yields items in the form:
1036
                ((curren_directory_path, fileid),
1037
                 [(file1_path, file1_name, file1_kind, (lstat), file1_id,
1038
                   file1_kind), ... ])
1039
1040
        This API returns a generator, which is only valid during the current
1041
        tree transaction - within a single lock_read or lock_write duration.
1042
1043
        If the tree is not locked, it may cause an error to be raised,
1044
        depending on the tree implementation.
1045
        """
1046
        from bisect import bisect_left
1047
        import operator
1048
        disk_top = self.abspath(prefix)
1049
        if disk_top.endswith('/'):
1050
            disk_top = disk_top[:-1]
1051
        top_strip_len = len(disk_top) + 1
1052
        inventory_iterator = self._walkdirs(prefix)
1053
        disk_iterator = osutils.walkdirs(disk_top, prefix)
1054
        try:
1055
            current_disk = next(disk_iterator)
1056
            disk_finished = False
1057
        except OSError as e:
1058
            if not (e.errno == errno.ENOENT or
1059
                (sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
1060
                raise
1061
            current_disk = None
1062
            disk_finished = True
1063
        try:
1064
            current_inv = next(inventory_iterator)
1065
            inv_finished = False
1066
        except StopIteration:
1067
            current_inv = None
1068
            inv_finished = True
1069
        while not inv_finished or not disk_finished:
1070
            if current_disk:
1071
                ((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
1072
                    cur_disk_dir_content) = current_disk
1073
            else:
1074
                ((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
1075
                    cur_disk_dir_content) = ((None, None), None)
1076
            if not disk_finished:
1077
                # strip out .bzr dirs
1078
                if (cur_disk_dir_path_from_top[top_strip_len:] == '' and
1079
                    len(cur_disk_dir_content) > 0):
1080
                    # osutils.walkdirs can be made nicer -
1081
                    # yield the path-from-prefix rather than the pathjoined
1082
                    # value.
1083
                    bzrdir_loc = bisect_left(cur_disk_dir_content,
1084
                        ('.git', '.git'))
1085
                    if (bzrdir_loc < len(cur_disk_dir_content)
1086
                        and self.controldir.is_control_filename(
1087
                            cur_disk_dir_content[bzrdir_loc][0])):
1088
                        # we dont yield the contents of, or, .bzr itself.
1089
                        del cur_disk_dir_content[bzrdir_loc]
1090
            if inv_finished:
1091
                # everything is unknown
1092
                direction = 1
1093
            elif disk_finished:
1094
                # everything is missing
1095
                direction = -1
1096
            else:
1097
                direction = cmp(current_inv[0][0], cur_disk_dir_relpath)
1098
            if direction > 0:
1099
                # disk is before inventory - unknown
1100
                dirblock = [(relpath, basename, kind, stat, None, None) for
1101
                    relpath, basename, kind, stat, top_path in
1102
                    cur_disk_dir_content]
1103
                yield (cur_disk_dir_relpath, None), dirblock
1104
                try:
1105
                    current_disk = next(disk_iterator)
1106
                except StopIteration:
1107
                    disk_finished = True
1108
            elif direction < 0:
1109
                # inventory is before disk - missing.
1110
                dirblock = [(relpath, basename, 'unknown', None, fileid, kind)
1111
                    for relpath, basename, dkind, stat, fileid, kind in
1112
                    current_inv[1]]
1113
                yield (current_inv[0][0], current_inv[0][1]), dirblock
1114
                try:
1115
                    current_inv = next(inventory_iterator)
1116
                except StopIteration:
1117
                    inv_finished = True
1118
            else:
1119
                # versioned present directory
1120
                # merge the inventory and disk data together
1121
                dirblock = []
1122
                for relpath, subiterator in itertools.groupby(sorted(
1123
                    current_inv[1] + cur_disk_dir_content,
1124
                    key=operator.itemgetter(0)), operator.itemgetter(1)):
1125
                    path_elements = list(subiterator)
1126
                    if len(path_elements) == 2:
1127
                        inv_row, disk_row = path_elements
1128
                        # versioned, present file
1129
                        dirblock.append((inv_row[0],
1130
                            inv_row[1], disk_row[2],
1131
                            disk_row[3], inv_row[4],
1132
                            inv_row[5]))
1133
                    elif len(path_elements[0]) == 5:
1134
                        # unknown disk file
1135
                        dirblock.append((path_elements[0][0],
1136
                            path_elements[0][1], path_elements[0][2],
1137
                            path_elements[0][3], None, None))
1138
                    elif len(path_elements[0]) == 6:
1139
                        # versioned, absent file.
1140
                        dirblock.append((path_elements[0][0],
1141
                            path_elements[0][1], 'unknown', None,
1142
                            path_elements[0][4], path_elements[0][5]))
1143
                    else:
1144
                        raise NotImplementedError('unreachable code')
1145
                yield current_inv[0], dirblock
1146
                try:
1147
                    current_inv = next(inventory_iterator)
1148
                except StopIteration:
1149
                    inv_finished = True
1150
                try:
1151
                    current_disk = next(disk_iterator)
1152
                except StopIteration:
1153
                    disk_finished = True
1154
1155
    def _walkdirs(self, prefix=""):
0.200.1210 by Jelmer Vernooij
Implement GitWorkingTree._walkdirs.
1156
        if prefix != "":
1157
            prefix += "/"
1158
        per_dir = defaultdict(list)
0.325.2 by Jelmer Vernooij
Handle root in walkdirs.
1159
        if prefix == "":
1160
            per_dir[('', self.get_root_id())] = []
0.200.1210 by Jelmer Vernooij
Implement GitWorkingTree._walkdirs.
1161
        for path, value in self.index.iteritems():
0.200.1328 by Jelmer Vernooij
More test fixes.
1162
            if self.mapping.is_special_file(path):
1163
                continue
0.200.1210 by Jelmer Vernooij
Implement GitWorkingTree._walkdirs.
1164
            if not path.startswith(prefix):
1165
                continue
1166
            (dirname, child_name) = posixpath.split(path)
1167
            dirname = dirname.decode("utf-8")
1168
            dir_file_id = self.path2id(dirname)
1169
            assert isinstance(value, tuple) and len(value) == 10
1170
            per_dir[(dirname, dir_file_id)].append(
1171
                (path.decode("utf-8"), child_name.decode("utf-8"),
0.324.1 by Jelmer Vernooij
initial work fixing walkdirs.
1172
                mode_kind(value.mode), None,
0.200.1210 by Jelmer Vernooij
Implement GitWorkingTree._walkdirs.
1173
                self.path2id(path.decode("utf-8")),
0.293.1 by Jelmer Vernooij
Fix walkdirs handling of unknown entries, mode.
1174
                mode_kind(value.mode)))
0.324.1 by Jelmer Vernooij
initial work fixing walkdirs.
1175
        return ((k, sorted(v)) for (k, v) in per_dir.iteritems())
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
1176
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
1177
    def _lookup_entry(self, path, update_index=False):
0.200.1543 by Jelmer Vernooij
Support symlinks.
1178
        assert type(path) == str
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
1179
        entry = self.index[path]
1180
        index_mode = entry[-6]
1181
        index_sha = entry[-2]
0.200.1741 by Jelmer Vernooij
Fix opentree tests.
1182
        disk_path = self.abspath(path.decode('utf-8')).encode(
1183
            osutils._fs_enc)
0.284.1 by Jelmer Vernooij
Raise KeyError when file was removed.
1184
        try:
1185
            disk_stat = os.lstat(disk_path)
1186
        except OSError, (num, msg):
1187
            if num in (errno.EISDIR, errno.ENOENT):
1188
                raise KeyError(path)
1189
            raise
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
1190
        disk_mtime = disk_stat.st_mtime
1191
        if isinstance(entry[1], tuple):
1192
            index_mtime = entry[1][0]
1193
        else:
1194
            index_mtime = int(entry[1])
1195
        mtime_delta = (disk_mtime - index_mtime)
1196
        disk_mode = cleanup_mode(disk_stat.st_mode)
1197
        if mtime_delta > 0 or disk_mode != index_mode:
1198
            if stat.S_ISDIR(disk_mode):
1199
                try:
1200
                    subrepo = Repo(disk_path)
1201
                except NotGitRepository:
1202
                    return (None, None)
1203
                else:
1204
                    disk_mode = S_IFGITLINK
1205
                    git_id = subrepo.head()
0.200.1543 by Jelmer Vernooij
Support symlinks.
1206
            elif stat.S_ISLNK(disk_mode):
0.200.1715 by Jelmer Vernooij
Fix some more tests.
1207
                blob = Blob.from_string(os.readlink(disk_path))
0.200.1543 by Jelmer Vernooij
Support symlinks.
1208
                git_id = blob.id
1209
            elif stat.S_ISREG(disk_mode):
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
1210
                with open(disk_path, 'r') as f:
1211
                    blob = Blob.from_string(f.read())
1212
                git_id = blob.id
0.200.1543 by Jelmer Vernooij
Support symlinks.
1213
            else:
1214
                raise AssertionError
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
1215
            if update_index:
1216
                flags = 0 # FIXME
0.200.1545 by Jelmer Vernooij
Some more test fixes.
1217
                self.index[path] = index_entry_from_stat(disk_stat, git_id, flags, disk_mode)
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
1218
            return (git_id, disk_mode)
1219
        return (index_sha, index_mode)
1220
0.200.1677 by Jelmer Vernooij
Mark shelving as unsupported.
1221
    def get_shelf_manager(self):
0.200.1729 by Jelmer Vernooij
ShelvingUnsupported doesn't take an argument.
1222
        raise workingtree.ShelvingUnsupported()
0.200.1677 by Jelmer Vernooij
Mark shelving as unsupported.
1223
0.200.1678 by Jelmer Vernooij
Fix tests.
1224
    def store_uncommitted(self):
1225
        raise errors.StoringUncommittedNotSupported(self)
1226
0.200.1703 by Jelmer Vernooij
Implement apply_inventory_delta.
1227
    def apply_inventory_delta(self, changes):
1228
        for (old_path, new_path, file_id, ie) in changes:
1229
            if old_path is not None:
1230
                del self.index[old_path.encode('utf-8')]
0.200.1772 by Jelmer Vernooij
Fix handling of unversioned file in get_file_sha1.
1231
                self._versioned_dirs = None
0.200.1703 by Jelmer Vernooij
Implement apply_inventory_delta.
1232
            if new_path is not None and ie.kind != 'directory':
1233
                self._index_add_entry(new_path, ie.kind)
0.316.2 by Jelmer Vernooij
Flush after modifying index.
1234
        self.flush()
0.200.1703 by Jelmer Vernooij
Implement apply_inventory_delta.
1235
0.200.1756 by Jelmer Vernooij
Initial work on annotate support.
1236
    def annotate_iter(self, path, file_id=None,
1237
                      default_revision=_mod_revision.CURRENT_REVISION):
1238
        """See Tree.annotate_iter
1239
1240
        This implementation will use the basis tree implementation if possible.
1241
        Lines not in the basis are attributed to CURRENT_REVISION
1242
1243
        If there are pending merges, lines added by those merges will be
1244
        incorrectly attributed to CURRENT_REVISION (but after committing, the
1245
        attribution will be correct).
1246
        """
1247
        with self.lock_read():
1248
            maybe_file_parent_keys = []
1249
            for parent_id in self.get_parent_ids():
1250
                try:
1251
                    parent_tree = self.revision_tree(parent_id)
1252
                except errors.NoSuchRevisionInTree:
1253
                    parent_tree = self.branch.repository.revision_tree(
1254
                            parent_id)
1255
                with parent_tree.lock_read():
1256
                    # TODO(jelmer): Use rename/copy tracker to find path name in parent
1257
                    parent_path = path
1258
                    try:
1259
                        kind = parent_tree.kind(parent_path)
1260
                    except errors.NoSuchFile:
1261
                        continue
1262
                    if kind != 'file':
1263
                        # Note: this is slightly unnecessary, because symlinks and
1264
                        # directories have a "text" which is the empty text, and we
1265
                        # know that won't mess up annotations. But it seems cleaner
1266
                        continue
1267
                    parent_text_key = (
1268
                        parent_path,
1269
                        parent_tree.get_file_revision(parent_path))
1270
                    if parent_text_key not in maybe_file_parent_keys:
1271
                        maybe_file_parent_keys.append(parent_text_key)
1272
            graph = self.branch.repository.get_file_graph()
1273
            heads = graph.heads(maybe_file_parent_keys)
1274
            file_parent_keys = []
1275
            for key in maybe_file_parent_keys:
1276
                if key in heads:
1277
                    file_parent_keys.append(key)
1278
1279
            # Now we have the parents of this content
1280
            from breezy.annotate import Annotator
1281
            from .annotate import AnnotateProvider
1282
            annotator = Annotator(AnnotateProvider(
1283
                self.branch.repository._file_change_scanner))
1284
            text = self.get_file_text(path)
1285
            this_key = (path, default_revision)
1286
            annotator.add_special_text(this_key, file_parent_keys, text)
1287
            annotations = [(key[-1], line)
1288
                           for key, line in annotator.annotate_flat(this_key)]
1289
            return annotations
1290
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
1291
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
1292
class GitWorkingTreeFormat(workingtree.WorkingTreeFormat):
1293
0.200.1206 by Jelmer Vernooij
Implement GitWorkingTree.all_file_ids.
1294
    _tree_class = GitWorkingTree
1295
0.200.1295 by Jelmer Vernooij
Mark working trees as not supporting directories.
1296
    supports_versioned_directories = False
1297
0.200.1661 by Jelmer Vernooij
Set supports_setting_file_ids to False.
1298
    supports_setting_file_ids = False
1299
0.200.1677 by Jelmer Vernooij
Mark shelving as unsupported.
1300
    supports_store_uncommitted = False
1301
0.200.1723 by Jelmer Vernooij
Set supports_leftmost_parent_id_as_ghost property.
1302
    supports_leftmost_parent_id_as_ghost = False
1303
0.200.1779 by Jelmer Vernooij
Actually store git revision ids rather than bzr revision ids.
1304
    supports_righthand_parent_id_as_ghost = False
1305
0.200.1768 by Jelmer Vernooij
Fix handling of normalized filenames.
1306
    requires_normalized_unicode_filenames = True
1307
0.200.656 by Jelmer Vernooij
Implement GitWorkingTreeFormat._matchingbzrdir.
1308
    @property
0.200.1665 by Jelmer Vernooij
Rename _matchingbzrdir to _matchingcnotroldir.
1309
    def _matchingcontroldir(self):
0.200.1641 by Jelmer Vernooij
Use relative imports where possible.
1310
        from .dir import LocalGitControlDirFormat
0.200.1013 by Jelmer Vernooij
More renames.
1311
        return LocalGitControlDirFormat()
0.200.656 by Jelmer Vernooij
Implement GitWorkingTreeFormat._matchingbzrdir.
1312
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
1313
    def get_format_description(self):
1314
        return "Git Working Tree"
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
1315
0.200.1648 by Jelmer Vernooij
Fix compatibility with newer versions of breezy.
1316
    def initialize(self, a_controldir, revision_id=None, from_branch=None,
0.200.1096 by Jelmer Vernooij
Implement GitWorkingTreeFormat.initialize.
1317
                   accelerator_tree=None, hardlink=False):
1318
        """See WorkingTreeFormat.initialize()."""
0.200.1648 by Jelmer Vernooij
Fix compatibility with newer versions of breezy.
1319
        if not isinstance(a_controldir, LocalGitDir):
1320
            raise errors.IncompatibleFormat(self, a_controldir)
1321
        index = Index(a_controldir.root_transport.local_abspath(".git/index"))
0.200.1096 by Jelmer Vernooij
Implement GitWorkingTreeFormat.initialize.
1322
        index.write()
0.308.1 by Jelmer Vernooij
Set revision id if specified to WorkingTreeFormat.initialize.
1323
        branch = a_controldir.open_branch()
1324
        if revision_id is not None:
1325
            branch.set_last_revision(revision_id)
0.200.1680 by Jelmer Vernooij
Fix repo locks.
1326
        wt = GitWorkingTree(
0.308.1 by Jelmer Vernooij
Set revision id if specified to WorkingTreeFormat.initialize.
1327
                a_controldir, a_controldir.open_repository(), branch, index)
0.200.1680 by Jelmer Vernooij
Fix repo locks.
1328
        for hook in MutableTree.hooks['post_build_tree']:
1329
            hook(wt)
1330
        return wt
0.200.1096 by Jelmer Vernooij
Implement GitWorkingTreeFormat.initialize.
1331
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
1332
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
1333
class InterIndexGitTree(InterGitTrees):
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
1334
    """InterTree that works between a Git revision tree and an index."""
1335
1336
    def __init__(self, source, target):
1337
        super(InterIndexGitTree, self).__init__(source, target)
1338
        self._index = target.index
1339
1340
    @classmethod
1341
    def is_compatible(cls, source, target):
0.200.1641 by Jelmer Vernooij
Use relative imports where possible.
1342
        from .repository import GitRevisionTree
0.200.1636 by Jelmer Vernooij
Some formatting fixes.
1343
        return (isinstance(source, GitRevisionTree) and
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
1344
                isinstance(target, GitWorkingTree))
1345
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
1346
    def _iter_git_changes(self, want_unchanged=False, specific_files=None,
1347
            require_versioned=False, include_root=False):
1348
        # TODO(jelmer): Handle include_root
1349
        # TODO(jelmer): Handle require_versioned
1350
        # TODO(jelmer): Restrict to specific_files, for performance reasons.
1351
        with self.lock_read():
0.200.1754 by Jelmer Vernooij
Avoid updating index when just comparing trees.
1352
            return changes_between_git_tree_and_working_copy(
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
1353
                self.source.store, self.source.tree,
1354
                self.target, want_unchanged=want_unchanged)
1355
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
1356
    def compare(self, want_unchanged=False, specific_files=None,
1357
                extra_trees=None, require_versioned=False, include_root=False,
1358
                want_unversioned=False):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
1359
        with self.lock_read():
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
1360
            changes = self._iter_git_changes(
1361
                    want_unchanged=want_unchanged,
1362
                    specific_files=specific_files,
1363
                    require_versioned=require_versioned,
1364
                    include_root=include_root)
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
1365
            source_fileid_map = self.source._fileid_map
1366
            target_fileid_map = self.target._fileid_map
1367
            ret = tree_delta_from_git_changes(changes, self.target.mapping,
1368
                (source_fileid_map, target_fileid_map),
0.287.6 by Jelmer Vernooij
Fix some more tests.
1369
                specific_files=specific_files, require_versioned=require_versioned,
1370
                include_root=include_root)
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
1371
            if want_unversioned:
1372
                for e in self.target.extras():
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
1373
                    ret.unversioned.append(
0.200.1732 by Jelmer Vernooij
Fix ignore.
1374
                        (osutils.normalized_filename(e)[0], None,
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
1375
                        osutils.file_kind(self.target.abspath(e))))
1376
            return ret
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
1377
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
1378
    def iter_changes(self, include_unchanged=False, specific_files=None,
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
1379
                     pb=None, extra_trees=[], require_versioned=True,
1380
                     want_unversioned=False):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
1381
        with self.lock_read():
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
1382
            changes = self._iter_git_changes(
1383
                    want_unchanged=include_unchanged,
1384
                    specific_files=specific_files,
1385
                    require_versioned=require_versioned)
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
1386
            if want_unversioned:
1387
                changes = itertools.chain(
1388
                        changes,
1389
                        untracked_changes(self.target))
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
1390
            return changes_from_git_changes(
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
1391
                    changes, self.target.mapping,
1392
                    specific_files=specific_files)
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
1393
0.200.1179 by Jelmer Vernooij
Avoid using verifiers for natively imported revisions, save a lot of time.
1394
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
1395
tree.InterTree.register_optimiser(InterIndexGitTree)
0.200.1529 by Jelmer Vernooij
Add changes_between_tree_and_index.
1396
1397
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
1398
def untracked_changes(tree):
1399
    for e in tree.extras():
1400
        ap = tree.abspath(e)
1401
        st = os.stat(ap)
1402
        try:
1403
            np, accessible  = osutils.normalized_filename(e)
1404
        except UnicodeDecodeError:
1405
            raise errors.BadFilenameEncoding(
1406
                e, osutils._fs_enc)
0.323.1 by Jelmer Vernooij
Fix iter_changes of untracked changes.
1407
        yield ((None, np), (None, st.st_mode),
1408
               (None, blob_from_path_and_stat(ap.encode('utf-8'), st).id))
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
1409
1410
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
1411
def changes_between_git_tree_and_index(store, from_tree_sha, target,
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
1412
        want_unchanged=False, update_index=False):
0.200.1529 by Jelmer Vernooij
Add changes_between_tree_and_index.
1413
    """Determine the changes between a git tree and a working tree with index.
1414
1415
    """
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
1416
    to_tree_sha = target.index.commit(store)
0.200.1754 by Jelmer Vernooij
Avoid updating index when just comparing trees.
1417
    return store.tree_changes(from_tree_sha, to_tree_sha, include_trees=True,
1418
            want_unchanged=want_unchanged)
1419
1420
1421
def changes_between_git_tree_and_working_copy(store, from_tree_sha, target,
1422
        want_unchanged=False, update_index=False):
1423
    """Determine the changes between a git tree and a working tree with index.
1424
1425
    """
1426
    blobs = iter_fresh_blobs(target.index, target.abspath('.').encode(sys.getfilesystemencoding()))
1427
    to_tree_sha = commit_tree(store, blobs)
0.287.3 by Jelmer Vernooij
Some improvements to changes iterator.
1428
    return store.tree_changes(from_tree_sha, to_tree_sha, include_trees=True,
1429
            want_unchanged=want_unchanged)