##// END OF EJS Templates
include marked.js in package_data
MinRK -
Show More
@@ -1,600 +1,601 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
149
150 os.chdir(os.path.join(cwd, 'IPython', 'nbconvert'))
150 os.chdir(os.path.join(cwd, 'IPython', 'nbconvert'))
151 nbconvert_templates = [os.path.join(dirpath, '*.*')
151 nbconvert_templates = [os.path.join(dirpath, '*.*')
152 for dirpath, _, _ in os.walk('templates')]
152 for dirpath, _, _ in os.walk('templates')]
153
153
154 os.chdir(cwd)
154 os.chdir(cwd)
155
155
156 package_data = {
156 package_data = {
157 'IPython.config.profile' : ['README*', '*/*.py'],
157 'IPython.config.profile' : ['README*', '*/*.py'],
158 'IPython.core.tests' : ['*.png', '*.jpg'],
158 'IPython.core.tests' : ['*.png', '*.jpg'],
159 'IPython.lib.tests' : ['*.wav'],
159 'IPython.lib.tests' : ['*.wav'],
160 'IPython.testing' : ['*.txt'],
160 'IPython.testing' : ['*.txt'],
161 'IPython.testing.plugin' : ['*.txt'],
161 'IPython.testing.plugin' : ['*.txt'],
162 'IPython.html' : ['templates/*'] + static_data,
162 'IPython.html' : ['templates/*'] + static_data,
163 'IPython.html.tests' : js_tests,
163 'IPython.html.tests' : js_tests,
164 'IPython.qt.console' : ['resources/icon/*.svg'],
164 'IPython.qt.console' : ['resources/icon/*.svg'],
165 'IPython.nbconvert' : nbconvert_templates +
165 'IPython.nbconvert' : nbconvert_templates +
166 ['tests/files/*.*', 'exporters/tests/files/*.*'],
166 ['tests/files/*.*', 'exporters/tests/files/*.*'],
167 'IPython.nbconvert.filters' : ['marked.js'],
167 'IPython.nbformat' : ['tests/*.ipynb']
168 'IPython.nbformat' : ['tests/*.ipynb']
168 }
169 }
169 return package_data
170 return package_data
170
171
171
172
172 #---------------------------------------------------------------------------
173 #---------------------------------------------------------------------------
173 # Find data files
174 # Find data files
174 #---------------------------------------------------------------------------
175 #---------------------------------------------------------------------------
175
176
176 def make_dir_struct(tag,base,out_base):
177 def make_dir_struct(tag,base,out_base):
177 """Make the directory structure of all files below a starting dir.
178 """Make the directory structure of all files below a starting dir.
178
179
179 This is just a convenience routine to help build a nested directory
180 This is just a convenience routine to help build a nested directory
180 hierarchy because distutils is too stupid to do this by itself.
181 hierarchy because distutils is too stupid to do this by itself.
181
182
182 XXX - this needs a proper docstring!
183 XXX - this needs a proper docstring!
183 """
184 """
184
185
185 # we'll use these a lot below
186 # we'll use these a lot below
186 lbase = len(base)
187 lbase = len(base)
187 pathsep = os.path.sep
188 pathsep = os.path.sep
188 lpathsep = len(pathsep)
189 lpathsep = len(pathsep)
189
190
190 out = []
191 out = []
191 for (dirpath,dirnames,filenames) in os.walk(base):
192 for (dirpath,dirnames,filenames) in os.walk(base):
192 # we need to strip out the dirpath from the base to map it to the
193 # we need to strip out the dirpath from the base to map it to the
193 # output (installation) path. This requires possibly stripping the
194 # output (installation) path. This requires possibly stripping the
194 # path separator, because otherwise pjoin will not work correctly
195 # path separator, because otherwise pjoin will not work correctly
195 # (pjoin('foo/','/bar') returns '/bar').
196 # (pjoin('foo/','/bar') returns '/bar').
196
197
197 dp_eff = dirpath[lbase:]
198 dp_eff = dirpath[lbase:]
198 if dp_eff.startswith(pathsep):
199 if dp_eff.startswith(pathsep):
199 dp_eff = dp_eff[lpathsep:]
200 dp_eff = dp_eff[lpathsep:]
200 # The output path must be anchored at the out_base marker
201 # The output path must be anchored at the out_base marker
201 out_path = pjoin(out_base,dp_eff)
202 out_path = pjoin(out_base,dp_eff)
202 # Now we can generate the final filenames. Since os.walk only produces
203 # Now we can generate the final filenames. Since os.walk only produces
203 # filenames, we must join back with the dirpath to get full valid file
204 # filenames, we must join back with the dirpath to get full valid file
204 # paths:
205 # paths:
205 pfiles = [pjoin(dirpath,f) for f in filenames]
206 pfiles = [pjoin(dirpath,f) for f in filenames]
206 # Finally, generate the entry we need, which is a pari of (output
207 # Finally, generate the entry we need, which is a pari of (output
207 # path, files) for use as a data_files parameter in install_data.
208 # path, files) for use as a data_files parameter in install_data.
208 out.append((out_path, pfiles))
209 out.append((out_path, pfiles))
209
210
210 return out
211 return out
211
212
212
213
213 def find_data_files():
214 def find_data_files():
214 """
215 """
215 Find IPython's data_files.
216 Find IPython's data_files.
216
217
217 Most of these are docs.
218 Most of these are docs.
218 """
219 """
219
220
220 docdirbase = pjoin('share', 'doc', 'ipython')
221 docdirbase = pjoin('share', 'doc', 'ipython')
221 manpagebase = pjoin('share', 'man', 'man1')
222 manpagebase = pjoin('share', 'man', 'man1')
222
223
223 # Simple file lists can be made by hand
224 # Simple file lists can be made by hand
224 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
225 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
225 if not manpages:
226 if not manpages:
226 # When running from a source tree, the manpages aren't gzipped
227 # When running from a source tree, the manpages aren't gzipped
227 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
228 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
228
229
229 igridhelpfiles = [f for f in glob(pjoin('IPython','extensions','igrid_help.*')) if isfile(f)]
230 igridhelpfiles = [f for f in glob(pjoin('IPython','extensions','igrid_help.*')) if isfile(f)]
230
231
231 # For nested structures, use the utility above
232 # For nested structures, use the utility above
232 example_files = make_dir_struct(
233 example_files = make_dir_struct(
233 'data',
234 'data',
234 pjoin('docs','examples'),
235 pjoin('docs','examples'),
235 pjoin(docdirbase,'examples')
236 pjoin(docdirbase,'examples')
236 )
237 )
237 manual_files = make_dir_struct(
238 manual_files = make_dir_struct(
238 'data',
239 'data',
239 pjoin('docs','html'),
240 pjoin('docs','html'),
240 pjoin(docdirbase,'manual')
241 pjoin(docdirbase,'manual')
241 )
242 )
242
243
243 # And assemble the entire output list
244 # And assemble the entire output list
244 data_files = [ (manpagebase, manpages),
245 data_files = [ (manpagebase, manpages),
245 (pjoin(docdirbase, 'extensions'), igridhelpfiles),
246 (pjoin(docdirbase, 'extensions'), igridhelpfiles),
246 ] + manual_files + example_files
247 ] + manual_files + example_files
247
248
248 return data_files
249 return data_files
249
250
250
251
251 def make_man_update_target(manpage):
252 def make_man_update_target(manpage):
252 """Return a target_update-compliant tuple for the given manpage.
253 """Return a target_update-compliant tuple for the given manpage.
253
254
254 Parameters
255 Parameters
255 ----------
256 ----------
256 manpage : string
257 manpage : string
257 Name of the manpage, must include the section number (trailing number).
258 Name of the manpage, must include the section number (trailing number).
258
259
259 Example
260 Example
260 -------
261 -------
261
262
262 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
263 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
263 ('docs/man/ipython.1.gz',
264 ('docs/man/ipython.1.gz',
264 ['docs/man/ipython.1'],
265 ['docs/man/ipython.1'],
265 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
266 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
266 """
267 """
267 man_dir = pjoin('docs', 'man')
268 man_dir = pjoin('docs', 'man')
268 manpage_gz = manpage + '.gz'
269 manpage_gz = manpage + '.gz'
269 manpath = pjoin(man_dir, manpage)
270 manpath = pjoin(man_dir, manpage)
270 manpath_gz = pjoin(man_dir, manpage_gz)
271 manpath_gz = pjoin(man_dir, manpage_gz)
271 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
272 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
272 locals() )
273 locals() )
273 return (manpath_gz, [manpath], gz_cmd)
274 return (manpath_gz, [manpath], gz_cmd)
274
275
275 # The two functions below are copied from IPython.utils.path, so we don't need
276 # The two functions below are copied from IPython.utils.path, so we don't need
276 # to import IPython during setup, which fails on Python 3.
277 # to import IPython during setup, which fails on Python 3.
277
278
278 def target_outdated(target,deps):
279 def target_outdated(target,deps):
279 """Determine whether a target is out of date.
280 """Determine whether a target is out of date.
280
281
281 target_outdated(target,deps) -> 1/0
282 target_outdated(target,deps) -> 1/0
282
283
283 deps: list of filenames which MUST exist.
284 deps: list of filenames which MUST exist.
284 target: single filename which may or may not exist.
285 target: single filename which may or may not exist.
285
286
286 If target doesn't exist or is older than any file listed in deps, return
287 If target doesn't exist or is older than any file listed in deps, return
287 true, otherwise return false.
288 true, otherwise return false.
288 """
289 """
289 try:
290 try:
290 target_time = os.path.getmtime(target)
291 target_time = os.path.getmtime(target)
291 except os.error:
292 except os.error:
292 return 1
293 return 1
293 for dep in deps:
294 for dep in deps:
294 dep_time = os.path.getmtime(dep)
295 dep_time = os.path.getmtime(dep)
295 if dep_time > target_time:
296 if dep_time > target_time:
296 #print "For target",target,"Dep failed:",dep # dbg
297 #print "For target",target,"Dep failed:",dep # dbg
297 #print "times (dep,tar):",dep_time,target_time # dbg
298 #print "times (dep,tar):",dep_time,target_time # dbg
298 return 1
299 return 1
299 return 0
300 return 0
300
301
301
302
302 def target_update(target,deps,cmd):
303 def target_update(target,deps,cmd):
303 """Update a target with a given command given a list of dependencies.
304 """Update a target with a given command given a list of dependencies.
304
305
305 target_update(target,deps,cmd) -> runs cmd if target is outdated.
306 target_update(target,deps,cmd) -> runs cmd if target is outdated.
306
307
307 This is just a wrapper around target_outdated() which calls the given
308 This is just a wrapper around target_outdated() which calls the given
308 command if target is outdated."""
309 command if target is outdated."""
309
310
310 if target_outdated(target,deps):
311 if target_outdated(target,deps):
311 os.system(cmd)
312 os.system(cmd)
312
313
313 #---------------------------------------------------------------------------
314 #---------------------------------------------------------------------------
314 # Find scripts
315 # Find scripts
315 #---------------------------------------------------------------------------
316 #---------------------------------------------------------------------------
316
317
317 def find_entry_points():
318 def find_entry_points():
318 """Find IPython's scripts.
319 """Find IPython's scripts.
319
320
320 if entry_points is True:
321 if entry_points is True:
321 return setuptools entry_point-style definitions
322 return setuptools entry_point-style definitions
322 else:
323 else:
323 return file paths of plain scripts [default]
324 return file paths of plain scripts [default]
324
325
325 suffix is appended to script names if entry_points is True, so that the
326 suffix is appended to script names if entry_points is True, so that the
326 Python 3 scripts get named "ipython3" etc.
327 Python 3 scripts get named "ipython3" etc.
327 """
328 """
328 ep = [
329 ep = [
329 'ipython%s = IPython:start_ipython',
330 'ipython%s = IPython:start_ipython',
330 'ipcontroller%s = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
331 'ipcontroller%s = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
331 'ipengine%s = IPython.parallel.apps.ipengineapp:launch_new_instance',
332 'ipengine%s = IPython.parallel.apps.ipengineapp:launch_new_instance',
332 'ipcluster%s = IPython.parallel.apps.ipclusterapp:launch_new_instance',
333 'ipcluster%s = IPython.parallel.apps.ipclusterapp:launch_new_instance',
333 'iptest%s = IPython.testing.iptestcontroller:main',
334 'iptest%s = IPython.testing.iptestcontroller:main',
334 ]
335 ]
335 suffix = str(sys.version_info[0])
336 suffix = str(sys.version_info[0])
336 return [e % '' for e in ep] + [e % suffix for e in ep]
337 return [e % '' for e in ep] + [e % suffix for e in ep]
337
338
338 script_src = """#!{executable}
339 script_src = """#!{executable}
339 # This script was automatically generated by setup.py
340 # This script was automatically generated by setup.py
340 if __name__ == '__main__':
341 if __name__ == '__main__':
341 from {mod} import {func}
342 from {mod} import {func}
342 {func}()
343 {func}()
343 """
344 """
344
345
345 class build_scripts_entrypt(build_scripts):
346 class build_scripts_entrypt(build_scripts):
346 def run(self):
347 def run(self):
347 self.mkpath(self.build_dir)
348 self.mkpath(self.build_dir)
348 outfiles = []
349 outfiles = []
349 for script in find_entry_points():
350 for script in find_entry_points():
350 name, entrypt = script.split('=')
351 name, entrypt = script.split('=')
351 name = name.strip()
352 name = name.strip()
352 entrypt = entrypt.strip()
353 entrypt = entrypt.strip()
353 outfile = os.path.join(self.build_dir, name)
354 outfile = os.path.join(self.build_dir, name)
354 outfiles.append(outfile)
355 outfiles.append(outfile)
355 print('Writing script to', outfile)
356 print('Writing script to', outfile)
356
357
357 mod, func = entrypt.split(':')
358 mod, func = entrypt.split(':')
358 with open(outfile, 'w') as f:
359 with open(outfile, 'w') as f:
359 f.write(script_src.format(executable=sys.executable,
360 f.write(script_src.format(executable=sys.executable,
360 mod=mod, func=func))
361 mod=mod, func=func))
361
362
362 return outfiles, outfiles
363 return outfiles, outfiles
363
364
364 class install_lib_symlink(Command):
365 class install_lib_symlink(Command):
365 user_options = [
366 user_options = [
366 ('install-dir=', 'd', "directory to install to"),
367 ('install-dir=', 'd', "directory to install to"),
367 ]
368 ]
368
369
369 def initialize_options(self):
370 def initialize_options(self):
370 self.install_dir = None
371 self.install_dir = None
371
372
372 def finalize_options(self):
373 def finalize_options(self):
373 self.set_undefined_options('symlink',
374 self.set_undefined_options('symlink',
374 ('install_lib', 'install_dir'),
375 ('install_lib', 'install_dir'),
375 )
376 )
376
377
377 def run(self):
378 def run(self):
378 if sys.platform == 'win32':
379 if sys.platform == 'win32':
379 raise Exception("This doesn't work on Windows.")
380 raise Exception("This doesn't work on Windows.")
380 pkg = os.path.join(os.getcwd(), 'IPython')
381 pkg = os.path.join(os.getcwd(), 'IPython')
381 dest = os.path.join(self.install_dir, 'IPython')
382 dest = os.path.join(self.install_dir, 'IPython')
382 if os.path.islink(dest):
383 if os.path.islink(dest):
383 print('removing existing symlink at %s' % dest)
384 print('removing existing symlink at %s' % dest)
384 os.unlink(dest)
385 os.unlink(dest)
385 print('symlinking %s -> %s' % (pkg, dest))
386 print('symlinking %s -> %s' % (pkg, dest))
386 os.symlink(pkg, dest)
387 os.symlink(pkg, dest)
387
388
388 class unsymlink(install):
389 class unsymlink(install):
389 def run(self):
390 def run(self):
390 dest = os.path.join(self.install_lib, 'IPython')
391 dest = os.path.join(self.install_lib, 'IPython')
391 if os.path.islink(dest):
392 if os.path.islink(dest):
392 print('removing symlink at %s' % dest)
393 print('removing symlink at %s' % dest)
393 os.unlink(dest)
394 os.unlink(dest)
394 else:
395 else:
395 print('No symlink exists at %s' % dest)
396 print('No symlink exists at %s' % dest)
396
397
397 class install_symlinked(install):
398 class install_symlinked(install):
398 def run(self):
399 def run(self):
399 if sys.platform == 'win32':
400 if sys.platform == 'win32':
400 raise Exception("This doesn't work on Windows.")
401 raise Exception("This doesn't work on Windows.")
401
402
402 # Run all sub-commands (at least those that need to be run)
403 # Run all sub-commands (at least those that need to be run)
403 for cmd_name in self.get_sub_commands():
404 for cmd_name in self.get_sub_commands():
404 self.run_command(cmd_name)
405 self.run_command(cmd_name)
405
406
406 # 'sub_commands': a list of commands this command might have to run to
407 # 'sub_commands': a list of commands this command might have to run to
407 # get its work done. See cmd.py for more info.
408 # get its work done. See cmd.py for more info.
408 sub_commands = [('install_lib_symlink', lambda self:True),
409 sub_commands = [('install_lib_symlink', lambda self:True),
409 ('install_scripts_sym', lambda self:True),
410 ('install_scripts_sym', lambda self:True),
410 ]
411 ]
411
412
412 class install_scripts_for_symlink(install_scripts):
413 class install_scripts_for_symlink(install_scripts):
413 """Redefined to get options from 'symlink' instead of 'install'.
414 """Redefined to get options from 'symlink' instead of 'install'.
414
415
415 I love distutils almost as much as I love setuptools.
416 I love distutils almost as much as I love setuptools.
416 """
417 """
417 def finalize_options(self):
418 def finalize_options(self):
418 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
419 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
419 self.set_undefined_options('symlink',
420 self.set_undefined_options('symlink',
420 ('install_scripts', 'install_dir'),
421 ('install_scripts', 'install_dir'),
421 ('force', 'force'),
422 ('force', 'force'),
422 ('skip_build', 'skip_build'),
423 ('skip_build', 'skip_build'),
423 )
424 )
424
425
425 #---------------------------------------------------------------------------
426 #---------------------------------------------------------------------------
426 # Verify all dependencies
427 # Verify all dependencies
427 #---------------------------------------------------------------------------
428 #---------------------------------------------------------------------------
428
429
429 def check_for_dependencies():
430 def check_for_dependencies():
430 """Check for IPython's dependencies.
431 """Check for IPython's dependencies.
431
432
432 This function should NOT be called if running under setuptools!
433 This function should NOT be called if running under setuptools!
433 """
434 """
434 from setupext.setupext import (
435 from setupext.setupext import (
435 print_line, print_raw, print_status,
436 print_line, print_raw, print_status,
436 check_for_sphinx, check_for_pygments,
437 check_for_sphinx, check_for_pygments,
437 check_for_nose, check_for_pexpect,
438 check_for_nose, check_for_pexpect,
438 check_for_pyzmq, check_for_readline,
439 check_for_pyzmq, check_for_readline,
439 check_for_jinja2, check_for_tornado
440 check_for_jinja2, check_for_tornado
440 )
441 )
441 print_line()
442 print_line()
442 print_raw("BUILDING IPYTHON")
443 print_raw("BUILDING IPYTHON")
443 print_status('python', sys.version)
444 print_status('python', sys.version)
444 print_status('platform', sys.platform)
445 print_status('platform', sys.platform)
445 if sys.platform == 'win32':
446 if sys.platform == 'win32':
446 print_status('Windows version', sys.getwindowsversion())
447 print_status('Windows version', sys.getwindowsversion())
447
448
448 print_raw("")
449 print_raw("")
449 print_raw("OPTIONAL DEPENDENCIES")
450 print_raw("OPTIONAL DEPENDENCIES")
450
451
451 check_for_sphinx()
452 check_for_sphinx()
452 check_for_pygments()
453 check_for_pygments()
453 check_for_nose()
454 check_for_nose()
454 check_for_pexpect()
455 check_for_pexpect()
455 check_for_pyzmq()
456 check_for_pyzmq()
456 check_for_tornado()
457 check_for_tornado()
457 check_for_readline()
458 check_for_readline()
458 check_for_jinja2()
459 check_for_jinja2()
459
460
460 #---------------------------------------------------------------------------
461 #---------------------------------------------------------------------------
461 # VCS related
462 # VCS related
462 #---------------------------------------------------------------------------
463 #---------------------------------------------------------------------------
463
464
464 # utils.submodule has checks for submodule status
465 # utils.submodule has checks for submodule status
465 execfile(pjoin('IPython','utils','submodule.py'), globals())
466 execfile(pjoin('IPython','utils','submodule.py'), globals())
466
467
467 class UpdateSubmodules(Command):
468 class UpdateSubmodules(Command):
468 """Update git submodules
469 """Update git submodules
469
470
470 IPython's external javascript dependencies live in a separate repo.
471 IPython's external javascript dependencies live in a separate repo.
471 """
472 """
472 description = "Update git submodules"
473 description = "Update git submodules"
473 user_options = []
474 user_options = []
474
475
475 def initialize_options(self):
476 def initialize_options(self):
476 pass
477 pass
477
478
478 def finalize_options(self):
479 def finalize_options(self):
479 pass
480 pass
480
481
481 def run(self):
482 def run(self):
482 failure = False
483 failure = False
483 try:
484 try:
484 self.spawn('git submodule init'.split())
485 self.spawn('git submodule init'.split())
485 self.spawn('git submodule update --recursive'.split())
486 self.spawn('git submodule update --recursive'.split())
486 except Exception as e:
487 except Exception as e:
487 failure = e
488 failure = e
488 print(e)
489 print(e)
489
490
490 if not check_submodule_status(repo_root) == 'clean':
491 if not check_submodule_status(repo_root) == 'clean':
491 print("submodules could not be checked out")
492 print("submodules could not be checked out")
492 sys.exit(1)
493 sys.exit(1)
493
494
494
495
495 def git_prebuild(pkg_dir, build_cmd=build_py):
496 def git_prebuild(pkg_dir, build_cmd=build_py):
496 """Return extended build or sdist command class for recording commit
497 """Return extended build or sdist command class for recording commit
497
498
498 records git commit in IPython.utils._sysinfo.commit
499 records git commit in IPython.utils._sysinfo.commit
499
500
500 for use in IPython.utils.sysinfo.sys_info() calls after installation.
501 for use in IPython.utils.sysinfo.sys_info() calls after installation.
501
502
502 Also ensures that submodules exist prior to running
503 Also ensures that submodules exist prior to running
503 """
504 """
504
505
505 class MyBuildPy(build_cmd):
506 class MyBuildPy(build_cmd):
506 ''' Subclass to write commit data into installation tree '''
507 ''' Subclass to write commit data into installation tree '''
507 def run(self):
508 def run(self):
508 build_cmd.run(self)
509 build_cmd.run(self)
509 # this one will only fire for build commands
510 # this one will only fire for build commands
510 if hasattr(self, 'build_lib'):
511 if hasattr(self, 'build_lib'):
511 self._record_commit(self.build_lib)
512 self._record_commit(self.build_lib)
512
513
513 def make_release_tree(self, base_dir, files):
514 def make_release_tree(self, base_dir, files):
514 # this one will fire for sdist
515 # this one will fire for sdist
515 build_cmd.make_release_tree(self, base_dir, files)
516 build_cmd.make_release_tree(self, base_dir, files)
516 self._record_commit(base_dir)
517 self._record_commit(base_dir)
517
518
518 def _record_commit(self, base_dir):
519 def _record_commit(self, base_dir):
519 import subprocess
520 import subprocess
520 proc = subprocess.Popen('git rev-parse --short HEAD',
521 proc = subprocess.Popen('git rev-parse --short HEAD',
521 stdout=subprocess.PIPE,
522 stdout=subprocess.PIPE,
522 stderr=subprocess.PIPE,
523 stderr=subprocess.PIPE,
523 shell=True)
524 shell=True)
524 repo_commit, _ = proc.communicate()
525 repo_commit, _ = proc.communicate()
525 repo_commit = repo_commit.strip().decode("ascii")
526 repo_commit = repo_commit.strip().decode("ascii")
526
527
527 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
528 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
528 if os.path.isfile(out_pth) and not repo_commit:
529 if os.path.isfile(out_pth) and not repo_commit:
529 # nothing to write, don't clobber
530 # nothing to write, don't clobber
530 return
531 return
531
532
532 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
533 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
533
534
534 # remove to avoid overwriting original via hard link
535 # remove to avoid overwriting original via hard link
535 try:
536 try:
536 os.remove(out_pth)
537 os.remove(out_pth)
537 except (IOError, OSError):
538 except (IOError, OSError):
538 pass
539 pass
539 with open(out_pth, 'w') as out_file:
540 with open(out_pth, 'w') as out_file:
540 out_file.writelines([
541 out_file.writelines([
541 '# GENERATED BY setup.py\n',
542 '# GENERATED BY setup.py\n',
542 'commit = "%s"\n' % repo_commit,
543 'commit = "%s"\n' % repo_commit,
543 ])
544 ])
544 return require_submodules(MyBuildPy)
545 return require_submodules(MyBuildPy)
545
546
546
547
547 def require_submodules(command):
548 def require_submodules(command):
548 """decorator for instructing a command to check for submodules before running"""
549 """decorator for instructing a command to check for submodules before running"""
549 class DecoratedCommand(command):
550 class DecoratedCommand(command):
550 def run(self):
551 def run(self):
551 if not check_submodule_status(repo_root) == 'clean':
552 if not check_submodule_status(repo_root) == 'clean':
552 print("submodules missing! Run `setup.py submodule` and try again")
553 print("submodules missing! Run `setup.py submodule` and try again")
553 sys.exit(1)
554 sys.exit(1)
554 command.run(self)
555 command.run(self)
555 return DecoratedCommand
556 return DecoratedCommand
556
557
557 #---------------------------------------------------------------------------
558 #---------------------------------------------------------------------------
558 # Notebook related
559 # Notebook related
559 #---------------------------------------------------------------------------
560 #---------------------------------------------------------------------------
560
561
561 class CompileCSS(Command):
562 class CompileCSS(Command):
562 """Recompile Notebook CSS
563 """Recompile Notebook CSS
563
564
564 Regenerate the compiled CSS from LESS sources.
565 Regenerate the compiled CSS from LESS sources.
565
566
566 Requires various dev dependencies, such as fabric and lessc.
567 Requires various dev dependencies, such as fabric and lessc.
567 """
568 """
568 description = "Recompile Notebook CSS"
569 description = "Recompile Notebook CSS"
569 user_options = []
570 user_options = []
570
571
571 def initialize_options(self):
572 def initialize_options(self):
572 pass
573 pass
573
574
574 def finalize_options(self):
575 def finalize_options(self):
575 pass
576 pass
576
577
577 def run(self):
578 def run(self):
578 call("fab css", shell=True, cwd=pjoin(repo_root, "IPython", "html"))
579 call("fab css", shell=True, cwd=pjoin(repo_root, "IPython", "html"))
579
580
580 class JavascriptVersion(Command):
581 class JavascriptVersion(Command):
581 """write the javascript version to notebook javascript"""
582 """write the javascript version to notebook javascript"""
582 description = "Write IPython version to javascript"
583 description = "Write IPython version to javascript"
583 user_options = []
584 user_options = []
584
585
585 def initialize_options(self):
586 def initialize_options(self):
586 pass
587 pass
587
588
588 def finalize_options(self):
589 def finalize_options(self):
589 pass
590 pass
590
591
591 def run(self):
592 def run(self):
592 nsfile = pjoin(repo_root, "IPython", "html", "static", "base", "js", "namespace.js")
593 nsfile = pjoin(repo_root, "IPython", "html", "static", "base", "js", "namespace.js")
593 with open(nsfile) as f:
594 with open(nsfile) as f:
594 lines = f.readlines()
595 lines = f.readlines()
595 with open(nsfile, 'w') as f:
596 with open(nsfile, 'w') as f:
596 for line in lines:
597 for line in lines:
597 if line.startswith("IPython.version"):
598 if line.startswith("IPython.version"):
598 line = 'IPython.version = "{0}";\n'.format(version)
599 line = 'IPython.version = "{0}";\n'.format(version)
599 f.write(line)
600 f.write(line)
600
601
General Comments 0
You need to be logged in to leave comments. Login now