~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/versionedfile.py

  • Committer: Tarmac
  • Author(s): Vincent Ladeuil
  • Date: 2017-01-30 14:42:05 UTC
  • mfrom: (6620.1.1 trunk)
  • Revision ID: tarmac-20170130144205-r8fh2xpmiuxyozpv
Merge  2.7 into trunk including fix for bug #1657238 [r=vila]

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
"""Versioned text file storage api."""
18
18
 
 
19
from __future__ import absolute_import
 
20
 
19
21
from copy import copy
20
22
from cStringIO import StringIO
21
23
import os
24
26
 
25
27
from bzrlib.lazy_import import lazy_import
26
28
lazy_import(globals(), """
27
 
import urllib
28
 
 
29
29
from bzrlib import (
30
30
    annotate,
 
31
    bencode,
31
32
    errors,
32
33
    graph as _mod_graph,
33
34
    groupcompress,
37
38
    multiparent,
38
39
    tsort,
39
40
    revision,
40
 
    ui,
 
41
    urlutils,
41
42
    )
42
 
from bzrlib.graph import DictParentsProvider, Graph, StackedParentsProvider
43
 
from bzrlib.transport.memory import MemoryTransport
44
43
""")
45
44
from bzrlib.registry import Registry
46
45
from bzrlib.textmerge import TextMerge
47
 
from bzrlib import bencode
48
46
 
49
47
 
50
48
adapter_registry = Registry()
824
822
 
825
823
    def map(self, key):
826
824
        """See KeyMapper.map()."""
827
 
        return urllib.quote(self._map(key))
 
825
        return urlutils.quote(self._map(key))
828
826
 
829
827
    def unmap(self, partition_id):
830
828
        """See KeyMapper.unmap()."""
831
 
        return self._unmap(urllib.unquote(partition_id))
 
829
        return self._unmap(urlutils.unquote(partition_id))
832
830
 
833
831
 
834
832
class PrefixMapper(URLEscapeMapper):
881
879
    def _escape(self, prefix):
882
880
        """Turn a key element into a filesystem safe string.
883
881
 
884
 
        This is similar to a plain urllib.quote, except
 
882
        This is similar to a plain urlutils.quote, except
885
883
        it uses specific safe characters, so that it doesn't
886
884
        have to translate a lot of valid file ids.
887
885
        """
894
892
 
895
893
    def _unescape(self, basename):
896
894
        """Escaped names are easily unescaped by urlutils."""
897
 
        return urllib.unquote(basename)
 
895
        return urlutils.unquote(basename)
898
896
 
899
897
 
900
898
def make_versioned_files_factory(versioned_file_factory, mapper):
975
973
    def _add_text(self, key, parents, text, nostore_sha=None, random_id=False):
976
974
        """Add a text to the store.
977
975
 
978
 
        This is a private function for use by CommitBuilder.
 
976
        This is a private function for use by VersionedFileCommitBuilder.
979
977
 
980
978
        :param key: The key tuple of the text to add. If the last element is
981
979
            None, a CHK string will be generated during the addition.
1425
1423
        return result
1426
1424
 
1427
1425
 
 
1426
class VersionedFilesWithFallbacks(VersionedFiles):
 
1427
 
 
1428
    def without_fallbacks(self):
 
1429
        """Return a clone of this object without any fallbacks configured."""
 
1430
        raise NotImplementedError(self.without_fallbacks)
 
1431
 
 
1432
    def add_fallback_versioned_files(self, a_versioned_files):
 
1433
        """Add a source of texts for texts not present in this knit.
 
1434
 
 
1435
        :param a_versioned_files: A VersionedFiles object.
 
1436
        """
 
1437
        raise NotImplementedError(self.add_fallback_versioned_files)
 
1438
 
 
1439
    def get_known_graph_ancestry(self, keys):
 
1440
        """Get a KnownGraph instance with the ancestry of keys."""
 
1441
        parent_map, missing_keys = self._index.find_ancestry(keys)
 
1442
        for fallback in self._transitive_fallbacks():
 
1443
            if not missing_keys:
 
1444
                break
 
1445
            (f_parent_map, f_missing_keys) = fallback._index.find_ancestry(
 
1446
                                                missing_keys)
 
1447
            parent_map.update(f_parent_map)
 
1448
            missing_keys = f_missing_keys
 
1449
        kg = _mod_graph.KnownGraph(parent_map)
 
1450
        return kg
 
1451
 
 
1452
 
1428
1453
class _PlanMergeVersionedFile(VersionedFiles):
1429
1454
    """A VersionedFile for uncommitted and committed texts.
1430
1455
 
1451
1476
        # line data for locally held keys.
1452
1477
        self._lines = {}
1453
1478
        # key lookup providers
1454
 
        self._providers = [DictParentsProvider(self._parents)]
 
1479
        self._providers = [_mod_graph.DictParentsProvider(self._parents)]
1455
1480
 
1456
1481
    def plan_merge(self, ver_a, ver_b, base=None):
1457
1482
        """See VersionedFile.plan_merge"""
1464
1489
 
1465
1490
    def plan_lca_merge(self, ver_a, ver_b, base=None):
1466
1491
        from bzrlib.merge import _PlanLCAMerge
1467
 
        graph = Graph(self)
 
1492
        graph = _mod_graph.Graph(self)
1468
1493
        new_plan = _PlanLCAMerge(ver_a, ver_b, self, (self._file_id,), graph).plan_merge()
1469
1494
        if base is None:
1470
1495
            return new_plan
1522
1547
            result[revision.NULL_REVISION] = ()
1523
1548
        self._providers = self._providers[:1] + self.fallback_versionedfiles
1524
1549
        result.update(
1525
 
            StackedParentsProvider(self._providers).get_parent_map(keys))
 
1550
            _mod_graph.StackedParentsProvider(
 
1551
                self._providers).get_parent_map(keys))
1526
1552
        for key, parents in result.iteritems():
1527
1553
            if parents == ():
1528
1554
                result[key] = (revision.NULL_REVISION,)
1874
1900
    for prefix in sorted(per_prefix_map):
1875
1901
        present_keys.extend(reversed(tsort.topo_sort(per_prefix_map[prefix])))
1876
1902
    return present_keys
 
1903
 
 
1904
 
 
1905
class _KeyRefs(object):
 
1906
 
 
1907
    def __init__(self, track_new_keys=False):
 
1908
        # dict mapping 'key' to 'set of keys referring to that key'
 
1909
        self.refs = {}
 
1910
        if track_new_keys:
 
1911
            # set remembering all new keys
 
1912
            self.new_keys = set()
 
1913
        else:
 
1914
            self.new_keys = None
 
1915
 
 
1916
    def clear(self):
 
1917
        if self.refs:
 
1918
            self.refs.clear()
 
1919
        if self.new_keys:
 
1920
            self.new_keys.clear()
 
1921
 
 
1922
    def add_references(self, key, refs):
 
1923
        # Record the new references
 
1924
        for referenced in refs:
 
1925
            try:
 
1926
                needed_by = self.refs[referenced]
 
1927
            except KeyError:
 
1928
                needed_by = self.refs[referenced] = set()
 
1929
            needed_by.add(key)
 
1930
        # Discard references satisfied by the new key
 
1931
        self.add_key(key)
 
1932
 
 
1933
    def get_new_keys(self):
 
1934
        return self.new_keys
 
1935
    
 
1936
    def get_unsatisfied_refs(self):
 
1937
        return self.refs.iterkeys()
 
1938
 
 
1939
    def _satisfy_refs_for_key(self, key):
 
1940
        try:
 
1941
            del self.refs[key]
 
1942
        except KeyError:
 
1943
            # No keys depended on this key.  That's ok.
 
1944
            pass
 
1945
 
 
1946
    def add_key(self, key):
 
1947
        # satisfy refs for key, and remember that we've seen this key.
 
1948
        self._satisfy_refs_for_key(key)
 
1949
        if self.new_keys is not None:
 
1950
            self.new_keys.add(key)
 
1951
 
 
1952
    def satisfy_refs_for_keys(self, keys):
 
1953
        for key in keys:
 
1954
            self._satisfy_refs_for_key(key)
 
1955
 
 
1956
    def get_referrers(self):
 
1957
        result = set()
 
1958
        for referrers in self.refs.itervalues():
 
1959
            result.update(referrers)
 
1960
        return result
 
1961
 
 
1962
 
 
1963