5 from cola
.git
import git
6 from cola
.observable
import Observable
8 # put summary at the end b/c it can contain
9 # any number of funky characters, including the separator
10 logfmt
= 'format:%H%x01%P%x01%d%x01%an%x01%ad%x01%ae%x01%s'
14 class CommitFactory(object):
21 cls
.root_generation
= 0
24 def new(cls
, sha1
=None, log_entry
=None):
25 if not sha1
and log_entry
:
28 commit
= cls
.commits
[sha1
]
29 if log_entry
and not commit
.parsed
:
30 commit
.parse(log_entry
)
31 cls
.root_generation
= max(commit
.generation
,
34 commit
= Commit(sha1
=sha1
,
37 cls
.root_generation
+= 1
38 commit
.generation
= max(commit
.generation
,
40 cls
.commits
[sha1
] = commit
44 class DAG(Observable
):
45 ref_updated
= 'ref_updated'
46 count_updated
= 'count_updated'
48 def __init__(self
, ref
, count
):
49 Observable
.__init
__(self
)
54 def set_ref(self
, ref
):
55 changed
= ref
!= self
.ref
58 self
.notify_observers(self
.ref_updated
)
61 def set_count(self
, count
):
62 changed
= count
!= self
.count
65 self
.notify_observers(self
.count_updated
)
68 def set_arguments(self
, args
):
71 if self
.set_count(args
.count
):
72 self
.overrides
['count'] = args
.count
75 ref
= subprocess
.list2cmdline(map(core
.decode
, args
.args
))
77 self
.overrides
['ref'] = ref
79 def overridden(self
, opt
):
80 return opt
in self
.overrides
83 all_refs
= utils
.shell_split(self
.ref
)
85 all_refs
= all_refs
[all_refs
.index('--'):]
87 return [p
for p
in all_refs
if p
and core
.exists(p
)]
103 def __init__(self
, sha1
=None, log_entry
=None):
113 self
.generation
= CommitFactory
.root_generation
115 self
.parse(log_entry
)
117 def parse(self
, log_entry
, sep
=logsep
):
118 self
.sha1
= log_entry
[:40]
119 (parents
, tags
, author
, authdate
, email
, summary
) = \
120 log_entry
[41:].split(sep
, 6)
122 self
.summary
= summary
and summary
or ''
123 self
.author
= author
and author
or ''
124 self
.authdate
= authdate
or ''
125 self
.email
= email
and email
or ''
129 for parent_sha1
in parents
.split(' '):
130 parent
= CommitFactory
.new(sha1
=parent_sha1
)
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(', '):
140 if tag
.startswith('tag: '):
141 tag
= tag
[5:] # tag: refs/
142 elif tag
.startswith('refs/remotes/'):
143 tag
= tag
[13:] # refs/remotes/
144 elif tag
.startswith('refs/heads/'):
145 tag
= tag
[11:] # refs/heads/
146 if tag
.endswith('/HEAD'):
158 " sha1: " + self
.sha1
+ "\n"
159 " summary: " + self
.summary
+ "\n"
160 " author: " + self
.author
+ "\n"
161 " authdate: " + self
.authdate
+ "\n"
162 " parents: [" + ', '.join([p
.sha1
for p
in self
.parents
]) + "]\n"
163 " tags: [" + ', '.join(self
.tags
) + "]\n"
167 ''' Returns True if the node is a fork'''
168 return len(self
.children
) > 1
171 ''' Returns True if the node is a fork'''
172 return len(self
.parents
) > 1
175 class RepoReader(object):
177 def __init__(self
, dag
, git
=git
):
182 self
._cmd
= ['git', 'log',
187 """Indicates that all data has been read"""
189 """Index into the cached commits"""
191 """List of commits objects in topological order"""
193 cached
= property(lambda self
: self
._cached
)
194 """Return True when no commits remain to be read"""
198 return len(self
._topo
_list
)
201 CommitFactory
.reset()
218 return self
._topo
_list
[self
._idx
]
223 if self
._proc
is None:
224 ref_args
= utils
.shell_split(self
.dag
.ref
)
225 cmd
= self
._cmd
+ ['-%d' % self
.dag
.count
] + ref_args
226 self
._proc
= utils
.start_command(cmd
)
229 log_entry
= core
.readline(self
._proc
.stdout
).rstrip()
236 sha1
= log_entry
[:40]
238 return self
._objects
[sha1
]
240 c
= CommitFactory
.new(log_entry
=log_entry
)
241 self
._objects
[c
.sha1
] = c
242 self
._topo
_list
.append(c
)
245 def __getitem__(self
, sha1
):
246 return self
._objects
[sha1
]
249 return self
._objects
.items()