##// END OF EJS Templates
Merge pull request #4207 from minrk/setup-css...
Brian E. Granger -
r12631:34e68335 merge
parent child Browse files
Show More
@@ -1,354 +1,356 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
2 # -*- coding: utf-8 -*-
3 """Setup script for IPython.
3 """Setup script for IPython.
4
4
5 Under Posix environments it works like a typical setup.py script.
5 Under Posix environments it works like a typical setup.py script.
6 Under Windows, the command sdist is not supported, since IPython
6 Under Windows, the command sdist is not supported, since IPython
7 requires utilities which are not available under Windows."""
7 requires utilities which are not available under Windows."""
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (c) 2008-2011, IPython Development Team.
10 # Copyright (c) 2008-2011, IPython Development Team.
11 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
11 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
12 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
12 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
13 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
13 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
14 #
14 #
15 # Distributed under the terms of the Modified BSD License.
15 # Distributed under the terms of the Modified BSD License.
16 #
16 #
17 # The full license is in the file COPYING.txt, distributed with this software.
17 # The full license is in the file COPYING.txt, distributed with this software.
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Minimal Python version sanity check
21 # Minimal Python version sanity check
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 from __future__ import print_function
23 from __future__ import print_function
24
24
25 import sys
25 import sys
26
26
27 # This check is also made in IPython/__init__, don't forget to update both when
27 # This check is also made in IPython/__init__, don't forget to update both when
28 # changing Python version requirements.
28 # changing Python version requirements.
29 if sys.version_info[:2] < (2,7):
29 if sys.version_info[:2] < (2,7):
30 error = "ERROR: IPython requires Python Version 2.7 or above."
30 error = "ERROR: IPython requires Python Version 2.7 or above."
31 print(error, file=sys.stderr)
31 print(error, file=sys.stderr)
32 sys.exit(1)
32 sys.exit(1)
33
33
34 PY3 = (sys.version_info[0] >= 3)
34 PY3 = (sys.version_info[0] >= 3)
35
35
36 # At least we're on the python version we need, move on.
36 # At least we're on the python version we need, move on.
37
37
38 #-------------------------------------------------------------------------------
38 #-------------------------------------------------------------------------------
39 # Imports
39 # Imports
40 #-------------------------------------------------------------------------------
40 #-------------------------------------------------------------------------------
41
41
42 # Stdlib imports
42 # Stdlib imports
43 import os
43 import os
44 import shutil
44 import shutil
45
45
46 from glob import glob
46 from glob import glob
47
47
48 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
48 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
49 # update it when the contents of directories change.
49 # update it when the contents of directories change.
50 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
50 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
51
51
52 from distutils.core import setup
52 from distutils.core import setup
53
53
54 # On Python 3, we need distribute (new setuptools) to do the 2to3 conversion
54 # On Python 3, we need distribute (new setuptools) to do the 2to3 conversion
55 if PY3:
55 if PY3:
56 import setuptools
56 import setuptools
57
57
58 # Our own imports
58 # Our own imports
59 from setupbase import target_update
59 from setupbase import target_update
60
60
61 from setupbase import (
61 from setupbase import (
62 setup_args,
62 setup_args,
63 find_packages,
63 find_packages,
64 find_package_data,
64 find_package_data,
65 find_scripts,
65 find_scripts,
66 find_data_files,
66 find_data_files,
67 check_for_dependencies,
67 check_for_dependencies,
68 git_prebuild,
68 git_prebuild,
69 check_submodule_status,
69 check_submodule_status,
70 update_submodules,
70 update_submodules,
71 require_submodules,
71 require_submodules,
72 UpdateSubmodules,
72 UpdateSubmodules,
73 CompileCSS,
73 )
74 )
74 from setupext import setupext
75 from setupext import setupext
75
76
76 isfile = os.path.isfile
77 isfile = os.path.isfile
77 pjoin = os.path.join
78 pjoin = os.path.join
78
79
79 #-----------------------------------------------------------------------------
80 #-----------------------------------------------------------------------------
80 # Function definitions
81 # Function definitions
81 #-----------------------------------------------------------------------------
82 #-----------------------------------------------------------------------------
82
83
83 def cleanup():
84 def cleanup():
84 """Clean up the junk left around by the build process"""
85 """Clean up the junk left around by the build process"""
85 if "develop" not in sys.argv and "egg_info" not in sys.argv:
86 if "develop" not in sys.argv and "egg_info" not in sys.argv:
86 try:
87 try:
87 shutil.rmtree('ipython.egg-info')
88 shutil.rmtree('ipython.egg-info')
88 except:
89 except:
89 try:
90 try:
90 os.unlink('ipython.egg-info')
91 os.unlink('ipython.egg-info')
91 except:
92 except:
92 pass
93 pass
93
94
94 #-------------------------------------------------------------------------------
95 #-------------------------------------------------------------------------------
95 # Handle OS specific things
96 # Handle OS specific things
96 #-------------------------------------------------------------------------------
97 #-------------------------------------------------------------------------------
97
98
98 if os.name in ('nt','dos'):
99 if os.name in ('nt','dos'):
99 os_name = 'windows'
100 os_name = 'windows'
100 else:
101 else:
101 os_name = os.name
102 os_name = os.name
102
103
103 # Under Windows, 'sdist' has not been supported. Now that the docs build with
104 # Under Windows, 'sdist' has not been supported. Now that the docs build with
104 # Sphinx it might work, but let's not turn it on until someone confirms that it
105 # Sphinx it might work, but let's not turn it on until someone confirms that it
105 # actually works.
106 # actually works.
106 if os_name == 'windows' and 'sdist' in sys.argv:
107 if os_name == 'windows' and 'sdist' in sys.argv:
107 print('The sdist command is not available under Windows. Exiting.')
108 print('The sdist command is not available under Windows. Exiting.')
108 sys.exit(1)
109 sys.exit(1)
109
110
110 #-------------------------------------------------------------------------------
111 #-------------------------------------------------------------------------------
111 # Make sure we aren't trying to run without submodules
112 # Make sure we aren't trying to run without submodules
112 #-------------------------------------------------------------------------------
113 #-------------------------------------------------------------------------------
113 here = os.path.abspath(os.path.dirname(__file__))
114 here = os.path.abspath(os.path.dirname(__file__))
114
115
115 def require_clean_submodules():
116 def require_clean_submodules():
116 """Check on git submodules before distutils can do anything
117 """Check on git submodules before distutils can do anything
117
118
118 Since distutils cannot be trusted to update the tree
119 Since distutils cannot be trusted to update the tree
119 after everything has been set in motion,
120 after everything has been set in motion,
120 this is not a distutils command.
121 this is not a distutils command.
121 """
122 """
122 # PACKAGERS: Add a return here to skip checks for git submodules
123 # PACKAGERS: Add a return here to skip checks for git submodules
123
124
124 # don't do anything if nothing is actually supposed to happen
125 # don't do anything if nothing is actually supposed to happen
125 for do_nothing in ('-h', '--help', '--help-commands', 'clean', 'submodule'):
126 for do_nothing in ('-h', '--help', '--help-commands', 'clean', 'submodule'):
126 if do_nothing in sys.argv:
127 if do_nothing in sys.argv:
127 return
128 return
128
129
129 status = check_submodule_status(here)
130 status = check_submodule_status(here)
130
131
131 if status == "missing":
132 if status == "missing":
132 print("checking out submodules for the first time")
133 print("checking out submodules for the first time")
133 update_submodules(here)
134 update_submodules(here)
134 elif status == "unclean":
135 elif status == "unclean":
135 print('\n'.join([
136 print('\n'.join([
136 "Cannot build / install IPython with unclean submodules",
137 "Cannot build / install IPython with unclean submodules",
137 "Please update submodules with",
138 "Please update submodules with",
138 " python setup.py submodule",
139 " python setup.py submodule",
139 "or",
140 "or",
140 " git submodule update",
141 " git submodule update",
141 "or commit any submodule changes you have made."
142 "or commit any submodule changes you have made."
142 ]))
143 ]))
143 sys.exit(1)
144 sys.exit(1)
144
145
145 require_clean_submodules()
146 require_clean_submodules()
146
147
147 #-------------------------------------------------------------------------------
148 #-------------------------------------------------------------------------------
148 # Things related to the IPython documentation
149 # Things related to the IPython documentation
149 #-------------------------------------------------------------------------------
150 #-------------------------------------------------------------------------------
150
151
151 # update the manuals when building a source dist
152 # update the manuals when building a source dist
152 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
153 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
153 import textwrap
154 import textwrap
154
155
155 # List of things to be updated. Each entry is a triplet of args for
156 # List of things to be updated. Each entry is a triplet of args for
156 # target_update()
157 # target_update()
157 to_update = [
158 to_update = [
158 # FIXME - Disabled for now: we need to redo an automatic way
159 # FIXME - Disabled for now: we need to redo an automatic way
159 # of generating the magic info inside the rst.
160 # of generating the magic info inside the rst.
160 #('docs/magic.tex',
161 #('docs/magic.tex',
161 #['IPython/Magic.py'],
162 #['IPython/Magic.py'],
162 #"cd doc && ./update_magic.sh" ),
163 #"cd doc && ./update_magic.sh" ),
163
164
164 ('docs/man/ipcluster.1.gz',
165 ('docs/man/ipcluster.1.gz',
165 ['docs/man/ipcluster.1'],
166 ['docs/man/ipcluster.1'],
166 'cd docs/man && gzip -9c ipcluster.1 > ipcluster.1.gz'),
167 'cd docs/man && gzip -9c ipcluster.1 > ipcluster.1.gz'),
167
168
168 ('docs/man/ipcontroller.1.gz',
169 ('docs/man/ipcontroller.1.gz',
169 ['docs/man/ipcontroller.1'],
170 ['docs/man/ipcontroller.1'],
170 'cd docs/man && gzip -9c ipcontroller.1 > ipcontroller.1.gz'),
171 'cd docs/man && gzip -9c ipcontroller.1 > ipcontroller.1.gz'),
171
172
172 ('docs/man/ipengine.1.gz',
173 ('docs/man/ipengine.1.gz',
173 ['docs/man/ipengine.1'],
174 ['docs/man/ipengine.1'],
174 'cd docs/man && gzip -9c ipengine.1 > ipengine.1.gz'),
175 'cd docs/man && gzip -9c ipengine.1 > ipengine.1.gz'),
175
176
176 ('docs/man/iplogger.1.gz',
177 ('docs/man/iplogger.1.gz',
177 ['docs/man/iplogger.1'],
178 ['docs/man/iplogger.1'],
178 'cd docs/man && gzip -9c iplogger.1 > iplogger.1.gz'),
179 'cd docs/man && gzip -9c iplogger.1 > iplogger.1.gz'),
179
180
180 ('docs/man/ipython.1.gz',
181 ('docs/man/ipython.1.gz',
181 ['docs/man/ipython.1'],
182 ['docs/man/ipython.1'],
182 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
183 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
183
184
184 ('docs/man/irunner.1.gz',
185 ('docs/man/irunner.1.gz',
185 ['docs/man/irunner.1'],
186 ['docs/man/irunner.1'],
186 'cd docs/man && gzip -9c irunner.1 > irunner.1.gz'),
187 'cd docs/man && gzip -9c irunner.1 > irunner.1.gz'),
187
188
188 ('docs/man/pycolor.1.gz',
189 ('docs/man/pycolor.1.gz',
189 ['docs/man/pycolor.1'],
190 ['docs/man/pycolor.1'],
190 'cd docs/man && gzip -9c pycolor.1 > pycolor.1.gz'),
191 'cd docs/man && gzip -9c pycolor.1 > pycolor.1.gz'),
191 ]
192 ]
192
193
193
194
194 [ target_update(*t) for t in to_update ]
195 [ target_update(*t) for t in to_update ]
195
196
196 #---------------------------------------------------------------------------
197 #---------------------------------------------------------------------------
197 # Find all the packages, package data, and data_files
198 # Find all the packages, package data, and data_files
198 #---------------------------------------------------------------------------
199 #---------------------------------------------------------------------------
199
200
200 packages = find_packages()
201 packages = find_packages()
201 package_data = find_package_data()
202 package_data = find_package_data()
202 data_files = find_data_files()
203 data_files = find_data_files()
203
204
204 setup_args['packages'] = packages
205 setup_args['packages'] = packages
205 setup_args['package_data'] = package_data
206 setup_args['package_data'] = package_data
206 setup_args['data_files'] = data_files
207 setup_args['data_files'] = data_files
207
208
208 #---------------------------------------------------------------------------
209 #---------------------------------------------------------------------------
209 # custom distutils commands
210 # custom distutils commands
210 #---------------------------------------------------------------------------
211 #---------------------------------------------------------------------------
211 # imports here, so they are after setuptools import if there was one
212 # imports here, so they are after setuptools import if there was one
212 from distutils.command.sdist import sdist
213 from distutils.command.sdist import sdist
213 from distutils.command.upload import upload
214 from distutils.command.upload import upload
214
215
215 class UploadWindowsInstallers(upload):
216 class UploadWindowsInstallers(upload):
216
217
217 description = "Upload Windows installers to PyPI (only used from tools/release_windows.py)"
218 description = "Upload Windows installers to PyPI (only used from tools/release_windows.py)"
218 user_options = upload.user_options + [
219 user_options = upload.user_options + [
219 ('files=', 'f', 'exe file (or glob) to upload')
220 ('files=', 'f', 'exe file (or glob) to upload')
220 ]
221 ]
221 def initialize_options(self):
222 def initialize_options(self):
222 upload.initialize_options(self)
223 upload.initialize_options(self)
223 meta = self.distribution.metadata
224 meta = self.distribution.metadata
224 base = '{name}-{version}'.format(
225 base = '{name}-{version}'.format(
225 name=meta.get_name(),
226 name=meta.get_name(),
226 version=meta.get_version()
227 version=meta.get_version()
227 )
228 )
228 self.files = os.path.join('dist', '%s.*.exe' % base)
229 self.files = os.path.join('dist', '%s.*.exe' % base)
229
230
230 def run(self):
231 def run(self):
231 for dist_file in glob(self.files):
232 for dist_file in glob(self.files):
232 self.upload_file('bdist_wininst', 'any', dist_file)
233 self.upload_file('bdist_wininst', 'any', dist_file)
233
234
234 setup_args['cmdclass'] = {
235 setup_args['cmdclass'] = {
235 'build_py': git_prebuild('IPython'),
236 'build_py': git_prebuild('IPython'),
236 'sdist' : git_prebuild('IPython', sdist),
237 'sdist' : git_prebuild('IPython', sdist),
237 'upload_wininst' : UploadWindowsInstallers,
238 'upload_wininst' : UploadWindowsInstallers,
238 'submodule' : UpdateSubmodules,
239 'submodule' : UpdateSubmodules,
240 'css' : CompileCSS,
239 }
241 }
240
242
241 #---------------------------------------------------------------------------
243 #---------------------------------------------------------------------------
242 # Handle scripts, dependencies, and setuptools specific things
244 # Handle scripts, dependencies, and setuptools specific things
243 #---------------------------------------------------------------------------
245 #---------------------------------------------------------------------------
244
246
245 # For some commands, use setuptools. Note that we do NOT list install here!
247 # For some commands, use setuptools. Note that we do NOT list install here!
246 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
248 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
247 needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
249 needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
248 'bdist', 'bdist_dumb', 'bdist_wininst', 'install_egg_info',
250 'bdist', 'bdist_dumb', 'bdist_wininst', 'install_egg_info',
249 'egg_info', 'easy_install', 'upload',
251 'egg_info', 'easy_install', 'upload',
250 ))
252 ))
251 if sys.platform == 'win32':
253 if sys.platform == 'win32':
252 # Depend on setuptools for install on *Windows only*
254 # Depend on setuptools for install on *Windows only*
253 # If we get script-installation working without setuptools,
255 # If we get script-installation working without setuptools,
254 # then we can back off, but until then use it.
256 # then we can back off, but until then use it.
255 # See Issue #369 on GitHub for more
257 # See Issue #369 on GitHub for more
256 needs_setuptools.add('install')
258 needs_setuptools.add('install')
257
259
258 if len(needs_setuptools.intersection(sys.argv)) > 0:
260 if len(needs_setuptools.intersection(sys.argv)) > 0:
259 import setuptools
261 import setuptools
260
262
261 # This dict is used for passing extra arguments that are setuptools
263 # This dict is used for passing extra arguments that are setuptools
262 # specific to setup
264 # specific to setup
263 setuptools_extra_args = {}
265 setuptools_extra_args = {}
264
266
265 if 'setuptools' in sys.modules:
267 if 'setuptools' in sys.modules:
266 # setup.py develop should check for submodules
268 # setup.py develop should check for submodules
267 from setuptools.command.develop import develop
269 from setuptools.command.develop import develop
268 setup_args['cmdclass']['develop'] = require_submodules(develop)
270 setup_args['cmdclass']['develop'] = require_submodules(develop)
269
271
270 setuptools_extra_args['zip_safe'] = False
272 setuptools_extra_args['zip_safe'] = False
271 setuptools_extra_args['entry_points'] = find_scripts(True)
273 setuptools_extra_args['entry_points'] = find_scripts(True)
272 setup_args['extras_require'] = dict(
274 setup_args['extras_require'] = dict(
273 parallel = 'pyzmq>=2.1.11',
275 parallel = 'pyzmq>=2.1.11',
274 qtconsole = ['pyzmq>=2.1.11', 'pygments'],
276 qtconsole = ['pyzmq>=2.1.11', 'pygments'],
275 zmq = 'pyzmq>=2.1.11',
277 zmq = 'pyzmq>=2.1.11',
276 doc = 'Sphinx>=0.3',
278 doc = 'Sphinx>=0.3',
277 test = 'nose>=0.10.1',
279 test = 'nose>=0.10.1',
278 notebook = ['tornado>=2.0', 'pyzmq>=2.1.11', 'jinja2'],
280 notebook = ['tornado>=2.0', 'pyzmq>=2.1.11', 'jinja2'],
279 nbconvert = ['pygments', 'jinja2', 'Sphinx>=0.3']
281 nbconvert = ['pygments', 'jinja2', 'Sphinx>=0.3']
280 )
282 )
281 everything = set()
283 everything = set()
282 for deps in setup_args['extras_require'].values():
284 for deps in setup_args['extras_require'].values():
283 if not isinstance(deps, list):
285 if not isinstance(deps, list):
284 deps = [deps]
286 deps = [deps]
285 for dep in deps:
287 for dep in deps:
286 everything.add(dep)
288 everything.add(dep)
287 setup_args['extras_require']['all'] = everything
289 setup_args['extras_require']['all'] = everything
288
290
289 requires = setup_args.setdefault('install_requires', [])
291 requires = setup_args.setdefault('install_requires', [])
290 setupext.display_status = False
292 setupext.display_status = False
291 if not setupext.check_for_readline():
293 if not setupext.check_for_readline():
292 if sys.platform == 'darwin':
294 if sys.platform == 'darwin':
293 requires.append('readline')
295 requires.append('readline')
294 elif sys.platform.startswith('win'):
296 elif sys.platform.startswith('win'):
295 # Pyreadline 64 bit windows issue solved in versions >=1.7.1
297 # Pyreadline 64 bit windows issue solved in versions >=1.7.1
296 # Also solves issues with some older versions of pyreadline that
298 # Also solves issues with some older versions of pyreadline that
297 # satisfy the unconstrained depdendency.
299 # satisfy the unconstrained depdendency.
298 requires.append('pyreadline>=1.7.1')
300 requires.append('pyreadline>=1.7.1')
299 else:
301 else:
300 pass
302 pass
301 # do we want to install readline here?
303 # do we want to install readline here?
302
304
303 # Script to be run by the windows binary installer after the default setup
305 # Script to be run by the windows binary installer after the default setup
304 # routine, to add shortcuts and similar windows-only things. Windows
306 # routine, to add shortcuts and similar windows-only things. Windows
305 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
307 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
306 # doesn't find them.
308 # doesn't find them.
307 if 'bdist_wininst' in sys.argv:
309 if 'bdist_wininst' in sys.argv:
308 if len(sys.argv) > 2 and \
310 if len(sys.argv) > 2 and \
309 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
311 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
310 print >> sys.stderr, "ERROR: bdist_wininst must be run alone. Exiting."
312 print >> sys.stderr, "ERROR: bdist_wininst must be run alone. Exiting."
311 sys.exit(1)
313 sys.exit(1)
312 setup_args['data_files'].append(
314 setup_args['data_files'].append(
313 ['Scripts', ('scripts/ipython.ico', 'scripts/ipython_nb.ico')])
315 ['Scripts', ('scripts/ipython.ico', 'scripts/ipython_nb.ico')])
314 setup_args['scripts'] = [pjoin('scripts','ipython_win_post_install.py')]
316 setup_args['scripts'] = [pjoin('scripts','ipython_win_post_install.py')]
315 setup_args['options'] = {"bdist_wininst":
317 setup_args['options'] = {"bdist_wininst":
316 {"install_script":
318 {"install_script":
317 "ipython_win_post_install.py"}}
319 "ipython_win_post_install.py"}}
318
320
319 if PY3:
321 if PY3:
320 setuptools_extra_args['use_2to3'] = True
322 setuptools_extra_args['use_2to3'] = True
321 # we try to make a 2.6, 2.7, and 3.1 to 3.3 python compatible code
323 # we try to make a 2.6, 2.7, and 3.1 to 3.3 python compatible code
322 # so we explicitly disable some 2to3 fixes to be sure we aren't forgetting
324 # so we explicitly disable some 2to3 fixes to be sure we aren't forgetting
323 # anything.
325 # anything.
324 setuptools_extra_args['use_2to3_exclude_fixers'] = [
326 setuptools_extra_args['use_2to3_exclude_fixers'] = [
325 'lib2to3.fixes.fix_apply',
327 'lib2to3.fixes.fix_apply',
326 'lib2to3.fixes.fix_except',
328 'lib2to3.fixes.fix_except',
327 'lib2to3.fixes.fix_has_key',
329 'lib2to3.fixes.fix_has_key',
328 'lib2to3.fixes.fix_next',
330 'lib2to3.fixes.fix_next',
329 'lib2to3.fixes.fix_repr',
331 'lib2to3.fixes.fix_repr',
330 'lib2to3.fixes.fix_tuple_params',
332 'lib2to3.fixes.fix_tuple_params',
331 ]
333 ]
332 from setuptools.command.build_py import build_py
334 from setuptools.command.build_py import build_py
333 setup_args['cmdclass'] = {'build_py': git_prebuild('IPython', build_cmd=build_py)}
335 setup_args['cmdclass'] = {'build_py': git_prebuild('IPython', build_cmd=build_py)}
334 setuptools_extra_args['entry_points'] = find_scripts(True, suffix='3')
336 setuptools_extra_args['entry_points'] = find_scripts(True, suffix='3')
335 setuptools._dont_write_bytecode = True
337 setuptools._dont_write_bytecode = True
336 else:
338 else:
337 # If we are running without setuptools, call this function which will
339 # If we are running without setuptools, call this function which will
338 # check for dependencies an inform the user what is needed. This is
340 # check for dependencies an inform the user what is needed. This is
339 # just to make life easy for users.
341 # just to make life easy for users.
340 check_for_dependencies()
342 check_for_dependencies()
341 setup_args['scripts'] = find_scripts(False)
343 setup_args['scripts'] = find_scripts(False)
342
344
343 #---------------------------------------------------------------------------
345 #---------------------------------------------------------------------------
344 # Do the actual setup now
346 # Do the actual setup now
345 #---------------------------------------------------------------------------
347 #---------------------------------------------------------------------------
346
348
347 setup_args.update(setuptools_extra_args)
349 setup_args.update(setuptools_extra_args)
348
350
349 def main():
351 def main():
350 setup(**setup_args)
352 setup(**setup_args)
351 cleanup()
353 cleanup()
352
354
353 if __name__ == '__main__':
355 if __name__ == '__main__':
354 main()
356 main()
@@ -1,476 +1,500 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 This module defines the things that are used in setup.py for building IPython
3 This module defines the things that are used in setup.py for building IPython
4
4
5 This includes:
5 This includes:
6
6
7 * The basic arguments to setup
7 * The basic arguments to setup
8 * Functions for finding things like packages, package data, etc.
8 * Functions for finding things like packages, package data, etc.
9 * A function for checking dependencies.
9 * A function for checking dependencies.
10 """
10 """
11 from __future__ import print_function
11 from __future__ import print_function
12
12
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14 # Copyright (C) 2008 The IPython Development Team
14 # Copyright (C) 2008 The IPython Development Team
15 #
15 #
16 # Distributed under the terms of the BSD License. The full license is in
16 # Distributed under the terms of the BSD License. The full license is in
17 # the file COPYING, distributed as part of this software.
17 # the file COPYING, distributed as part of this software.
18 #-------------------------------------------------------------------------------
18 #-------------------------------------------------------------------------------
19
19
20 #-------------------------------------------------------------------------------
20 #-------------------------------------------------------------------------------
21 # Imports
21 # Imports
22 #-------------------------------------------------------------------------------
22 #-------------------------------------------------------------------------------
23 import os
23 import os
24 import sys
24 import sys
25
25
26 try:
26 try:
27 from configparser import ConfigParser
27 from configparser import ConfigParser
28 except:
28 except:
29 from ConfigParser import ConfigParser
29 from ConfigParser import ConfigParser
30 from distutils.command.build_py import build_py
30 from distutils.command.build_py import build_py
31 from distutils.cmd import Command
31 from distutils.cmd import Command
32 from glob import glob
32 from glob import glob
33 from subprocess import call
33
34
34 from setupext import install_data_ext
35 from setupext import install_data_ext
35
36
36 #-------------------------------------------------------------------------------
37 #-------------------------------------------------------------------------------
37 # Useful globals and utility functions
38 # Useful globals and utility functions
38 #-------------------------------------------------------------------------------
39 #-------------------------------------------------------------------------------
39
40
40 # A few handy globals
41 # A few handy globals
41 isfile = os.path.isfile
42 isfile = os.path.isfile
42 pjoin = os.path.join
43 pjoin = os.path.join
43 repo_root = os.path.dirname(os.path.abspath(__file__))
44 repo_root = os.path.dirname(os.path.abspath(__file__))
44
45
45 def oscmd(s):
46 def oscmd(s):
46 print(">", s)
47 print(">", s)
47 os.system(s)
48 os.system(s)
48
49
49 # Py3 compatibility hacks, without assuming IPython itself is installed with
50 # Py3 compatibility hacks, without assuming IPython itself is installed with
50 # the full py3compat machinery.
51 # the full py3compat machinery.
51
52
52 try:
53 try:
53 execfile
54 execfile
54 except NameError:
55 except NameError:
55 def execfile(fname, globs, locs=None):
56 def execfile(fname, globs, locs=None):
56 locs = locs or globs
57 locs = locs or globs
57 exec(compile(open(fname).read(), fname, "exec"), globs, locs)
58 exec(compile(open(fname).read(), fname, "exec"), globs, locs)
58
59
59 # A little utility we'll need below, since glob() does NOT allow you to do
60 # A little utility we'll need below, since glob() does NOT allow you to do
60 # exclusion on multiple endings!
61 # exclusion on multiple endings!
61 def file_doesnt_endwith(test,endings):
62 def file_doesnt_endwith(test,endings):
62 """Return true if test is a file and its name does NOT end with any
63 """Return true if test is a file and its name does NOT end with any
63 of the strings listed in endings."""
64 of the strings listed in endings."""
64 if not isfile(test):
65 if not isfile(test):
65 return False
66 return False
66 for e in endings:
67 for e in endings:
67 if test.endswith(e):
68 if test.endswith(e):
68 return False
69 return False
69 return True
70 return True
70
71
71 #---------------------------------------------------------------------------
72 #---------------------------------------------------------------------------
72 # Basic project information
73 # Basic project information
73 #---------------------------------------------------------------------------
74 #---------------------------------------------------------------------------
74
75
75 # release.py contains version, authors, license, url, keywords, etc.
76 # release.py contains version, authors, license, url, keywords, etc.
76 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
77 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
77
78
78 # Create a dict with the basic information
79 # Create a dict with the basic information
79 # This dict is eventually passed to setup after additional keys are added.
80 # This dict is eventually passed to setup after additional keys are added.
80 setup_args = dict(
81 setup_args = dict(
81 name = name,
82 name = name,
82 version = version,
83 version = version,
83 description = description,
84 description = description,
84 long_description = long_description,
85 long_description = long_description,
85 author = author,
86 author = author,
86 author_email = author_email,
87 author_email = author_email,
87 url = url,
88 url = url,
88 download_url = download_url,
89 download_url = download_url,
89 license = license,
90 license = license,
90 platforms = platforms,
91 platforms = platforms,
91 keywords = keywords,
92 keywords = keywords,
92 classifiers = classifiers,
93 classifiers = classifiers,
93 cmdclass = {'install_data': install_data_ext},
94 cmdclass = {'install_data': install_data_ext},
94 )
95 )
95
96
96
97
97 #---------------------------------------------------------------------------
98 #---------------------------------------------------------------------------
98 # Find packages
99 # Find packages
99 #---------------------------------------------------------------------------
100 #---------------------------------------------------------------------------
100
101
101 def find_packages():
102 def find_packages():
102 """
103 """
103 Find all of IPython's packages.
104 Find all of IPython's packages.
104 """
105 """
105 excludes = ['deathrow', 'quarantine']
106 excludes = ['deathrow', 'quarantine']
106 packages = []
107 packages = []
107 for dir,subdirs,files in os.walk('IPython'):
108 for dir,subdirs,files in os.walk('IPython'):
108 package = dir.replace(os.path.sep, '.')
109 package = dir.replace(os.path.sep, '.')
109 if any(package.startswith('IPython.'+exc) for exc in excludes):
110 if any(package.startswith('IPython.'+exc) for exc in excludes):
110 # package is to be excluded (e.g. deathrow)
111 # package is to be excluded (e.g. deathrow)
111 continue
112 continue
112 if '__init__.py' not in files:
113 if '__init__.py' not in files:
113 # not a package
114 # not a package
114 continue
115 continue
115 packages.append(package)
116 packages.append(package)
116 return packages
117 return packages
117
118
118 #---------------------------------------------------------------------------
119 #---------------------------------------------------------------------------
119 # Find package data
120 # Find package data
120 #---------------------------------------------------------------------------
121 #---------------------------------------------------------------------------
121
122
122 def find_package_data():
123 def find_package_data():
123 """
124 """
124 Find IPython's package_data.
125 Find IPython's package_data.
125 """
126 """
126 # This is not enough for these things to appear in an sdist.
127 # This is not enough for these things to appear in an sdist.
127 # We need to muck with the MANIFEST to get this to work
128 # We need to muck with the MANIFEST to get this to work
128
129
129 # exclude static things that we don't ship (e.g. mathjax)
130 # exclude static things that we don't ship (e.g. mathjax)
130 excludes = ['mathjax']
131 excludes = ['mathjax']
131
132
132 # add 'static/' prefix to exclusions, and tuplify for use in startswith
133 # add 'static/' prefix to exclusions, and tuplify for use in startswith
133 excludes = tuple([os.path.join('static', ex) for ex in excludes])
134 excludes = tuple([os.path.join('static', ex) for ex in excludes])
134
135
135 # walk notebook resources:
136 # walk notebook resources:
136 cwd = os.getcwd()
137 cwd = os.getcwd()
137 os.chdir(os.path.join('IPython', 'html'))
138 os.chdir(os.path.join('IPython', 'html'))
138 static_walk = list(os.walk('static'))
139 static_walk = list(os.walk('static'))
139 os.chdir(cwd)
140 os.chdir(cwd)
140 static_data = []
141 static_data = []
141 for parent, dirs, files in static_walk:
142 for parent, dirs, files in static_walk:
142 if parent.startswith(excludes):
143 if parent.startswith(excludes):
143 continue
144 continue
144 for f in files:
145 for f in files:
145 static_data.append(os.path.join(parent, f))
146 static_data.append(os.path.join(parent, f))
146
147
147 package_data = {
148 package_data = {
148 'IPython.config.profile' : ['README*', '*/*.py'],
149 'IPython.config.profile' : ['README*', '*/*.py'],
149 'IPython.core.tests' : ['*.png', '*.jpg'],
150 'IPython.core.tests' : ['*.png', '*.jpg'],
150 'IPython.testing' : ['*.txt'],
151 'IPython.testing' : ['*.txt'],
151 'IPython.testing.plugin' : ['*.txt'],
152 'IPython.testing.plugin' : ['*.txt'],
152 'IPython.html' : ['templates/*'] + static_data,
153 'IPython.html' : ['templates/*'] + static_data,
153 'IPython.qt.console' : ['resources/icon/*.svg'],
154 'IPython.qt.console' : ['resources/icon/*.svg'],
154 'IPython.nbconvert' : ['templates/*.tpl', 'templates/latex/*.tplx',
155 'IPython.nbconvert' : ['templates/*.tpl', 'templates/latex/*.tplx',
155 'templates/latex/skeleton/*.tplx', 'templates/skeleton/*',
156 'templates/latex/skeleton/*.tplx', 'templates/skeleton/*',
156 'templates/reveal_internals/*.tpl', 'tests/files/*.*',
157 'templates/reveal_internals/*.tpl', 'tests/files/*.*',
157 'exporters/tests/files/*.*']
158 'exporters/tests/files/*.*']
158 }
159 }
159 return package_data
160 return package_data
160
161
161
162
162 #---------------------------------------------------------------------------
163 #---------------------------------------------------------------------------
163 # Find data files
164 # Find data files
164 #---------------------------------------------------------------------------
165 #---------------------------------------------------------------------------
165
166
166 def make_dir_struct(tag,base,out_base):
167 def make_dir_struct(tag,base,out_base):
167 """Make the directory structure of all files below a starting dir.
168 """Make the directory structure of all files below a starting dir.
168
169
169 This is just a convenience routine to help build a nested directory
170 This is just a convenience routine to help build a nested directory
170 hierarchy because distutils is too stupid to do this by itself.
171 hierarchy because distutils is too stupid to do this by itself.
171
172
172 XXX - this needs a proper docstring!
173 XXX - this needs a proper docstring!
173 """
174 """
174
175
175 # we'll use these a lot below
176 # we'll use these a lot below
176 lbase = len(base)
177 lbase = len(base)
177 pathsep = os.path.sep
178 pathsep = os.path.sep
178 lpathsep = len(pathsep)
179 lpathsep = len(pathsep)
179
180
180 out = []
181 out = []
181 for (dirpath,dirnames,filenames) in os.walk(base):
182 for (dirpath,dirnames,filenames) in os.walk(base):
182 # we need to strip out the dirpath from the base to map it to the
183 # we need to strip out the dirpath from the base to map it to the
183 # output (installation) path. This requires possibly stripping the
184 # output (installation) path. This requires possibly stripping the
184 # path separator, because otherwise pjoin will not work correctly
185 # path separator, because otherwise pjoin will not work correctly
185 # (pjoin('foo/','/bar') returns '/bar').
186 # (pjoin('foo/','/bar') returns '/bar').
186
187
187 dp_eff = dirpath[lbase:]
188 dp_eff = dirpath[lbase:]
188 if dp_eff.startswith(pathsep):
189 if dp_eff.startswith(pathsep):
189 dp_eff = dp_eff[lpathsep:]
190 dp_eff = dp_eff[lpathsep:]
190 # The output path must be anchored at the out_base marker
191 # The output path must be anchored at the out_base marker
191 out_path = pjoin(out_base,dp_eff)
192 out_path = pjoin(out_base,dp_eff)
192 # Now we can generate the final filenames. Since os.walk only produces
193 # Now we can generate the final filenames. Since os.walk only produces
193 # filenames, we must join back with the dirpath to get full valid file
194 # filenames, we must join back with the dirpath to get full valid file
194 # paths:
195 # paths:
195 pfiles = [pjoin(dirpath,f) for f in filenames]
196 pfiles = [pjoin(dirpath,f) for f in filenames]
196 # Finally, generate the entry we need, which is a pari of (output
197 # Finally, generate the entry we need, which is a pari of (output
197 # path, files) for use as a data_files parameter in install_data.
198 # path, files) for use as a data_files parameter in install_data.
198 out.append((out_path, pfiles))
199 out.append((out_path, pfiles))
199
200
200 return out
201 return out
201
202
202
203
203 def find_data_files():
204 def find_data_files():
204 """
205 """
205 Find IPython's data_files.
206 Find IPython's data_files.
206
207
207 Most of these are docs.
208 Most of these are docs.
208 """
209 """
209
210
210 docdirbase = pjoin('share', 'doc', 'ipython')
211 docdirbase = pjoin('share', 'doc', 'ipython')
211 manpagebase = pjoin('share', 'man', 'man1')
212 manpagebase = pjoin('share', 'man', 'man1')
212
213
213 # Simple file lists can be made by hand
214 # Simple file lists can be made by hand
214 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
215 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
215 if not manpages:
216 if not manpages:
216 # When running from a source tree, the manpages aren't gzipped
217 # When running from a source tree, the manpages aren't gzipped
217 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
218 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
218
219
219 igridhelpfiles = [f for f in glob(pjoin('IPython','extensions','igrid_help.*')) if isfile(f)]
220 igridhelpfiles = [f for f in glob(pjoin('IPython','extensions','igrid_help.*')) if isfile(f)]
220
221
221 # For nested structures, use the utility above
222 # For nested structures, use the utility above
222 example_files = make_dir_struct(
223 example_files = make_dir_struct(
223 'data',
224 'data',
224 pjoin('docs','examples'),
225 pjoin('docs','examples'),
225 pjoin(docdirbase,'examples')
226 pjoin(docdirbase,'examples')
226 )
227 )
227 manual_files = make_dir_struct(
228 manual_files = make_dir_struct(
228 'data',
229 'data',
229 pjoin('docs','html'),
230 pjoin('docs','html'),
230 pjoin(docdirbase,'manual')
231 pjoin(docdirbase,'manual')
231 )
232 )
232
233
233 # And assemble the entire output list
234 # And assemble the entire output list
234 data_files = [ (manpagebase, manpages),
235 data_files = [ (manpagebase, manpages),
235 (pjoin(docdirbase, 'extensions'), igridhelpfiles),
236 (pjoin(docdirbase, 'extensions'), igridhelpfiles),
236 ] + manual_files + example_files
237 ] + manual_files + example_files
237
238
238 return data_files
239 return data_files
239
240
240
241
241 def make_man_update_target(manpage):
242 def make_man_update_target(manpage):
242 """Return a target_update-compliant tuple for the given manpage.
243 """Return a target_update-compliant tuple for the given manpage.
243
244
244 Parameters
245 Parameters
245 ----------
246 ----------
246 manpage : string
247 manpage : string
247 Name of the manpage, must include the section number (trailing number).
248 Name of the manpage, must include the section number (trailing number).
248
249
249 Example
250 Example
250 -------
251 -------
251
252
252 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
253 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
253 ('docs/man/ipython.1.gz',
254 ('docs/man/ipython.1.gz',
254 ['docs/man/ipython.1'],
255 ['docs/man/ipython.1'],
255 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
256 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
256 """
257 """
257 man_dir = pjoin('docs', 'man')
258 man_dir = pjoin('docs', 'man')
258 manpage_gz = manpage + '.gz'
259 manpage_gz = manpage + '.gz'
259 manpath = pjoin(man_dir, manpage)
260 manpath = pjoin(man_dir, manpage)
260 manpath_gz = pjoin(man_dir, manpage_gz)
261 manpath_gz = pjoin(man_dir, manpage_gz)
261 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
262 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
262 locals() )
263 locals() )
263 return (manpath_gz, [manpath], gz_cmd)
264 return (manpath_gz, [manpath], gz_cmd)
264
265
265 # The two functions below are copied from IPython.utils.path, so we don't need
266 # The two functions below are copied from IPython.utils.path, so we don't need
266 # to import IPython during setup, which fails on Python 3.
267 # to import IPython during setup, which fails on Python 3.
267
268
268 def target_outdated(target,deps):
269 def target_outdated(target,deps):
269 """Determine whether a target is out of date.
270 """Determine whether a target is out of date.
270
271
271 target_outdated(target,deps) -> 1/0
272 target_outdated(target,deps) -> 1/0
272
273
273 deps: list of filenames which MUST exist.
274 deps: list of filenames which MUST exist.
274 target: single filename which may or may not exist.
275 target: single filename which may or may not exist.
275
276
276 If target doesn't exist or is older than any file listed in deps, return
277 If target doesn't exist or is older than any file listed in deps, return
277 true, otherwise return false.
278 true, otherwise return false.
278 """
279 """
279 try:
280 try:
280 target_time = os.path.getmtime(target)
281 target_time = os.path.getmtime(target)
281 except os.error:
282 except os.error:
282 return 1
283 return 1
283 for dep in deps:
284 for dep in deps:
284 dep_time = os.path.getmtime(dep)
285 dep_time = os.path.getmtime(dep)
285 if dep_time > target_time:
286 if dep_time > target_time:
286 #print "For target",target,"Dep failed:",dep # dbg
287 #print "For target",target,"Dep failed:",dep # dbg
287 #print "times (dep,tar):",dep_time,target_time # dbg
288 #print "times (dep,tar):",dep_time,target_time # dbg
288 return 1
289 return 1
289 return 0
290 return 0
290
291
291
292
292 def target_update(target,deps,cmd):
293 def target_update(target,deps,cmd):
293 """Update a target with a given command given a list of dependencies.
294 """Update a target with a given command given a list of dependencies.
294
295
295 target_update(target,deps,cmd) -> runs cmd if target is outdated.
296 target_update(target,deps,cmd) -> runs cmd if target is outdated.
296
297
297 This is just a wrapper around target_outdated() which calls the given
298 This is just a wrapper around target_outdated() which calls the given
298 command if target is outdated."""
299 command if target is outdated."""
299
300
300 if target_outdated(target,deps):
301 if target_outdated(target,deps):
301 os.system(cmd)
302 os.system(cmd)
302
303
303 #---------------------------------------------------------------------------
304 #---------------------------------------------------------------------------
304 # Find scripts
305 # Find scripts
305 #---------------------------------------------------------------------------
306 #---------------------------------------------------------------------------
306
307
307 def find_scripts(entry_points=False, suffix=''):
308 def find_scripts(entry_points=False, suffix=''):
308 """Find IPython's scripts.
309 """Find IPython's scripts.
309
310
310 if entry_points is True:
311 if entry_points is True:
311 return setuptools entry_point-style definitions
312 return setuptools entry_point-style definitions
312 else:
313 else:
313 return file paths of plain scripts [default]
314 return file paths of plain scripts [default]
314
315
315 suffix is appended to script names if entry_points is True, so that the
316 suffix is appended to script names if entry_points is True, so that the
316 Python 3 scripts get named "ipython3" etc.
317 Python 3 scripts get named "ipython3" etc.
317 """
318 """
318 if entry_points:
319 if entry_points:
319 console_scripts = [s % suffix for s in [
320 console_scripts = [s % suffix for s in [
320 'ipython%s = IPython:start_ipython',
321 'ipython%s = IPython:start_ipython',
321 'pycolor%s = IPython.utils.PyColorize:main',
322 'pycolor%s = IPython.utils.PyColorize:main',
322 'ipcontroller%s = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
323 'ipcontroller%s = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
323 'ipengine%s = IPython.parallel.apps.ipengineapp:launch_new_instance',
324 'ipengine%s = IPython.parallel.apps.ipengineapp:launch_new_instance',
324 'iplogger%s = IPython.parallel.apps.iploggerapp:launch_new_instance',
325 'iplogger%s = IPython.parallel.apps.iploggerapp:launch_new_instance',
325 'ipcluster%s = IPython.parallel.apps.ipclusterapp:launch_new_instance',
326 'ipcluster%s = IPython.parallel.apps.ipclusterapp:launch_new_instance',
326 'iptest%s = IPython.testing.iptestcontroller:main',
327 'iptest%s = IPython.testing.iptestcontroller:main',
327 'irunner%s = IPython.lib.irunner:main',
328 'irunner%s = IPython.lib.irunner:main',
328 ]]
329 ]]
329 gui_scripts = []
330 gui_scripts = []
330 scripts = dict(console_scripts=console_scripts, gui_scripts=gui_scripts)
331 scripts = dict(console_scripts=console_scripts, gui_scripts=gui_scripts)
331 else:
332 else:
332 parallel_scripts = pjoin('IPython','parallel','scripts')
333 parallel_scripts = pjoin('IPython','parallel','scripts')
333 main_scripts = pjoin('IPython','scripts')
334 main_scripts = pjoin('IPython','scripts')
334 scripts = [
335 scripts = [
335 pjoin(parallel_scripts, 'ipengine'),
336 pjoin(parallel_scripts, 'ipengine'),
336 pjoin(parallel_scripts, 'ipcontroller'),
337 pjoin(parallel_scripts, 'ipcontroller'),
337 pjoin(parallel_scripts, 'ipcluster'),
338 pjoin(parallel_scripts, 'ipcluster'),
338 pjoin(parallel_scripts, 'iplogger'),
339 pjoin(parallel_scripts, 'iplogger'),
339 pjoin(main_scripts, 'ipython'),
340 pjoin(main_scripts, 'ipython'),
340 pjoin(main_scripts, 'pycolor'),
341 pjoin(main_scripts, 'pycolor'),
341 pjoin(main_scripts, 'irunner'),
342 pjoin(main_scripts, 'irunner'),
342 pjoin(main_scripts, 'iptest')
343 pjoin(main_scripts, 'iptest')
343 ]
344 ]
344 return scripts
345 return scripts
345
346
346 #---------------------------------------------------------------------------
347 #---------------------------------------------------------------------------
347 # Verify all dependencies
348 # Verify all dependencies
348 #---------------------------------------------------------------------------
349 #---------------------------------------------------------------------------
349
350
350 def check_for_dependencies():
351 def check_for_dependencies():
351 """Check for IPython's dependencies.
352 """Check for IPython's dependencies.
352
353
353 This function should NOT be called if running under setuptools!
354 This function should NOT be called if running under setuptools!
354 """
355 """
355 from setupext.setupext import (
356 from setupext.setupext import (
356 print_line, print_raw, print_status,
357 print_line, print_raw, print_status,
357 check_for_sphinx, check_for_pygments,
358 check_for_sphinx, check_for_pygments,
358 check_for_nose, check_for_pexpect,
359 check_for_nose, check_for_pexpect,
359 check_for_pyzmq, check_for_readline,
360 check_for_pyzmq, check_for_readline,
360 check_for_jinja2, check_for_tornado
361 check_for_jinja2, check_for_tornado
361 )
362 )
362 print_line()
363 print_line()
363 print_raw("BUILDING IPYTHON")
364 print_raw("BUILDING IPYTHON")
364 print_status('python', sys.version)
365 print_status('python', sys.version)
365 print_status('platform', sys.platform)
366 print_status('platform', sys.platform)
366 if sys.platform == 'win32':
367 if sys.platform == 'win32':
367 print_status('Windows version', sys.getwindowsversion())
368 print_status('Windows version', sys.getwindowsversion())
368
369
369 print_raw("")
370 print_raw("")
370 print_raw("OPTIONAL DEPENDENCIES")
371 print_raw("OPTIONAL DEPENDENCIES")
371
372
372 check_for_sphinx()
373 check_for_sphinx()
373 check_for_pygments()
374 check_for_pygments()
374 check_for_nose()
375 check_for_nose()
375 check_for_pexpect()
376 check_for_pexpect()
376 check_for_pyzmq()
377 check_for_pyzmq()
377 check_for_tornado()
378 check_for_tornado()
378 check_for_readline()
379 check_for_readline()
379 check_for_jinja2()
380 check_for_jinja2()
380
381
381 #---------------------------------------------------------------------------
382 #---------------------------------------------------------------------------
382 # VCS related
383 # VCS related
383 #---------------------------------------------------------------------------
384 #---------------------------------------------------------------------------
384
385
385 # utils.submodule has checks for submodule status
386 # utils.submodule has checks for submodule status
386 execfile(pjoin('IPython','utils','submodule.py'), globals())
387 execfile(pjoin('IPython','utils','submodule.py'), globals())
387
388
388 class UpdateSubmodules(Command):
389 class UpdateSubmodules(Command):
389 """Update git submodules
390 """Update git submodules
390
391
391 IPython's external javascript dependencies live in a separate repo.
392 IPython's external javascript dependencies live in a separate repo.
392 """
393 """
393 description = "Update git submodules"
394 description = "Update git submodules"
394 user_options = []
395 user_options = []
395
396
396 def initialize_options(self):
397 def initialize_options(self):
397 pass
398 pass
398
399
399 def finalize_options(self):
400 def finalize_options(self):
400 pass
401 pass
401
402
402 def run(self):
403 def run(self):
403 failure = False
404 failure = False
404 try:
405 try:
405 self.spawn('git submodule init'.split())
406 self.spawn('git submodule init'.split())
406 self.spawn('git submodule update --recursive'.split())
407 self.spawn('git submodule update --recursive'.split())
407 except Exception as e:
408 except Exception as e:
408 failure = e
409 failure = e
409 print(e)
410 print(e)
410
411
411 if not check_submodule_status(repo_root) == 'clean':
412 if not check_submodule_status(repo_root) == 'clean':
412 print("submodules could not be checked out")
413 print("submodules could not be checked out")
413 sys.exit(1)
414 sys.exit(1)
414
415
415
416
416 def git_prebuild(pkg_dir, build_cmd=build_py):
417 def git_prebuild(pkg_dir, build_cmd=build_py):
417 """Return extended build or sdist command class for recording commit
418 """Return extended build or sdist command class for recording commit
418
419
419 records git commit in IPython.utils._sysinfo.commit
420 records git commit in IPython.utils._sysinfo.commit
420
421
421 for use in IPython.utils.sysinfo.sys_info() calls after installation.
422 for use in IPython.utils.sysinfo.sys_info() calls after installation.
422
423
423 Also ensures that submodules exist prior to running
424 Also ensures that submodules exist prior to running
424 """
425 """
425
426
426 class MyBuildPy(build_cmd):
427 class MyBuildPy(build_cmd):
427 ''' Subclass to write commit data into installation tree '''
428 ''' Subclass to write commit data into installation tree '''
428 def run(self):
429 def run(self):
429 build_cmd.run(self)
430 build_cmd.run(self)
430 # this one will only fire for build commands
431 # this one will only fire for build commands
431 if hasattr(self, 'build_lib'):
432 if hasattr(self, 'build_lib'):
432 self._record_commit(self.build_lib)
433 self._record_commit(self.build_lib)
433
434
434 def make_release_tree(self, base_dir, files):
435 def make_release_tree(self, base_dir, files):
435 # this one will fire for sdist
436 # this one will fire for sdist
436 build_cmd.make_release_tree(self, base_dir, files)
437 build_cmd.make_release_tree(self, base_dir, files)
437 self._record_commit(base_dir)
438 self._record_commit(base_dir)
438
439
439 def _record_commit(self, base_dir):
440 def _record_commit(self, base_dir):
440 import subprocess
441 import subprocess
441 proc = subprocess.Popen('git rev-parse --short HEAD',
442 proc = subprocess.Popen('git rev-parse --short HEAD',
442 stdout=subprocess.PIPE,
443 stdout=subprocess.PIPE,
443 stderr=subprocess.PIPE,
444 stderr=subprocess.PIPE,
444 shell=True)
445 shell=True)
445 repo_commit, _ = proc.communicate()
446 repo_commit, _ = proc.communicate()
446 repo_commit = repo_commit.strip().decode("ascii")
447 repo_commit = repo_commit.strip().decode("ascii")
447
448
448 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
449 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
449 if os.path.isfile(out_pth) and not repo_commit:
450 if os.path.isfile(out_pth) and not repo_commit:
450 # nothing to write, don't clobber
451 # nothing to write, don't clobber
451 return
452 return
452
453
453 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
454 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
454
455
455 # remove to avoid overwriting original via hard link
456 # remove to avoid overwriting original via hard link
456 try:
457 try:
457 os.remove(out_pth)
458 os.remove(out_pth)
458 except (IOError, OSError):
459 except (IOError, OSError):
459 pass
460 pass
460 with open(out_pth, 'w') as out_file:
461 with open(out_pth, 'w') as out_file:
461 out_file.writelines([
462 out_file.writelines([
462 '# GENERATED BY setup.py\n',
463 '# GENERATED BY setup.py\n',
463 'commit = "%s"\n' % repo_commit,
464 'commit = "%s"\n' % repo_commit,
464 ])
465 ])
465 return require_submodules(MyBuildPy)
466 return require_submodules(MyBuildPy)
466
467
467
468
468 def require_submodules(command):
469 def require_submodules(command):
469 """decorator for instructing a command to check for submodules before running"""
470 """decorator for instructing a command to check for submodules before running"""
470 class DecoratedCommand(command):
471 class DecoratedCommand(command):
471 def run(self):
472 def run(self):
472 if not check_submodule_status(repo_root) == 'clean':
473 if not check_submodule_status(repo_root) == 'clean':
473 print("submodules missing! Run `setup.py submodule` and try again")
474 print("submodules missing! Run `setup.py submodule` and try again")
474 sys.exit(1)
475 sys.exit(1)
475 command.run(self)
476 command.run(self)
476 return DecoratedCommand
477 return DecoratedCommand
478
479 #---------------------------------------------------------------------------
480 # Notebook related
481 #---------------------------------------------------------------------------
482
483 class CompileCSS(Command):
484 """Recompile Notebook CSS
485
486 Regenerate the compiled CSS from LESS sources.
487
488 Requires various dev dependencies, such as fabric and lessc.
489 """
490 description = "Recompile Notebook CSS"
491 user_options = []
492
493 def initialize_options(self):
494 pass
495
496 def finalize_options(self):
497 pass
498
499 def run(self):
500 call("fab css", shell=True, cwd=pjoin(repo_root, "IPython", "html"))
General Comments 0
You need to be logged in to leave comments. Login now