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