/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
1
# (C) 2005 Canonical Development Ltd
2
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
17
"""Serializer factory for reading and writing bundles.
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
18
"""
19
1185.82.96 by Aaron Bentley
Got first binary test passing
20
import base64
21
from StringIO import StringIO
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
22
import re
23
24
import bzrlib.errors as errors
1185.82.96 by Aaron Bentley
Got first binary test passing
25
from bzrlib.diff import internal_diff
1185.82.58 by Aaron Bentley
Handle empty branches properly
26
from bzrlib.revision import NULL_REVISION
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
27
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
28
# New bundles should try to use this header format
29
BUNDLE_HEADER = '# Bazaar revision bundle v'
30
BUNDLE_HEADER_RE = re.compile(r'^# Bazaar revision bundle v(?P<version>\d+[\w.]*)\n$')
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
31
CHANGESET_OLD_HEADER_RE = re.compile(r'^# Bazaar-NG changeset v(?P<version>\d+[\w.]*)\n$')
32
33
34
_serializers = {} 
35
36
37
def _get_filename(f):
38
    if hasattr(f, 'name'):
39
        return f.name
40
    return '<unknown>'
41
42
43
def read(f):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
44
    """Read in a bundle from a filelike object.
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
45
46
    :param f: A file-like object
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
47
    :return: A list of Bundle objects
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
48
    """
49
    version = None
50
    for line in f:
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
51
        m = BUNDLE_HEADER_RE.match(line)
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
52
        if m:
53
            version = m.group('version')
54
            break
55
        m = CHANGESET_OLD_HEADER_RE.match(line)
56
        if m:
57
            version = m.group('version')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
58
            raise errors.BundleNotSupported(version, 'old format bundles not supported')
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
59
60
    if version is None:
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
61
        raise errors.NoBundleFound(_get_filename(f))
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
62
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
63
    # Now we have a version, to figure out how to read the bundle 
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
64
    if not _serializers.has_key(version):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
65
        raise errors.BundleNotSupported(version, 'version not listed in known versions')
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
66
67
    serializer = _serializers[version](version)
68
69
    return serializer.read(f)
70
71
1185.82.74 by Aaron Bentley
Allow custom base for any revision
72
def write(source, revision_ids, f, version=None, forced_bases={}):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
73
    """Serialize a list of bundles to a filelike object.
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
74
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
75
    :param source: A source for revision information
76
    :param revision_ids: The list of revision ids to serialize
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
77
    :param f: The file to output to
78
    :param version: [optional] target serialization version
79
    """
80
81
    if not _serializers.has_key(version):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
82
        raise errors.BundleNotSupported(version, 'unknown bundle format')
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
83
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
84
    serializer = _serializers[version](version)
1185.82.74 by Aaron Bentley
Allow custom base for any revision
85
    return serializer.write(source, revision_ids, forced_bases, f) 
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
86
87
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
88
def write_bundle(repository, revision_id, base_revision_id, out):
1185.82.53 by Aaron Bentley
Factored out write_changeset to select revisions
89
    """"""
1185.82.58 by Aaron Bentley
Handle empty branches properly
90
    if base_revision_id is NULL_REVISION:
91
        base_revision_id = None
1185.82.53 by Aaron Bentley
Factored out write_changeset to select revisions
92
    base_ancestry = set(repository.get_ancestry(base_revision_id))
93
    revision_ids = [r for r in repository.get_ancestry(revision_id) if r
94
                    not in base_ancestry]
95
    revision_ids = list(reversed(revision_ids))
1185.82.74 by Aaron Bentley
Allow custom base for any revision
96
    write(repository, revision_ids, out, 
97
          forced_bases = {revision_id:base_revision_id})
1185.82.53 by Aaron Bentley
Factored out write_changeset to select revisions
98
    return revision_ids
99
100
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
101
def format_highres_date(t, offset=0):
102
    """Format a date, such that it includes higher precision in the
103
    seconds field.
104
105
    :param t:   The local time in fractional seconds since the epoch
106
    :type t: float
107
    :param offset:  The timezone offset in integer seconds
108
    :type offset: int
109
110
    Example: format_highres_date(time.time(), -time.timezone)
111
    this will return a date stamp for right now,
112
    formatted for the local timezone.
113
114
    >>> from bzrlib.osutils import format_date
115
    >>> format_date(1120153132.350850105, 0)
116
    'Thu 2005-06-30 17:38:52 +0000'
117
    >>> format_highres_date(1120153132.350850105, 0)
118
    'Thu 2005-06-30 17:38:52.350850105 +0000'
119
    >>> format_date(1120153132.350850105, -5*3600)
120
    'Thu 2005-06-30 12:38:52 -0500'
121
    >>> format_highres_date(1120153132.350850105, -5*3600)
122
    'Thu 2005-06-30 12:38:52.350850105 -0500'
123
    >>> format_highres_date(1120153132.350850105, 7200)
124
    'Thu 2005-06-30 19:38:52.350850105 +0200'
125
    """
126
    import time
127
    assert isinstance(t, float)
128
    
129
    # This has to be formatted for "original" date, so that the
130
    # revision XML entry will be reproduced faithfully.
131
    if offset == None:
132
        offset = 0
133
    tt = time.gmtime(t + offset)
134
135
    return (time.strftime("%a %Y-%m-%d %H:%M:%S", tt)
136
            + ('%.9f' % (t - int(t)))[1:] # Get the high-res seconds, but ignore the 0
137
            + ' %+03d%02d' % (offset / 3600, (offset / 60) % 60))
138
139
140
def unpack_highres_date(date):
141
    """This takes the high-resolution date stamp, and
142
    converts it back into the tuple (timestamp, timezone)
143
    Where timestamp is in real UTC since epoch seconds, and timezone is an integer
144
    number of seconds offset.
145
146
    :param date: A date formated by format_highres_date
147
    :type date: string
148
149
    >>> import time, random
150
    >>> unpack_highres_date('Thu 2005-06-30 12:38:52.350850105 -0500')
151
    (1120153132.3508501, -18000)
152
    >>> unpack_highres_date('Thu 2005-06-30 17:38:52.350850105 +0000')
153
    (1120153132.3508501, 0)
154
    >>> unpack_highres_date('Thu 2005-06-30 19:38:52.350850105 +0200')
155
    (1120153132.3508501, 7200)
156
    >>> from bzrlib.osutils import local_time_offset
157
    >>> t = time.time()
158
    >>> o = local_time_offset()
159
    >>> t2, o2 = unpack_highres_date(format_highres_date(t, o))
160
    >>> t == t2
161
    True
162
    >>> o == o2
163
    True
164
    >>> t -= 24*3600*365*2 # Start 2 years ago
165
    >>> o = -12*3600
166
    >>> for count in xrange(500):
167
    ...   t += random.random()*24*3600*30
168
    ...   o = ((o/3600 + 13) % 25 - 12)*3600 # Add 1 wrap around from [-12, 12]
169
    ...   date = format_highres_date(t, o)
170
    ...   t2, o2 = unpack_highres_date(date)
171
    ...   if t != t2 or o != o2:
172
    ...      print 'Failed on date %r, %s,%s diff:%s' % (date, t, o, t2-t)
173
    ...      break
174
175
    """
176
    import time, calendar
177
    # Up until the first period is a datestamp that is generated
178
    # as normal from time.strftime, so use time.strptime to
179
    # parse it
180
    dot_loc = date.find('.')
181
    if dot_loc == -1:
182
        raise ValueError('Date string does not contain high-precision seconds: %r' % date)
183
    base_time = time.strptime(date[:dot_loc], "%a %Y-%m-%d %H:%M:%S")
184
    fract_seconds, offset = date[dot_loc:].split()
185
    fract_seconds = float(fract_seconds)
186
    offset = int(offset)
187
    offset = int(offset / 100) * 3600 + offset % 100
188
    
189
    # time.mktime returns localtime, but calendar.timegm returns UTC time
190
    timestamp = calendar.timegm(base_time)
191
    timestamp -= offset
192
    # Add back in the fractional seconds
193
    timestamp += fract_seconds
194
    return (timestamp, offset)
195
196
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
197
class BundleSerializer(object):
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
198
    """The base class for Serializers.
199
200
    Common functionality should be included here.
201
    """
202
    def __init__(self, version):
203
        self.version = version
204
205
    def read(self, f):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
206
        """Read the rest of the bundles from the supplied file.
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
207
208
        :param f: The file to read from
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
209
        :return: A list of bundle trees
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
210
        """
211
        raise NotImplementedError
212
1185.82.74 by Aaron Bentley
Allow custom base for any revision
213
    def write(self, source, revision_ids, forced_bases, f):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
214
        """Write the bundle to the supplied file.
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
215
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
216
        :param source: A source for revision information
217
        :param revision_ids: The list of revision ids to serialize
1185.82.74 by Aaron Bentley
Allow custom base for any revision
218
        :param forced_bases: A dict of revision -> base that overrides default
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
219
        :param f: The file to output to
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
220
        """
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
221
        raise NotImplementedError
222
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
223
224
def register(version, klass, overwrite=False):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
225
    """Register a BundleSerializer version.
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
226
227
    :param version: The version associated with this format
228
    :param klass: The class to instantiate, which must take a version argument
229
    """
230
    global _serializers
231
    if overwrite:
232
        _serializers[version] = klass
233
        return
234
235
    if not _serializers.has_key(version):
236
        _serializers[version] = klass
237
238
239
def register_lazy(version, module, classname, overwrite=False):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
240
    """Register lazy-loaded bundle serializer.
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
241
242
    :param version: The version associated with this reader
243
    :param module: String indicating what module should be loaded
244
    :param classname: Name of the class that will be instantiated
245
    :param overwrite: Should this version override a default
246
    """
247
    def _loader(version):
248
        mod = __import__(module, globals(), locals(), [classname])
249
        klass = getattr(mod, classname)
250
        return klass(version)
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
251
    register(version, _loader, overwrite=overwrite)
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
252
253
1185.82.96 by Aaron Bentley
Got first binary test passing
254
def binary_diff(old_filename, old_lines, new_filename, new_lines, to_file):
255
    temp = StringIO()
256
    internal_diff(old_filename, old_lines, new_filename, new_lines, temp,
257
                  allow_binary=True)
258
    temp.seek(0)
259
    base64.encode(temp, to_file)
260
    to_file.write('\n')
261
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
262
register_lazy('0.7', 'bzrlib.bundle.serializer.v07', 'BundleSerializerV07')
263
register_lazy(None, 'bzrlib.bundle.serializer.v07', 'BundleSerializerV07')
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
264