/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/commit.py

  • Committer: Martin Pool
  • Date: 2007-06-15 07:01:24 UTC
  • mfrom: (2528 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2530.
  • Revision ID: mbp@sourcefrog.net-20070615070124-clpwqh5gxc4wbf9l
Merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
106
106
 
107
107
class ReportCommitToLog(NullCommitReporter):
108
108
 
109
 
    # this may be more useful if 'note' was replaced by an overridable
110
 
    # method on self, which would allow more trivial subclassing.
111
 
    # alternative, a callable could be passed in, allowing really trivial
112
 
    # reuse for some uis. RBC 20060511
 
109
    def _note(self, format, *args):
 
110
        """Output a message.
 
111
 
 
112
        Messages are output by writing directly to stderr instead of
 
113
        using bzrlib.trace.note(). The latter constantly updates the
 
114
        log file as we go causing an unnecessary performance hit.
 
115
 
 
116
        Subclasses may choose to override this method but need to be aware
 
117
        of its potential impact on performance.
 
118
        """
 
119
        bzrlib.ui.ui_factory.clear_term()
 
120
        sys.stderr.write((format + "\n") % args)
113
121
 
114
122
    def snapshot_change(self, change, path):
115
123
        if change == 'unchanged':
116
124
            return
117
125
        if change == 'added' and path == '':
118
126
            return
119
 
        note("%s %s", change, path)
 
127
        self._note("%s %s", change, path)
120
128
 
121
129
    def completed(self, revno, rev_id):
122
 
        note('Committed revision %d.', revno)
 
130
        self._note('Committed revision %d.', revno)
123
131
    
124
132
    def deleted(self, file_id):
125
 
        note('deleted %s', file_id)
 
133
        self._note('deleted %s', file_id)
126
134
 
127
135
    def escaped(self, escape_count, message):
128
 
        note("replaced %d control characters in message", escape_count)
 
136
        self._note("replaced %d control characters in message", escape_count)
129
137
 
130
138
    def missing(self, path):
131
 
        note('missing %s', path)
 
139
        self._note('missing %s', path)
132
140
 
133
141
    def renamed(self, change, old_path, new_path):
134
 
        note('%s %s => %s', change, old_path, new_path)
 
142
        self._note('%s %s => %s', change, old_path, new_path)
135
143
 
136
144
 
137
145
class Commit(object):
153
161
            self.reporter = reporter
154
162
        else:
155
163
            self.reporter = NullCommitReporter()
156
 
        if config is not None:
157
 
            self.config = config
158
 
        else:
159
 
            self.config = None
 
164
        self.config = config
160
165
        
161
166
    def commit(self,
162
167
               message=None,
177
182
               recursive='down'):
178
183
        """Commit working copy as a new revision.
179
184
 
180
 
        message -- the commit message (it or message_callback is required)
181
 
 
182
 
        timestamp -- if not None, seconds-since-epoch for a
183
 
             postdated/predated commit.
184
 
 
185
 
        specific_files -- If true, commit only those files.
186
 
 
187
 
        rev_id -- If set, use this as the new revision id.
 
185
        :param message: the commit message (it or message_callback is required)
 
186
 
 
187
        :param timestamp: if not None, seconds-since-epoch for a
 
188
            postdated/predated commit.
 
189
 
 
190
        :param specific_files: If true, commit only those files.
 
191
 
 
192
        :param rev_id: If set, use this as the new revision id.
188
193
            Useful for test or import commands that need to tightly
189
194
            control what revisions are assigned.  If you duplicate
190
195
            a revision id that exists elsewhere it is your own fault.
191
196
            If null (default), a time/random revision id is generated.
192
197
 
193
 
        allow_pointless -- If true (default), commit even if nothing
 
198
        :param allow_pointless: If true (default), commit even if nothing
194
199
            has changed and no merges are recorded.
195
200
 
196
 
        strict -- If true, don't allow a commit if the working tree
 
201
        :param strict: If true, don't allow a commit if the working tree
197
202
            contains unknown files.
198
203
 
199
 
        revprops -- Properties for new revision
 
204
        :param revprops: Properties for new revision
200
205
        :param local: Perform a local only commit.
201
206
        :param recursive: If set to 'down', commit in any subtrees that have
202
207
            pending changes of any sort during this commit.
233
238
        self.timestamp = timestamp
234
239
        self.timezone = timezone
235
240
        self.committer = committer
236
 
        self.specific_files = specific_files
237
241
        self.strict = strict
238
242
        self.verbose = verbose
239
 
        self.local = local
240
243
 
241
244
        if reporter is None and self.reporter is None:
242
245
            self.reporter = NullCommitReporter()
249
252
        self.basis_tree.lock_read()
250
253
        try:
251
254
            # Cannot commit with conflicts present.
252
 
            if len(self.work_tree.conflicts())>0:
 
255
            if len(self.work_tree.conflicts()) > 0:
253
256
                raise ConflictsInTree
254
257
 
255
 
            # setup the bound branch variables as needed.
 
258
            # Setup the bound branch variables as needed.
256
259
            self._check_bound_branch()
257
260
 
258
 
            # check for out of date working trees
259
 
            try:
260
 
                first_tree_parent = self.work_tree.get_parent_ids()[0]
261
 
            except IndexError:
262
 
                # if there are no parents, treat our parent as 'None'
263
 
                # this is so that we still consier the master branch
264
 
                # - in a checkout scenario the tree may have no
265
 
                # parents but the branch may do.
266
 
                first_tree_parent = bzrlib.revision.NULL_REVISION
267
 
            old_revno, master_last = self.master_branch.last_revision_info()
268
 
            if master_last != first_tree_parent:
269
 
                if master_last != bzrlib.revision.NULL_REVISION:
270
 
                    raise errors.OutOfDateTree(self.work_tree)
271
 
            if self.branch.repository.has_revision(first_tree_parent):
272
 
                new_revno = old_revno + 1
273
 
            else:
274
 
                # ghost parents never appear in revision history.
275
 
                new_revno = 1
 
261
            # Check that the working tree is up to date
 
262
            old_revno,new_revno = self._check_out_of_date_tree()
 
263
 
276
264
            if strict:
277
265
                # raise an exception as soon as we find a single unknown.
278
266
                for unknown in self.work_tree.unknowns():
290
278
                # cheaply?
291
279
                tree.find_ids_across_trees(specific_files,
292
280
                                           [self.basis_tree, self.work_tree])
 
281
 
 
282
            # Setup the progress bar ...
293
283
            # one to finish, one for rev and inventory, and one for each
294
284
            # inventory entry, and the same for the new inventory.
295
285
            # note that this estimate is too long when we do a partial tree
300
290
 
301
291
            self._gather_parents()
302
292
            if len(self.parents) > 1 and self.specific_files:
303
 
                raise NotImplementedError('selected-file commit of merges is not supported yet: files %r',
304
 
                        self.specific_files)
 
293
                raise errors.CannotCommitSelectedFileMerge(self.specific_files)
305
294
            
 
295
            # Build the new inventory
306
296
            self.builder = self.branch.get_commit_builder(self.parents,
307
297
                self.config, timestamp, timezone, committer, revprops, rev_id)
308
 
            
309
298
            self._remove_deleted()
310
299
            self._populate_new_inv()
311
300
            self._report_deletes()
312
 
 
313
301
            self._check_pointless()
 
302
            self._emit_progress_update()
314
303
 
315
 
            self._emit_progress_update()
316
304
            # TODO: Now the new inventory is known, check for conflicts and
317
305
            # prompt the user for a commit message.
318
306
            # ADHB 2006-08-08: If this is done, populate_new_inv should not add
325
313
            self.message = message
326
314
            self._escape_commit_message()
327
315
 
 
316
            # Add revision data to the local branch
328
317
            self.rev_id = self.builder.commit(self.message)
329
318
            self._emit_progress_update()
330
 
            # revision data is in the local branch now.
331
319
            
332
320
            # upload revision data to the master.
333
321
            # this will propagate merged revisions too if needed.
335
323
                self.master_branch.repository.fetch(self.branch.repository,
336
324
                                                    revision_id=self.rev_id)
337
325
                # now the master has the revision data
338
 
                # 'commit' to the master first so a timeout here causes the local
339
 
                # branch to be out of date
 
326
                # 'commit' to the master first so a timeout here causes the
 
327
                # local branch to be out of date
340
328
                self.master_branch.set_last_revision_info(new_revno,
341
329
                                                          self.rev_id)
342
330
 
343
331
            # and now do the commit locally.
344
332
            self.branch.set_last_revision_info(new_revno, self.rev_id)
345
333
 
 
334
            # Make the working tree up to date with the branch
346
335
            rev_tree = self.builder.revision_tree()
347
336
            self.work_tree.set_parent_trees([(self.rev_id, rev_tree)])
348
 
            # now the work tree is up to date with the branch
349
 
            
350
337
            self.reporter.completed(new_revno, self.rev_id)
351
 
            # old style commit hooks - should be deprecated ? (obsoleted in
352
 
            # 0.15)
353
 
            if self.config.post_commit() is not None:
354
 
                hooks = self.config.post_commit().split(' ')
355
 
                # this would be nicer with twisted.python.reflect.namedAny
356
 
                for hook in hooks:
357
 
                    result = eval(hook + '(branch, rev_id)',
358
 
                                  {'branch':self.branch,
359
 
                                   'bzrlib':bzrlib,
360
 
                                   'rev_id':self.rev_id})
361
 
            # new style commit hooks:
362
 
            if not self.bound_branch:
363
 
                hook_master = self.branch
364
 
                hook_local = None
365
 
            else:
366
 
                hook_master = self.master_branch
367
 
                hook_local = self.branch
368
 
            # With bound branches, when the master is behind the local branch,
369
 
            # the 'old_revno' and old_revid values here are incorrect.
370
 
            # XXX: FIXME ^. RBC 20060206
371
 
            if self.parents:
372
 
                old_revid = self.parents[0]
373
 
            else:
374
 
                old_revid = bzrlib.revision.NULL_REVISION
375
 
            for hook in Branch.hooks['post_commit']:
376
 
                hook(hook_local, hook_master, old_revno, old_revid, new_revno,
377
 
                    self.rev_id)
 
338
 
 
339
            # Process the post commit hooks, if any
 
340
            self._process_hooks(old_revno, new_revno)
378
341
            self._emit_progress_update()
379
342
        finally:
380
343
            self._cleanup()
477
440
        self.master_branch.lock_write()
478
441
        self.master_locked = True
479
442
 
 
443
    def _check_out_of_date_tree(self):
 
444
        """Check that the working tree is up to date.
 
445
 
 
446
        :return: old_revision_number,new_revision_number tuple
 
447
        """
 
448
        try:
 
449
            first_tree_parent = self.work_tree.get_parent_ids()[0]
 
450
        except IndexError:
 
451
            # if there are no parents, treat our parent as 'None'
 
452
            # this is so that we still consider the master branch
 
453
            # - in a checkout scenario the tree may have no
 
454
            # parents but the branch may do.
 
455
            first_tree_parent = bzrlib.revision.NULL_REVISION
 
456
        old_revno, master_last = self.master_branch.last_revision_info()
 
457
        if master_last != first_tree_parent:
 
458
            if master_last != bzrlib.revision.NULL_REVISION:
 
459
                raise errors.OutOfDateTree(self.work_tree)
 
460
        if self.branch.repository.has_revision(first_tree_parent):
 
461
            new_revno = old_revno + 1
 
462
        else:
 
463
            # ghost parents never appear in revision history.
 
464
            new_revno = 1
 
465
        return old_revno,new_revno
 
466
 
 
467
    def _process_hooks(self, old_revno, new_revno):
 
468
        """Process any registered commit hooks."""
 
469
        # old style commit hooks - should be deprecated ? (obsoleted in
 
470
        # 0.15)
 
471
        if self.config.post_commit() is not None:
 
472
            hooks = self.config.post_commit().split(' ')
 
473
            # this would be nicer with twisted.python.reflect.namedAny
 
474
            for hook in hooks:
 
475
                result = eval(hook + '(branch, rev_id)',
 
476
                              {'branch':self.branch,
 
477
                               'bzrlib':bzrlib,
 
478
                               'rev_id':self.rev_id})
 
479
        # new style commit hooks:
 
480
        if not self.bound_branch:
 
481
            hook_master = self.branch
 
482
            hook_local = None
 
483
        else:
 
484
            hook_master = self.master_branch
 
485
            hook_local = self.branch
 
486
        # With bound branches, when the master is behind the local branch,
 
487
        # the 'old_revno' and old_revid values here are incorrect.
 
488
        # XXX: FIXME ^. RBC 20060206
 
489
        if self.parents:
 
490
            old_revid = self.parents[0]
 
491
        else:
 
492
            old_revid = bzrlib.revision.NULL_REVISION
 
493
        for hook in Branch.hooks['post_commit']:
 
494
            hook(hook_local, hook_master, old_revno, old_revid, new_revno,
 
495
                self.rev_id)
 
496
 
480
497
    def _cleanup(self):
481
498
        """Cleanup any open locks, progress bars etc."""
482
499
        cleanups = [self._cleanup_bound_branch,