/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.264.10 by Jelmer Vernooij
Yield inventory entries.
1
# Copyright (C) 2008-2011 Jelmer Vernooij <jelmer@samba.org>
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
0.200.381 by Jelmer Vernooij
Support working trees properly, status and ls.
17
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
18
"""An adapter between a Git index and a Bazaar Working Tree"""
19
0.200.1594 by Jelmer Vernooij
Use absolute_import everywhere.
20
from __future__ import absolute_import
0.200.381 by Jelmer Vernooij
Support working trees properly, status and ls.
21
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
22
import itertools
0.200.385 by Jelmer Vernooij
Cope with removed files.
23
from cStringIO import (
24
    StringIO,
25
    )
0.200.1210 by Jelmer Vernooij
Implement GitWorkingTree._walkdirs.
26
from collections import defaultdict
0.239.4 by Jelmer Vernooij
Cope with nonexistent files and directories in get_file_sha1.
27
import errno
0.200.1538 by Jelmer Vernooij
More work on tree-reference support.
28
from dulwich.errors import NotGitRepository
0.200.1655 by Jelmer Vernooij
Basic support for git ignores.
29
from dulwich.ignore import (
0.200.1658 by Jelmer Vernooij
Fix handling of ignores - return patterns that matched.
30
    IgnoreFilterManager,
0.200.1655 by Jelmer Vernooij
Basic support for git ignores.
31
    )
0.200.1096 by Jelmer Vernooij
Implement GitWorkingTreeFormat.initialize.
32
from dulwich.index import (
33
    Index,
0.200.1531 by Jelmer Vernooij
Don't trust index contents - verify against file timestamps.
34
    changes_from_tree,
35
    cleanup_mode,
36
    index_entry_from_stat,
0.200.1096 by Jelmer Vernooij
Implement GitWorkingTreeFormat.initialize.
37
    )
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
38
from dulwich.object_store import (
39
    tree_lookup_path,
40
    )
0.200.383 by Jelmer Vernooij
Simplify, support rewriting index based on inventory.
41
from dulwich.objects import (
42
    Blob,
0.200.1538 by Jelmer Vernooij
More work on tree-reference support.
43
    S_IFGITLINK,
0.200.948 by Jelmer Vernooij
Cope with empty inventories.
44
    ZERO_SHA,
45
    )
0.200.1538 by Jelmer Vernooij
More work on tree-reference support.
46
from dulwich.repo import Repo
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
47
import os
0.264.10 by Jelmer Vernooij
Yield inventory entries.
48
import posixpath
0.200.1655 by Jelmer Vernooij
Basic support for git ignores.
49
import re
0.200.384 by Jelmer Vernooij
Fix reading of inventory from index.
50
import stat
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
51
import sys
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
52
0.200.1641 by Jelmer Vernooij
Use relative imports where possible.
53
from ... import (
0.200.382 by Jelmer Vernooij
Support flushing index.
54
    errors,
0.262.1 by Jelmer Vernooij
Fix WorkingTree.conflicts().
55
    conflicts as _mod_conflicts,
0.200.1655 by Jelmer Vernooij
Basic support for git ignores.
56
    globbing,
0.200.409 by Jelmer Vernooij
Support parsing .gitignore.
57
    ignores,
0.200.1476 by Jelmer Vernooij
Cope with working tree refactoring.
58
    lock,
0.200.381 by Jelmer Vernooij
Support working trees properly, status and ls.
59
    osutils,
0.200.1720 by Jelmer Vernooij
Fix handling of pending merges.
60
    revision as _mod_revision,
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
61
    trace,
0.200.519 by Jelmer Vernooij
Move imports down, might not be available in older bzr-git versions.
62
    tree,
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
63
    workingtree,
64
    )
0.200.1648 by Jelmer Vernooij
Fix compatibility with newer versions of breezy.
65
from ...bzr import (
66
    inventory,
67
    )
0.200.1680 by Jelmer Vernooij
Fix repo locks.
68
from ...mutabletree import (
69
    MutableTree,
70
    )
0.200.1641 by Jelmer Vernooij
Use relative imports where possible.
71
72
73
from .dir import (
0.200.1096 by Jelmer Vernooij
Implement GitWorkingTreeFormat.initialize.
74
    LocalGitDir,
75
    )
0.200.1641 by Jelmer Vernooij
Use relative imports where possible.
76
from .tree import (
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
77
    changes_from_git_changes,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
78
    tree_delta_from_git_changes,
79
    )
0.200.1641 by Jelmer Vernooij
Use relative imports where possible.
80
from .mapping import (
0.200.971 by Chadrik
Fix 'bzr status' after 'bzr add' in native git working trees.
81
    GitFileIdMap,
0.264.10 by Jelmer Vernooij
Yield inventory entries.
82
    mode_kind,
0.200.971 by Chadrik
Fix 'bzr status' after 'bzr add' in native git working trees.
83
    )
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
84
0.200.409 by Jelmer Vernooij
Support parsing .gitignore.
85
IGNORE_FILENAME = ".gitignore"
86
87
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
88
class GitWorkingTree(workingtree.WorkingTree):
89
    """A Git working tree."""
90
0.200.1648 by Jelmer Vernooij
Fix compatibility with newer versions of breezy.
91
    def __init__(self, controldir, repo, branch, index):
0.200.1741 by Jelmer Vernooij
Fix opentree tests.
92
        basedir = controldir.root_transport.local_abspath('.')
93
        self.basedir = osutils.realpath(basedir)
0.200.1648 by Jelmer Vernooij
Fix compatibility with newer versions of breezy.
94
        self.controldir = controldir
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
95
        self.repository = repo
0.200.1205 by Jelmer Vernooij
Implement GitWorkingTree.stored_kind.
96
        self.store = self.repository._git.object_store
0.200.384 by Jelmer Vernooij
Fix reading of inventory from index.
97
        self.mapping = self.repository.get_mapping()
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
98
        self._branch = branch
0.200.1648 by Jelmer Vernooij
Fix compatibility with newer versions of breezy.
99
        self._transport = controldir.transport
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
100
        self._format = GitWorkingTreeFormat()
0.200.803 by Jelmer Vernooij
Default to non-bare repositories when initializing a control directory.
101
        self.index = index
0.200.1242 by Jelmer Vernooij
Support directories better.
102
        self._versioned_dirs = None
0.200.239 by Jelmer Vernooij
Provide views.
103
        self.views = self._make_views()
0.200.1173 by Jelmer Vernooij
Provide GitWorkingTree._rules_searcher.
104
        self._rules_searcher = None
0.200.381 by Jelmer Vernooij
Support working trees properly, status and ls.
105
        self._detect_case_handling()
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
106
        self._reset_data()
107
        self._fileid_map = self._basis_fileid_map.copy()
0.200.1476 by Jelmer Vernooij
Cope with working tree refactoring.
108
        self._lock_mode = None
109
        self._lock_count = 0
110
0.200.1650 by Jelmer Vernooij
Implement GitWorkingTree.supports_tree_reference.
111
    def supports_tree_reference(self):
112
        return False
113
0.200.1476 by Jelmer Vernooij
Cope with working tree refactoring.
114
    def lock_read(self):
115
        """Lock the repository for read operations.
116
0.200.1646 by Jelmer Vernooij
Rename bzrlib to breezy.
117
        :return: A breezy.lock.LogicalLockResult.
0.200.1476 by Jelmer Vernooij
Cope with working tree refactoring.
118
        """
119
        if not self._lock_mode:
120
            self._lock_mode = 'r'
121
            self._lock_count = 1
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
122
            self.index.read()
0.200.1476 by Jelmer Vernooij
Cope with working tree refactoring.
123
        else:
124
            self._lock_count += 1
125
        self.branch.lock_read()
126
        return lock.LogicalLockResult(self.unlock)
127
0.200.1477 by Jelmer Vernooij
Implement GitWorkingTree.lock_tree_write.
128
    def lock_tree_write(self):
129
        if not self._lock_mode:
130
            self._lock_mode = 'w'
131
            self._lock_count = 1
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
132
            self.index.read()
0.200.1477 by Jelmer Vernooij
Implement GitWorkingTree.lock_tree_write.
133
        elif self._lock_mode == 'r':
134
            raise errors.ReadOnlyError(self)
135
        else:
136
            self._lock_count +=1
137
        self.branch.lock_read()
138
        return lock.LogicalLockResult(self.unlock)
139
0.200.1476 by Jelmer Vernooij
Cope with working tree refactoring.
140
    def lock_write(self, token=None):
141
        if not self._lock_mode:
142
            self._lock_mode = 'w'
143
            self._lock_count = 1
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
144
            self.index.read()
0.200.1476 by Jelmer Vernooij
Cope with working tree refactoring.
145
        elif self._lock_mode == 'r':
146
            raise errors.ReadOnlyError(self)
147
        else:
148
            self._lock_count +=1
149
        self.branch.lock_write()
150
        return lock.LogicalLockResult(self.unlock)
151
152
    def is_locked(self):
153
        return self._lock_count >= 1
154
155
    def get_physical_lock_status(self):
156
        return False
157
158
    def unlock(self):
159
        if not self._lock_count:
160
            return lock.cant_unlock_not_held(self)
0.200.1530 by Jelmer Vernooij
Fix lock order.
161
        self.branch.unlock()
0.200.1476 by Jelmer Vernooij
Cope with working tree refactoring.
162
        self._cleanup()
163
        self._lock_count -= 1
164
        if self._lock_count > 0:
165
            return
166
        self._lock_mode = None
0.200.173 by Jelmer Vernooij
Merge changes, open index.
167
0.200.1658 by Jelmer Vernooij
Fix handling of ignores - return patterns that matched.
168
    def _cleanup(self):
169
        pass
170
0.200.1322 by Jelmer Vernooij
Add case detection.
171
    def _detect_case_handling(self):
172
        try:
173
            self._transport.stat(".git/cOnFiG")
174
        except errors.NoSuchFile:
175
            self.case_sensitive = True
176
        else:
177
            self.case_sensitive = False
178
0.200.1315 by Jelmer Vernooij
Implement WorkingTree.merge_modified.
179
    def merge_modified(self):
180
        return {}
181
0.200.1696 by Jelmer Vernooij
Fix set_merge_modified.
182
    def set_merge_modified(self, modified_hashes):
0.200.1690 by Jelmer Vernooij
Implement WorkingTree.set_merge_modified.
183
        # TODO(jelmer)
184
        pass
185
0.200.1220 by Jelmer Vernooij
Support set_parent_trees.
186
    def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
187
        self.set_parent_ids([p for p, t in parents_list])
188
0.200.1720 by Jelmer Vernooij
Fix handling of pending merges.
189
    def _set_merges_from_parent_ids(self, parent_ids):
190
        merges = parent_ids[1:]
191
        self.control_transport.put_bytes('MERGE_HEAD', '\n'.join(merges),
192
            mode=self.controldir._get_file_mode())
193
194
    def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
195
        """Set the parent ids to revision_ids.
196
197
        See also set_parent_trees. This api will try to retrieve the tree data
198
        for each element of revision_ids from the trees repository. If you have
199
        tree data already available, it is more efficient to use
200
        set_parent_trees rather than set_parent_ids. set_parent_ids is however
201
        an easier API to use.
202
203
        :param revision_ids: The revision_ids to set as the parent ids of this
204
            working tree. Any of these may be ghosts.
205
        """
206
        with self.lock_tree_write():
207
            self._check_parents_for_ghosts(revision_ids,
208
                allow_leftmost_as_ghost=allow_leftmost_as_ghost)
209
            for revision_id in revision_ids:
210
                _mod_revision.check_not_reserved_id(revision_id)
211
212
            revision_ids = self._filter_parent_ids_by_ancestry(revision_ids)
213
214
            if len(revision_ids) > 0:
215
                self.set_last_revision(revision_ids[0])
216
            else:
217
                self.set_last_revision(_mod_revision.NULL_REVISION)
218
219
            self._set_merges_from_parent_ids(revision_ids)
220
221
    def get_parent_ids(self):
222
        """See Tree.get_parent_ids.
223
224
        This implementation reads the pending merges list and last_revision
225
        value and uses that to decide what the parents list should be.
226
        """
227
        last_rev = _mod_revision.ensure_null(self._last_revision())
228
        if _mod_revision.NULL_REVISION == last_rev:
229
            parents = []
230
        else:
231
            parents = [last_rev]
232
        try:
233
            merges_bytes = self.control_transport.get_bytes('MERGE_HEAD')
234
        except errors.NoSuchFile:
235
            pass
236
        else:
237
            for l in osutils.split_lines(merges_bytes):
238
                revision_id = l.rstrip('\n')
239
                parents.append(revision_id)
240
        return parents
241
0.200.1599 by Jelmer Vernooij
Implement GitWorkingTree.iter_children.
242
    def iter_children(self, file_id):
243
        dpath = self.id2path(file_id) + "/"
244
        if dpath in self.index:
245
            return
246
        for path in self.index:
247
            if not path.startswith(dpath):
248
                continue
249
            if "/" in path[len(dpath):]:
250
                # Not a direct child but something further down
251
                continue
252
            yield self.path2id(path)
253
0.200.1663 by Jelmer Vernooij
Raise SettingFileIdUnsupported
254
    def _index_add_entry(self, path, kind):
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
255
        assert self._lock_mode is not None
0.200.1206 by Jelmer Vernooij
Implement GitWorkingTree.all_file_ids.
256
        assert isinstance(path, basestring)
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
257
        if kind == "directory":
258
            # Git indexes don't contain directories
259
            return
260
        if kind == "file":
261
            blob = Blob()
262
            try:
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
263
                file, stat_val = self.get_file_with_stat(path)
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
264
            except (errors.NoSuchFile, IOError):
265
                # TODO: Rather than come up with something here, use the old index
266
                file = StringIO()
0.265.1 by Martin
Don't import posix module, the os wrapper exists for portability
267
                stat_val = os.stat_result(
268
                    (stat.S_IFREG | 0644, 0, 0, 0, 0, 0, 0, 0, 0, 0))
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
269
            blob.set_raw_string(file.read())
270
        elif kind == "symlink":
271
            blob = Blob()
272
            try:
273
                stat_val = os.lstat(self.abspath(path))
274
            except (errors.NoSuchFile, OSError):
0.200.1636 by Jelmer Vernooij
Some formatting fixes.
275
                # TODO: Rather than come up with something here, use the
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
276
                # old index
0.265.1 by Martin
Don't import posix module, the os wrapper exists for portability
277
                stat_val = os.stat_result(
278
                    (stat.S_IFLNK, 0, 0, 0, 0, 0, 0, 0, 0, 0))
0.200.1321 by Jelmer Vernooij
More fixes for compatibility with bzr.dev testsuite.
279
            blob.set_raw_string(
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
280
                self.get_symlink_target(path).encode("utf-8"))
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
281
        else:
282
            raise AssertionError("unknown kind '%s'" % kind)
283
        # Add object to the repository if it didn't exist yet
0.200.1205 by Jelmer Vernooij
Implement GitWorkingTree.stored_kind.
284
        if not blob.id in self.store:
285
            self.store.add_object(blob)
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
286
        # Add an entry to the index or update the existing entry
287
        flags = 0 # FIXME
0.200.1242 by Jelmer Vernooij
Support directories better.
288
        encoded_path = path.encode("utf-8")
0.200.1531 by Jelmer Vernooij
Don't trust index contents - verify against file timestamps.
289
        self.index[encoded_path] = index_entry_from_stat(
290
            stat_val, blob.id, flags)
0.200.1242 by Jelmer Vernooij
Support directories better.
291
        if self._versioned_dirs is not None:
292
            self._ensure_versioned_dir(encoded_path)
293
294
    def _ensure_versioned_dir(self, dirname):
0.200.1249 by Jelmer Vernooij
Fix file id for tree root
295
        if dirname in self._versioned_dirs:
0.200.1242 by Jelmer Vernooij
Support directories better.
296
            return
0.200.1249 by Jelmer Vernooij
Fix file id for tree root
297
        if dirname != "":
298
            self._ensure_versioned_dir(posixpath.dirname(dirname))
0.200.1242 by Jelmer Vernooij
Support directories better.
299
        self._versioned_dirs.add(dirname)
300
301
    def _load_dirs(self):
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
302
        assert self._lock_mode is not None
0.200.1242 by Jelmer Vernooij
Support directories better.
303
        self._versioned_dirs = set()
304
        for p in self.index:
305
            self._ensure_versioned_dir(posixpath.dirname(p))
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
306
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
307
    def _unversion_path(self, path):
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
308
        assert self._lock_mode is not None
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
309
        encoded_path = path.encode("utf-8")
310
        try:
311
            del self.index[encoded_path]
312
        except KeyError:
313
            # A directory, perhaps?
314
            for p in list(self.index):
0.200.1692 by Jelmer Vernooij
Mark three more tests as xfail.
315
                if p.startswith(encoded_path+b"/"):
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
316
                    del self.index[p]
0.200.1242 by Jelmer Vernooij
Support directories better.
317
        # FIXME: remove empty directories
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
318
0.285.8 by Jelmer Vernooij
Fix more tests for swapped arguments.
319
    def unversion(self, paths, file_ids=None):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
320
        with self.lock_tree_write():
0.200.1690 by Jelmer Vernooij
Implement WorkingTree.set_merge_modified.
321
            for path in paths:
0.200.1742 by Jelmer Vernooij
Fix some unversion tests.
322
                encoded_path = path.encode("utf-8")
323
                try:
324
                    del self.index[encoded_path]
325
                except KeyError:
326
                    if not self._has_dir(path):
327
                        raise errors.NoSuchFile(path)
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
328
            self.flush()
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
329
0.200.1678 by Jelmer Vernooij
Fix tests.
330
    def update_basis_by_delta(self, revid, delta):
331
        # TODO(jelmer): This shouldn't be called, it's inventory specific.
332
        pass
333
0.200.1243 by Jelmer Vernooij
Implement WorkingTree.check_state.
334
    def check_state(self):
335
        """Check that the working state is/isn't valid."""
336
        pass
337
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
338
    def remove(self, files, verbose=False, to_file=None, keep_files=True,
339
        force=False):
340
        """Remove nominated files from the working tree metadata.
341
342
        :param files: File paths relative to the basedir.
343
        :param keep_files: If true, the files will also be kept.
344
        :param force: Delete files and directories, even if they are changed
345
            and even if the directories are not empty.
346
        """
347
        if isinstance(files, basestring):
348
            files = [files]
349
350
        if to_file is None:
351
            to_file = sys.stdout
352
0.200.1735 by Jelmer Vernooij
Fix remove tests.
353
        files = list(files)
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
354
355
        if len(files) == 0:
356
            return # nothing to do
357
358
        # Sort needed to first handle directory content before the directory
359
        files.sort(reverse=True)
360
361
        def backup(file_to_backup):
362
            abs_path = self.abspath(file_to_backup)
0.200.1648 by Jelmer Vernooij
Fix compatibility with newer versions of breezy.
363
            backup_name = self.controldir._available_backup_name(file_to_backup)
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
364
            osutils.rename(abs_path, self.abspath(backup_name))
365
            return "removed %s (but kept a copy: %s)" % (
366
                file_to_backup, backup_name)
367
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
368
        with self.lock_tree_write():
369
            for f in files:
0.200.1735 by Jelmer Vernooij
Fix remove tests.
370
                if f == '':
371
                    continue
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
372
                fid = self.path2id(f)
373
                if not fid:
374
                    message = "%s is not versioned." % (f,)
375
                else:
376
                    abs_path = self.abspath(f)
377
                    if verbose:
378
                        # having removed it, it must be either ignored or unknown
379
                        if self.is_ignored(f):
380
                            new_status = 'I'
381
                        else:
382
                            new_status = '?'
383
                        # XXX: Really should be a more abstract reporter interface
384
                        kind_ch = osutils.kind_marker(self.kind(fid))
385
                        to_file.write(new_status + '       ' + f + kind_ch + '\n')
386
                    # Unversion file
387
                    # FIXME: _unversion_path() is O(size-of-index) for directories
388
                    self._unversion_path(f)
389
                    message = "removed %s" % (f,)
390
                    if osutils.lexists(abs_path):
391
                        if (osutils.isdir(abs_path) and
392
                            len(os.listdir(abs_path)) > 0):
393
                            if force:
394
                                osutils.rmtree(abs_path)
395
                                message = "deleted %s" % (f,)
396
                            else:
397
                                message = backup(f)
398
                        else:
399
                            if not keep_files:
400
                                osutils.delete_any(abs_path)
401
                                message = "deleted %s" % (f,)
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
402
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
403
                # print only one message (if any) per file.
404
                if message is not None:
405
                    trace.note(message)
406
            self.flush()
0.200.1192 by Jelmer Vernooij
Implement path2id.
407
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
408
    def _add(self, files, ids, kinds):
409
        for (path, file_id, kind) in zip(files, ids, kinds):
0.200.1201 by Jelmer Vernooij
Implement _set_root_id.
410
            if file_id is not None:
0.200.1663 by Jelmer Vernooij
Raise SettingFileIdUnsupported
411
                raise workingtree.SettingFileIdUnsupported()
412
            self._index_add_entry(path, kind)
0.200.1201 by Jelmer Vernooij
Implement _set_root_id.
413
0.200.1240 by Jelmer Vernooij
Implement GitWorkingTree.smart_add.
414
    def smart_add(self, file_list, recurse=True, action=None, save=True):
415
        added = []
416
        ignored = {}
417
        user_dirs = []
0.200.1733 by Jelmer Vernooij
Support handling of custom ids in smart_add.
418
        def call_action(filepath, kind):
419
            if action is not None:
420
                parent_path = posixpath.dirname(filepath)
421
                parent_id = self.path2id(parent_path)
422
                parent_ie = self._get_dir_ie(parent_path, parent_id)
423
                file_id = action(self, parent_ie, filepath, kind)
424
                if file_id is not None:
425
                    raise workingtree.SettingFileIdUnsupported()
426
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
427
        with self.lock_tree_write():
428
            for filepath in osutils.canonical_relpaths(self.basedir, file_list):
429
                abspath = self.abspath(filepath)
0.200.1240 by Jelmer Vernooij
Implement GitWorkingTree.smart_add.
430
                kind = osutils.file_kind(abspath)
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
431
                if kind in ("file", "symlink"):
0.200.1733 by Jelmer Vernooij
Support handling of custom ids in smart_add.
432
                    call_action(filepath, kind)
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
433
                    if save:
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
434
                        self._index_add_entry(filepath, kind)
435
                    added.append(filepath)
436
                elif kind == "directory":
0.200.1733 by Jelmer Vernooij
Support handling of custom ids in smart_add.
437
                    call_action(filepath, kind)
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
438
                    if recurse:
439
                        user_dirs.append(filepath)
440
                else:
441
                    raise errors.BadFileKindError(filename=abspath, kind=kind)
442
            for user_dir in user_dirs:
443
                abs_user_dir = self.abspath(user_dir)
444
                for name in os.listdir(abs_user_dir):
445
                    subp = os.path.join(user_dir, name)
446
                    if self.is_control_filename(subp) or self.mapping.is_special_file(subp):
447
                        continue
448
                    ignore_glob = self.is_ignored(subp)
449
                    if ignore_glob is not None:
450
                        ignored.setdefault(ignore_glob, []).append(subp)
451
                        continue
452
                    abspath = self.abspath(subp)
453
                    kind = osutils.file_kind(abspath)
454
                    if kind == "directory":
455
                        user_dirs.append(subp)
456
                    else:
0.200.1733 by Jelmer Vernooij
Support handling of custom ids in smart_add.
457
                        call_action(filepath, kind)
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
458
                        if save:
459
                            self._index_add_entry(subp, kind)
460
            if added and save:
461
                self.flush()
462
            return added, ignored
0.200.1240 by Jelmer Vernooij
Implement GitWorkingTree.smart_add.
463
0.200.1201 by Jelmer Vernooij
Implement _set_root_id.
464
    def _set_root_id(self, file_id):
465
        self._fileid_map.set_file_id("", file_id)
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
466
0.200.1193 by Jelmer Vernooij
Implement GitWorkingTree.{move,rename_one}.
467
    def move(self, from_paths, to_dir=None, after=False):
468
        rename_tuples = []
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
469
        with self.lock_tree_write():
470
            to_abs = self.abspath(to_dir)
471
            if not os.path.isdir(to_abs):
472
                raise errors.BzrMoveFailedError('', to_dir,
473
                    errors.NotADirectory(to_abs))
474
475
            for from_rel in from_paths:
476
                from_tail = os.path.split(from_rel)[-1]
477
                to_rel = os.path.join(to_dir, from_tail)
478
                self.rename_one(from_rel, to_rel, after=after)
479
                rename_tuples.append((from_rel, to_rel))
480
            self.flush()
481
            return rename_tuples
482
0.200.1193 by Jelmer Vernooij
Implement GitWorkingTree.{move,rename_one}.
483
    def rename_one(self, from_rel, to_rel, after=False):
0.200.1203 by Jelmer Vernooij
Fix per_workingtree.test_rename_one.TestRenameOne.test_rename_after_non_existant_non_ascii
484
        from_path = from_rel.encode("utf-8")
485
        to_path = to_rel.encode("utf-8")
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
486
        with self.lock_tree_write():
0.200.1737 by Jelmer Vernooij
Fix rename tests.
487
            if not after:
488
                if not self.has_filename(from_rel):
489
                    raise errors.BzrMoveFailedError(from_rel, to_rel,
490
                        errors.NoSuchFile(from_rel))
491
            else:
492
                if not self.has_filename(to_rel):
493
                    raise errors.BzrMoveFailedError(from_rel, to_rel,
494
                        errors.NoSuchFile(to_rel))
495
0.200.1748 by Jelmer Vernooij
Fix rename test.
496
            kind = self.kind(from_rel)
497
            if not from_path in self.index and kind != 'directory':
498
                # It's not a file
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
499
                raise errors.BzrMoveFailedError(from_rel, to_rel,
500
                    errors.NotVersionedError(path=from_rel))
0.200.1737 by Jelmer Vernooij
Fix rename tests.
501
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
502
            if not after:
0.200.1737 by Jelmer Vernooij
Fix rename tests.
503
                try:
504
                    os.rename(self.abspath(from_rel), self.abspath(to_rel))
505
                except OSError as e:
506
                    if e.errno == errno.ENOENT:
507
                        raise errors.BzrMoveFailedError(from_rel, to_rel,
508
                            errors.NoSuchFile(to_rel))
509
                    raise
0.200.1748 by Jelmer Vernooij
Fix rename test.
510
            if kind != 'directory':
511
                self.index[to_path] = self.index[from_path]
512
                del self.index[from_path]
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
513
            self.flush()
0.200.1193 by Jelmer Vernooij
Implement GitWorkingTree.{move,rename_one}.
514
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
515
    def get_root_id(self):
0.200.1192 by Jelmer Vernooij
Implement path2id.
516
        return self.path2id("")
517
0.200.1712 by Jelmer Vernooij
Add file_id prefix.
518
    def has_filename(self, filename):
519
        return osutils.lexists(self.abspath(filename))
520
0.200.1242 by Jelmer Vernooij
Support directories better.
521
    def _has_dir(self, path):
0.200.1368 by Jelmer Vernooij
There is always a tree root.
522
        if path == "":
523
            return True
0.200.1242 by Jelmer Vernooij
Support directories better.
524
        if self._versioned_dirs is None:
525
            self._load_dirs()
526
        return path in self._versioned_dirs
527
0.200.1192 by Jelmer Vernooij
Implement path2id.
528
    def path2id(self, path):
0.200.1600 by Jelmer Vernooij
Cope with paths as lists of elements.
529
        if type(path) is list:
530
            path = u"/".join(path)
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
531
        with self.lock_read():
532
            encoded_path = path.encode("utf-8")
533
            if self._is_versioned(encoded_path):
534
                return self._fileid_map.lookup_file_id(encoded_path)
535
            return None
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
536
0.200.1328 by Jelmer Vernooij
More test fixes.
537
    def _iter_files_recursive(self, from_dir=None):
538
        if from_dir is None:
539
            from_dir = ""
540
        for (dirpath, dirnames, filenames) in os.walk(self.abspath(from_dir)):
0.200.1302 by Jelmer Vernooij
Significantly improve performance of WorkingTree.extras().
541
            dir_relpath = dirpath[len(self.basedir):].strip("/")
0.200.1648 by Jelmer Vernooij
Fix compatibility with newer versions of breezy.
542
            if self.controldir.is_control_filename(dir_relpath):
0.200.605 by Jelmer Vernooij
Ignore directories in WorkingTree.extras().
543
                continue
0.200.615 by Jelmer Vernooij
Optimize WorkingTree.extras().
544
            for filename in filenames:
0.200.1328 by Jelmer Vernooij
More test fixes.
545
                if not self.mapping.is_special_file(filename):
546
                    yield os.path.join(dir_relpath, filename)
0.200.1327 by Jelmer Vernooij
Factor out all file browsing in extras.
547
548
    def extras(self):
549
        """Yield all unversioned files in this WorkingTree.
550
        """
0.200.1676 by Jelmer Vernooij
Fix typo.
551
        with self.lock_read():
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
552
            return set(self._iter_files_recursive()) - set(self.index)
0.200.605 by Jelmer Vernooij
Ignore directories in WorkingTree.extras().
553
0.200.382 by Jelmer Vernooij
Support flushing index.
554
    def flush(self):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
555
        with self.lock_tree_write():
556
            # TODO: Maybe this should only write on dirty ?
557
            if self._lock_mode != 'w':
558
                raise errors.NotWriteLocked(self)
559
            self.index.write()
0.200.382 by Jelmer Vernooij
Support flushing index.
560
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
561
    def __iter__(self):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
562
        with self.lock_read():
563
            for path in self.index:
564
                yield self.path2id(path)
565
            self._load_dirs()
566
            for path in self._versioned_dirs:
567
                yield self.path2id(path)
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
568
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
569
    def has_or_had_id(self, file_id):
570
        if self.has_id(file_id):
571
            return True
572
        if self.had_id(file_id):
573
            return True
574
        return False
575
576
    def had_id(self, file_id):
577
        path = self._basis_fileid_map.lookup_file_id(file_id)
578
        try:
579
            head = self.repository._git.head()
580
        except KeyError:
581
            # Assume no if basis is not accessible
582
            return False
0.200.1205 by Jelmer Vernooij
Implement GitWorkingTree.stored_kind.
583
        if head == ZERO_SHA:
584
            return False
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
585
        root_tree = self.store[head].tree
586
        try:
587
            tree_lookup_path(self.store.__getitem__, root_tree, path)
588
        except KeyError:
589
            return False
590
        else:
591
            return True
592
0.200.1198 by Jelmer Vernooij
Implement GitWorkingTree.has_id.
593
    def has_id(self, file_id):
594
        try:
595
            self.id2path(file_id)
596
        except errors.NoSuchId:
597
            return False
598
        else:
599
            return True
600
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
601
    def id2path(self, file_id):
0.200.1532 by Jelmer Vernooij
Cope with float timestamps.
602
        assert type(file_id) is str, "file id not a string: %r" % file_id
0.200.1411 by Jelmer Vernooij
Fix control files.
603
        file_id = osutils.safe_utf8(file_id)
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
604
        with self.lock_read():
0.200.1712 by Jelmer Vernooij
Add file_id prefix.
605
            try:
606
                path = self._fileid_map.lookup_path(file_id)
607
            except ValueError:
608
                raise errors.NoSuchId(self, file_id)
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
609
            # FIXME: What about directories?
610
            if self._is_versioned(path):
611
                return path.decode("utf-8")
612
            raise errors.NoSuchId(self, file_id)
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
613
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
614
    def get_file_mtime(self, path, file_id=None):
0.200.1200 by Jelmer Vernooij
Support GitWorkingTree.get_file_mtime.
615
        """See Tree.get_file_mtime."""
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
616
        try:
617
            return os.lstat(self.abspath(path)).st_mtime
618
        except OSError, (num, msg):
619
            if num == errno.ENOENT:
620
                raise errors.NoSuchFile(path)
621
            raise
0.200.1200 by Jelmer Vernooij
Support GitWorkingTree.get_file_mtime.
622
0.200.1655 by Jelmer Vernooij
Basic support for git ignores.
623
    def is_ignored(self, filename):
624
        r"""Check whether the filename matches an ignore pattern.
625
626
        If the file is ignored, returns the pattern which caused it to
627
        be ignored, otherwise None.  So this can simply be used as a
628
        boolean if desired."""
629
        if getattr(self, '_global_ignoreglobster', None) is None:
630
            ignore_globs = set()
631
            ignore_globs.update(ignores.get_runtime_ignores())
632
            ignore_globs.update(ignores.get_user_ignores())
633
            self._global_ignoreglobster = globbing.ExceptionGlobster(ignore_globs)
0.200.1656 by Jelmer Vernooij
Report proper patterns, ignore files.
634
        match = self._global_ignoreglobster.match(filename)
635
        if match is not None:
636
            return match
0.200.1716 by Jelmer Vernooij
Fix some more tests.
637
        try:
638
            if self.kind(filename) == 'directory':
639
                filename += b'/'
640
        except errors.NoSuchFile:
641
            pass
642
        filename = filename.lstrip(b'/')
0.200.1658 by Jelmer Vernooij
Fix handling of ignores - return patterns that matched.
643
        ignore_manager = self._get_ignore_manager()
644
        ps = list(ignore_manager.find_matching(filename))
645
        if not ps:
646
            return None
647
        if not ps[-1].is_exclude:
648
            return None
649
        return bytes(ps[-1])
650
651
    def _get_ignore_manager(self):
652
        ignoremanager = getattr(self, '_ignoremanager', None)
653
        if ignoremanager is not None:
654
            return ignoremanager
655
656
        ignore_manager = IgnoreFilterManager.from_repo(self.repository._git)
657
        self._ignoremanager = ignore_manager
658
        return ignore_manager
0.200.409 by Jelmer Vernooij
Support parsing .gitignore.
659
0.200.1716 by Jelmer Vernooij
Fix some more tests.
660
    def _flush_ignore_list_cache(self):
661
        self._ignoremanager = None
662
0.200.508 by Jelmer Vernooij
Skip inventory caching bits.
663
    def set_last_revision(self, revid):
0.200.1720 by Jelmer Vernooij
Fix handling of pending merges.
664
        if _mod_revision.is_null(revid):
665
            self.branch.set_last_revision_info(0, revid)
666
            return False
667
        _mod_revision.check_not_reserved_id(revid)
668
        try:
669
            self.branch.generate_revision_history(revid)
670
        except errors.NoSuchRevision:
671
            raise errors.GhostRevisionUnusableHere(revid)
0.200.508 by Jelmer Vernooij
Skip inventory caching bits.
672
0.200.379 by Jelmer Vernooij
Re-enable working tree support.
673
    def _reset_data(self):
0.248.3 by Jelmer Vernooij
Handle working trees without valid HEAD branch.
674
        try:
675
            head = self.repository._git.head()
676
        except KeyError, name:
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
677
            raise errors.NotBranchError("branch %s at %s" % (name,
678
                self.repository.base))
0.200.948 by Jelmer Vernooij
Cope with empty inventories.
679
        if head == ZERO_SHA:
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
680
            self._basis_fileid_map = GitFileIdMap({}, self.mapping)
0.200.948 by Jelmer Vernooij
Cope with empty inventories.
681
        else:
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
682
            self._basis_fileid_map = self.mapping.get_fileid_map(
683
                self.store.__getitem__, self.store[head].tree)
0.200.379 by Jelmer Vernooij
Re-enable working tree support.
684
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
685
    def get_file_verifier(self, path, file_id=None, stat_value=None):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
686
        with self.lock_read():
687
            try:
688
                return ("GIT", self.index[path][-2])
689
            except KeyError:
690
                if self._has_dir(path):
691
                    return ("GIT", None)
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
692
                raise errors.NoSuchFile(path)
0.200.1302 by Jelmer Vernooij
Significantly improve performance of WorkingTree.extras().
693
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
694
    def get_file_sha1(self, path, file_id=None, stat_value=None):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
695
        with self.lock_read():
696
            abspath = self.abspath(path).encode(osutils._fs_enc)
697
            try:
698
                return osutils.sha_file_by_name(abspath)
699
            except OSError, (num, msg):
700
                if num in (errno.EISDIR, errno.ENOENT):
701
                    return None
702
                raise
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
703
0.200.610 by Jelmer Vernooij
Support retrieving basis tree properly.
704
    def revision_tree(self, revid):
705
        return self.repository.revision_tree(revid)
706
0.200.1242 by Jelmer Vernooij
Support directories better.
707
    def _is_versioned(self, path):
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
708
        assert self._lock_mode is not None
0.200.1242 by Jelmer Vernooij
Support directories better.
709
        return (path in self.index or self._has_dir(path))
710
0.200.1239 by Jelmer Vernooij
Implement GitWorkingTree.filter_unversioned_files.
711
    def filter_unversioned_files(self, files):
0.200.1316 by Jelmer Vernooij
Fix filter_unversioned_files.
712
        return set([p for p in files if not self._is_versioned(p.encode("utf-8"))])
0.200.1239 by Jelmer Vernooij
Implement GitWorkingTree.filter_unversioned_files.
713
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
714
    def _get_dir_ie(self, path, parent_id):
0.200.1192 by Jelmer Vernooij
Implement path2id.
715
        file_id = self.path2id(path)
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
716
        return inventory.InventoryDirectory(file_id,
0.200.1190 by Jelmer Vernooij
Fix get_symlink_target call.
717
            posixpath.basename(path).strip("/"), parent_id)
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
718
719
    def _add_missing_parent_ids(self, path, dir_ids):
720
        if path in dir_ids:
721
            return []
722
        parent = posixpath.dirname(path).strip("/")
723
        ret = self._add_missing_parent_ids(parent, dir_ids)
724
        parent_id = dir_ids[parent]
725
        ie = self._get_dir_ie(path, parent_id)
726
        dir_ids[path] = ie.file_id
727
        ret.append((path, ie))
728
        return ret
729
0.200.1321 by Jelmer Vernooij
More fixes for compatibility with bzr.dev testsuite.
730
    def _get_file_ie(self, name, path, value, parent_id):
731
        assert isinstance(name, unicode)
0.200.1192 by Jelmer Vernooij
Implement path2id.
732
        assert isinstance(path, unicode)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
733
        assert isinstance(value, tuple) and len(value) == 10
734
        (ctime, mtime, dev, ino, mode, uid, gid, size, sha, flags) = value
0.200.1192 by Jelmer Vernooij
Implement path2id.
735
        file_id = self.path2id(path)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
736
        if type(file_id) != str:
737
            raise AssertionError
738
        kind = mode_kind(mode)
0.200.1321 by Jelmer Vernooij
More fixes for compatibility with bzr.dev testsuite.
739
        ie = inventory.entry_factory[kind](file_id, name, parent_id)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
740
        if kind == 'symlink':
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
741
            ie.symlink_target = self.get_symlink_target(path, file_id)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
742
        else:
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
743
            data = self.get_file_text(path, file_id)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
744
            ie.text_sha1 = osutils.sha_string(data)
745
            ie.text_size = len(data)
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
746
            ie.executable = self.is_executable(path, file_id)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
747
        ie.revision = None
748
        return ie
749
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
750
    def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
751
        mode = stat_result.st_mode
752
        return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
753
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
754
    def stored_kind(self, path, file_id=None):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
755
        with self.lock_read():
756
            try:
757
                return mode_kind(self.index[path.encode("utf-8")][4])
758
            except KeyError:
759
                # Maybe it's a directory?
760
                if self._has_dir(path):
761
                    return "directory"
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
762
                raise errors.NoSuchFile(path)
0.200.1205 by Jelmer Vernooij
Implement GitWorkingTree.stored_kind.
763
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
764
    def is_executable(self, path, file_id=None):
0.200.1539 by Jelmer Vernooij
Cope with new is_executable.
765
        if getattr(self, "_supports_executable", osutils.supports_executable)():
766
            mode = os.lstat(self.abspath(path)).st_mode
767
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
768
        else:
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
769
            basis_tree = self.basis_tree()
770
            if file_id in basis_tree:
0.285.1 by Jelmer Vernooij
Swap arguments for tree methods.
771
                return basis_tree.is_executable(path, file_id)
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
772
            # Default to not executable
773
            return False
774
0.200.1539 by Jelmer Vernooij
Cope with new is_executable.
775
    def _is_executable_from_path_and_stat(self, path, stat_result):
776
        if getattr(self, "_supports_executable", osutils.supports_executable)():
777
            return self._is_executable_from_path_and_stat_from_stat(path, stat_result)
778
        else:
779
            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.
780
0.264.10 by Jelmer Vernooij
Yield inventory entries.
781
    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.
782
        if from_dir is None:
783
            from_dir = ""
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
784
        dir_ids = {}
0.200.1339 by Jelmer Vernooij
Some reformatting.
785
        fk_entries = {'directory': workingtree.TreeDirectory,
786
                      'file': workingtree.TreeFile,
787
                      'symlink': workingtree.TreeLink}
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
788
        with self.lock_read():
789
            root_ie = self._get_dir_ie(u"", None)
790
            if include_root and not from_dir:
791
                yield "", "V", root_ie.kind, root_ie.file_id, root_ie
792
            dir_ids[u""] = root_ie.file_id
793
            if recursive:
794
                path_iterator = self._iter_files_recursive(from_dir)
795
            else:
796
                if from_dir is None:
797
                    start = self.basedir
798
                else:
799
                    start = os.path.join(self.basedir, from_dir)
800
                path_iterator = sorted([os.path.join(from_dir, name) for name in
801
                    os.listdir(start) if not self.controldir.is_control_filename(name)
802
                    and not self.mapping.is_special_file(name)])
803
            for path in path_iterator:
804
                try:
805
                    value = self.index[path]
806
                except KeyError:
807
                    value = None
808
                path = path.decode("utf-8")
809
                parent, name = posixpath.split(path)
810
                for dir_path, dir_ie in self._add_missing_parent_ids(parent, dir_ids):
811
                    yield dir_path, "V", dir_ie.kind, dir_ie.file_id, dir_ie
812
                if value is not None:
813
                    ie = self._get_file_ie(name, path, value, dir_ids[parent])
814
                    yield path, "V", ie.kind, ie.file_id, ie
815
                else:
816
                    kind = osutils.file_kind(self.abspath(path))
817
                    ie = fk_entries[kind]()
818
                    yield path, ("I" if self.is_ignored(path) else "?"), kind, None, ie
0.264.10 by Jelmer Vernooij
Yield inventory entries.
819
0.200.1206 by Jelmer Vernooij
Implement GitWorkingTree.all_file_ids.
820
    def all_file_ids(self):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
821
        with self.lock_read():
822
            ids = {u"": self.path2id("")}
823
            for path in self.index:
824
                if self.mapping.is_special_file(path):
825
                    continue
826
                path = path.decode("utf-8")
827
                parent = posixpath.dirname(path).strip("/")
828
                for e in self._add_missing_parent_ids(parent, ids):
829
                    pass
830
                ids[path] = self.path2id(path)
831
            return set(ids.values())
0.200.1206 by Jelmer Vernooij
Implement GitWorkingTree.all_file_ids.
832
0.200.1710 by Jelmer Vernooij
Regenerate xfail.
833
    def all_versioned_paths(self):
834
        with self.lock_read():
835
            paths = {u""}
836
            for path in self.index:
837
                if self.mapping.is_special_file(path):
838
                    continue
839
                path = path.decode("utf-8")
840
                paths.add(path)
841
                while path != "":
842
                    path = posixpath.dirname(path).strip("/")
843
                    if path in paths:
844
                        break
845
                    paths.add(path)
846
            return paths
847
0.200.1374 by Jelmer Vernooij
Implement GitWorkingTree._directory_is_tree_reference.
848
    def _directory_is_tree_reference(self, path):
849
        # FIXME: Check .gitsubmodules for path
850
        return False
851
0.200.1716 by Jelmer Vernooij
Fix some more tests.
852
    def iter_child_entries(self, path, file_id=None):
853
        encoded_path = path.encode('utf-8')
0.200.1739 by Jelmer Vernooij
Fix iteration order for iter_child_entries.
854
        parent_id = self.path2id(path)
0.200.1738 by Jelmer Vernooij
Fix test_does_not_exist.
855
        found_any = False
0.200.1739 by Jelmer Vernooij
Fix iteration order for iter_child_entries.
856
        seen_children = set()
0.200.1716 by Jelmer Vernooij
Fix some more tests.
857
        for item_path, value in self.index.iteritems():
858
            if self.mapping.is_special_file(item_path):
859
                continue
0.200.1739 by Jelmer Vernooij
Fix iteration order for iter_child_entries.
860
            if not osutils.is_inside(encoded_path, item_path):
0.200.1716 by Jelmer Vernooij
Fix some more tests.
861
                continue
0.200.1738 by Jelmer Vernooij
Fix test_does_not_exist.
862
            found_any = True
0.200.1739 by Jelmer Vernooij
Fix iteration order for iter_child_entries.
863
            subpath = posixpath.relpath(item_path, encoded_path)
0.200.1716 by Jelmer Vernooij
Fix some more tests.
864
            if b'/' in subpath:
0.200.1739 by Jelmer Vernooij
Fix iteration order for iter_child_entries.
865
                dirname = subpath.split(b'/', 1)[0]
866
                file_ie = self._get_dir_ie(posixpath.join(path, dirname), parent_id)
867
            else:
868
                (parent, name) = posixpath.split(item_path)
869
                try:
870
                    file_ie = self._get_file_ie(name, item_path, value, parent_id)
871
                except IOError:
872
                    continue
0.200.1716 by Jelmer Vernooij
Fix some more tests.
873
            yield file_ie
0.200.1738 by Jelmer Vernooij
Fix test_does_not_exist.
874
        if not found_any:
875
            raise errors.NoSuchFile(path)
0.200.1716 by Jelmer Vernooij
Fix some more tests.
876
0.264.9 by Jelmer Vernooij
Implement basic GitWorkingTree.iter_entries_by_dir.
877
    def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):
0.200.1252 by Jelmer Vernooij
Support specific_file_ids in GitWorkingTree.iter_entries_by_dir.
878
        if yield_parents:
879
            raise NotImplementedError(self.iter_entries_by_dir)
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
880
        with self.lock_read():
881
            if specific_file_ids is not None:
0.200.1712 by Jelmer Vernooij
Add file_id prefix.
882
                specific_paths = []
883
                for file_id in specific_file_ids:
884
                    assert file_id is not None, "file id %r" % file_id
885
                    specific_paths.append(self.id2path(file_id))
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
886
                if specific_paths in ([u""], []):
887
                    specific_paths = None
888
                else:
889
                    specific_paths = set(specific_paths)
890
            else:
0.200.1252 by Jelmer Vernooij
Support specific_file_ids in GitWorkingTree.iter_entries_by_dir.
891
                specific_paths = None
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
892
            root_ie = self._get_dir_ie(u"", None)
0.200.1740 by Jelmer Vernooij
Fix iter_entries_by_dir order.
893
            ret = {}
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
894
            if specific_paths is None:
0.200.1740 by Jelmer Vernooij
Fix iter_entries_by_dir order.
895
                ret[(None, u"")] = root_ie
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
896
            dir_ids = {u"": root_ie.file_id}
897
            for path, value in self.index.iteritems():
898
                if self.mapping.is_special_file(path):
899
                    continue
900
                path = path.decode("utf-8")
901
                if specific_paths is not None and not path in specific_paths:
902
                    continue
903
                (parent, name) = posixpath.split(path)
904
                try:
905
                    file_ie = self._get_file_ie(name, path, value, None)
906
                except IOError:
907
                    continue
0.200.1730 by Jelmer Vernooij
Fix test_is_executable_dir.
908
                if yield_parents or specific_file_ids is None:
909
                    for (dir_path, dir_ie) in self._add_missing_parent_ids(parent,
910
                            dir_ids):
0.200.1740 by Jelmer Vernooij
Fix iter_entries_by_dir order.
911
                        ret[(posixpath.dirname(dir_path), dir_path)] = dir_ie
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
912
                file_ie.parent_id = self.path2id(parent)
0.200.1740 by Jelmer Vernooij
Fix iter_entries_by_dir order.
913
                ret[(posixpath.dirname(path), path)] = file_ie
914
            return ((path, ie) for ((_, path), ie) in sorted(ret.items()))
0.264.9 by Jelmer Vernooij
Implement basic GitWorkingTree.iter_entries_by_dir.
915
0.200.619 by Jelmer Vernooij
Provide dummy WorkingTree.conflicts() implementation rather than spending a lot of time not finding any conflicts.
916
    def conflicts(self):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
917
        with self.lock_read():
918
            # FIXME:
919
            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.
920
0.200.1328 by Jelmer Vernooij
More test fixes.
921
    def get_canonical_inventory_path(self, path):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
922
        with self.lock_read():
923
            for p in self.index:
924
                if p.lower() == path.lower():
925
                    return p
926
            else:
927
                return path
0.200.1328 by Jelmer Vernooij
More test fixes.
928
0.200.1705 by Jelmer Vernooij
Fix walkdirs.
929
    def walkdirs(self, prefix=""):
0.200.1210 by Jelmer Vernooij
Implement GitWorkingTree._walkdirs.
930
        if prefix != "":
931
            prefix += "/"
932
        per_dir = defaultdict(list)
933
        for path, value in self.index.iteritems():
0.200.1328 by Jelmer Vernooij
More test fixes.
934
            if self.mapping.is_special_file(path):
935
                continue
0.200.1210 by Jelmer Vernooij
Implement GitWorkingTree._walkdirs.
936
            if not path.startswith(prefix):
937
                continue
938
            (dirname, child_name) = posixpath.split(path)
939
            dirname = dirname.decode("utf-8")
940
            dir_file_id = self.path2id(dirname)
941
            assert isinstance(value, tuple) and len(value) == 10
942
            (ctime, mtime, dev, ino, mode, uid, gid, size, sha, flags) = value
0.265.1 by Martin
Don't import posix module, the os wrapper exists for portability
943
            stat_result = os.stat_result((mode, ino,
0.200.1211 by Jelmer Vernooij
Fix statresult.
944
                    dev, 1, uid, gid, size,
0.200.1736 by Jelmer Vernooij
Fix a walkdirs test.
945
                    int(mtime), int(mtime), int(ctime)))
0.200.1210 by Jelmer Vernooij
Implement GitWorkingTree._walkdirs.
946
            per_dir[(dirname, dir_file_id)].append(
947
                (path.decode("utf-8"), child_name.decode("utf-8"),
948
                mode_kind(mode), stat_result,
949
                self.path2id(path.decode("utf-8")),
950
                mode_kind(mode)))
951
        return per_dir.iteritems()
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
952
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
953
    def _lookup_entry(self, path, update_index=False):
0.200.1543 by Jelmer Vernooij
Support symlinks.
954
        assert type(path) == str
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
955
        entry = self.index[path]
956
        index_mode = entry[-6]
957
        index_sha = entry[-2]
0.200.1741 by Jelmer Vernooij
Fix opentree tests.
958
        disk_path = self.abspath(path.decode('utf-8')).encode(
959
            osutils._fs_enc)
0.284.1 by Jelmer Vernooij
Raise KeyError when file was removed.
960
        try:
961
            disk_stat = os.lstat(disk_path)
962
        except OSError, (num, msg):
963
            if num in (errno.EISDIR, errno.ENOENT):
964
                raise KeyError(path)
965
            raise
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
966
        disk_mtime = disk_stat.st_mtime
967
        if isinstance(entry[1], tuple):
968
            index_mtime = entry[1][0]
969
        else:
970
            index_mtime = int(entry[1])
971
        mtime_delta = (disk_mtime - index_mtime)
972
        disk_mode = cleanup_mode(disk_stat.st_mode)
973
        if mtime_delta > 0 or disk_mode != index_mode:
974
            if stat.S_ISDIR(disk_mode):
975
                try:
976
                    subrepo = Repo(disk_path)
977
                except NotGitRepository:
978
                    return (None, None)
979
                else:
980
                    disk_mode = S_IFGITLINK
981
                    git_id = subrepo.head()
0.200.1543 by Jelmer Vernooij
Support symlinks.
982
            elif stat.S_ISLNK(disk_mode):
0.200.1715 by Jelmer Vernooij
Fix some more tests.
983
                blob = Blob.from_string(os.readlink(disk_path))
0.200.1543 by Jelmer Vernooij
Support symlinks.
984
                git_id = blob.id
985
            elif stat.S_ISREG(disk_mode):
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
986
                with open(disk_path, 'r') as f:
987
                    blob = Blob.from_string(f.read())
988
                git_id = blob.id
0.200.1543 by Jelmer Vernooij
Support symlinks.
989
            else:
990
                raise AssertionError
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
991
            if update_index:
992
                flags = 0 # FIXME
0.200.1545 by Jelmer Vernooij
Some more test fixes.
993
                self.index[path] = index_entry_from_stat(disk_stat, git_id, flags, disk_mode)
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
994
            return (git_id, disk_mode)
995
        return (index_sha, index_mode)
996
0.200.1677 by Jelmer Vernooij
Mark shelving as unsupported.
997
    def get_shelf_manager(self):
0.200.1729 by Jelmer Vernooij
ShelvingUnsupported doesn't take an argument.
998
        raise workingtree.ShelvingUnsupported()
0.200.1677 by Jelmer Vernooij
Mark shelving as unsupported.
999
0.200.1678 by Jelmer Vernooij
Fix tests.
1000
    def store_uncommitted(self):
1001
        raise errors.StoringUncommittedNotSupported(self)
1002
0.200.1703 by Jelmer Vernooij
Implement apply_inventory_delta.
1003
    def apply_inventory_delta(self, changes):
1004
        for (old_path, new_path, file_id, ie) in changes:
1005
            if old_path is not None:
1006
                del self.index[old_path.encode('utf-8')]
1007
            if new_path is not None and ie.kind != 'directory':
1008
                self._index_add_entry(new_path, ie.kind)
1009
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
1010
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
1011
class GitWorkingTreeFormat(workingtree.WorkingTreeFormat):
1012
0.200.1206 by Jelmer Vernooij
Implement GitWorkingTree.all_file_ids.
1013
    _tree_class = GitWorkingTree
1014
0.200.1295 by Jelmer Vernooij
Mark working trees as not supporting directories.
1015
    supports_versioned_directories = False
1016
0.200.1661 by Jelmer Vernooij
Set supports_setting_file_ids to False.
1017
    supports_setting_file_ids = False
1018
0.200.1677 by Jelmer Vernooij
Mark shelving as unsupported.
1019
    supports_store_uncommitted = False
1020
0.200.1723 by Jelmer Vernooij
Set supports_leftmost_parent_id_as_ghost property.
1021
    supports_leftmost_parent_id_as_ghost = False
1022
0.200.656 by Jelmer Vernooij
Implement GitWorkingTreeFormat._matchingbzrdir.
1023
    @property
0.200.1665 by Jelmer Vernooij
Rename _matchingbzrdir to _matchingcnotroldir.
1024
    def _matchingcontroldir(self):
0.200.1641 by Jelmer Vernooij
Use relative imports where possible.
1025
        from .dir import LocalGitControlDirFormat
0.200.1013 by Jelmer Vernooij
More renames.
1026
        return LocalGitControlDirFormat()
0.200.656 by Jelmer Vernooij
Implement GitWorkingTreeFormat._matchingbzrdir.
1027
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
1028
    def get_format_description(self):
1029
        return "Git Working Tree"
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
1030
0.200.1648 by Jelmer Vernooij
Fix compatibility with newer versions of breezy.
1031
    def initialize(self, a_controldir, revision_id=None, from_branch=None,
0.200.1096 by Jelmer Vernooij
Implement GitWorkingTreeFormat.initialize.
1032
                   accelerator_tree=None, hardlink=False):
1033
        """See WorkingTreeFormat.initialize()."""
0.200.1648 by Jelmer Vernooij
Fix compatibility with newer versions of breezy.
1034
        if not isinstance(a_controldir, LocalGitDir):
1035
            raise errors.IncompatibleFormat(self, a_controldir)
1036
        index = Index(a_controldir.root_transport.local_abspath(".git/index"))
0.200.1096 by Jelmer Vernooij
Implement GitWorkingTreeFormat.initialize.
1037
        index.write()
0.200.1680 by Jelmer Vernooij
Fix repo locks.
1038
        wt = GitWorkingTree(
1039
                a_controldir, a_controldir.open_repository(),
0.200.1648 by Jelmer Vernooij
Fix compatibility with newer versions of breezy.
1040
            a_controldir.open_branch(), index)
0.200.1680 by Jelmer Vernooij
Fix repo locks.
1041
        for hook in MutableTree.hooks['post_build_tree']:
1042
            hook(wt)
1043
        return wt
0.200.1096 by Jelmer Vernooij
Implement GitWorkingTreeFormat.initialize.
1044
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
1045
1046
class InterIndexGitTree(tree.InterTree):
1047
    """InterTree that works between a Git revision tree and an index."""
1048
1049
    def __init__(self, source, target):
1050
        super(InterIndexGitTree, self).__init__(source, target)
1051
        self._index = target.index
1052
1053
    @classmethod
1054
    def is_compatible(cls, source, target):
0.200.1641 by Jelmer Vernooij
Use relative imports where possible.
1055
        from .repository import GitRevisionTree
0.200.1636 by Jelmer Vernooij
Some formatting fixes.
1056
        return (isinstance(source, GitRevisionTree) and
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
1057
                isinstance(target, GitWorkingTree))
1058
1059
    def compare(self, want_unchanged=False, specific_files=None,
1060
                extra_trees=None, require_versioned=False, include_root=False,
1061
                want_unversioned=False):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
1062
        with self.lock_read():
1063
            # FIXME: Handle include_root
1064
            changes = changes_between_git_tree_and_index(
1065
                self.source.store, self.source.tree,
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
1066
                self.target, want_unchanged=want_unchanged)
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
1067
            source_fileid_map = self.source._fileid_map
1068
            target_fileid_map = self.target._fileid_map
1069
            ret = tree_delta_from_git_changes(changes, self.target.mapping,
1070
                (source_fileid_map, target_fileid_map),
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
1071
                specific_files=specific_files, require_versioned=require_versioned)
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
1072
            if want_unversioned:
1073
                for e in self.target.extras():
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
1074
                    ret.unversioned.append(
0.200.1732 by Jelmer Vernooij
Fix ignore.
1075
                        (osutils.normalized_filename(e)[0], None,
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
1076
                        osutils.file_kind(self.target.abspath(e))))
1077
            return ret
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
1078
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
1079
    def iter_changes(self, include_unchanged=False, specific_files=None,
0.200.1207 by Jelmer Vernooij
Fix some formatting.
1080
        pb=None, extra_trees=[], require_versioned=True,
1081
        want_unversioned=False):
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
1082
        with self.lock_read():
1083
            changes = changes_between_git_tree_and_index(
1084
                self.source.store, self.source.tree,
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
1085
                self.target, want_unchanged=include_unchanged)
1086
            if want_unversioned:
1087
                changes = itertools.chain(
1088
                        changes,
1089
                        untracked_changes(self.target))
0.200.1675 by Jelmer Vernooij
Remove uses of decorators.
1090
            return changes_from_git_changes(
0.200.1743 by Jelmer Vernooij
Fix some revision delta filtering.
1091
                    changes, self.target.mapping, specific_files=specific_files)
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
1092
0.200.1179 by Jelmer Vernooij
Avoid using verifiers for natively imported revisions, save a lot of time.
1093
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
1094
tree.InterTree.register_optimiser(InterIndexGitTree)
0.200.1529 by Jelmer Vernooij
Add changes_between_tree_and_index.
1095
1096
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
1097
def untracked_changes(tree):
1098
    for e in tree.extras():
1099
        ap = tree.abspath(e)
1100
        st = os.stat(ap)
1101
        try:
1102
            np, accessible  = osutils.normalized_filename(e)
1103
        except UnicodeDecodeError:
1104
            raise errors.BadFilenameEncoding(
1105
                e, osutils._fs_enc)
1106
        yield (np, st.st_mode,
1107
               blob_from_path_and_stat(ap, st).id)
1108
1109
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
1110
def changes_between_git_tree_and_index(object_store, tree, target,
0.200.1731 by Jelmer Vernooij
Add support for checking untracked changes.
1111
        want_unchanged=False, update_index=False):
0.200.1529 by Jelmer Vernooij
Add changes_between_tree_and_index.
1112
    """Determine the changes between a git tree and a working tree with index.
1113
1114
    """
0.200.1538 by Jelmer Vernooij
More work on tree-reference support.
1115
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
1116
    names = target.index._byname.keys()
1117
    for (name, mode, sha) in changes_from_tree(names, target._lookup_entry,
0.200.1531 by Jelmer Vernooij
Don't trust index contents - verify against file timestamps.
1118
            object_store, tree, want_unchanged=want_unchanged):
0.200.1538 by Jelmer Vernooij
More work on tree-reference support.
1119
        if name == (None, None):
1120
            continue
0.200.1531 by Jelmer Vernooij
Don't trust index contents - verify against file timestamps.
1121
        yield (name, mode, sha)