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