setupbase.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import os
  2. import pipes
  3. import sys
  4. from distutils import log
  5. from distutils.cmd import Command
  6. from subprocess import check_call
  7. if sys.platform == 'win32':
  8. from subprocess import list2cmdline
  9. else:
  10. def list2cmdline(cmd_list):
  11. return ' '.join(map(pipes.quote, cmd_list))
  12. here = os.path.dirname(os.path.abspath(__file__))
  13. is_repo = os.path.exists(os.path.join(here, '.git'))
  14. def run(cmd, *args, **kwargs):
  15. """Echo a command before running it"""
  16. log.info('> ' + list2cmdline(cmd))
  17. kwargs['shell'] = (sys.platform == 'win32')
  18. return check_call(cmd, *args, **kwargs)
  19. #---------------------------------------------------------------------------
  20. # Find packages
  21. #---------------------------------------------------------------------------
  22. def find_packages():
  23. """
  24. Find all of the packages.
  25. """
  26. packages = []
  27. for dir, subdirs, files in os.walk('jupyterlab'):
  28. package = dir.replace(os.path.sep, '.')
  29. if '__init__.py' not in files:
  30. # not a package
  31. continue
  32. packages.append(package)
  33. return packages
  34. def js_prerelease(command, strict=False):
  35. """decorator for building minified js/css prior to another command"""
  36. class DecoratedCommand(command):
  37. def run(self):
  38. jsdeps = self.distribution.get_command_obj('jsdeps')
  39. if not is_repo and all(os.path.exists(t) for t in jsdeps.targets):
  40. # sdist, nothing to do
  41. command.run(self)
  42. return
  43. try:
  44. self.distribution.run_command('jsdeps')
  45. except Exception as e:
  46. missing = [t for t in jsdeps.targets if not os.path.exists(t)]
  47. if strict or missing:
  48. log.warn('rebuilding js and css failed')
  49. if missing:
  50. log.error('missing files: %s' % missing)
  51. raise e
  52. else:
  53. log.warn('rebuilding js and css failed (not a problem)')
  54. log.warn(str(e))
  55. command.run(self)
  56. return DecoratedCommand
  57. def update_package_data(distribution):
  58. """update build_py options to get package_data changes"""
  59. build_py = distribution.get_command_obj('build_py')
  60. build_py.finalize_options()
  61. class NPM(Command):
  62. description = 'install package.json dependencies using npm'
  63. user_options = []
  64. # Representative files that should exist after a successful build
  65. targets = [
  66. os.path.join(here, 'jupyterlab', 'build', 'main.css'),
  67. os.path.join(here, 'jupyterlab', 'build', 'main.bundle.js'),
  68. ]
  69. def initialize_options(self):
  70. pass
  71. def finalize_options(self):
  72. pass
  73. def has_npm(self):
  74. try:
  75. run(['npm', '--version'])
  76. return True
  77. except:
  78. return False
  79. def run(self):
  80. has_npm = self.has_npm()
  81. if not has_npm:
  82. log.error("`npm` unavailable. If you're running this command using sudo, make sure `npm` is available to sudo")
  83. log.info("Installing build dependencies with npm. This may take a while...")
  84. run(['npm', 'install'], cwd=here)
  85. run(['npm', 'run', 'build:serverextension'], cwd=here)
  86. for t in self.targets:
  87. if not os.path.exists(t):
  88. msg = 'Missing file: %s' % t
  89. if not has_npm:
  90. msg += '\nnpm is required to build the development version'
  91. raise ValueError(msg)
  92. # update package data in case this created new files
  93. update_package_data(self.distribution)