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