/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
1
#!/usr/bin/env python
2
"""\
3
Common entries, like strings, etc, for the changeset reading + writing code.
4
"""
5
0.5.57 by John Arbash Meinel
Simplified the header, only output base if it is not the expected one.
6
header_str = 'Bazaar-NG changeset v'
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
7
version = (0, 0, 5)
8
9
def get_header():
10
    return [
11
        header_str + '.'.join([str(v) for v in version]),
12
        ''
13
    ]
14
0.5.36 by John Arbash Meinel
Updated so that read_changeset is able to parse the output
15
def canonicalize_revision(branch, revnos):
16
    """Turn some sort of revision information into a single
17
    set of from-to revision ids.
18
19
    A revision id can be None if there is no associated revison.
20
21
    :param revnos:  A list of revisions to lookup, should be at most 2 long
22
    :return: (old, new)
23
    """
24
    # If only 1 entry is given, then we assume we want just the
25
    # changeset between that entry and it's base (we assume parents[0])
26
    if len(revnos) == 0:
27
        revnos = [None, None]
28
    elif len(revnos) == 1:
29
        revnos = [None, revnos[0]]
30
31
    if revnos[1] is None:
32
        new = branch.last_patch()
33
    else:
34
        new = branch.lookup_revision(revnos[1])
35
    if revnos[0] is None:
0.5.58 by John Arbash Meinel
Fixed a bug in the case that there are no revision committed yet.
36
        if new is None:
37
            old = None
38
        else:
39
            old = branch.get_revision(new).parents[0].revision_id
0.5.36 by John Arbash Meinel
Updated so that read_changeset is able to parse the output
40
    else:
41
        old = branch.lookup_revision(revnos[0])
42
43
    return old, new
44
0.5.39 by John Arbash Meinel
(broken) Working on changing the processing to use a ChangesetTree.
45
class ChangesetTree(object):
46
    """This class is designed to take a base tree, and re-create
47
    a final tree based on the information contained within a
48
    changeset.
49
    """
50
51
    def __init__(self, branch, changeset_info):
52
        """Initialize this ChangesetTree.
53
54
        :param branch:  This is where information will be acquired
55
                        and updated.
56
        :param changeset_info:  Information about a given changeset,
57
                                so that we can identify the base,
58
                                and other information.
59
        """
60
        self.branch = branch
61
        self.changeset_info = changeset_info
62
63
        self._build_tree()
64
65
    def _build_tree(self):
66
        """Build the final description of the tree, based on
67
        the changeset_info object.
68
        """
0.5.40 by John Arbash Meinel
Added some highres formatting of datestamps.
69
        self.base_tree = self.branch.revision_tree(self.changeset_info.base)
0.5.39 by John Arbash Meinel
(broken) Working on changing the processing to use a ChangesetTree.
70
        
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
71
def guess_text_id(tree, file_id, rev_id, modified=True):
72
    """This returns the estimated text_id for a given file.
73
    The idea is that in general the text_id should be the id last
74
    revision which modified the file.
75
76
    :param tree: This should be the base tree for a changeset, since that
77
                 is all the target has for guessing.
78
    :param file_id: The file id to guess the text_id for.
79
    :param rev_id: The target revision id
80
    :param modified: Was the file modified between base and target?
81
    """
82
    from bzrlib.errors import BzrError
83
    if modified:
84
        # If the file was modified in an intermediate stage
85
        # (not in the final target), this won't be correct
86
        # but it is our best guess.
87
        # TODO: In the current code, text-ids are randomly generated
88
        # using the filename as the base. In the future they will
89
        # probably follow this format.
90
        return file_id + '-' + rev_id
91
    # The file was not actually modified in this changeset
92
    # so the text_id should be equal to it's previous value
93
    if not file_id in tree.inventory:
94
        raise BzrError('Unable to generate text_id for file_id {%s}'
95
            ', file does not exist in tree.' % file_id)
96
    # This is the last known text_id for this file
97
    # so assume that it is being used.
98
    text_id = tree.inventory[file_id].text_id
99
100
def encode(s):
101
    """Take a unicode string, and make sure to escape it for
102
    use in a changeset.
103
104
    Note: It can be either a normal, or a unicode string
105
106
    >>> encode(u'abcdefg')
107
    'abcdefg'
108
    >>> encode(u'a b\tc\\nd\\\\e')
109
    'a b\\\\tc\\\\nd\\\\e'
110
    >>> encode('a b\tc\\nd\\e')
111
    'a b\\\\tc\\\\nd\\\\e'
112
    >>> encode(u'\\u1234\\u0020')
113
    '\\\\u1234 '
114
    >>> encode('abcdefg')
115
    'abcdefg'
116
    >>> encode(u'')
117
    ''
118
    >>> encode('')
119
    ''
120
    """
121
    return s.encode('unicode_escape')
122
123
def decode(s):
124
    """Undo the encode operation, returning a unicode string.
125
126
    >>> decode('abcdefg')
127
    u'abcdefg'
128
    >>> decode('a b\\\\tc\\\\nd\\\\e')
129
    u'a b\tc\\nd\\\\e'
130
    >>> decode('\\\\u1234\\\\u0020')
131
    u'\\u1234 '
132
    >>> for s in ('test', 'strings'):
133
    ...   if decode(encode(s)) != s:
134
    ...     print 'Failed: %r' % s # There should be no failures
135
136
    """
137
    return s.decode('unicode_escape')
138
0.5.39 by John Arbash Meinel
(broken) Working on changing the processing to use a ChangesetTree.
139
def format_highres_date(t, offset=0):
140
    """Format a date, such that it includes higher precision in the
141
    seconds field.
142
0.5.40 by John Arbash Meinel
Added some highres formatting of datestamps.
143
    :param t:   The local time in fractional seconds since the epoch
0.5.39 by John Arbash Meinel
(broken) Working on changing the processing to use a ChangesetTree.
144
    :type t: float
145
    :param offset:  The timezone offset in integer seconds
146
    :type offset: int
147
0.5.40 by John Arbash Meinel
Added some highres formatting of datestamps.
148
    Example: format_highres_date(time.time(), -time.timezone)
149
    this will return a date stamp for right now,
150
    formatted for the local timezone.
151
0.5.39 by John Arbash Meinel
(broken) Working on changing the processing to use a ChangesetTree.
152
    >>> from bzrlib.osutils import format_date
153
    >>> format_date(1120153132.350850105, 0)
154
    'Thu 2005-06-30 17:38:52 +0000'
155
    >>> format_highres_date(1120153132.350850105, 0)
156
    'Thu 2005-06-30 17:38:52.350850105 +0000'
157
    >>> format_date(1120153132.350850105, -5*3600)
158
    'Thu 2005-06-30 12:38:52 -0500'
159
    >>> format_highres_date(1120153132.350850105, -5*3600)
160
    'Thu 2005-06-30 12:38:52.350850105 -0500'
0.5.40 by John Arbash Meinel
Added some highres formatting of datestamps.
161
    >>> format_highres_date(1120153132.350850105, 7200)
162
    'Thu 2005-06-30 19:38:52.350850105 +0200'
0.5.39 by John Arbash Meinel
(broken) Working on changing the processing to use a ChangesetTree.
163
    """
164
    import time
165
    assert isinstance(t, float)
166
    
167
    # This has to be formatted for "original" date, so that the
168
    # revision XML entry will be reproduced faithfully.
169
    if offset == None:
170
        offset = 0
171
    tt = time.gmtime(t + offset)
172
173
    return (time.strftime("%a %Y-%m-%d %H:%M:%S", tt)
174
            + ('%.9f' % (t - int(t)))[1:] # Get the high-res seconds, but ignore the 0
175
            + ' %+03d%02d' % (offset / 3600, (offset / 60) % 60))
176
177
def unpack_highres_date(date):
178
    """This takes the high-resolution date stamp, and
179
    converts it back into the tuple (timestamp, timezone)
180
    Where timestamp is in real seconds, and timezone is an integer
181
    number of seconds offset.
182
183
    :param date: A date formated by format_highres_date
184
    :type date: string
185
0.5.40 by John Arbash Meinel
Added some highres formatting of datestamps.
186
    >>> import time, random
187
    >>> unpack_highres_date('Thu 2005-06-30 12:38:52.350850105 -0500')
188
    (1120153132.3508501, -18000)
189
    >>> unpack_highres_date('Thu 2005-06-30 17:38:52.350850105 +0000')
190
    (1120153132.3508501, 0)
191
    >>> unpack_highres_date('Thu 2005-06-30 19:38:52.350850105 +0200')
192
    (1120153132.3508501, 7200)
193
    >>> from bzrlib.osutils import local_time_offset
194
    >>> t = time.time()
195
    >>> o = local_time_offset()
196
    >>> t2, o2 = unpack_highres_date(format_highres_date(t, o))
197
    >>> t == t2
198
    True
199
    >>> o == o2
200
    True
201
    >>> for count in xrange(500):
202
    ...   t += random.random()*24*3600*365*2 - 24*3600*364 # Random time within +/- 1 year
203
    ...   o = random.randint(-12,12)*3600 # Random timezone
204
    ...   date = format_highres_date(t, o)
205
    ...   t2, o2 = unpack_highres_date(date)
206
    ...   if t != t2 or o != o2:
207
    ...      print 'Failed on date %r, %s,%s diff:%s' % (date, t, o, t2-t)
208
0.5.39 by John Arbash Meinel
(broken) Working on changing the processing to use a ChangesetTree.
209
    """
0.5.40 by John Arbash Meinel
Added some highres formatting of datestamps.
210
    #from bzrlib.errors import BzrError
211
    from bzrlib.osutils import local_time_offset
212
    import time
213
    # Up until the first period is a datestamp that is generated
214
    # as normal from time.strftime, so use time.strptime to
215
    # parse it
216
    dot_loc = date.find('.')
217
    if dot_loc == -1:
218
        raise ValueError('Date string does not contain high-precision seconds: %r' % date)
219
    base_time = time.strptime(date[:dot_loc], "%a %Y-%m-%d %H:%M:%S")
220
    fract_seconds, offset = date[dot_loc:].split()
221
    fract_seconds = float(fract_seconds)
222
    offset = int(offset)
223
    offset = int(offset / 100) * 3600 + offset % 100
224
    
225
    # mktime returns the a local timestamp, not the timestamp based
226
    # on the offset given in the file, so we need to adjust based
227
    # on what the local offset is, and then re-adjust based on
228
    # offset read
229
    timestamp = time.mktime(base_time)
230
    timestamp += local_time_offset(timestamp) - offset
231
    # Add back in the fractional seconds
232
    timestamp += fract_seconds
233
    return (timestamp, offset)
0.5.39 by John Arbash Meinel
(broken) Working on changing the processing to use a ChangesetTree.
234
235
if __name__ == '__main__':
236
    import doctest
237
    doctest.testmod()
0.5.40 by John Arbash Meinel
Added some highres formatting of datestamps.
238