]> git.donarmstrong.com Git - lilypond.git/blob - scripts/update-lily.py
patch::: 1.5.9.jcn1
[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 sys.path.append ('@datadir@/python')
35 try:
36         import gettext
37         gettext.bindtextdomain ('lilypond', '@localedir@')
38         gettext.textdomain('lilypond')
39         _ = gettext.gettext
40 except:
41         def _ (s):
42                 return s
43
44 program_name = 'build-lily'
45 package_name = 'lilypond'
46 help_summary = _("Fetch and rebuild from latest source package")
47 build_root = os.path.join (os.environ ['HOME'], 'usr', 'src')
48 release_dir = build_root + '/releases'
49 patch_dir = build_root + '/patches'
50 notify = 0
51
52 build_command = '''
53 set -x
54 cd %b &&
55 [ -d %n-%v ] && exit 1 || true;
56 mkdir -p %n-%v
57 (
58 tar xzf %r/%t &&
59 rm -f building &&
60 ln -s %n-%v building &&
61 cd %n-%v &&
62 ./configure --prefix=$HOME/usr && make all web
63 ) >> %n-%v/log.txt 2>&1 &&
64 rm -f %n &&
65 ln -s %n-%v %n
66 '''
67
68
69 url = 'file:/home/ftp/pub/gnu/LilyPond/development/lilypond-*.tar.gz'
70 url = 'ftp://appel.lilypond.org/pub/gnu/LilyPond/development/lilypond-*.tar.gz'
71 url = 'ftp://ftp.cs.uu.nl/pub/GNU/LilyPond/development/lilypond-*.tar.gz'
72
73 remove_previous_p = 0
74
75
76 # lily_py.py -- options and stuff
77
78 # source file of the GNU LilyPond music typesetter
79
80 # BEGIN Library for these?
81 # cut-n-paste from ly2dvi
82
83 program_version = '@TOPLEVEL_VERSION@'
84 if program_version == '@' + 'TOPLEVEL_VERSION' + '@':
85         program_version = '1.3.142'
86
87
88 original_dir = os.getcwd ()
89 temp_dir = '%s.dir' % program_name
90 keep_temp_dir_p = 0
91 verbose_p = 0
92
93 def identify ():
94         sys.stdout.write ('%s (GNU LilyPond) %s\n' % (program_name, program_version))
95
96 def warranty ():
97         identify ()
98         sys.stdout.write ('\n')
99         sys.stdout.write (_ ('Copyright (c) %s by' % ' 2001'))
100         sys.stdout.write ('\n')
101         sys.stdout.write ('  Han-Wen Nienhuys')
102         sys.stdout.write ('  Jan Nieuwenhuizen')
103         sys.stdout.write ('\n')
104         sys.stdout.write (_ (r'''
105 Distributed under terms of the GNU General Public License. It comes with
106 NO WARRANTY.'''))
107         sys.stdout.write ('\n')
108
109 def progress (s):
110         sys.stderr.write (s + '\n')
111
112 def warning (s):
113         sys.stderr.write (_ ("warning: ") + s)
114         sys.stderr.write ('\n')
115         
116                 
117 def error (s):
118         sys.stderr.write (_ ("error: ") + s)
119         sys.stderr.write ('\n')
120         raise _ ("Exiting ... ")
121
122 def getopt_args (opts):
123         '''Construct arguments (LONG, SHORT) for getopt from  list of options.'''
124         short = ''
125         long = []
126         for o in opts:
127                 if o[1]:
128                         short = short + o[1]
129                         if o[0]:
130                                 short = short + ':'
131                 if o[2]:
132                         l = o[2]
133                         if o[0]:
134                                 l = l + '='
135                         long.append (l)
136         return (short, long)
137
138 def option_help_str (o):
139         '''Transform one option description (4-tuple ) into neatly formatted string'''
140         sh = '  '       
141         if o[1]:
142                 sh = '-%s' % o[1]
143
144         sep = ' '
145         if o[1] and o[2]:
146                 sep = ','
147                 
148         long = ''
149         if o[2]:
150                 long= '--%s' % o[2]
151
152         arg = ''
153         if o[0]:
154                 if o[2]:
155                         arg = '='
156                 arg = arg + o[0]
157         return '  ' + sh + sep + long + arg
158
159
160 def options_help_str (opts):
161         '''Convert a list of options into a neatly formatted string'''
162         w = 0
163         strs =[]
164         helps = []
165
166         for o in opts:
167                 s = option_help_str (o)
168                 strs.append ((s, o[3]))
169                 if len (s) > w:
170                         w = len (s)
171
172         str = ''
173         for s in strs:
174                 str = str + '%s%s%s\n' % (s[0], ' ' * (w - len(s[0])  + 3), s[1])
175         return str
176
177 def help ():
178         sys.stdout.write (_ ("Usage: %s [OPTION]... FILE") % program_name)
179         sys.stdout.write ('\n\n')
180         sys.stdout.write (help_summary)
181         sys.stdout.write ('\n\n')
182         sys.stdout.write (_ ("Options:"))
183         sys.stdout.write ('\n')
184         sys.stdout.write (options_help_str (option_definitions))
185         sys.stdout.write ('\n\n')
186         sys.stdout.write (_ ("Report bugs to %s") % 'bug-gnu-music@gnu.org')
187         sys.stdout.write ('\n')
188         sys.exit (0)
189
190
191 def setup_temp ():
192         global temp_dir
193         if not keep_temp_dir_p:
194                 temp_dir = tempfile.mktemp (program_name)
195         try:
196                 os.mkdir (temp_dir, 0777)
197         except OSError:
198                 pass
199                 
200         
201 def system (cmd, ignore_error = 0):
202         if verbose_p:
203                 progress (_ ("Invoking `%s\'") % cmd)
204         st = os.system (cmd)
205         if st:
206                 msg =  ( _ ("error: ") + _ ("command exited with value %d") % st)
207                 if ignore_error:
208                         sys.stderr.write (msg + ' ' + _ ("(ignored)") + ' ')
209                 else:
210                         error (msg)
211
212         return st
213
214
215 def cleanup_temp ():
216         if not keep_temp_dir_p:
217                 if verbose_p:
218                         progress (_ ("Cleaning `%s'...") % temp_dir)
219                 system ('rm -rf %s' % temp_dir)
220
221
222 def set_setting (dict, key, val):
223         try:
224                 val = string.atof (val)
225         except ValueError:
226                 #warning (_ ("invalid value: %s") % `val`)
227                 pass
228
229         try:
230                 dict[key].append (val)
231         except KeyError:
232                 warning (_ ("no such setting: %s") % `key`)
233                 dict[key] = [val]
234
235 # END Library
236
237 option_definitions = [
238         ('DIR', 'b', 'build-root', _ ("unpack and build in DIR [%s]") % build_root),
239         ('COMMAND', 'c', 'command', _ ("execute COMMAND, subtitute:") \
240          + '\n                            ' + _ ("%b: build root") \
241          + '\n                            ' + _ ("%n: package name") \
242          + '\n                            ' + _ ("%r: release directory") \
243          + '\n                            ' + _ ("%t: tarball") \
244          + '\n                            ' + _ ("%v: package version") \
245          ),
246         ('', 'h', 'help', _ ("this help")),
247         ('', 'k', 'keep', _ ("keep all output, and name the directory %s") % temp_dir),
248         ('EMAIL', 'n', 'notify', _ ("upon failure notify EMAIL[,EMAIL]")),
249         ('', 'r', 'remove-previous', _ ("remove previous build")),
250         ('', 'V', 'verbose', _ ("verbose")),
251         ('', 'v', 'version', _ ("print version number")),
252         ('URL', 'u', 'url', _ ("fetch and build URL [%s]") % url),
253         ('', 'w', 'warranty', _ ("show warranty and copyright")),
254         ]
255
256 def list_file (user, passwd, host, dir, file):
257         match = []
258         for i in os.listdir (dir):
259                 if fnmatch.fnmatch (i, file):
260                         match.append (i)
261         return match
262
263 list_ = list_file
264
265 def list_ftp (user, passwd, host, dir, file):
266         if user == 'None':
267                 user = 'anonymous'
268         if passwd == 'None':
269                 passwd = program_name
270
271         ftp = ftplib.FTP (host)
272         ftp.login (user, passwd)
273         ftp.set_pasv (1)
274         ftp.cwd (dir)
275         list = ftp.nlst (file)
276         try:
277                 ftp.quit ()
278         except:
279                 ftp.close ()
280         return list
281         
282 def split_url (url):
283         m = re.match ('([^:/]*)(:)?(/*([^:]*):)?(/*([^@]*)@)?(//([^/]*))?(.*)/(.*)',
284                       url)
285         if not m:
286                 error ("can't parse url: %s " % url)
287         return (m.group (1), m.group (4), m.group (6), m.group (8),
288                 m.group (9), m.group (10))
289         
290 def list_url (url):
291         s = "list_%s ('%s', '%s', '%s', '%s', '%s')" % split_url (url)
292         return eval (s)
293
294 def version_tuple_to_str (t):
295         if t[3]:
296                 my = '.%s%d' % (t[3], t[4])
297         else:
298                 my = ''
299         return ('%d.%d.%d' % t[0:3]) + my
300
301 def version_str_to_tuple (s):
302         t = string.split (s, '.')
303         if len (t) >= 4:
304                 my_name = t[3][:-1]
305                 my_number = string.atoi (t[3][-1])
306         else:
307                 my_name = None
308                 my_number = None
309         return (string.atoi (t[0]), string.atoi (t[1]), string.atoi (t[2]),
310                 my_name, my_number)
311
312 def split_package (p):
313         m = re.match ('(.*)-([0-9]*.*).tar.gz', p)
314         return (m.group (1), version_str_to_tuple (m.group (2)))
315
316 def join_package (t):
317         return t[0] + '-' + version_tuple_to_str (t[1])
318
319 def copy_file (user, passwd, host, dir, file):
320         os.system ('cp %s/%s .' % (dir, file))
321
322 copy_ = copy_file
323
324 def copy_ftp (user, passwd, host, dir, file):
325         if user == 'None':
326                 user = 'anonymous'
327         if passwd == 'None':
328                 passwd = program_name
329
330         ftp = ftplib.FTP (host)
331         ftp.login (user, passwd)
332         ftp.set_pasv (1)
333         t = tempfile.mktemp (program_name)
334         try:
335                 f = open (t, 'w')
336                 ftp.retrbinary ('RETR %s/%s' % (dir, file),
337                         lambda x, f=f: f.write (x))
338                 f.close ()
339                 # huh? Invalid cross-device link
340                 # os.rename (t, file)
341                 system ('mv %s %s' % (t, file))
342         except:
343                 os.remove (t)
344                 raise 'Foo'
345         try:
346                 ftp.quit ()
347         except:
348                 ftp.close ()
349         return list
350         
351
352
353 def copy_url (url, dir):
354         os.chdir (dir)
355         s = "copy_%s ('%s', '%s', '%s', '%s', '%s')" % split_url (url)
356         eval (s)
357
358
359 def find_latest (url):
360         progress (_ ("Listing `%s'...") % url)
361         list = map (split_package, list_url (url))
362         list.sort ()
363         return join_package (list[-1])
364
365 def build (p):
366         tar_ball = p + '.tar.gz'
367         (tar_name, tar_version) = split_package (tar_ball)
368         
369         expand = {
370                 '%b' : build_root,
371                 '%n' : tar_name,
372                 '%r' : release_dir,
373                 '%v' : version_tuple_to_str (tar_version),
374                 '%t' : tar_ball,
375                 }
376
377         c = build_command
378         for i in expand.keys ():
379                 c = re.sub (i, expand[i], c)
380         return system (c, 1)
381
382 (sh, long) = getopt_args (__main__.option_definitions)
383 try:
384         (options, files) = getopt.getopt (sys.argv[1:], sh, long)
385 except:
386         help ()
387         sys.exit (2)
388         
389 for opt in options:     
390         o = opt[0]
391         a = opt[1]
392
393         if 0:
394                 pass
395         elif o == '--help' or o == '-h':
396                 help ()
397         elif o == '--buid-root' or o == '-b':
398                 build_root = a
399         elif o == '--command' or o == '-c':
400                 build_command = a
401         elif o == '--notify' or o == '-n':
402                 notify = a
403         elif o == '--remove-previous' or o == '-r':
404                 remove_previous_p = 1
405         elif o == '--url' or o == '-u':
406                 url = a
407         elif o == '--verbose' or o == '-V':
408                 verbose_p = 1
409         elif o == '--version' or o == '-v':
410                 identify ()
411                 sys.exit (0)
412         elif o == '--warranty' or o == '-w':
413                 warranty ()
414                 sys.exit (0)
415                 
416 if 1:
417         latest = find_latest (url)
418
419         # if os.path.isdir ('%s/%s' % (build_root, latest)):
420         if os.path.exists ('%s/%s/index.html' % (build_root, latest)):
421                 progress (_ ("latest is: %s") % latest)
422                 progress (_ ("relax, %s is up to date" % package_name))
423                 sys.exit (0)
424
425         get_base = url[:string.rindex (url, '/')] + '/'
426         if os.path.isdir (patch_dir):
427                 os.chdir (patch_dir)
428                 if not os.path.isfile (latest + '.diff.gz'):
429                         get = get_base + latest + '.diff.gz'
430                         progress (_ ("Fetching `%s'...") % get)
431                         copy_url (get, '.')
432
433         if not os.path.isdir (build_root):
434                 build_root = temp_dir
435                 
436         if not os.path.isdir (release_dir):
437                 release_dir = temp_dir
438                 setup_temp ()
439                 
440         os.chdir (release_dir)
441         if not os.path.isfile (latest + '.tar.gz'):
442                 get = get_base + latest + '.tar.gz'
443                 progress (_ ("Fetching `%s'...") % get)
444                 copy_url (get, '.')
445
446         if os.path.isdir (os.path.join (build_root, package_name)):
447                 os.chdir (os.path.join (build_root, package_name))
448                 previous = os.getcwd ()
449         else:
450                 previous = 0
451
452         progress (_ ("Building `%s'...") % latest)
453         os.chdir (build_root)
454         if not build (latest):
455                 if previous and remove_previous_p:
456                         system ('rm -rf %s' % os.path.join (build_root, previous))
457         else:
458                 if notify:
459                         system ('(date; uname -a) | mail -s "%s failed" %s' % (program_name, notify))
460                 sys.exit (1)
461                 
462         os.chdir (original_dir)
463         if release_dir != temp_dir:
464                 cleanup_temp ()
465         sys.exit (0)
466