/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: 2019-03-04 00:16:27 UTC
  • mfrom: (7293 work)
  • mto: This revision was merged to the branch mainline in revision 7318.
  • Revision ID: jelmer@jelmer.uk-20190304001627-v6u7o6pf97tukhek
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,
97
83
    mode_kind,
98
84
    )
99
85
 
100
 
IGNORE_FILENAME = ".gitignore"
101
 
 
102
 
 
103
 
class GitWorkingTree(MutableGitIndexTree,workingtree.WorkingTree):
 
86
 
 
87
class GitWorkingTree(MutableGitIndexTree, workingtree.WorkingTree):
104
88
    """A Git working tree."""
105
89
 
106
90
    def __init__(self, controldir, repo, branch):
112
96
        self.store = self.repository._git.object_store
113
97
        self.mapping = self.repository.get_mapping()
114
98
        self._branch = branch
115
 
        self._transport = controldir.transport
 
99
        self._transport = self.repository._git._controltransport
116
100
        self._format = GitWorkingTreeFormat()
117
101
        self.index = None
118
102
        self._index_file = None
150
134
            self._lock_mode = 'w'
151
135
            self._lock_count = 1
152
136
            try:
153
 
                self._index_file = GitFile(self.control_transport.local_abspath('index'), 'wb')
 
137
                self._index_file = GitFile(
 
138
                    self.control_transport.local_abspath('index'), 'wb')
154
139
            except FileLocked:
155
140
                raise errors.LockContention('index')
156
141
            self._read_index()
157
142
        elif self._lock_mode == 'r':
158
143
            raise errors.ReadOnlyError(self)
159
144
        else:
160
 
            self._lock_count +=1
 
145
            self._lock_count += 1
161
146
 
162
147
    def lock_tree_write(self):
163
148
        self.branch.lock_read()
164
149
        try:
165
150
            self._lock_write_tree()
166
151
            return lock.LogicalLockResult(self.unlock)
167
 
        except:
 
152
        except BaseException:
168
153
            self.branch.unlock()
169
154
            raise
170
155
 
173
158
        try:
174
159
            self._lock_write_tree()
175
160
            return lock.LogicalLockResult(self.unlock)
176
 
        except:
 
161
        except BaseException:
177
162
            self.branch.unlock()
178
163
            raise
179
164
 
235
220
 
236
221
    def _set_merges_from_parent_ids(self, rhs_parent_ids):
237
222
        try:
238
 
            merges = [self.branch.lookup_bzr_revision_id(revid)[0] for revid in rhs_parent_ids]
 
223
            merges = [self.branch.lookup_bzr_revision_id(
 
224
                revid)[0] for revid in rhs_parent_ids]
239
225
        except errors.NoSuchRevision as e:
240
226
            raise errors.GhostRevisionUnusableHere(e.revision)
241
227
        if merges:
242
 
            self.control_transport.put_bytes('MERGE_HEAD', b'\n'.join(merges),
 
228
            self.control_transport.put_bytes(
 
229
                'MERGE_HEAD', b'\n'.join(merges),
243
230
                mode=self.controldir._get_file_mode())
244
231
        else:
245
232
            try:
260
247
            working tree. Any of these may be ghosts.
261
248
        """
262
249
        with self.lock_tree_write():
263
 
            self._check_parents_for_ghosts(revision_ids,
264
 
                allow_leftmost_as_ghost=allow_leftmost_as_ghost)
 
250
            self._check_parents_for_ghosts(
 
251
                revision_ids, allow_leftmost_as_ghost=allow_leftmost_as_ghost)
265
252
            for revision_id in revision_ids:
266
253
                _mod_revision.check_not_reserved_id(revision_id)
267
254
 
292
279
        else:
293
280
            for l in osutils.split_lines(merges_bytes):
294
281
                revision_id = l.rstrip(b'\n')
295
 
                parents.append(self.branch.lookup_foreign_revision_id(revision_id))
 
282
                parents.append(
 
283
                    self.branch.lookup_foreign_revision_id(revision_id))
296
284
        return parents
297
285
 
298
286
    def check_state(self):
300
288
        pass
301
289
 
302
290
    def remove(self, files, verbose=False, to_file=None, keep_files=True,
303
 
        force=False):
 
291
               force=False):
304
292
        """Remove nominated files from the working tree metadata.
305
293
 
306
294
        :param files: File paths relative to the basedir.
316
304
 
317
305
        def backup(file_to_backup):
318
306
            abs_path = self.abspath(file_to_backup)
319
 
            backup_name = self.controldir._available_backup_name(file_to_backup)
 
307
            backup_name = self.controldir._available_backup_name(
 
308
                file_to_backup)
320
309
            osutils.rename(abs_path, self.abspath(backup_name))
321
310
            return "removed %s (but kept a copy: %s)" % (
322
311
                file_to_backup, backup_name)
353
342
            files = list(all_files)
354
343
 
355
344
            if len(files) == 0:
356
 
                return # nothing to do
 
345
                return  # nothing to do
357
346
 
358
 
            # Sort needed to first handle directory content before the directory
 
347
            # Sort needed to first handle directory content before the
 
348
            # directory
359
349
            files.sort(reverse=True)
360
350
 
361
351
            # Bail out if we are going to delete files we shouldn't
362
352
            if not keep_files and not force:
363
353
                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:
 
354
                     kind, executable) in self.iter_changes(
 
355
                         self.basis_tree(), include_unchanged=True,
 
356
                         require_versioned=False, want_unversioned=True,
 
357
                         specific_files=files):
 
358
                    if versioned[0] is False:
368
359
                        # The record is unknown or newly added
369
360
                        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])):
 
361
                        files_to_backup.extend(
 
362
                            osutils.parent_directories(path[1]))
 
363
                    elif (content_change and (kind[1] is not None)
 
364
                            and osutils.is_inside_any(files, path[1])):
373
365
                        # Versioned and changed, but not deleted, and still
374
366
                        # in one of the dirs to be deleted.
375
367
                        files_to_backup.append(path[1])
376
 
                        files_to_backup.extend(osutils.parent_directories(path[1]))
 
368
                        files_to_backup.extend(
 
369
                            osutils.parent_directories(path[1]))
377
370
 
378
371
            for f in files:
379
372
                if f == '':
421
414
        # expand any symlinks in the directory part, while leaving the
422
415
        # filename alone
423
416
        # only expanding if symlinks are supported avoids windows path bugs
424
 
        if osutils.has_symlinks():
 
417
        if self.supports_symlinks():
425
418
            file_list = list(map(osutils.normalizepath, file_list))
426
419
 
427
420
        conflicts_related = set()
431
424
        added = []
432
425
        ignored = {}
433
426
        user_dirs = []
 
427
 
434
428
        def call_action(filepath, kind):
 
429
            if filepath == '':
 
430
                return
435
431
            if action is not None:
436
432
                parent_path = posixpath.dirname(filepath)
437
433
                parent_id = self.path2id(parent_path)
441
437
                    raise workingtree.SettingFileIdUnsupported()
442
438
 
443
439
        with self.lock_tree_write():
444
 
            for filepath in osutils.canonical_relpaths(self.basedir, file_list):
 
440
            for filepath in osutils.canonical_relpaths(
 
441
                    self.basedir, file_list):
445
442
                filepath, can_access = osutils.normalized_filename(filepath)
446
443
                if not can_access:
447
444
                    raise errors.InvalidNormalization(filepath)
449
446
                abspath = self.abspath(filepath)
450
447
                kind = osutils.file_kind(abspath)
451
448
                if kind in ("file", "symlink"):
452
 
                    (index, subpath) = self._lookup_index(filepath.encode('utf-8'))
 
449
                    (index, subpath) = self._lookup_index(
 
450
                        filepath.encode('utf-8'))
453
451
                    if subpath in index:
454
452
                        # Already present
455
453
                        continue
458
456
                        self._index_add_entry(filepath, kind)
459
457
                    added.append(filepath)
460
458
                elif kind == "directory":
461
 
                    (index, subpath) = self._lookup_index(filepath.encode('utf-8'))
 
459
                    (index, subpath) = self._lookup_index(
 
460
                        filepath.encode('utf-8'))
462
461
                    if subpath not in index:
463
462
                        call_action(filepath, kind)
464
463
                    if recurse:
469
468
                abs_user_dir = self.abspath(user_dir)
470
469
                if user_dir != '':
471
470
                    try:
472
 
                        transport = _mod_transport.get_transport_from_path(abs_user_dir)
 
471
                        transport = _mod_transport.get_transport_from_path(
 
472
                            abs_user_dir)
473
473
                        _mod_controldir.ControlDirFormat.find_format(transport)
474
474
                        subtree = True
475
475
                    except errors.NotBranchError:
484
484
 
485
485
                for name in os.listdir(abs_user_dir):
486
486
                    subp = os.path.join(user_dir, name)
487
 
                    if self.is_control_filename(subp) or self.mapping.is_special_file(subp):
 
487
                    if (self.is_control_filename(subp) or
 
488
                            self.mapping.is_special_file(subp)):
488
489
                        continue
489
490
                    ignore_glob = self.is_ignored(subp)
490
491
                    if ignore_glob is not None:
495
496
                    if kind == "directory":
496
497
                        user_dirs.append(subp)
497
498
                    else:
498
 
                        (index, subpath) = self._lookup_index(subp.encode('utf-8'))
 
499
                        (index, subpath) = self._lookup_index(
 
500
                            subp.encode('utf-8'))
499
501
                        if subpath in index:
500
502
                            # Already present
501
503
                            continue
502
504
                        if subp in conflicts_related:
503
505
                            continue
504
 
                        call_action(filepath, kind)
 
506
                        call_action(subp, kind)
505
507
                        if save:
506
508
                            self._index_add_entry(subp, kind)
507
509
                        added.append(subp)
513
515
    def _iter_files_recursive(self, from_dir=None, include_dirs=False):
514
516
        if from_dir is None:
515
517
            from_dir = u""
516
 
        for (dirpath, dirnames, filenames) in os.walk(self.abspath(from_dir).encode(osutils._fs_enc)):
 
518
        encoded_from_dir = self.abspath(from_dir).encode(osutils._fs_enc)
 
519
        for (dirpath, dirnames, filenames) in os.walk(encoded_from_dir):
517
520
            dir_relpath = dirpath[len(self.basedir):].strip(b"/")
518
 
            if self.controldir.is_control_filename(dir_relpath.decode(osutils._fs_enc)):
 
521
            if self.controldir.is_control_filename(
 
522
                    dir_relpath.decode(osutils._fs_enc)):
519
523
                continue
520
524
            for name in list(dirnames):
521
 
                if self.controldir.is_control_filename(name.decode(osutils._fs_enc)):
 
525
                if self.controldir.is_control_filename(
 
526
                        name.decode(osutils._fs_enc)):
522
527
                    dirnames.remove(name)
523
528
                    continue
524
529
                relpath = os.path.join(dir_relpath, name)
528
533
                    except UnicodeDecodeError:
529
534
                        raise errors.BadFilenameEncoding(
530
535
                            relpath, osutils._fs_enc)
531
 
                if not self._has_dir(relpath):
532
 
                    dirnames.remove(name)
 
536
                    if not self._has_dir(relpath):
 
537
                        dirnames.remove(name)
533
538
            for name in filenames:
534
 
                if not self.mapping.is_special_file(name):
535
 
                    yp = os.path.join(dir_relpath, name)
536
 
                    try:
537
 
                        yield yp.decode(osutils._fs_enc)
538
 
                    except UnicodeDecodeError:
539
 
                        raise errors.BadFilenameEncoding(
540
 
                            yp, osutils._fs_enc)
 
539
                if self.mapping.is_special_file(name):
 
540
                    continue
 
541
                if self.controldir.is_control_filename(
 
542
                        name.decode(osutils._fs_enc, 'replace')):
 
543
                    continue
 
544
                yp = os.path.join(dir_relpath, name)
 
545
                try:
 
546
                    yield yp.decode(osutils._fs_enc)
 
547
                except UnicodeDecodeError:
 
548
                    raise errors.BadFilenameEncoding(
 
549
                        yp, osutils._fs_enc)
541
550
 
542
551
    def extras(self):
543
552
        """Yield all unversioned files in this WorkingTree.
544
553
        """
545
554
        with self.lock_read():
546
 
            index_paths = set([p.decode('utf-8') for p, i in self._recurse_index_entries()])
547
 
            all_paths = set(self._iter_files_recursive(include_dirs=True))
548
 
            for p in (all_paths - index_paths):
549
 
                if not self._has_dir(p.encode('utf-8')):
550
 
                    yield p
 
555
            index_paths = set(
 
556
                [p.decode('utf-8') for p, i in self._recurse_index_entries()])
 
557
            all_paths = set(self._iter_files_recursive(include_dirs=False))
 
558
            return iter(all_paths - index_paths)
551
559
 
552
560
    def _gather_kinds(self, files, kinds):
553
561
        """See MutableTree._gather_kinds."""
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
746
            if self._supports_executable():
733
747
                mode = self._lstat(path).st_mode
743
757
        if self._supports_executable():
744
758
            return self._is_executable_from_path_and_stat_from_stat(path, stat_result)
745
759
        else:
746
 
            return self._is_executable_from_path_and_stat_from_basis(path, stat_result)
 
760
            return self._is_executable_from_path_and_stat_from_basis(
 
761
                path, stat_result)
747
762
 
748
763
    def list_files(self, include_root=False, from_dir=None, recursive=True):
749
 
        if from_dir is None:
 
764
        if from_dir is None or from_dir == '.':
750
765
            from_dir = u""
751
766
        dir_ids = {}
752
767
        fk_entries = {'directory': tree.TreeDirectory,
756
771
        with self.lock_read():
757
772
            root_ie = self._get_dir_ie(u"", None)
758
773
            if include_root and not from_dir:
759
 
                yield "", "V", root_ie.kind, root_ie.file_id, root_ie
 
774
                yield "", "V", root_ie.kind, root_ie
760
775
            dir_ids[u""] = root_ie.file_id
761
776
            if recursive:
762
 
                path_iterator = sorted(self._iter_files_recursive(from_dir, include_dirs=True))
 
777
                path_iterator = sorted(
 
778
                    self._iter_files_recursive(from_dir, include_dirs=True))
763
779
            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))])
 
780
                encoded_from_dir = self.abspath(from_dir).encode(
 
781
                    osutils._fs_enc)
 
782
                path_iterator = sorted(
 
783
                    [os.path.join(from_dir, name.decode(osutils._fs_enc))
 
784
                     for name in os.listdir(encoded_from_dir)
 
785
                     if not self.controldir.is_control_filename(
 
786
                         name.decode(osutils._fs_enc)) and
 
787
                     not self.mapping.is_special_file(
 
788
                         name.decode(osutils._fs_enc))])
768
789
            for path in path_iterator:
769
790
                try:
770
791
                    encoded_path = path.encode("utf-8")
778
799
                    value = None
779
800
                kind = self.kind(path)
780
801
                parent, name = posixpath.split(path)
781
 
                for dir_path, dir_ie in self._add_missing_parent_ids(parent, dir_ids):
 
802
                for dir_path, dir_ie in self._add_missing_parent_ids(
 
803
                        parent, dir_ids):
782
804
                    pass
783
805
                if kind in ('directory', 'tree-reference'):
784
806
                    if path != from_dir:
785
807
                        if self._has_dir(encoded_path):
786
808
                            ie = self._get_dir_ie(path, self.path2id(path))
787
809
                            status = "V"
788
 
                            file_id = ie.file_id
789
810
                        elif self.is_ignored(path):
790
811
                            status = "I"
791
812
                            ie = fk_entries[kind]()
792
 
                            file_id = None
793
813
                        else:
794
814
                            status = "?"
795
815
                            ie = fk_entries[kind]()
796
 
                            file_id = None
797
 
                        yield posixpath.relpath(path, from_dir), status, kind, file_id, ie
 
816
                        yield (posixpath.relpath(path, from_dir), status, kind,
 
817
                               ie)
798
818
                    continue
799
819
                if value is not None:
800
820
                    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
 
821
                    yield (posixpath.relpath(path, from_dir), "V", ie.kind, ie)
802
822
                else:
803
823
                    ie = fk_entries[kind]()
804
 
                    yield posixpath.relpath(path, from_dir), ("I" if self.is_ignored(path) else "?"), kind, None, ie
 
824
                    yield (posixpath.relpath(path, from_dir),
 
825
                           ("I" if self.is_ignored(path) else "?"), kind, ie)
805
826
 
806
827
    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())
 
828
        raise errors.UnsupportedOperation(self.all_file_ids, self)
818
829
 
819
830
    def all_versioned_paths(self):
820
831
        with self.lock_read():
831
842
                    paths.add(path)
832
843
            return paths
833
844
 
834
 
    def iter_child_entries(self, path, file_id=None):
 
845
    def iter_child_entries(self, path):
835
846
        encoded_path = path.encode('utf-8')
836
847
        with self.lock_read():
837
848
            parent_id = self.path2id(path)
838
849
            found_any = False
839
 
            seen_children = set()
840
850
            for item_path, value in self.index.iteritems():
841
851
                decoded_item_path = item_path.decode('utf-8')
842
852
                if self.mapping.is_special_file(item_path):
847
857
                subpath = posixpath.relpath(decoded_item_path, path)
848
858
                if '/' in subpath:
849
859
                    dirname = subpath.split('/', 1)[0]
850
 
                    file_ie = self._get_dir_ie(posixpath.join(path, dirname), parent_id)
 
860
                    file_ie = self._get_dir_ie(
 
861
                        posixpath.join(path, dirname), parent_id)
851
862
                else:
852
863
                    (unused_parent, name) = posixpath.split(decoded_item_path)
853
864
                    file_ie = self._get_file_ie(
861
872
            conflicts = _mod_conflicts.ConflictList()
862
873
            for item_path, value in self.index.iteritems():
863
874
                if value.flags & FLAG_STAGEMASK:
864
 
                    conflicts.append(_mod_conflicts.TextConflict(item_path.decode('utf-8')))
 
875
                    conflicts.append(_mod_conflicts.TextConflict(
 
876
                        item_path.decode('utf-8')))
865
877
            return conflicts
866
878
 
867
879
    def set_conflicts(self, conflicts):
882
894
        if conflicted:
883
895
            self.index[path] = (value[:9] + (value[9] | FLAG_STAGEMASK, ))
884
896
        else:
885
 
            self.index[path] = (value[:9] + (value[9] &~ FLAG_STAGEMASK, ))
 
897
            self.index[path] = (value[:9] + (value[9] & ~ FLAG_STAGEMASK, ))
886
898
 
887
899
    def add_conflicts(self, new_conflicts):
888
900
        with self.lock_tree_write():
889
901
            for conflict in new_conflicts:
890
 
                if conflict.typestring in ('text conflict', 'contents conflict'):
 
902
                if conflict.typestring in ('text conflict',
 
903
                                           'contents conflict'):
891
904
                    try:
892
 
                        self._set_conflicted(conflict.path.encode('utf-8'), True)
 
905
                        self._set_conflicted(
 
906
                            conflict.path.encode('utf-8'), True)
893
907
                    except KeyError:
894
 
                        raise errors.UnsupportedOperation(self.add_conflicts, self)
 
908
                        raise errors.UnsupportedOperation(
 
909
                            self.add_conflicts, self)
895
910
                else:
896
911
                    raise errors.UnsupportedOperation(self.add_conflicts, self)
897
912
 
921
936
            current_disk = next(disk_iterator)
922
937
            disk_finished = False
923
938
        except OSError as e:
924
 
            if not (e.errno == errno.ENOENT or
925
 
                (sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
 
939
            if not (e.errno == errno.ENOENT
 
940
                    or (sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
926
941
                raise
927
942
            current_disk = None
928
943
            disk_finished = True
941
956
                    cur_disk_dir_content) = ((None, None), None)
942
957
            if not disk_finished:
943
958
                # strip out .bzr dirs
944
 
                if (cur_disk_dir_path_from_top[top_strip_len:] == '' and
945
 
                    len(cur_disk_dir_content) > 0):
 
959
                if (cur_disk_dir_path_from_top[top_strip_len:] == ''
 
960
                        and len(cur_disk_dir_content) > 0):
946
961
                    # osutils.walkdirs can be made nicer -
947
962
                    # yield the path-from-prefix rather than the pathjoined
948
963
                    # value.
949
964
                    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(
 
965
                                             ('.git', '.git'))
 
966
                    if (bzrdir_loc < len(cur_disk_dir_content) and
 
967
                        self.controldir.is_control_filename(
953
968
                            cur_disk_dir_content[bzrdir_loc][0])):
954
969
                        # we dont yield the contents of, or, .bzr itself.
955
970
                        del cur_disk_dir_content[bzrdir_loc]
960
975
                # everything is missing
961
976
                direction = -1
962
977
            else:
963
 
                direction = ((current_inv[0][0] > cur_disk_dir_relpath) -
964
 
                             (current_inv[0][0] < cur_disk_dir_relpath))
 
978
                direction = ((current_inv[0][0] > cur_disk_dir_relpath)
 
979
                             - (current_inv[0][0] < cur_disk_dir_relpath))
965
980
            if direction > 0:
966
981
                # disk is before inventory - unknown
967
982
                dirblock = [(relpath, basename, kind, stat, None, None) for
968
 
                    relpath, basename, kind, stat, top_path in
969
 
                    cur_disk_dir_content]
 
983
                            relpath, basename, kind, stat, top_path in
 
984
                            cur_disk_dir_content]
970
985
                yield (cur_disk_dir_relpath, None), dirblock
971
986
                try:
972
987
                    current_disk = next(disk_iterator)
975
990
            elif direction < 0:
976
991
                # inventory is before disk - missing.
977
992
                dirblock = [(relpath, basename, 'unknown', None, fileid, kind)
978
 
                    for relpath, basename, dkind, stat, fileid, kind in
979
 
                    current_inv[1]]
 
993
                            for relpath, basename, dkind, stat, fileid, kind in
 
994
                            current_inv[1]]
980
995
                yield (current_inv[0][0], current_inv[0][1]), dirblock
981
996
                try:
982
997
                    current_inv = next(inventory_iterator)
987
1002
                # merge the inventory and disk data together
988
1003
                dirblock = []
989
1004
                for relpath, subiterator in itertools.groupby(sorted(
990
 
                    current_inv[1] + cur_disk_dir_content,
991
 
                    key=operator.itemgetter(0)), operator.itemgetter(1)):
 
1005
                        current_inv[1] + cur_disk_dir_content,
 
1006
                        key=operator.itemgetter(0)), operator.itemgetter(1)):
992
1007
                    path_elements = list(subiterator)
993
1008
                    if len(path_elements) == 2:
994
1009
                        inv_row, disk_row = path_elements
995
1010
                        # versioned, present file
996
1011
                        dirblock.append((inv_row[0],
997
 
                            inv_row[1], disk_row[2],
998
 
                            disk_row[3], inv_row[4],
999
 
                            inv_row[5]))
 
1012
                                         inv_row[1], disk_row[2],
 
1013
                                         disk_row[3], inv_row[4],
 
1014
                                         inv_row[5]))
1000
1015
                    elif len(path_elements[0]) == 5:
1001
1016
                        # 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))
 
1017
                        dirblock.append(
 
1018
                            (path_elements[0][0], path_elements[0][1],
 
1019
                                path_elements[0][2], path_elements[0][3],
 
1020
                                None, None))
1005
1021
                    elif len(path_elements[0]) == 6:
1006
1022
                        # 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]))
 
1023
                        dirblock.append(
 
1024
                            (path_elements[0][0], path_elements[0][1],
 
1025
                                'unknown', None, path_elements[0][4],
 
1026
                                path_elements[0][5]))
1010
1027
                    else:
1011
1028
                        raise NotImplementedError('unreachable code')
1012
1029
                yield current_inv[0], dirblock
1026
1043
        per_dir = defaultdict(set)
1027
1044
        if prefix == b"":
1028
1045
            per_dir[(u'', self.get_root_id())] = set()
 
1046
 
1029
1047
        def add_entry(path, kind):
1030
1048
            if path == b'' or not path.startswith(prefix):
1031
1049
                return
1037
1055
                raise ValueError(value)
1038
1056
            per_dir[(dirname, dir_file_id)].add(
1039
1057
                (path.decode("utf-8"), child_name.decode("utf-8"),
1040
 
                kind, None,
1041
 
                self.path2id(path.decode("utf-8")),
1042
 
                kind))
 
1058
                 kind, None,
 
1059
                 self.path2id(path.decode("utf-8")),
 
1060
                 kind))
1043
1061
        with self.lock_read():
1044
1062
            for path, value in self.index.iteritems():
1045
1063
                if self.mapping.is_special_file(path):
1058
1076
    def apply_inventory_delta(self, changes):
1059
1077
        for (old_path, new_path, file_id, ie) in changes:
1060
1078
            if old_path is not None:
1061
 
                (index, old_subpath) = self._lookup_index(old_path.encode('utf-8'))
 
1079
                (index, old_subpath) = self._lookup_index(
 
1080
                    old_path.encode('utf-8'))
1062
1081
                try:
1063
1082
                    self._index_del_entry(index, old_subpath)
1064
1083
                except KeyError:
1068
1087
            if new_path is not None and ie.kind != 'directory':
1069
1088
                if ie.kind == 'tree-reference':
1070
1089
                    self._index_add_entry(
1071
 
                            new_path, ie.kind,
1072
 
                            reference_revision=ie.reference_revision)
 
1090
                        new_path, ie.kind,
 
1091
                        reference_revision=ie.reference_revision)
1073
1092
                else:
1074
1093
                    self._index_add_entry(new_path, ie.kind)
1075
1094
        self.flush()
1076
1095
 
1077
 
    def annotate_iter(self, path, file_id=None,
 
1096
    def annotate_iter(self, path,
1078
1097
                      default_revision=_mod_revision.CURRENT_REVISION):
1079
1098
        """See Tree.annotate_iter
1080
1099
 
1092
1111
                    parent_tree = self.revision_tree(parent_id)
1093
1112
                except errors.NoSuchRevisionInTree:
1094
1113
                    parent_tree = self.branch.repository.revision_tree(
1095
 
                            parent_id)
 
1114
                        parent_id)
1096
1115
                with parent_tree.lock_read():
1097
 
                    # TODO(jelmer): Use rename/copy tracker to find path name in parent
 
1116
                    # TODO(jelmer): Use rename/copy tracker to find path name
 
1117
                    # in parent
1098
1118
                    parent_path = path
1099
1119
                    try:
1100
1120
                        kind = parent_tree.kind(parent_path)
1101
1121
                    except errors.NoSuchFile:
1102
1122
                        continue
1103
1123
                    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
 
1124
                        # Note: this is slightly unnecessary, because symlinks
 
1125
                        # and directories have a "text" which is the empty
 
1126
                        # text, and we know that won't mess up annotations. But
 
1127
                        # it seems cleaner
1107
1128
                        continue
1108
1129
                    parent_text_key = (
1109
1130
                        parent_path,
1140
1161
            self.user_transport.local_abspath('.'),
1141
1162
            self.control_transport.local_abspath("index"),
1142
1163
            self.store,
1143
 
            None if self.branch.head is None else self.store[self.branch.head].tree,
 
1164
            None
 
1165
            if self.branch.head is None
 
1166
            else self.store[self.branch.head].tree,
1144
1167
            honor_filemode=self._supports_executable())
1145
1168
 
1146
1169
    def reset_state(self, revision_ids=None):
1155
1178
            self.index.clear()
1156
1179
            self._index_dirty = True
1157
1180
            if self.branch.head is not None:
1158
 
                for entry in self.store.iter_tree_contents(self.store[self.branch.head].tree):
 
1181
                for entry in self.store.iter_tree_contents(
 
1182
                        self.store[self.branch.head].tree):
1159
1183
                    if not validate_path(entry.path):
1160
1184
                        continue
1161
1185
 
1162
1186
                    if S_ISGITLINK(entry.mode):
1163
 
                        pass # TODO(jelmer): record and return submodule paths
 
1187
                        pass  # TODO(jelmer): record and return submodule paths
1164
1188
                    else:
1165
1189
                        # Let's at least try to use the working tree file:
1166
1190
                        try:
1167
 
                            st = self._lstat(self.abspath(entry.path.decode('utf-8')))
 
1191
                            st = self._lstat(self.abspath(
 
1192
                                entry.path.decode('utf-8')))
1168
1193
                        except OSError:
1169
1194
                            # But if it doesn't exist, we'll make something up.
1170
1195
                            obj = self.store[entry.sha]
1171
1196
                            st = os.stat_result((entry.mode, 0, 0, 0,
1172
 
                                  0, 0, len(obj.as_raw_string()), 0,
1173
 
                                  0, 0))
 
1197
                                                 0, 0, len(
 
1198
                                                     obj.as_raw_string()), 0,
 
1199
                                                 0, 0))
1174
1200
                    (index, subpath) = self._lookup_index(entry.path)
1175
1201
                    index[subpath] = index_entry_from_stat(st, entry.sha, 0)
1176
1202
 
1188
1214
                with basis_tree.lock_read():
1189
1215
                    new_basis_tree = self.branch.basis_tree()
1190
1216
                    merge.merge_inner(
1191
 
                                self.branch,
1192
 
                                new_basis_tree,
1193
 
                                basis_tree,
1194
 
                                this_tree=self,
1195
 
                                change_reporter=change_reporter,
1196
 
                                show_base=show_base)
 
1217
                        self.branch,
 
1218
                        new_basis_tree,
 
1219
                        basis_tree,
 
1220
                        this_tree=self,
 
1221
                        change_reporter=change_reporter,
 
1222
                        show_base=show_base)
1197
1223
            return count
1198
1224
 
1199
1225
    def add_reference(self, sub_tree):
1206
1232
                sub_tree_path = self.relpath(sub_tree.basedir)
1207
1233
            except errors.PathNotChild:
1208
1234
                raise BadReferenceTarget(
1209
 
                        self, sub_tree, 'Target not inside tree.')
 
1235
                    self, sub_tree, 'Target not inside tree.')
1210
1236
 
1211
1237
            self._add([sub_tree_path], [None], ['tree-reference'])
1212
1238
 
1213
1239
    def _read_submodule_head(self, path):
1214
1240
        return read_submodule_head(self.abspath(path))
1215
1241
 
1216
 
    def get_reference_revision(self, path, file_id=None):
 
1242
    def get_reference_revision(self, path):
1217
1243
        hexsha = self._read_submodule_head(path)
1218
1244
        if hexsha is None:
1219
1245
            return _mod_revision.NULL_REVISION
1220
1246
        return self.branch.lookup_foreign_revision_id(hexsha)
1221
1247
 
1222
 
    def get_nested_tree(self, path, file_id=None):
 
1248
    def get_nested_tree(self, path):
1223
1249
        return workingtree.WorkingTree.open(self.abspath(path))
1224
1250
 
1225
1251
    def _directory_is_tree_reference(self, relpath):
1227
1253
        # it's a tree reference, except that the root of the tree is not
1228
1254
        return relpath and osutils.lexists(self.abspath(relpath) + u"/.git")
1229
1255
 
1230
 
    def extract(self, sub_path, file_id=None, format=None):
 
1256
    def extract(self, sub_path, format=None):
1231
1257
        """Extract a subtree from this tree.
1232
1258
 
1233
1259
        A new branch will be created, relative to the path for this tree.
1289
1315
                    other_tree = self.revision_tree(revision_id)
1290
1316
                except errors.NoSuchRevision:
1291
1317
                    other_tree = self.branch.repository.revision_tree(
1292
 
                            revision_id)
 
1318
                        revision_id)
1293
1319
 
1294
1320
                merge.transform_tree(tree, other_tree)
1295
1321
                if revision_id == _mod_revision.NULL_REVISION:
1317
1343
 
1318
1344
    supports_merge_modified = False
1319
1345
 
 
1346
    ignore_filename = ".gitignore"
 
1347
 
1320
1348
    @property
1321
1349
    def _matchingcontroldir(self):
1322
1350
        from .dir import LocalGitControlDirFormat
1334
1362
        if revision_id is not None:
1335
1363
            branch.set_last_revision(revision_id)
1336
1364
        wt = GitWorkingTree(
1337
 
                a_controldir, a_controldir.open_repository(), branch)
 
1365
            a_controldir, a_controldir.open_repository(), branch)
1338
1366
        for hook in MutableTree.hooks['post_build_tree']:
1339
1367
            hook(wt)
1340
1368
        return wt