]> git.donarmstrong.com Git - lilypond.git/blob - buildscripts/git-update-changelog.py
git foo
[lilypond.git] / buildscripts / git-update-changelog.py
1 #!/usr/bin/python
2
3 import sys
4 import time
5 import os
6 import re
7 import optparse
8
9 def read_pipe (x):
10     print 'pipe', x
11     return os.popen (x).read ()
12 def system (x):
13     print x
14     return os.system (x)
15     
16 class PatchFailed(Exception):
17     pass
18
19 class Commit:
20     def __init__ (self, dict):
21         for v in ('message',
22                   'date',
23                   'author',
24                   'committish'):
25             self.__dict__[v] = dict[v]
26         
27         self.date = ' '.join  (self.date.split (' ')[:-1])
28         self.date = time.strptime (self.date, '%a %b %d %H:%M:%S %Y')
29         
30         m = re.search ('(.*)<(.*)>', self.author)
31         self.email = m.group (2).strip ()
32         self.name = m.group (1).strip ()
33         self.diff = read_pipe ('git show %s' % self.committish)
34         
35     def touched_files (self):
36         files = []
37         def note_file (x):
38             files.append (x.group (1))
39             return ''
40
41         re.sub ('\n--- a/([^\n]+)\n',
42                 note_file, self.diff)
43         re.sub('\n--- /dev/null\n\\+\\+\\+ b/([^\n]+)',
44                note_file, self.diff)
45
46         return files
47
48     def apply (self, add_del_files):
49         def note_add_file (x):
50             add_del_files.append (('add', x.group (1)))
51             return ''
52         
53         def note_del_file (x):
54             add_del_files.append (('del', x.group (1)))
55             return ''
56         
57         re.sub('\n--- /dev/null\n\\+\\+\\+ b/([^\n]+)',
58                note_add_file, self.diff)
59         
60         re.sub('\n--- a/([^\n]+)\n\\+\\+\\+ /dev/null',
61                note_del_file, self.diff)
62
63         p = os.popen ('patch -f -p1 ', 'w')
64         p.write (self.diff)
65
66         if p.close ():
67             raise PatchFailed, self.committish
68         
69     
70 def parse_commit_log (log):
71     committish = re.search ('^([^\n]+)', log).group (1)
72     author = re.search ('\nAuthor:\s+([^\n]+)', log).group (1)
73     date_match = re.search ('\nDate:\s+([^\n]+)', log)
74     date = date_match.group (1)
75     log = log[date_match.end (1):]
76
77     message = re.sub ("\n *", '', log)
78     message = message.strip ()
79
80     c = Commit (locals ())
81     return c
82
83 def parse_add_changes (from_commit):
84     
85     log = read_pipe ('git log %(from_commit)s..' % locals ())
86
87     log = log[len ('commit '):]
88     log = log.strip ()
89
90     if not log:
91         return []
92         
93     commits = map (parse_commit_log, re.split ('\ncommit ', log))
94     commits.reverse ()
95     
96     return commits
97
98
99 def header (commit):
100     return '%d-%02d-%02d  %s  <%s>\n' % (commit.date[:3] + (commit.name, commit.email))
101
102 def changelog_body (commit):
103     s = ''
104     s += ''.join ('\n* %s: ' % f for f in commit.touched_files())
105     s += '\n' + commit.message
106     
107     s = s.replace ('\n', '\n\t')
108     s += '\n'
109     return s
110
111 def main ():
112     p = optparse.OptionParser (usage="usage git-update-changelog.py [options]",
113                                description="""
114 Apply GIT patches and update change log.
115
116 Run this file from the CVS directory, with --git-dir 
117 """)
118     p.add_option ("--start",
119                   action='store',
120                   default='',
121                   dest="start",
122                   help="start of log messages to merge.")
123     
124     p.add_option ("--git-dir",
125                   action='store',
126                   default='',
127                   dest="gitdir",
128                   help="the GIT directory to merge.")
129
130     (options, args) = p.parse_args ()
131     
132     log = open ('ChangeLog').read ()
133
134     if not options.start:
135         print 'Must set start committish.'  
136         sys.exit (1)
137
138     if options.gitdir:
139         os.environ['GIT_DIR'] = options.gitdir
140      
141     commits = parse_add_changes (options.start)
142     if not commits:
143         return
144     
145     new_log = ''
146     last_commit = None
147
148     first = header (commits[0]) + '\n'
149     if first == log[:len (first)]:
150         log = log[len (first):]
151
152     file_adddel = []
153     final_log = ''
154     
155     for c in commits:
156         print 'patch ', c.committish
157         try:
158             c.apply (file_adddel)
159         except PatchFailed:
160             break
161         
162         if c.touched_files () == ['ChangeLog']:
163             continue
164         
165         if (last_commit
166             and c.author != last_commit.author
167             and c.date[:3] != last_commit.date[:3]):
168
169             new_log += header (last_commit)
170
171         new_log = changelog_body (c)  + new_log
172         last_commit = c
173
174         final_log += self.message + '\n'
175         
176         
177     for (op, f) in file_adddel:
178         if op == 'del':
179             system ('cvs remove %(f)s' % locals ())
180         if op == 'add':
181             system ('cvs add %(f)s' % locals ())
182
183     new_log = header (last_commit) + new_log + '\n'
184
185     log = new_log + log
186
187     try:
188         os.unlink ('ChangeLog~')
189     except OSError:
190         pass
191     
192     os.rename ('ChangeLog', 'ChangeLog~')
193     open ('ChangeLog', 'w').write (log)
194
195     open ('.msg','w').write (final_log)
196     print 'cvs commit -F .msg '
197     
198 main ()
199     
200     
201