59
51
If null (default), a time/random revision id is generated.
64
from bzrlib.osutils import local_time_offset, username
65
from bzrlib.branch import gen_file_id
66
from bzrlib.errors import BzrError, PointlessCommit
67
from bzrlib.revision import Revision, RevisionReference
68
from bzrlib.trace import mutter, note
69
from bzrlib.xml import pack_xml
74
# First walk over the working inventory; and both update that
75
# and also build a new revision inventory. The revision
76
# inventory needs to hold the text-id, sha1 and size of the
77
# actual file versions committed in the revision. (These are
78
# not present in the working inventory.) We also need to
79
# detect missing/deleted files, and remove them from the
82
work_tree = branch.working_tree()
83
work_inv = work_tree.inventory
84
basis = branch.basis_tree()
85
basis_inv = basis.inventory
88
note('looking for changes...')
90
pending_merges = branch.pending_merges()
92
missing_ids, new_inv, any_changes = \
93
_gather_commit(branch,
100
if not (any_changes or allow_pointless or pending_merges):
101
raise PointlessCommit()
103
for file_id in missing_ids:
104
# Any files that have been deleted are now removed from the
105
# working inventory. Files that were not selected for commit
106
# are left as they were in the working inventory and ommitted
107
# from the revision inventory.
109
# have to do this later so we don't mess up the iterator.
110
# since parents may be removed before their children we
113
# FIXME: There's probably a better way to do this; perhaps
114
# the workingtree should know how to filter itbranch.
115
if work_inv.has_id(file_id):
116
del work_inv[file_id]
120
rev_id = _gen_revision_id(time.time())
123
inv_tmp = tempfile.TemporaryFile()
124
pack_xml(new_inv, inv_tmp)
126
branch.inventory_store.add(inv_tmp, inv_id)
127
mutter('new inventory_id is {%s}' % inv_id)
129
# We could also just sha hash the inv_tmp file
130
# however, in the case that branch.inventory_store.add()
131
# ever actually does anything special
132
inv_sha1 = branch.get_inventory_sha1(inv_id)
134
branch._write_inventory(work_inv)
136
if timestamp == None:
137
timestamp = time.time()
139
if committer == None:
140
committer = username()
143
timezone = local_time_offset()
145
mutter("building commit log message")
146
rev = Revision(timestamp=timestamp,
151
inventory_sha1=inv_sha1,
155
precursor_id = branch.last_patch()
157
precursor_sha1 = branch.get_revision_sha1(precursor_id)
158
rev.parents.append(RevisionReference(precursor_id, precursor_sha1))
159
for merge_rev in pending_merges:
160
rev.parents.append(RevisionReference(merge_rev))
162
rev_tmp = tempfile.TemporaryFile()
163
pack_xml(rev, rev_tmp)
165
branch.revision_store.add(rev_tmp, rev_id)
166
mutter("new revision_id is {%s}" % rev_id)
168
## XXX: Everything up to here can simply be orphaned if we abort
169
## the commit; it will leave junk files behind but that doesn't
172
## TODO: Read back the just-generated changeset, and make sure it
173
## applies and recreates the right state.
175
## TODO: Also calculate and store the inventory SHA1
176
mutter("committing patch r%d" % (branch.revno() + 1))
178
branch.append_revision(rev_id)
180
branch.set_pending_merges([])
183
note("commited r%d" % branch.revno())
189
def _gen_revision_id(when):
190
"""Return new revision-id."""
191
from binascii import hexlify
192
from osutils import rand_bytes, compact_date, user_email
194
s = '%s-%s-' % (user_email(), compact_date(when))
195
s += hexlify(rand_bytes(8))
199
def _gather_commit(branch, work_tree, work_inv, basis_inv, specific_files,
201
"""Build inventory preparatory to commit.
203
Returns missing_ids, new_inv, any_changes.
205
This adds any changed files into the text store, and sets their
206
test-id, sha and size in the returned inventory appropriately.
209
Modified to hold a list of files that have been deleted from
210
the working directory; these should be removed from the
213
from bzrlib.inventory import Inventory
214
from bzrlib.osutils import isdir, isfile, sha_string, quotefn, \
54
import os, time, tempfile
56
from inventory import Inventory
57
from osutils import isdir, isfile, sha_string, quotefn, \
215
58
local_time_offset, username, kind_marker, is_inside_any
217
from bzrlib.branch import gen_file_id
218
from bzrlib.errors import BzrError
219
from bzrlib.revision import Revision
220
from bzrlib.trace import mutter, note
223
inv = Inventory(work_inv.root.file_id)
60
from branch import gen_file_id
61
from errors import BzrError
62
from revision import Revision
63
from trace import mutter, note
65
branch._need_writelock()
67
# First walk over the working inventory; and both update that
68
# and also build a new revision inventory. The revision
69
# inventory needs to hold the text-id, sha1 and size of the
70
# actual file versions committed in the revision. (These are
71
# not present in the working inventory.) We also need to
72
# detect missing/deleted files, and remove them from the
75
work_tree = branch.working_tree()
76
work_inv = work_tree.inventory
78
basis = branch.basis_tree()
79
basis_inv = basis.inventory
83
note('looking for changes...')
226
85
for path, entry in work_inv.iter_entries():
227
86
## TODO: Check that the file kind has not changed from the previous
228
87
## revision of this file (if any).
230
91
p = branch.abspath(path)
231
92
file_id = entry.file_id
232
93
mutter('commit prep file %s, id %r ' % (p, file_id))
234
95
if specific_files and not is_inside_any(specific_files, path):
235
mutter(' skipping file excluded from commit')
236
96
if basis_inv.has_id(file_id):
237
97
# carry over with previous state
238
98
inv.add(basis_inv[file_id].copy())
284
139
content = file(p, 'rb').read()
286
# calculate the sha again, just in case the file contents
287
# changed since we updated the cache
288
141
entry.text_sha1 = sha_string(content)
289
142
entry.text_size = len(content)
291
144
entry.text_id = gen_file_id(entry.name)
292
145
branch.text_store.add(content, entry.text_id)
293
146
mutter(' stored with text_id {%s}' % entry.text_id)
296
marked = path + kind_marker(entry.kind)
298
print 'added', marked
300
elif old_ie == entry:
302
elif (old_ie.name == entry.name
303
and old_ie.parent_id == entry.parent_id):
304
print 'modified', marked
307
print 'renamed', marked
310
return missing_ids, inv, any_changes
149
print('added %s' % path)
150
elif (old_ie.name == entry.name
151
and old_ie.parent_id == entry.parent_id):
152
print('modified %s' % path)
154
print('renamed %s' % path)
157
for file_id in missing_ids:
158
# Any files that have been deleted are now removed from the
159
# working inventory. Files that were not selected for commit
160
# are left as they were in the working inventory and ommitted
161
# from the revision inventory.
163
# have to do this later so we don't mess up the iterator.
164
# since parents may be removed before their children we
167
# FIXME: There's probably a better way to do this; perhaps
168
# the workingtree should know how to filter itbranch.
169
if work_inv.has_id(file_id):
170
del work_inv[file_id]
174
rev_id = _gen_revision_id(time.time())
177
inv_tmp = tempfile.TemporaryFile()
178
inv.write_xml(inv_tmp)
180
branch.inventory_store.add(inv_tmp, inv_id)
181
mutter('new inventory_id is {%s}' % inv_id)
183
branch._write_inventory(work_inv)
185
if timestamp == None:
186
timestamp = time.time()
188
if committer == None:
189
committer = username()
192
timezone = local_time_offset()
194
mutter("building commit log message")
195
rev = Revision(timestamp=timestamp,
198
precursor = branch.last_patch(),
203
rev_tmp = tempfile.TemporaryFile()
204
rev.write_xml(rev_tmp)
206
branch.revision_store.add(rev_tmp, rev_id)
207
mutter("new revision_id is {%s}" % rev_id)
209
## XXX: Everything up to here can simply be orphaned if we abort
210
## the commit; it will leave junk files behind but that doesn't
213
## TODO: Read back the just-generated changeset, and make sure it
214
## applies and recreates the right state.
216
## TODO: Also calculate and store the inventory SHA1
217
mutter("committing patch r%d" % (branch.revno() + 1))
219
branch.append_revision(rev_id)
222
note("commited r%d" % branch.revno())
226
def _gen_revision_id(when):
227
"""Return new revision-id."""
228
from binascii import hexlify
229
from osutils import rand_bytes, compact_date, user_email
231
s = '%s-%s-' % (user_email(), compact_date(when))
232
s += hexlify(rand_bytes(8))