##// END OF EJS Templates
add strict arg to css_js setup decorator...
MinRK -
Show More
@@ -1,353 +1,355 b''
1 1 #!/usr/bin/env python
2 2 # -*- coding: utf-8 -*-
3 3 """Setup script for IPython.
4 4
5 5 Under Posix environments it works like a typical setup.py script.
6 6 Under Windows, the command sdist is not supported, since IPython
7 7 requires utilities which are not available under Windows."""
8 8
9 9 #-----------------------------------------------------------------------------
10 10 # Copyright (c) 2008-2011, IPython Development Team.
11 11 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
12 12 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
13 13 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
14 14 #
15 15 # Distributed under the terms of the Modified BSD License.
16 16 #
17 17 # The full license is in the file COPYING.rst, distributed with this software.
18 18 #-----------------------------------------------------------------------------
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Minimal Python version sanity check
22 22 #-----------------------------------------------------------------------------
23 23 from __future__ import print_function
24 24
25 25 import sys
26 26
27 27 # This check is also made in IPython/__init__, don't forget to update both when
28 28 # changing Python version requirements.
29 29 v = sys.version_info
30 30 if v[:2] < (2,7) or (v[0] >= 3 and v[:2] < (3,3)):
31 31 error = "ERROR: IPython requires Python version 2.7 or 3.3 or above."
32 32 print(error, file=sys.stderr)
33 33 sys.exit(1)
34 34
35 35 PY3 = (sys.version_info[0] >= 3)
36 36
37 37 # At least we're on the python version we need, move on.
38 38
39 39 #-------------------------------------------------------------------------------
40 40 # Imports
41 41 #-------------------------------------------------------------------------------
42 42
43 43 # Stdlib imports
44 44 import os
45 45 import shutil
46 46
47 47 from glob import glob
48 48
49 49 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
50 50 # update it when the contents of directories change.
51 51 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
52 52
53 53 from distutils.core import setup
54 54
55 55 # Our own imports
56 56 from setupbase import target_update
57 57
58 58 from setupbase import (
59 59 setup_args,
60 60 find_packages,
61 61 find_package_data,
62 62 check_package_data_first,
63 63 find_entry_points,
64 64 build_scripts_entrypt,
65 65 find_data_files,
66 66 check_for_dependencies,
67 67 git_prebuild,
68 68 check_submodule_status,
69 69 update_submodules,
70 70 require_submodules,
71 71 UpdateSubmodules,
72 72 get_bdist_wheel,
73 73 CompileCSS,
74 74 JavascriptVersion,
75 75 css_js_prerelease,
76 76 install_symlinked,
77 77 install_lib_symlink,
78 78 install_scripts_for_symlink,
79 79 unsymlink,
80 80 )
81 81 from setupext import setupext
82 82
83 83 isfile = os.path.isfile
84 84 pjoin = os.path.join
85 85
86 86 #-----------------------------------------------------------------------------
87 87 # Function definitions
88 88 #-----------------------------------------------------------------------------
89 89
90 90 def cleanup():
91 91 """Clean up the junk left around by the build process"""
92 92 if "develop" not in sys.argv and "egg_info" not in sys.argv:
93 93 try:
94 94 shutil.rmtree('ipython.egg-info')
95 95 except:
96 96 try:
97 97 os.unlink('ipython.egg-info')
98 98 except:
99 99 pass
100 100
101 101 #-------------------------------------------------------------------------------
102 102 # Handle OS specific things
103 103 #-------------------------------------------------------------------------------
104 104
105 105 if os.name in ('nt','dos'):
106 106 os_name = 'windows'
107 107 else:
108 108 os_name = os.name
109 109
110 110 # Under Windows, 'sdist' has not been supported. Now that the docs build with
111 111 # Sphinx it might work, but let's not turn it on until someone confirms that it
112 112 # actually works.
113 113 if os_name == 'windows' and 'sdist' in sys.argv:
114 114 print('The sdist command is not available under Windows. Exiting.')
115 115 sys.exit(1)
116 116
117 117 #-------------------------------------------------------------------------------
118 118 # Make sure we aren't trying to run without submodules
119 119 #-------------------------------------------------------------------------------
120 120 here = os.path.abspath(os.path.dirname(__file__))
121 121
122 122 def require_clean_submodules():
123 123 """Check on git submodules before distutils can do anything
124 124
125 125 Since distutils cannot be trusted to update the tree
126 126 after everything has been set in motion,
127 127 this is not a distutils command.
128 128 """
129 129 # PACKAGERS: Add a return here to skip checks for git submodules
130 130
131 131 # don't do anything if nothing is actually supposed to happen
132 132 for do_nothing in ('-h', '--help', '--help-commands', 'clean', 'submodule'):
133 133 if do_nothing in sys.argv:
134 134 return
135 135
136 136 status = check_submodule_status(here)
137 137
138 138 if status == "missing":
139 139 print("checking out submodules for the first time")
140 140 update_submodules(here)
141 141 elif status == "unclean":
142 142 print('\n'.join([
143 143 "Cannot build / install IPython with unclean submodules",
144 144 "Please update submodules with",
145 145 " python setup.py submodule",
146 146 "or",
147 147 " git submodule update",
148 148 "or commit any submodule changes you have made."
149 149 ]))
150 150 sys.exit(1)
151 151
152 152 require_clean_submodules()
153 153
154 154 #-------------------------------------------------------------------------------
155 155 # Things related to the IPython documentation
156 156 #-------------------------------------------------------------------------------
157 157
158 158 # update the manuals when building a source dist
159 159 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
160 160
161 161 # List of things to be updated. Each entry is a triplet of args for
162 162 # target_update()
163 163 to_update = [
164 164 # FIXME - Disabled for now: we need to redo an automatic way
165 165 # of generating the magic info inside the rst.
166 166 #('docs/magic.tex',
167 167 #['IPython/Magic.py'],
168 168 #"cd doc && ./update_magic.sh" ),
169 169
170 170 ('docs/man/ipcluster.1.gz',
171 171 ['docs/man/ipcluster.1'],
172 172 'cd docs/man && gzip -9c ipcluster.1 > ipcluster.1.gz'),
173 173
174 174 ('docs/man/ipcontroller.1.gz',
175 175 ['docs/man/ipcontroller.1'],
176 176 'cd docs/man && gzip -9c ipcontroller.1 > ipcontroller.1.gz'),
177 177
178 178 ('docs/man/ipengine.1.gz',
179 179 ['docs/man/ipengine.1'],
180 180 'cd docs/man && gzip -9c ipengine.1 > ipengine.1.gz'),
181 181
182 182 ('docs/man/ipython.1.gz',
183 183 ['docs/man/ipython.1'],
184 184 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
185 185
186 186 ]
187 187
188 188
189 189 [ target_update(*t) for t in to_update ]
190 190
191 191 #---------------------------------------------------------------------------
192 192 # Find all the packages, package data, and data_files
193 193 #---------------------------------------------------------------------------
194 194
195 195 packages = find_packages()
196 196 package_data = find_package_data()
197 197
198 198 data_files = find_data_files()
199 199
200 200 setup_args['packages'] = packages
201 201 setup_args['package_data'] = package_data
202 202 setup_args['data_files'] = data_files
203 203
204 204 #---------------------------------------------------------------------------
205 205 # custom distutils commands
206 206 #---------------------------------------------------------------------------
207 207 # imports here, so they are after setuptools import if there was one
208 208 from distutils.command.sdist import sdist
209 209 from distutils.command.upload import upload
210 210
211 211 class UploadWindowsInstallers(upload):
212 212
213 213 description = "Upload Windows installers to PyPI (only used from tools/release_windows.py)"
214 214 user_options = upload.user_options + [
215 215 ('files=', 'f', 'exe file (or glob) to upload')
216 216 ]
217 217 def initialize_options(self):
218 218 upload.initialize_options(self)
219 219 meta = self.distribution.metadata
220 220 base = '{name}-{version}'.format(
221 221 name=meta.get_name(),
222 222 version=meta.get_version()
223 223 )
224 224 self.files = os.path.join('dist', '%s.*.exe' % base)
225 225
226 226 def run(self):
227 227 for dist_file in glob(self.files):
228 228 self.upload_file('bdist_wininst', 'any', dist_file)
229 229
230 230 setup_args['cmdclass'] = {
231 'build_py': check_package_data_first(git_prebuild('IPython')),
231 'build_py': css_js_prerelease(
232 check_package_data_first(git_prebuild('IPython')),
233 strict=False),
232 234 'sdist' : css_js_prerelease(git_prebuild('IPython', sdist)),
233 235 'upload_wininst' : UploadWindowsInstallers,
234 236 'submodule' : UpdateSubmodules,
235 237 'css' : CompileCSS,
236 238 'symlink': install_symlinked,
237 239 'install_lib_symlink': install_lib_symlink,
238 240 'install_scripts_sym': install_scripts_for_symlink,
239 241 'unsymlink': unsymlink,
240 242 'jsversion' : JavascriptVersion,
241 243 }
242 244
243 245 #---------------------------------------------------------------------------
244 246 # Handle scripts, dependencies, and setuptools specific things
245 247 #---------------------------------------------------------------------------
246 248
247 249 # For some commands, use setuptools. Note that we do NOT list install here!
248 250 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
249 251 needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
250 252 'bdist', 'bdist_dumb', 'bdist_wininst', 'bdist_wheel',
251 253 'egg_info', 'easy_install', 'upload', 'install_egg_info',
252 254 ))
253 255 if sys.platform == 'win32':
254 256 # Depend on setuptools for install on *Windows only*
255 257 # If we get script-installation working without setuptools,
256 258 # then we can back off, but until then use it.
257 259 # See Issue #369 on GitHub for more
258 260 needs_setuptools.add('install')
259 261
260 262 if len(needs_setuptools.intersection(sys.argv)) > 0:
261 263 import setuptools
262 264
263 265 # This dict is used for passing extra arguments that are setuptools
264 266 # specific to setup
265 267 setuptools_extra_args = {}
266 268
267 269 # setuptools requirements
268 270
269 271 extras_require = dict(
270 272 parallel = ['pyzmq>=2.1.11'],
271 273 qtconsole = ['pyzmq>=2.1.11', 'pygments'],
272 274 zmq = ['pyzmq>=2.1.11'],
273 275 doc = ['Sphinx>=1.1', 'numpydoc'],
274 276 test = ['nose>=0.10.1'],
275 277 terminal = [],
276 278 nbformat = ['jsonschema>=2.0', 'jsonpointer>=1.3'],
277 279 notebook = ['tornado>=3.1', 'pyzmq>=2.1.11', 'jinja2', 'pygments', 'mistune>=0.3'],
278 280 nbconvert = ['pygments', 'jinja2', 'mistune>=0.3']
279 281 )
280 282
281 283 if sys.version_info < (3, 3):
282 284 extras_require['test'].append('mock')
283 285
284 286 extras_require['notebook'].extend(extras_require['nbformat'])
285 287 extras_require['nbconvert'].extend(extras_require['nbformat'])
286 288
287 289 everything = set()
288 290 for deps in extras_require.values():
289 291 everything.update(deps)
290 292 extras_require['all'] = everything
291 293
292 294 install_requires = []
293 295
294 296 # add readline
295 297 if sys.platform == 'darwin':
296 298 if any(arg.startswith('bdist') for arg in sys.argv) or not setupext.check_for_readline():
297 299 install_requires.append('gnureadline')
298 300 elif sys.platform.startswith('win'):
299 301 extras_require['terminal'].append('pyreadline>=2.0')
300 302
301 303
302 304 if 'setuptools' in sys.modules:
303 305 # setup.py develop should check for submodules
304 306 from setuptools.command.develop import develop
305 307 setup_args['cmdclass']['develop'] = require_submodules(develop)
306 308 setup_args['cmdclass']['bdist_wheel'] = css_js_prerelease(get_bdist_wheel())
307 309
308 310 setuptools_extra_args['zip_safe'] = False
309 311 setuptools_extra_args['entry_points'] = {'console_scripts':find_entry_points()}
310 312 setup_args['extras_require'] = extras_require
311 313 requires = setup_args['install_requires'] = install_requires
312 314
313 315 # Script to be run by the windows binary installer after the default setup
314 316 # routine, to add shortcuts and similar windows-only things. Windows
315 317 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
316 318 # doesn't find them.
317 319 if 'bdist_wininst' in sys.argv:
318 320 if len(sys.argv) > 2 and \
319 321 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
320 322 print >> sys.stderr, "ERROR: bdist_wininst must be run alone. Exiting."
321 323 sys.exit(1)
322 324 setup_args['data_files'].append(
323 325 ['Scripts', ('scripts/ipython.ico', 'scripts/ipython_nb.ico')])
324 326 setup_args['scripts'] = [pjoin('scripts','ipython_win_post_install.py')]
325 327 setup_args['options'] = {"bdist_wininst":
326 328 {"install_script":
327 329 "ipython_win_post_install.py"}}
328 330
329 331 else:
330 332 # If we are installing without setuptools, call this function which will
331 333 # check for dependencies an inform the user what is needed. This is
332 334 # just to make life easy for users.
333 335 for install_cmd in ('install', 'symlink'):
334 336 if install_cmd in sys.argv:
335 337 check_for_dependencies()
336 338 break
337 339 # scripts has to be a non-empty list, or install_scripts isn't called
338 340 setup_args['scripts'] = [e.split('=')[0].strip() for e in find_entry_points()]
339 341
340 342 setup_args['cmdclass']['build_scripts'] = build_scripts_entrypt
341 343
342 344 #---------------------------------------------------------------------------
343 345 # Do the actual setup now
344 346 #---------------------------------------------------------------------------
345 347
346 348 setup_args.update(setuptools_extra_args)
347 349
348 350 def main():
349 351 setup(**setup_args)
350 352 cleanup()
351 353
352 354 if __name__ == '__main__':
353 355 main()
@@ -1,717 +1,724 b''
1 1 # encoding: utf-8
2 2 """
3 3 This module defines the things that are used in setup.py for building IPython
4 4
5 5 This includes:
6 6
7 7 * The basic arguments to setup
8 8 * Functions for finding things like packages, package data, etc.
9 9 * A function for checking dependencies.
10 10 """
11 11
12 12 # Copyright (c) IPython Development Team.
13 13 # Distributed under the terms of the Modified BSD License.
14 14
15 15 from __future__ import print_function
16 16
17 17 import errno
18 18 import os
19 19 import sys
20 20
21 from distutils import log
21 22 from distutils.command.build_py import build_py
22 23 from distutils.command.build_scripts import build_scripts
23 24 from distutils.command.install import install
24 25 from distutils.command.install_scripts import install_scripts
25 26 from distutils.cmd import Command
26 27 from fnmatch import fnmatch
27 28 from glob import glob
28 29 from subprocess import check_call
29 30
30 31 from setupext import install_data_ext
31 32
32 33 #-------------------------------------------------------------------------------
33 34 # Useful globals and utility functions
34 35 #-------------------------------------------------------------------------------
35 36
36 37 # A few handy globals
37 38 isfile = os.path.isfile
38 39 pjoin = os.path.join
39 40 repo_root = os.path.dirname(os.path.abspath(__file__))
40 41
41 42 def oscmd(s):
42 43 print(">", s)
43 44 os.system(s)
44 45
45 46 # Py3 compatibility hacks, without assuming IPython itself is installed with
46 47 # the full py3compat machinery.
47 48
48 49 try:
49 50 execfile
50 51 except NameError:
51 52 def execfile(fname, globs, locs=None):
52 53 locs = locs or globs
53 54 exec(compile(open(fname).read(), fname, "exec"), globs, locs)
54 55
55 56 # A little utility we'll need below, since glob() does NOT allow you to do
56 57 # exclusion on multiple endings!
57 58 def file_doesnt_endwith(test,endings):
58 59 """Return true if test is a file and its name does NOT end with any
59 60 of the strings listed in endings."""
60 61 if not isfile(test):
61 62 return False
62 63 for e in endings:
63 64 if test.endswith(e):
64 65 return False
65 66 return True
66 67
67 68 #---------------------------------------------------------------------------
68 69 # Basic project information
69 70 #---------------------------------------------------------------------------
70 71
71 72 # release.py contains version, authors, license, url, keywords, etc.
72 73 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
73 74
74 75 # Create a dict with the basic information
75 76 # This dict is eventually passed to setup after additional keys are added.
76 77 setup_args = dict(
77 78 name = name,
78 79 version = version,
79 80 description = description,
80 81 long_description = long_description,
81 82 author = author,
82 83 author_email = author_email,
83 84 url = url,
84 85 download_url = download_url,
85 86 license = license,
86 87 platforms = platforms,
87 88 keywords = keywords,
88 89 classifiers = classifiers,
89 90 cmdclass = {'install_data': install_data_ext},
90 91 )
91 92
92 93
93 94 #---------------------------------------------------------------------------
94 95 # Find packages
95 96 #---------------------------------------------------------------------------
96 97
97 98 def find_packages():
98 99 """
99 100 Find all of IPython's packages.
100 101 """
101 102 excludes = ['deathrow', 'quarantine']
102 103 packages = []
103 104 for dir,subdirs,files in os.walk('IPython'):
104 105 package = dir.replace(os.path.sep, '.')
105 106 if any(package.startswith('IPython.'+exc) for exc in excludes):
106 107 # package is to be excluded (e.g. deathrow)
107 108 continue
108 109 if '__init__.py' not in files:
109 110 # not a package
110 111 continue
111 112 packages.append(package)
112 113 return packages
113 114
114 115 #---------------------------------------------------------------------------
115 116 # Find package data
116 117 #---------------------------------------------------------------------------
117 118
118 119 def find_package_data():
119 120 """
120 121 Find IPython's package_data.
121 122 """
122 123 # This is not enough for these things to appear in an sdist.
123 124 # We need to muck with the MANIFEST to get this to work
124 125
125 126 # exclude components and less from the walk;
126 127 # we will build the components separately
127 128 excludes = [
128 129 pjoin('static', 'components'),
129 130 pjoin('static', '*', 'less'),
130 131 ]
131 132
132 133 # walk notebook resources:
133 134 cwd = os.getcwd()
134 135 os.chdir(os.path.join('IPython', 'html'))
135 136 static_data = []
136 137 for parent, dirs, files in os.walk('static'):
137 138 if any(fnmatch(parent, pat) for pat in excludes):
138 139 # prevent descending into subdirs
139 140 dirs[:] = []
140 141 continue
141 142 for f in files:
142 143 static_data.append(pjoin(parent, f))
143 144
144 145 components = pjoin("static", "components")
145 146 # select the components we actually need to install
146 147 # (there are lots of resources we bundle for sdist-reasons that we don't actually use)
147 148 static_data.extend([
148 149 pjoin(components, "backbone", "backbone-min.js"),
149 150 pjoin(components, "bootstrap", "js", "bootstrap.min.js"),
150 151 pjoin(components, "bootstrap-tour", "build", "css", "bootstrap-tour.min.css"),
151 152 pjoin(components, "bootstrap-tour", "build", "js", "bootstrap-tour.min.js"),
152 153 pjoin(components, "font-awesome", "font", "*.*"),
153 154 pjoin(components, "google-caja", "html-css-sanitizer-minified.js"),
154 155 pjoin(components, "highlight.js", "build", "highlight.pack.js"),
155 156 pjoin(components, "jquery", "jquery.min.js"),
156 157 pjoin(components, "jquery-ui", "ui", "minified", "jquery-ui.min.js"),
157 158 pjoin(components, "jquery-ui", "themes", "smoothness", "jquery-ui.min.css"),
158 159 pjoin(components, "jquery-ui", "themes", "smoothness", "images", "*"),
159 160 pjoin(components, "marked", "lib", "marked.js"),
160 161 pjoin(components, "requirejs", "require.js"),
161 162 pjoin(components, "underscore", "underscore-min.js"),
162 163 ])
163 164
164 165 # Ship all of Codemirror's CSS and JS
165 166 for parent, dirs, files in os.walk(pjoin(components, 'codemirror')):
166 167 for f in files:
167 168 if f.endswith(('.js', '.css')):
168 169 static_data.append(pjoin(parent, f))
169 170
170 171 os.chdir(os.path.join('tests',))
171 172 js_tests = glob('*.js') + glob('*/*.js')
172 173
173 174 os.chdir(os.path.join(cwd, 'IPython', 'nbconvert'))
174 175 nbconvert_templates = [os.path.join(dirpath, '*.*')
175 176 for dirpath, _, _ in os.walk('templates')]
176 177
177 178 os.chdir(cwd)
178 179
179 180 package_data = {
180 181 'IPython.config.profile' : ['README*', '*/*.py'],
181 182 'IPython.core.tests' : ['*.png', '*.jpg'],
182 183 'IPython.lib.tests' : ['*.wav'],
183 184 'IPython.testing.plugin' : ['*.txt'],
184 185 'IPython.html' : ['templates/*'] + static_data,
185 186 'IPython.html.tests' : js_tests,
186 187 'IPython.qt.console' : ['resources/icon/*.svg'],
187 188 'IPython.nbconvert' : nbconvert_templates +
188 189 [
189 190 'tests/files/*.*',
190 191 'exporters/tests/files/*.*',
191 192 'preprocessors/tests/files/*.*',
192 193 ],
193 194 'IPython.nbconvert.filters' : ['marked.js'],
194 195 'IPython.nbformat' : ['tests/*.ipynb','v3/v3.withref.json']
195 196 }
196 197
197 198 return package_data
198 199
199 200
200 201 def check_package_data(package_data):
201 202 """verify that package_data globs make sense"""
202 203 print("checking package data")
203 204 for pkg, data in package_data.items():
204 205 pkg_root = pjoin(*pkg.split('.'))
205 206 for d in data:
206 207 path = pjoin(pkg_root, d)
207 208 if '*' in path:
208 209 assert len(glob(path)) > 0, "No files match pattern %s" % path
209 210 else:
210 211 assert os.path.exists(path), "Missing package data: %s" % path
211 212
212 213
213 214 def check_package_data_first(command):
214 215 """decorator for checking package_data before running a given command
215 216
216 217 Probably only needs to wrap build_py
217 218 """
218 219 class DecoratedCommand(command):
219 220 def run(self):
220 221 check_package_data(self.package_data)
221 222 command.run(self)
222 223 return DecoratedCommand
223 224
224 225
225 226 #---------------------------------------------------------------------------
226 227 # Find data files
227 228 #---------------------------------------------------------------------------
228 229
229 230 def make_dir_struct(tag,base,out_base):
230 231 """Make the directory structure of all files below a starting dir.
231 232
232 233 This is just a convenience routine to help build a nested directory
233 234 hierarchy because distutils is too stupid to do this by itself.
234 235
235 236 XXX - this needs a proper docstring!
236 237 """
237 238
238 239 # we'll use these a lot below
239 240 lbase = len(base)
240 241 pathsep = os.path.sep
241 242 lpathsep = len(pathsep)
242 243
243 244 out = []
244 245 for (dirpath,dirnames,filenames) in os.walk(base):
245 246 # we need to strip out the dirpath from the base to map it to the
246 247 # output (installation) path. This requires possibly stripping the
247 248 # path separator, because otherwise pjoin will not work correctly
248 249 # (pjoin('foo/','/bar') returns '/bar').
249 250
250 251 dp_eff = dirpath[lbase:]
251 252 if dp_eff.startswith(pathsep):
252 253 dp_eff = dp_eff[lpathsep:]
253 254 # The output path must be anchored at the out_base marker
254 255 out_path = pjoin(out_base,dp_eff)
255 256 # Now we can generate the final filenames. Since os.walk only produces
256 257 # filenames, we must join back with the dirpath to get full valid file
257 258 # paths:
258 259 pfiles = [pjoin(dirpath,f) for f in filenames]
259 260 # Finally, generate the entry we need, which is a pari of (output
260 261 # path, files) for use as a data_files parameter in install_data.
261 262 out.append((out_path, pfiles))
262 263
263 264 return out
264 265
265 266
266 267 def find_data_files():
267 268 """
268 269 Find IPython's data_files.
269 270
270 271 Just man pages at this point.
271 272 """
272 273
273 274 manpagebase = pjoin('share', 'man', 'man1')
274 275
275 276 # Simple file lists can be made by hand
276 277 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
277 278 if not manpages:
278 279 # When running from a source tree, the manpages aren't gzipped
279 280 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
280 281
281 282 # And assemble the entire output list
282 283 data_files = [ (manpagebase, manpages) ]
283 284
284 285 return data_files
285 286
286 287
287 288 def make_man_update_target(manpage):
288 289 """Return a target_update-compliant tuple for the given manpage.
289 290
290 291 Parameters
291 292 ----------
292 293 manpage : string
293 294 Name of the manpage, must include the section number (trailing number).
294 295
295 296 Example
296 297 -------
297 298
298 299 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
299 300 ('docs/man/ipython.1.gz',
300 301 ['docs/man/ipython.1'],
301 302 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
302 303 """
303 304 man_dir = pjoin('docs', 'man')
304 305 manpage_gz = manpage + '.gz'
305 306 manpath = pjoin(man_dir, manpage)
306 307 manpath_gz = pjoin(man_dir, manpage_gz)
307 308 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
308 309 locals() )
309 310 return (manpath_gz, [manpath], gz_cmd)
310 311
311 312 # The two functions below are copied from IPython.utils.path, so we don't need
312 313 # to import IPython during setup, which fails on Python 3.
313 314
314 315 def target_outdated(target,deps):
315 316 """Determine whether a target is out of date.
316 317
317 318 target_outdated(target,deps) -> 1/0
318 319
319 320 deps: list of filenames which MUST exist.
320 321 target: single filename which may or may not exist.
321 322
322 323 If target doesn't exist or is older than any file listed in deps, return
323 324 true, otherwise return false.
324 325 """
325 326 try:
326 327 target_time = os.path.getmtime(target)
327 328 except os.error:
328 329 return 1
329 330 for dep in deps:
330 331 dep_time = os.path.getmtime(dep)
331 332 if dep_time > target_time:
332 333 #print "For target",target,"Dep failed:",dep # dbg
333 334 #print "times (dep,tar):",dep_time,target_time # dbg
334 335 return 1
335 336 return 0
336 337
337 338
338 339 def target_update(target,deps,cmd):
339 340 """Update a target with a given command given a list of dependencies.
340 341
341 342 target_update(target,deps,cmd) -> runs cmd if target is outdated.
342 343
343 344 This is just a wrapper around target_outdated() which calls the given
344 345 command if target is outdated."""
345 346
346 347 if target_outdated(target,deps):
347 348 os.system(cmd)
348 349
349 350 #---------------------------------------------------------------------------
350 351 # Find scripts
351 352 #---------------------------------------------------------------------------
352 353
353 354 def find_entry_points():
354 355 """Find IPython's scripts.
355 356
356 357 if entry_points is True:
357 358 return setuptools entry_point-style definitions
358 359 else:
359 360 return file paths of plain scripts [default]
360 361
361 362 suffix is appended to script names if entry_points is True, so that the
362 363 Python 3 scripts get named "ipython3" etc.
363 364 """
364 365 ep = [
365 366 'ipython%s = IPython:start_ipython',
366 367 'ipcontroller%s = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
367 368 'ipengine%s = IPython.parallel.apps.ipengineapp:launch_new_instance',
368 369 'ipcluster%s = IPython.parallel.apps.ipclusterapp:launch_new_instance',
369 370 'iptest%s = IPython.testing.iptestcontroller:main',
370 371 ]
371 372 suffix = str(sys.version_info[0])
372 373 return [e % '' for e in ep] + [e % suffix for e in ep]
373 374
374 375 script_src = """#!{executable}
375 376 # This script was automatically generated by setup.py
376 377 if __name__ == '__main__':
377 378 from {mod} import {func}
378 379 {func}()
379 380 """
380 381
381 382 class build_scripts_entrypt(build_scripts):
382 383 def run(self):
383 384 self.mkpath(self.build_dir)
384 385 outfiles = []
385 386 for script in find_entry_points():
386 387 name, entrypt = script.split('=')
387 388 name = name.strip()
388 389 entrypt = entrypt.strip()
389 390 outfile = os.path.join(self.build_dir, name)
390 391 outfiles.append(outfile)
391 392 print('Writing script to', outfile)
392 393
393 394 mod, func = entrypt.split(':')
394 395 with open(outfile, 'w') as f:
395 396 f.write(script_src.format(executable=sys.executable,
396 397 mod=mod, func=func))
397 398
398 399 return outfiles, outfiles
399 400
400 401 class install_lib_symlink(Command):
401 402 user_options = [
402 403 ('install-dir=', 'd', "directory to install to"),
403 404 ]
404 405
405 406 def initialize_options(self):
406 407 self.install_dir = None
407 408
408 409 def finalize_options(self):
409 410 self.set_undefined_options('symlink',
410 411 ('install_lib', 'install_dir'),
411 412 )
412 413
413 414 def run(self):
414 415 if sys.platform == 'win32':
415 416 raise Exception("This doesn't work on Windows.")
416 417 pkg = os.path.join(os.getcwd(), 'IPython')
417 418 dest = os.path.join(self.install_dir, 'IPython')
418 419 if os.path.islink(dest):
419 420 print('removing existing symlink at %s' % dest)
420 421 os.unlink(dest)
421 422 print('symlinking %s -> %s' % (pkg, dest))
422 423 os.symlink(pkg, dest)
423 424
424 425 class unsymlink(install):
425 426 def run(self):
426 427 dest = os.path.join(self.install_lib, 'IPython')
427 428 if os.path.islink(dest):
428 429 print('removing symlink at %s' % dest)
429 430 os.unlink(dest)
430 431 else:
431 432 print('No symlink exists at %s' % dest)
432 433
433 434 class install_symlinked(install):
434 435 def run(self):
435 436 if sys.platform == 'win32':
436 437 raise Exception("This doesn't work on Windows.")
437 438
438 439 # Run all sub-commands (at least those that need to be run)
439 440 for cmd_name in self.get_sub_commands():
440 441 self.run_command(cmd_name)
441 442
442 443 # 'sub_commands': a list of commands this command might have to run to
443 444 # get its work done. See cmd.py for more info.
444 445 sub_commands = [('install_lib_symlink', lambda self:True),
445 446 ('install_scripts_sym', lambda self:True),
446 447 ]
447 448
448 449 class install_scripts_for_symlink(install_scripts):
449 450 """Redefined to get options from 'symlink' instead of 'install'.
450 451
451 452 I love distutils almost as much as I love setuptools.
452 453 """
453 454 def finalize_options(self):
454 455 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
455 456 self.set_undefined_options('symlink',
456 457 ('install_scripts', 'install_dir'),
457 458 ('force', 'force'),
458 459 ('skip_build', 'skip_build'),
459 460 )
460 461
461 462 #---------------------------------------------------------------------------
462 463 # Verify all dependencies
463 464 #---------------------------------------------------------------------------
464 465
465 466 def check_for_dependencies():
466 467 """Check for IPython's dependencies.
467 468
468 469 This function should NOT be called if running under setuptools!
469 470 """
470 471 from setupext.setupext import (
471 472 print_line, print_raw, print_status,
472 473 check_for_sphinx, check_for_pygments,
473 474 check_for_nose, check_for_pexpect,
474 475 check_for_pyzmq, check_for_readline,
475 476 check_for_jinja2, check_for_tornado
476 477 )
477 478 print_line()
478 479 print_raw("BUILDING IPYTHON")
479 480 print_status('python', sys.version)
480 481 print_status('platform', sys.platform)
481 482 if sys.platform == 'win32':
482 483 print_status('Windows version', sys.getwindowsversion())
483 484
484 485 print_raw("")
485 486 print_raw("OPTIONAL DEPENDENCIES")
486 487
487 488 check_for_sphinx()
488 489 check_for_pygments()
489 490 check_for_nose()
490 491 if os.name == 'posix':
491 492 check_for_pexpect()
492 493 check_for_pyzmq()
493 494 check_for_tornado()
494 495 check_for_readline()
495 496 check_for_jinja2()
496 497
497 498 #---------------------------------------------------------------------------
498 499 # VCS related
499 500 #---------------------------------------------------------------------------
500 501
501 502 # utils.submodule has checks for submodule status
502 503 execfile(pjoin('IPython','utils','submodule.py'), globals())
503 504
504 505 class UpdateSubmodules(Command):
505 506 """Update git submodules
506 507
507 508 IPython's external javascript dependencies live in a separate repo.
508 509 """
509 510 description = "Update git submodules"
510 511 user_options = []
511 512
512 513 def initialize_options(self):
513 514 pass
514 515
515 516 def finalize_options(self):
516 517 pass
517 518
518 519 def run(self):
519 520 failure = False
520 521 try:
521 522 self.spawn('git submodule init'.split())
522 523 self.spawn('git submodule update --recursive'.split())
523 524 except Exception as e:
524 525 failure = e
525 526 print(e)
526 527
527 528 if not check_submodule_status(repo_root) == 'clean':
528 529 print("submodules could not be checked out")
529 530 sys.exit(1)
530 531
531 532
532 533 def git_prebuild(pkg_dir, build_cmd=build_py):
533 534 """Return extended build or sdist command class for recording commit
534 535
535 536 records git commit in IPython.utils._sysinfo.commit
536 537
537 538 for use in IPython.utils.sysinfo.sys_info() calls after installation.
538 539
539 540 Also ensures that submodules exist prior to running
540 541 """
541 542
542 543 class MyBuildPy(build_cmd):
543 544 ''' Subclass to write commit data into installation tree '''
544 545 def run(self):
545 546 build_cmd.run(self)
546 547 # this one will only fire for build commands
547 548 if hasattr(self, 'build_lib'):
548 549 self._record_commit(self.build_lib)
549 550
550 551 def make_release_tree(self, base_dir, files):
551 552 # this one will fire for sdist
552 553 build_cmd.make_release_tree(self, base_dir, files)
553 554 self._record_commit(base_dir)
554 555
555 556 def _record_commit(self, base_dir):
556 557 import subprocess
557 558 proc = subprocess.Popen('git rev-parse --short HEAD',
558 559 stdout=subprocess.PIPE,
559 560 stderr=subprocess.PIPE,
560 561 shell=True)
561 562 repo_commit, _ = proc.communicate()
562 563 repo_commit = repo_commit.strip().decode("ascii")
563 564
564 565 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
565 566 if os.path.isfile(out_pth) and not repo_commit:
566 567 # nothing to write, don't clobber
567 568 return
568 569
569 570 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
570 571
571 572 # remove to avoid overwriting original via hard link
572 573 try:
573 574 os.remove(out_pth)
574 575 except (IOError, OSError):
575 576 pass
576 577 with open(out_pth, 'w') as out_file:
577 578 out_file.writelines([
578 579 '# GENERATED BY setup.py\n',
579 580 'commit = "%s"\n' % repo_commit,
580 581 ])
581 582 return require_submodules(MyBuildPy)
582 583
583 584
584 585 def require_submodules(command):
585 586 """decorator for instructing a command to check for submodules before running"""
586 587 class DecoratedCommand(command):
587 588 def run(self):
588 589 if not check_submodule_status(repo_root) == 'clean':
589 590 print("submodules missing! Run `setup.py submodule` and try again")
590 591 sys.exit(1)
591 592 command.run(self)
592 593 return DecoratedCommand
593 594
594 595 #---------------------------------------------------------------------------
595 596 # bdist related
596 597 #---------------------------------------------------------------------------
597 598
598 599 def get_bdist_wheel():
599 600 """Construct bdist_wheel command for building wheels
600 601
601 602 Constructs py2-none-any tag, instead of py2.7-none-any
602 603 """
603 604 class RequiresWheel(Command):
604 605 description = "Dummy command for missing bdist_wheel"
605 606 user_options = []
606 607
607 608 def initialize_options(self):
608 609 pass
609 610
610 611 def finalize_options(self):
611 612 pass
612 613
613 614 def run(self):
614 615 print("bdist_wheel requires the wheel package")
615 616 sys.exit(1)
616 617
617 618 if 'setuptools' not in sys.modules:
618 619 return RequiresWheel
619 620 else:
620 621 try:
621 622 from wheel.bdist_wheel import bdist_wheel, read_pkg_info, write_pkg_info
622 623 except ImportError:
623 624 return RequiresWheel
624 625
625 626 class bdist_wheel_tag(bdist_wheel):
626 627
627 628 def add_requirements(self, metadata_path):
628 629 """transform platform-dependent requirements"""
629 630 pkg_info = read_pkg_info(metadata_path)
630 631 # pkg_info is an email.Message object (?!)
631 632 # we have to remove the unconditional 'readline' and/or 'pyreadline' entries
632 633 # and transform them to conditionals
633 634 requires = pkg_info.get_all('Requires-Dist')
634 635 del pkg_info['Requires-Dist']
635 636 def _remove_startswith(lis, prefix):
636 637 """like list.remove, but with startswith instead of =="""
637 638 found = False
638 639 for idx, item in enumerate(lis):
639 640 if item.startswith(prefix):
640 641 found = True
641 642 break
642 643 if found:
643 644 lis.pop(idx)
644 645
645 646 for pkg in ("gnureadline", "pyreadline", "mock"):
646 647 _remove_startswith(requires, pkg)
647 648 requires.append("gnureadline; sys.platform == 'darwin' and platform.python_implementation == 'CPython'")
648 649 requires.append("pyreadline (>=2.0); extra == 'terminal' and sys.platform == 'win32' and platform.python_implementation == 'CPython'")
649 650 requires.append("pyreadline (>=2.0); extra == 'all' and sys.platform == 'win32' and platform.python_implementation == 'CPython'")
650 651 requires.append("mock; extra == 'test' and python_version < '3.3'")
651 652 for r in requires:
652 653 pkg_info['Requires-Dist'] = r
653 654 write_pkg_info(metadata_path, pkg_info)
654 655
655 656 return bdist_wheel_tag
656 657
657 658 #---------------------------------------------------------------------------
658 659 # Notebook related
659 660 #---------------------------------------------------------------------------
660 661
661 662 class CompileCSS(Command):
662 663 """Recompile Notebook CSS
663 664
664 665 Regenerate the compiled CSS from LESS sources.
665 666
666 667 Requires various dev dependencies, such as fabric and lessc.
667 668 """
668 669 description = "Recompile Notebook CSS"
669 670 user_options = [
670 671 ('minify', 'x', "minify CSS"),
671 672 ]
672 673
673 674 def initialize_options(self):
674 675 self.minify = False
675 676
676 677 def finalize_options(self):
677 678 self.minify = bool(self.minify)
678 679
679 680 def run(self):
680 681 check_call("fab css:minify=%s" % self.minify,
681 682 shell=True,
682 683 cwd=pjoin(repo_root, "IPython", "html"),
683 684 )
684 685
685 686
686 687 class JavascriptVersion(Command):
687 688 """write the javascript version to notebook javascript"""
688 689 description = "Write IPython version to javascript"
689 690 user_options = []
690 691
691 692 def initialize_options(self):
692 693 pass
693 694
694 695 def finalize_options(self):
695 696 pass
696 697
697 698 def run(self):
698 699 nsfile = pjoin(repo_root, "IPython", "html", "static", "base", "js", "namespace.js")
699 700 with open(nsfile) as f:
700 701 lines = f.readlines()
701 702 with open(nsfile, 'w') as f:
702 703 for line in lines:
703 704 if line.startswith("IPython.version"):
704 705 line = 'IPython.version = "{0}";\n'.format(version)
705 706 f.write(line)
706 707
707 708
708 def css_js_prerelease(command):
709 def css_js_prerelease(command, strict=True):
709 710 """decorator for building js/minified css prior to a release"""
710 711 class DecoratedCommand(command):
711 712 def run(self):
712 713 self.distribution.run_command('jsversion')
713 714 css = self.distribution.get_command_obj('css')
714 715 css.minify = True
715 self.distribution.run_command('css')
716 try:
717 self.distribution.run_command('css')
718 except Exception as e:
719 if strict:
720 raise
721 else:
722 log.warn("Failed to build css sourcemaps: %s" % e)
716 723 command.run(self)
717 724 return DecoratedCommand
General Comments 0
You need to be logged in to leave comments. Login now