~bzr-pqm/bzr/bzr.dev

1196 by Martin Pool
- [WIP] retrieve historical texts from weaves
1
#! /usr/bin/python
2
3
# Copyright (C) 2005 Canonical Ltd
4
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
9
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU General Public License for more details.
14
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
1393.1.19 by Martin Pool
- add WeaveStore.__iter__, __contains__ and copy_multi()
19
# XXX: Some consideration of the problems that might occur if there are
20
# files whose id differs only in case.  That should probably be forbidden.
21
22
1471 by Robert Collins
Bugfix to previous url escaping patch - include weave stores
23
import errno
24
import os
1393.1.19 by Martin Pool
- add WeaveStore.__iter__, __contains__ and copy_multi()
25
from cStringIO import StringIO
1471 by Robert Collins
Bugfix to previous url escaping patch - include weave stores
26
import urllib
1223 by Martin Pool
- store inventories in weave
27
28
from bzrlib.weavefile import read_weave, write_weave_v5
29
from bzrlib.weave import Weave
1430 by Robert Collins
touchup the prefixed-store patch
30
from bzrlib.store import TransportStore, hash_prefix
1223 by Martin Pool
- store inventories in weave
31
from bzrlib.atomicfile import AtomicFile
1429 by Robert Collins
merge in niemeyers prefixed-store patch
32
from bzrlib.errors import NoSuchFile, FileExists
1393.1.19 by Martin Pool
- add WeaveStore.__iter__, __contains__ and copy_multi()
33
from bzrlib.trace import mutter
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
34
35
1430 by Robert Collins
touchup the prefixed-store patch
36
class WeaveStore(TransportStore):
1352 by Martin Pool
- store control weaves in .bzr/, not mixed in with file weaves
37
    """Collection of several weave files in a directory.
38
39
    This has some shortcuts for reading and writing them.
40
    """
1393.1.19 by Martin Pool
- add WeaveStore.__iter__, __contains__ and copy_multi()
41
    FILE_SUFFIX = '.weave'
42
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
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)
1417.1.10 by Robert Collins
add a cache bound to Transactions, and a precious facility, so that we keep inventory.weave in memory, but can discard weaves for other such files.
48
        self._precious = precious
1196 by Martin Pool
- [WIP] retrieve historical texts from weaves
49
1223 by Martin Pool
- store inventories in weave
50
    def filename(self, file_id):
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
51
        """Return the path relative to the transport root."""
1429 by Robert Collins
merge in niemeyers prefixed-store patch
52
        if self._prefixed:
1471 by Robert Collins
Bugfix to previous url escaping patch - include weave stores
53
            return hash_prefix(file_id) + urllib.quote(file_id) + WeaveStore.FILE_SUFFIX
1429 by Robert Collins
merge in niemeyers prefixed-store patch
54
        else:
1471 by Robert Collins
Bugfix to previous url escaping patch - include weave stores
55
            return urllib.quote(file_id) + WeaveStore.FILE_SUFFIX
1429 by Robert Collins
merge in niemeyers prefixed-store patch
56
1393.1.19 by Martin Pool
- add WeaveStore.__iter__, __contains__ and copy_multi()
57
    def __iter__(self):
58
        l = len(WeaveStore.FILE_SUFFIX)
1479 by Robert Collins
More quoting at the transport layer bugfixes.
59
        for relpath in self._iter_files_recursive():
1429 by Robert Collins
merge in niemeyers prefixed-store patch
60
            if relpath.endswith(WeaveStore.FILE_SUFFIX):
61
                yield os.path.basename(relpath[:-l])
1393.1.19 by Martin Pool
- add WeaveStore.__iter__, __contains__ and copy_multi()
62
1442.1.45 by Robert Collins
replace __contains__ calls in stores with has_id
63
    def has_id(self, fileid):
1393.1.19 by Martin Pool
- add WeaveStore.__iter__, __contains__ and copy_multi()
64
        return self._transport.has(self.filename(fileid))
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
65
66
    def _get(self, file_id):
67
        return self._transport.get(self.filename(file_id))
68
69
    def _put(self, file_id, f):
1429 by Robert Collins
merge in niemeyers prefixed-store patch
70
        if self._prefixed:
71
            try:
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
72
                self._transport.mkdir(hash_prefix(file_id), mode=self._dir_mode)
1429 by Robert Collins
merge in niemeyers prefixed-store patch
73
            except FileExists:
74
                pass
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
75
        return self._transport.put(self.filename(file_id), f, mode=self._file_mode)
1223 by Martin Pool
- store inventories in weave
76
1417.1.8 by Robert Collins
use transactions in the weave store interface, which enables caching for log
77
    def get_weave(self, file_id, transaction):
78
        weave = transaction.map.find_weave(file_id)
79
        if weave:
80
            mutter("cache hit in %s for %s", self, file_id)
81
            return weave
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
82
        w = read_weave(self._get(file_id))
1417.1.8 by Robert Collins
use transactions in the weave store interface, which enables caching for log
83
        transaction.map.add_weave(file_id, w)
1417.1.10 by Robert Collins
add a cache bound to Transactions, and a precious facility, so that we keep inventory.weave in memory, but can discard weaves for other such files.
84
        transaction.register_clean(w, precious=self._precious)
1185.50.28 by John Arbash Meinel
Lots of updates for 'bzr check'
85
        # TODO: jam 20051219 This should check if there is a prelude
86
        #       which is already cached, and if so, should remove it
87
        #       But transaction doesn't seem to have a 'remove'
88
        #       One workaround would be to re-add the object with
89
        #       the PRELUDE marker.
90
        return w
91
92
    def get_weave_prelude(self, file_id, transaction):
93
        weave_id = file_id
94
        weave = transaction.map.find_weave(weave_id)
95
        if weave:
96
            mutter("cache hit in %s for %s", self, weave_id)
97
            return weave
98
        # We want transactions to also cache preludes if that
99
        # is all that we are loading. So we need a unique
100
        # identifier, so that someone who wants the whole text
101
        # won't get just the prelude
102
        weave_id = 'PRELUDE-' + file_id
103
        weave = transaction.map.find_weave(weave_id)
104
        if weave:
105
            mutter("cache hit in %s for %s", self, weave_id)
106
            return weave
107
        w = read_weave(self._get(file_id), prelude=True)
108
        transaction.map.add_weave(weave_id, w)
109
        transaction.register_clean(w, precious=self._precious)
1363 by Martin Pool
- add quick-and-dirty cache for weaves to speed check command
110
        return w
1262 by Martin Pool
- fetch should also copy ancestry records
111
1417.1.8 by Robert Collins
use transactions in the weave store interface, which enables caching for log
112
    def get_lines(self, file_id, rev_id, transaction):
1262 by Martin Pool
- fetch should also copy ancestry records
113
        """Return text from a particular version of a weave.
114
115
        Returned as a list of lines."""
1417.1.8 by Robert Collins
use transactions in the weave store interface, which enables caching for log
116
        w = self.get_weave(file_id, transaction)
1262 by Martin Pool
- fetch should also copy ancestry records
117
        return w.get(w.lookup(rev_id))
1196 by Martin Pool
- [WIP] retrieve historical texts from weaves
118
    
1185.33.88 by Martin Pool
[patch] read only the table-of-contents of weaves to speed up commit
119
    def get_weave_prelude_or_empty(self, file_id, transaction):
120
        """cheap version that reads the prelude but not the lines
121
        """
122
        try:
1185.50.28 by John Arbash Meinel
Lots of updates for 'bzr check'
123
            return self.get_weave_prelude(file_id, transaction)
1185.33.88 by Martin Pool
[patch] read only the table-of-contents of weaves to speed up commit
124
        except NoSuchFile:
1185.50.28 by John Arbash Meinel
Lots of updates for 'bzr check'
125
            # We can cache here, because we know that there
126
            # is no complete object, since we got NoSuchFile
127
            weave = Weave(weave_name=file_id)
128
            transaction.map.add_weave(file_id, weave)
129
            transaction.register_clean(weave, precious=self._precious)
130
            return weave
1185.33.88 by Martin Pool
[patch] read only the table-of-contents of weaves to speed up commit
131
1417.1.8 by Robert Collins
use transactions in the weave store interface, which enables caching for log
132
    def get_weave_or_empty(self, file_id, transaction):
1224 by Martin Pool
- new method WeaveStore.get_weave_or_empty
133
        """Return a weave, or an empty one if it doesn't exist.""" 
134
        try:
1417.1.8 by Robert Collins
use transactions in the weave store interface, which enables caching for log
135
            return self.get_weave(file_id, transaction)
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
136
        except NoSuchFile:
1417.1.8 by Robert Collins
use transactions in the weave store interface, which enables caching for log
137
            weave = Weave(weave_name=file_id)
138
            transaction.map.add_weave(file_id, weave)
1417.1.10 by Robert Collins
add a cache bound to Transactions, and a precious facility, so that we keep inventory.weave in memory, but can discard weaves for other such files.
139
            transaction.register_clean(weave, precious=self._precious)
1417.1.8 by Robert Collins
use transactions in the weave store interface, which enables caching for log
140
            return weave
1224 by Martin Pool
- new method WeaveStore.get_weave_or_empty
141
1417.1.8 by Robert Collins
use transactions in the weave store interface, which enables caching for log
142
    def put_weave(self, file_id, weave, transaction):
1223 by Martin Pool
- store inventories in weave
143
        """Write back a modified weave"""
1417.1.8 by Robert Collins
use transactions in the weave store interface, which enables caching for log
144
        transaction.register_dirty(weave)
145
        # TODO FOR WRITE TRANSACTIONS: this should be done in a callback
146
        # from the transaction, when it decides to save.
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
147
        sio = StringIO()
148
        write_weave_v5(weave, sio)
149
        sio.seek(0)
150
        self._put(file_id, sio)
1223 by Martin Pool
- store inventories in weave
151
1417.1.8 by Robert Collins
use transactions in the weave store interface, which enables caching for log
152
    def add_text(self, file_id, rev_id, new_lines, parents, transaction):
153
        w = self.get_weave_or_empty(file_id, transaction)
1223 by Martin Pool
- store inventories in weave
154
        parent_idxs = map(w.lookup, parents)
155
        w.add(rev_id, parent_idxs, new_lines)
1417.1.8 by Robert Collins
use transactions in the weave store interface, which enables caching for log
156
        self.put_weave(file_id, w, transaction)
1223 by Martin Pool
- store inventories in weave
157
        
1417.1.8 by Robert Collins
use transactions in the weave store interface, which enables caching for log
158
    def add_identical_text(self, file_id, old_rev_id, new_rev_id, parents,
159
                           transaction):
160
        w = self.get_weave_or_empty(file_id, transaction)
1092.2.22 by Robert Collins
text_version and name_version unification looking reasonable
161
        parent_idxs = map(w.lookup, parents)
162
        w.add_identical(old_rev_id, new_rev_id, parent_idxs)
1417.1.8 by Robert Collins
use transactions in the weave store interface, which enables caching for log
163
        self.put_weave(file_id, w, transaction)
1223 by Martin Pool
- store inventories in weave
164
     
1393.1.19 by Martin Pool
- add WeaveStore.__iter__, __contains__ and copy_multi()
165
    def copy_multi(self, from_store, file_ids):
166
        assert isinstance(from_store, WeaveStore)
167
        for f in file_ids:
168
            mutter("copy weave {%s} into %s", f, self)
169
            self._put(f, from_store._get(f))