53
53
If null (default), a time/random revision id is generated.
58
from bzrlib.osutils import local_time_offset, username
59
from bzrlib.branch import gen_file_id
60
from bzrlib.errors import BzrError
61
from bzrlib.revision import Revision, RevisionReference
62
from bzrlib.trace import mutter, note
63
from bzrlib.xml import pack_xml
68
# First walk over the working inventory; and both update that
69
# and also build a new revision inventory. The revision
70
# inventory needs to hold the text-id, sha1 and size of the
71
# actual file versions committed in the revision. (These are
72
# not present in the working inventory.) We also need to
73
# detect missing/deleted files, and remove them from the
76
work_tree = branch.working_tree()
77
work_inv = work_tree.inventory
78
basis = branch.basis_tree()
79
basis_inv = basis.inventory
82
note('looking for changes...')
84
missing_ids, new_inv = _gather_commit(branch,
91
for file_id in missing_ids:
92
# Any files that have been deleted are now removed from the
93
# working inventory. Files that were not selected for commit
94
# are left as they were in the working inventory and ommitted
95
# from the revision inventory.
97
# have to do this later so we don't mess up the iterator.
98
# since parents may be removed before their children we
101
# FIXME: There's probably a better way to do this; perhaps
102
# the workingtree should know how to filter itbranch.
103
if work_inv.has_id(file_id):
104
del work_inv[file_id]
108
rev_id = _gen_revision_id(time.time())
111
inv_tmp = tempfile.TemporaryFile()
112
pack_xml(new_inv, inv_tmp)
114
branch.inventory_store.add(inv_tmp, inv_id)
115
mutter('new inventory_id is {%s}' % inv_id)
117
# We could also just sha hash the inv_tmp file
118
# however, in the case that branch.inventory_store.add()
119
# ever actually does anything special
120
inv_sha1 = branch.get_inventory_sha1(inv_id)
122
branch._write_inventory(work_inv)
124
if timestamp == None:
125
timestamp = time.time()
127
if committer == None:
128
committer = username()
131
timezone = local_time_offset()
133
mutter("building commit log message")
134
rev = Revision(timestamp=timestamp,
139
inventory_sha1=inv_sha1,
142
precursor_id = branch.last_patch()
144
precursor_sha1 = branch.get_revision_sha1(precursor_id)
145
rev.parents = [RevisionReference(precursor_id, precursor_sha1)]
147
rev_tmp = tempfile.TemporaryFile()
148
pack_xml(rev, rev_tmp)
150
branch.revision_store.add(rev_tmp, rev_id)
151
mutter("new revision_id is {%s}" % rev_id)
153
## XXX: Everything up to here can simply be orphaned if we abort
154
## the commit; it will leave junk files behind but that doesn't
157
## TODO: Read back the just-generated changeset, and make sure it
158
## applies and recreates the right state.
160
## TODO: Also calculate and store the inventory SHA1
161
mutter("committing patch r%d" % (branch.revno() + 1))
163
branch.append_revision(rev_id)
166
note("commited r%d" % branch.revno())
172
def _gen_revision_id(when):
173
"""Return new revision-id."""
174
from binascii import hexlify
175
from osutils import rand_bytes, compact_date, user_email
177
s = '%s-%s-' % (user_email(), compact_date(when))
178
s += hexlify(rand_bytes(8))
182
def _gather_commit(branch, work_tree, work_inv, basis_inv, specific_files,
184
"""Build inventory preparatory to commit.
186
This adds any changed files into the text store, and sets their
187
test-id, sha and size in the returned inventory appropriately.
190
Modified to hold a list of files that have been deleted from
191
the working directory; these should be removed from the
194
from bzrlib.inventory import Inventory
56
import os, time, tempfile
58
from inventory import Inventory
195
59
from osutils import isdir, isfile, sha_string, quotefn, \
196
60
local_time_offset, username, kind_marker, is_inside_any
198
62
from branch import gen_file_id
199
63
from errors import BzrError
200
64
from revision import Revision
201
from bzrlib.trace import mutter, note
65
from trace import mutter, note
67
branch._need_writelock()
69
# First walk over the working inventory; and both update that
70
# and also build a new revision inventory. The revision
71
# inventory needs to hold the text-id, sha1 and size of the
72
# actual file versions committed in the revision. (These are
73
# not present in the working inventory.) We also need to
74
# detect missing/deleted files, and remove them from the
77
work_tree = branch.working_tree()
78
work_inv = work_tree.inventory
80
basis = branch.basis_tree()
81
basis_inv = basis.inventory
85
note('looking for changes...')
206
87
for path, entry in work_inv.iter_entries():
207
88
## TODO: Check that the file kind has not changed from the previous
208
89
## revision of this file (if any).
210
93
p = branch.abspath(path)
211
94
file_id = entry.file_id
212
95
mutter('commit prep file %s, id %r ' % (p, file_id))
269
148
entry.text_id = gen_file_id(entry.name)
270
149
branch.text_store.add(content, entry.text_id)
271
150
mutter(' stored with text_id {%s}' % entry.text_id)
274
marked = path + kind_marker(entry.kind)
276
print 'added', marked
277
elif old_ie == entry:
279
elif (old_ie.name == entry.name
280
and old_ie.parent_id == entry.parent_id):
281
print 'modified', marked
283
print 'renamed', marked
285
return missing_ids, inv
153
print('added %s' % path)
154
elif (old_ie.name == entry.name
155
and old_ie.parent_id == entry.parent_id):
156
print('modified %s' % path)
158
print('renamed %s' % path)
161
for file_id in missing_ids:
162
# Any files that have been deleted are now removed from the
163
# working inventory. Files that were not selected for commit
164
# are left as they were in the working inventory and ommitted
165
# from the revision inventory.
167
# have to do this later so we don't mess up the iterator.
168
# since parents may be removed before their children we
171
# FIXME: There's probably a better way to do this; perhaps
172
# the workingtree should know how to filter itbranch.
173
if work_inv.has_id(file_id):
174
del work_inv[file_id]
178
rev_id = _gen_revision_id(time.time())
181
inv_tmp = tempfile.TemporaryFile()
182
inv.write_xml(inv_tmp)
184
branch.inventory_store.add(inv_tmp, inv_id)
185
mutter('new inventory_id is {%s}' % inv_id)
187
branch._write_inventory(work_inv)
189
if timestamp == None:
190
timestamp = time.time()
192
if committer == None:
193
committer = username()
196
timezone = local_time_offset()
198
mutter("building commit log message")
199
rev = Revision(timestamp=timestamp,
202
precursor = branch.last_patch(),
207
rev_tmp = tempfile.TemporaryFile()
208
rev.write_xml(rev_tmp)
210
branch.revision_store.add(rev_tmp, rev_id)
211
mutter("new revision_id is {%s}" % rev_id)
213
## XXX: Everything up to here can simply be orphaned if we abort
214
## the commit; it will leave junk files behind but that doesn't
217
## TODO: Read back the just-generated changeset, and make sure it
218
## applies and recreates the right state.
220
## TODO: Also calculate and store the inventory SHA1
221
mutter("committing patch r%d" % (branch.revno() + 1))
223
branch.append_revision(rev_id)
226
note("commited r%d" % branch.revno())
230
def _gen_revision_id(when):
231
"""Return new revision-id."""
232
from binascii import hexlify
233
from osutils import rand_bytes, compact_date, user_email
235
s = '%s-%s-' % (user_email(), compact_date(when))
236
s += hexlify(rand_bytes(8))