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