Polish notes output a bit
[trackgit.git] / notes.py
blob89f36a9632205d68458472405cb66747ed74ca86
1 import os
2 import sys
3 import time
4 import re
5 from collections import defaultdict
6 from sqlalchemy.orm import join
8 import db
9 from git import git
11 NOTES_INDEX = '.git/git-notes-index'
12 notes_env = {
13 'GIT_INDEX_FILE': NOTES_INDEX,
15 NOTES_REF = 'refs/heads/mailnotes'
17 _eol_space_re = re.compile('\s+$', re.MULTILINE)
18 def write_notes(commit_sha1, notes):
19 notes = _eol_space_re.sub('', notes)
20 notes = notes.strip('\n')
21 blob_sha1 = git('hash-object', '-w', '--stdin', input=notes)[0]
22 git('update-index', '--add', '--cacheinfo', '0644', blob_sha1, commit_sha1, env=notes_env)
24 def finalize_notes():
25 previous, ret = git('rev-parse', NOTES_REF)
26 if ret != 0:
27 args = []
28 previous_arg = []
29 else:
30 args = ['-p', previous.strip()]
31 previous_arg = [previous.strip()]
32 tree_sha1 = git('write-tree', env=notes_env)[0].strip()
33 head_sha1 = git('commit-tree', tree_sha1, *args,
34 input='Mass annotation by notes.py')[0].strip()
35 git('update-ref', '-m', 'Mass annotation by notes.py',
36 NOTES_REF, head_sha1, *previous_arg)
38 def split_and_tab(buf):
39 ret = []
40 for line in str(buf).splitlines():
41 ret.append('\t%s\n' % line)
42 return ret
44 def compute_notes(session, commit, mail):
45 notes = []
46 if mail.author:
47 notes.append('From: %s\n' % mail.author)
48 if mail.subject:
49 notes.append('Subject: %s\n' % mail.subject)
50 notes.append('Message-Id: <%s>\n' % mail.message_id)
51 notes.append('Posted-Date: %s\n'
52 % time.strftime("%c", time.localtime(mail.post_date)))
53 if mail.in_reply_to:
54 notes.append('In-Reply-To: %s\n' % mail.in_reply_to)
55 if mail.gmane_id:
56 notes.append('Archived-At: <http://permalink.gmane.org/gmane.comp.version-control.git/%d>' % mail.gmane_id)
57 if len(mail.patch)>0 and mail.patch[0].extra_notes:
58 notes.append('Extra-notes:\n')
59 notes.extend(split_and_tab(mail.patch[0].extra_notes))
60 return notes
62 _merge_re = re.compile("^([a-f0-9]{40}) Merge branch '([^']+)'")
63 def _redo_pu(session, notes):
64 pu_ref = git('rev-parse', 'origin/pu')[0].strip()
65 pu_topic = session.query(db.Topic).filter(db.Topic.name == 'pu').first()
66 if pu_topic:
67 notes[pu_ref].append('Pu-Overview:\n')
68 notes[pu_ref].extend(split_and_tab(pu_topic.cooking_notes))
69 notes[pu_ref].append('\n')
70 for line in git('log', '--first-parent', '--pretty=tformat:%H %s',
71 'origin/master..origin/pu', ret_pipe=True):
72 m = _merge_re.match(line)
73 if not m:
74 continue
75 sha1 = m.group(1)
76 branch = m.group(2)
77 t = session.query(db.Topic).filter(db.Topic.name == branch).first()
78 if t and t.cooking_notes:
79 notes[sha1].append('Pu-Topic:\n')
80 notes[sha1].extend(split_and_tab(t.cooking_notes))
81 notes[sha1].append('\n')
83 def _redo_patches(session, notes):
84 count = 0
85 for cmt, mail in (session.query(db.Commit, db.Mail)
86 .select_from(join(db.Mail, db.Commit,
87 db.Mail.patch_id==db.Commit.patch_id))
88 .filter(db.Commit.upstream==True)
89 .filter(db.Mail.has_patch==True)):
90 nts = compute_notes(session, cmt, mail)
91 if not nts:
92 continue
93 if notes[cmt.sha1]:
94 notes[cmt.sha1].append('\n')
95 notes[cmt.sha1].extend(nts)
96 sys.stdout.write('\r%6d' % count)
97 sys.stdout.flush()
98 count = count + 1
99 sys.stdout.write('\n')
101 def _redo_all():
102 session = db.Session()
103 count = 0
104 notes = defaultdict(list)
105 _redo_patches(session, notes)
106 _redo_pu(session, notes)
107 os.unlink(NOTES_INDEX)
108 count = 0
109 for cmt, nts in notes.iteritems():
110 sys.stdout.write('\r%6d' % count)
111 sys.stdout.flush()
112 write_notes(cmt, ''.join(nts))
113 count = count + 1
114 sys.stdout.write('\n')
115 finalize_notes()
117 if __name__ == '__main__':
118 if len(sys.argv) > 1:
119 session = db.Session()
120 cmt = session.query(db.Commit).filter(db.Commit.sha1==sys.argv[1]).one()
121 print compute_notes(session, cmt)
122 else:
123 _redo_all()