57
53
If null (default), a time/random revision id is generated.
56
import os, time, tempfile
62
from bzrlib.osutils import local_time_offset, username
63
from bzrlib.branch import gen_file_id
64
from bzrlib.errors import BzrError, PointlessCommit
65
from bzrlib.revision import Revision, RevisionReference
66
from bzrlib.trace import mutter, note
67
from bzrlib.xml import serializer_v4
58
from inventory import Inventory
59
from osutils import isdir, isfile, sha_string, quotefn, \
60
local_time_offset, username, kind_marker, is_inside_any
62
from branch import gen_file_id
63
from errors import BzrError
64
from revision import Revision
65
from trace import mutter, note
69
67
branch.lock_write()
80
78
work_tree = branch.working_tree()
81
79
work_inv = work_tree.inventory
82
81
basis = branch.basis_tree()
83
82
basis_inv = basis.inventory
86
# note('looking for changes...')
87
# print 'looking for changes...'
88
# disabled; should be done at a higher level
91
pending_merges = branch.pending_merges()
93
missing_ids, new_inv, any_changes = \
94
_gather_commit(branch,
101
if not (any_changes or allow_pointless or pending_merges):
102
raise PointlessCommit()
86
note('looking for changes...')
88
for path, entry in work_inv.iter_entries():
89
## TODO: Check that the file kind has not changed from the previous
90
## revision of this file (if any).
94
p = branch.abspath(path)
95
file_id = entry.file_id
96
mutter('commit prep file %s, id %r ' % (p, file_id))
98
if specific_files and not is_inside_any(specific_files, path):
99
if basis_inv.has_id(file_id):
100
# carry over with previous state
101
inv.add(basis_inv[file_id].copy())
103
# omit this from committed inventory
107
if not work_tree.has_id(file_id):
109
print('deleted %s%s' % (path, kind_marker(entry.kind)))
110
mutter(" file is missing, removing from inventory")
111
missing_ids.append(file_id)
116
if basis_inv.has_id(file_id):
117
old_kind = basis_inv[file_id].kind
118
if old_kind != entry.kind:
119
raise BzrError("entry %r changed kind from %r to %r"
120
% (file_id, old_kind, entry.kind))
122
if entry.kind == 'directory':
124
raise BzrError("%s is entered as directory but not a directory"
126
elif entry.kind == 'file':
128
raise BzrError("%s is entered as file but is not a file" % quotefn(p))
130
new_sha1 = work_tree.get_file_sha1(file_id)
132
old_ie = basis_inv.has_id(file_id) and basis_inv[file_id]
134
and old_ie.text_sha1 == new_sha1):
135
## assert content == basis.get_file(file_id).read()
136
entry.text_id = old_ie.text_id
137
entry.text_sha1 = new_sha1
138
entry.text_size = old_ie.text_size
139
mutter(' unchanged from previous text_id {%s}' %
142
content = file(p, 'rb').read()
144
# calculate the sha again, just in case the file contents
145
# changed since we updated the cache
146
entry.text_sha1 = sha_string(content)
147
entry.text_size = len(content)
149
entry.text_id = gen_file_id(entry.name)
150
branch.text_store.add(content, entry.text_id)
151
mutter(' stored with text_id {%s}' % entry.text_id)
154
print('added %s' % path)
155
elif (old_ie.name == entry.name
156
and old_ie.parent_id == entry.parent_id):
157
print('modified %s' % path)
159
print('renamed %s' % path)
104
162
for file_id in missing_ids:
105
163
# Any files that have been deleted are now removed from the
116
174
if work_inv.has_id(file_id):
117
175
del work_inv[file_id]
119
178
if rev_id is None:
120
rev_id = _gen_revision_id(branch, time.time())
179
rev_id = _gen_revision_id(time.time())
123
182
inv_tmp = tempfile.TemporaryFile()
125
serializer_v4.write_inventory(new_inv, inv_tmp)
183
inv.write_xml(inv_tmp)
127
185
branch.inventory_store.add(inv_tmp, inv_id)
128
186
mutter('new inventory_id is {%s}' % inv_id)
130
# We could also just sha hash the inv_tmp file
131
# however, in the case that branch.inventory_store.add()
132
# ever actually does anything special
133
inv_sha1 = branch.get_inventory_sha1(inv_id)
135
188
branch._write_inventory(work_inv)
137
190
if timestamp == None:
138
191
timestamp = time.time()
140
193
if committer == None:
141
committer = username(branch)
194
committer = username()
143
196
if timezone == None:
144
197
timezone = local_time_offset()
179
224
branch.append_revision(rev_id)
181
branch.set_pending_merges([])
184
# disabled; should go through logging
185
# note("commited r%d" % branch.revno())
186
# print ("commited r%d" % branch.revno())
227
note("commited r%d" % branch.revno())
193
def _gen_revision_id(branch, when):
233
def _gen_revision_id(when):
194
234
"""Return new revision-id."""
195
235
from binascii import hexlify
196
from bzrlib.osutils import rand_bytes, compact_date, user_email
236
from osutils import rand_bytes, compact_date, user_email
198
s = '%s-%s-' % (user_email(branch), compact_date(when))
238
s = '%s-%s-' % (user_email(), compact_date(when))
199
239
s += hexlify(rand_bytes(8))
203
def _gather_commit(branch, work_tree, work_inv, basis_inv, specific_files,
205
"""Build inventory preparatory to commit.
207
Returns missing_ids, new_inv, any_changes.
209
This adds any changed files into the text store, and sets their
210
test-id, sha and size in the returned inventory appropriately.
213
Modified to hold a list of files that have been deleted from
214
the working directory; these should be removed from the
217
from bzrlib.inventory import Inventory
218
from bzrlib.osutils import isdir, isfile, sha_string, quotefn, \
219
local_time_offset, username, kind_marker, is_inside_any
221
from bzrlib.branch import gen_file_id
222
from bzrlib.errors import BzrError
223
from bzrlib.revision import Revision
224
from bzrlib.trace import mutter, note
227
inv = Inventory(work_inv.root.file_id)
230
for path, entry in work_inv.iter_entries():
231
## TODO: Check that the file kind has not changed from the previous
232
## revision of this file (if any).
234
p = branch.abspath(path)
235
file_id = entry.file_id
236
mutter('commit prep file %s, id %r ' % (p, file_id))
238
if specific_files and not is_inside_any(specific_files, path):
239
mutter(' skipping file excluded from commit')
240
if basis_inv.has_id(file_id):
241
# carry over with previous state
242
inv.add(basis_inv[file_id].copy())
244
# omit this from committed inventory
248
if not work_tree.has_id(file_id):
250
print('deleted %s%s' % (path, kind_marker(entry.kind)))
252
mutter(" file is missing, removing from inventory")
253
missing_ids.append(file_id)
256
# this is present in the new inventory; may be new, modified or
258
old_ie = basis_inv.has_id(file_id) and basis_inv[file_id]
264
old_kind = old_ie.kind
265
if old_kind != entry.kind:
266
raise BzrError("entry %r changed kind from %r to %r"
267
% (file_id, old_kind, entry.kind))
269
if entry.kind == 'directory':
271
raise BzrError("%s is entered as directory but not a directory"
273
elif entry.kind == 'file':
275
raise BzrError("%s is entered as file but is not a file" % quotefn(p))
277
new_sha1 = work_tree.get_file_sha1(file_id)
280
and old_ie.text_sha1 == new_sha1):
281
## assert content == basis.get_file(file_id).read()
282
entry.text_id = old_ie.text_id
283
entry.text_sha1 = new_sha1
284
entry.text_size = old_ie.text_size
285
mutter(' unchanged from previous text_id {%s}' %
288
content = file(p, 'rb').read()
290
# calculate the sha again, just in case the file contents
291
# changed since we updated the cache
292
entry.text_sha1 = sha_string(content)
293
entry.text_size = len(content)
295
entry.text_id = gen_file_id(entry.name)
296
branch.text_store.add(content, entry.text_id)
297
mutter(' stored with text_id {%s}' % entry.text_id)
300
marked = path + kind_marker(entry.kind)
302
print 'added', marked
304
elif old_ie == entry:
306
elif (old_ie.name == entry.name
307
and old_ie.parent_id == entry.parent_id):
308
print 'modified', marked
311
print 'renamed', marked
313
elif old_ie != entry:
316
return missing_ids, inv, any_changes