~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/store/weave.py

[merge] fix \t in commit messages

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
# along with this program; if not, write to the Free Software
17
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
18
 
19
 
# Author: Martin Pool <mbp@canonical.com>
20
 
 
21
 
 
 
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
 
 
23
import errno
22
24
import os
23
 
import errno
 
25
from cStringIO import StringIO
 
26
import urllib
24
27
 
25
28
from bzrlib.weavefile import read_weave, write_weave_v5
26
29
from bzrlib.weave import Weave
 
30
from bzrlib.store import TransportStore, hash_prefix
27
31
from bzrlib.atomicfile import AtomicFile
28
 
 
29
 
 
30
 
class WeaveStore(object):
31
 
    """Collection of several weave files."""
32
 
    def __init__(self, dir):
33
 
        self._dir = dir
34
 
 
 
32
from bzrlib.errors import NoSuchFile, FileExists
 
33
from bzrlib.trace import mutter
 
34
 
 
35
 
 
36
class WeaveStore(TransportStore):
 
37
    """Collection of several weave files in a directory.
 
38
 
 
39
    This has some shortcuts for reading and writing them.
 
40
    """
 
41
    FILE_SUFFIX = '.weave'
 
42
 
 
43
    def __init__(self, transport, prefixed=False, precious=False):
 
44
        self._transport = transport
 
45
        self._prefixed = prefixed
 
46
        self._precious = precious
35
47
 
36
48
    def filename(self, file_id):
37
 
        return self._dir + os.sep + file_id + '.weave'
38
 
 
39
 
 
40
 
    def get_weave(self, file_id):
41
 
        return read_weave(file(self.filename(file_id), 'rb'))
 
49
        """Return the path relative to the transport root."""
 
50
        if self._prefixed:
 
51
            return hash_prefix(file_id) + urllib.quote(file_id) + WeaveStore.FILE_SUFFIX
 
52
        else:
 
53
            return urllib.quote(file_id) + WeaveStore.FILE_SUFFIX
 
54
 
 
55
    def __iter__(self):
 
56
        l = len(WeaveStore.FILE_SUFFIX)
 
57
        for relpath in self._iter_files_recursive():
 
58
            if relpath.endswith(WeaveStore.FILE_SUFFIX):
 
59
                yield os.path.basename(relpath[:-l])
 
60
 
 
61
    def has_id(self, fileid):
 
62
        return self._transport.has(self.filename(fileid))
 
63
 
 
64
    def _get(self, file_id):
 
65
        return self._transport.get(self.filename(file_id))
 
66
 
 
67
    def _put(self, file_id, f):
 
68
        if self._prefixed:
 
69
            try:
 
70
                self._transport.mkdir(hash_prefix(file_id))
 
71
            except FileExists:
 
72
                pass
 
73
        return self._transport.put(self.filename(file_id), f)
 
74
 
 
75
    def get_weave(self, file_id, transaction):
 
76
        weave = transaction.map.find_weave(file_id)
 
77
        if weave:
 
78
            mutter("cache hit in %s for %s", self, file_id)
 
79
            return weave
 
80
        w = read_weave(self._get(file_id))
 
81
        transaction.map.add_weave(file_id, w)
 
82
        transaction.register_clean(w, precious=self._precious)
 
83
        return w
 
84
 
 
85
    def get_lines(self, file_id, rev_id, transaction):
 
86
        """Return text from a particular version of a weave.
 
87
 
 
88
        Returned as a list of lines."""
 
89
        w = self.get_weave(file_id, transaction)
 
90
        return w.get(w.lookup(rev_id))
42
91
    
43
 
 
44
 
    def get_weave_or_empty(self, file_id):
 
92
    def get_weave_or_empty(self, file_id, transaction):
45
93
        """Return a weave, or an empty one if it doesn't exist.""" 
46
94
        try:
47
 
            inf = file(self.filename(file_id), 'rb')
48
 
        except IOError, e:
49
 
            if e.errno == errno.ENOENT:
50
 
                return Weave()
51
 
            else:
52
 
                raise
53
 
        else:
54
 
            return read_weave(inf)
55
 
    
 
95
            return self.get_weave(file_id, transaction)
 
96
        except NoSuchFile:
 
97
            weave = Weave(weave_name=file_id)
 
98
            transaction.map.add_weave(file_id, weave)
 
99
            transaction.register_clean(weave, precious=self._precious)
 
100
            return weave
56
101
 
57
 
    def put_weave(self, file_id, weave):
 
102
    def put_weave(self, file_id, weave, transaction):
58
103
        """Write back a modified weave"""
59
 
        weave_fn = self.filename(file_id)
60
 
        af = AtomicFile(weave_fn)
61
 
        try:
62
 
            write_weave_v5(weave, af)
63
 
            af.commit()
64
 
        finally:
65
 
            af.close()
66
 
 
67
 
 
68
 
    def add_text(self, file_id, rev_id, new_lines, parents):
69
 
        w = self.get_weave_or_empty(file_id)
 
104
        transaction.register_dirty(weave)
 
105
        # TODO FOR WRITE TRANSACTIONS: this should be done in a callback
 
106
        # from the transaction, when it decides to save.
 
107
        sio = StringIO()
 
108
        write_weave_v5(weave, sio)
 
109
        sio.seek(0)
 
110
        self._put(file_id, sio)
 
111
 
 
112
    def add_text(self, file_id, rev_id, new_lines, parents, transaction):
 
113
        w = self.get_weave_or_empty(file_id, transaction)
70
114
        parent_idxs = map(w.lookup, parents)
71
115
        w.add(rev_id, parent_idxs, new_lines)
72
 
        self.put_weave(file_id, w)
 
116
        self.put_weave(file_id, w, transaction)
73
117
        
 
118
    def add_identical_text(self, file_id, old_rev_id, new_rev_id, parents,
 
119
                           transaction):
 
120
        w = self.get_weave_or_empty(file_id, transaction)
 
121
        parent_idxs = map(w.lookup, parents)
 
122
        w.add_identical(old_rev_id, new_rev_id, parent_idxs)
 
123
        self.put_weave(file_id, w, transaction)
74
124
     
 
125
    def copy_multi(self, from_store, file_ids):
 
126
        assert isinstance(from_store, WeaveStore)
 
127
        for f in file_ids:
 
128
            mutter("copy weave {%s} into %s", f, self)
 
129
            self._put(f, from_store._get(f))