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