/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-06-02 02:35:46 UTC
  • mfrom: (7309 work)
  • mto: This revision was merged to the branch mainline in revision 7319.
  • Revision ID: jelmer@jelmer.uk-20190602023546-lqco868tnv26d8ow
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):
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 == '':
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
 
            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,
756
774
        with self.lock_read():
757
775
            root_ie = self._get_dir_ie(u"", None)
758
776
            if include_root and not from_dir:
759
 
                yield "", "V", root_ie.kind, root_ie.file_id, root_ie
 
777
                yield "", "V", root_ie.kind, 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:
785
810
                        if self._has_dir(encoded_path):
786
811
                            ie = self._get_dir_ie(path, self.path2id(path))
787
812
                            status = "V"
788
 
                            file_id = ie.file_id
789
813
                        elif self.is_ignored(path):
790
814
                            status = "I"
791
815
                            ie = fk_entries[kind]()
792
 
                            file_id = None
793
816
                        else:
794
817
                            status = "?"
795
818
                            ie = fk_entries[kind]()
796
 
                            file_id = None
797
 
                        yield posixpath.relpath(path, from_dir), status, kind, file_id, ie
 
819
                        yield (posixpath.relpath(path, from_dir), status, kind,
 
820
                               ie)
798
821
                    continue
799
822
                if value is not None:
800
823
                    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
 
824
                    yield (posixpath.relpath(path, from_dir), "V", ie.kind, ie)
802
825
                else:
803
826
                    ie = fk_entries[kind]()
804
 
                    yield posixpath.relpath(path, from_dir), ("I" if self.is_ignored(path) else "?"), kind, None, ie
 
827
                    yield (posixpath.relpath(path, from_dir),
 
828
                           ("I" if self.is_ignored(path) else "?"), kind, ie)
805
829
 
806
830
    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())
 
831
        raise errors.UnsupportedOperation(self.all_file_ids, self)
818
832
 
819
833
    def all_versioned_paths(self):
820
834
        with self.lock_read():
831
845
                    paths.add(path)
832
846
            return paths
833
847
 
834
 
    def iter_child_entries(self, path, file_id=None):
 
848
    def iter_child_entries(self, path):
835
849
        encoded_path = path.encode('utf-8')
836
850
        with self.lock_read():
837
851
            parent_id = self.path2id(path)
838
852
            found_any = False
839
 
            seen_children = set()
840
853
            for item_path, value in self.index.iteritems():
841
854
                decoded_item_path = item_path.decode('utf-8')
842
855
                if self.mapping.is_special_file(item_path):
847
860
                subpath = posixpath.relpath(decoded_item_path, path)
848
861
                if '/' in subpath:
849
862
                    dirname = subpath.split('/', 1)[0]
850
 
                    file_ie = self._get_dir_ie(posixpath.join(path, dirname), parent_id)
 
863
                    file_ie = self._get_dir_ie(
 
864
                        posixpath.join(path, dirname), parent_id)
851
865
                else:
852
866
                    (unused_parent, name) = posixpath.split(decoded_item_path)
853
867
                    file_ie = self._get_file_ie(
861
875
            conflicts = _mod_conflicts.ConflictList()
862
876
            for item_path, value in self.index.iteritems():
863
877
                if value.flags & FLAG_STAGEMASK:
864
 
                    conflicts.append(_mod_conflicts.TextConflict(item_path.decode('utf-8')))
 
878
                    conflicts.append(_mod_conflicts.TextConflict(
 
879
                        item_path.decode('utf-8')))
865
880
            return conflicts
866
881
 
867
882
    def set_conflicts(self, conflicts):
882
897
        if conflicted:
883
898
            self.index[path] = (value[:9] + (value[9] | FLAG_STAGEMASK, ))
884
899
        else:
885
 
            self.index[path] = (value[:9] + (value[9] &~ FLAG_STAGEMASK, ))
 
900
            self.index[path] = (value[:9] + (value[9] & ~ FLAG_STAGEMASK, ))
886
901
 
887
902
    def add_conflicts(self, new_conflicts):
888
903
        with self.lock_tree_write():
889
904
            for conflict in new_conflicts:
890
 
                if conflict.typestring in ('text conflict', 'contents conflict'):
 
905
                if conflict.typestring in ('text conflict',
 
906
                                           'contents conflict'):
891
907
                    try:
892
 
                        self._set_conflicted(conflict.path.encode('utf-8'), True)
 
908
                        self._set_conflicted(
 
909
                            conflict.path.encode('utf-8'), True)
893
910
                    except KeyError:
894
 
                        raise errors.UnsupportedOperation(self.add_conflicts, self)
 
911
                        raise errors.UnsupportedOperation(
 
912
                            self.add_conflicts, self)
895
913
                else:
896
914
                    raise errors.UnsupportedOperation(self.add_conflicts, self)
897
915
 
921
939
            current_disk = next(disk_iterator)
922
940
            disk_finished = False
923
941
        except OSError as e:
924
 
            if not (e.errno == errno.ENOENT or
925
 
                (sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
 
942
            if not (e.errno == errno.ENOENT
 
943
                    or (sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
926
944
                raise
927
945
            current_disk = None
928
946
            disk_finished = True
941
959
                    cur_disk_dir_content) = ((None, None), None)
942
960
            if not disk_finished:
943
961
                # strip out .bzr dirs
944
 
                if (cur_disk_dir_path_from_top[top_strip_len:] == '' and
945
 
                    len(cur_disk_dir_content) > 0):
 
962
                if (cur_disk_dir_path_from_top[top_strip_len:] == ''
 
963
                        and len(cur_disk_dir_content) > 0):
946
964
                    # osutils.walkdirs can be made nicer -
947
965
                    # yield the path-from-prefix rather than the pathjoined
948
966
                    # value.
949
967
                    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(
 
968
                                             ('.git', '.git'))
 
969
                    if (bzrdir_loc < len(cur_disk_dir_content) and
 
970
                        self.controldir.is_control_filename(
953
971
                            cur_disk_dir_content[bzrdir_loc][0])):
954
972
                        # we dont yield the contents of, or, .bzr itself.
955
973
                        del cur_disk_dir_content[bzrdir_loc]
960
978
                # everything is missing
961
979
                direction = -1
962
980
            else:
963
 
                direction = ((current_inv[0][0] > cur_disk_dir_relpath) -
964
 
                             (current_inv[0][0] < cur_disk_dir_relpath))
 
981
                direction = ((current_inv[0][0] > cur_disk_dir_relpath)
 
982
                             - (current_inv[0][0] < cur_disk_dir_relpath))
965
983
            if direction > 0:
966
984
                # disk is before inventory - unknown
967
985
                dirblock = [(relpath, basename, kind, stat, None, None) for
968
 
                    relpath, basename, kind, stat, top_path in
969
 
                    cur_disk_dir_content]
 
986
                            relpath, basename, kind, stat, top_path in
 
987
                            cur_disk_dir_content]
970
988
                yield (cur_disk_dir_relpath, None), dirblock
971
989
                try:
972
990
                    current_disk = next(disk_iterator)
975
993
            elif direction < 0:
976
994
                # inventory is before disk - missing.
977
995
                dirblock = [(relpath, basename, 'unknown', None, fileid, kind)
978
 
                    for relpath, basename, dkind, stat, fileid, kind in
979
 
                    current_inv[1]]
 
996
                            for relpath, basename, dkind, stat, fileid, kind in
 
997
                            current_inv[1]]
980
998
                yield (current_inv[0][0], current_inv[0][1]), dirblock
981
999
                try:
982
1000
                    current_inv = next(inventory_iterator)
987
1005
                # merge the inventory and disk data together
988
1006
                dirblock = []
989
1007
                for relpath, subiterator in itertools.groupby(sorted(
990
 
                    current_inv[1] + cur_disk_dir_content,
991
 
                    key=operator.itemgetter(0)), operator.itemgetter(1)):
 
1008
                        current_inv[1] + cur_disk_dir_content,
 
1009
                        key=operator.itemgetter(0)), operator.itemgetter(1)):
992
1010
                    path_elements = list(subiterator)
993
1011
                    if len(path_elements) == 2:
994
1012
                        inv_row, disk_row = path_elements
995
1013
                        # versioned, present file
996
1014
                        dirblock.append((inv_row[0],
997
 
                            inv_row[1], disk_row[2],
998
 
                            disk_row[3], inv_row[4],
999
 
                            inv_row[5]))
 
1015
                                         inv_row[1], disk_row[2],
 
1016
                                         disk_row[3], inv_row[4],
 
1017
                                         inv_row[5]))
1000
1018
                    elif len(path_elements[0]) == 5:
1001
1019
                        # 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))
 
1020
                        dirblock.append(
 
1021
                            (path_elements[0][0], path_elements[0][1],
 
1022
                                path_elements[0][2], path_elements[0][3],
 
1023
                                None, None))
1005
1024
                    elif len(path_elements[0]) == 6:
1006
1025
                        # 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]))
 
1026
                        dirblock.append(
 
1027
                            (path_elements[0][0], path_elements[0][1],
 
1028
                                'unknown', None, path_elements[0][4],
 
1029
                                path_elements[0][5]))
1010
1030
                    else:
1011
1031
                        raise NotImplementedError('unreachable code')
1012
1032
                yield current_inv[0], dirblock
1026
1046
        per_dir = defaultdict(set)
1027
1047
        if prefix == b"":
1028
1048
            per_dir[(u'', self.get_root_id())] = set()
 
1049
 
1029
1050
        def add_entry(path, kind):
1030
1051
            if path == b'' or not path.startswith(prefix):
1031
1052
                return
1037
1058
                raise ValueError(value)
1038
1059
            per_dir[(dirname, dir_file_id)].add(
1039
1060
                (path.decode("utf-8"), child_name.decode("utf-8"),
1040
 
                kind, None,
1041
 
                self.path2id(path.decode("utf-8")),
1042
 
                kind))
 
1061
                 kind, None,
 
1062
                 self.path2id(path.decode("utf-8")),
 
1063
                 kind))
1043
1064
        with self.lock_read():
1044
1065
            for path, value in self.index.iteritems():
1045
1066
                if self.mapping.is_special_file(path):
1058
1079
    def apply_inventory_delta(self, changes):
1059
1080
        for (old_path, new_path, file_id, ie) in changes:
1060
1081
            if old_path is not None:
1061
 
                (index, old_subpath) = self._lookup_index(old_path.encode('utf-8'))
 
1082
                (index, old_subpath) = self._lookup_index(
 
1083
                    old_path.encode('utf-8'))
1062
1084
                try:
1063
1085
                    self._index_del_entry(index, old_subpath)
1064
1086
                except KeyError:
1068
1090
            if new_path is not None and ie.kind != 'directory':
1069
1091
                if ie.kind == 'tree-reference':
1070
1092
                    self._index_add_entry(
1071
 
                            new_path, ie.kind,
1072
 
                            reference_revision=ie.reference_revision)
 
1093
                        new_path, ie.kind,
 
1094
                        reference_revision=ie.reference_revision)
1073
1095
                else:
1074
1096
                    self._index_add_entry(new_path, ie.kind)
1075
1097
        self.flush()
1076
1098
 
1077
 
    def annotate_iter(self, path, file_id=None,
 
1099
    def annotate_iter(self, path,
1078
1100
                      default_revision=_mod_revision.CURRENT_REVISION):
1079
1101
        """See Tree.annotate_iter
1080
1102
 
1092
1114
                    parent_tree = self.revision_tree(parent_id)
1093
1115
                except errors.NoSuchRevisionInTree:
1094
1116
                    parent_tree = self.branch.repository.revision_tree(
1095
 
                            parent_id)
 
1117
                        parent_id)
1096
1118
                with parent_tree.lock_read():
1097
 
                    # TODO(jelmer): Use rename/copy tracker to find path name in parent
 
1119
                    # TODO(jelmer): Use rename/copy tracker to find path name
 
1120
                    # in parent
1098
1121
                    parent_path = path
1099
1122
                    try:
1100
1123
                        kind = parent_tree.kind(parent_path)
1101
1124
                    except errors.NoSuchFile:
1102
1125
                        continue
1103
1126
                    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
 
1127
                        # Note: this is slightly unnecessary, because symlinks
 
1128
                        # and directories have a "text" which is the empty
 
1129
                        # text, and we know that won't mess up annotations. But
 
1130
                        # it seems cleaner
1107
1131
                        continue
1108
1132
                    parent_text_key = (
1109
1133
                        parent_path,
1140
1164
            self.user_transport.local_abspath('.'),
1141
1165
            self.control_transport.local_abspath("index"),
1142
1166
            self.store,
1143
 
            None if self.branch.head is None else self.store[self.branch.head].tree)
 
1167
            None
 
1168
            if self.branch.head is None
 
1169
            else self.store[self.branch.head].tree)
1144
1170
 
1145
1171
    def reset_state(self, revision_ids=None):
1146
1172
        """Reset the state of the working tree.
1154
1180
            self.index.clear()
1155
1181
            self._index_dirty = True
1156
1182
            if self.branch.head is not None:
1157
 
                for entry in self.store.iter_tree_contents(self.store[self.branch.head].tree):
 
1183
                for entry in self.store.iter_tree_contents(
 
1184
                        self.store[self.branch.head].tree):
1158
1185
                    if not validate_path(entry.path):
1159
1186
                        continue
1160
1187
 
1161
1188
                    if S_ISGITLINK(entry.mode):
1162
 
                        pass # TODO(jelmer): record and return submodule paths
 
1189
                        pass  # TODO(jelmer): record and return submodule paths
1163
1190
                    else:
1164
1191
                        # Let's at least try to use the working tree file:
1165
1192
                        try:
1166
 
                            st = self._lstat(self.abspath(entry.path.decode('utf-8')))
 
1193
                            st = self._lstat(self.abspath(
 
1194
                                entry.path.decode('utf-8')))
1167
1195
                        except OSError:
1168
1196
                            # But if it doesn't exist, we'll make something up.
1169
1197
                            obj = self.store[entry.sha]
1170
1198
                            st = os.stat_result((entry.mode, 0, 0, 0,
1171
 
                                  0, 0, len(obj.as_raw_string()), 0,
1172
 
                                  0, 0))
 
1199
                                                 0, 0, len(
 
1200
                                                     obj.as_raw_string()), 0,
 
1201
                                                 0, 0))
1173
1202
                    (index, subpath) = self._lookup_index(entry.path)
1174
1203
                    index[subpath] = index_entry_from_stat(st, entry.sha, 0)
1175
1204
 
1187
1216
                with basis_tree.lock_read():
1188
1217
                    new_basis_tree = self.branch.basis_tree()
1189
1218
                    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)
 
1219
                        self.branch,
 
1220
                        new_basis_tree,
 
1221
                        basis_tree,
 
1222
                        this_tree=self,
 
1223
                        change_reporter=change_reporter,
 
1224
                        show_base=show_base)
1196
1225
            return count
1197
1226
 
1198
1227
    def add_reference(self, sub_tree):
1205
1234
                sub_tree_path = self.relpath(sub_tree.basedir)
1206
1235
            except errors.PathNotChild:
1207
1236
                raise BadReferenceTarget(
1208
 
                        self, sub_tree, 'Target not inside tree.')
 
1237
                    self, sub_tree, 'Target not inside tree.')
1209
1238
 
1210
1239
            self._add([sub_tree_path], [None], ['tree-reference'])
1211
1240
 
1212
1241
    def _read_submodule_head(self, path):
1213
1242
        return read_submodule_head(self.abspath(path))
1214
1243
 
1215
 
    def get_reference_revision(self, path, file_id=None):
 
1244
    def get_reference_revision(self, path):
1216
1245
        hexsha = self._read_submodule_head(path)
1217
1246
        if hexsha is None:
1218
1247
            return _mod_revision.NULL_REVISION
1219
1248
        return self.branch.lookup_foreign_revision_id(hexsha)
1220
1249
 
1221
 
    def get_nested_tree(self, path, file_id=None):
 
1250
    def get_nested_tree(self, path):
1222
1251
        return workingtree.WorkingTree.open(self.abspath(path))
1223
1252
 
1224
1253
    def _directory_is_tree_reference(self, relpath):
1226
1255
        # it's a tree reference, except that the root of the tree is not
1227
1256
        return relpath and osutils.lexists(self.abspath(relpath) + u"/.git")
1228
1257
 
1229
 
    def extract(self, sub_path, file_id=None, format=None):
 
1258
    def extract(self, sub_path, format=None):
1230
1259
        """Extract a subtree from this tree.
1231
1260
 
1232
1261
        A new branch will be created, relative to the path for this tree.
1288
1317
                    other_tree = self.revision_tree(revision_id)
1289
1318
                except errors.NoSuchRevision:
1290
1319
                    other_tree = self.branch.repository.revision_tree(
1291
 
                            revision_id)
 
1320
                        revision_id)
1292
1321
 
1293
1322
                merge.transform_tree(tree, other_tree)
1294
1323
                if revision_id == _mod_revision.NULL_REVISION:
1316
1345
 
1317
1346
    supports_merge_modified = False
1318
1347
 
 
1348
    ignore_filename = ".gitignore"
 
1349
 
1319
1350
    @property
1320
1351
    def _matchingcontroldir(self):
1321
1352
        from .dir import LocalGitControlDirFormat
1333
1364
        if revision_id is not None:
1334
1365
            branch.set_last_revision(revision_id)
1335
1366
        wt = GitWorkingTree(
1336
 
                a_controldir, a_controldir.open_repository(), branch)
 
1367
            a_controldir, a_controldir.open_repository(), branch)
1337
1368
        for hook in MutableTree.hooks['post_build_tree']:
1338
1369
            hook(wt)
1339
1370
        return wt