]> git.donarmstrong.com Git - lilypond.git/blob - buildscripts/git-update-changelog.py
* scm/define-grobs.scm:
[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
104     s = '\n'
105     s += ''.join ('\n* %s: ' % f for f in commit.touched_files())
106     s += '\n' + commit.message
107     
108     s = s.replace ('\n', '\n\t')
109     s += '\n'
110     return s
111
112 def main ():
113     p = optparse.OptionParser (usage="usage git-update-changelog.py [options]",
114                                description="""
115 Apply GIT patches and update change log.
116
117 Run this file from the CVS directory, with --git-dir 
118 """)
119     p.add_option ("--start",
120                   action='store',
121                   default='',
122                   dest="start",
123                   help="start of log messages to merge.")
124     
125     p.add_option ("--git-dir",
126                   action='store',
127                   default='',
128                   dest="gitdir",
129                   help="the GIT directory to merge.")
130
131     (options, args) = p.parse_args ()
132     
133     log = open ('ChangeLog').read ()
134
135     if not options.start:
136         print 'Must set start committish.'  
137         sys.exit (1)
138
139     if options.gitdir:
140         os.environ['GIT_DIR'] = options.gitdir
141      
142     commits = parse_add_changes (options.start)
143     if not commits:
144         return
145     
146     new_log = ''
147     last_commit = None
148
149     first = header (commits[0]) + '\n'
150     if first == log[:len (first)]:
151         log = log[len (first):]
152
153     file_adddel = []
154     for c in commits:
155         print 'patch ', c.committish
156         try:
157             c.apply (file_adddel)
158         except PatchFailed:
159             break
160         
161         if c.touched_files () == ['ChangeLog']:
162             continue
163         
164         if (last_commit
165             and c.author != last_commit.author
166             and c.date[:3] != last_commit.date[:3]):
167
168             new_log += header (last_commit)
169
170         new_log += changelog_body (c)  
171         last_commit = c
172         
173     for (op, f) in file_adddel:
174         if op == 'del':
175             system ('cvs remove %(f)s' % locals ())
176         if op == 'add':
177             system ('cvs add %(f)s' % locals ())
178
179     new_log = header (last_commit) + new_log + '\n'
180
181     log = new_log + log
182
183     try:
184         os.unlink ('ChangeLog~')
185     except OSError:
186         pass
187     
188     os.rename ('ChangeLog', 'ChangeLog~')
189     open ('ChangeLog', 'w').write (log)
190     
191 main ()
192     
193     
194