]> git.donarmstrong.com Git - lilypond.git/blob - scripts/update-lily.py
e60de66dba0382d7cc9e8eb630f9d4e8ef2b7600
[lilypond.git] / scripts / update-lily.py
1 #!@PYTHON@
2 #
3 # update-lily.py -- lilypond autobuilder
4
5 # source file of the GNU LilyPond music typesetter
6 #
7 # download and rebuild latest lilypond or from specified url
8 #
9
10
11 '''
12 TODO:
13
14     * use urllib iso ftplib
15
16     * more flexible build/ftp/patches/releases paths
17
18     
19     show only: --command='echo "latest is: %n-%v"'
20 '''
21
22 import ftplib
23 import fnmatch
24 import getopt
25 import re
26 import operator
27 import os
28 import tempfile
29 import stat
30 import string
31 import sys
32 import __main__
33
34
35 url = 'file:/home/ftp/pub/gnu/LilyPond/development/lilypond-*.tar.gz'
36 url = 'ftp://appel.lilypond.org/pub/gnu/LilyPond/development/lilypond-*.tar.gz'
37 url = 'ftp://ftp.cs.uu.nl/pub/GNU/LilyPond/development/lilypond-*.tar.gz'
38
39 remove_previous_p = 0
40
41
42 sys.path.append ('@datadir@/python')
43 sys.path.append ('@datadir@/buildscripts/out')
44
45 try:
46         import gettext
47         gettext.bindtextdomain ('lilypond', '@localedir@')
48         gettext.textdomain ('lilypond')
49         _ = gettext.gettext
50 except:
51         def _ (s):
52                 return s
53
54 # Attempt to fix problems with limited stack size set by Python!
55 # Sets unlimited stack size. Note that the resource module only
56 # is available on UNIX.
57 try:
58        import resource
59        resource.setrlimit (resource.RLIMIT_STACK, (-1, -1))
60 except:
61        pass
62
63
64 program_name = 'build-lily'
65 package_name = 'lilypond'
66 help_summary = _ ("Fetch and rebuild from latest source package")
67
68 build_root = os.path.join (os.environ ['HOME'], 'usr', 'src')
69 release_dir = build_root + '/releases'
70 patch_dir = build_root + '/patches'
71 original_dir = os.getcwd ()
72 temp_dir = os.path.join (original_dir,  '%s.dir' % program_name)
73
74
75 option_definitions = [
76         ('DIR', 'b', 'build-root', _ ("unpack and build in DIR [%s]") % build_root),
77         ('COMMAND', 'c', 'command', _ ("execute COMMAND, subtitute:") \
78          + '\n                            ' + _ ("%b: build root") \
79          + '\n                            ' + _ ("%n: package name") \
80          + '\n                            ' + _ ("%r: release directory") \
81          + '\n                            ' + _ ("%t: tarball") \
82          + '\n                            ' + _ ("%v: package version") \
83          ),
84         ('', 'h', 'help', _ ("this help")),
85         ('', 'k', 'keep', _ ("keep all output, and name the directory %s") % temp_dir),
86         ('EMAIL', 'n', 'notify', _ ("upon failure notify EMAIL[,EMAIL]")),
87         ('', 'r', 'remove-previous', _ ("remove previous build")),
88         ('', 'V', 'verbose', _ ("verbose")),
89         ('', 'v', 'version', _ ("print version number")),
90         ('URL', 'u', 'url', _ ("fetch and build URL [%s]") % url),
91         ('', 'w', 'warranty', _ ("show warranty and copyright")),
92         ]
93
94 from lilylib import *
95
96
97 notify = 0
98
99 build_command = '''
100 set -x
101 cd %b &&
102 [ -d %n-%v ] && exit 1 || true;
103 mkdir -p %n-%v
104 (
105 tar xzf %r/%t &&
106 rm -f building &&
107 ln -s %n-%v building &&
108 cd %n-%v &&
109 ./configure --prefix=$HOME/usr && make all web
110 ) >> %n-%v/log.txt 2>&1 &&
111 rm -f %n &&
112 ln -s %n-%v %n
113 '''
114
115
116 def list_file (user, passwd, host, dir, file):
117         match = []
118         for i in os.listdir (dir):
119                 if fnmatch.fnmatch (i, file):
120                         match.append (i)
121         return match
122
123 list_ = list_file
124
125 def list_ftp (user, passwd, host, dir, file):
126         if user == 'None':
127                 user = 'anonymous'
128         if passwd == 'None':
129                 passwd = program_name
130
131         ftp = ftplib.FTP (host)
132         ftp.login (user, passwd)
133         ftp.set_pasv (1)
134         ftp.cwd (dir)
135         list = ftp.nlst (file)
136         try:
137                 ftp.quit ()
138         except:
139                 ftp.close ()
140         return list
141         
142 def split_url (url):
143         m = re.match ('([^:/]*)(:)?(/*([^:]*):)?(/*([^@]*)@)?(//([^/]*))?(.*)/(.*)',
144                       url)
145         if not m:
146                 error ("can't parse url: %s " % url)
147         return (m.group (1), m.group (4), m.group (6), m.group (8),
148                 m.group (9), m.group (10))
149         
150 def list_url (url):
151         s = "list_%s ('%s', '%s', '%s', '%s', '%s')" % split_url (url)
152         return eval (s)
153
154 def version_tuple_to_str (t):
155         if t[3]:
156                 my = '.%s%d' % (t[3], t[4])
157         else:
158                 my = ''
159         return ('%d.%d.%d' % t[0:3]) + my
160
161 def version_str_to_tuple (s):
162         t = string.split (s, '.')
163         if len (t) >= 4:
164                 my_name = t[3][:-1]
165                 my_number = string.atoi (t[3][-1])
166         else:
167                 my_name = None
168                 my_number = None
169         return (string.atoi (t[0]), string.atoi (t[1]), string.atoi (t[2]),
170                 my_name, my_number)
171
172 def split_package (p):
173         m = re.match ('(.*)-([0-9]*.*).tar.gz', p)
174         return (m.group (1), version_str_to_tuple (m.group (2)))
175
176 def join_package (t):
177         return t[0] + '-' + version_tuple_to_str (t[1])
178
179 def copy_file (user, passwd, host, dir, file):
180         os.system ('cp %s/%s .' % (dir, file))
181
182 copy_ = copy_file
183
184 def copy_ftp (user, passwd, host, dir, file):
185         if user == 'None':
186                 user = 'anonymous'
187         if passwd == 'None':
188                 passwd = program_name
189
190         ftp = ftplib.FTP (host)
191         ftp.login (user, passwd)
192         ftp.set_pasv (1)
193         t = tempfile.mktemp (program_name)
194         try:
195                 f = open (t, 'w')
196                 ftp.retrbinary ('RETR %s/%s' % (dir, file),
197                         lambda x, f=f: f.write (x))
198                 f.close ()
199                 # huh? Invalid cross-device link
200                 # os.rename (t, file)
201                 system ('mv %s %s' % (t, file))
202         except:
203                 os.remove (t)
204                 raise 'Foo'
205         try:
206                 ftp.quit ()
207         except:
208                 ftp.close ()
209         return list
210         
211
212
213 def copy_url (url, dir):
214         os.chdir (dir)
215         s = "copy_%s ('%s', '%s', '%s', '%s', '%s')" % split_url (url)
216         eval (s)
217
218
219 def find_latest (url):
220         progress (_ ("Listing `%s'...") % url)
221         list = map (split_package, list_url (url))
222         list.sort ()
223         return join_package (list[-1])
224
225 def build (p):
226         tar_ball = p + '.tar.gz'
227         (tar_name, tar_version) = split_package (tar_ball)
228         
229         expand = {
230                 '%b' : build_root,
231                 '%n' : tar_name,
232                 '%r' : release_dir,
233                 '%v' : version_tuple_to_str (tar_version),
234                 '%t' : tar_ball,
235                 }
236
237         c = build_command
238         for i in expand.keys ():
239                 c = re.sub (i, expand[i], c)
240         return system (c, 1)
241
242
243
244 (sh, long) = getopt_args (__main__.option_definitions)
245 try:
246         (options, files) = getopt.getopt(sys.argv[1:], sh, long)
247 except getopt.error, s:
248         errorport.write ('\n')
249         errorport.write (_ ("error: ") + _ ("getopt says: `%s\'" % s))
250         errorport.write ('\n')
251         errorport.write ('\n')
252         help ()
253         sys.exit (2)
254
255 for opt in options:     
256         o = opt[0]
257         a = opt[1]
258
259         if 0:
260                 pass
261         elif o == '--help' or o == '-h':
262                 help ()
263         elif o == '--buid-root' or o == '-b':
264                 build_root = a
265         elif o == '--command' or o == '-c':
266                 build_command = a
267         elif o == '--notify' or o == '-n':
268                 notify = a
269         elif o == '--remove-previous' or o == '-r':
270                 remove_previous_p = 1
271         elif o == '--url' or o == '-u':
272                 url = a
273         elif o == '--verbose' or o == '-V':
274                 verbose_p = 1
275         elif o == '--version' or o == '-v':
276                 identify ()
277                 sys.exit (0)
278         elif o == '--warranty' or o == '-w':
279                 warranty ()
280                 sys.exit (0)
281                 
282 if 1:
283         latest = find_latest (url)
284
285         # if os.path.isdir ('%s/%s' % (build_root, latest)):
286         if os.path.exists ('%s/%s/index.html' % (build_root, latest)):
287                 progress (_ ("latest is: %s") % latest)
288                 progress (_ ("relax, %s is up to date" % package_name))
289                 sys.exit (0)
290
291         get_base = url[:string.rindex (url, '/')] + '/'
292         if os.path.isdir (patch_dir):
293                 os.chdir (patch_dir)
294                 if not os.path.isfile (latest + '.diff.gz'):
295                         get = get_base + latest + '.diff.gz'
296                         progress (_ ("Fetching `%s'...") % get)
297                         copy_url (get, '.')
298
299         if not os.path.isdir (build_root):
300                 build_root = temp_dir
301                 
302         if not os.path.isdir (release_dir):
303                 release_dir = temp_dir
304                 setup_temp ()
305                 
306         os.chdir (release_dir)
307         if not os.path.isfile (latest + '.tar.gz'):
308                 get = get_base + latest + '.tar.gz'
309                 progress (_ ("Fetching `%s'...") % get)
310                 copy_url (get, '.')
311
312         if os.path.isdir (os.path.join (build_root, package_name)):
313                 os.chdir (os.path.join (build_root, package_name))
314                 previous = os.getcwd ()
315         else:
316                 previous = 0
317
318         progress (_ ("Building `%s'...") % latest)
319         os.chdir (build_root)
320         if not build (latest):
321                 if previous and remove_previous_p:
322                         system ('rm -rf %s' % os.path.join (build_root, previous))
323         else:
324                 if notify:
325                         system ('(date; uname -a) | mail -s "%s failed" %s' % (program_name, notify))
326                 sys.exit (1)
327                 
328         os.chdir (original_dir)
329         if release_dir != temp_dir:
330                 cleanup_temp ()
331         sys.exit (0)
332