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