Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 460 lines (377 sloc) 14.619 kb
28a5f5f David Cournapeau Add paver file for scipy.
cournape authored
1 """
2 This paver file is intented to help with the release process as much as
3 possible. It relies on virtualenv to generate 'bootstrap' environments as
4 independent from the user system as possible (e.g. to make sure the sphinx doc
5 is built against the built scipy, not an installed one).
6
7 Building a simple (no-superpack) windows installer from wine
8 ============================================================
9
10 It assumes that blas/lapack are in c:\local\lib inside drive_c. Build python
11 2.5 and python 2.6 installers.
12
13 paver bdist_wininst_simple
14
15 You will have to configure your wine python locations (WINE_PYS).
16
17 The superpack requires all the atlas libraries for every arch to be installed
18 (see SITECFG), and can then be built as follows::
19
20 paver bdist_superpack
21
22 Building changelog + notes
23 ==========================
24
25 Assumes you have git and the binaries/tarballs in installers/::
26
27 paver write_release
28 paver write_note
29
30 This automatically put the checksum into NOTES.txt, and write the Changelog
31 which can be uploaded to sourceforge.
32
33 TODO
34 ====
35 - the script is messy, lots of global variables
36 - make it more easily customizable (through command line args)
37 - missing targets: install & test, sdist test, debian packaging
38 - fix bdist_mpkg: we build the same source twice -> how to make sure we use
39 the same underlying python for egg install in venv and for bdist_mpkg
40 """
41 import os
42 import sys
43 import subprocess
44 import re
45 import shutil
46 try:
47 from hash import md5
48 except ImportError:
49 import md5
50
51 import distutils
52
53 try:
54 from paver.tasks import VERSION as _PVER
55 if not _PVER >= '1.0':
56 raise RuntimeError("paver version >= 1.0 required (was %s)" % _PVER)
57 except ImportError, e:
58 raise RuntimeError("paver version >= 1.0 required")
59
60 import paver
61 import paver.doctools
62 import paver.path
cbb82e4 David Cournapeau Fix bdist_wininst_simple task.
cournape authored
63 from paver.easy import options, Bunch, task, needs, dry, sh, call_task, cmdopts
28a5f5f David Cournapeau Add paver file for scipy.
cournape authored
64
65 sys.path.insert(0, os.path.dirname(__file__))
66 try:
67 setup_py = __import__("setup")
68 FULLVERSION = setup_py.FULLVERSION
69 finally:
70 sys.path.pop(0)
71
72 # Wine config for win32 builds
73 WINE_SITE_CFG = ""
74 if sys.platform == "darwin":
352b639 David Cournapeau Fix wine build under darwin.
cournape authored
75 WINE_PY25 = ["/Applications/Darwine/Wine.bundle/Contents/bin/wine",
76 "/Users/david/.wine/drive_c/Python25/python.exe"]
77 WINE_PY26 = ["/Applications/Darwine/Wine.bundle/Contents/bin/wine",
78 "/Users/david/.wine/drive_c/Python26/python.exe"]
28a5f5f David Cournapeau Add paver file for scipy.
cournape authored
79 else:
352b639 David Cournapeau Fix wine build under darwin.
cournape authored
80 WINE_PY25 = ["/home/david/.wine/drive_c/Python25/python.exe"]
81 WINE_PY26 = ["/home/david/.wine/drive_c/Python26/python.exe"]
28a5f5f David Cournapeau Add paver file for scipy.
cournape authored
82 WINE_PYS = {'2.6' : WINE_PY26, '2.5': WINE_PY25}
83 SUPERPACK_BUILD = 'build-superpack'
84 SUPERPACK_BINDIR = os.path.join(SUPERPACK_BUILD, 'binaries')
85
86 # XXX: fix this in a sane way
87 MPKG_PYTHON = {"25": "/Library/Frameworks/Python.framework/Versions/2.5/bin/python",
88 "26": "/Library/Frameworks/Python.framework/Versions/2.6/bin/python"}
89 # Full path to the *static* gfortran runtime
90 LIBGFORTRAN_A_PATH = "/usr/local/lib/libgfortran.a"
91
92 # Where to put built documentation (where it will picked up for copy to
93 # binaries)
94 PDF_DESTDIR = paver.path.path('build') / 'pdf'
95 HTML_DESTDIR = paver.path.path('build') / 'html'
96 DOC_ROOT = paver.path.path("doc")
97 DOC_SRC = DOC_ROOT / "source"
98 DOC_BLD = DOC_ROOT / "build"
99 DOC_BLD_LATEX = DOC_BLD / "latex"
100
101 # Source of the release notes
102 RELEASE = 'doc/release/0.8.0-notes.rst'
103
104 # Start/end of the log (from git)
105 LOG_START = 'svn/tags/0.7.0'
106 LOG_END = 'master'
107
108 # Virtualenv bootstrap stuff
109 BOOTSTRAP_DIR = "bootstrap"
110 BOOTSTRAP_PYEXEC = "%s/bin/python" % BOOTSTRAP_DIR
111 BOOTSTRAP_SCRIPT = "%s/bootstrap.py" % BOOTSTRAP_DIR
112
113 # Where to put the final installers, as put on sourceforge
114 RELEASE_DIR = 'release'
115 INSTALLERS_DIR = os.path.join(RELEASE_DIR, 'installers')
116
117
118 options(sphinx=Bunch(builddir="build", sourcedir="source", docroot='doc'),
119 virtualenv=Bunch(script_name=BOOTSTRAP_SCRIPT,
120 packages_to_install=["sphinx==0.6.1"]),
121 wininst=Bunch(pyver="2.5", scratch=True))
122
123 # Bootstrap stuff
124 @task
125 def bootstrap():
126 """create virtualenv in ./install"""
127 install = paver.path.path(BOOTSTRAP_DIR)
128 if not install.exists():
129 install.mkdir()
130 call_task('paver.virtual.bootstrap')
131 sh('cd %s; %s bootstrap.py' % (BOOTSTRAP_DIR, sys.executable))
132
133 @task
134 def clean():
135 """Remove build, dist, egg-info garbage."""
136 d = ['build', 'dist', 'scipy.egg-info']
137 for i in d:
138 paver.path.path(i).rmtree()
139
140 (paver.path.path('doc') / options.sphinx.builddir).rmtree()
141
142 @task
143 def clean_bootstrap():
144 paver.path.path('bootstrap').rmtree()
145
146 @task
147 @needs('clean', 'clean_bootstrap')
148 def nuke():
149 """Remove everything: build dir, installers, bootstrap dirs, etc..."""
150 d = [SUPERPACK_BUILD, INSTALLERS_DIR]
151 for i in d:
152 paver.path.path(i).rmtree()
153
154 # NOTES/Changelog stuff
155 def compute_md5():
156 released = paver.path.path(INSTALLERS_DIR).listdir()
157 checksums = []
158 for f in released:
159 m = md5.md5(open(f, 'r').read())
160 checksums.append('%s %s' % (m.hexdigest(), f))
161
162 return checksums
163
164 def write_release_task(filename='NOTES.txt'):
165 source = paver.path.path(RELEASE)
166 target = paver.path.path(filename)
167 if target.exists():
168 target.remove()
169 source.copy(target)
170 ftarget = open(str(target), 'a')
171 ftarget.writelines("""
172 Checksums
173 =========
174
175 """)
176 ftarget.writelines(['%s\n' % c for c in compute_md5()])
177
178 def write_log_task(filename='Changelog'):
179 st = subprocess.Popen(
180 ['git', 'svn', 'log', '%s..%s' % (LOG_START, LOG_END)],
181 stdout=subprocess.PIPE)
182
183 out = st.communicate()[0]
184 a = open(filename, 'w')
185 a.writelines(out)
186 a.close()
187
188 @task
189 def write_release():
190 write_release_task()
191
192 @task
193 def write_log():
194 write_log_task()
195
196 #------------
197 # Doc tasks
198 #------------
199 @task
200 def html(options):
201 """Build scipy documentation and put it into build/docs"""
202 # Don't use paver html target because of scipy bootstrapping problems
203 subprocess.check_call(["make", "html"], cwd="doc")
204 builtdocs = paver.path.path("doc") / options.sphinx.builddir / "html"
205 HTML_DESTDIR.rmtree()
206 builtdocs.copytree(HTML_DESTDIR)
207
208 @task
209 def latex():
210 """Build scipy documentation in latex format."""
211 subprocess.check_call(["make", "latex"], cwd="doc")
212
213 @task
214 @needs('latex')
215 def pdf():
216 def build_pdf():
217 subprocess.check_call(["make", "all-pdf"], cwd=str(DOC_BLD_LATEX))
218 dry("Build pdf doc", build_pdf)
219
220 PDF_DESTDIR.rmtree()
221 PDF_DESTDIR.makedirs()
222
223 user = DOC_BLD_LATEX / "scipy-user.pdf"
224 user.copy(PDF_DESTDIR / "userguide.pdf")
225 ref = DOC_BLD_LATEX / "scipy-ref.pdf"
226 ref.copy(PDF_DESTDIR / "reference.pdf")
227
228 def tarball_name(type='gztar'):
229 root = 'scipy-%s' % FULLVERSION
230 if type == 'gztar':
231 return root + '.tar.gz'
232 elif type == 'zip':
233 return root + '.zip'
234 raise ValueError("Unknown type %s" % type)
235
236 @task
237 def sdist():
238 # To be sure to bypass paver when building sdist... paver + scipy.distutils
239 # do not play well together.
240 sh('python setup.py sdist --formats=gztar,zip')
241
242 # Copy the superpack into installers dir
243 if not os.path.exists(INSTALLERS_DIR):
244 os.makedirs(INSTALLERS_DIR)
245
246 for t in ['gztar', 'zip']:
247 source = os.path.join('dist', tarball_name(t))
248 target = os.path.join(INSTALLERS_DIR, tarball_name(t))
249 shutil.copy(source, target)
250
251 #------------------
252 # Wine-based builds
253 #------------------
747dc66 David Cournapeau Fix ATLAS/SSE handling for wine builds.
cournape authored
254 SSE3_CFG = {'BLAS': 'None', 'LAPACK': 'None', 'ATLAS': r'C:\local\lib\yop\sse3'}
255 SSE2_CFG = {'BLAS': 'None', 'LAPACK': 'None', 'ATLAS': r'C:\local\lib\yop\sse2'}
256 NOSSE_CFG = {'ATLAS': 'None', 'BLAS': r'C:\local\lib\yop\nosse', 'LAPACK': r'C:\local\lib\yop\nosse'}
28a5f5f David Cournapeau Add paver file for scipy.
cournape authored
257
258 SITECFG = {"sse2" : SSE2_CFG, "sse3" : SSE3_CFG, "nosse" : NOSSE_CFG}
259
260 def internal_wininst_name(arch, ismsi=False):
261 """Return the name of the wininst as it will be inside the superpack (i.e.
262 with the arch encoded."""
263 if ismsi:
264 ext = '.msi'
265 else:
266 ext = '.exe'
267 return "scipy-%s-%s%s" % (FULLVERSION, arch, ext)
268
269 def wininst_name(pyver, ismsi=False):
270 """Return the name of the installer built by wininst command."""
271 # Yeah, the name logic is harcoded in distutils. We have to reproduce it
272 # here
273 if ismsi:
274 ext = '.msi'
275 else:
276 ext = '.exe'
277 name = "scipy-%s.win32-py%s%s" % (FULLVERSION, pyver, ext)
278 return name
279
280 def bdist_wininst_arch(pyver, arch, scratch=True):
281 """Arch specific wininst build."""
282 if scratch:
283 paver.path.path('build').rmtree()
284
285 if not os.path.exists(SUPERPACK_BINDIR):
286 os.makedirs(SUPERPACK_BINDIR)
e0da5ef David Cournapeau Fix bdist_wininst_arch task on win32.
cournape authored
287 env = os.environ.copy()
288 for k, v in SITECFG[arch].items():
289 env[k] = v
290 _bdist_wininst(pyver, env)
28a5f5f David Cournapeau Add paver file for scipy.
cournape authored
291 source = os.path.join('dist', wininst_name(pyver))
292 target = os.path.join(SUPERPACK_BINDIR, internal_wininst_name(arch))
293 if os.path.exists(target):
294 os.remove(target)
295 os.rename(source, target)
296
297 def superpack_name(pyver, numver):
298 """Return the filename of the superpack installer."""
299 return 'scipy-%s-win32-superpack-python%s.exe' % (numver, pyver)
300
301 def prepare_nsis_script(pyver, numver):
302 if not os.path.exists(SUPERPACK_BUILD):
303 os.makedirs(SUPERPACK_BUILD)
304
d426942 David Cournapeau Fix nsis template location.
cournape authored
305 tpl = os.path.join('tools/win32/build_scripts/nsis_scripts', 'scipy-superinstaller.nsi.in')
28a5f5f David Cournapeau Add paver file for scipy.
cournape authored
306 source = open(tpl, 'r')
307 target = open(os.path.join(SUPERPACK_BUILD, 'scipy-superinstaller.nsi'), 'w')
308
309 installer_name = superpack_name(pyver, numver)
310 cnt = "".join(source.readlines())
6d54df7 David Cournapeau Fix bdist_superpack paver task (forgot to change name from numpy to scip...
cournape authored
311 cnt = cnt.replace('@SCIPY_INSTALLER_NAME@', installer_name)
28a5f5f David Cournapeau Add paver file for scipy.
cournape authored
312 for arch in ['nosse', 'sse2', 'sse3']:
313 cnt = cnt.replace('@%s_BINARY@' % arch.upper(),
314 internal_wininst_name(arch))
315
316 target.write(cnt)
317
318 @task
319 def bdist_wininst_nosse(options):
320 """Build the nosse wininst installer."""
321 bdist_wininst_arch(options.wininst.pyver, 'nosse', scratch=options.wininst.scratch)
322
323 @task
324 def bdist_wininst_sse2(options):
325 """Build the sse2 wininst installer."""
326 bdist_wininst_arch(options.wininst.pyver, 'sse2', scratch=options.wininst.scratch)
327
328 @task
329 def bdist_wininst_sse3(options):
330 """Build the sse3 wininst installer."""
331 bdist_wininst_arch(options.wininst.pyver, 'sse3', scratch=options.wininst.scratch)
332
333 @task
334 @needs('bdist_wininst_nosse', 'bdist_wininst_sse2', 'bdist_wininst_sse3')
335 def bdist_superpack(options):
336 """Build all arch specific wininst installers."""
337 prepare_nsis_script(options.wininst.pyver, FULLVERSION)
338 subprocess.check_call(['makensis', 'scipy-superinstaller.nsi'],
339 cwd=SUPERPACK_BUILD)
340
341 # Copy the superpack into installers dir
342 if not os.path.exists(INSTALLERS_DIR):
343 os.makedirs(INSTALLERS_DIR)
344
345 source = os.path.join(SUPERPACK_BUILD,
346 superpack_name(options.wininst.pyver, FULLVERSION))
347 target = os.path.join(INSTALLERS_DIR,
348 superpack_name(options.wininst.pyver, FULLVERSION))
349 shutil.copy(source, target)
350
351 @task
cbb82e4 David Cournapeau Fix bdist_wininst_simple task.
cournape authored
352 @cmdopts([('python_version=', 'p', 'Python version to build the installer against')])
28a5f5f David Cournapeau Add paver file for scipy.
cournape authored
353 def bdist_wininst_simple():
354 """Simple wininst-based installer."""
cbb82e4 David Cournapeau Fix bdist_wininst_simple task.
cournape authored
355 call_task("clean")
356 _bdist_wininst(options.bdist_wininst_simple.python_version, SITECFG['nosse'])
28a5f5f David Cournapeau Add paver file for scipy.
cournape authored
357
358 def _bdist_wininst(pyver, cfg_env=WINE_SITE_CFG):
352b639 David Cournapeau Fix wine build under darwin.
cournape authored
359 subprocess.call(WINE_PYS[pyver] + ['setup.py', 'build', '-c', 'mingw32', 'bdist_wininst'], env=cfg_env)
28a5f5f David Cournapeau Add paver file for scipy.
cournape authored
360
361 #-------------------
362 # Mac OS X installer
363 #-------------------
364 def macosx_version():
365 if not sys.platform == 'darwin':
366 raise ValueError("Not darwin ??")
367 st = subprocess.Popen(["sw_vers"], stdout=subprocess.PIPE)
368 out = st.stdout.readlines()
369 ver = re.compile("ProductVersion:\s+([0-9]+)\.([0-9]+)\.([0-9]+)")
370 for i in out:
371 m = ver.match(i)
372 if m:
373 return m.groups()
374
375 def mpkg_name():
376 maj, min = macosx_version()[:2]
377 pyver = ".".join([str(i) for i in sys.version_info[:2]])
378 return "scipy-%s-py%s-macosx%s.%s.mpkg" % \
379 (FULLVERSION, pyver, maj, min)
380
381 def dmg_name():
382 #maj, min = macosx_version()[:2]
383 pyver = ".".join([str(i) for i in sys.version_info[:2]])
384 #return "scipy-%s-py%s-macosx%s.%s.dmg" % \
385 # (FULLVERSION, pyver, maj, min)
386 return "scipy-%s-py%s-python.org.dmg" % \
387 (FULLVERSION, pyver)
388
389 def prepare_static_gfortran_runtime(d):
390 if not os.path.exists(d):
391 os.makedirs(d)
392 shutil.copy(LIBGFORTRAN_A_PATH, d)
393
394 @task
395 def bdist_mpkg():
396 call_task("clean")
397
398 prepare_static_gfortran_runtime("build")
399 ldflags = "-undefined dynamic_lookup -bundle -arch i386 -arch ppc -Wl,-search_paths_first"
400 ldflags += " -L%s" % os.path.join(os.path.dirname(__file__), "build")
401 pyver = "".join([str(i) for i in sys.version_info[:2]])
402 sh("LDFLAGS='%s' %s setupegg.py bdist_mpkg" % (ldflags, MPKG_PYTHON[pyver]))
403
404 @task
405 @needs("bdist_mpkg", "pdf")
406 def dmg():
407 pyver = ".".join([str(i) for i in sys.version_info[:2]])
408
409 dmg_n = dmg_name()
410 dmg = paver.path.path('scipy-macosx-installer') / dmg_n
411 if dmg.exists():
412 dmg.remove()
413
414 # Clean the image source
415 content = DMG_CONTENT
416 content.rmtree()
417 content.mkdir()
418
419 # Copy mpkg into image source
420 mpkg_n = mpkg_name()
421 mpkg_tn = "scipy-%s-py%s.mpkg" % (FULLVERSION, pyver)
422 mpkg_source = paver.path.path("dist") / mpkg_n
423 mpkg_target = content / mpkg_tn
424 mpkg_source.copytree(content / mpkg_tn)
425
426 # Copy docs into image source
427
428 #html_docs = HTML_DESTDIR
429 #html_docs.copytree(content / "Documentation" / "html")
430
431 pdf_docs = DMG_CONTENT / "Documentation"
432 pdf_docs.rmtree()
433 pdf_docs.makedirs()
434
435 user = PDF_DESTDIR / "userguide.pdf"
436 user.copy(pdf_docs / "userguide.pdf")
437 ref = PDF_DESTDIR / "reference.pdf"
438 ref.copy(pdf_docs / "reference.pdf")
439
440 # Build the dmg
441 cmd = ["./create-dmg", "--window-size", "500", "500", "--background",
442 "art/dmgbackground.png", "--icon-size", "128", "--icon", mpkg_tn,
443 "125", "320", "--icon", "Documentation", "375", "320", "--volname", "scipy",
444 dmg_n, "./content"]
445 subprocess.check_call(cmd, cwd="scipy-macosx-installer")
446
447 @task
448 def simple_dmg():
449 # Build the dmg
450 image_name = dmg_name()
451 image = paver.path.path(image_name)
452 image.remove()
453 cmd = ["hdiutil", "create", image_name, "-srcdir", str("dist")]
454 sh(" ".join(cmd))
455
456 @task
457 def write_note_changelog():
458 write_release_task(os.path.join(RELEASE_DIR, 'NOTES.txt'))
459 write_log_task(os.path.join(RELEASE_DIR, 'Changelog'))
Something went wrong with that request. Please try again.