30
30
# Lists of command names
31
COMMAND_NAMES = ['blob', 'checkpoint', 'commit', 'progress', 'reset', 'tag']
31
COMMAND_NAMES = ['blob', 'checkpoint', 'commit', 'feature', 'progress',
32
33
FILE_COMMAND_NAMES = ['filemodify', 'filedelete', 'filecopy', 'filerename',
35
36
# Bazaar file kinds
38
DIRECTORY_KIND = 'directory'
37
39
SYMLINK_KIND = 'symlink'
40
TREE_REFERENCE_KIND = 'tree-reference'
43
MULTIPLE_AUTHORS_FEATURE = "multiple-authors"
44
COMMIT_PROPERTIES_FEATURE = "commit-properties"
45
EMPTY_DIRS_FEATURE = "empty-directories"
47
MULTIPLE_AUTHORS_FEATURE,
48
COMMIT_PROPERTIES_FEATURE,
40
53
class ImportCommand(object):
45
58
# List of field names not to display
48
64
def dump_str(self, names=None, child_lists=None, verbose=False):
49
65
"""Dump fields as a string.
106
122
class CommitCommand(ImportCommand):
108
124
def __init__(self, ref, mark, author, committer, message, from_,
109
merges, file_iter, lineno=0):
125
merges, file_iter, lineno=0, more_authors=None, properties=None):
110
126
ImportCommand.__init__(self, 'commit')
116
132
self.from_ = from_
117
133
self.merges = merges
118
134
self.file_iter = file_iter
135
self.more_authors = more_authors
136
self.properties = properties
119
137
self.lineno = lineno
120
138
self._binary = ['file_iter']
121
139
# Provide a unique id in case the mark is missing
125
143
self.id = ':%s' % mark
127
145
def __repr__(self):
146
return self.to_string(include_file_contents=True)
149
return self.to_string(include_file_contents=False)
151
def to_string(self, use_features=True, include_file_contents=False):
128
152
if self.mark is None:
131
155
mark_line = "\nmark :%s" % self.mark
132
156
if self.author is None:
135
author_line = "\nauthor %s" % format_who_when(self.author)
159
author_section = "\nauthor %s" % format_who_when(self.author)
160
if use_features and self.more_authors:
161
for author in self.more_authors:
162
author_section += "\nauthor %s" % format_who_when(author)
136
163
committer = "committer %s" % format_who_when(self.committer)
137
164
if self.message is None:
149
176
merge_lines = "".join(["\nmerge %s" % (m,)
150
177
for m in self.merges])
178
if use_features and self.properties:
180
for name in sorted(self.properties):
181
value = self.properties[name]
182
property_lines.append("\n" + format_property(name, value))
183
properties_section = "".join(property_lines)
185
properties_section = ""
151
186
if self.file_iter is None:
152
187
filecommands = ""
154
filecommands = "".join(["\n%r" % (c,)
155
for c in iter(self.file_iter)])
156
return "commit %s%s%s\n%s%s%s%s%s" % (self.ref, mark_line, author_line,
157
committer, msg_section, from_line, merge_lines, filecommands)
189
if include_file_contents:
193
filecommands = "".join([format_str % (c,)
194
for c in self.iter_files()])
195
return "commit %s%s%s\n%s%s%s%s%s%s" % (self.ref, mark_line,
196
author_section, committer, msg_section, from_line, merge_lines,
197
properties_section, filecommands)
159
199
def dump_str(self, names=None, child_lists=None, verbose=False):
160
200
result = [ImportCommand.dump_str(self, names, verbose=verbose)]
161
for f in iter(self.file_iter):
201
for f in self.iter_files():
162
202
if child_lists is None:
168
208
result.append("\t%s" % f.dump_str(child_names, verbose=verbose))
169
209
return '\n'.join(result)
211
def iter_files(self):
212
"""Iterate over files."""
213
# file_iter may be a callable or an iterator
214
if callable(self.file_iter):
215
return self.file_iter()
217
return iter(self.file_iter)
220
class FeatureCommand(ImportCommand):
222
def __init__(self, feature_name, value=None, lineno=0):
223
ImportCommand.__init__(self, 'feature')
224
self.feature_name = feature_name
229
if self.value is None:
232
value_text = "=%s" % self.value
233
return "feature %s%s" % (self.feature_name, value_text)
172
236
class ProgressCommand(ImportCommand):
243
307
self._binary = ['data']
245
309
def __repr__(self):
246
if self.kind == 'symlink':
248
elif self.is_executable:
310
return self.to_string(include_file_contents=True)
313
return self.to_string(include_file_contents=False)
315
def to_string(self, include_file_contents=False):
316
if self.is_executable:
318
elif self.kind == 'file':
252
if self.dataref is None:
320
elif self.kind == 'directory':
322
elif self.kind == 'symlink':
324
elif self.kind == 'tree-reference':
327
raise AssertionError("unknown kind %s" % (self.kind,))
329
if self.kind == 'directory':
331
elif self.dataref is None:
253
332
dataref = "inline"
254
datastr = "\ndata %d\n%s" % (len(self.data), self.data)
333
if include_file_contents:
334
datastr = "\ndata %d\n%s" % (len(self.data), self.data)
256
336
dataref = "%s" % (self.dataref,)
258
337
path = format_path(self.path)
259
338
return "M %s %s %s%s" % (mode, dataref, path, datastr)
348
result = "%s%s<%s> %d %s" % (name, sep, fields[1], fields[2], offset_str)
349
return result.encode('utf8')
427
if isinstance(name, unicode):
428
name = name.encode('utf8')
430
if isinstance(email, unicode):
431
email = email.encode('utf8')
432
result = "%s%s<%s> %d %s" % (name, sep, email, fields[2], offset_str)
436
def format_property(name, value):
437
"""Format the name and value (both unicode) of a property as a string."""
438
utf8_name = name.encode('utf8')
439
if value is not None:
440
utf8_value = value.encode('utf8')
441
result = "property %s %d %s" % (utf8_name, len(utf8_value), utf8_value)
443
result = "property %s" % (utf8_name,)