1844
1877
self.pb.update(message, self.count, self.total)
1880
class CommitBuilder(object):
1881
"""Provides an interface to build up a commit.
1883
This allows describing a tree to be committed without needing to
1884
know the internals of the format of the repository.
1886
def __init__(self, repository, parents, config, timestamp=None,
1887
timezone=None, committer=None, revprops=None,
1889
"""Initiate a CommitBuilder.
1891
:param repository: Repository to commit to.
1892
:param parents: Revision ids of the parents of the new revision.
1893
:param config: Configuration to use.
1894
:param timestamp: Optional timestamp recorded for commit.
1895
:param timezone: Optional timezone for timestamp.
1896
:param committer: Optional committer to set for commit.
1897
:param revprops: Optional dictionary of revision properties.
1898
:param revision_id: Optional revision id.
1900
self._config = config
1902
if committer is None:
1903
self._committer = self._config.username()
1905
assert isinstance(committer, basestring), type(committer)
1906
self._committer = committer
1908
self.new_inventory = Inventory()
1909
self._new_revision_id = revision_id
1910
self.parents = parents
1911
self.repository = repository
1914
if revprops is not None:
1915
self._revprops.update(revprops)
1917
if timestamp is None:
1918
self._timestamp = time.time()
1920
self._timestamp = long(timestamp)
1922
if timezone is None:
1923
self._timezone = local_time_offset()
1925
self._timezone = int(timezone)
1927
self._generate_revision_if_needed()
1929
def commit(self, message):
1930
"""Make the actual commit.
1932
:return: The revision id of the recorded revision.
1934
rev = Revision(timestamp=self._timestamp,
1935
timezone=self._timezone,
1936
committer=self._committer,
1938
inventory_sha1=self.inv_sha1,
1939
revision_id=self._new_revision_id,
1940
properties=self._revprops)
1941
rev.parent_ids = self.parents
1942
self.repository.add_revision(self._new_revision_id, rev,
1943
self.new_inventory, self._config)
1944
return self._new_revision_id
1946
def finish_inventory(self):
1947
"""Tell the builder that the inventory is finished."""
1948
self.new_inventory.revision = self._new_revision_id
1949
self.inv_sha1 = self.repository.add_inventory(
1950
self._new_revision_id,
1955
def _gen_revision_id(self):
1956
"""Return new revision-id."""
1957
s = '%s-%s-' % (self._config.user_email(),
1958
compact_date(self._timestamp))
1959
s += hexlify(rand_bytes(8))
1962
def _generate_revision_if_needed(self):
1963
"""Create a revision id if None was supplied.
1965
If the repository can not support user-specified revision ids
1966
they should override this function and raise UnsupportedOperation
1967
if _new_revision_id is not None.
1969
:raises: UnsupportedOperation
1971
if self._new_revision_id is None:
1972
self._new_revision_id = self._gen_revision_id()
1974
def record_entry_contents(self, ie, parent_invs, path, tree):
1975
"""Record the content of ie from tree into the commit if needed.
1977
:param ie: An inventory entry present in the commit.
1978
:param parent_invs: The inventories of the parent revisions of the
1980
:param path: The path the entry is at in the tree.
1981
:param tree: The tree which contains this entry and should be used to
1984
self.new_inventory.add(ie)
1986
# ie.revision is always None if the InventoryEntry is considered
1987
# for committing. ie.snapshot will record the correct revision
1988
# which may be the sole parent if it is untouched.
1989
if ie.revision is not None:
1991
previous_entries = ie.find_previous_heads(
1993
self.repository.weave_store,
1994
self.repository.get_transaction())
1995
# we are creating a new revision for ie in the history store
1997
ie.snapshot(self._new_revision_id, path, previous_entries, tree, self)
1999
def modified_directory(self, file_id, file_parents):
2000
"""Record the presence of a symbolic link.
2002
:param file_id: The file_id of the link to record.
2003
:param file_parents: The per-file parent revision ids.
2005
self._add_text_to_weave(file_id, [], file_parents.keys())
2007
def modified_file_text(self, file_id, file_parents,
2008
get_content_byte_lines, text_sha1=None,
2010
"""Record the text of file file_id
2012
:param file_id: The file_id of the file to record the text of.
2013
:param file_parents: The per-file parent revision ids.
2014
:param get_content_byte_lines: A callable which will return the byte
2016
:param text_sha1: Optional SHA1 of the file contents.
2017
:param text_size: Optional size of the file contents.
2019
mutter('storing text of file {%s} in revision {%s} into %r',
2020
file_id, self._new_revision_id, self.repository.weave_store)
2021
# special case to avoid diffing on renames or
2023
if (len(file_parents) == 1
2024
and text_sha1 == file_parents.values()[0].text_sha1
2025
and text_size == file_parents.values()[0].text_size):
2026
previous_ie = file_parents.values()[0]
2027
versionedfile = self.repository.weave_store.get_weave(file_id,
2028
self.repository.get_transaction())
2029
versionedfile.clone_text(self._new_revision_id,
2030
previous_ie.revision, file_parents.keys())
2031
return text_sha1, text_size
2033
new_lines = get_content_byte_lines()
2034
# TODO: Rather than invoking sha_strings here, _add_text_to_weave
2035
# should return the SHA1 and size
2036
self._add_text_to_weave(file_id, new_lines, file_parents.keys())
2037
return bzrlib.osutils.sha_strings(new_lines), \
2038
sum(map(len, new_lines))
2040
def modified_link(self, file_id, file_parents, link_target):
2041
"""Record the presence of a symbolic link.
2043
:param file_id: The file_id of the link to record.
2044
:param file_parents: The per-file parent revision ids.
2045
:param link_target: Target location of this link.
2047
self._add_text_to_weave(file_id, [], file_parents.keys())
2049
def _add_text_to_weave(self, file_id, new_lines, parents):
2050
versionedfile = self.repository.weave_store.get_weave_or_empty(
2051
file_id, self.repository.get_transaction())
2052
versionedfile.add_lines(self._new_revision_id, parents, new_lines)
2053
versionedfile.clear_cache()
1847
2056
# Copied from xml.sax.saxutils
1848
2057
def _unescape_xml(data):
1849
2058
"""Unescape &, <, and > in a string of data.