/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.385 by Jelmer Vernooij
Cope with removed files.
22
from cStringIO import (
23
    StringIO,
24
    )
0.200.1210 by Jelmer Vernooij
Implement GitWorkingTree._walkdirs.
25
from collections import defaultdict
0.239.4 by Jelmer Vernooij
Cope with nonexistent files and directories in get_file_sha1.
26
import errno
0.200.1538 by Jelmer Vernooij
More work on tree-reference support.
27
from dulwich.errors import NotGitRepository
0.200.1096 by Jelmer Vernooij
Implement GitWorkingTreeFormat.initialize.
28
from dulwich.index import (
29
    Index,
0.200.1531 by Jelmer Vernooij
Don't trust index contents - verify against file timestamps.
30
    changes_from_tree,
31
    cleanup_mode,
32
    index_entry_from_stat,
0.200.1096 by Jelmer Vernooij
Implement GitWorkingTreeFormat.initialize.
33
    )
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
34
from dulwich.object_store import (
35
    tree_lookup_path,
36
    )
0.200.383 by Jelmer Vernooij
Simplify, support rewriting index based on inventory.
37
from dulwich.objects import (
38
    Blob,
0.200.1538 by Jelmer Vernooij
More work on tree-reference support.
39
    S_IFGITLINK,
0.200.948 by Jelmer Vernooij
Cope with empty inventories.
40
    ZERO_SHA,
41
    )
0.200.1538 by Jelmer Vernooij
More work on tree-reference support.
42
from dulwich.repo import Repo
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
43
import os
0.264.10 by Jelmer Vernooij
Yield inventory entries.
44
import posixpath
0.200.384 by Jelmer Vernooij
Fix reading of inventory from index.
45
import stat
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
46
import sys
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
47
48
from bzrlib import (
0.200.382 by Jelmer Vernooij
Support flushing index.
49
    errors,
0.262.1 by Jelmer Vernooij
Fix WorkingTree.conflicts().
50
    conflicts as _mod_conflicts,
0.200.409 by Jelmer Vernooij
Support parsing .gitignore.
51
    ignores,
0.264.10 by Jelmer Vernooij
Yield inventory entries.
52
    inventory,
0.200.1476 by Jelmer Vernooij
Cope with working tree refactoring.
53
    lock,
0.200.381 by Jelmer Vernooij
Support working trees properly, status and ls.
54
    osutils,
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
55
    trace,
0.200.519 by Jelmer Vernooij
Move imports down, might not be available in older bzr-git versions.
56
    tree,
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
57
    workingtree,
58
    )
0.200.381 by Jelmer Vernooij
Support working trees properly, status and ls.
59
from bzrlib.decorators import (
60
    needs_read_lock,
61
    )
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
62
from bzrlib.mutabletree import needs_tree_write_lock
0.200.381 by Jelmer Vernooij
Support working trees properly, status and ls.
63
64
0.200.1096 by Jelmer Vernooij
Implement GitWorkingTreeFormat.initialize.
65
from bzrlib.plugins.git.dir import (
66
    LocalGitDir,
67
    )
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
68
from bzrlib.plugins.git.tree import (
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
69
    changes_from_git_changes,
0.200.617 by Jelmer Vernooij
Add custom InterTree for use between git revision trees.
70
    tree_delta_from_git_changes,
71
    )
0.200.971 by Chadrik
Fix 'bzr status' after 'bzr add' in native git working trees.
72
from bzrlib.plugins.git.mapping import (
73
    GitFileIdMap,
0.264.10 by Jelmer Vernooij
Yield inventory entries.
74
    mode_kind,
0.200.971 by Chadrik
Fix 'bzr status' after 'bzr add' in native git working trees.
75
    )
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
76
0.200.409 by Jelmer Vernooij
Support parsing .gitignore.
77
IGNORE_FILENAME = ".gitignore"
78
79
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
80
class GitWorkingTree(workingtree.WorkingTree):
81
    """A Git working tree."""
82
0.200.803 by Jelmer Vernooij
Default to non-bare repositories when initializing a control directory.
83
    def __init__(self, bzrdir, repo, branch, index):
0.200.379 by Jelmer Vernooij
Re-enable working tree support.
84
        self.basedir = bzrdir.root_transport.local_abspath('.')
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
85
        self.bzrdir = bzrdir
86
        self.repository = repo
0.200.1205 by Jelmer Vernooij
Implement GitWorkingTree.stored_kind.
87
        self.store = self.repository._git.object_store
0.200.384 by Jelmer Vernooij
Fix reading of inventory from index.
88
        self.mapping = self.repository.get_mapping()
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
89
        self._branch = branch
90
        self._transport = bzrdir.transport
91
        self._format = GitWorkingTreeFormat()
0.200.803 by Jelmer Vernooij
Default to non-bare repositories when initializing a control directory.
92
        self.index = index
0.200.1242 by Jelmer Vernooij
Support directories better.
93
        self._versioned_dirs = None
0.200.239 by Jelmer Vernooij
Provide views.
94
        self.views = self._make_views()
0.200.1173 by Jelmer Vernooij
Provide GitWorkingTree._rules_searcher.
95
        self._rules_searcher = None
0.200.381 by Jelmer Vernooij
Support working trees properly, status and ls.
96
        self._detect_case_handling()
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
97
        self._reset_data()
98
        self._fileid_map = self._basis_fileid_map.copy()
0.200.1476 by Jelmer Vernooij
Cope with working tree refactoring.
99
        self._lock_mode = None
100
        self._lock_count = 0
101
102
    def lock_read(self):
103
        """Lock the repository for read operations.
104
105
        :return: A bzrlib.lock.LogicalLockResult.
106
        """
107
        if not self._lock_mode:
108
            self._lock_mode = 'r'
109
            self._lock_count = 1
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
110
            self.index.read()
0.200.1476 by Jelmer Vernooij
Cope with working tree refactoring.
111
        else:
112
            self._lock_count += 1
113
        self.branch.lock_read()
114
        return lock.LogicalLockResult(self.unlock)
115
0.200.1477 by Jelmer Vernooij
Implement GitWorkingTree.lock_tree_write.
116
    def lock_tree_write(self):
117
        if not self._lock_mode:
118
            self._lock_mode = 'w'
119
            self._lock_count = 1
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
120
            self.index.read()
0.200.1477 by Jelmer Vernooij
Implement GitWorkingTree.lock_tree_write.
121
        elif self._lock_mode == 'r':
122
            raise errors.ReadOnlyError(self)
123
        else:
124
            self._lock_count +=1
125
        self.branch.lock_read()
126
        return lock.LogicalLockResult(self.unlock)
127
0.200.1476 by Jelmer Vernooij
Cope with working tree refactoring.
128
    def lock_write(self, token=None):
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.1476 by Jelmer Vernooij
Cope with working tree refactoring.
133
        elif self._lock_mode == 'r':
134
            raise errors.ReadOnlyError(self)
135
        else:
136
            self._lock_count +=1
137
        self.branch.lock_write()
138
        return lock.LogicalLockResult(self.unlock)
139
140
    def is_locked(self):
141
        return self._lock_count >= 1
142
143
    def get_physical_lock_status(self):
144
        return False
145
146
    def unlock(self):
147
        if not self._lock_count:
148
            return lock.cant_unlock_not_held(self)
0.200.1530 by Jelmer Vernooij
Fix lock order.
149
        self.branch.unlock()
0.200.1476 by Jelmer Vernooij
Cope with working tree refactoring.
150
        self._cleanup()
151
        self._lock_count -= 1
152
        if self._lock_count > 0:
153
            return
154
        self._lock_mode = None
0.200.173 by Jelmer Vernooij
Merge changes, open index.
155
0.200.1322 by Jelmer Vernooij
Add case detection.
156
    def _detect_case_handling(self):
157
        try:
158
            self._transport.stat(".git/cOnFiG")
159
        except errors.NoSuchFile:
160
            self.case_sensitive = True
161
        else:
162
            self.case_sensitive = False
163
0.200.1315 by Jelmer Vernooij
Implement WorkingTree.merge_modified.
164
    def merge_modified(self):
165
        return {}
166
0.200.1220 by Jelmer Vernooij
Support set_parent_trees.
167
    def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
168
        self.set_parent_ids([p for p, t in parents_list])
169
0.200.1599 by Jelmer Vernooij
Implement GitWorkingTree.iter_children.
170
    def iter_children(self, file_id):
171
        dpath = self.id2path(file_id) + "/"
172
        if dpath in self.index:
173
            return
174
        for path in self.index:
175
            if not path.startswith(dpath):
176
                continue
177
            if "/" in path[len(dpath):]:
178
                # Not a direct child but something further down
179
                continue
180
            yield self.path2id(path)
181
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
182
    def _index_add_entry(self, path, file_id, kind):
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
183
        assert self._lock_mode is not None
0.200.1206 by Jelmer Vernooij
Implement GitWorkingTree.all_file_ids.
184
        assert isinstance(path, basestring)
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
185
        assert type(file_id) == str or file_id is None
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
186
        if kind == "directory":
187
            # Git indexes don't contain directories
188
            return
189
        if kind == "file":
190
            blob = Blob()
191
            try:
192
                file, stat_val = self.get_file_with_stat(file_id, path)
193
            except (errors.NoSuchFile, IOError):
194
                # TODO: Rather than come up with something here, use the old index
195
                file = StringIO()
0.265.1 by Martin
Don't import posix module, the os wrapper exists for portability
196
                stat_val = os.stat_result(
197
                    (stat.S_IFREG | 0644, 0, 0, 0, 0, 0, 0, 0, 0, 0))
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
198
            blob.set_raw_string(file.read())
199
        elif kind == "symlink":
200
            blob = Blob()
201
            try:
202
                stat_val = os.lstat(self.abspath(path))
203
            except (errors.NoSuchFile, OSError):
204
                # TODO: Rather than come up with something here, use the 
205
                # old index
0.265.1 by Martin
Don't import posix module, the os wrapper exists for portability
206
                stat_val = os.stat_result(
207
                    (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.
208
            blob.set_raw_string(
209
                self.get_symlink_target(file_id, path).encode("utf-8"))
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
210
        else:
211
            raise AssertionError("unknown kind '%s'" % kind)
212
        # Add object to the repository if it didn't exist yet
0.200.1205 by Jelmer Vernooij
Implement GitWorkingTree.stored_kind.
213
        if not blob.id in self.store:
214
            self.store.add_object(blob)
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
215
        # Add an entry to the index or update the existing entry
216
        flags = 0 # FIXME
0.200.1242 by Jelmer Vernooij
Support directories better.
217
        encoded_path = path.encode("utf-8")
0.200.1531 by Jelmer Vernooij
Don't trust index contents - verify against file timestamps.
218
        self.index[encoded_path] = index_entry_from_stat(
219
            stat_val, blob.id, flags)
0.200.1242 by Jelmer Vernooij
Support directories better.
220
        if self._versioned_dirs is not None:
221
            self._ensure_versioned_dir(encoded_path)
222
223
    def _ensure_versioned_dir(self, dirname):
0.200.1249 by Jelmer Vernooij
Fix file id for tree root
224
        if dirname in self._versioned_dirs:
0.200.1242 by Jelmer Vernooij
Support directories better.
225
            return
0.200.1249 by Jelmer Vernooij
Fix file id for tree root
226
        if dirname != "":
227
            self._ensure_versioned_dir(posixpath.dirname(dirname))
0.200.1242 by Jelmer Vernooij
Support directories better.
228
        self._versioned_dirs.add(dirname)
229
230
    def _load_dirs(self):
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
231
        assert self._lock_mode is not None
0.200.1242 by Jelmer Vernooij
Support directories better.
232
        self._versioned_dirs = set()
233
        for p in self.index:
234
            self._ensure_versioned_dir(posixpath.dirname(p))
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
235
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
236
    def _unversion_path(self, path):
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
237
        assert self._lock_mode is not None
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
238
        encoded_path = path.encode("utf-8")
239
        try:
240
            del self.index[encoded_path]
241
        except KeyError:
242
            # A directory, perhaps?
243
            for p in list(self.index):
244
                if p.startswith(encoded_path+"/"):
245
                    del self.index[p]
0.200.1242 by Jelmer Vernooij
Support directories better.
246
        # FIXME: remove empty directories
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
247
0.200.1328 by Jelmer Vernooij
More test fixes.
248
    @needs_tree_write_lock
0.200.1192 by Jelmer Vernooij
Implement path2id.
249
    def unversion(self, file_ids):
250
        for file_id in file_ids:
251
            path = self.id2path(file_id)
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
252
            self._unversion_path(path)
0.200.1328 by Jelmer Vernooij
More test fixes.
253
        self.flush()
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
254
0.200.1243 by Jelmer Vernooij
Implement WorkingTree.check_state.
255
    def check_state(self):
256
        """Check that the working state is/isn't valid."""
257
        pass
258
0.200.1328 by Jelmer Vernooij
More test fixes.
259
    @needs_tree_write_lock
0.200.1215 by Jelmer Vernooij
Implement GitWorkingTree.remove.
260
    def remove(self, files, verbose=False, to_file=None, keep_files=True,
261
        force=False):
262
        """Remove nominated files from the working tree metadata.
263
264
        :param files: File paths relative to the basedir.
265
        :param keep_files: If true, the files will also be kept.
266
        :param force: Delete files and directories, even if they are changed
267
            and even if the directories are not empty.
268
        """
269
        all_files = set() # specified and nested files 
270
271
        if isinstance(files, basestring):
272
            files = [files]
273
274
        if to_file is None:
275
            to_file = sys.stdout
276
277
        files = list(all_files)
278
279
        if len(files) == 0:
280
            return # nothing to do
281
282
        # Sort needed to first handle directory content before the directory
283
        files.sort(reverse=True)
284
285
        def backup(file_to_backup):
286
            abs_path = self.abspath(file_to_backup)
287
            backup_name = self.bzrdir._available_backup_name(file_to_backup)
288
            osutils.rename(abs_path, self.abspath(backup_name))
289
            return "removed %s (but kept a copy: %s)" % (
290
                file_to_backup, backup_name)
291
292
        for f in files:
293
            fid = self.path2id(f)
294
            if not fid:
295
                message = "%s is not versioned." % (f,)
296
            else:
297
                abs_path = self.abspath(f)
298
                if verbose:
299
                    # having removed it, it must be either ignored or unknown
300
                    if self.is_ignored(f):
301
                        new_status = 'I'
302
                    else:
303
                        new_status = '?'
304
                    # XXX: Really should be a more abstract reporter interface
305
                    kind_ch = osutils.kind_marker(self.kind(fid))
306
                    to_file.write(new_status + '       ' + f + kind_ch + '\n')
307
                # Unversion file
308
                # FIXME: _unversion_path() is O(size-of-index) for directories
309
                self._unversion_path(f)
310
                message = "removed %s" % (f,)
311
                if osutils.lexists(abs_path):
312
                    if (osutils.isdir(abs_path) and
313
                        len(os.listdir(abs_path)) > 0):
314
                        if force:
315
                            osutils.rmtree(abs_path)
316
                            message = "deleted %s" % (f,)
317
                        else:
318
                            message = backup(f)
319
                    else:
320
                        if not keep_files:
321
                            osutils.delete_any(abs_path)
322
                            message = "deleted %s" % (f,)
323
324
            # print only one message (if any) per file.
325
            if message is not None:
326
                trace.note(message)
0.200.1328 by Jelmer Vernooij
More test fixes.
327
        self.flush()
0.200.1192 by Jelmer Vernooij
Implement path2id.
328
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
329
    def _add(self, files, ids, kinds):
330
        for (path, file_id, kind) in zip(files, ids, kinds):
0.200.1201 by Jelmer Vernooij
Implement _set_root_id.
331
            if file_id is not None:
0.200.1210 by Jelmer Vernooij
Implement GitWorkingTree._walkdirs.
332
                self._fileid_map.set_file_id(path.encode("utf-8"), file_id)
0.200.1206 by Jelmer Vernooij
Implement GitWorkingTree.all_file_ids.
333
            else:
0.200.1210 by Jelmer Vernooij
Implement GitWorkingTree._walkdirs.
334
                file_id = self._fileid_map.lookup_file_id(path.encode("utf-8"))
0.200.1206 by Jelmer Vernooij
Implement GitWorkingTree.all_file_ids.
335
            self._index_add_entry(path, file_id, kind)
0.200.1201 by Jelmer Vernooij
Implement _set_root_id.
336
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
337
    @needs_tree_write_lock
0.200.1240 by Jelmer Vernooij
Implement GitWorkingTree.smart_add.
338
    def smart_add(self, file_list, recurse=True, action=None, save=True):
339
        added = []
340
        ignored = {}
341
        user_dirs = []
342
        for filepath in osutils.canonical_relpaths(self.basedir, file_list):
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
343
            abspath = self.abspath(filepath)
344
            kind = osutils.file_kind(abspath)
0.200.1240 by Jelmer Vernooij
Implement GitWorkingTree.smart_add.
345
            if action is not None:
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
346
                file_id = action(self, None, filepath, kind)
0.200.1240 by Jelmer Vernooij
Implement GitWorkingTree.smart_add.
347
            else:
348
                file_id = None
349
            if kind in ("file", "symlink"):
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
350
                if save:
0.200.1240 by Jelmer Vernooij
Implement GitWorkingTree.smart_add.
351
                    self._index_add_entry(filepath, file_id, kind)
352
                added.append(filepath)
353
            elif kind == "directory":
354
                if recurse:
355
                    user_dirs.append(filepath)
356
            else:
357
                raise errors.BadFileKindError(filename=abspath, kind=kind)
358
        for user_dir in user_dirs:
359
            abs_user_dir = self.abspath(user_dir)
360
            for name in os.listdir(abs_user_dir):
361
                subp = os.path.join(user_dir, name)
0.200.1328 by Jelmer Vernooij
More test fixes.
362
                if self.is_control_filename(subp) or self.mapping.is_special_file(subp):
0.200.1257 by Jelmer Vernooij
Don't be verbose on control filenames.
363
                    continue
0.200.1240 by Jelmer Vernooij
Implement GitWorkingTree.smart_add.
364
                ignore_glob = self.is_ignored(subp)
365
                if ignore_glob is not None:
366
                    ignored.setdefault(ignore_glob, []).append(subp)
367
                    continue
368
                abspath = self.abspath(subp)
369
                kind = osutils.file_kind(abspath)
370
                if kind == "directory":
371
                    user_dirs.append(subp)
372
                else:
373
                    if action is not None:
0.200.1493 by Jelmer Vernooij
Test fixes.
374
                        file_id = action(self, None, filepath, kind)
0.200.1240 by Jelmer Vernooij
Implement GitWorkingTree.smart_add.
375
                    else:
376
                        file_id = None
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
377
                    if save:
0.200.1240 by Jelmer Vernooij
Implement GitWorkingTree.smart_add.
378
                        self._index_add_entry(subp, file_id, kind)
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
379
        if added and save:
380
            self.flush()
0.200.1240 by Jelmer Vernooij
Implement GitWorkingTree.smart_add.
381
        return added, ignored
382
0.200.1201 by Jelmer Vernooij
Implement _set_root_id.
383
    def _set_root_id(self, file_id):
384
        self._fileid_map.set_file_id("", file_id)
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
385
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
386
    @needs_tree_write_lock
0.200.1193 by Jelmer Vernooij
Implement GitWorkingTree.{move,rename_one}.
387
    def move(self, from_paths, to_dir=None, after=False):
388
        rename_tuples = []
389
        to_abs = self.abspath(to_dir)
390
        if not os.path.isdir(to_abs):
391
            raise errors.BzrMoveFailedError('', to_dir,
392
                errors.NotADirectory(to_abs))
393
394
        for from_rel in from_paths:
395
            from_tail = os.path.split(from_rel)[-1]
396
            to_rel = os.path.join(to_dir, from_tail)
397
            self.rename_one(from_rel, to_rel, after=after)
398
            rename_tuples.append((from_rel, to_rel))
0.200.1328 by Jelmer Vernooij
More test fixes.
399
        self.flush()
0.200.1193 by Jelmer Vernooij
Implement GitWorkingTree.{move,rename_one}.
400
        return rename_tuples
401
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
402
    @needs_tree_write_lock
0.200.1193 by Jelmer Vernooij
Implement GitWorkingTree.{move,rename_one}.
403
    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
404
        from_path = from_rel.encode("utf-8")
405
        to_path = to_rel.encode("utf-8")
406
        if not self.has_filename(to_rel):
407
            raise errors.BzrMoveFailedError(from_rel, to_rel,
408
                errors.NoSuchFile(to_rel))
409
        if not from_path in self.index:
410
            raise errors.BzrMoveFailedError(from_rel, to_rel,
411
                errors.NotVersionedError(path=from_rel))
0.200.1355 by Jelmer Vernooij
Fix missing import of posix.
412
        if not after:
413
            os.rename(self.abspath(from_rel), self.abspath(to_rel))
0.200.1203 by Jelmer Vernooij
Fix per_workingtree.test_rename_one.TestRenameOne.test_rename_after_non_existant_non_ascii
414
        self.index[to_path] = self.index[from_path]
415
        del self.index[from_path]
0.200.1328 by Jelmer Vernooij
More test fixes.
416
        self.flush()
0.200.1193 by Jelmer Vernooij
Implement GitWorkingTree.{move,rename_one}.
417
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
418
    def get_root_id(self):
0.200.1192 by Jelmer Vernooij
Implement path2id.
419
        return self.path2id("")
420
0.200.1242 by Jelmer Vernooij
Support directories better.
421
    def _has_dir(self, path):
0.200.1368 by Jelmer Vernooij
There is always a tree root.
422
        if path == "":
423
            return True
0.200.1242 by Jelmer Vernooij
Support directories better.
424
        if self._versioned_dirs is None:
425
            self._load_dirs()
426
        return path in self._versioned_dirs
427
0.200.1192 by Jelmer Vernooij
Implement path2id.
428
    @needs_read_lock
429
    def path2id(self, path):
0.200.1242 by Jelmer Vernooij
Support directories better.
430
        encoded_path = path.encode("utf-8")
431
        if self._is_versioned(encoded_path):
432
            return self._fileid_map.lookup_file_id(encoded_path)
433
        return None
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
434
0.200.1328 by Jelmer Vernooij
More test fixes.
435
    def _iter_files_recursive(self, from_dir=None):
436
        if from_dir is None:
437
            from_dir = ""
438
        for (dirpath, dirnames, filenames) in os.walk(self.abspath(from_dir)):
0.200.1302 by Jelmer Vernooij
Significantly improve performance of WorkingTree.extras().
439
            dir_relpath = dirpath[len(self.basedir):].strip("/")
440
            if self.bzrdir.is_control_filename(dir_relpath):
0.200.605 by Jelmer Vernooij
Ignore directories in WorkingTree.extras().
441
                continue
0.200.615 by Jelmer Vernooij
Optimize WorkingTree.extras().
442
            for filename in filenames:
0.200.1328 by Jelmer Vernooij
More test fixes.
443
                if not self.mapping.is_special_file(filename):
444
                    yield os.path.join(dir_relpath, filename)
0.200.1327 by Jelmer Vernooij
Factor out all file browsing in extras.
445
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
446
    @needs_read_lock
0.200.1327 by Jelmer Vernooij
Factor out all file browsing in extras.
447
    def extras(self):
448
        """Yield all unversioned files in this WorkingTree.
449
        """
0.200.1328 by Jelmer Vernooij
More test fixes.
450
        return set(self._iter_files_recursive()) - set(self.index)
0.200.605 by Jelmer Vernooij
Ignore directories in WorkingTree.extras().
451
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
452
    @needs_tree_write_lock
0.200.382 by Jelmer Vernooij
Support flushing index.
453
    def flush(self):
454
        # TODO: Maybe this should only write on dirty ?
0.200.1478 by Jelmer Vernooij
Avoid _control_files, it no longer exists.
455
        if self._lock_mode != 'w':
0.200.382 by Jelmer Vernooij
Support flushing index.
456
            raise errors.NotWriteLocked(self)
0.200.385 by Jelmer Vernooij
Cope with removed files.
457
        self.index.write()
0.200.382 by Jelmer Vernooij
Support flushing index.
458
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
459
    @needs_read_lock
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
460
    def __iter__(self):
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
461
        for path in self.index:
0.200.1192 by Jelmer Vernooij
Implement path2id.
462
            yield self.path2id(path)
0.200.1242 by Jelmer Vernooij
Support directories better.
463
        self._load_dirs()
464
        for path in self._versioned_dirs:
465
            yield self.path2id(path)
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
466
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
467
    def has_or_had_id(self, file_id):
468
        if self.has_id(file_id):
469
            return True
470
        if self.had_id(file_id):
471
            return True
472
        return False
473
474
    def had_id(self, file_id):
475
        path = self._basis_fileid_map.lookup_file_id(file_id)
476
        try:
477
            head = self.repository._git.head()
478
        except KeyError:
479
            # Assume no if basis is not accessible
480
            return False
0.200.1205 by Jelmer Vernooij
Implement GitWorkingTree.stored_kind.
481
        if head == ZERO_SHA:
482
            return False
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
483
        root_tree = self.store[head].tree
484
        try:
485
            tree_lookup_path(self.store.__getitem__, root_tree, path)
486
        except KeyError:
487
            return False
488
        else:
489
            return True
490
0.200.1198 by Jelmer Vernooij
Implement GitWorkingTree.has_id.
491
    def has_id(self, file_id):
492
        try:
493
            self.id2path(file_id)
494
        except errors.NoSuchId:
495
            return False
496
        else:
497
            return True
498
0.200.1530 by Jelmer Vernooij
Fix lock order.
499
    @needs_read_lock
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
500
    def id2path(self, file_id):
0.200.1532 by Jelmer Vernooij
Cope with float timestamps.
501
        assert type(file_id) is str, "file id not a string: %r" % file_id
0.200.1411 by Jelmer Vernooij
Fix control files.
502
        file_id = osutils.safe_utf8(file_id)
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
503
        path = self._fileid_map.lookup_path(file_id)
0.200.1213 by Jelmer Vernooij
Add note about directories.
504
        # FIXME: What about directories?
0.200.1242 by Jelmer Vernooij
Support directories better.
505
        if self._is_versioned(path):
506
            return path.decode("utf-8")
0.200.1214 by Jelmer Vernooij
Set container when raising NoSuchId.
507
        raise errors.NoSuchId(self, file_id)
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
508
0.200.1200 by Jelmer Vernooij
Support GitWorkingTree.get_file_mtime.
509
    def get_file_mtime(self, file_id, path=None):
510
        """See Tree.get_file_mtime."""
511
        if not path:
512
            path = self.id2path(file_id)
513
        return os.lstat(self.abspath(path)).st_mtime
514
0.200.409 by Jelmer Vernooij
Support parsing .gitignore.
515
    def get_ignore_list(self):
516
        ignoreset = getattr(self, '_ignoreset', None)
517
        if ignoreset is not None:
518
            return ignoreset
519
520
        ignore_globs = set()
521
        ignore_globs.update(ignores.get_runtime_ignores())
522
        ignore_globs.update(ignores.get_user_ignores())
523
        if self.has_filename(IGNORE_FILENAME):
524
            f = self.get_file_byname(IGNORE_FILENAME)
525
            try:
0.200.1198 by Jelmer Vernooij
Implement GitWorkingTree.has_id.
526
                # FIXME: Parse git file format, rather than assuming it's
527
                # the same as for bzr's native formats.
0.200.409 by Jelmer Vernooij
Support parsing .gitignore.
528
                ignore_globs.update(ignores.parse_ignore_file(f))
529
            finally:
530
                f.close()
531
        self._ignoreset = ignore_globs
532
        return ignore_globs
533
0.200.508 by Jelmer Vernooij
Skip inventory caching bits.
534
    def set_last_revision(self, revid):
535
        self._change_last_revision(revid)
536
0.200.379 by Jelmer Vernooij
Re-enable working tree support.
537
    def _reset_data(self):
0.248.3 by Jelmer Vernooij
Handle working trees without valid HEAD branch.
538
        try:
539
            head = self.repository._git.head()
540
        except KeyError, name:
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
541
            raise errors.NotBranchError("branch %s at %s" % (name,
542
                self.repository.base))
0.200.948 by Jelmer Vernooij
Cope with empty inventories.
543
        if head == ZERO_SHA:
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
544
            self._basis_fileid_map = GitFileIdMap({}, self.mapping)
0.200.948 by Jelmer Vernooij
Cope with empty inventories.
545
        else:
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
546
            self._basis_fileid_map = self.mapping.get_fileid_map(
547
                self.store.__getitem__, self.store[head].tree)
0.200.379 by Jelmer Vernooij
Re-enable working tree support.
548
0.200.381 by Jelmer Vernooij
Support working trees properly, status and ls.
549
    @needs_read_lock
0.200.1302 by Jelmer Vernooij
Significantly improve performance of WorkingTree.extras().
550
    def get_file_verifier(self, file_id, path=None, stat_value=None):
551
        if path is None:
552
            path = self.id2path(file_id)
0.200.1590 by Jelmer Vernooij
Fix support for directories in WorkingTree.
553
        try:
554
            return ("GIT", self.index[path][-2])
555
        except KeyError:
556
            if self._has_dir(path):
557
                return ("GIT", None)
558
            raise errors.NoSuchId(self, file_id)
0.200.1302 by Jelmer Vernooij
Significantly improve performance of WorkingTree.extras().
559
560
    @needs_read_lock
0.200.381 by Jelmer Vernooij
Support working trees properly, status and ls.
561
    def get_file_sha1(self, file_id, path=None, stat_value=None):
562
        if not path:
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
563
            path = self.id2path(file_id)
0.200.1302 by Jelmer Vernooij
Significantly improve performance of WorkingTree.extras().
564
        abspath = self.abspath(path).encode(osutils._fs_enc)
0.239.4 by Jelmer Vernooij
Cope with nonexistent files and directories in get_file_sha1.
565
        try:
0.200.1302 by Jelmer Vernooij
Significantly improve performance of WorkingTree.extras().
566
            return osutils.sha_file_by_name(abspath)
0.239.4 by Jelmer Vernooij
Cope with nonexistent files and directories in get_file_sha1.
567
        except OSError, (num, msg):
568
            if num in (errno.EISDIR, errno.ENOENT):
569
                return None
570
            raise
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
571
0.200.610 by Jelmer Vernooij
Support retrieving basis tree properly.
572
    def revision_tree(self, revid):
573
        return self.repository.revision_tree(revid)
574
0.200.1242 by Jelmer Vernooij
Support directories better.
575
    def _is_versioned(self, path):
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
576
        assert self._lock_mode is not None
0.200.1242 by Jelmer Vernooij
Support directories better.
577
        return (path in self.index or self._has_dir(path))
578
0.200.1239 by Jelmer Vernooij
Implement GitWorkingTree.filter_unversioned_files.
579
    def filter_unversioned_files(self, files):
0.200.1316 by Jelmer Vernooij
Fix filter_unversioned_files.
580
        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.
581
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
582
    def _get_dir_ie(self, path, parent_id):
0.200.1192 by Jelmer Vernooij
Implement path2id.
583
        file_id = self.path2id(path)
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
584
        return inventory.InventoryDirectory(file_id,
0.200.1190 by Jelmer Vernooij
Fix get_symlink_target call.
585
            posixpath.basename(path).strip("/"), parent_id)
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
586
587
    def _add_missing_parent_ids(self, path, dir_ids):
588
        if path in dir_ids:
589
            return []
590
        parent = posixpath.dirname(path).strip("/")
591
        ret = self._add_missing_parent_ids(parent, dir_ids)
592
        parent_id = dir_ids[parent]
593
        ie = self._get_dir_ie(path, parent_id)
594
        dir_ids[path] = ie.file_id
595
        ret.append((path, ie))
596
        return ret
597
0.200.1321 by Jelmer Vernooij
More fixes for compatibility with bzr.dev testsuite.
598
    def _get_file_ie(self, name, path, value, parent_id):
599
        assert isinstance(name, unicode)
0.200.1192 by Jelmer Vernooij
Implement path2id.
600
        assert isinstance(path, unicode)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
601
        assert isinstance(value, tuple) and len(value) == 10
602
        (ctime, mtime, dev, ino, mode, uid, gid, size, sha, flags) = value
0.200.1192 by Jelmer Vernooij
Implement path2id.
603
        file_id = self.path2id(path)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
604
        if type(file_id) != str:
605
            raise AssertionError
606
        kind = mode_kind(mode)
0.200.1321 by Jelmer Vernooij
More fixes for compatibility with bzr.dev testsuite.
607
        ie = inventory.entry_factory[kind](file_id, name, parent_id)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
608
        if kind == 'symlink':
0.200.1190 by Jelmer Vernooij
Fix get_symlink_target call.
609
            ie.symlink_target = self.get_symlink_target(file_id)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
610
        else:
611
            data = self.get_file_text(file_id, path)
612
            ie.text_sha1 = osutils.sha_string(data)
613
            ie.text_size = len(data)
614
            ie.executable = self.is_executable(file_id, path)
615
        ie.revision = None
616
        return ie
617
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
618
    def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
619
        mode = stat_result.st_mode
620
        return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
621
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
622
    @needs_read_lock
0.200.1205 by Jelmer Vernooij
Implement GitWorkingTree.stored_kind.
623
    def stored_kind(self, file_id, path=None):
624
        if path is None:
625
            path = self.id2path(file_id)
0.200.1328 by Jelmer Vernooij
More test fixes.
626
        try:
627
            return mode_kind(self.index[path.encode("utf-8")][4])
628
        except KeyError:
629
            # Maybe it's a directory?
630
            if self._has_dir(path):
631
                return "directory"
0.200.1205 by Jelmer Vernooij
Implement GitWorkingTree.stored_kind.
632
            raise errors.NoSuchId(self, file_id)
633
0.200.1539 by Jelmer Vernooij
Cope with new is_executable.
634
    def is_executable(self, file_id, path=None):
635
        if getattr(self, "_supports_executable", osutils.supports_executable)():
636
            if not path:
637
                path = self.id2path(file_id)
638
            mode = os.lstat(self.abspath(path)).st_mode
639
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
640
        else:
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
641
            basis_tree = self.basis_tree()
642
            if file_id in basis_tree:
643
                return basis_tree.is_executable(file_id)
644
            # Default to not executable
645
            return False
646
0.200.1539 by Jelmer Vernooij
Cope with new is_executable.
647
    def _is_executable_from_path_and_stat(self, path, stat_result):
648
        if getattr(self, "_supports_executable", osutils.supports_executable)():
649
            return self._is_executable_from_path_and_stat_from_stat(path, stat_result)
650
        else:
651
            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.
652
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
653
    @needs_read_lock
0.264.10 by Jelmer Vernooij
Yield inventory entries.
654
    def list_files(self, include_root=False, from_dir=None, recursive=True):
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
655
        # FIXME: Yield non-versioned files
0.200.1321 by Jelmer Vernooij
More fixes for compatibility with bzr.dev testsuite.
656
        if from_dir is None:
657
            from_dir = ""
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
658
        dir_ids = {}
0.200.1339 by Jelmer Vernooij
Some reformatting.
659
        fk_entries = {'directory': workingtree.TreeDirectory,
660
                      'file': workingtree.TreeFile,
661
                      'symlink': workingtree.TreeLink}
0.200.1192 by Jelmer Vernooij
Implement path2id.
662
        root_ie = self._get_dir_ie(u"", None)
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
663
        if include_root and not from_dir:
664
            yield "", "V", root_ie.kind, root_ie.file_id, root_ie
0.200.1192 by Jelmer Vernooij
Implement path2id.
665
        dir_ids[u""] = root_ie.file_id
0.200.1328 by Jelmer Vernooij
More test fixes.
666
        if recursive:
667
            path_iterator = self._iter_files_recursive(from_dir)
668
        else:
669
            if from_dir is None:
670
                start = self.basedir
671
            else:
672
                start = os.path.join(self.basedir, from_dir)
673
            path_iterator = sorted([os.path.join(from_dir, name) for name in
674
                os.listdir(start) if not self.bzrdir.is_control_filename(name)
675
                and not self.mapping.is_special_file(name)])
676
        for path in path_iterator:
677
            try:
678
                value = self.index[path]
679
            except KeyError:
680
                value = None
0.200.1192 by Jelmer Vernooij
Implement path2id.
681
            path = path.decode("utf-8")
0.200.1321 by Jelmer Vernooij
More fixes for compatibility with bzr.dev testsuite.
682
            parent, name = posixpath.split(path)
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
683
            for dir_path, dir_ie in self._add_missing_parent_ids(parent, dir_ids):
684
                yield dir_path, "V", dir_ie.kind, dir_ie.file_id, dir_ie
0.200.1328 by Jelmer Vernooij
More test fixes.
685
            if value is not None:
686
                ie = self._get_file_ie(name, path, value, dir_ids[parent])
687
                yield path, "V", ie.kind, ie.file_id, ie
688
            else:
689
                kind = osutils.file_kind(self.abspath(path))
690
                ie = fk_entries[kind]()
691
                yield path, "?", kind, None, ie
0.264.10 by Jelmer Vernooij
Yield inventory entries.
692
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
693
    @needs_read_lock
0.200.1206 by Jelmer Vernooij
Implement GitWorkingTree.all_file_ids.
694
    def all_file_ids(self):
695
        ids = {u"": self.path2id("")}
696
        for path in self.index:
0.200.1328 by Jelmer Vernooij
More test fixes.
697
            if self.mapping.is_special_file(path):
698
                continue
0.200.1206 by Jelmer Vernooij
Implement GitWorkingTree.all_file_ids.
699
            path = path.decode("utf-8")
700
            parent = posixpath.dirname(path).strip("/")
701
            for e in self._add_missing_parent_ids(parent, ids):
702
                pass
703
            ids[path] = self.path2id(path)
704
        return set(ids.values())
705
0.200.1374 by Jelmer Vernooij
Implement GitWorkingTree._directory_is_tree_reference.
706
    def _directory_is_tree_reference(self, path):
707
        # FIXME: Check .gitsubmodules for path
708
        return False
709
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
710
    @needs_read_lock
0.264.9 by Jelmer Vernooij
Implement basic GitWorkingTree.iter_entries_by_dir.
711
    def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):
712
        # FIXME: Is return order correct?
0.200.1252 by Jelmer Vernooij
Support specific_file_ids in GitWorkingTree.iter_entries_by_dir.
713
        if yield_parents:
714
            raise NotImplementedError(self.iter_entries_by_dir)
0.264.9 by Jelmer Vernooij
Implement basic GitWorkingTree.iter_entries_by_dir.
715
        if specific_file_ids is not None:
0.200.1252 by Jelmer Vernooij
Support specific_file_ids in GitWorkingTree.iter_entries_by_dir.
716
            specific_paths = [self.id2path(file_id) for file_id in specific_file_ids]
717
            if specific_paths in ([u""], []):
718
                specific_paths = None
719
            else:
720
                specific_paths = set(specific_paths)
721
        else:
722
            specific_paths = None
0.200.1192 by Jelmer Vernooij
Implement path2id.
723
        root_ie = self._get_dir_ie(u"", None)
0.200.1252 by Jelmer Vernooij
Support specific_file_ids in GitWorkingTree.iter_entries_by_dir.
724
        if specific_paths is None:
725
            yield u"", root_ie
0.200.1192 by Jelmer Vernooij
Implement path2id.
726
        dir_ids = {u"": root_ie.file_id}
0.264.10 by Jelmer Vernooij
Yield inventory entries.
727
        for path, value in self.index.iteritems():
0.200.1328 by Jelmer Vernooij
More test fixes.
728
            if self.mapping.is_special_file(path):
729
                continue
0.200.1192 by Jelmer Vernooij
Implement path2id.
730
            path = path.decode("utf-8")
0.200.1252 by Jelmer Vernooij
Support specific_file_ids in GitWorkingTree.iter_entries_by_dir.
731
            if specific_paths is not None and not path in specific_paths:
732
                continue
0.200.1321 by Jelmer Vernooij
More fixes for compatibility with bzr.dev testsuite.
733
            (parent, name) = posixpath.split(path)
0.200.1251 by Jelmer Vernooij
Cope with files dissapearing in GitWorkingTree.
734
            try:
0.200.1321 by Jelmer Vernooij
More fixes for compatibility with bzr.dev testsuite.
735
                file_ie = self._get_file_ie(name, path, value, None)
0.200.1251 by Jelmer Vernooij
Cope with files dissapearing in GitWorkingTree.
736
            except IOError:
737
                continue
0.200.1207 by Jelmer Vernooij
Fix some formatting.
738
            for (dir_path, dir_ie) in self._add_missing_parent_ids(parent,
739
                    dir_ids):
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
740
                yield dir_path, dir_ie
0.200.1251 by Jelmer Vernooij
Cope with files dissapearing in GitWorkingTree.
741
            file_ie.parent_id = self.path2id(parent)
742
            yield path, file_ie
0.264.9 by Jelmer Vernooij
Implement basic GitWorkingTree.iter_entries_by_dir.
743
0.200.619 by Jelmer Vernooij
Provide dummy WorkingTree.conflicts() implementation rather than spending a lot of time not finding any conflicts.
744
    @needs_read_lock
745
    def conflicts(self):
746
        # FIXME:
0.262.1 by Jelmer Vernooij
Fix WorkingTree.conflicts().
747
        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.
748
0.200.1193 by Jelmer Vernooij
Implement GitWorkingTree.{move,rename_one}.
749
    def update_basis_by_delta(self, new_revid, delta):
0.200.1196 by Jelmer Vernooij
Implement GitWorkingTree.update_basis_by_delta.
750
        # The index just contains content, which won't have changed.
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
751
        self._reset_data()
0.200.1193 by Jelmer Vernooij
Implement GitWorkingTree.{move,rename_one}.
752
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
753
    @needs_read_lock
0.200.1328 by Jelmer Vernooij
More test fixes.
754
    def get_canonical_inventory_path(self, path):
755
        for p in self.index:
756
            if p.lower() == path.lower():
757
                return p
758
        else:
759
            return path
760
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
761
    @needs_read_lock
0.200.1210 by Jelmer Vernooij
Implement GitWorkingTree._walkdirs.
762
    def _walkdirs(self, prefix=""):
763
        if prefix != "":
764
            prefix += "/"
765
        per_dir = defaultdict(list)
766
        for path, value in self.index.iteritems():
0.200.1328 by Jelmer Vernooij
More test fixes.
767
            if self.mapping.is_special_file(path):
768
                continue
0.200.1210 by Jelmer Vernooij
Implement GitWorkingTree._walkdirs.
769
            if not path.startswith(prefix):
770
                continue
771
            (dirname, child_name) = posixpath.split(path)
772
            dirname = dirname.decode("utf-8")
773
            dir_file_id = self.path2id(dirname)
774
            assert isinstance(value, tuple) and len(value) == 10
775
            (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
776
            stat_result = os.stat_result((mode, ino,
0.200.1211 by Jelmer Vernooij
Fix statresult.
777
                    dev, 1, uid, gid, size,
778
                    0, mtime, ctime))
0.200.1210 by Jelmer Vernooij
Implement GitWorkingTree._walkdirs.
779
            per_dir[(dirname, dir_file_id)].append(
780
                (path.decode("utf-8"), child_name.decode("utf-8"),
781
                mode_kind(mode), stat_result,
782
                self.path2id(path.decode("utf-8")),
783
                mode_kind(mode)))
784
        return per_dir.iteritems()
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
785
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
786
    def _lookup_entry(self, path, update_index=False):
0.200.1543 by Jelmer Vernooij
Support symlinks.
787
        assert type(path) == str
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
788
        entry = self.index[path]
789
        index_mode = entry[-6]
790
        index_sha = entry[-2]
791
        disk_path = os.path.join(self.basedir, path)
792
        disk_stat = os.lstat(disk_path)
793
        disk_mtime = disk_stat.st_mtime
794
        if isinstance(entry[1], tuple):
795
            index_mtime = entry[1][0]
796
        else:
797
            index_mtime = int(entry[1])
798
        mtime_delta = (disk_mtime - index_mtime)
799
        disk_mode = cleanup_mode(disk_stat.st_mode)
800
        if mtime_delta > 0 or disk_mode != index_mode:
801
            if stat.S_ISDIR(disk_mode):
802
                try:
803
                    subrepo = Repo(disk_path)
804
                except NotGitRepository:
805
                    return (None, None)
806
                else:
807
                    disk_mode = S_IFGITLINK
808
                    git_id = subrepo.head()
0.200.1543 by Jelmer Vernooij
Support symlinks.
809
            elif stat.S_ISLNK(disk_mode):
0.200.1545 by Jelmer Vernooij
Some more test fixes.
810
                blob = Blob.from_string(os.readlink(disk_path).encode('utf-8'))
0.200.1543 by Jelmer Vernooij
Support symlinks.
811
                git_id = blob.id
812
            elif stat.S_ISREG(disk_mode):
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
813
                with open(disk_path, 'r') as f:
814
                    blob = Blob.from_string(f.read())
815
                git_id = blob.id
0.200.1543 by Jelmer Vernooij
Support symlinks.
816
            else:
817
                raise AssertionError
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
818
            if update_index:
819
                flags = 0 # FIXME
0.200.1545 by Jelmer Vernooij
Some more test fixes.
820
                self.index[path] = index_entry_from_stat(disk_stat, git_id, flags, disk_mode)
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
821
            return (git_id, disk_mode)
822
        return (index_sha, index_mode)
823
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
824
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
825
class GitWorkingTreeFormat(workingtree.WorkingTreeFormat):
826
0.200.1206 by Jelmer Vernooij
Implement GitWorkingTree.all_file_ids.
827
    _tree_class = GitWorkingTree
828
0.200.1295 by Jelmer Vernooij
Mark working trees as not supporting directories.
829
    supports_versioned_directories = False
830
0.200.656 by Jelmer Vernooij
Implement GitWorkingTreeFormat._matchingbzrdir.
831
    @property
832
    def _matchingbzrdir(self):
0.200.1140 by Jelmer Vernooij
Update now that the control dir formats are no longer in __init__.
833
        from bzrlib.plugins.git.dir import LocalGitControlDirFormat
0.200.1013 by Jelmer Vernooij
More renames.
834
        return LocalGitControlDirFormat()
0.200.656 by Jelmer Vernooij
Implement GitWorkingTreeFormat._matchingbzrdir.
835
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
836
    def get_format_description(self):
837
        return "Git Working Tree"
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
838
0.200.1096 by Jelmer Vernooij
Implement GitWorkingTreeFormat.initialize.
839
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
840
                   accelerator_tree=None, hardlink=False):
841
        """See WorkingTreeFormat.initialize()."""
842
        if not isinstance(a_bzrdir, LocalGitDir):
843
            raise errors.IncompatibleFormat(self, a_bzrdir)
844
        index = Index(a_bzrdir.root_transport.local_abspath(".git/index"))
845
        index.write()
846
        return GitWorkingTree(a_bzrdir, a_bzrdir.open_repository(),
847
            a_bzrdir.open_branch(), index)
848
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
849
850
class InterIndexGitTree(tree.InterTree):
851
    """InterTree that works between a Git revision tree and an index."""
852
853
    def __init__(self, source, target):
854
        super(InterIndexGitTree, self).__init__(source, target)
855
        self._index = target.index
856
857
    @classmethod
858
    def is_compatible(cls, source, target):
859
        from bzrlib.plugins.git.repository import GitRevisionTree
860
        return (isinstance(source, GitRevisionTree) and 
861
                isinstance(target, GitWorkingTree))
862
0.200.1536 by Jelmer Vernooij
Fix locks.
863
    @needs_read_lock
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
864
    def compare(self, want_unchanged=False, specific_files=None,
865
                extra_trees=None, require_versioned=False, include_root=False,
866
                want_unversioned=False):
0.200.1529 by Jelmer Vernooij
Add changes_between_tree_and_index.
867
        # FIXME: Handle include_root
868
        changes = changes_between_git_tree_and_index(
0.200.1205 by Jelmer Vernooij
Implement GitWorkingTree.stored_kind.
869
            self.source.store, self.source.tree, 
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
870
            self.target, want_unchanged=want_unchanged,
0.200.1529 by Jelmer Vernooij
Add changes_between_tree_and_index.
871
            want_unversioned=want_unversioned)
0.200.1338 by Jelmer Vernooij
Simplify code for getting file id map.
872
        source_fileid_map = self.source._fileid_map
873
        target_fileid_map = self.target._fileid_map
0.200.1030 by Jelmer Vernooij
More work on supporting roundtripping push.
874
        ret = tree_delta_from_git_changes(changes, self.target.mapping,
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
875
            (source_fileid_map, target_fileid_map),
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
876
            specific_file=specific_files, require_versioned=require_versioned)
877
        if want_unversioned:
878
            for e in self.target.extras():
0.200.1207 by Jelmer Vernooij
Fix some formatting.
879
                ret.unversioned.append((e, None,
880
                    osutils.file_kind(self.target.abspath(e))))
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
881
        return ret
882
0.200.1536 by Jelmer Vernooij
Fix locks.
883
    @needs_read_lock
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
884
    def iter_changes(self, include_unchanged=False, specific_files=None,
0.200.1207 by Jelmer Vernooij
Fix some formatting.
885
        pb=None, extra_trees=[], require_versioned=True,
886
        want_unversioned=False):
0.200.1529 by Jelmer Vernooij
Add changes_between_tree_and_index.
887
        changes = changes_between_git_tree_and_index(
0.200.1205 by Jelmer Vernooij
Implement GitWorkingTree.stored_kind.
888
            self.source.store, self.source.tree,
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
889
            self.target, want_unchanged=include_unchanged,
0.200.1529 by Jelmer Vernooij
Add changes_between_tree_and_index.
890
            want_unversioned=want_unversioned)
0.200.1179 by Jelmer Vernooij
Avoid using verifiers for natively imported revisions, save a lot of time.
891
        return changes_from_git_changes(changes, self.target.mapping,
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
892
            specific_file=specific_files)
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
893
0.200.1179 by Jelmer Vernooij
Avoid using verifiers for natively imported revisions, save a lot of time.
894
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
895
tree.InterTree.register_optimiser(InterIndexGitTree)
0.200.1529 by Jelmer Vernooij
Add changes_between_tree_and_index.
896
897
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
898
def changes_between_git_tree_and_index(object_store, tree, target,
0.200.1529 by Jelmer Vernooij
Add changes_between_tree_and_index.
899
        want_unchanged=False, want_unversioned=False, update_index=False):
900
    """Determine the changes between a git tree and a working tree with index.
901
902
    """
0.200.1538 by Jelmer Vernooij
More work on tree-reference support.
903
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
904
    names = target.index._byname.keys()
905
    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.
906
            object_store, tree, want_unchanged=want_unchanged):
0.200.1538 by Jelmer Vernooij
More work on tree-reference support.
907
        if name == (None, None):
908
            continue
0.200.1531 by Jelmer Vernooij
Don't trust index contents - verify against file timestamps.
909
        yield (name, mode, sha)