/brz/remove-bazaar

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