5 from ..models
import prefs
7 # put summary at the end b/c it can contain
8 # any number of funky characters, including the separator
9 logfmt
= r
'format:%H%x01%P%x01%d%x01%an%x01%ad%x01%ae%x01%s'
20 cls
.root_generation
= 0
23 def new(cls
, oid
=None, log_entry
=None):
24 if not oid
and log_entry
:
27 commit
= cls
.commits
[oid
]
28 if log_entry
and not commit
.parsed
:
29 commit
.parse(log_entry
)
30 cls
.root_generation
= max(commit
.generation
, cls
.root_generation
)
32 commit
= Commit(oid
=oid
, log_entry
=log_entry
)
34 cls
.root_generation
+= 1
35 commit
.generation
= max(commit
.generation
, cls
.root_generation
)
36 cls
.commits
[oid
] = commit
41 def __init__(self
, ref
, count
):
46 def set_ref(self
, ref
):
47 changed
= ref
!= self
.ref
52 def set_count(self
, count
):
53 changed
= count
!= self
.count
58 def set_arguments(self
, args
):
61 if self
.set_count(args
.count
):
62 self
.overrides
['count'] = args
.count
64 if hasattr(args
, 'args') and args
.args
:
65 ref
= core
.list2cmdline(args
.args
)
67 self
.overrides
['ref'] = ref
69 def overridden(self
, opt
):
70 return opt
in self
.overrides
73 all_refs
= utils
.shell_split(self
.ref
)
75 all_refs
= all_refs
[all_refs
.index('--') :]
77 return [p
for p
in all_refs
if p
and core
.exists(p
)]
99 def __init__(self
, oid
=None, log_entry
=None):
110 self
.generation
= CommitFactory
.root_generation
114 self
.parse(log_entry
)
116 def parse(self
, log_entry
, sep
=logsep
):
117 self
.oid
= log_entry
[:40]
118 after_oid
= log_entry
[41:]
119 details
= after_oid
.split(sep
, 5)
120 (parents
, tags
, author
, authdate
, email
, summary
) = details
122 self
.summary
= summary
if summary
else ''
123 self
.author
= author
if author
else ''
124 self
.authdate
= authdate
if authdate
else ''
125 self
.email
= email
if email
else ''
129 for parent_oid
in parents
.split(' '):
130 parent
= CommitFactory
.new(oid
=parent_oid
)
131 parent
.children
.append(self
)
132 if generation
is None:
133 generation
= parent
.generation
+ 1
134 self
.parents
.append(parent
)
135 generation
= max(parent
.generation
+ 1, generation
)
136 self
.generation
= generation
139 for tag
in tags
[2:-1].split(', '):
145 def add_label(self
, tag
):
146 """Add tag/branch labels from `git log --decorate ....`"""
148 if tag
.startswith('tag: '):
149 tag
= tag
[5:] # strip off "tag: " leaving refs/tags/
151 if tag
.startswith('refs/heads/'):
153 self
.branches
.append(branch
)
155 if tag
.startswith('refs/'):
156 # strip off refs/ leaving just tags/XXX remotes/XXX heads/XXX
159 if tag
.endswith('/HEAD'):
162 # Git 2.4 Release Notes (draft)
163 # =============================
165 # Backward compatibility warning(s)
166 # ---------------------------------
168 # This release has a few changes in the user-visible output from
169 # Porcelain commands. These are not meant to be parsed by scripts, but
170 # the users still may want to be aware of the changes:
172 # * Output from "git log --decorate" (and "%d" format specifier used in
173 # the userformat "--format=<string>" parameter "git log" family of
174 # command takes) used to list "HEAD" just like other tips of branch
175 # names, separated with a comma in between. E.g.
177 # $ git log --decorate -1 main
178 # commit bdb0f6788fa5e3cacc4315e9ff318a27b2676ff4 (HEAD, main)
181 # This release updates the output slightly when HEAD refers to the tip
182 # of a branch whose name is also shown in the output. The above is
185 # $ git log --decorate -1 main
186 # commit bdb0f6788fa5e3cacc4315e9ff318a27b2676ff4 (HEAD -> main)
189 # C.f. http://thread.gmane.org/gmane.linux.kernel/1931234
191 head_arrow
= 'HEAD -> '
192 if tag
.startswith(head_arrow
):
193 self
.tags
.append('HEAD')
194 self
.add_label(tag
[len(head_arrow
) :])
196 self
.tags
.append(tag
)
204 'summary': self
.summary
,
205 'author': self
.author
,
206 'authdate': self
.authdate
,
207 'parents': [p
.oid
for p
in self
.parents
],
212 return json
.dumps(self
.data(), sort_keys
=True, indent
=4, default
=list)
215 """Returns True if the node is a fork"""
216 return len(self
.children
) > 1
219 """Returns True if the node is a fork"""
220 return len(self
.parents
) > 1
224 def __init__(self
, context
, params
):
225 self
.context
= context
227 self
.git
= context
.git
234 'log.abbrevCommit=false',
236 'log.showSignature=false',
240 '--pretty=' + logfmt
,
243 """Indicates that all data has been read"""
245 """List of commits objects in topological order"""
247 cached
= property(lambda self
: self
._cached
)
248 """Return True when no commits remain to be read"""
251 return len(self
._topo
_list
)
254 CommitFactory
.reset()
261 """Generator function returns Commit objects found by the params"""
266 yield self
._topo
_list
[idx
]
273 ref_args
= utils
.shell_split(self
.params
.ref
)
276 + ['-%d' % self
.params
.count
]
277 + ['--date=%s' % prefs
.logdate(self
.context
)]
280 status
, out
, _
= core
.run_command(cmd
)
281 for log_entry
in reversed(out
.splitlines()):
286 yield self
._objects
[oid
]
288 commit
= CommitFactory
.new(log_entry
=log_entry
)
289 self
._objects
[commit
.oid
] = commit
290 self
._topo
_list
.append(commit
)
294 self
.returncode
= status
296 def __getitem__(self
, oid
):
297 return self
._objects
[oid
]
300 return list(self
._objects
.items())