/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.1600 by Jelmer Vernooij
Cope with paths as lists of elements.
430
        if type(path) is list:
431
            path = u"/".join(path)
0.200.1242 by Jelmer Vernooij
Support directories better.
432
        encoded_path = path.encode("utf-8")
433
        if self._is_versioned(encoded_path):
434
            return self._fileid_map.lookup_file_id(encoded_path)
435
        return None
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
436
0.200.1328 by Jelmer Vernooij
More test fixes.
437
    def _iter_files_recursive(self, from_dir=None):
438
        if from_dir is None:
439
            from_dir = ""
440
        for (dirpath, dirnames, filenames) in os.walk(self.abspath(from_dir)):
0.200.1302 by Jelmer Vernooij
Significantly improve performance of WorkingTree.extras().
441
            dir_relpath = dirpath[len(self.basedir):].strip("/")
442
            if self.bzrdir.is_control_filename(dir_relpath):
0.200.605 by Jelmer Vernooij
Ignore directories in WorkingTree.extras().
443
                continue
0.200.615 by Jelmer Vernooij
Optimize WorkingTree.extras().
444
            for filename in filenames:
0.200.1328 by Jelmer Vernooij
More test fixes.
445
                if not self.mapping.is_special_file(filename):
446
                    yield os.path.join(dir_relpath, filename)
0.200.1327 by Jelmer Vernooij
Factor out all file browsing in extras.
447
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
448
    @needs_read_lock
0.200.1327 by Jelmer Vernooij
Factor out all file browsing in extras.
449
    def extras(self):
450
        """Yield all unversioned files in this WorkingTree.
451
        """
0.200.1328 by Jelmer Vernooij
More test fixes.
452
        return set(self._iter_files_recursive()) - set(self.index)
0.200.605 by Jelmer Vernooij
Ignore directories in WorkingTree.extras().
453
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
454
    @needs_tree_write_lock
0.200.382 by Jelmer Vernooij
Support flushing index.
455
    def flush(self):
456
        # TODO: Maybe this should only write on dirty ?
0.200.1478 by Jelmer Vernooij
Avoid _control_files, it no longer exists.
457
        if self._lock_mode != 'w':
0.200.382 by Jelmer Vernooij
Support flushing index.
458
            raise errors.NotWriteLocked(self)
0.200.385 by Jelmer Vernooij
Cope with removed files.
459
        self.index.write()
0.200.382 by Jelmer Vernooij
Support flushing index.
460
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
461
    @needs_read_lock
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
462
    def __iter__(self):
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
463
        for path in self.index:
0.200.1192 by Jelmer Vernooij
Implement path2id.
464
            yield self.path2id(path)
0.200.1242 by Jelmer Vernooij
Support directories better.
465
        self._load_dirs()
466
        for path in self._versioned_dirs:
467
            yield self.path2id(path)
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
468
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
469
    def has_or_had_id(self, file_id):
470
        if self.has_id(file_id):
471
            return True
472
        if self.had_id(file_id):
473
            return True
474
        return False
475
476
    def had_id(self, file_id):
477
        path = self._basis_fileid_map.lookup_file_id(file_id)
478
        try:
479
            head = self.repository._git.head()
480
        except KeyError:
481
            # Assume no if basis is not accessible
482
            return False
0.200.1205 by Jelmer Vernooij
Implement GitWorkingTree.stored_kind.
483
        if head == ZERO_SHA:
484
            return False
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
485
        root_tree = self.store[head].tree
486
        try:
487
            tree_lookup_path(self.store.__getitem__, root_tree, path)
488
        except KeyError:
489
            return False
490
        else:
491
            return True
492
0.200.1198 by Jelmer Vernooij
Implement GitWorkingTree.has_id.
493
    def has_id(self, file_id):
494
        try:
495
            self.id2path(file_id)
496
        except errors.NoSuchId:
497
            return False
498
        else:
499
            return True
500
0.200.1530 by Jelmer Vernooij
Fix lock order.
501
    @needs_read_lock
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
502
    def id2path(self, file_id):
0.200.1532 by Jelmer Vernooij
Cope with float timestamps.
503
        assert type(file_id) is str, "file id not a string: %r" % file_id
0.200.1411 by Jelmer Vernooij
Fix control files.
504
        file_id = osutils.safe_utf8(file_id)
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
505
        path = self._fileid_map.lookup_path(file_id)
0.200.1213 by Jelmer Vernooij
Add note about directories.
506
        # FIXME: What about directories?
0.200.1242 by Jelmer Vernooij
Support directories better.
507
        if self._is_versioned(path):
508
            return path.decode("utf-8")
0.200.1214 by Jelmer Vernooij
Set container when raising NoSuchId.
509
        raise errors.NoSuchId(self, file_id)
0.264.1 by Jelmer Vernooij
Provide stubs using inventory for the moment.:
510
0.200.1200 by Jelmer Vernooij
Support GitWorkingTree.get_file_mtime.
511
    def get_file_mtime(self, file_id, path=None):
512
        """See Tree.get_file_mtime."""
513
        if not path:
514
            path = self.id2path(file_id)
515
        return os.lstat(self.abspath(path)).st_mtime
516
0.200.409 by Jelmer Vernooij
Support parsing .gitignore.
517
    def get_ignore_list(self):
518
        ignoreset = getattr(self, '_ignoreset', None)
519
        if ignoreset is not None:
520
            return ignoreset
521
522
        ignore_globs = set()
523
        ignore_globs.update(ignores.get_runtime_ignores())
524
        ignore_globs.update(ignores.get_user_ignores())
525
        if self.has_filename(IGNORE_FILENAME):
526
            f = self.get_file_byname(IGNORE_FILENAME)
527
            try:
0.200.1198 by Jelmer Vernooij
Implement GitWorkingTree.has_id.
528
                # FIXME: Parse git file format, rather than assuming it's
529
                # the same as for bzr's native formats.
0.200.409 by Jelmer Vernooij
Support parsing .gitignore.
530
                ignore_globs.update(ignores.parse_ignore_file(f))
531
            finally:
532
                f.close()
533
        self._ignoreset = ignore_globs
534
        return ignore_globs
535
0.200.508 by Jelmer Vernooij
Skip inventory caching bits.
536
    def set_last_revision(self, revid):
537
        self._change_last_revision(revid)
538
0.200.379 by Jelmer Vernooij
Re-enable working tree support.
539
    def _reset_data(self):
0.248.3 by Jelmer Vernooij
Handle working trees without valid HEAD branch.
540
        try:
541
            head = self.repository._git.head()
542
        except KeyError, name:
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
543
            raise errors.NotBranchError("branch %s at %s" % (name,
544
                self.repository.base))
0.200.948 by Jelmer Vernooij
Cope with empty inventories.
545
        if head == ZERO_SHA:
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
546
            self._basis_fileid_map = GitFileIdMap({}, self.mapping)
0.200.948 by Jelmer Vernooij
Cope with empty inventories.
547
        else:
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
548
            self._basis_fileid_map = self.mapping.get_fileid_map(
549
                self.store.__getitem__, self.store[head].tree)
0.200.379 by Jelmer Vernooij
Re-enable working tree support.
550
0.200.381 by Jelmer Vernooij
Support working trees properly, status and ls.
551
    @needs_read_lock
0.200.1302 by Jelmer Vernooij
Significantly improve performance of WorkingTree.extras().
552
    def get_file_verifier(self, file_id, path=None, stat_value=None):
553
        if path is None:
554
            path = self.id2path(file_id)
0.200.1590 by Jelmer Vernooij
Fix support for directories in WorkingTree.
555
        try:
556
            return ("GIT", self.index[path][-2])
557
        except KeyError:
558
            if self._has_dir(path):
559
                return ("GIT", None)
560
            raise errors.NoSuchId(self, file_id)
0.200.1302 by Jelmer Vernooij
Significantly improve performance of WorkingTree.extras().
561
562
    @needs_read_lock
0.200.381 by Jelmer Vernooij
Support working trees properly, status and ls.
563
    def get_file_sha1(self, file_id, path=None, stat_value=None):
564
        if not path:
0.264.2 by Jelmer Vernooij
Implement GitWorkingTree.{_add,__iter__,id2path}.
565
            path = self.id2path(file_id)
0.200.1302 by Jelmer Vernooij
Significantly improve performance of WorkingTree.extras().
566
        abspath = self.abspath(path).encode(osutils._fs_enc)
0.239.4 by Jelmer Vernooij
Cope with nonexistent files and directories in get_file_sha1.
567
        try:
0.200.1302 by Jelmer Vernooij
Significantly improve performance of WorkingTree.extras().
568
            return osutils.sha_file_by_name(abspath)
0.239.4 by Jelmer Vernooij
Cope with nonexistent files and directories in get_file_sha1.
569
        except OSError, (num, msg):
570
            if num in (errno.EISDIR, errno.ENOENT):
571
                return None
572
            raise
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
573
0.200.610 by Jelmer Vernooij
Support retrieving basis tree properly.
574
    def revision_tree(self, revid):
575
        return self.repository.revision_tree(revid)
576
0.200.1242 by Jelmer Vernooij
Support directories better.
577
    def _is_versioned(self, path):
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
578
        assert self._lock_mode is not None
0.200.1242 by Jelmer Vernooij
Support directories better.
579
        return (path in self.index or self._has_dir(path))
580
0.200.1239 by Jelmer Vernooij
Implement GitWorkingTree.filter_unversioned_files.
581
    def filter_unversioned_files(self, files):
0.200.1316 by Jelmer Vernooij
Fix filter_unversioned_files.
582
        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.
583
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
584
    def _get_dir_ie(self, path, parent_id):
0.200.1192 by Jelmer Vernooij
Implement path2id.
585
        file_id = self.path2id(path)
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
586
        return inventory.InventoryDirectory(file_id,
0.200.1190 by Jelmer Vernooij
Fix get_symlink_target call.
587
            posixpath.basename(path).strip("/"), parent_id)
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
588
589
    def _add_missing_parent_ids(self, path, dir_ids):
590
        if path in dir_ids:
591
            return []
592
        parent = posixpath.dirname(path).strip("/")
593
        ret = self._add_missing_parent_ids(parent, dir_ids)
594
        parent_id = dir_ids[parent]
595
        ie = self._get_dir_ie(path, parent_id)
596
        dir_ids[path] = ie.file_id
597
        ret.append((path, ie))
598
        return ret
599
0.200.1321 by Jelmer Vernooij
More fixes for compatibility with bzr.dev testsuite.
600
    def _get_file_ie(self, name, path, value, parent_id):
601
        assert isinstance(name, unicode)
0.200.1192 by Jelmer Vernooij
Implement path2id.
602
        assert isinstance(path, unicode)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
603
        assert isinstance(value, tuple) and len(value) == 10
604
        (ctime, mtime, dev, ino, mode, uid, gid, size, sha, flags) = value
0.200.1192 by Jelmer Vernooij
Implement path2id.
605
        file_id = self.path2id(path)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
606
        if type(file_id) != str:
607
            raise AssertionError
608
        kind = mode_kind(mode)
0.200.1321 by Jelmer Vernooij
More fixes for compatibility with bzr.dev testsuite.
609
        ie = inventory.entry_factory[kind](file_id, name, parent_id)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
610
        if kind == 'symlink':
0.200.1190 by Jelmer Vernooij
Fix get_symlink_target call.
611
            ie.symlink_target = self.get_symlink_target(file_id)
0.264.10 by Jelmer Vernooij
Yield inventory entries.
612
        else:
613
            data = self.get_file_text(file_id, path)
614
            ie.text_sha1 = osutils.sha_string(data)
615
            ie.text_size = len(data)
616
            ie.executable = self.is_executable(file_id, path)
617
        ie.revision = None
618
        return ie
619
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
620
    def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
621
        mode = stat_result.st_mode
622
        return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
623
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
624
    @needs_read_lock
0.200.1205 by Jelmer Vernooij
Implement GitWorkingTree.stored_kind.
625
    def stored_kind(self, file_id, path=None):
626
        if path is None:
627
            path = self.id2path(file_id)
0.200.1328 by Jelmer Vernooij
More test fixes.
628
        try:
629
            return mode_kind(self.index[path.encode("utf-8")][4])
630
        except KeyError:
631
            # Maybe it's a directory?
632
            if self._has_dir(path):
633
                return "directory"
0.200.1205 by Jelmer Vernooij
Implement GitWorkingTree.stored_kind.
634
            raise errors.NoSuchId(self, file_id)
635
0.200.1539 by Jelmer Vernooij
Cope with new is_executable.
636
    def is_executable(self, file_id, path=None):
637
        if getattr(self, "_supports_executable", osutils.supports_executable)():
638
            if not path:
639
                path = self.id2path(file_id)
640
            mode = os.lstat(self.abspath(path)).st_mode
641
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
642
        else:
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
643
            basis_tree = self.basis_tree()
644
            if file_id in basis_tree:
645
                return basis_tree.is_executable(file_id)
646
            # Default to not executable
647
            return False
648
0.200.1539 by Jelmer Vernooij
Cope with new is_executable.
649
    def _is_executable_from_path_and_stat(self, path, stat_result):
650
        if getattr(self, "_supports_executable", osutils.supports_executable)():
651
            return self._is_executable_from_path_and_stat_from_stat(path, stat_result)
652
        else:
653
            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.
654
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
655
    @needs_read_lock
0.264.10 by Jelmer Vernooij
Yield inventory entries.
656
    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.
657
        # FIXME: Yield non-versioned files
0.200.1321 by Jelmer Vernooij
More fixes for compatibility with bzr.dev testsuite.
658
        if from_dir is None:
659
            from_dir = ""
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
660
        dir_ids = {}
0.200.1339 by Jelmer Vernooij
Some reformatting.
661
        fk_entries = {'directory': workingtree.TreeDirectory,
662
                      'file': workingtree.TreeFile,
663
                      'symlink': workingtree.TreeLink}
0.200.1192 by Jelmer Vernooij
Implement path2id.
664
        root_ie = self._get_dir_ie(u"", None)
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
665
        if include_root and not from_dir:
666
            yield "", "V", root_ie.kind, root_ie.file_id, root_ie
0.200.1192 by Jelmer Vernooij
Implement path2id.
667
        dir_ids[u""] = root_ie.file_id
0.200.1328 by Jelmer Vernooij
More test fixes.
668
        if recursive:
669
            path_iterator = self._iter_files_recursive(from_dir)
670
        else:
671
            if from_dir is None:
672
                start = self.basedir
673
            else:
674
                start = os.path.join(self.basedir, from_dir)
675
            path_iterator = sorted([os.path.join(from_dir, name) for name in
676
                os.listdir(start) if not self.bzrdir.is_control_filename(name)
677
                and not self.mapping.is_special_file(name)])
678
        for path in path_iterator:
679
            try:
680
                value = self.index[path]
681
            except KeyError:
682
                value = None
0.200.1192 by Jelmer Vernooij
Implement path2id.
683
            path = path.decode("utf-8")
0.200.1321 by Jelmer Vernooij
More fixes for compatibility with bzr.dev testsuite.
684
            parent, name = posixpath.split(path)
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
685
            for dir_path, dir_ie in self._add_missing_parent_ids(parent, dir_ids):
686
                yield dir_path, "V", dir_ie.kind, dir_ie.file_id, dir_ie
0.200.1328 by Jelmer Vernooij
More test fixes.
687
            if value is not None:
688
                ie = self._get_file_ie(name, path, value, dir_ids[parent])
689
                yield path, "V", ie.kind, ie.file_id, ie
690
            else:
691
                kind = osutils.file_kind(self.abspath(path))
692
                ie = fk_entries[kind]()
693
                yield path, "?", kind, None, ie
0.264.10 by Jelmer Vernooij
Yield inventory entries.
694
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
695
    @needs_read_lock
0.200.1206 by Jelmer Vernooij
Implement GitWorkingTree.all_file_ids.
696
    def all_file_ids(self):
697
        ids = {u"": self.path2id("")}
698
        for path in self.index:
0.200.1328 by Jelmer Vernooij
More test fixes.
699
            if self.mapping.is_special_file(path):
700
                continue
0.200.1206 by Jelmer Vernooij
Implement GitWorkingTree.all_file_ids.
701
            path = path.decode("utf-8")
702
            parent = posixpath.dirname(path).strip("/")
703
            for e in self._add_missing_parent_ids(parent, ids):
704
                pass
705
            ids[path] = self.path2id(path)
706
        return set(ids.values())
707
0.200.1374 by Jelmer Vernooij
Implement GitWorkingTree._directory_is_tree_reference.
708
    def _directory_is_tree_reference(self, path):
709
        # FIXME: Check .gitsubmodules for path
710
        return False
711
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
712
    @needs_read_lock
0.264.9 by Jelmer Vernooij
Implement basic GitWorkingTree.iter_entries_by_dir.
713
    def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):
714
        # FIXME: Is return order correct?
0.200.1252 by Jelmer Vernooij
Support specific_file_ids in GitWorkingTree.iter_entries_by_dir.
715
        if yield_parents:
716
            raise NotImplementedError(self.iter_entries_by_dir)
0.264.9 by Jelmer Vernooij
Implement basic GitWorkingTree.iter_entries_by_dir.
717
        if specific_file_ids is not None:
0.200.1252 by Jelmer Vernooij
Support specific_file_ids in GitWorkingTree.iter_entries_by_dir.
718
            specific_paths = [self.id2path(file_id) for file_id in specific_file_ids]
719
            if specific_paths in ([u""], []):
720
                specific_paths = None
721
            else:
722
                specific_paths = set(specific_paths)
723
        else:
724
            specific_paths = None
0.200.1192 by Jelmer Vernooij
Implement path2id.
725
        root_ie = self._get_dir_ie(u"", None)
0.200.1252 by Jelmer Vernooij
Support specific_file_ids in GitWorkingTree.iter_entries_by_dir.
726
        if specific_paths is None:
727
            yield u"", root_ie
0.200.1192 by Jelmer Vernooij
Implement path2id.
728
        dir_ids = {u"": root_ie.file_id}
0.264.10 by Jelmer Vernooij
Yield inventory entries.
729
        for path, value in self.index.iteritems():
0.200.1328 by Jelmer Vernooij
More test fixes.
730
            if self.mapping.is_special_file(path):
731
                continue
0.200.1192 by Jelmer Vernooij
Implement path2id.
732
            path = path.decode("utf-8")
0.200.1252 by Jelmer Vernooij
Support specific_file_ids in GitWorkingTree.iter_entries_by_dir.
733
            if specific_paths is not None and not path in specific_paths:
734
                continue
0.200.1321 by Jelmer Vernooij
More fixes for compatibility with bzr.dev testsuite.
735
            (parent, name) = posixpath.split(path)
0.200.1251 by Jelmer Vernooij
Cope with files dissapearing in GitWorkingTree.
736
            try:
0.200.1321 by Jelmer Vernooij
More fixes for compatibility with bzr.dev testsuite.
737
                file_ie = self._get_file_ie(name, path, value, None)
0.200.1251 by Jelmer Vernooij
Cope with files dissapearing in GitWorkingTree.
738
            except IOError:
739
                continue
0.200.1207 by Jelmer Vernooij
Fix some formatting.
740
            for (dir_path, dir_ie) in self._add_missing_parent_ids(parent,
741
                    dir_ids):
0.264.11 by Jelmer Vernooij
Completer implementation of iter_entries_by_dir and list_files.
742
                yield dir_path, dir_ie
0.200.1251 by Jelmer Vernooij
Cope with files dissapearing in GitWorkingTree.
743
            file_ie.parent_id = self.path2id(parent)
744
            yield path, file_ie
0.264.9 by Jelmer Vernooij
Implement basic GitWorkingTree.iter_entries_by_dir.
745
0.200.619 by Jelmer Vernooij
Provide dummy WorkingTree.conflicts() implementation rather than spending a lot of time not finding any conflicts.
746
    @needs_read_lock
747
    def conflicts(self):
748
        # FIXME:
0.262.1 by Jelmer Vernooij
Fix WorkingTree.conflicts().
749
        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.
750
0.200.1193 by Jelmer Vernooij
Implement GitWorkingTree.{move,rename_one}.
751
    def update_basis_by_delta(self, new_revid, delta):
0.200.1196 by Jelmer Vernooij
Implement GitWorkingTree.update_basis_by_delta.
752
        # The index just contains content, which won't have changed.
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
753
        self._reset_data()
0.200.1193 by Jelmer Vernooij
Implement GitWorkingTree.{move,rename_one}.
754
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
755
    @needs_read_lock
0.200.1328 by Jelmer Vernooij
More test fixes.
756
    def get_canonical_inventory_path(self, path):
757
        for p in self.index:
758
            if p.lower() == path.lower():
759
                return p
760
        else:
761
            return path
762
0.200.1525 by Jelmer Vernooij
Make sure to always use an up-to-date index.
763
    @needs_read_lock
0.200.1210 by Jelmer Vernooij
Implement GitWorkingTree._walkdirs.
764
    def _walkdirs(self, prefix=""):
765
        if prefix != "":
766
            prefix += "/"
767
        per_dir = defaultdict(list)
768
        for path, value in self.index.iteritems():
0.200.1328 by Jelmer Vernooij
More test fixes.
769
            if self.mapping.is_special_file(path):
770
                continue
0.200.1210 by Jelmer Vernooij
Implement GitWorkingTree._walkdirs.
771
            if not path.startswith(prefix):
772
                continue
773
            (dirname, child_name) = posixpath.split(path)
774
            dirname = dirname.decode("utf-8")
775
            dir_file_id = self.path2id(dirname)
776
            assert isinstance(value, tuple) and len(value) == 10
777
            (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
778
            stat_result = os.stat_result((mode, ino,
0.200.1211 by Jelmer Vernooij
Fix statresult.
779
                    dev, 1, uid, gid, size,
780
                    0, mtime, ctime))
0.200.1210 by Jelmer Vernooij
Implement GitWorkingTree._walkdirs.
781
            per_dir[(dirname, dir_file_id)].append(
782
                (path.decode("utf-8"), child_name.decode("utf-8"),
783
                mode_kind(mode), stat_result,
784
                self.path2id(path.decode("utf-8")),
785
                mode_kind(mode)))
786
        return per_dir.iteritems()
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
787
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
788
    def _lookup_entry(self, path, update_index=False):
0.200.1543 by Jelmer Vernooij
Support symlinks.
789
        assert type(path) == str
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
790
        entry = self.index[path]
791
        index_mode = entry[-6]
792
        index_sha = entry[-2]
793
        disk_path = os.path.join(self.basedir, path)
794
        disk_stat = os.lstat(disk_path)
795
        disk_mtime = disk_stat.st_mtime
796
        if isinstance(entry[1], tuple):
797
            index_mtime = entry[1][0]
798
        else:
799
            index_mtime = int(entry[1])
800
        mtime_delta = (disk_mtime - index_mtime)
801
        disk_mode = cleanup_mode(disk_stat.st_mode)
802
        if mtime_delta > 0 or disk_mode != index_mode:
803
            if stat.S_ISDIR(disk_mode):
804
                try:
805
                    subrepo = Repo(disk_path)
806
                except NotGitRepository:
807
                    return (None, None)
808
                else:
809
                    disk_mode = S_IFGITLINK
810
                    git_id = subrepo.head()
0.200.1543 by Jelmer Vernooij
Support symlinks.
811
            elif stat.S_ISLNK(disk_mode):
0.200.1545 by Jelmer Vernooij
Some more test fixes.
812
                blob = Blob.from_string(os.readlink(disk_path).encode('utf-8'))
0.200.1543 by Jelmer Vernooij
Support symlinks.
813
                git_id = blob.id
814
            elif stat.S_ISREG(disk_mode):
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
815
                with open(disk_path, 'r') as f:
816
                    blob = Blob.from_string(f.read())
817
                git_id = blob.id
0.200.1543 by Jelmer Vernooij
Support symlinks.
818
            else:
819
                raise AssertionError
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
820
            if update_index:
821
                flags = 0 # FIXME
0.200.1545 by Jelmer Vernooij
Some more test fixes.
822
                self.index[path] = index_entry_from_stat(disk_stat, git_id, flags, disk_mode)
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
823
            return (git_id, disk_mode)
824
        return (index_sha, index_mode)
825
0.200.1308 by Jelmer Vernooij
Write index to disk after adding files.
826
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
827
class GitWorkingTreeFormat(workingtree.WorkingTreeFormat):
828
0.200.1206 by Jelmer Vernooij
Implement GitWorkingTree.all_file_ids.
829
    _tree_class = GitWorkingTree
830
0.200.1295 by Jelmer Vernooij
Mark working trees as not supporting directories.
831
    supports_versioned_directories = False
832
0.200.656 by Jelmer Vernooij
Implement GitWorkingTreeFormat._matchingbzrdir.
833
    @property
834
    def _matchingbzrdir(self):
0.200.1140 by Jelmer Vernooij
Update now that the control dir formats are no longer in __init__.
835
        from bzrlib.plugins.git.dir import LocalGitControlDirFormat
0.200.1013 by Jelmer Vernooij
More renames.
836
        return LocalGitControlDirFormat()
0.200.656 by Jelmer Vernooij
Implement GitWorkingTreeFormat._matchingbzrdir.
837
0.200.90 by Jelmer Vernooij
Basic support for opening working trees.
838
    def get_format_description(self):
839
        return "Git Working Tree"
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
840
0.200.1096 by Jelmer Vernooij
Implement GitWorkingTreeFormat.initialize.
841
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
842
                   accelerator_tree=None, hardlink=False):
843
        """See WorkingTreeFormat.initialize()."""
844
        if not isinstance(a_bzrdir, LocalGitDir):
845
            raise errors.IncompatibleFormat(self, a_bzrdir)
846
        index = Index(a_bzrdir.root_transport.local_abspath(".git/index"))
847
        index.write()
848
        return GitWorkingTree(a_bzrdir, a_bzrdir.open_repository(),
849
            a_bzrdir.open_branch(), index)
850
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
851
852
class InterIndexGitTree(tree.InterTree):
853
    """InterTree that works between a Git revision tree and an index."""
854
855
    def __init__(self, source, target):
856
        super(InterIndexGitTree, self).__init__(source, target)
857
        self._index = target.index
858
859
    @classmethod
860
    def is_compatible(cls, source, target):
861
        from bzrlib.plugins.git.repository import GitRevisionTree
862
        return (isinstance(source, GitRevisionTree) and 
863
                isinstance(target, GitWorkingTree))
864
0.200.1536 by Jelmer Vernooij
Fix locks.
865
    @needs_read_lock
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
866
    def compare(self, want_unchanged=False, specific_files=None,
867
                extra_trees=None, require_versioned=False, include_root=False,
868
                want_unversioned=False):
0.200.1529 by Jelmer Vernooij
Add changes_between_tree_and_index.
869
        # FIXME: Handle include_root
870
        changes = changes_between_git_tree_and_index(
0.200.1205 by Jelmer Vernooij
Implement GitWorkingTree.stored_kind.
871
            self.source.store, self.source.tree, 
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
872
            self.target, want_unchanged=want_unchanged,
0.200.1529 by Jelmer Vernooij
Add changes_between_tree_and_index.
873
            want_unversioned=want_unversioned)
0.200.1338 by Jelmer Vernooij
Simplify code for getting file id map.
874
        source_fileid_map = self.source._fileid_map
875
        target_fileid_map = self.target._fileid_map
0.200.1030 by Jelmer Vernooij
More work on supporting roundtripping push.
876
        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.
877
            (source_fileid_map, target_fileid_map),
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
878
            specific_file=specific_files, require_versioned=require_versioned)
879
        if want_unversioned:
880
            for e in self.target.extras():
0.200.1207 by Jelmer Vernooij
Fix some formatting.
881
                ret.unversioned.append((e, None,
882
                    osutils.file_kind(self.target.abspath(e))))
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
883
        return ret
884
0.200.1536 by Jelmer Vernooij
Fix locks.
885
    @needs_read_lock
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
886
    def iter_changes(self, include_unchanged=False, specific_files=None,
0.200.1207 by Jelmer Vernooij
Fix some formatting.
887
        pb=None, extra_trees=[], require_versioned=True,
888
        want_unversioned=False):
0.200.1529 by Jelmer Vernooij
Add changes_between_tree_and_index.
889
        changes = changes_between_git_tree_and_index(
0.200.1205 by Jelmer Vernooij
Implement GitWorkingTree.stored_kind.
890
            self.source.store, self.source.tree,
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
891
            self.target, want_unchanged=include_unchanged,
0.200.1529 by Jelmer Vernooij
Add changes_between_tree_and_index.
892
            want_unversioned=want_unversioned)
0.200.1179 by Jelmer Vernooij
Avoid using verifiers for natively imported revisions, save a lot of time.
893
        return changes_from_git_changes(changes, self.target.mapping,
0.200.622 by Jelmer Vernooij
Implement InterTree.iter_changes() as well.
894
            specific_file=specific_files)
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
895
0.200.1179 by Jelmer Vernooij
Avoid using verifiers for natively imported revisions, save a lot of time.
896
0.200.616 by Jelmer Vernooij
Provide custom intertree implementation for GitRevisionTree->GitWorkingTree.
897
tree.InterTree.register_optimiser(InterIndexGitTree)
0.200.1529 by Jelmer Vernooij
Add changes_between_tree_and_index.
898
899
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
900
def changes_between_git_tree_and_index(object_store, tree, target,
0.200.1529 by Jelmer Vernooij
Add changes_between_tree_and_index.
901
        want_unchanged=False, want_unversioned=False, update_index=False):
902
    """Determine the changes between a git tree and a working tree with index.
903
904
    """
0.200.1538 by Jelmer Vernooij
More work on tree-reference support.
905
0.200.1542 by Jelmer Vernooij
Refactor iter_changes.
906
    names = target.index._byname.keys()
907
    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.
908
            object_store, tree, want_unchanged=want_unchanged):
0.200.1538 by Jelmer Vernooij
More work on tree-reference support.
909
        if name == (None, None):
910
            continue
0.200.1531 by Jelmer Vernooij
Don't trust index contents - verify against file timestamps.
911
        yield (name, mode, sha)