/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
1185.82.15 by Aaron Bentley
Disabled validate_revisions (needs info it doesn't have), updated API to repos
6
from sha import sha
7
0.5.79 by John Arbash Meinel
Added common to the set of tests, fixed a problem with time conversions.
8
import bzrlib
1185.82.15 by Aaron Bentley
Disabled validate_revisions (needs info it doesn't have), updated API to repos
9
from bzrlib.testament import Testament
0.5.79 by John Arbash Meinel
Added common to the set of tests, fixed a problem with time conversions.
10
1185.82.26 by Aaron Bentley
Get changeset merges closer to working
11
header_str = 'Bazaar changeset v'
1185.82.38 by Aaron Bentley
Changed changeset version number to 0.7
12
version = (0, 7)
0.5.7 by John Arbash Meinel
Added a bunch more information about changesets. Can now read back in all of the meta information.
13
14
def get_header():
15
    return [
16
        header_str + '.'.join([str(v) for v in version]),
17
        ''
18
    ]
19
0.5.36 by John Arbash Meinel
Updated so that read_changeset is able to parse the output
20
def canonicalize_revision(branch, revnos):
21
    """Turn some sort of revision information into a single
22
    set of from-to revision ids.
23
24
    A revision id can be None if there is no associated revison.
25
26
    :param revnos:  A list of revisions to lookup, should be at most 2 long
27
    :return: (old, new)
28
    """
29
    # If only 1 entry is given, then we assume we want just the
30
    # changeset between that entry and it's base (we assume parents[0])
31
    if len(revnos) == 0:
32
        revnos = [None, None]
33
    elif len(revnos) == 1:
34
        revnos = [None, revnos[0]]
35
36
    if revnos[1] is None:
37
        new = branch.last_patch()
38
    else:
39
        new = branch.lookup_revision(revnos[1])
40
    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.
41
        if new is None:
42
            old = None
43
        else:
0.5.59 by John Arbash Meinel
Several fixes for handling the case where you are doing a changeset against revno=0 (Null base)
44
            oldrev = branch.get_revision(new)
45
            if len(oldrev.parents) == 0:
46
                old = None
47
            else:
48
                old = oldrev.parents[0].revision_id
0.5.36 by John Arbash Meinel
Updated so that read_changeset is able to parse the output
49
    else:
50
        old = branch.lookup_revision(revnos[0])
51
52
    return old, new
53
0.5.39 by John Arbash Meinel
(broken) Working on changing the processing to use a ChangesetTree.
54
class ChangesetTree(object):
55
    """This class is designed to take a base tree, and re-create
56
    a final tree based on the information contained within a
57
    changeset.
58
    """
59
60
    def __init__(self, branch, changeset_info):
61
        """Initialize this ChangesetTree.
62
63
        :param branch:  This is where information will be acquired
64
                        and updated.
65
        :param changeset_info:  Information about a given changeset,
66
                                so that we can identify the base,
67
                                and other information.
68
        """
69
        self.branch = branch
70
        self.changeset_info = changeset_info
71
72
        self._build_tree()
73
74
    def _build_tree(self):
75
        """Build the final description of the tree, based on
76
        the changeset_info object.
77
        """
0.5.40 by John Arbash Meinel
Added some highres formatting of datestamps.
78
        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.
79
        
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
80
def encode(s):
81
    """Take a unicode string, and make sure to escape it for
82
    use in a changeset.
83
84
    Note: It can be either a normal, or a unicode string
85
86
    >>> encode(u'abcdefg')
87
    'abcdefg'
0.5.79 by John Arbash Meinel
Added common to the set of tests, fixed a problem with time conversions.
88
    >>> encode(u'a b\\tc\\nd\\\\e')
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
89
    'a b\\tc\\nd\\\\e'
0.5.79 by John Arbash Meinel
Added common to the set of tests, fixed a problem with time conversions.
90
    >>> encode('a b\\tc\\nd\\e')
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
91
    'a b\\tc\\nd\\\\e'
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
92
    >>> encode(u'\\u1234\\u0020')
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
93
    '\\xe1\\x88\\xb4 '
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
94
    >>> encode('abcdefg')
95
    'abcdefg'
96
    >>> encode(u'')
97
    ''
98
    >>> encode('')
99
    ''
100
    """
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
101
    return s.encode('utf-8')
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
102
103
def decode(s):
104
    """Undo the encode operation, returning a unicode string.
105
106
    >>> decode('abcdefg')
107
    u'abcdefg'
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
108
    >>> decode('a b\\tc\\nd\\\\e')
0.5.79 by John Arbash Meinel
Added common to the set of tests, fixed a problem with time conversions.
109
    u'a b\\tc\\nd\\\\e'
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
110
    >>> decode('\\xe1\\x88\\xb4 ')
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
111
    u'\\u1234 '
112
    >>> for s in ('test', 'strings'):
113
    ...   if decode(encode(s)) != s:
114
    ...     print 'Failed: %r' % s # There should be no failures
115
116
    """
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
117
    return s.decode('utf-8')
0.5.55 by John Arbash Meinel
Lots of updates. Using a minimized annotations for changesets.
118
0.5.39 by John Arbash Meinel
(broken) Working on changing the processing to use a ChangesetTree.
119
def format_highres_date(t, offset=0):
120
    """Format a date, such that it includes higher precision in the
121
    seconds field.
122
0.5.40 by John Arbash Meinel
Added some highres formatting of datestamps.
123
    :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.
124
    :type t: float
125
    :param offset:  The timezone offset in integer seconds
126
    :type offset: int
127
0.5.40 by John Arbash Meinel
Added some highres formatting of datestamps.
128
    Example: format_highres_date(time.time(), -time.timezone)
129
    this will return a date stamp for right now,
130
    formatted for the local timezone.
131
0.5.39 by John Arbash Meinel
(broken) Working on changing the processing to use a ChangesetTree.
132
    >>> from bzrlib.osutils import format_date
133
    >>> format_date(1120153132.350850105, 0)
134
    'Thu 2005-06-30 17:38:52 +0000'
135
    >>> format_highres_date(1120153132.350850105, 0)
136
    'Thu 2005-06-30 17:38:52.350850105 +0000'
137
    >>> format_date(1120153132.350850105, -5*3600)
138
    'Thu 2005-06-30 12:38:52 -0500'
139
    >>> format_highres_date(1120153132.350850105, -5*3600)
140
    'Thu 2005-06-30 12:38:52.350850105 -0500'
0.5.40 by John Arbash Meinel
Added some highres formatting of datestamps.
141
    >>> format_highres_date(1120153132.350850105, 7200)
142
    '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.
143
    """
144
    import time
145
    assert isinstance(t, float)
146
    
147
    # This has to be formatted for "original" date, so that the
148
    # revision XML entry will be reproduced faithfully.
149
    if offset == None:
150
        offset = 0
151
    tt = time.gmtime(t + offset)
152
153
    return (time.strftime("%a %Y-%m-%d %H:%M:%S", tt)
154
            + ('%.9f' % (t - int(t)))[1:] # Get the high-res seconds, but ignore the 0
155
            + ' %+03d%02d' % (offset / 3600, (offset / 60) % 60))
156
157
def unpack_highres_date(date):
158
    """This takes the high-resolution date stamp, and
159
    converts it back into the tuple (timestamp, timezone)
0.5.79 by John Arbash Meinel
Added common to the set of tests, fixed a problem with time conversions.
160
    Where timestamp is in real UTC since epoch seconds, and timezone is an integer
0.5.39 by John Arbash Meinel
(broken) Working on changing the processing to use a ChangesetTree.
161
    number of seconds offset.
162
163
    :param date: A date formated by format_highres_date
164
    :type date: string
165
0.5.40 by John Arbash Meinel
Added some highres formatting of datestamps.
166
    >>> import time, random
167
    >>> unpack_highres_date('Thu 2005-06-30 12:38:52.350850105 -0500')
168
    (1120153132.3508501, -18000)
169
    >>> unpack_highres_date('Thu 2005-06-30 17:38:52.350850105 +0000')
170
    (1120153132.3508501, 0)
171
    >>> unpack_highres_date('Thu 2005-06-30 19:38:52.350850105 +0200')
172
    (1120153132.3508501, 7200)
173
    >>> from bzrlib.osutils import local_time_offset
174
    >>> t = time.time()
175
    >>> o = local_time_offset()
176
    >>> t2, o2 = unpack_highres_date(format_highres_date(t, o))
177
    >>> t == t2
178
    True
179
    >>> o == o2
180
    True
0.5.90 by John Arbash Meinel
Switching from random walk, to random progression
181
    >>> t -= 24*3600*365*2 # Start 2 years ago
182
    >>> o = -12*3600
0.5.40 by John Arbash Meinel
Added some highres formatting of datestamps.
183
    >>> for count in xrange(500):
0.5.90 by John Arbash Meinel
Switching from random walk, to random progression
184
    ...   t += random.random()*24*3600*30
185
    ...   o = ((o/3600 + 13) % 25 - 12)*3600 # Add 1 wrap around from [-12, 12]
0.5.40 by John Arbash Meinel
Added some highres formatting of datestamps.
186
    ...   date = format_highres_date(t, o)
187
    ...   t2, o2 = unpack_highres_date(date)
188
    ...   if t != t2 or o != o2:
189
    ...      print 'Failed on date %r, %s,%s diff:%s' % (date, t, o, t2-t)
0.5.79 by John Arbash Meinel
Added common to the set of tests, fixed a problem with time conversions.
190
    ...      break
0.5.40 by John Arbash Meinel
Added some highres formatting of datestamps.
191
0.5.39 by John Arbash Meinel
(broken) Working on changing the processing to use a ChangesetTree.
192
    """
0.5.79 by John Arbash Meinel
Added common to the set of tests, fixed a problem with time conversions.
193
    import time, calendar
0.5.40 by John Arbash Meinel
Added some highres formatting of datestamps.
194
    # Up until the first period is a datestamp that is generated
195
    # as normal from time.strftime, so use time.strptime to
196
    # parse it
197
    dot_loc = date.find('.')
198
    if dot_loc == -1:
199
        raise ValueError('Date string does not contain high-precision seconds: %r' % date)
200
    base_time = time.strptime(date[:dot_loc], "%a %Y-%m-%d %H:%M:%S")
201
    fract_seconds, offset = date[dot_loc:].split()
202
    fract_seconds = float(fract_seconds)
203
    offset = int(offset)
204
    offset = int(offset / 100) * 3600 + offset % 100
205
    
0.5.79 by John Arbash Meinel
Added common to the set of tests, fixed a problem with time conversions.
206
    # time.mktime returns localtime, but calendar.timegm returns UTC time
207
    timestamp = calendar.timegm(base_time)
208
    timestamp -= offset
0.5.40 by John Arbash Meinel
Added some highres formatting of datestamps.
209
    # Add back in the fractional seconds
210
    timestamp += fract_seconds
211
    return (timestamp, offset)
0.5.39 by John Arbash Meinel
(broken) Working on changing the processing to use a ChangesetTree.
212
1185.82.15 by Aaron Bentley
Disabled validate_revisions (needs info it doesn't have), updated API to repos
213
214
def testament_sha1(repository, revision_id):
215
    text = Testament.from_revision(repository, revision_id).as_short_text()
216
    s = sha(text)
217
    return s.hexdigest()
218
 
219
0.5.39 by John Arbash Meinel
(broken) Working on changing the processing to use a ChangesetTree.
220
if __name__ == '__main__':
221
    import doctest
222
    doctest.testmod()
0.5.40 by John Arbash Meinel
Added some highres formatting of datestamps.
223