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