/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-16 23:15:15 UTC
  • mfrom: (7180 work)
  • mto: This revision was merged to the branch mainline in revision 7183.
  • Revision ID: jelmer@jelmer.uk-20181116231515-zqd2yn6kj8lfydyp
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):
112
98
        self.store = self.repository._git.object_store
113
99
        self.mapping = self.repository.get_mapping()
114
100
        self._branch = branch
115
 
        self._transport = controldir.transport
 
101
        self._transport = self.repository._git._controltransport
116
102
        self._format = GitWorkingTreeFormat()
117
103
        self.index = None
118
104
        self._index_file = None
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
836
        with self.lock_read():
831
860
                    paths.add(path)
832
861
            return paths
833
862
 
834
 
    def iter_child_entries(self, path, file_id=None):
 
863
    def iter_child_entries(self, path):
835
864
        encoded_path = path.encode('utf-8')
836
865
        with self.lock_read():
837
866
            parent_id = self.path2id(path)
838
867
            found_any = False
839
 
            seen_children = set()
840
868
            for item_path, value in self.index.iteritems():
841
869
                decoded_item_path = item_path.decode('utf-8')
842
870
                if self.mapping.is_special_file(item_path):
847
875
                subpath = posixpath.relpath(decoded_item_path, path)
848
876
                if '/' in subpath:
849
877
                    dirname = subpath.split('/', 1)[0]
850
 
                    file_ie = self._get_dir_ie(posixpath.join(path, dirname), parent_id)
 
878
                    file_ie = self._get_dir_ie(
 
879
                        posixpath.join(path, dirname), parent_id)
851
880
                else:
852
881
                    (unused_parent, name) = posixpath.split(decoded_item_path)
853
882
                    file_ie = self._get_file_ie(
861
890
            conflicts = _mod_conflicts.ConflictList()
862
891
            for item_path, value in self.index.iteritems():
863
892
                if value.flags & FLAG_STAGEMASK:
864
 
                    conflicts.append(_mod_conflicts.TextConflict(item_path.decode('utf-8')))
 
893
                    conflicts.append(_mod_conflicts.TextConflict(
 
894
                        item_path.decode('utf-8')))
865
895
            return conflicts
866
896
 
867
897
    def set_conflicts(self, conflicts):
882
912
        if conflicted:
883
913
            self.index[path] = (value[:9] + (value[9] | FLAG_STAGEMASK, ))
884
914
        else:
885
 
            self.index[path] = (value[:9] + (value[9] &~ FLAG_STAGEMASK, ))
 
915
            self.index[path] = (value[:9] + (value[9] & ~ FLAG_STAGEMASK, ))
886
916
 
887
917
    def add_conflicts(self, new_conflicts):
888
918
        with self.lock_tree_write():
889
919
            for conflict in new_conflicts:
890
 
                if conflict.typestring in ('text conflict', 'contents conflict'):
 
920
                if conflict.typestring in ('text conflict',
 
921
                                           'contents conflict'):
891
922
                    try:
892
 
                        self._set_conflicted(conflict.path.encode('utf-8'), True)
 
923
                        self._set_conflicted(
 
924
                            conflict.path.encode('utf-8'), True)
893
925
                    except KeyError:
894
 
                        raise errors.UnsupportedOperation(self.add_conflicts, self)
 
926
                        raise errors.UnsupportedOperation(
 
927
                            self.add_conflicts, self)
895
928
                else:
896
929
                    raise errors.UnsupportedOperation(self.add_conflicts, self)
897
930
 
921
954
            current_disk = next(disk_iterator)
922
955
            disk_finished = False
923
956
        except OSError as e:
924
 
            if not (e.errno == errno.ENOENT or
925
 
                (sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
 
957
            if not (e.errno == errno.ENOENT
 
958
                    or (sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
926
959
                raise
927
960
            current_disk = None
928
961
            disk_finished = True
941
974
                    cur_disk_dir_content) = ((None, None), None)
942
975
            if not disk_finished:
943
976
                # strip out .bzr dirs
944
 
                if (cur_disk_dir_path_from_top[top_strip_len:] == '' and
945
 
                    len(cur_disk_dir_content) > 0):
 
977
                if (cur_disk_dir_path_from_top[top_strip_len:] == ''
 
978
                        and len(cur_disk_dir_content) > 0):
946
979
                    # osutils.walkdirs can be made nicer -
947
980
                    # yield the path-from-prefix rather than the pathjoined
948
981
                    # value.
949
982
                    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(
 
983
                                             ('.git', '.git'))
 
984
                    if (bzrdir_loc < len(cur_disk_dir_content) and
 
985
                        self.controldir.is_control_filename(
953
986
                            cur_disk_dir_content[bzrdir_loc][0])):
954
987
                        # we dont yield the contents of, or, .bzr itself.
955
988
                        del cur_disk_dir_content[bzrdir_loc]
960
993
                # everything is missing
961
994
                direction = -1
962
995
            else:
963
 
                direction = ((current_inv[0][0] > cur_disk_dir_relpath) -
964
 
                             (current_inv[0][0] < cur_disk_dir_relpath))
 
996
                direction = ((current_inv[0][0] > cur_disk_dir_relpath)
 
997
                             - (current_inv[0][0] < cur_disk_dir_relpath))
965
998
            if direction > 0:
966
999
                # disk is before inventory - unknown
967
1000
                dirblock = [(relpath, basename, kind, stat, None, None) for
968
 
                    relpath, basename, kind, stat, top_path in
969
 
                    cur_disk_dir_content]
 
1001
                            relpath, basename, kind, stat, top_path in
 
1002
                            cur_disk_dir_content]
970
1003
                yield (cur_disk_dir_relpath, None), dirblock
971
1004
                try:
972
1005
                    current_disk = next(disk_iterator)
975
1008
            elif direction < 0:
976
1009
                # inventory is before disk - missing.
977
1010
                dirblock = [(relpath, basename, 'unknown', None, fileid, kind)
978
 
                    for relpath, basename, dkind, stat, fileid, kind in
979
 
                    current_inv[1]]
 
1011
                            for relpath, basename, dkind, stat, fileid, kind in
 
1012
                            current_inv[1]]
980
1013
                yield (current_inv[0][0], current_inv[0][1]), dirblock
981
1014
                try:
982
1015
                    current_inv = next(inventory_iterator)
987
1020
                # merge the inventory and disk data together
988
1021
                dirblock = []
989
1022
                for relpath, subiterator in itertools.groupby(sorted(
990
 
                    current_inv[1] + cur_disk_dir_content,
991
 
                    key=operator.itemgetter(0)), operator.itemgetter(1)):
 
1023
                        current_inv[1] + cur_disk_dir_content,
 
1024
                        key=operator.itemgetter(0)), operator.itemgetter(1)):
992
1025
                    path_elements = list(subiterator)
993
1026
                    if len(path_elements) == 2:
994
1027
                        inv_row, disk_row = path_elements
995
1028
                        # versioned, present file
996
1029
                        dirblock.append((inv_row[0],
997
 
                            inv_row[1], disk_row[2],
998
 
                            disk_row[3], inv_row[4],
999
 
                            inv_row[5]))
 
1030
                                         inv_row[1], disk_row[2],
 
1031
                                         disk_row[3], inv_row[4],
 
1032
                                         inv_row[5]))
1000
1033
                    elif len(path_elements[0]) == 5:
1001
1034
                        # 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))
 
1035
                        dirblock.append(
 
1036
                            (path_elements[0][0], path_elements[0][1],
 
1037
                                path_elements[0][2], path_elements[0][3],
 
1038
                                None, None))
1005
1039
                    elif len(path_elements[0]) == 6:
1006
1040
                        # 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]))
 
1041
                        dirblock.append(
 
1042
                            (path_elements[0][0], path_elements[0][1],
 
1043
                                'unknown', None, path_elements[0][4],
 
1044
                                path_elements[0][5]))
1010
1045
                    else:
1011
1046
                        raise NotImplementedError('unreachable code')
1012
1047
                yield current_inv[0], dirblock
1026
1061
        per_dir = defaultdict(set)
1027
1062
        if prefix == b"":
1028
1063
            per_dir[(u'', self.get_root_id())] = set()
 
1064
 
1029
1065
        def add_entry(path, kind):
1030
1066
            if path == b'' or not path.startswith(prefix):
1031
1067
                return
1037
1073
                raise ValueError(value)
1038
1074
            per_dir[(dirname, dir_file_id)].add(
1039
1075
                (path.decode("utf-8"), child_name.decode("utf-8"),
1040
 
                kind, None,
1041
 
                self.path2id(path.decode("utf-8")),
1042
 
                kind))
 
1076
                 kind, None,
 
1077
                 self.path2id(path.decode("utf-8")),
 
1078
                 kind))
1043
1079
        with self.lock_read():
1044
1080
            for path, value in self.index.iteritems():
1045
1081
                if self.mapping.is_special_file(path):
1058
1094
    def apply_inventory_delta(self, changes):
1059
1095
        for (old_path, new_path, file_id, ie) in changes:
1060
1096
            if old_path is not None:
1061
 
                (index, old_subpath) = self._lookup_index(old_path.encode('utf-8'))
 
1097
                (index, old_subpath) = self._lookup_index(
 
1098
                    old_path.encode('utf-8'))
1062
1099
                try:
1063
1100
                    self._index_del_entry(index, old_subpath)
1064
1101
                except KeyError:
1068
1105
            if new_path is not None and ie.kind != 'directory':
1069
1106
                if ie.kind == 'tree-reference':
1070
1107
                    self._index_add_entry(
1071
 
                            new_path, ie.kind,
1072
 
                            reference_revision=ie.reference_revision)
 
1108
                        new_path, ie.kind,
 
1109
                        reference_revision=ie.reference_revision)
1073
1110
                else:
1074
1111
                    self._index_add_entry(new_path, ie.kind)
1075
1112
        self.flush()
1076
1113
 
1077
 
    def annotate_iter(self, path, file_id=None,
 
1114
    def annotate_iter(self, path,
1078
1115
                      default_revision=_mod_revision.CURRENT_REVISION):
1079
1116
        """See Tree.annotate_iter
1080
1117
 
1092
1129
                    parent_tree = self.revision_tree(parent_id)
1093
1130
                except errors.NoSuchRevisionInTree:
1094
1131
                    parent_tree = self.branch.repository.revision_tree(
1095
 
                            parent_id)
 
1132
                        parent_id)
1096
1133
                with parent_tree.lock_read():
1097
 
                    # TODO(jelmer): Use rename/copy tracker to find path name in parent
 
1134
                    # TODO(jelmer): Use rename/copy tracker to find path name
 
1135
                    # in parent
1098
1136
                    parent_path = path
1099
1137
                    try:
1100
1138
                        kind = parent_tree.kind(parent_path)
1101
1139
                    except errors.NoSuchFile:
1102
1140
                        continue
1103
1141
                    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
 
1142
                        # Note: this is slightly unnecessary, because symlinks
 
1143
                        # and directories have a "text" which is the empty
 
1144
                        # text, and we know that won't mess up annotations. But
 
1145
                        # it seems cleaner
1107
1146
                        continue
1108
1147
                    parent_text_key = (
1109
1148
                        parent_path,
1140
1179
            self.user_transport.local_abspath('.'),
1141
1180
            self.control_transport.local_abspath("index"),
1142
1181
            self.store,
1143
 
            None if self.branch.head is None else self.store[self.branch.head].tree)
 
1182
            None
 
1183
            if self.branch.head is None
 
1184
            else self.store[self.branch.head].tree)
1144
1185
 
1145
1186
    def reset_state(self, revision_ids=None):
1146
1187
        """Reset the state of the working tree.
1154
1195
            self.index.clear()
1155
1196
            self._index_dirty = True
1156
1197
            if self.branch.head is not None:
1157
 
                for entry in self.store.iter_tree_contents(self.store[self.branch.head].tree):
 
1198
                for entry in self.store.iter_tree_contents(
 
1199
                        self.store[self.branch.head].tree):
1158
1200
                    if not validate_path(entry.path):
1159
1201
                        continue
1160
1202
 
1161
1203
                    if S_ISGITLINK(entry.mode):
1162
 
                        pass # TODO(jelmer): record and return submodule paths
 
1204
                        pass  # TODO(jelmer): record and return submodule paths
1163
1205
                    else:
1164
1206
                        # Let's at least try to use the working tree file:
1165
1207
                        try:
1166
 
                            st = self._lstat(self.abspath(entry.path.decode('utf-8')))
 
1208
                            st = self._lstat(self.abspath(
 
1209
                                entry.path.decode('utf-8')))
1167
1210
                        except OSError:
1168
1211
                            # But if it doesn't exist, we'll make something up.
1169
1212
                            obj = self.store[entry.sha]
1170
1213
                            st = os.stat_result((entry.mode, 0, 0, 0,
1171
 
                                  0, 0, len(obj.as_raw_string()), 0,
1172
 
                                  0, 0))
 
1214
                                                 0, 0, len(
 
1215
                                                     obj.as_raw_string()), 0,
 
1216
                                                 0, 0))
1173
1217
                    (index, subpath) = self._lookup_index(entry.path)
1174
1218
                    index[subpath] = index_entry_from_stat(st, entry.sha, 0)
1175
1219
 
1187
1231
                with basis_tree.lock_read():
1188
1232
                    new_basis_tree = self.branch.basis_tree()
1189
1233
                    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)
 
1234
                        self.branch,
 
1235
                        new_basis_tree,
 
1236
                        basis_tree,
 
1237
                        this_tree=self,
 
1238
                        change_reporter=change_reporter,
 
1239
                        show_base=show_base)
1196
1240
            return count
1197
1241
 
1198
1242
    def add_reference(self, sub_tree):
1205
1249
                sub_tree_path = self.relpath(sub_tree.basedir)
1206
1250
            except errors.PathNotChild:
1207
1251
                raise BadReferenceTarget(
1208
 
                        self, sub_tree, 'Target not inside tree.')
 
1252
                    self, sub_tree, 'Target not inside tree.')
1209
1253
 
1210
1254
            self._add([sub_tree_path], [None], ['tree-reference'])
1211
1255
 
1212
1256
    def _read_submodule_head(self, path):
1213
1257
        return read_submodule_head(self.abspath(path))
1214
1258
 
1215
 
    def get_reference_revision(self, path, file_id=None):
 
1259
    def get_reference_revision(self, path):
1216
1260
        hexsha = self._read_submodule_head(path)
1217
1261
        if hexsha is None:
1218
1262
            return _mod_revision.NULL_REVISION
1219
1263
        return self.branch.lookup_foreign_revision_id(hexsha)
1220
1264
 
1221
 
    def get_nested_tree(self, path, file_id=None):
 
1265
    def get_nested_tree(self, path):
1222
1266
        return workingtree.WorkingTree.open(self.abspath(path))
1223
1267
 
1224
1268
    def _directory_is_tree_reference(self, relpath):
1226
1270
        # it's a tree reference, except that the root of the tree is not
1227
1271
        return relpath and osutils.lexists(self.abspath(relpath) + u"/.git")
1228
1272
 
1229
 
    def extract(self, sub_path, file_id=None, format=None):
 
1273
    def extract(self, sub_path, format=None):
1230
1274
        """Extract a subtree from this tree.
1231
1275
 
1232
1276
        A new branch will be created, relative to the path for this tree.
1288
1332
                    other_tree = self.revision_tree(revision_id)
1289
1333
                except errors.NoSuchRevision:
1290
1334
                    other_tree = self.branch.repository.revision_tree(
1291
 
                            revision_id)
 
1335
                        revision_id)
1292
1336
 
1293
1337
                merge.transform_tree(tree, other_tree)
1294
1338
                if revision_id == _mod_revision.NULL_REVISION:
1333
1377
        if revision_id is not None:
1334
1378
            branch.set_last_revision(revision_id)
1335
1379
        wt = GitWorkingTree(
1336
 
                a_controldir, a_controldir.open_repository(), branch)
 
1380
            a_controldir, a_controldir.open_repository(), branch)
1337
1381
        for hook in MutableTree.hooks['post_build_tree']:
1338
1382
            hook(wt)
1339
1383
        return wt