setup.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. # -*- coding: utf-8 -*-
  2. # Copyright (c) Jupyter Development Team.
  3. # Distributed under the terms of the Modified BSD License.
  4. from __future__ import print_function
  5. from setuptools import setup, find_packages, Command
  6. from setuptools.command.sdist import sdist
  7. from setuptools.command.build_py import build_py
  8. from setuptools.command.egg_info import egg_info
  9. from subprocess import check_call
  10. import os
  11. import sys
  12. import platform
  13. import shutil
  14. here = os.path.dirname(os.path.abspath(__file__))
  15. node_root = os.path.join(here, 'jupyterlab')
  16. is_repo = os.path.exists(os.path.join(here, '.git'))
  17. npm_path = os.pathsep.join([
  18. os.path.join(node_root, 'node_modules', '.bin'),
  19. os.environ.get('PATH', os.defpath),
  20. ])
  21. from distutils import log
  22. log.set_verbosity(log.DEBUG)
  23. log.info('setup.py entered')
  24. log.info('$PATH=%s' % os.environ['PATH'])
  25. LONG_DESCRIPTION = 'This is a very early pre-alpha developer preview. It is not ready for general usage yet.'
  26. def js_prerelease(command, strict=False):
  27. """decorator for building minified js/css prior to another command"""
  28. class DecoratedCommand(command):
  29. def run(self):
  30. jsdeps = self.distribution.get_command_obj('jsdeps')
  31. if not is_repo and all(os.path.exists(t) for t in jsdeps.targets):
  32. # sdist, nothing to do
  33. command.run(self)
  34. return
  35. try:
  36. self.distribution.run_command('jsdeps')
  37. except Exception as e:
  38. missing = [t for t in jsdeps.targets if not os.path.exists(t)]
  39. if strict or missing:
  40. log.warn('rebuilding js and css failed')
  41. if missing:
  42. log.error('missing files: %s' % missing)
  43. raise e
  44. else:
  45. log.warn('rebuilding js and css failed (not a problem)')
  46. log.warn(str(e))
  47. command.run(self)
  48. update_package_data(self.distribution)
  49. return DecoratedCommand
  50. def update_package_data(distribution):
  51. """update package_data to catch changes during setup"""
  52. build_py = distribution.get_command_obj('build_py')
  53. # distribution.package_data = find_package_data()
  54. # re-init build_py options which load package_data
  55. build_py.finalize_options()
  56. class NPM(Command):
  57. description = 'install package.json dependencies using npm'
  58. user_options = []
  59. node_modules = os.path.join(node_root, 'node_modules')
  60. targets = [
  61. os.path.join(here, 'jupyterlab', 'build', 'bundle.js'),
  62. ]
  63. def initialize_options(self):
  64. pass
  65. def finalize_options(self):
  66. pass
  67. def has_npm(self):
  68. try:
  69. check_call(['npm', '--version'])
  70. return True
  71. except:
  72. return False
  73. def should_run_npm_install(self):
  74. package_json = os.path.join(node_root, 'package.json')
  75. node_modules_exists = os.path.exists(self.node_modules)
  76. return self.has_npm()
  77. def run(self):
  78. has_npm = self.has_npm()
  79. if not has_npm:
  80. log.error("`npm` unavailable. If you're running this command using sudo, make sure `npm` is available to sudo")
  81. env = os.environ.copy()
  82. env['PATH'] = npm_path
  83. if self.should_run_npm_install():
  84. log.info("Installing build dependencies with npm. This may take a while...")
  85. # remove just jupyterlab so that it is always updated
  86. shutil.rmtree(os.path.join(self.node_modules, 'jupyterlab'), ignore_errors=True)
  87. check_call(['npm', 'install'], cwd=node_root, stdout=sys.stdout, stderr=sys.stderr)
  88. check_call(['npm', 'run', 'build'], cwd=node_root, stdout=sys.stdout, stderr=sys.stderr)
  89. os.utime(self.node_modules, None)
  90. for t in self.targets:
  91. if not os.path.exists(t):
  92. msg = 'Missing file: %s' % t
  93. if not has_npm:
  94. msg += '\nnpm is required to build a development version of widgetsnbextension'
  95. raise ValueError(msg)
  96. # update package data in case this created new files
  97. update_package_data(self.distribution)
  98. import json
  99. with open(os.path.join(here, 'package.json')) as f:
  100. packagejson = json.load(f)
  101. setup_args = {
  102. 'name': 'jupyterlab',
  103. 'version': packagejson['version'],
  104. 'description': 'A pre-alpha Jupyter lab environment notebook server extension.',
  105. 'long_description': LONG_DESCRIPTION,
  106. 'License': 'BSD',
  107. 'include_package_data': True,
  108. 'install_requires': ['notebook>=4.2.0'],
  109. 'packages': find_packages(),
  110. 'zip_safe': False,
  111. 'package_data': {'jupyterlab': [
  112. 'build/*',
  113. 'lab.html'
  114. ]},
  115. 'cmdclass': {
  116. 'build_py': js_prerelease(build_py),
  117. 'egg_info': js_prerelease(egg_info),
  118. 'sdist': js_prerelease(sdist, strict=True),
  119. 'jsdeps': NPM,
  120. },
  121. 'author': 'Jupyter Development Team',
  122. 'author_email': 'jupyter@googlegroups.com',
  123. 'url': 'http://jupyter.org',
  124. 'keywords': ['ipython', 'jupyter', 'Web'],
  125. 'classifiers': [
  126. 'Development Status :: 2 - Pre-Alpha',
  127. 'Intended Audience :: Developers',
  128. 'Intended Audience :: Science/Research',
  129. 'License :: OSI Approved :: BSD License',
  130. 'Programming Language :: Python :: 2',
  131. 'Programming Language :: Python :: 2.7',
  132. 'Programming Language :: Python :: 3',
  133. ],
  134. }
  135. setup(**setup_args)