/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/git/workingtree.py

  • Committer: Jelmer Vernooij
  • Date: 2018-11-17 00:47:52 UTC
  • mfrom: (7182 work)
  • mto: This revision was merged to the branch mainline in revision 7305.
  • Revision ID: jelmer@jelmer.uk-20181117004752-6ywampe5pfywlby4
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
    Index,
31
31
    SHA1Writer,
32
32
    build_index_from_tree,
33
 
    changes_from_tree,
34
33
    index_entry_from_path,
35
34
    index_entry_from_stat,
36
 
    iter_fresh_entries,
37
35
    FLAG_STAGEMASK,
38
36
    read_submodule_head,
39
37
    validate_path,
43
41
    tree_lookup_path,
44
42
    )
45
43
from dulwich.objects import (
46
 
    Blob,
47
 
    Tree,
48
 
    S_IFGITLINK,
49
44
    S_ISGITLINK,
50
 
    ZERO_SHA,
51
 
    )
52
 
from dulwich.repo import (
53
 
    NotGitRepository,
54
 
    Repo as GitRepo,
55
45
    )
56
46
import os
57
47
import posixpath
58
 
import re
59
48
import stat
60
49
import sys
61
50
 
77
66
from ..decorators import (
78
67
    only_raises,
79
68
    )
80
 
from ..bzr import (
81
 
    inventory,
82
 
    )
83
69
from ..mutabletree import (
84
70
    BadReferenceTarget,
85
71
    MutableTree,
100
86
IGNORE_FILENAME = ".gitignore"
101
87
 
102
88
 
103
 
class GitWorkingTree(MutableGitIndexTree,workingtree.WorkingTree):
 
89
class GitWorkingTree(MutableGitIndexTree, workingtree.WorkingTree):
104
90
    """A Git working tree."""
105
91
 
106
92
    def __init__(self, controldir, repo, branch):
150
136
            self._lock_mode = 'w'
151
137
            self._lock_count = 1
152
138
            try:
153
 
                self._index_file = GitFile(self.control_transport.local_abspath('index'), 'wb')
 
139
                self._index_file = GitFile(
 
140
                    self.control_transport.local_abspath('index'), 'wb')
154
141
            except FileLocked:
155
142
                raise errors.LockContention('index')
156
143
            self._read_index()
157
144
        elif self._lock_mode == 'r':
158
145
            raise errors.ReadOnlyError(self)
159
146
        else:
160
 
            self._lock_count +=1
 
147
            self._lock_count += 1
161
148
 
162
149
    def lock_tree_write(self):
163
150
        self.branch.lock_read()
164
151
        try:
165
152
            self._lock_write_tree()
166
153
            return lock.LogicalLockResult(self.unlock)
167
 
        except:
 
154
        except BaseException:
168
155
            self.branch.unlock()
169
156
            raise
170
157
 
173
160
        try:
174
161
            self._lock_write_tree()
175
162
            return lock.LogicalLockResult(self.unlock)
176
 
        except:
 
163
        except BaseException:
177
164
            self.branch.unlock()
178
165
            raise
179
166
 
235
222
 
236
223
    def _set_merges_from_parent_ids(self, rhs_parent_ids):
237
224
        try:
238
 
            merges = [self.branch.lookup_bzr_revision_id(revid)[0] for revid in rhs_parent_ids]
 
225
            merges = [self.branch.lookup_bzr_revision_id(
 
226
                revid)[0] for revid in rhs_parent_ids]
239
227
        except errors.NoSuchRevision as e:
240
228
            raise errors.GhostRevisionUnusableHere(e.revision)
241
229
        if merges:
242
 
            self.control_transport.put_bytes('MERGE_HEAD', b'\n'.join(merges),
 
230
            self.control_transport.put_bytes(
 
231
                'MERGE_HEAD', b'\n'.join(merges),
243
232
                mode=self.controldir._get_file_mode())
244
233
        else:
245
234
            try:
260
249
            working tree. Any of these may be ghosts.
261
250
        """
262
251
        with self.lock_tree_write():
263
 
            self._check_parents_for_ghosts(revision_ids,
264
 
                allow_leftmost_as_ghost=allow_leftmost_as_ghost)
 
252
            self._check_parents_for_ghosts(
 
253
                revision_ids, allow_leftmost_as_ghost=allow_leftmost_as_ghost)
265
254
            for revision_id in revision_ids:
266
255
                _mod_revision.check_not_reserved_id(revision_id)
267
256
 
292
281
        else:
293
282
            for l in osutils.split_lines(merges_bytes):
294
283
                revision_id = l.rstrip(b'\n')
295
 
                parents.append(self.branch.lookup_foreign_revision_id(revision_id))
 
284
                parents.append(
 
285
                    self.branch.lookup_foreign_revision_id(revision_id))
296
286
        return parents
297
287
 
298
288
    def check_state(self):
300
290
        pass
301
291
 
302
292
    def remove(self, files, verbose=False, to_file=None, keep_files=True,
303
 
        force=False):
 
293
               force=False):
304
294
        """Remove nominated files from the working tree metadata.
305
295
 
306
296
        :param files: File paths relative to the basedir.
316
306
 
317
307
        def backup(file_to_backup):
318
308
            abs_path = self.abspath(file_to_backup)
319
 
            backup_name = self.controldir._available_backup_name(file_to_backup)
 
309
            backup_name = self.controldir._available_backup_name(
 
310
                file_to_backup)
320
311
            osutils.rename(abs_path, self.abspath(backup_name))
321
312
            return "removed %s (but kept a copy: %s)" % (
322
313
                file_to_backup, backup_name)
353
344
            files = list(all_files)
354
345
 
355
346
            if len(files) == 0:
356
 
                return # nothing to do
 
347
                return  # nothing to do
357
348
 
358
 
            # Sort needed to first handle directory content before the directory
 
349
            # Sort needed to first handle directory content before the
 
350
            # directory
359
351
            files.sort(reverse=True)
360
352
 
361
353
            # Bail out if we are going to delete files we shouldn't
362
354
            if not keep_files and not force:
363
355
                for (file_id, path, content_change, versioned, parent_id, name,
364
 
                     kind, executable) in self.iter_changes(self.basis_tree(),
365
 
                         include_unchanged=True, require_versioned=False,
366
 
                         want_unversioned=True, specific_files=files):
367
 
                    if versioned[0] == False:
 
356
                     kind, executable) in self.iter_changes(
 
357
                         self.basis_tree(), include_unchanged=True,
 
358
                         require_versioned=False, want_unversioned=True,
 
359
                         specific_files=files):
 
360
                    if versioned[0] is False:
368
361
                        # The record is unknown or newly added
369
362
                        files_to_backup.append(path[1])
370
 
                        files_to_backup.extend(osutils.parent_directories(path[1]))
371
 
                    elif (content_change and (kind[1] is not None) and
372
 
                            osutils.is_inside_any(files, path[1])):
 
363
                        files_to_backup.extend(
 
364
                            osutils.parent_directories(path[1]))
 
365
                    elif (content_change and (kind[1] is not None)
 
366
                            and osutils.is_inside_any(files, path[1])):
373
367
                        # Versioned and changed, but not deleted, and still
374
368
                        # in one of the dirs to be deleted.
375
369
                        files_to_backup.append(path[1])
376
 
                        files_to_backup.extend(osutils.parent_directories(path[1]))
 
370
                        files_to_backup.extend(
 
371
                            osutils.parent_directories(path[1]))
377
372
 
378
373
            for f in files:
379
374
                if f == '':
431
426
        added = []
432
427
        ignored = {}
433
428
        user_dirs = []
 
429
 
434
430
        def call_action(filepath, kind):
 
431
            if filepath == '':
 
432
                return
435
433
            if action is not None:
436
434
                parent_path = posixpath.dirname(filepath)
437
435
                parent_id = self.path2id(parent_path)
441
439
                    raise workingtree.SettingFileIdUnsupported()
442
440
 
443
441
        with self.lock_tree_write():
444
 
            for filepath in osutils.canonical_relpaths(self.basedir, file_list):
 
442
            for filepath in osutils.canonical_relpaths(
 
443
                    self.basedir, file_list):
445
444
                filepath, can_access = osutils.normalized_filename(filepath)
446
445
                if not can_access:
447
446
                    raise errors.InvalidNormalization(filepath)
449
448
                abspath = self.abspath(filepath)
450
449
                kind = osutils.file_kind(abspath)
451
450
                if kind in ("file", "symlink"):
452
 
                    (index, subpath) = self._lookup_index(filepath.encode('utf-8'))
 
451
                    (index, subpath) = self._lookup_index(
 
452
                        filepath.encode('utf-8'))
453
453
                    if subpath in index:
454
454
                        # Already present
455
455
                        continue
458
458
                        self._index_add_entry(filepath, kind)
459
459
                    added.append(filepath)
460
460
                elif kind == "directory":
461
 
                    (index, subpath) = self._lookup_index(filepath.encode('utf-8'))
 
461
                    (index, subpath) = self._lookup_index(
 
462
                        filepath.encode('utf-8'))
462
463
                    if subpath not in index:
463
464
                        call_action(filepath, kind)
464
465
                    if recurse:
469
470
                abs_user_dir = self.abspath(user_dir)
470
471
                if user_dir != '':
471
472
                    try:
472
 
                        transport = _mod_transport.get_transport_from_path(abs_user_dir)
 
473
                        transport = _mod_transport.get_transport_from_path(
 
474
                            abs_user_dir)
473
475
                        _mod_controldir.ControlDirFormat.find_format(transport)
474
476
                        subtree = True
475
477
                    except errors.NotBranchError:
484
486
 
485
487
                for name in os.listdir(abs_user_dir):
486
488
                    subp = os.path.join(user_dir, name)
487
 
                    if self.is_control_filename(subp) or self.mapping.is_special_file(subp):
 
489
                    if (self.is_control_filename(subp) or
 
490
                            self.mapping.is_special_file(subp)):
488
491
                        continue
489
492
                    ignore_glob = self.is_ignored(subp)
490
493
                    if ignore_glob is not None:
495
498
                    if kind == "directory":
496
499
                        user_dirs.append(subp)
497
500
                    else:
498
 
                        (index, subpath) = self._lookup_index(subp.encode('utf-8'))
 
501
                        (index, subpath) = self._lookup_index(
 
502
                            subp.encode('utf-8'))
499
503
                        if subpath in index:
500
504
                            # Already present
501
505
                            continue
502
506
                        if subp in conflicts_related:
503
507
                            continue
504
 
                        call_action(filepath, kind)
 
508
                        call_action(subp, kind)
505
509
                        if save:
506
510
                            self._index_add_entry(subp, kind)
507
511
                        added.append(subp)
513
517
    def _iter_files_recursive(self, from_dir=None, include_dirs=False):
514
518
        if from_dir is None:
515
519
            from_dir = u""
516
 
        for (dirpath, dirnames, filenames) in os.walk(self.abspath(from_dir).encode(osutils._fs_enc)):
 
520
        encoded_from_dir = self.abspath(from_dir).encode(osutils._fs_enc)
 
521
        for (dirpath, dirnames, filenames) in os.walk(encoded_from_dir):
517
522
            dir_relpath = dirpath[len(self.basedir):].strip(b"/")
518
 
            if self.controldir.is_control_filename(dir_relpath.decode(osutils._fs_enc)):
 
523
            if self.controldir.is_control_filename(
 
524
                    dir_relpath.decode(osutils._fs_enc)):
519
525
                continue
520
526
            for name in list(dirnames):
521
 
                if self.controldir.is_control_filename(name.decode(osutils._fs_enc)):
 
527
                if self.controldir.is_control_filename(
 
528
                        name.decode(osutils._fs_enc)):
522
529
                    dirnames.remove(name)
523
530
                    continue
524
531
                relpath = os.path.join(dir_relpath, name)
543
550
        """Yield all unversioned files in this WorkingTree.
544
551
        """
545
552
        with self.lock_read():
546
 
            index_paths = set([p.decode('utf-8') for p, i in self._recurse_index_entries()])
 
553
            index_paths = set([p.decode('utf-8')
 
554
                               for p, i in self._recurse_index_entries()])
547
555
            all_paths = set(self._iter_files_recursive(include_dirs=True))
548
556
            for p in (all_paths - index_paths):
549
557
                if not self._has_dir(p.encode('utf-8')):
556
564
                if kinds[pos] is None:
557
565
                    fullpath = osutils.normpath(self.abspath(f))
558
566
                    try:
559
 
                         kind = osutils.file_kind(fullpath)
 
567
                        kind = osutils.file_kind(fullpath)
560
568
                    except OSError as e:
561
569
                        if e.errno == errno.ENOENT:
562
570
                            raise errors.NoSuchFile(fullpath)
563
 
                    if kind == 'directory' and f != '' and os.path.exists(os.path.join(fullpath, '.git')):
 
571
                    if (kind == 'directory' and f != '' and
 
572
                            os.path.exists(os.path.join(fullpath, '.git'))):
564
573
                        kind = 'tree-reference'
565
574
                    kinds[pos] = kind
566
575
 
568
577
        if self._lock_mode != 'w':
569
578
            raise errors.NotWriteLocked(self)
570
579
        # TODO(jelmer): This shouldn't be writing in-place, but index.lock is
571
 
        # already in use and GitFile doesn't allow overriding the lock file name :(
 
580
        # already in use and GitFile doesn't allow overriding the lock file
 
581
        # name :(
572
582
        f = open(self.control_transport.local_abspath('index'), 'wb')
573
583
        # Note that _flush will close the file
574
584
        self._flush(f)
578
588
            shaf = SHA1Writer(f)
579
589
            write_index_dict(shaf, self.index)
580
590
            shaf.close()
581
 
        except:
 
591
        except BaseException:
582
592
            f.abort()
583
593
            raise
584
594
        self._index_dirty = False
602
612
        except KeyError:
603
613
            return False
604
614
        try:
605
 
            tree_lookup_path(self.store.__getitem__, root_tree, path.encode('utf-8'))
 
615
            tree_lookup_path(self.store.__getitem__,
 
616
                             root_tree, path.encode('utf-8'))
606
617
        except KeyError:
607
618
            return False
608
619
        else:
609
620
            return True
610
621
 
611
 
    def get_file_mtime(self, path, file_id=None):
 
622
    def get_file_mtime(self, path):
612
623
        """See Tree.get_file_mtime."""
613
624
        try:
614
625
            return self._lstat(path).st_mtime
627
638
            ignore_globs = set()
628
639
            ignore_globs.update(ignores.get_runtime_ignores())
629
640
            ignore_globs.update(ignores.get_user_ignores())
630
 
            self._global_ignoreglobster = globbing.ExceptionGlobster(ignore_globs)
 
641
            self._global_ignoreglobster = globbing.ExceptionGlobster(
 
642
                ignore_globs)
631
643
        match = self._global_ignoreglobster.match(filename)
632
644
        if match is not None:
633
645
            return match
677
689
                self.store.__getitem__, self.store[head].tree)
678
690
        self._fileid_map = self._basis_fileid_map.copy()
679
691
 
680
 
    def get_file_verifier(self, path, file_id=None, stat_value=None):
 
692
    def get_file_verifier(self, path, stat_value=None):
681
693
        with self.lock_read():
682
694
            (index, subpath) = self._lookup_index(path.encode('utf-8'))
683
695
            try:
687
699
                    return ("GIT", None)
688
700
                raise errors.NoSuchFile(path)
689
701
 
690
 
    def get_file_sha1(self, path, file_id=None, stat_value=None):
 
702
    def get_file_sha1(self, path, stat_value=None):
691
703
        with self.lock_read():
692
704
            if not self.is_versioned(path):
693
705
                raise errors.NoSuchFile(path)
709
721
    def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
710
722
        return self.basis_tree().is_executable(path)
711
723
 
712
 
    def stored_kind(self, path, file_id=None):
 
724
    def stored_kind(self, path):
713
725
        with self.lock_read():
714
726
            encoded_path = path.encode('utf-8')
715
727
            (index, subpath) = self._lookup_index(encoded_path)
725
737
        return os.lstat(self.abspath(path))
726
738
 
727
739
    def _live_entry(self, path):
728
 
        return index_entry_from_path(self.abspath(path.decode('utf-8')).encode(osutils._fs_enc))
 
740
        encoded_path = self.abspath(path.decode('utf-8')).encode(
 
741
            osutils._fs_enc)
 
742
        return index_entry_from_path(encoded_path)
729
743
 
730
 
    def is_executable(self, path, file_id=None):
 
744
    def is_executable(self, path):
731
745
        with self.lock_read():
732
 
            if getattr(self, "_supports_executable", osutils.supports_executable)():
 
746
            if getattr(self, "_supports_executable",
 
747
                       osutils.supports_executable)():
733
748
                mode = self._lstat(path).st_mode
734
749
            else:
735
750
                (index, subpath) = self._lookup_index(path.encode('utf-8'))
740
755
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
741
756
 
742
757
    def _is_executable_from_path_and_stat(self, path, stat_result):
743
 
        if getattr(self, "_supports_executable", osutils.supports_executable)():
744
 
            return self._is_executable_from_path_and_stat_from_stat(path, stat_result)
 
758
        if getattr(self, "_supports_executable",
 
759
                   osutils.supports_executable)():
 
760
            return self._is_executable_from_path_and_stat_from_stat(
 
761
                path, stat_result)
745
762
        else:
746
 
            return self._is_executable_from_path_and_stat_from_basis(path, stat_result)
 
763
            return self._is_executable_from_path_and_stat_from_basis(
 
764
                path, stat_result)
747
765
 
748
766
    def list_files(self, include_root=False, from_dir=None, recursive=True):
749
 
        if from_dir is None:
 
767
        if from_dir is None or from_dir == '.':
750
768
            from_dir = u""
751
769
        dir_ids = {}
752
770
        fk_entries = {'directory': tree.TreeDirectory,
759
777
                yield "", "V", root_ie.kind, root_ie.file_id, root_ie
760
778
            dir_ids[u""] = root_ie.file_id
761
779
            if recursive:
762
 
                path_iterator = sorted(self._iter_files_recursive(from_dir, include_dirs=True))
 
780
                path_iterator = sorted(
 
781
                    self._iter_files_recursive(from_dir, include_dirs=True))
763
782
            else:
764
 
                path_iterator = sorted([os.path.join(from_dir, name.decode(osutils._fs_enc)) for name in
765
 
                    os.listdir(self.abspath(from_dir).encode(osutils._fs_enc))
766
 
                    if not self.controldir.is_control_filename(name.decode(osutils._fs_enc))
767
 
                    and not self.mapping.is_special_file(name.decode(osutils._fs_enc))])
 
783
                encoded_from_dir = self.abspath(from_dir).encode(
 
784
                    osutils._fs_enc)
 
785
                path_iterator = sorted(
 
786
                    [os.path.join(from_dir, name.decode(osutils._fs_enc))
 
787
                     for name in os.listdir(encoded_from_dir)
 
788
                     if not self.controldir.is_control_filename(
 
789
                         name.decode(osutils._fs_enc)) and
 
790
                     not self.mapping.is_special_file(
 
791
                         name.decode(osutils._fs_enc))])
768
792
            for path in path_iterator:
769
793
                try:
770
794
                    encoded_path = path.encode("utf-8")
778
802
                    value = None
779
803
                kind = self.kind(path)
780
804
                parent, name = posixpath.split(path)
781
 
                for dir_path, dir_ie in self._add_missing_parent_ids(parent, dir_ids):
 
805
                for dir_path, dir_ie in self._add_missing_parent_ids(
 
806
                        parent, dir_ids):
782
807
                    pass
783
808
                if kind in ('directory', 'tree-reference'):
784
809
                    if path != from_dir:
794
819
                            status = "?"
795
820
                            ie = fk_entries[kind]()
796
821
                            file_id = None
797
 
                        yield posixpath.relpath(path, from_dir), status, kind, file_id, ie
 
822
                        yield (
 
823
                            posixpath.relpath(path, from_dir), status, kind,
 
824
                            file_id, ie)
798
825
                    continue
799
826
                if value is not None:
800
827
                    ie = self._get_file_ie(name, path, value, dir_ids[parent])
801
 
                    yield posixpath.relpath(path, from_dir), "V", ie.kind, ie.file_id, ie
 
828
                    yield (posixpath.relpath(path, from_dir), "V", ie.kind,
 
829
                           ie.file_id, ie)
802
830
                else:
803
831
                    ie = fk_entries[kind]()
804
 
                    yield posixpath.relpath(path, from_dir), ("I" if self.is_ignored(path) else "?"), kind, None, ie
 
832
                    yield (posixpath.relpath(path, from_dir), ("I" if
 
833
                                                               self.is_ignored(path) else "?"), kind, None, ie)
805
834
 
806
835
    def all_file_ids(self):
807
 
        with self.lock_read():
808
 
            ids = {u"": self.path2id("")}
809
 
            for path in self.index:
810
 
                if self.mapping.is_special_file(path):
811
 
                    continue
812
 
                path = path.decode("utf-8")
813
 
                parent = posixpath.dirname(path).strip("/")
814
 
                for e in self._add_missing_parent_ids(parent, ids):
815
 
                    pass
816
 
                ids[path] = self.path2id(path)
817
 
            return set(ids.values())
 
836
        raise errors.UnsupportedOperation(self.all_file_ids, self)
818
837
 
819
838
    def all_versioned_paths(self):
820
839
        with self.lock_read():
831
850
                    paths.add(path)
832
851
            return paths
833
852
 
834
 
    def iter_child_entries(self, path, file_id=None):
 
853
    def iter_child_entries(self, path):
835
854
        encoded_path = path.encode('utf-8')
836
855
        with self.lock_read():
837
856
            parent_id = self.path2id(path)
838
857
            found_any = False
839
 
            seen_children = set()
840
858
            for item_path, value in self.index.iteritems():
841
859
                decoded_item_path = item_path.decode('utf-8')
842
860
                if self.mapping.is_special_file(item_path):
847
865
                subpath = posixpath.relpath(decoded_item_path, path)
848
866
                if '/' in subpath:
849
867
                    dirname = subpath.split('/', 1)[0]
850
 
                    file_ie = self._get_dir_ie(posixpath.join(path, dirname), parent_id)
 
868
                    file_ie = self._get_dir_ie(
 
869
                        posixpath.join(path, dirname), parent_id)
851
870
                else:
852
871
                    (unused_parent, name) = posixpath.split(decoded_item_path)
853
872
                    file_ie = self._get_file_ie(
861
880
            conflicts = _mod_conflicts.ConflictList()
862
881
            for item_path, value in self.index.iteritems():
863
882
                if value.flags & FLAG_STAGEMASK:
864
 
                    conflicts.append(_mod_conflicts.TextConflict(item_path.decode('utf-8')))
 
883
                    conflicts.append(_mod_conflicts.TextConflict(
 
884
                        item_path.decode('utf-8')))
865
885
            return conflicts
866
886
 
867
887
    def set_conflicts(self, conflicts):
882
902
        if conflicted:
883
903
            self.index[path] = (value[:9] + (value[9] | FLAG_STAGEMASK, ))
884
904
        else:
885
 
            self.index[path] = (value[:9] + (value[9] &~ FLAG_STAGEMASK, ))
 
905
            self.index[path] = (value[:9] + (value[9] & ~ FLAG_STAGEMASK, ))
886
906
 
887
907
    def add_conflicts(self, new_conflicts):
888
908
        with self.lock_tree_write():
889
909
            for conflict in new_conflicts:
890
 
                if conflict.typestring in ('text conflict', 'contents conflict'):
 
910
                if conflict.typestring in ('text conflict',
 
911
                                           'contents conflict'):
891
912
                    try:
892
 
                        self._set_conflicted(conflict.path.encode('utf-8'), True)
 
913
                        self._set_conflicted(
 
914
                            conflict.path.encode('utf-8'), True)
893
915
                    except KeyError:
894
 
                        raise errors.UnsupportedOperation(self.add_conflicts, self)
 
916
                        raise errors.UnsupportedOperation(
 
917
                            self.add_conflicts, self)
895
918
                else:
896
919
                    raise errors.UnsupportedOperation(self.add_conflicts, self)
897
920
 
921
944
            current_disk = next(disk_iterator)
922
945
            disk_finished = False
923
946
        except OSError as e:
924
 
            if not (e.errno == errno.ENOENT or
925
 
                (sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
 
947
            if not (e.errno == errno.ENOENT
 
948
                    or (sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
926
949
                raise
927
950
            current_disk = None
928
951
            disk_finished = True
941
964
                    cur_disk_dir_content) = ((None, None), None)
942
965
            if not disk_finished:
943
966
                # strip out .bzr dirs
944
 
                if (cur_disk_dir_path_from_top[top_strip_len:] == '' and
945
 
                    len(cur_disk_dir_content) > 0):
 
967
                if (cur_disk_dir_path_from_top[top_strip_len:] == ''
 
968
                        and len(cur_disk_dir_content) > 0):
946
969
                    # osutils.walkdirs can be made nicer -
947
970
                    # yield the path-from-prefix rather than the pathjoined
948
971
                    # value.
949
972
                    bzrdir_loc = bisect_left(cur_disk_dir_content,
950
 
                        ('.git', '.git'))
951
 
                    if (bzrdir_loc < len(cur_disk_dir_content)
952
 
                        and self.controldir.is_control_filename(
 
973
                                             ('.git', '.git'))
 
974
                    if (bzrdir_loc < len(cur_disk_dir_content) and
 
975
                        self.controldir.is_control_filename(
953
976
                            cur_disk_dir_content[bzrdir_loc][0])):
954
977
                        # we dont yield the contents of, or, .bzr itself.
955
978
                        del cur_disk_dir_content[bzrdir_loc]
960
983
                # everything is missing
961
984
                direction = -1
962
985
            else:
963
 
                direction = ((current_inv[0][0] > cur_disk_dir_relpath) -
964
 
                             (current_inv[0][0] < cur_disk_dir_relpath))
 
986
                direction = ((current_inv[0][0] > cur_disk_dir_relpath)
 
987
                             - (current_inv[0][0] < cur_disk_dir_relpath))
965
988
            if direction > 0:
966
989
                # disk is before inventory - unknown
967
990
                dirblock = [(relpath, basename, kind, stat, None, None) for
968
 
                    relpath, basename, kind, stat, top_path in
969
 
                    cur_disk_dir_content]
 
991
                            relpath, basename, kind, stat, top_path in
 
992
                            cur_disk_dir_content]
970
993
                yield (cur_disk_dir_relpath, None), dirblock
971
994
                try:
972
995
                    current_disk = next(disk_iterator)
975
998
            elif direction < 0:
976
999
                # inventory is before disk - missing.
977
1000
                dirblock = [(relpath, basename, 'unknown', None, fileid, kind)
978
 
                    for relpath, basename, dkind, stat, fileid, kind in
979
 
                    current_inv[1]]
 
1001
                            for relpath, basename, dkind, stat, fileid, kind in
 
1002
                            current_inv[1]]
980
1003
                yield (current_inv[0][0], current_inv[0][1]), dirblock
981
1004
                try:
982
1005
                    current_inv = next(inventory_iterator)
987
1010
                # merge the inventory and disk data together
988
1011
                dirblock = []
989
1012
                for relpath, subiterator in itertools.groupby(sorted(
990
 
                    current_inv[1] + cur_disk_dir_content,
991
 
                    key=operator.itemgetter(0)), operator.itemgetter(1)):
 
1013
                        current_inv[1] + cur_disk_dir_content,
 
1014
                        key=operator.itemgetter(0)), operator.itemgetter(1)):
992
1015
                    path_elements = list(subiterator)
993
1016
                    if len(path_elements) == 2:
994
1017
                        inv_row, disk_row = path_elements
995
1018
                        # versioned, present file
996
1019
                        dirblock.append((inv_row[0],
997
 
                            inv_row[1], disk_row[2],
998
 
                            disk_row[3], inv_row[4],
999
 
                            inv_row[5]))
 
1020
                                         inv_row[1], disk_row[2],
 
1021
                                         disk_row[3], inv_row[4],
 
1022
                                         inv_row[5]))
1000
1023
                    elif len(path_elements[0]) == 5:
1001
1024
                        # unknown disk file
1002
 
                        dirblock.append((path_elements[0][0],
1003
 
                            path_elements[0][1], path_elements[0][2],
1004
 
                            path_elements[0][3], None, None))
 
1025
                        dirblock.append(
 
1026
                            (path_elements[0][0], path_elements[0][1],
 
1027
                                path_elements[0][2], path_elements[0][3],
 
1028
                                None, None))
1005
1029
                    elif len(path_elements[0]) == 6:
1006
1030
                        # versioned, absent file.
1007
 
                        dirblock.append((path_elements[0][0],
1008
 
                            path_elements[0][1], 'unknown', None,
1009
 
                            path_elements[0][4], path_elements[0][5]))
 
1031
                        dirblock.append(
 
1032
                            (path_elements[0][0], path_elements[0][1],
 
1033
                                'unknown', None, path_elements[0][4],
 
1034
                                path_elements[0][5]))
1010
1035
                    else:
1011
1036
                        raise NotImplementedError('unreachable code')
1012
1037
                yield current_inv[0], dirblock
1026
1051
        per_dir = defaultdict(set)
1027
1052
        if prefix == b"":
1028
1053
            per_dir[(u'', self.get_root_id())] = set()
 
1054
 
1029
1055
        def add_entry(path, kind):
1030
1056
            if path == b'' or not path.startswith(prefix):
1031
1057
                return
1037
1063
                raise ValueError(value)
1038
1064
            per_dir[(dirname, dir_file_id)].add(
1039
1065
                (path.decode("utf-8"), child_name.decode("utf-8"),
1040
 
                kind, None,
1041
 
                self.path2id(path.decode("utf-8")),
1042
 
                kind))
 
1066
                 kind, None,
 
1067
                 self.path2id(path.decode("utf-8")),
 
1068
                 kind))
1043
1069
        with self.lock_read():
1044
1070
            for path, value in self.index.iteritems():
1045
1071
                if self.mapping.is_special_file(path):
1058
1084
    def apply_inventory_delta(self, changes):
1059
1085
        for (old_path, new_path, file_id, ie) in changes:
1060
1086
            if old_path is not None:
1061
 
                (index, old_subpath) = self._lookup_index(old_path.encode('utf-8'))
 
1087
                (index, old_subpath) = self._lookup_index(
 
1088
                    old_path.encode('utf-8'))
1062
1089
                try:
1063
1090
                    self._index_del_entry(index, old_subpath)
1064
1091
                except KeyError:
1068
1095
            if new_path is not None and ie.kind != 'directory':
1069
1096
                if ie.kind == 'tree-reference':
1070
1097
                    self._index_add_entry(
1071
 
                            new_path, ie.kind,
1072
 
                            reference_revision=ie.reference_revision)
 
1098
                        new_path, ie.kind,
 
1099
                        reference_revision=ie.reference_revision)
1073
1100
                else:
1074
1101
                    self._index_add_entry(new_path, ie.kind)
1075
1102
        self.flush()
1076
1103
 
1077
 
    def annotate_iter(self, path, file_id=None,
 
1104
    def annotate_iter(self, path,
1078
1105
                      default_revision=_mod_revision.CURRENT_REVISION):
1079
1106
        """See Tree.annotate_iter
1080
1107
 
1092
1119
                    parent_tree = self.revision_tree(parent_id)
1093
1120
                except errors.NoSuchRevisionInTree:
1094
1121
                    parent_tree = self.branch.repository.revision_tree(
1095
 
                            parent_id)
 
1122
                        parent_id)
1096
1123
                with parent_tree.lock_read():
1097
 
                    # TODO(jelmer): Use rename/copy tracker to find path name in parent
 
1124
                    # TODO(jelmer): Use rename/copy tracker to find path name
 
1125
                    # in parent
1098
1126
                    parent_path = path
1099
1127
                    try:
1100
1128
                        kind = parent_tree.kind(parent_path)
1101
1129
                    except errors.NoSuchFile:
1102
1130
                        continue
1103
1131
                    if kind != 'file':
1104
 
                        # Note: this is slightly unnecessary, because symlinks and
1105
 
                        # directories have a "text" which is the empty text, and we
1106
 
                        # know that won't mess up annotations. But it seems cleaner
 
1132
                        # Note: this is slightly unnecessary, because symlinks
 
1133
                        # and directories have a "text" which is the empty
 
1134
                        # text, and we know that won't mess up annotations. But
 
1135
                        # it seems cleaner
1107
1136
                        continue
1108
1137
                    parent_text_key = (
1109
1138
                        parent_path,
1140
1169
            self.user_transport.local_abspath('.'),
1141
1170
            self.control_transport.local_abspath("index"),
1142
1171
            self.store,
1143
 
            None if self.branch.head is None else self.store[self.branch.head].tree)
 
1172
            None
 
1173
            if self.branch.head is None
 
1174
            else self.store[self.branch.head].tree)
1144
1175
 
1145
1176
    def reset_state(self, revision_ids=None):
1146
1177
        """Reset the state of the working tree.
1154
1185
            self.index.clear()
1155
1186
            self._index_dirty = True
1156
1187
            if self.branch.head is not None:
1157
 
                for entry in self.store.iter_tree_contents(self.store[self.branch.head].tree):
 
1188
                for entry in self.store.iter_tree_contents(
 
1189
                        self.store[self.branch.head].tree):
1158
1190
                    if not validate_path(entry.path):
1159
1191
                        continue
1160
1192
 
1161
1193
                    if S_ISGITLINK(entry.mode):
1162
 
                        pass # TODO(jelmer): record and return submodule paths
 
1194
                        pass  # TODO(jelmer): record and return submodule paths
1163
1195
                    else:
1164
1196
                        # Let's at least try to use the working tree file:
1165
1197
                        try:
1166
 
                            st = self._lstat(self.abspath(entry.path.decode('utf-8')))
 
1198
                            st = self._lstat(self.abspath(
 
1199
                                entry.path.decode('utf-8')))
1167
1200
                        except OSError:
1168
1201
                            # But if it doesn't exist, we'll make something up.
1169
1202
                            obj = self.store[entry.sha]
1170
1203
                            st = os.stat_result((entry.mode, 0, 0, 0,
1171
 
                                  0, 0, len(obj.as_raw_string()), 0,
1172
 
                                  0, 0))
 
1204
                                                 0, 0, len(
 
1205
                                                     obj.as_raw_string()), 0,
 
1206
                                                 0, 0))
1173
1207
                    (index, subpath) = self._lookup_index(entry.path)
1174
1208
                    index[subpath] = index_entry_from_stat(st, entry.sha, 0)
1175
1209
 
1187
1221
                with basis_tree.lock_read():
1188
1222
                    new_basis_tree = self.branch.basis_tree()
1189
1223
                    merge.merge_inner(
1190
 
                                self.branch,
1191
 
                                new_basis_tree,
1192
 
                                basis_tree,
1193
 
                                this_tree=self,
1194
 
                                change_reporter=change_reporter,
1195
 
                                show_base=show_base)
 
1224
                        self.branch,
 
1225
                        new_basis_tree,
 
1226
                        basis_tree,
 
1227
                        this_tree=self,
 
1228
                        change_reporter=change_reporter,
 
1229
                        show_base=show_base)
1196
1230
            return count
1197
1231
 
1198
1232
    def add_reference(self, sub_tree):
1205
1239
                sub_tree_path = self.relpath(sub_tree.basedir)
1206
1240
            except errors.PathNotChild:
1207
1241
                raise BadReferenceTarget(
1208
 
                        self, sub_tree, 'Target not inside tree.')
 
1242
                    self, sub_tree, 'Target not inside tree.')
1209
1243
 
1210
1244
            self._add([sub_tree_path], [None], ['tree-reference'])
1211
1245
 
1212
1246
    def _read_submodule_head(self, path):
1213
1247
        return read_submodule_head(self.abspath(path))
1214
1248
 
1215
 
    def get_reference_revision(self, path, file_id=None):
 
1249
    def get_reference_revision(self, path):
1216
1250
        hexsha = self._read_submodule_head(path)
1217
1251
        if hexsha is None:
1218
1252
            return _mod_revision.NULL_REVISION
1219
1253
        return self.branch.lookup_foreign_revision_id(hexsha)
1220
1254
 
1221
 
    def get_nested_tree(self, path, file_id=None):
 
1255
    def get_nested_tree(self, path):
1222
1256
        return workingtree.WorkingTree.open(self.abspath(path))
1223
1257
 
1224
1258
    def _directory_is_tree_reference(self, relpath):
1226
1260
        # it's a tree reference, except that the root of the tree is not
1227
1261
        return relpath and osutils.lexists(self.abspath(relpath) + u"/.git")
1228
1262
 
1229
 
    def extract(self, sub_path, file_id=None, format=None):
 
1263
    def extract(self, sub_path, format=None):
1230
1264
        """Extract a subtree from this tree.
1231
1265
 
1232
1266
        A new branch will be created, relative to the path for this tree.
1288
1322
                    other_tree = self.revision_tree(revision_id)
1289
1323
                except errors.NoSuchRevision:
1290
1324
                    other_tree = self.branch.repository.revision_tree(
1291
 
                            revision_id)
 
1325
                        revision_id)
1292
1326
 
1293
1327
                merge.transform_tree(tree, other_tree)
1294
1328
                if revision_id == _mod_revision.NULL_REVISION:
1333
1367
        if revision_id is not None:
1334
1368
            branch.set_last_revision(revision_id)
1335
1369
        wt = GitWorkingTree(
1336
 
                a_controldir, a_controldir.open_repository(), branch)
 
1370
            a_controldir, a_controldir.open_repository(), branch)
1337
1371
        for hook in MutableTree.hooks['post_build_tree']:
1338
1372
            hook(wt)
1339
1373
        return wt