~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/store/weave.py

  • Committer: Robert Collins
  • Date: 2006-02-11 11:58:06 UTC
  • mto: (1534.1.22 integration)
  • mto: This revision was merged to the branch mainline in revision 1554.
  • Revision ID: robertc@robertcollins.net-20060211115806-732dabc1e35714ed
Give format3 working trees their own last-revision marker.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
# files whose id differs only in case.  That should probably be forbidden.
21
21
 
22
22
 
 
23
import errno
 
24
import os
23
25
from cStringIO import StringIO
24
 
import os
25
 
import errno
 
26
import urllib
26
27
 
27
28
from bzrlib.weavefile import read_weave, write_weave_v5
28
29
from bzrlib.weave import Weave
29
 
from bzrlib.store import Store
 
30
from bzrlib.store import TransportStore, hash_prefix
30
31
from bzrlib.atomicfile import AtomicFile
31
 
from bzrlib.errors import NoSuchFile
 
32
from bzrlib.errors import NoSuchFile, FileExists
32
33
from bzrlib.trace import mutter
33
34
 
34
35
 
35
 
 
36
 
 
37
 
class WeaveStore(Store):
 
36
class WeaveStore(TransportStore):
38
37
    """Collection of several weave files in a directory.
39
38
 
40
39
    This has some shortcuts for reading and writing them.
41
40
    """
42
41
    FILE_SUFFIX = '.weave'
43
42
 
44
 
    def __init__(self, transport):
45
 
        self._transport = transport
46
 
        self._cache = {}
47
 
        self.enable_cache = False
48
 
 
 
43
    def __init__(self, transport, prefixed=False, precious=False,
 
44
                 dir_mode=None, file_mode=None):
 
45
        super(WeaveStore, self).__init__(transport,
 
46
                dir_mode=dir_mode, file_mode=file_mode,
 
47
                prefixed=prefixed, compressed=False)
 
48
        self._precious = precious
49
49
 
50
50
    def filename(self, file_id):
51
51
        """Return the path relative to the transport root."""
52
 
        return file_id + WeaveStore.FILE_SUFFIX
 
52
        if self._prefixed:
 
53
            return hash_prefix(file_id) + urllib.quote(file_id) + WeaveStore.FILE_SUFFIX
 
54
        else:
 
55
            return urllib.quote(file_id) + WeaveStore.FILE_SUFFIX
53
56
 
54
57
    def __iter__(self):
55
58
        l = len(WeaveStore.FILE_SUFFIX)
56
 
        for f in self._transport.list_dir('.'):
57
 
            if f.endswith(WeaveStore.FILE_SUFFIX):
58
 
                f = f[:-l]
59
 
                yield f
 
59
        for relpath in self._iter_files_recursive():
 
60
            if relpath.endswith(WeaveStore.FILE_SUFFIX):
 
61
                yield os.path.basename(relpath[:-l])
60
62
 
61
 
    def __contains__(self, fileid):
62
 
        """"""
 
63
    def has_id(self, fileid):
63
64
        return self._transport.has(self.filename(fileid))
64
65
 
65
66
    def _get(self, file_id):
66
67
        return self._transport.get(self.filename(file_id))
67
68
 
68
69
    def _put(self, file_id, f):
69
 
        return self._transport.put(self.filename(file_id), f)
70
 
 
71
 
 
72
 
    def get_weave(self, file_id):
73
 
        if self.enable_cache:
74
 
            if file_id in self._cache:
75
 
                return self._cache[file_id]
 
70
        # less round trips to mkdir on failure than mkdir always
 
71
        try:
 
72
            return self._transport.put(self.filename(file_id), f, mode=self._file_mode)
 
73
        except NoSuchFile:
 
74
            if not self._prefixed:
 
75
                raise
 
76
            self._transport.mkdir(hash_prefix(file_id), mode=self._dir_mode)
 
77
            return self._transport.put(self.filename(file_id), f, mode=self._file_mode)
 
78
 
 
79
    def get_weave(self, file_id, transaction):
 
80
        weave = transaction.map.find_weave(file_id)
 
81
        if weave:
 
82
            mutter("cache hit in %s for %s", self, file_id)
 
83
            return weave
76
84
        w = read_weave(self._get(file_id))
77
 
        if self.enable_cache:
78
 
            self._cache[file_id] = w
79
 
        return w
80
 
 
81
 
 
82
 
    def get_lines(self, file_id, rev_id):
 
85
        transaction.map.add_weave(file_id, w)
 
86
        transaction.register_clean(w, precious=self._precious)
 
87
        # TODO: jam 20051219 This should check if there is a prelude
 
88
        #       which is already cached, and if so, should remove it
 
89
        #       But transaction doesn't seem to have a 'remove'
 
90
        #       One workaround would be to re-add the object with
 
91
        #       the PRELUDE marker.
 
92
        return w
 
93
 
 
94
    def get_weave_prelude(self, file_id, transaction):
 
95
        weave_id = file_id
 
96
        weave = transaction.map.find_weave(weave_id)
 
97
        if weave:
 
98
            mutter("cache hit in %s for %s", self, weave_id)
 
99
            return weave
 
100
        # We want transactions to also cache preludes if that
 
101
        # is all that we are loading. So we need a unique
 
102
        # identifier, so that someone who wants the whole text
 
103
        # won't get just the prelude
 
104
        weave_id = 'PRELUDE-' + file_id
 
105
        weave = transaction.map.find_weave(weave_id)
 
106
        if weave:
 
107
            mutter("cache hit in %s for %s", self, weave_id)
 
108
            return weave
 
109
        w = read_weave(self._get(file_id), prelude=True)
 
110
        transaction.map.add_weave(weave_id, w)
 
111
        transaction.register_clean(w, precious=self._precious)
 
112
        return w
 
113
 
 
114
    def get_lines(self, file_id, rev_id, transaction):
83
115
        """Return text from a particular version of a weave.
84
116
 
85
117
        Returned as a list of lines."""
86
 
        w = self.get_weave(file_id)
 
118
        w = self.get_weave(file_id, transaction)
87
119
        return w.get(w.lookup(rev_id))
88
120
    
 
121
    def get_weave_prelude_or_empty(self, file_id, transaction):
 
122
        """cheap version that reads the prelude but not the lines
 
123
        """
 
124
        try:
 
125
            return self.get_weave_prelude(file_id, transaction)
 
126
        except NoSuchFile:
 
127
            # We can cache here, because we know that there
 
128
            # is no complete object, since we got NoSuchFile
 
129
            weave = Weave(weave_name=file_id)
 
130
            transaction.map.add_weave(file_id, weave)
 
131
            transaction.register_clean(weave, precious=self._precious)
 
132
            return weave
89
133
 
90
 
    def get_weave_or_empty(self, file_id):
 
134
    def get_weave_or_empty(self, file_id, transaction):
91
135
        """Return a weave, or an empty one if it doesn't exist.""" 
92
136
        try:
93
 
            inf = self._get(file_id)
 
137
            return self.get_weave(file_id, transaction)
94
138
        except NoSuchFile:
95
 
            return Weave(weave_name=file_id)
96
 
        else:
97
 
            return read_weave(inf)
98
 
    
 
139
            weave = Weave(weave_name=file_id)
 
140
            transaction.map.add_weave(file_id, weave)
 
141
            transaction.register_clean(weave, precious=self._precious)
 
142
            return weave
99
143
 
100
 
    def put_weave(self, file_id, weave):
 
144
    def put_weave(self, file_id, weave, transaction):
101
145
        """Write back a modified weave"""
102
 
        if self.enable_cache:
103
 
            self._cache[file_id] = weave
104
 
 
 
146
        transaction.register_dirty(weave)
 
147
        # TODO FOR WRITE TRANSACTIONS: this should be done in a callback
 
148
        # from the transaction, when it decides to save.
105
149
        sio = StringIO()
106
150
        write_weave_v5(weave, sio)
107
151
        sio.seek(0)
108
 
 
109
152
        self._put(file_id, sio)
110
153
 
111
 
 
112
 
    def add_text(self, file_id, rev_id, new_lines, parents):
113
 
        w = self.get_weave_or_empty(file_id)
 
154
    def add_text(self, file_id, rev_id, new_lines, parents, transaction):
 
155
        w = self.get_weave_or_empty(file_id, transaction)
114
156
        parent_idxs = map(w.lookup, parents)
115
157
        w.add(rev_id, parent_idxs, new_lines)
116
 
        self.put_weave(file_id, w)
 
158
        self.put_weave(file_id, w, transaction)
117
159
        
118
 
    def add_identical_text(self, file_id, old_rev_id, new_rev_id, parents):
119
 
        w = self.get_weave_or_empty(file_id)
 
160
    def add_identical_text(self, file_id, old_rev_id, new_rev_id, parents,
 
161
                           transaction):
 
162
        w = self.get_weave_or_empty(file_id, transaction)
120
163
        parent_idxs = map(w.lookup, parents)
121
164
        w.add_identical(old_rev_id, new_rev_id, parent_idxs)
122
 
        self.put_weave(file_id, w)
 
165
        self.put_weave(file_id, w, transaction)
123
166
     
124
167
    def copy_multi(self, from_store, file_ids):
125
168
        assert isinstance(from_store, WeaveStore)