From c41df91b10509e93b0c8cdbc08d2f75e66be01c6 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 21 Jul 2015 16:34:44 -0700 Subject: [PATCH] remove gulp Follow-suit from ipywidgets and build js/css with Python/js scripts instead: e.g. - `npm run build` - `setup.py js css` --- gulpfile.js | 114 --------------------------- package.json | 16 ++-- setupbase.py | 89 ++++++++++++++++----- build-main.js => tools/build-main.js | 0 4 files changed, 77 insertions(+), 142 deletions(-) delete mode 100644 gulpfile.js rename build-main.js => tools/build-main.js (100%) diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100644 index afc207dbf..000000000 --- a/gulpfile.js +++ /dev/null @@ -1,114 +0,0 @@ -var fork = require('child_process').fork; -var fs = require('fs'); -var path = require('path'); - -var through = require('through'); -var gulp = require('gulp'); -var less = require('gulp-less'); -var newer = require('gulp-newer'); -var rename = require('gulp-rename'); -var sourcemaps = require('gulp-sourcemaps'); - -// now some dev nice utilities. -var livereload = require('gulp-livereload'); - -gulp.task('css', function () { - return gulp.src('./notebook/static/style/*.less') - .pipe(sourcemaps.init()) - .pipe(less({ - paths: [ path.join(__dirname, 'less', 'includes') ] - })) - // we don't minify on purpose as it removes rules - .pipe(rename({ - suffix: '.min' - })) - .pipe(sourcemaps.write('./')) - .pipe(gulp.dest('./notebook/static/style')) - .pipe(livereload()); -}); - -function build_main(name, callback) { - // build main.min.js for a given application name - // run in a subprocess to allow parallel builds - // clone requirejs config - var p = fork('./build-main.js', [name]); - p.on('exit', function (code, status) { - if (code) { - callback(new Error("Build failed")); - } else { - callback(); - } - }); - return; -} - -// build notebook-js, edit-js, etc. tasks -// which enables parallelism -var apps = ['notebook', 'tree', 'edit', 'terminal', 'auth']; - -apps.map(function (name) { - gulp.task(name + '-js', function (finish) { - var s = path.join('notebook', 'static'); - var src = path.join(s, name, 'js', 'main.js'); - var rel_dest = path.join(name, 'js', 'main.min.js'); - var dest = path.join(s, rel_dest); - - var sources = [ - path.join(s, name, 'js', '*.js'), - path.join(s, "base", 'js', '*.js'), - path.join(s, "auth", 'js', '*.js'), - path.join(s, "services", 'config.js'), - ]; - - // for required_components - if (name === 'notebook') { - sources.push(path.join(s, "services", '**', '*.js')); - } - - fs.readdirSync(path.join(s, 'components')).map(function (c) { - if (c !== 'MathJax') { - // skip MathJax because it has tons of files and makes everything super slow - sources.push(path.join(s, 'components', c, '**', '*.js')); - } - }); - - // sources is a greedy list, containing all dependencies plus some for simplicity. - gulp.src(sources, {base: s}) - .pipe(newer(dest)) - .pipe(through(function(file) { - // if any dependency changed, update main.min.js - console.log("A dependency has changed, updating " + rel_dest); - // pause halts the pipeline - this.pause(); - build_main(name, finish); - return; - })) - .on('end', function () { - // if we get here, no dependency is newer than the target - console.log(rel_dest + " up to date"); - finish(); - }); - }); -}); - -gulp.task('js', apps.map(function (name) { return name + '-js'; })); - -gulp.task('watch', function() { - livereload.listen(); - gulp.watch('notebook/static/**/*.less', ['css']); - - var s = path.join('notebook', 'static'); - - function alljs(name) { - return path.join(s, name, '**', '*.js'); - } - var common_js = ['components', 'base', 'auth', 'services'].map(alljs); - - gulp.watch(common_js, ['js']); - apps.map(function (name) { - gulp.watch([ - alljs(name), - '!' + path.join(s, name, 'js', 'main.min.js'), - ], [name + '-js']); - }); -}); diff --git a/package.json b/package.json index 10a2cdfb2..603923bfd 100644 --- a/package.json +++ b/package.json @@ -3,22 +3,18 @@ "version": "4.0.0", "description": "Jupyter Notebook nodejs dependencies", "author": "Jupyter Developers", - "license": "BSD", + "license": "BSD-3-Clause", "repository": { "type": "git", "url": "https://github.com/jupyter/notebook.git" }, + "scripts": { + "bower": "bower install", + "build": "python setup.py js css" + }, "devDependencies": { "bower": "*", - "gulp": "^3.8.11", - "gulp-less": "^3.0.2", - "gulp-livereload": "^3.8.0", - "gulp-newer": "^0.5.0", - "gulp-rename": "^1.2.2", - "gulp-sourcemaps": "^1.5.1", "less": "~2", - "requirejs": "^2.1.17", - "source-map": "^0.4.2", - "through": "^2.3.7" + "requirejs": "^2.1.17" } } diff --git a/setupbase.py b/setupbase.py index ae6fc428d..aa592b173 100644 --- a/setupbase.py +++ b/setupbase.py @@ -16,12 +16,15 @@ from __future__ import print_function import os import sys +import pipes from distutils import log from distutils.cmd import Command from fnmatch import fnmatch from glob import glob +from multiprocessing.pool import ThreadPool from subprocess import check_call + #------------------------------------------------------------------------------- # Useful globals and utility functions #------------------------------------------------------------------------------- @@ -287,6 +290,11 @@ def mtime(path): return os.stat(path).st_mtime +def run(cmd, *args, **kwargs): + """Echo a command before running it""" + log.info(" ".join(cmd)) + return check_call(cmd, *args, **kwargs) + class Bower(Command): description = "fetch static client-side components with bower" @@ -326,14 +334,14 @@ class Bower(Command): if self.should_run_npm(): print("installing build dependencies with npm") - check_call(['npm', 'install'], cwd=repo_root) + run(['npm', 'install'], cwd=repo_root) os.utime(self.node_modules, None) env = os.environ.copy() env['PATH'] = npm_path try: - check_call( + run( ['bower', 'install', '--allow-root', '--config.interactive=false'], cwd=repo_root, env=env @@ -352,7 +360,7 @@ class CompileCSS(Command): Regenerate the compiled CSS from LESS sources. - Requires various dev dependencies, such as gulp and lessc. + Requires various dev dependencies, such as require and lessc. """ description = "Recompile Notebook CSS" user_options = [] @@ -367,22 +375,32 @@ class CompileCSS(Command): self.run_command('jsdeps') env = os.environ.copy() env['PATH'] = npm_path - try: - check_call(['gulp','css'], cwd=repo_root, env=env) - except OSError as e: - print("Failed to run gulp css: %s" % e, file=sys.stderr) - print("You can install js dependencies with `npm install`", file=sys.stderr) - raise + + for name in ('ipython', 'style'): + + src = pjoin(static, 'style', '%s.less' % name) + dst = pjoin(static, 'style', '%s.min.css' % name) + try: + run(['lessc', + '--source-map', + '--include-path=%s' % pipes.quote(static), + src, + dst, + ], cwd=repo_root, env=env) + except OSError as e: + print("Failed to build css: %s" % e, file=sys.stderr) + print("You can install js dependencies with `npm install`", file=sys.stderr) + raise # update package data in case this created new files update_package_data(self.distribution) class CompileJS(Command): - """Rebuild minified Notebook Javascript + """Rebuild Notebook Javascript main.min.js files - Calls `gulp js` + Calls require via build-main.js """ - description = "Rebuild Notebook Javascript" + description = "Rebuild Notebook Javascript main.min.js files" user_options = [] def initialize_options(self): @@ -390,17 +408,52 @@ class CompileJS(Command): def finalize_options(self): pass + + def sources(self, name): + """Generator yielding .js sources that an application depends on""" + yield pjoin(static, name, 'js', 'main.js') + + for sec in [name, 'base', 'auth']: + for f in glob(pjoin(static, sec, 'js', '*.js')): + yield f + yield pjoin(static, 'services', 'config.js') + if name == 'notebook': + for f in glob(pjoin(static, 'services', '*', '*.js')): + yield f + for parent, dirs, files in os.walk(pjoin(static, 'components')): + if os.path.basename(parent) == 'MathJax': + # don't look in MathJax, since it takes forever to walk it + dirs[:] = [] + continue + for f in files: + yield pjoin(parent, f) + + def should_run(self, name, target): + if not os.path.exists(target): + return True + target_mtime = mtime(target) + for source in self.sources(name): + if mtime(source) > target_mtime: + print(source, target) + return True + return False + + def build_main(self, name): + """Build main.min.js""" + target = pjoin(static, name, 'js', 'main.min.js') + + if not self.should_run(name, target): + log.info("%s up to date" % target) + return + log.info("Rebuilding %s" % target) + run(['node', 'tools/build-main.js', name]) def run(self): self.run_command('jsdeps') env = os.environ.copy() env['PATH'] = npm_path - try: - check_call(['gulp','js'], cwd=repo_root, env=env) - except OSError as e: - print("Failed to run gulp js: %s" % e, file=sys.stderr) - print("You can install js dependencies with `npm install`", file=sys.stderr) - raise + pool = ThreadPool() + pool.map(self.build_main, ['notebook', 'tree', 'edit', 'terminal', 'auth']) # update package data in case this created new files update_package_data(self.distribution) diff --git a/build-main.js b/tools/build-main.js similarity index 100% rename from build-main.js rename to tools/build-main.js