Make a status test pass against old servers.
[svn.git] / build / win32 / make_dist.py
blobe6753dc135b87a93957076308caa8f51502b08a0
1 import os
2 import sys
3 import shutil
4 import getopt
5 try:
6 my_getopt = getopt.gnu_getopt
7 except AttributeError:
8 my_getopt = getopt.getopt
9 import glob
10 import traceback
11 import ConfigParser
13 # The script directory and the source base directory
14 _scriptdir = os.path.dirname(sys.argv[0])
15 _srcdir = os.path.join(_scriptdir, '..', '..')
16 _distname = None
17 _distdir = None
18 _readme = None
21 _stdout = sys.stdout
22 _stderr = sys.stderr
24 _logname = os.path.abspath(os.path.join(_scriptdir, 'make_dist.log'))
25 _logfile = open(_logname, 'w')
26 sys.stdout = _logfile
27 sys.stderr = _logfile
29 def _exit(code=0):
30 if code:
31 _stderr.write('make_dist: Exit %d\n' % (code,))
32 sys.exit(code)
35 # Action classes
37 class MissingMethodImpl:
38 pass
40 class Action:
41 def run(self, dir, cfg):
42 raise MissingMethodImpl()
44 def _expand(self, cfg, value):
45 cfg.set('__expand__', '__expand__', value)
46 return cfg.get('__expand__', '__expand__')
48 def _safe_expand(self, cfg, value):
49 try:
50 return self._expand(cfg, value)
51 except:
52 return None
54 def _copy_file(self, source, target):
55 print 'copy:', source
56 print ' to:', target
57 shutil.copyfile(source, target)
59 class File(Action):
60 def __init__(self, path, name=None):
61 self.path = path
62 self.name = name
64 def run(self, dir, cfg):
65 path = self._expand(cfg, self.path)
66 if self.name is None:
67 name = os.path.basename(path)
68 else:
69 name = self.name
70 self._copy_file(path, os.path.join(dir, name))
72 class OptFile(Action):
73 def __init__(self, path, name=None):
74 self.path = path
75 self.name = name
77 def run(self, dir, cfg):
78 path = self._safe_expand(cfg, self.path)
79 if path is None or not os.path.isfile(path):
80 print 'make_dist: File not found:', self.path
81 return
82 if self.name is None:
83 name = os.path.basename(path)
84 else:
85 name = self.name
86 self._copy_file(path, os.path.join(dir, name))
88 class FileGlob(Action):
89 def __init__(self, pattern):
90 self.pattern = pattern
92 def run(self, dir, cfg):
93 pattern = self._expand(cfg, self.pattern)
94 for source in glob.glob(pattern):
95 self._copy_file(source, os.path.join(dir, os.path.basename(source)))
97 class InstallDocs(Action):
98 def __init__(self, config, path):
99 self.config = config
100 self.path = path
102 def run(self, dir, cfg):
103 config = self._expand(cfg, self.config)
104 pattern = os.path.join(self._expand(cfg, self.path), '*.*')
105 print 'make_dist: Generating documentation'
106 old_cwd = os.getcwd()
107 try:
108 os.chdir(_srcdir)
109 _system('"%s" "%s"' % (cfg.get('tools', 'doxygen'), config))
110 os.chdir(old_cwd)
111 FileGlob(pattern).run(dir, cfg)
112 except:
113 os.chdir(old_cwd)
114 raise
115 else:
116 os.chdir(old_cwd)
118 class InstallIconv(Action):
119 def __init__(self, source, build_mode):
120 self.source = source
121 self.build_mode = build_mode
123 def run(self, dir, cfg):
124 source = os.path.abspath(self._expand(cfg, self.source))
125 build_mode = self._expand(cfg, self.build_mode)
126 print 'make_dist: Installing apr-iconv modules'
127 install = ('"%s" -nologo -f Makefile.win install'
128 + ' INSTALL_DIR="%s"'
129 + ' BUILD_MODE=%s BIND_MODE=%s') \
130 % (cfg.get('tools', 'nmake'),
131 os.path.abspath(dir),
132 build_mode,
133 'shared')
134 old_cwd = os.getcwd()
135 try:
136 os.chdir(os.path.join(source, 'ccs'))
137 _system(install)
138 os.chdir(os.path.join(source, 'ces'))
139 _system(install)
140 except:
141 os.chdir(old_cwd)
142 raise
143 else:
144 os.chdir(old_cwd)
146 class InstallJar(Action):
147 def __init__(self, jar, source):
148 self.jar = jar
149 self.source = source
151 def run(self, dir, cfg):
152 source = os.path.abspath(self._expand(cfg, self.source))
153 jarfile = os.path.abspath(os.path.join(dir, self.jar))
154 print 'make_dist: Creating jar', self.jar
155 _system('"%s" cvf "%s" -C "%s" .'
156 % (cfg.get('tools', 'jar'), jarfile, source))
158 class InstallMoFiles(Action):
159 def __init__(self, source):
160 self.source = source
162 def run(self, dir, cfg):
163 pattern = os.path.join(self._expand(cfg, self.source), '*.mo')
164 for mofile in glob.glob(pattern):
165 localedir = os.path.join(dir, os.path.basename(mofile)[:-3],
166 'LC_MESSAGES')
167 os.makedirs(localedir)
168 self._copy_file(mofile, os.path.join(localedir, 'subversion.mo'))
170 # This is the distribution tree
171 _disttree = {'': OptFile('%(readme)s', 'README.txt'),
173 'bin': (File('%(blddir)s/svn/svn.exe'),
174 File('%(blddir)s/svn/svn.pdb'),
175 File('%(blddir)s/svnsync/svnsync.pdb'),
176 File('%(blddir)s/svnsync/svnsync.exe'),
177 File('%(blddir)s/svnadmin/svnadmin.exe'),
178 File('%(blddir)s/svnadmin/svnadmin.pdb'),
179 File('%(blddir)s/svnlook/svnlook.exe'),
180 File('%(blddir)s/svnlook/svnlook.pdb'),
181 File('%(blddir)s/svndumpfilter/svndumpfilter.exe'),
182 File('%(blddir)s/svndumpfilter/svndumpfilter.pdb'),
183 File('%(blddir)s/svnserve/svnserve.exe'),
184 File('%(blddir)s/svnserve/svnserve.pdb'),
185 File('%(blddir)s/svnversion/svnversion.exe'),
186 File('%(blddir)s/svnversion/svnversion.pdb'),
187 File('%(blddir)s/mod_dav_svn/mod_dav_svn.so'),
188 File('%(blddir)s/mod_dav_svn/mod_dav_svn.pdb'),
189 File('%(blddir)s/mod_authz_svn/mod_authz_svn.so'),
190 File('%(blddir)s/mod_authz_svn/mod_authz_svn.pdb'),
191 File('%(@apr)s/%(aprrel)s/libapr.dll'),
192 File('%(@apr)s/%(aprrel)s/libapr.pdb'),
193 File('%(@apr-iconv)s/%(aprrel)s/libapriconv.dll'),
194 File('%(@apr-iconv)s/%(aprrel)s/libapriconv.pdb'),
195 File('%(@apr-util)s/%(aprrel)s/libaprutil.dll'),
196 File('%(@apr-util)s/%(aprrel)s/libaprutil.pdb'),
197 File('%(@berkeley-db)s/bin/libdb%(bdbver)s.dll'),
198 OptFile('%(@berkeley-db)s/bin/libdb%(bdbver)s.pdb'),
199 OptFile('%(@openssl)s/out32dll/libeay32.dll'),
200 OptFile('%(@openssl)s/out32dll/libeay32.pdb'),
201 OptFile('%(@openssl)s/out32dll/ssleay32.dll'),
202 OptFile('%(@openssl)s/out32dll/ssleay32.pdb'),
203 OptFile('%(@libintl)s/bin/intl3_svn.dll'),
204 OptFile('%(@libintl)s/bin/intl3_svn.pdb'),
207 'doc': InstallDocs('%(srcdir)s/doc/doxygen.conf',
208 '%(srcdir)s/doc/doxygen/html'),
210 'iconv': InstallIconv('%(@apr-iconv)s', '%(aprrel)s'),
212 'include': FileGlob('%(svndir)s/include/*.h'),
213 'include/apr': FileGlob('%(@apr)s/include/*.h'),
214 'include/apr-iconv': FileGlob('%(@apr-iconv)s/include/*.h'),
215 'include/apr-util': FileGlob('%(@apr-util)s/include/*.h'),
217 'lib': (FileGlob('%(blddir)s/libsvn_*/*.lib'),
218 FileGlob('%(blddir)s/libsvn_*/*.pdb')),
219 'lib/apr': File('%(@apr)s/%(aprrel)s/libapr.lib'),
220 'lib/apr-iconv': File('%(@apr-iconv)s/%(aprrel)s/libapriconv.lib'),
221 'lib/apr-util': (File('%(@apr-util)s/%(aprrel)s/libaprutil.lib'),
222 File('%(@apr-util)s/%(aprxml)s/xml.lib'),
223 File('%(@apr-util)s/%(aprxml)s/xml_src.pdb'),
225 'lib/neon': (File('%(@neon)s/libneon.lib'),
226 OptFile('%(@zlib)s/zlibstat.lib'),
229 'licenses': None,
230 'licenses/bdb': File('%(@berkeley-db)s/LICENSE'),
231 'licenses/neon': File('%(@neon)s/src/COPYING.LIB'),
232 'licenses/zlib': File('%(@zlib)s/README'),
233 'licenses/apr-util': (File('%(@apr-util)s/LICENSE'),
234 File('%(@apr-util)s/NOTICE'),
236 'licenses/apr-iconv': (File('%(@apr-iconv)s/LICENSE'),
237 File('%(@apr-iconv)s/NOTICE'),
239 'licenses/apr': (File('%(@apr)s/LICENSE'),
240 File('%(@apr)s/NOTICE'),
242 'licenses/openssl': File('%(@openssl)s/LICENSE'),
243 'licenses/svn' : File('%(srcdir)s/COPYING'),
245 'perl': None,
246 'perl/site': None,
247 'perl/site/lib': None,
248 'perl/site/lib/SVN': FileGlob('%(bindsrc)s/swig/perl/native/*.pm'),
249 'perl/site/lib/auto': None,
250 'perl/site/lib/auto/SVN': None,
251 # Perl module DLLs defined below
253 'python': None,
254 'python/libsvn': (FileGlob('%(binddir)s/swig/python/libsvn_swig_py/*.dll'),
255 FileGlob('%(binddir)s/swig/python/libsvn_swig_py/*.pdb'),
256 FileGlob('%(bindsrc)s/swig/python/*.py'),
257 FileGlob('%(binddir)s/swig/python/*.dll'),
258 FileGlob('%(binddir)s/swig/python/*.pdb'),
260 'python/svn': FileGlob('%(bindsrc)s/swig/python/svn/*.py'),
262 'javahl': (FileGlob('%(binddir)s/java/javahl/native/libsvn*.dll'),
263 FileGlob('%(binddir)s/java/javahl/native/libsvn*.pdb'),
264 InstallJar('svnjavahl.jar',
265 '%(bindsrc)s/java/javahl/classes'),
268 'ruby': None,
269 'ruby/lib': None,
270 'ruby/lib/svn': FileGlob('%(bindsrc)s/swig/ruby/svn/*.rb'),
271 'ruby/ext': None,
272 'ruby/ext/svn': None,
273 'ruby/ext/svn/ext':
274 (FileGlob('%(binddir)s/swig/ruby/*.dll'),
275 FileGlob('%(binddir)s/swig/ruby/*.pdb'),
276 FileGlob('%(binddir)s/swig/ruby/libsvn_swig_ruby/*.dll'),
277 FileGlob('%(binddir)s/swig/ruby/libsvn_swig_ruby/*.pdb'),
278 FileGlob('%(blddir)s/libsvn_*/*.dll'),
279 File('%(@berkeley-db)s/bin/libdb%(bdbver)s.dll'),
280 OptFile('%(@libintl)s/bin/intl3_svn.dll'),
281 File('%(@apr)s/%(aprrel)s/libapr.dll'),
282 File('%(@apr-iconv)s/%(aprrel)s/libapriconv.dll'),
283 File('%(@apr-util)s/%(aprrel)s/libaprutil.dll')),
285 'share': None,
286 'share/locale': InstallMoFiles('%(srcdir)s/%(svnrel)s/mo'),
289 # Define Perl module DLLs
290 for module in ('Client', 'Core', 'Delta', 'Fs', 'Ra', 'Repos', 'Wc'):
291 _disttree['perl/site/lib/auto/SVN/_' + module] = (
292 File('%(binddir)s/swig/perl/native/_' + module + '.dll'),
293 File('%(binddir)s/swig/perl/native/_' + module + '.pdb'))
295 def _system(command):
296 def reopen_log():
297 global _logfile
298 _logfile = open(_logname, 'a')
299 sys.stdout = _logfile
300 sys.stderr = _logfile
301 try:
302 _logfile.close()
303 sys.stdout = _stdout
304 sys.stderr = _stderr
305 os.system('"%s >>%s 2>&1"' % (command, _logname))
306 except:
307 reopen_log()
308 raise
309 else:
310 reopen_log()
313 def _read_config():
314 # Read make_dist.conf first. Fill in the default package locations.
315 path_defaults = {'@berkeley-db':
316 os.path.abspath(os.path.join(_srcdir, 'db4-win32')),
317 '@apr':
318 os.path.abspath(os.path.join(_srcdir, 'apr')),
319 '@apr-iconv':
320 os.path.abspath(os.path.join(_srcdir, 'apr-iconv')),
321 '@apr-util':
322 os.path.abspath(os.path.join(_srcdir, 'apr-util')),
323 '@neon':
324 os.path.abspath(os.path.join(_srcdir, 'neon')),
327 cfg = ConfigParser.ConfigParser(path_defaults)
328 try:
329 cfg.readfp(open(os.path.join(_scriptdir, 'make_dist.conf'), 'r'))
330 except:
331 _stderr.write('Unable to open and read make_dist.conf\n')
332 _exit(1)
334 # Read the options config generated by gen-make.py
335 optcfg = ConfigParser.ConfigParser()
336 optcfg.readfp(open(os.path.join(_srcdir, 'gen-make.opts'), 'r'))
338 # Move the runtime options into the DEFAULT section
339 for opt in optcfg.options('options'):
340 if not opt[:7] == '--with-':
341 continue
342 optdir = os.path.abspath(os.path.join(_srcdir, optcfg.get('options', opt)))
343 if not os.path.isdir(optdir):
344 print 'make_dist:', opt, '=', optdir
345 print 'make_dist: Target is not a directory'
346 _exit(1)
347 cfg.set('DEFAULT', '@' + opt[7:], optdir)
349 # Also add the global parameters to the defaults
350 cfg.set('DEFAULT', 'srcdir', os.path.abspath(_srcdir))
351 cfg.set('DEFAULT', 'blddir', os.path.join(_srcdir,
352 '%(svnrel)s', 'subversion'))
353 cfg.set('DEFAULT', 'svndir', os.path.join(_srcdir, 'subversion'))
354 cfg.set('DEFAULT', 'binddir', '%(blddir)s/bindings')
355 cfg.set('DEFAULT', 'bindsrc', '%(svndir)s/bindings')
358 if _distname is not None:
359 cfg.set('DEFAULT', 'distname', os.path.abspath(_distname))
360 if _distdir is not None:
361 cfg.set('DEFAULT', 'distdir', os.path.abspath(_distdir))
362 if _readme is not None:
363 cfg.set('DEFAULT', 'readme', os.path.abspath(_readme))
365 return cfg
368 def _make_zip(suffix, pathlist, extras):
369 zipname = '%s%s.zip' % (_distname, suffix)
370 zipcmd = '"%s" -9 -r "%s"' % (cfg.get('tools', 'zip'), zipname)
371 for path in pathlist:
372 zipcmd = zipcmd + ' "' + _distname + path + '"'
373 if extras:
374 zipcmd = zipcmd + ' ' + extras
375 old_cwd = os.getcwd()
376 try:
377 os.chdir(_distdir)
378 if os.path.exists(zipname):
379 os.remove(zipname)
380 print 'make_dist: Creating %s' % zipname
381 _stdout.write('make_dist: Creating %s\n' % zipname)
382 _system(zipcmd)
383 except:
384 os.chdir(old_cwd)
385 raise
386 else:
387 os.chdir(old_cwd)
390 def _make_dist(cfg):
391 try:
392 cfg.add_section('__expand__')
393 distdir = os.path.abspath(os.path.join(_distdir, _distname))
394 if os.path.isdir(distdir):
395 shutil.rmtree(distdir)
396 os.makedirs(distdir)
398 dirlist = _disttree.keys()
399 dirlist.sort()
401 for reldir in dirlist:
402 dir = os.path.join(distdir, reldir)
403 if not os.path.exists(dir):
404 print 'make_dist: Creating directory', reldir
405 _stdout.write('make_dist: Creating directory %s\n' % reldir)
406 os.makedirs(dir)
407 action = _disttree[reldir]
408 if action is None:
409 continue
410 if type(action) == type(()):
411 for subaction in action:
412 subaction.run(dir, cfg)
413 else:
414 action.run(dir, cfg)
416 xpdb = '-x "*.pdb"'
417 _make_zip('', ('/README.txt', '/bin', '/httpd',
418 '/iconv', '/licenses', '/share/locale'), xpdb)
419 _make_zip('_dev', ('/README.txt', '/doc', '/include', '/lib'), xpdb)
420 _make_zip('_javahl', ('/README.txt', '/javahl'), xpdb)
421 _make_zip('_pdb', ('',), '-i "*.pdb"')
422 _make_zip('_pl', ('/README.txt', '/perl'), xpdb)
423 _make_zip('_py', ('/README.txt', '/python'), xpdb)
424 _make_zip('_rb', ('/README.txt', '/ruby', '/licenses', '/share/locale'),
425 xpdb)
427 _stdout.write('make_dist: Creating ruby gem\n')
428 gem_script = os.path.join(_scriptdir, 'make_gem.rb')
429 rubycmd = '"%s" "%s" --output-dir="%s"' % (cfg.get('tools', 'ruby'),
430 gem_script, _distdir)
431 rubycmd += ' "' + distdir + '\\README.txt"'
432 rubycmd += ' "' + distdir + '\\ruby"'
433 rubycmd += ' "' + distdir + '\\licenses"'
434 rubycmd += ' "' + distdir + '\\share"'
435 _system(rubycmd)
436 except:
437 traceback.print_exc(None, _stderr)
438 _exit(1)
441 if __name__ == '__main__':
442 opts, args = my_getopt(sys.argv[1:], '', ['readme='])
443 if len(args) != 2 or len(opts) > 1:
444 _stderr.write('Usage: make_dist.py [--readme=<file>] <distname> <distdir>\n')
445 _exit(2)
447 _distname, _distdir = args
449 if len(opts) != 0:
450 _readme = opts[0][1]
452 cfg = _read_config()
453 _make_dist(cfg)