/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
1793.3.16 by John Arbash Meinel
Add tests to ensure that we gracefully handle opening and trailing non-bundle text.
34
_serializers = {}
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
35
36
37
def _get_filename(f):
38
    if hasattr(f, 'name'):
39
        return f.name
40
    return '<unknown>'
41
42
1793.2.2 by Aaron Bentley
Move BundleReader into v07 serializer
43
def read_bundle(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
1793.2.7 by Aaron Bentley
Fix reporting of malformed, (especially, crlf) bundles
55
        elif line.startswith(BUNDLE_HEADER):
56
            raise errors.MalformedHeader()
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
57
        m = CHANGESET_OLD_HEADER_RE.match(line)
58
        if m:
59
            version = m.group('version')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
60
            raise errors.BundleNotSupported(version, 'old format bundles not supported')
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
61
62
    if version is None:
1793.2.2 by Aaron Bentley
Move BundleReader into v07 serializer
63
        raise errors.NotABundle('Did not find an opening header')
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
64
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
65
    # 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.
66
    if not _serializers.has_key(version):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
67
        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.
68
69
    serializer = _serializers[version](version)
70
71
    return serializer.read(f)
72
73
1185.82.74 by Aaron Bentley
Allow custom base for any revision
74
def write(source, revision_ids, f, version=None, forced_bases={}):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
75
    """Serialize a list of bundles to a filelike object.
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
76
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
77
    :param source: A source for revision information
78
    :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.
79
    :param f: The file to output to
80
    :param version: [optional] target serialization version
81
    """
82
83
    if not _serializers.has_key(version):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
84
        raise errors.BundleNotSupported(version, 'unknown bundle format')
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
85
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
86
    serializer = _serializers[version](version)
1185.82.74 by Aaron Bentley
Allow custom base for any revision
87
    return serializer.write(source, revision_ids, forced_bases, f) 
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
88
89
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
90
def write_bundle(repository, revision_id, base_revision_id, out):
1752.2.18 by Martin Pool
Formatting cleanups & docstrings
91
    """Write a bundle of revisions.
92
93
    :param repository: Repository containing revisions to serialize.
94
    :param revision_id: Head revision_id of the bundle.
95
    :param base_revision_id: Revision assumed to be present in repositories
96
         applying the bundle.
97
    :param out: Output file.
98
    """
1185.82.58 by Aaron Bentley
Handle empty branches properly
99
    if base_revision_id is NULL_REVISION:
100
        base_revision_id = None
1185.82.53 by Aaron Bentley
Factored out write_changeset to select revisions
101
    base_ancestry = set(repository.get_ancestry(base_revision_id))
102
    revision_ids = [r for r in repository.get_ancestry(revision_id) if r
103
                    not in base_ancestry]
104
    revision_ids = list(reversed(revision_ids))
1185.82.74 by Aaron Bentley
Allow custom base for any revision
105
    write(repository, revision_ids, out, 
106
          forced_bases = {revision_id:base_revision_id})
1185.82.53 by Aaron Bentley
Factored out write_changeset to select revisions
107
    return revision_ids
108
109
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
110
def format_highres_date(t, offset=0):
111
    """Format a date, such that it includes higher precision in the
112
    seconds field.
113
114
    :param t:   The local time in fractional seconds since the epoch
115
    :type t: float
116
    :param offset:  The timezone offset in integer seconds
117
    :type offset: int
118
119
    Example: format_highres_date(time.time(), -time.timezone)
120
    this will return a date stamp for right now,
121
    formatted for the local timezone.
122
123
    >>> from bzrlib.osutils import format_date
124
    >>> format_date(1120153132.350850105, 0)
125
    'Thu 2005-06-30 17:38:52 +0000'
126
    >>> format_highres_date(1120153132.350850105, 0)
127
    'Thu 2005-06-30 17:38:52.350850105 +0000'
128
    >>> format_date(1120153132.350850105, -5*3600)
129
    'Thu 2005-06-30 12:38:52 -0500'
130
    >>> format_highres_date(1120153132.350850105, -5*3600)
131
    'Thu 2005-06-30 12:38:52.350850105 -0500'
132
    >>> format_highres_date(1120153132.350850105, 7200)
133
    'Thu 2005-06-30 19:38:52.350850105 +0200'
1793.3.7 by John Arbash Meinel
Properly handle non-hour timezone offsets.
134
    >>> format_highres_date(1152428738.867522, 19800)
135
    'Sun 2006-07-09 12:35:38.867522001 +0530'
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
136
    """
137
    import time
138
    assert isinstance(t, float)
139
    
140
    # This has to be formatted for "original" date, so that the
141
    # revision XML entry will be reproduced faithfully.
142
    if offset == None:
143
        offset = 0
144
    tt = time.gmtime(t + offset)
145
146
    return (time.strftime("%a %Y-%m-%d %H:%M:%S", tt)
147
            + ('%.9f' % (t - int(t)))[1:] # Get the high-res seconds, but ignore the 0
148
            + ' %+03d%02d' % (offset / 3600, (offset / 60) % 60))
149
150
151
def unpack_highres_date(date):
152
    """This takes the high-resolution date stamp, and
153
    converts it back into the tuple (timestamp, timezone)
154
    Where timestamp is in real UTC since epoch seconds, and timezone is an integer
155
    number of seconds offset.
156
157
    :param date: A date formated by format_highres_date
158
    :type date: string
159
160
    >>> import time, random
161
    >>> unpack_highres_date('Thu 2005-06-30 12:38:52.350850105 -0500')
162
    (1120153132.3508501, -18000)
163
    >>> unpack_highres_date('Thu 2005-06-30 17:38:52.350850105 +0000')
164
    (1120153132.3508501, 0)
165
    >>> unpack_highres_date('Thu 2005-06-30 19:38:52.350850105 +0200')
166
    (1120153132.3508501, 7200)
1793.3.7 by John Arbash Meinel
Properly handle non-hour timezone offsets.
167
    >>> unpack_highres_date('Sun 2006-07-09 12:35:38.867522001 +0530')
168
    (1152428738.867522, 19800)
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
169
    >>> from bzrlib.osutils import local_time_offset
170
    >>> t = time.time()
171
    >>> o = local_time_offset()
172
    >>> t2, o2 = unpack_highres_date(format_highres_date(t, o))
173
    >>> t == t2
174
    True
175
    >>> o == o2
176
    True
177
    >>> t -= 24*3600*365*2 # Start 2 years ago
178
    >>> o = -12*3600
179
    >>> for count in xrange(500):
180
    ...   t += random.random()*24*3600*30
181
    ...   o = ((o/3600 + 13) % 25 - 12)*3600 # Add 1 wrap around from [-12, 12]
182
    ...   date = format_highres_date(t, o)
183
    ...   t2, o2 = unpack_highres_date(date)
184
    ...   if t != t2 or o != o2:
185
    ...      print 'Failed on date %r, %s,%s diff:%s' % (date, t, o, t2-t)
186
    ...      break
187
188
    """
189
    import time, calendar
190
    # Up until the first period is a datestamp that is generated
191
    # as normal from time.strftime, so use time.strptime to
192
    # parse it
193
    dot_loc = date.find('.')
194
    if dot_loc == -1:
195
        raise ValueError('Date string does not contain high-precision seconds: %r' % date)
196
    base_time = time.strptime(date[:dot_loc], "%a %Y-%m-%d %H:%M:%S")
197
    fract_seconds, offset = date[dot_loc:].split()
198
    fract_seconds = float(fract_seconds)
1793.3.11 by John Arbash Meinel
Cleanup unpack_highres_date from Aaron's suggestions.
199
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
200
    offset = int(offset)
1793.3.11 by John Arbash Meinel
Cleanup unpack_highres_date from Aaron's suggestions.
201
202
    hours = int(offset / 100)
203
    minutes = (offset % 100)
204
    seconds_offset = (hours * 3600) + (minutes * 60)
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
205
    
206
    # time.mktime returns localtime, but calendar.timegm returns UTC time
207
    timestamp = calendar.timegm(base_time)
1793.3.11 by John Arbash Meinel
Cleanup unpack_highres_date from Aaron's suggestions.
208
    timestamp -= seconds_offset
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
209
    # Add back in the fractional seconds
210
    timestamp += fract_seconds
1793.3.11 by John Arbash Meinel
Cleanup unpack_highres_date from Aaron's suggestions.
211
    return (timestamp, seconds_offset)
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
212
213
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
214
class BundleSerializer(object):
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
215
    """The base class for Serializers.
216
217
    Common functionality should be included here.
218
    """
219
    def __init__(self, version):
220
        self.version = version
221
222
    def read(self, f):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
223
        """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.
224
225
        :param f: The file to read from
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
226
        :return: A list of bundle trees
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
227
        """
228
        raise NotImplementedError
229
1185.82.74 by Aaron Bentley
Allow custom base for any revision
230
    def write(self, source, revision_ids, forced_bases, f):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
231
        """Write the bundle to the supplied file.
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
232
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
233
        :param source: A source for revision information
234
        :param revision_ids: The list of revision ids to serialize
1185.82.74 by Aaron Bentley
Allow custom base for any revision
235
        :param forced_bases: A dict of revision -> base that overrides default
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
236
        :param f: The file to output to
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
237
        """
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
238
        raise NotImplementedError
239
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
240
241
def register(version, klass, overwrite=False):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
242
    """Register a BundleSerializer version.
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
243
244
    :param version: The version associated with this format
245
    :param klass: The class to instantiate, which must take a version argument
246
    """
247
    global _serializers
248
    if overwrite:
249
        _serializers[version] = klass
250
        return
251
252
    if not _serializers.has_key(version):
253
        _serializers[version] = klass
254
255
256
def register_lazy(version, module, classname, overwrite=False):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
257
    """Register lazy-loaded bundle serializer.
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
258
259
    :param version: The version associated with this reader
260
    :param module: String indicating what module should be loaded
261
    :param classname: Name of the class that will be instantiated
262
    :param overwrite: Should this version override a default
263
    """
264
    def _loader(version):
265
        mod = __import__(module, globals(), locals(), [classname])
266
        klass = getattr(mod, classname)
267
        return klass(version)
1185.82.4 by John Arbash Meinel
Created output format, slightly simplified code
268
    register(version, _loader, overwrite=overwrite)
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
269
270
1185.82.96 by Aaron Bentley
Got first binary test passing
271
def binary_diff(old_filename, old_lines, new_filename, new_lines, to_file):
272
    temp = StringIO()
273
    internal_diff(old_filename, old_lines, new_filename, new_lines, temp,
274
                  allow_binary=True)
275
    temp.seek(0)
276
    base64.encode(temp, to_file)
277
    to_file.write('\n')
278
1551.7.3 by Aaron Bentley
Fix strict testaments, as_sha1
279
register_lazy('0.8', 'bzrlib.bundle.serializer.v08', 'BundleSerializerV08')
280
register_lazy(None, 'bzrlib.bundle.serializer.v08', 'BundleSerializerV08')
1185.82.3 by John Arbash Meinel
Working on creating a factor for serializing changesets.
281