/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 breezy/commit.py

  • Committer: Jelmer Vernooij
  • Date: 2019-09-21 17:08:09 UTC
  • mfrom: (7389 work)
  • mto: This revision was merged to the branch mainline in revision 7390.
  • Revision ID: jelmer@jelmer.uk-20190921170809-ejewbeue585deajo
merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
57
57
    ui,
58
58
    )
59
59
from .branch import Branch
60
 
from .cleanup import OperationWithCleanups
 
60
from .cleanup import ExitStack
61
61
import breezy.config
62
62
from .errors import (BzrError,
63
63
                     ConflictsInTree,
285
285
        :param lossy: When committing to a foreign VCS, ignore any
286
286
            data that can not be natively represented.
287
287
        """
288
 
        operation = OperationWithCleanups(self._commit)
289
 
        self.revprops = revprops or {}
290
 
        # XXX: Can be set on __init__ or passed in - this is a bit ugly.
291
 
        self.config_stack = config or self.config_stack
292
 
        return operation.run(
293
 
            message=message,
294
 
            timestamp=timestamp,
295
 
            timezone=timezone,
296
 
            committer=committer,
297
 
            specific_files=specific_files,
298
 
            rev_id=rev_id,
299
 
            allow_pointless=allow_pointless,
300
 
            strict=strict,
301
 
            verbose=verbose,
302
 
            working_tree=working_tree,
303
 
            local=local,
304
 
            reporter=reporter,
305
 
            message_callback=message_callback,
306
 
            recursive=recursive,
307
 
            exclude=exclude,
308
 
            possible_master_transports=possible_master_transports,
309
 
            lossy=lossy)
310
 
 
311
 
    def _commit(self, operation, message, timestamp, timezone, committer,
312
 
                specific_files, rev_id, allow_pointless, strict, verbose,
313
 
                working_tree, local, reporter, message_callback, recursive,
314
 
                exclude, possible_master_transports, lossy):
315
 
        mutter('preparing to commit')
316
 
 
317
 
        if working_tree is None:
318
 
            raise BzrError("working_tree must be passed into commit().")
319
 
        else:
320
 
            self.work_tree = working_tree
321
 
            self.branch = self.work_tree.branch
322
 
            if getattr(self.work_tree, 'requires_rich_root', lambda: False)():
323
 
                if not self.branch.repository.supports_rich_root():
324
 
                    raise errors.RootNotRich()
325
 
        if message_callback is None:
326
 
            if message is not None:
327
 
                if isinstance(message, bytes):
328
 
                    message = message.decode(get_user_encoding())
329
 
 
330
 
                def message_callback(x):
331
 
                    return message
332
 
            else:
333
 
                raise BzrError("The message or message_callback keyword"
334
 
                               " parameter is required for commit().")
335
 
 
336
 
        self.bound_branch = None
337
 
        self.any_entries_deleted = False
338
 
        if exclude is not None:
339
 
            self.exclude = sorted(
340
 
                minimum_path_selection(exclude))
341
 
        else:
342
 
            self.exclude = []
343
 
        self.local = local
344
 
        self.master_branch = None
345
 
        self.recursive = recursive
346
 
        self.rev_id = None
347
 
        # self.specific_files is None to indicate no filter, or any iterable to
348
 
        # indicate a filter - [] means no files at all, as per iter_changes.
349
 
        if specific_files is not None:
350
 
            self.specific_files = sorted(
351
 
                minimum_path_selection(specific_files))
352
 
        else:
353
 
            self.specific_files = None
354
 
 
355
 
        self.allow_pointless = allow_pointless
356
 
        self.message_callback = message_callback
357
 
        self.timestamp = timestamp
358
 
        self.timezone = timezone
359
 
        self.committer = committer
360
 
        self.strict = strict
361
 
        self.verbose = verbose
362
 
 
363
 
        self.work_tree.lock_write()
364
 
        operation.add_cleanup(self.work_tree.unlock)
365
 
        self.parents = self.work_tree.get_parent_ids()
366
 
        self.pb = ui.ui_factory.nested_progress_bar()
367
 
        operation.add_cleanup(self.pb.finished)
368
 
        self.basis_revid = self.work_tree.last_revision()
369
 
        self.basis_tree = self.work_tree.basis_tree()
370
 
        self.basis_tree.lock_read()
371
 
        operation.add_cleanup(self.basis_tree.unlock)
372
 
        # Cannot commit with conflicts present.
373
 
        if len(self.work_tree.conflicts()) > 0:
374
 
            raise ConflictsInTree
375
 
 
376
 
        # Setup the bound branch variables as needed.
377
 
        self._check_bound_branch(operation, possible_master_transports)
378
 
 
379
 
        if self.config_stack is None:
380
 
            self.config_stack = self.work_tree.get_config_stack()
381
 
 
382
 
        # Check that the working tree is up to date
383
 
        old_revno, old_revid, new_revno = self._check_out_of_date_tree()
384
 
 
385
 
        # Complete configuration setup
386
 
        if reporter is not None:
387
 
            self.reporter = reporter
388
 
        elif self.reporter is None:
389
 
            self.reporter = self._select_reporter()
390
 
 
391
 
        # Setup the progress bar. As the number of files that need to be
392
 
        # committed in unknown, progress is reported as stages.
393
 
        # We keep track of entries separately though and include that
394
 
        # information in the progress bar during the relevant stages.
395
 
        self.pb_stage_name = ""
396
 
        self.pb_stage_count = 0
397
 
        self.pb_stage_total = 5
398
 
        if self.bound_branch:
399
 
            # 2 extra stages: "Uploading data to master branch" and "Merging
400
 
            # tags to master branch"
401
 
            self.pb_stage_total += 2
402
 
        self.pb.show_pct = False
403
 
        self.pb.show_spinner = False
404
 
        self.pb.show_eta = False
405
 
        self.pb.show_count = True
406
 
        self.pb.show_bar = True
407
 
 
408
 
        # After a merge, a selected file commit is not supported.
409
 
        # See 'bzr help merge' for an explanation as to why.
410
 
        if len(self.parents) > 1 and self.specific_files is not None:
411
 
            raise CannotCommitSelectedFileMerge(self.specific_files)
412
 
        # Excludes are a form of selected file commit.
413
 
        if len(self.parents) > 1 and self.exclude:
414
 
            raise CannotCommitSelectedFileMerge(self.exclude)
415
 
 
416
 
        # Collect the changes
417
 
        self._set_progress_stage("Collecting changes", counter=True)
418
 
        self._lossy = lossy
419
 
        self.builder = self.branch.get_commit_builder(
420
 
            self.parents, self.config_stack, timestamp, timezone, committer,
421
 
            self.revprops, rev_id, lossy=lossy)
422
 
 
423
 
        if self.builder.updates_branch and self.bound_branch:
424
 
            self.builder.abort()
425
 
            raise AssertionError(
426
 
                "bound branches not supported for commit builders "
427
 
                "that update the branch")
428
 
 
429
 
        try:
430
 
            # find the location being committed to
 
288
        with ExitStack() as stack:
 
289
            self.revprops = revprops or {}
 
290
            # XXX: Can be set on __init__ or passed in - this is a bit ugly.
 
291
            self.config_stack = config or self.config_stack
 
292
            mutter('preparing to commit')
 
293
 
 
294
            if working_tree is None:
 
295
                raise BzrError("working_tree must be passed into commit().")
 
296
            else:
 
297
                self.work_tree = working_tree
 
298
                self.branch = self.work_tree.branch
 
299
                if getattr(self.work_tree, 'requires_rich_root', lambda: False)():
 
300
                    if not self.branch.repository.supports_rich_root():
 
301
                        raise errors.RootNotRich()
 
302
            if message_callback is None:
 
303
                if message is not None:
 
304
                    if isinstance(message, bytes):
 
305
                        message = message.decode(get_user_encoding())
 
306
 
 
307
                    def message_callback(x):
 
308
                        return message
 
309
                else:
 
310
                    raise BzrError("The message or message_callback keyword"
 
311
                                   " parameter is required for commit().")
 
312
 
 
313
            self.bound_branch = None
 
314
            self.any_entries_deleted = False
 
315
            if exclude is not None:
 
316
                self.exclude = sorted(
 
317
                    minimum_path_selection(exclude))
 
318
            else:
 
319
                self.exclude = []
 
320
            self.local = local
 
321
            self.master_branch = None
 
322
            self.recursive = recursive
 
323
            self.rev_id = None
 
324
            # self.specific_files is None to indicate no filter, or any iterable to
 
325
            # indicate a filter - [] means no files at all, as per iter_changes.
 
326
            if specific_files is not None:
 
327
                self.specific_files = sorted(
 
328
                    minimum_path_selection(specific_files))
 
329
            else:
 
330
                self.specific_files = None
 
331
 
 
332
            self.allow_pointless = allow_pointless
 
333
            self.message_callback = message_callback
 
334
            self.timestamp = timestamp
 
335
            self.timezone = timezone
 
336
            self.committer = committer
 
337
            self.strict = strict
 
338
            self.verbose = verbose
 
339
 
 
340
            stack.enter_context(self.work_tree.lock_write())
 
341
            self.parents = self.work_tree.get_parent_ids()
 
342
            self.pb = ui.ui_factory.nested_progress_bar()
 
343
            stack.callback(self.pb.finished)
 
344
            self.basis_revid = self.work_tree.last_revision()
 
345
            self.basis_tree = self.work_tree.basis_tree()
 
346
            stack.enter_context(self.basis_tree.lock_read())
 
347
            # Cannot commit with conflicts present.
 
348
            if len(self.work_tree.conflicts()) > 0:
 
349
                raise ConflictsInTree
 
350
 
 
351
            # Setup the bound branch variables as needed.
 
352
            self._check_bound_branch(stack, possible_master_transports)
 
353
            if self.config_stack is None:
 
354
                self.config_stack = self.work_tree.get_config_stack()
 
355
 
 
356
            # Check that the working tree is up to date
 
357
            old_revno, old_revid, new_revno = self._check_out_of_date_tree()
 
358
 
 
359
            # Complete configuration setup
 
360
            if reporter is not None:
 
361
                self.reporter = reporter
 
362
            elif self.reporter is None:
 
363
                self.reporter = self._select_reporter()
 
364
 
 
365
            # Setup the progress bar. As the number of files that need to be
 
366
            # committed in unknown, progress is reported as stages.
 
367
            # We keep track of entries separately though and include that
 
368
            # information in the progress bar during the relevant stages.
 
369
            self.pb_stage_name = ""
 
370
            self.pb_stage_count = 0
 
371
            self.pb_stage_total = 5
431
372
            if self.bound_branch:
432
 
                master_location = self.master_branch.base
433
 
            else:
434
 
                master_location = self.branch.base
435
 
 
436
 
            # report the start of the commit
437
 
            self.reporter.started(new_revno, self.rev_id, master_location)
438
 
 
439
 
            self._update_builder_with_changes()
440
 
            self._check_pointless()
441
 
 
442
 
            # TODO: Now the new inventory is known, check for conflicts.
443
 
            # ADHB 2006-08-08: If this is done, populate_new_inv should not add
444
 
            # weave lines, because nothing should be recorded until it is known
445
 
            # that commit will succeed.
446
 
            self._set_progress_stage("Saving data locally")
447
 
            self.builder.finish_inventory()
448
 
 
449
 
            # Prompt the user for a commit message if none provided
450
 
            message = message_callback(self)
451
 
            self.message = message
452
 
 
453
 
            # Add revision data to the local branch
454
 
            self.rev_id = self.builder.commit(self.message)
455
 
 
456
 
        except Exception:
457
 
            mutter("aborting commit write group because of exception:")
458
 
            trace.log_exception_quietly()
459
 
            self.builder.abort()
460
 
            raise
461
 
 
462
 
        self._update_branches(old_revno, old_revid, new_revno)
463
 
 
464
 
        # Make the working tree be up to date with the branch. This
465
 
        # includes automatic changes scheduled to be made to the tree, such
466
 
        # as updating its basis and unversioning paths that were missing.
467
 
        self.work_tree.unversion(self.deleted_paths)
468
 
        self._set_progress_stage("Updating the working tree")
469
 
        self.work_tree.update_basis_by_delta(self.rev_id,
470
 
                                             self.builder.get_basis_delta())
471
 
        self.reporter.completed(new_revno, self.rev_id)
472
 
        self._process_post_hooks(old_revno, new_revno)
473
 
        return self.rev_id
 
373
                # 2 extra stages: "Uploading data to master branch" and "Merging
 
374
                # tags to master branch"
 
375
                self.pb_stage_total += 2
 
376
            self.pb.show_pct = False
 
377
            self.pb.show_spinner = False
 
378
            self.pb.show_eta = False
 
379
            self.pb.show_count = True
 
380
            self.pb.show_bar = True
 
381
 
 
382
            # After a merge, a selected file commit is not supported.
 
383
            # See 'bzr help merge' for an explanation as to why.
 
384
            if len(self.parents) > 1 and self.specific_files is not None:
 
385
                raise CannotCommitSelectedFileMerge(self.specific_files)
 
386
            # Excludes are a form of selected file commit.
 
387
            if len(self.parents) > 1 and self.exclude:
 
388
                raise CannotCommitSelectedFileMerge(self.exclude)
 
389
 
 
390
            # Collect the changes
 
391
            self._set_progress_stage("Collecting changes", counter=True)
 
392
            self._lossy = lossy
 
393
            self.builder = self.branch.get_commit_builder(
 
394
                self.parents, self.config_stack, timestamp, timezone, committer,
 
395
                self.revprops, rev_id, lossy=lossy)
 
396
 
 
397
            if self.builder.updates_branch and self.bound_branch:
 
398
                self.builder.abort()
 
399
                raise AssertionError(
 
400
                    "bound branches not supported for commit builders "
 
401
                    "that update the branch")
 
402
 
 
403
            try:
 
404
                # find the location being committed to
 
405
                if self.bound_branch:
 
406
                    master_location = self.master_branch.base
 
407
                else:
 
408
                    master_location = self.branch.base
 
409
 
 
410
                # report the start of the commit
 
411
                self.reporter.started(new_revno, self.rev_id, master_location)
 
412
 
 
413
                self._update_builder_with_changes()
 
414
                self._check_pointless()
 
415
 
 
416
                # TODO: Now the new inventory is known, check for conflicts.
 
417
                # ADHB 2006-08-08: If this is done, populate_new_inv should not add
 
418
                # weave lines, because nothing should be recorded until it is known
 
419
                # that commit will succeed.
 
420
                self._set_progress_stage("Saving data locally")
 
421
                self.builder.finish_inventory()
 
422
 
 
423
                # Prompt the user for a commit message if none provided
 
424
                message = message_callback(self)
 
425
                self.message = message
 
426
 
 
427
                # Add revision data to the local branch
 
428
                self.rev_id = self.builder.commit(self.message)
 
429
 
 
430
            except Exception:
 
431
                mutter("aborting commit write group because of exception:")
 
432
                trace.log_exception_quietly()
 
433
                self.builder.abort()
 
434
                raise
 
435
 
 
436
            self._update_branches(old_revno, old_revid, new_revno)
 
437
 
 
438
            # Make the working tree be up to date with the branch. This
 
439
            # includes automatic changes scheduled to be made to the tree, such
 
440
            # as updating its basis and unversioning paths that were missing.
 
441
            self.work_tree.unversion(self.deleted_paths)
 
442
            self._set_progress_stage("Updating the working tree")
 
443
            self.work_tree.update_basis_by_delta(self.rev_id,
 
444
                                                 self.builder.get_basis_delta())
 
445
            self.reporter.completed(new_revno, self.rev_id)
 
446
            self._process_post_hooks(old_revno, new_revno)
 
447
            return self.rev_id
474
448
 
475
449
    def _update_branches(self, old_revno, old_revid, new_revno):
476
450
        """Update the master and local branch to the new revision.
537
511
            return
538
512
        raise PointlessCommit()
539
513
 
540
 
    def _check_bound_branch(self, operation, possible_master_transports=None):
 
514
    def _check_bound_branch(self, stack, possible_master_transports=None):
541
515
        """Check to see if the local branch is bound.
542
516
 
543
517
        If it is bound, then most of the commit will actually be
577
551
        # Now things are ready to change the master branch
578
552
        # so grab the lock
579
553
        self.bound_branch = self.branch
580
 
        self.master_branch.lock_write()
581
 
        operation.add_cleanup(self.master_branch.unlock)
 
554
        stack.enter_context(self.master_branch.lock_write())
582
555
 
583
556
    def _check_out_of_date_tree(self):
584
557
        """Check that the working tree is up to date.