/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 workingtree.py

  • Committer: Jelmer Vernooij
  • Date: 2018-03-14 02:47:13 UTC
  • mto: (0.200.1859 work)
  • mto: This revision was merged to the branch mainline in revision 6960.
  • Revision ID: jelmer@jelmer.uk-20180314024713-tnmvf80ci3w452po
Implement GitMemoryTree.

Show diffs side-by-side

added added

removed removed

Lines of Context:
81
81
    changes_from_git_changes,
82
82
    tree_delta_from_git_changes,
83
83
    InterGitTrees,
 
84
    MutableGitIndexTree,
84
85
    )
85
86
from .mapping import (
86
87
    GitFileIdMap,
90
91
IGNORE_FILENAME = ".gitignore"
91
92
 
92
93
 
93
 
def ensure_normalized_path(path):
94
 
    """Check whether path is normalized.
95
 
 
96
 
    :raises InvalidNormalization: When path is not normalized, and cannot be
97
 
        accessed on this platform by the normalized path.
98
 
    :return: The NFC normalised version of path.
99
 
    """
100
 
    norm_path, can_access = osutils.normalized_filename(path)
101
 
    if norm_path != path:
102
 
        if can_access:
103
 
            return norm_path
104
 
        else:
105
 
            raise errors.InvalidNormalization(path)
106
 
    return path
107
 
 
108
 
 
109
 
class GitWorkingTree(workingtree.WorkingTree):
 
94
class GitWorkingTree(MutableGitIndexTree,workingtree.WorkingTree):
110
95
    """A Git working tree."""
111
96
 
112
97
    def __init__(self, controldir, repo, branch, index):
 
98
        MutableGitIndexTree.__init__(self)
113
99
        basedir = controldir.root_transport.local_abspath('.')
114
100
        self.basedir = osutils.realpath(basedir)
115
101
        self.controldir = controldir
120
106
        self._transport = controldir.transport
121
107
        self._format = GitWorkingTreeFormat()
122
108
        self.index = index
123
 
        self._versioned_dirs = None
124
109
        self.views = self._make_views()
125
110
        self._rules_searcher = None
126
111
        self._detect_case_handling()
127
112
        self._reset_data()
128
113
        self._fileid_map = self._basis_fileid_map.copy()
129
 
        self._lock_mode = None
130
 
        self._lock_count = 0
131
114
 
132
115
    def supports_tree_reference(self):
133
116
        return False
192
175
    def _cleanup(self):
193
176
        pass
194
177
 
 
178
    def _cleanup(self):
 
179
        pass
 
180
 
195
181
    def _detect_case_handling(self):
196
182
        try:
197
183
            self._transport.stat(".git/cOnFiG")
283
269
                continue
284
270
            yield self.path2id(path)
285
271
 
286
 
    def _index_add_entry(self, path, kind, flags=0):
287
 
        assert self._lock_mode is not None
288
 
        assert isinstance(path, basestring)
289
 
        if kind == "directory":
290
 
            # Git indexes don't contain directories
291
 
            return
292
 
        if kind == "file":
293
 
            blob = Blob()
294
 
            try:
295
 
                file, stat_val = self.get_file_with_stat(path)
296
 
            except (errors.NoSuchFile, IOError):
297
 
                # TODO: Rather than come up with something here, use the old index
298
 
                file = StringIO()
299
 
                stat_val = os.stat_result(
300
 
                    (stat.S_IFREG | 0644, 0, 0, 0, 0, 0, 0, 0, 0, 0))
301
 
            blob.set_raw_string(file.read())
302
 
        elif kind == "symlink":
303
 
            blob = Blob()
304
 
            try:
305
 
                stat_val = os.lstat(self.abspath(path))
306
 
            except (errors.NoSuchFile, OSError):
307
 
                # TODO: Rather than come up with something here, use the
308
 
                # old index
309
 
                stat_val = os.stat_result(
310
 
                    (stat.S_IFLNK, 0, 0, 0, 0, 0, 0, 0, 0, 0))
311
 
            blob.set_raw_string(
312
 
                self.get_symlink_target(path).encode("utf-8"))
313
 
        else:
314
 
            raise AssertionError("unknown kind '%s'" % kind)
315
 
        # Add object to the repository if it didn't exist yet
316
 
        if not blob.id in self.store:
317
 
            self.store.add_object(blob)
318
 
        # Add an entry to the index or update the existing entry
319
 
        ensure_normalized_path(path)
320
 
        encoded_path = path.encode("utf-8")
321
 
        if b'\r' in encoded_path or b'\n' in encoded_path:
322
 
            # TODO(jelmer): Why do we need to do this?
323
 
            trace.mutter('ignoring path with invalid newline in it: %r', path)
324
 
            return
325
 
        self.index[encoded_path] = index_entry_from_stat(
326
 
            stat_val, blob.id, flags)
327
 
        if self._versioned_dirs is not None:
328
 
            self._ensure_versioned_dir(encoded_path)
329
 
 
330
 
    def _ensure_versioned_dir(self, dirname):
331
 
        if dirname in self._versioned_dirs:
332
 
            return
333
 
        if dirname != "":
334
 
            self._ensure_versioned_dir(posixpath.dirname(dirname))
335
 
        self._versioned_dirs.add(dirname)
336
 
 
337
 
    def _load_dirs(self):
338
 
        assert self._lock_mode is not None
339
 
        self._versioned_dirs = set()
340
 
        for p in self.index:
341
 
            self._ensure_versioned_dir(posixpath.dirname(p))
342
 
 
343
 
    def _unversion_path(self, path):
344
 
        assert self._lock_mode is not None
345
 
        encoded_path = path.encode("utf-8")
346
 
        count = 0
347
 
        try:
348
 
            del self.index[encoded_path]
349
 
        except KeyError:
350
 
            # A directory, perhaps?
351
 
            for p in list(self.index):
352
 
                if p.startswith(encoded_path+b"/"):
353
 
                    count += 1
354
 
                    del self.index[p]
355
 
        else:
356
 
            count = 1
357
 
        self._versioned_dirs = None
358
 
        return count
359
 
 
360
 
    def unversion(self, paths, file_ids=None):
361
 
        with self.lock_tree_write():
362
 
            for path in paths:
363
 
                if self._unversion_path(path) == 0:
364
 
                    raise errors.NoSuchFile(path)
365
 
            self._versioned_dirs = None
366
 
            self.flush()
367
 
 
368
 
    def update_basis_by_delta(self, revid, delta):
369
 
        # TODO(jelmer): This shouldn't be called, it's inventory specific.
370
 
        for (old_path, new_path, file_id, ie) in delta:
371
 
            if old_path is not None and old_path.encode('utf-8') in self.index:
372
 
                del self.index[old_path.encode('utf-8')]
373
 
                self._versioned_dirs = None
374
 
            if new_path is not None and ie.kind != 'directory':
375
 
                self._index_add_entry(new_path, ie.kind)
376
 
        self.flush()
377
 
        self._set_merges_from_parent_ids([])
378
 
 
379
272
    def check_state(self):
380
273
        """Check that the working state is/isn't valid."""
381
274
        pass
455
348
                    trace.note(message)
456
349
            self.flush()
457
350
 
458
 
    def _add(self, files, ids, kinds):
459
 
        for (path, file_id, kind) in zip(files, ids, kinds):
460
 
            if file_id is not None:
461
 
                raise workingtree.SettingFileIdUnsupported()
462
 
            self._index_add_entry(path, kind)
463
 
 
464
351
    def smart_add(self, file_list, recurse=True, action=None, save=True):
465
352
        if not file_list:
466
353
            file_list = [u'.']
540
427
                self.flush()
541
428
            return added, ignored
542
429
 
543
 
    def _set_root_id(self, file_id):
544
 
        self._fileid_map.set_file_id("", file_id)
545
 
 
546
430
    def move(self, from_paths, to_dir=None, after=None):
547
431
        rename_tuples = []
548
432
        with self.lock_tree_write():
561
445
 
562
446
    def rename_one(self, from_rel, to_rel, after=None):
563
447
        from_path = from_rel.encode("utf-8")
564
 
        ensure_normalized_path(to_rel)
 
448
        to_rel, can_access = osutils.normalized_filename(to_rel)
 
449
        if not can_access:
 
450
            raise errors.InvalidNormalization(to_rel)
565
451
        to_path = to_rel.encode("utf-8")
566
452
        with self.lock_tree_write():
567
453
            if not after:
630
516
            self._versioned_dirs = None
631
517
            self.flush()
632
518
 
633
 
    def get_root_id(self):
634
 
        return self.path2id("")
635
 
 
636
519
    def has_filename(self, filename):
637
520
        return osutils.lexists(self.abspath(filename))
638
521
 
639
 
    def _has_dir(self, path):
640
 
        if path == "":
641
 
            return True
642
 
        if self._versioned_dirs is None:
643
 
            self._load_dirs()
644
 
        return path in self._versioned_dirs
645
 
 
646
 
    def path2id(self, path):
647
 
        with self.lock_read():
648
 
            path = path.rstrip('/')
649
 
            if self.is_versioned(path.rstrip('/')):
650
 
                return self._fileid_map.lookup_file_id(path.encode("utf-8"))
651
 
            return None
652
 
 
653
522
    def _iter_files_recursive(self, from_dir=None, include_dirs=False):
654
523
        if from_dir is None:
655
524
            from_dir = ""
731
600
        else:
732
601
            return True
733
602
 
734
 
    def has_id(self, file_id):
735
 
        try:
736
 
            self.id2path(file_id)
737
 
        except errors.NoSuchId:
738
 
            return False
739
 
        else:
740
 
            return True
741
 
 
742
 
    def id2path(self, file_id):
743
 
        assert type(file_id) is str, "file id not a string: %r" % file_id
744
 
        file_id = osutils.safe_utf8(file_id)
745
 
        with self.lock_read():
746
 
            try:
747
 
                path = self._fileid_map.lookup_path(file_id)
748
 
            except ValueError:
749
 
                raise errors.NoSuchId(self, file_id)
750
 
            path = path.decode('utf-8')
751
 
            if self.is_versioned(path):
752
 
                return path
753
 
            raise errors.NoSuchId(self, file_id)
754
 
 
755
603
    def get_file_mtime(self, path, file_id=None):
756
604
        """See Tree.get_file_mtime."""
757
605
        try:
758
 
            return os.lstat(self.abspath(path)).st_mtime
 
606
            return self._lstat(path).st_mtime
759
607
        except OSError, (num, msg):
760
608
            if num == errno.ENOENT:
761
609
                raise errors.NoSuchFile(path)
844
692
    def revision_tree(self, revid):
845
693
        return self.repository.revision_tree(revid)
846
694
 
847
 
    def is_versioned(self, path):
848
 
        with self.lock_read():
849
 
            path = path.rstrip('/').encode('utf-8')
850
 
            return (path in self.index or self._has_dir(path))
851
 
 
852
695
    def filter_unversioned_files(self, files):
853
696
        return set([p for p in files if not self.is_versioned(p)])
854
697
 
855
 
    def _get_dir_ie(self, path, parent_id):
856
 
        file_id = self.path2id(path)
857
 
        return inventory.InventoryDirectory(file_id,
858
 
            posixpath.basename(path).strip("/"), parent_id)
859
 
 
860
 
    def _add_missing_parent_ids(self, path, dir_ids):
861
 
        if path in dir_ids:
862
 
            return []
863
 
        parent = posixpath.dirname(path).strip("/")
864
 
        ret = self._add_missing_parent_ids(parent, dir_ids)
865
 
        parent_id = dir_ids[parent]
866
 
        ie = self._get_dir_ie(path, parent_id)
867
 
        dir_ids[path] = ie.file_id
868
 
        ret.append((path, ie))
869
 
        return ret
870
 
 
871
 
    def _get_file_ie(self, name, path, value, parent_id):
872
 
        assert isinstance(name, unicode)
873
 
        assert isinstance(path, unicode)
874
 
        assert isinstance(value, tuple) and len(value) == 10
875
 
        (ctime, mtime, dev, ino, mode, uid, gid, size, sha, flags) = value
876
 
        file_id = self.path2id(path)
877
 
        if type(file_id) != str:
878
 
            raise AssertionError
879
 
        kind = mode_kind(mode)
880
 
        ie = inventory.entry_factory[kind](file_id, name, parent_id)
881
 
        if kind == 'symlink':
882
 
            ie.symlink_target = self.get_symlink_target(path, file_id)
883
 
        else:
884
 
            try:
885
 
                data = self.get_file_text(path, file_id)
886
 
            except errors.NoSuchFile:
887
 
                data = None
888
 
            except IOError as e:
889
 
                if e.errno != errno.ENOENT:
890
 
                    raise
891
 
                data = None
892
 
            if data is None:
893
 
                data = self.repository._git.object_store[sha].data
894
 
            ie.text_sha1 = osutils.sha_string(data)
895
 
            ie.text_size = len(data)
896
 
            ie.executable = bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
897
 
        ie.revision = None
898
 
        return ie
899
 
 
900
698
    def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
901
699
        mode = stat_result.st_mode
902
700
        return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
914
712
                    return "directory"
915
713
                raise errors.NoSuchFile(path)
916
714
 
 
715
    def _lstat(self, path):
 
716
        return os.lstat(self.abspath(path))
 
717
 
917
718
    def is_executable(self, path, file_id=None):
918
719
        if getattr(self, "_supports_executable", osutils.supports_executable)():
919
 
            mode = os.lstat(self.abspath(path)).st_mode
 
720
            mode = self._lstat(path).st_mode
920
721
        else:
921
722
            try:
922
723
                mode = self.index[path.encode('utf-8')].mode
1046
847
        if not found_any:
1047
848
            raise errors.NoSuchFile(path)
1048
849
 
1049
 
    def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):
1050
 
        if yield_parents:
1051
 
            raise NotImplementedError(self.iter_entries_by_dir)
1052
 
        with self.lock_read():
1053
 
            if specific_file_ids is not None:
1054
 
                specific_paths = []
1055
 
                for file_id in specific_file_ids:
1056
 
                    if file_id is None:
1057
 
                        continue
1058
 
                    try:
1059
 
                        specific_paths.append(self.id2path(file_id))
1060
 
                    except errors.NoSuchId:
1061
 
                        pass
1062
 
                if specific_paths in ([u""], []):
1063
 
                    specific_paths = None
1064
 
                else:
1065
 
                    specific_paths = set(specific_paths)
1066
 
            else:
1067
 
                specific_paths = None
1068
 
            root_ie = self._get_dir_ie(u"", None)
1069
 
            ret = {}
1070
 
            if specific_paths is None:
1071
 
                ret[(None, u"")] = root_ie
1072
 
            dir_ids = {u"": root_ie.file_id}
1073
 
            for path, value in self.index.iteritems():
1074
 
                if self.mapping.is_special_file(path):
1075
 
                    continue
1076
 
                path = path.decode("utf-8")
1077
 
                if specific_paths is not None and not path in specific_paths:
1078
 
                    continue
1079
 
                (parent, name) = posixpath.split(path)
1080
 
                try:
1081
 
                    file_ie = self._get_file_ie(name, path, value, None)
1082
 
                except errors.NoSuchFile:
1083
 
                    continue
1084
 
                if yield_parents or specific_file_ids is None:
1085
 
                    for (dir_path, dir_ie) in self._add_missing_parent_ids(parent,
1086
 
                            dir_ids):
1087
 
                        ret[(posixpath.dirname(dir_path), dir_path)] = dir_ie
1088
 
                file_ie.parent_id = self.path2id(parent)
1089
 
                ret[(posixpath.dirname(path), path)] = file_ie
1090
 
            return ((path, ie) for ((_, path), ie) in sorted(ret.items()))
1091
 
 
1092
850
    def conflicts(self):
1093
851
        with self.lock_read():
1094
852
            # FIXME: