1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
1
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
71
from bzrlib.osutils import (kind_marker, isdir,isfile, is_inside_any,
72
from bzrlib.osutils import (get_user_encoding,
73
kind_marker, isdir,isfile, is_inside_any,
72
74
is_inside_or_parent_of_any,
73
75
minimum_path_selection,
74
76
quotefn, sha_file, split_lines,
77
79
from bzrlib.testament import Testament
78
80
from bzrlib.trace import mutter, note, warning, is_quiet
79
from bzrlib.xml5 import serializer_v5
80
from bzrlib.inventory import InventoryEntry, make_entry
81
from bzrlib.inventory import Inventory, InventoryEntry, make_entry
81
82
from bzrlib import symbol_versioning
82
83
from bzrlib.symbol_versioning import (deprecated_passed,
83
84
deprecated_function,
250
252
if message_callback is None:
251
253
if message is not None:
252
254
if isinstance(message, str):
253
message = message.decode(bzrlib.user_encoding)
255
message = message.decode(get_user_encoding())
254
256
message_callback = lambda x: message
256
258
raise BzrError("The message or message_callback keyword"
283
285
self.committer = committer
284
286
self.strict = strict
285
287
self.verbose = verbose
286
# accumulates an inventory delta to the basis entry, so we can make
287
# just the necessary updates to the workingtree's cached basis.
288
self._basis_delta = []
290
289
self.work_tree.lock_write()
291
290
self.pb = bzrlib.ui.ui_factory.nested_progress_bar()
298
297
raise ConflictsInTree
300
299
# Setup the bound branch variables as needed.
301
self._check_bound_branch()
300
self._check_bound_branch(possible_master_transports)
303
302
# Check that the working tree is up to date
304
303
old_revno, new_revno = self._check_out_of_date_tree()
353
352
entries_title="Directory")
354
353
self.builder = self.branch.get_commit_builder(self.parents,
355
354
self.config, timestamp, timezone, committer, revprops, rev_id)
357
self.builder.will_record_deletes()
358
358
# find the location being committed to
359
359
if self.bound_branch:
360
360
master_location = self.master_branch.base
383
383
# Add revision data to the local branch
384
384
self.rev_id = self.builder.commit(self.message)
387
mutter("aborting commit write group because of exception:")
388
trace.log_exception_quietly()
389
note("aborting commit write group: %r" % (e,))
387
390
self.builder.abort()
409
412
# Make the working tree up to date with the branch
410
413
self._set_progress_stage("Updating the working tree")
411
414
self.work_tree.update_basis_by_delta(self.rev_id,
415
self.builder.get_basis_delta())
413
416
self.reporter.completed(new_revno, self.rev_id)
414
417
self._process_post_hooks(old_revno, new_revno)
428
431
# A merge with no effect on files
429
432
if len(self.parents) > 1:
431
# TODO: we could simplify this by using self._basis_delta.
434
# TODO: we could simplify this by using self.builder.basis_delta.
433
436
# The initial commit adds a root directory, but this in itself is not
434
437
# a worthwhile commit.
445
448
raise PointlessCommit()
447
def _check_bound_branch(self):
450
def _check_bound_branch(self, possible_master_transports=None):
448
451
"""Check to see if the local branch is bound.
450
453
If it is bound, then most of the commit will actually be
455
458
raise errors.LocalRequiresBoundBranch()
457
460
if not self.local:
458
self.master_branch = self.branch.get_master_branch()
461
self.master_branch = self.branch.get_master_branch(
462
possible_master_transports)
460
464
if not self.master_branch:
461
465
# make this branch the reference branch for out of date checks.
690
694
# required after that changes.
691
695
if len(self.parents) > 1:
692
696
ie.revision = None
693
delta, version_recorded = self.builder.record_entry_contents(
697
_, version_recorded, _ = self.builder.record_entry_contents(
694
698
ie, self.parent_invs, path, self.basis_tree, None)
695
699
if version_recorded:
696
700
self.any_entries_changed = True
697
if delta: self._basis_delta.append(delta)
699
702
def _report_and_accumulate_deletes(self):
700
703
# XXX: Could the list of deleted paths and ids be instead taken from
701
704
# _populate_from_inventory?
702
deleted_ids = set(self.basis_inv._byid.keys()) - \
703
set(self.builder.new_inventory._byid.keys())
705
if (isinstance(self.basis_inv, Inventory)
706
and isinstance(self.builder.new_inventory, Inventory)):
707
# the older Inventory classes provide a _byid dict, and building a
708
# set from the keys of this dict is substantially faster than even
709
# getting a set of ids from the inventory
711
# <lifeless> set(dict) is roughly the same speed as
712
# set(iter(dict)) and both are significantly slower than
714
deleted_ids = set(self.basis_inv._byid.keys()) - \
715
set(self.builder.new_inventory._byid.keys())
717
deleted_ids = set(self.basis_inv) - set(self.builder.new_inventory)
705
719
self.any_entries_deleted = True
706
720
deleted = [(self.basis_tree.id2path(file_id), file_id)
709
723
# XXX: this is not quite directory-order sorting
710
724
for path, file_id in deleted:
711
self._basis_delta.append((path, None, file_id, None))
725
self.builder.record_delete(path, file_id)
712
726
self.reporter.deleted(path)
714
728
def _populate_from_inventory(self):
844
858
ie = existing_ie.copy()
845
859
ie.revision = None
846
delta, version_recorded = self.builder.record_entry_contents(ie,
847
self.parent_invs, path, self.work_tree, content_summary)
849
self._basis_delta.append(delta)
860
# For carried over entries we don't care about the fs hash - the repo
861
# isn't generating a sha, so we're not saving computation time.
862
_, version_recorded, fs_hash = self.builder.record_entry_contents(
863
ie, self.parent_invs, path, self.work_tree, content_summary)
850
864
if version_recorded:
851
865
self.any_entries_changed = True
852
866
if report_changes:
853
867
self._report_change(ie, path)
869
self.work_tree._observed_sha1(ie.file_id, path, fs_hash)
856
872
def _report_change(self, ie, path):