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