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