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