~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/versionedfile.py

  • Committer: Vincent Ladeuil
  • Date: 2010-09-28 08:57:31 UTC
  • mto: (5490.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 5492.
  • Revision ID: v.ladeuil+lp@free.fr-20100928085731-8h0duqj5wf4acsgy
Add -m to search for a regexp in news entries instead of the bug number.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2011 Canonical Ltd
 
1
# Copyright (C) 2006-2010 Canonical Ltd
 
2
#
 
3
# Authors:
 
4
#   Johan Rydberg <jrydberg@gnu.org>
2
5
#
3
6
# This program is free software; you can redistribute it and/or modify
4
7
# it under the terms of the GNU General Public License as published by
16
19
 
17
20
"""Versioned text file storage api."""
18
21
 
19
 
from __future__ import absolute_import
20
 
 
21
22
from copy import copy
22
23
from cStringIO import StringIO
23
24
import os
26
27
 
27
28
from bzrlib.lazy_import import lazy_import
28
29
lazy_import(globals(), """
 
30
import urllib
 
31
 
29
32
from bzrlib import (
30
33
    annotate,
31
 
    bencode,
32
34
    errors,
33
35
    graph as _mod_graph,
34
36
    groupcompress,
38
40
    multiparent,
39
41
    tsort,
40
42
    revision,
41
 
    urlutils,
 
43
    ui,
42
44
    )
 
45
from bzrlib.graph import DictParentsProvider, Graph, StackedParentsProvider
 
46
from bzrlib.transport.memory import MemoryTransport
43
47
""")
44
48
from bzrlib.registry import Registry
45
49
from bzrlib.textmerge import TextMerge
 
50
from bzrlib import bencode
46
51
 
47
52
 
48
53
adapter_registry = Registry()
822
827
 
823
828
    def map(self, key):
824
829
        """See KeyMapper.map()."""
825
 
        return urlutils.quote(self._map(key))
 
830
        return urllib.quote(self._map(key))
826
831
 
827
832
    def unmap(self, partition_id):
828
833
        """See KeyMapper.unmap()."""
829
 
        return self._unmap(urlutils.unquote(partition_id))
 
834
        return self._unmap(urllib.unquote(partition_id))
830
835
 
831
836
 
832
837
class PrefixMapper(URLEscapeMapper):
879
884
    def _escape(self, prefix):
880
885
        """Turn a key element into a filesystem safe string.
881
886
 
882
 
        This is similar to a plain urlutils.quote, except
 
887
        This is similar to a plain urllib.quote, except
883
888
        it uses specific safe characters, so that it doesn't
884
889
        have to translate a lot of valid file ids.
885
890
        """
892
897
 
893
898
    def _unescape(self, basename):
894
899
        """Escaped names are easily unescaped by urlutils."""
895
 
        return urlutils.unquote(basename)
 
900
        return urllib.unquote(basename)
896
901
 
897
902
 
898
903
def make_versioned_files_factory(versioned_file_factory, mapper):
925
930
 
926
931
    The use of tuples allows a single code base to support several different
927
932
    uses with only the mapping logic changing from instance to instance.
928
 
 
929
 
    :ivar _immediate_fallback_vfs: For subclasses that support stacking,
930
 
        this is a list of other VersionedFiles immediately underneath this
931
 
        one.  They may in turn each have further fallbacks.
932
933
    """
933
934
 
934
935
    def add_lines(self, key, parents, lines, parent_texts=None,
973
974
    def _add_text(self, key, parents, text, nostore_sha=None, random_id=False):
974
975
        """Add a text to the store.
975
976
 
976
 
        This is a private function for use by VersionedFileCommitBuilder.
 
977
        This is a private function for use by CommitBuilder.
977
978
 
978
979
        :param key: The key tuple of the text to add. If the last element is
979
980
            None, a CHK string will be generated during the addition.
1192
1193
    def _extract_blocks(self, version_id, source, target):
1193
1194
        return None
1194
1195
 
1195
 
    def _transitive_fallbacks(self):
1196
 
        """Return the whole stack of fallback versionedfiles.
1197
 
 
1198
 
        This VersionedFiles may have a list of fallbacks, but it doesn't
1199
 
        necessarily know about the whole stack going down, and it can't know
1200
 
        at open time because they may change after the objects are opened.
1201
 
        """
1202
 
        all_fallbacks = []
1203
 
        for a_vfs in self._immediate_fallback_vfs:
1204
 
            all_fallbacks.append(a_vfs)
1205
 
            all_fallbacks.extend(a_vfs._transitive_fallbacks())
1206
 
        return all_fallbacks
1207
 
 
1208
1196
 
1209
1197
class ThunkedVersionedFiles(VersionedFiles):
1210
1198
    """Storage for many versioned files thunked onto a 'VersionedFile' class.
1423
1411
        return result
1424
1412
 
1425
1413
 
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
 
 
1453
1414
class _PlanMergeVersionedFile(VersionedFiles):
1454
1415
    """A VersionedFile for uncommitted and committed texts.
1455
1416
 
1476
1437
        # line data for locally held keys.
1477
1438
        self._lines = {}
1478
1439
        # key lookup providers
1479
 
        self._providers = [_mod_graph.DictParentsProvider(self._parents)]
 
1440
        self._providers = [DictParentsProvider(self._parents)]
1480
1441
 
1481
1442
    def plan_merge(self, ver_a, ver_b, base=None):
1482
1443
        """See VersionedFile.plan_merge"""
1489
1450
 
1490
1451
    def plan_lca_merge(self, ver_a, ver_b, base=None):
1491
1452
        from bzrlib.merge import _PlanLCAMerge
1492
 
        graph = _mod_graph.Graph(self)
 
1453
        graph = Graph(self)
1493
1454
        new_plan = _PlanLCAMerge(ver_a, ver_b, self, (self._file_id,), graph).plan_merge()
1494
1455
        if base is None:
1495
1456
            return new_plan
1547
1508
            result[revision.NULL_REVISION] = ()
1548
1509
        self._providers = self._providers[:1] + self.fallback_versionedfiles
1549
1510
        result.update(
1550
 
            _mod_graph.StackedParentsProvider(
1551
 
                self._providers).get_parent_map(keys))
 
1511
            StackedParentsProvider(self._providers).get_parent_map(keys))
1552
1512
        for key, parents in result.iteritems():
1553
1513
            if parents == ():
1554
1514
                result[key] = (revision.NULL_REVISION,)
1900
1860
    for prefix in sorted(per_prefix_map):
1901
1861
        present_keys.extend(reversed(tsort.topo_sort(per_prefix_map[prefix])))
1902
1862
    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