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