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