~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to read_changeset.py

  • Committer: John Arbash Meinel
  • Date: 2005-07-02 06:35:00 UTC
  • mto: (0.5.85) (1185.82.1 bzr-w-changeset)
  • mto: This revision was merged to the branch mainline in revision 1738.
  • Revision ID: john@arbash-meinel.com-20050702063459-031705c159631d21
A couple more fixups, it seems actually capable now of writing out a changeset, and reading it back.

Show diffs side-by-side

added added

removed removed

Lines of Context:
78
78
 
79
79
        # A list of RevisionInfo objects
80
80
        self.revisions = []
 
81
 
 
82
        self.actions = []
 
83
 
 
84
        # The next entries are created during complete_info() and
 
85
        # other post-read functions.
 
86
 
 
87
        # A list of real Revision objects
 
88
        self.real_revisions = []
81
89
        self.text_ids = {} # file_id => text_id
82
90
 
83
 
        self.actions = []
84
 
 
85
91
        self.timestamp = None
86
92
        self.timezone = None
87
93
 
93
99
        split up, based on the assumptions that can be made
94
100
        when information is missing.
95
101
        """
96
 
        if self.base is None:
97
 
            # When we don't have a base, then the real base
98
 
            # is the first parent of the last revision listed
99
 
            rev = self.revisions[-1]
100
 
            self.base = rev.parents[0].revision_id
101
 
            # In general, if self.base is None, self.base_sha1 should
102
 
            # also be None
103
 
            if self.base_sha1 is not None:
104
 
                assert self.base_sha1 == rev.parent[0].revision_sha1
105
 
            self.base_sha1 = rev.parents[0].revision_sha1
106
 
 
 
102
        # Put in all of the guessable information.
107
103
        if not self.timestamp and self.date:
108
104
            self.timestamp, self.timezone = common.unpack_highres_date(self.date)
109
105
 
 
106
        self.real_revisions = []
110
107
        for rev in self.revisions:
111
108
            if rev.timestamp is None and self.timestamp is not None:
112
109
                rev.timestamp = self.timestamp
115
112
                rev.message = self.message
116
113
            if rev.committer is None and self.committer:
117
114
                rev.committer = self.committer
 
115
            if rev.inventory_id is None:
 
116
                rev.inventory_id = rev.rev_id
 
117
            self.real_revisions.append(rev.as_revision())
 
118
 
 
119
        if self.base is None:
 
120
            # When we don't have a base, then the real base
 
121
            # is the first parent of the first revision listed
 
122
            rev = self.real_revisions[0]
 
123
            self.base = rev.parents[0].revision_id
 
124
            # In general, if self.base is None, self.base_sha1 should
 
125
            # also be None
 
126
            if self.base_sha1 is not None:
 
127
                assert self.base_sha1 == rev.parents[0].revision_sha1
 
128
            self.base_sha1 = rev.parents[0].revision_sha1
 
129
 
 
130
 
118
131
 
119
132
class ChangesetReader(object):
120
133
    """This class reads in a changeset from a file, and returns
151
164
        tree = ChangesetTree(branch.revision_tree(self.info.base))
152
165
        self._update_tree(tree)
153
166
 
154
 
        return self.info, self.tree
 
167
        return self.info, tree
155
168
 
156
169
    def _next(self):
157
170
        """yield the next line, but secretly
158
171
        keep 1 extra line for peeking.
159
172
        """
 
173
        from bzrlib.trace import mutter
160
174
        for line in self.from_file:
161
175
            last = self._next_line
162
176
            self._next_line = line
163
177
            if last is not None:
 
178
                mutter('yielding line: %r' % last)
164
179
                yield last
 
180
        last = self._next_line
 
181
        self._next_line = None
 
182
        mutter('yielding line: %r' % last)
 
183
        yield last
165
184
 
166
185
    def _read_header(self):
167
186
        """Read the bzr header"""
198
217
    def _read_next_entry(self, line, indent=1):
199
218
        """Read in a key-value pair
200
219
        """
 
220
        from bzrlib.trace import mutter
201
221
        if line[:1] != '#':
202
222
            raise MalformedHeader('Bzr header did not start with #')
203
223
        line = line[1:-1] # Remove the '#' and '\n'
220
240
                    ' did not find the colon %r' % (line))
221
241
 
222
242
        key = key.replace(' ', '_')
 
243
        mutter('found %s: %s' % (key, value))
223
244
        return key, value
224
245
 
225
246
    def _handle_next(self, line):
245
266
        This detects the end of the list, because it will be a line that
246
267
        does not start properly indented.
247
268
        """
 
269
        from bzrlib.trace import mutter
248
270
        values = []
249
271
        start = '#' + (' '*indent)
250
272
 
251
 
        if self._next_line[:len(start)] != start:
 
273
        if self._next_line is None or self._next_line[:len(start)] != start:
252
274
            return values
253
275
 
254
276
        for line in self._next():
255
277
            values.append(line[len(start):-1])
256
 
            if self._next_line[:len(start)] != start:
 
278
            if self._next_line is None or self._next_line[:len(start)] != start:
257
279
                break
258
280
        return values
259
281
 
264
286
        :return: action, lines, do_continue
265
287
        """
266
288
        # Peek and see if there are no patches
267
 
        if self._next_line[:1] == '#':
 
289
        if self._next_line is None or self._next_line[:1] == '#':
268
290
            return None, [], False
269
291
 
270
292
        line = self._next().next()
271
293
        if line[:3] != '***':
272
294
            raise MalformedPatches('The first line of all patches'
273
 
                ' should be a bzr meta line "***"')
 
295
                ' should be a bzr meta line "***"'
 
296
                ': %r' % line)
274
297
        action = line[4:-1]
275
298
 
276
299
        lines = []
277
300
        for line in self._next():
278
301
            lines.append(line)
279
302
 
280
 
            if self._next_line[:3] == '***':
 
303
            if self._next_line is not None and self._next_line[:3] == '***':
281
304
                return action, lines, True
282
 
            elif self._next_line[:1] == '#':
 
305
            elif self._next_line is None or self._next_line[:1] == '#':
283
306
                return action, lines, False
284
307
        return action, lines, False
285
308
            
308
331
                # What do we do with a key we don't recognize
309
332
                raise MalformedHeader('Unknown Key: %s' % key)
310
333
 
311
 
            if self._next_line[:len(start)] != start:
 
334
            if self._next_line is None or self._next_line[:len(start)] != start:
312
335
                break
313
336
 
314
337
        self.info.revisions.append(rev_info)
322
345
        line = self._next().next()
323
346
        for line in self._next():
324
347
            self._handle_next(line)
325
 
            if self._next_line[:1] != '#':
 
348
            if self._next_line is None or self._next_line[:1] != '#':
326
349
                break
327
350
 
328
351
    def _update_tree(self, tree):
442
465
            if first == -1:
443
466
                raise BzrError('Bogus action line'
444
467
                        ' (no opening space): %r' % action_line)
445
 
            second = action_line.find(' ', first)
 
468
            second = action_line.find(' ', first+1)
446
469
            if second == -1:
447
470
                raise BzrError('Bogus action line'
448
471
                        ' (missing second space): %r' % action_line)
450
473
            kind = action_line[first+1:second]
451
474
            if kind not in ('file', 'directory'):
452
475
                raise BzrError('Bogus action line'
453
 
                        ' (invalid object kind): %r' % action_line)
 
476
                        ' (invalid object kind %r): %r' % (kind, action_line))
454
477
            extra = action_line[second+1:]
455
478
 
456
479
            if action not in valid_actions:
458
481
                        ' (unrecognized action): %r' % action_line)
459
482
            valid_actions[action](kind, extra, lines)
460
483
 
461
 
def read_changeset(from_file):
462
 
    """Read in a changeset from a filelike object (must have "readline" support), and
463
 
    parse it into a Changeset object.
 
484
def read_changeset(from_file, branch):
 
485
    """Read in a changeset from a iterable object (such as a file object)
 
486
 
 
487
    :param from_file: A file-like object to read the changeset information.
 
488
    :param branch: This will be used to build the changeset tree, it needs
 
489
                   to contain the base of the changeset. (Which you probably
 
490
                   won't know about until after the changeset is parsed.)
464
491
    """
465
492
    cr = ChangesetReader(from_file)
466
 
    info = cr.get_info()
467
 
    return info
468
 
 
 
493
    return cr.get_info_and_tree(branch)
469
494
 
470
495
class ChangesetTree:
471
496
    def __init__(self, base_tree=None):
508
533
        if old_path is not None:
509
534
            return old_path
510
535
        dirname,basename = os.path.split(new_path)
511
 
        if dirname is not '':
 
536
        # dirname is not '' doesn't work, because
 
537
        # dirname may be a unicode entry, and is
 
538
        # requires the objects to be identical
 
539
        if dirname != '':
512
540
            old_dir = self.old_path(dirname)
513
541
            if old_dir is None:
514
542
                old_path = None
558
586
            return None
559
587
        if old_path in self.deleted:
560
588
            return None
561
 
        return self.base_tree.path2id(old_path)
 
589
        return self.base_tree.inventory.path2id(old_path)
562
590
 
563
591
    def id2path(self, file_id):
564
592
        """Return the new path in the target tree of the file with id file_id"""