Merge pull request #6196 from minrk/git-friendlyish-less-css

Make less/sourcemaps a bit friendlier to git
This commit is contained in:
Min RK 2014-07-24 12:09:54 -07:00
commit 43e25ab4d9
9 changed files with 11662 additions and 29 deletions

1
.gitignore vendored
View File

@ -7,6 +7,7 @@ docs/source/api/generated
docs/source/config/options docs/source/config/options
docs/gh-pages docs/gh-pages
IPython/html/notebook/static/mathjax IPython/html/notebook/static/mathjax
IPython/html/static/style/*.map
*.py[co] *.py[co]
__pycache__ __pycache__
*.egg-info *.egg-info

View File

@ -8,13 +8,48 @@ from subprocess import check_output
pjoin = os.path.join pjoin = os.path.join
static_dir = 'static' static_dir = 'static'
components_dir = os.path.join(static_dir, 'components') components_dir = pjoin(static_dir, 'components')
here = os.path.dirname(__file__)
min_less_version = '1.7.0' min_less_version = '1.7.0'
max_less_version = '1.8.0' # exclusive max_less_version = '1.8.0' # exclusive
def css(minify=True, verbose=False): def _need_css_update():
"""Does less need to run?"""
static_path = pjoin(here, static_dir)
css_targets = [
pjoin(static_path, 'style', '%s.min.css' % name)
for name in ('style', 'ipython')
]
css_maps = [t + '.map' for t in css_targets]
targets = css_targets + css_maps
if not all(os.path.exists(t) for t in targets):
# some generated files don't exist
return True
earliest_target = sorted(os.stat(t).st_mtime for t in targets)[0]
# check if any .less files are newer than the generated targets
for (dirpath, dirnames, filenames) in os.walk(static_path):
for f in filenames:
if f.endswith('.less'):
path = pjoin(static_path, dirpath, f)
timestamp = os.stat(path).st_mtime
if timestamp > earliest_target:
return True
return False
def css(minify=False, verbose=False, force=False):
"""generate the css from less files""" """generate the css from less files"""
minify = _to_bool(minify)
verbose = _to_bool(verbose)
force = _to_bool(force)
# minify implies force because it's not the default behavior
if not force and not minify and not _need_css_update():
print("css up-to-date")
return
for name in ('style', 'ipython'): for name in ('style', 'ipython'):
source = pjoin('style', "%s.less" % name) source = pjoin('style', "%s.less" % name)
target = pjoin('style', "%s.min.css" % name) target = pjoin('style', "%s.min.css" % name)
@ -28,8 +63,6 @@ def _to_bool(b):
def _compile_less(source, target, sourcemap, minify=True, verbose=False): def _compile_less(source, target, sourcemap, minify=True, verbose=False):
"""Compile a less file by source and target relative to static_dir""" """Compile a less file by source and target relative to static_dir"""
minify = _to_bool(minify)
verbose = _to_bool(verbose)
min_flag = '-x' if minify is True else '' min_flag = '-x' if minify is True else ''
ver_flag = '--verbose' if verbose is True else '' ver_flag = '--verbose' if verbose is True else ''
@ -46,7 +79,7 @@ def _compile_less(source, target, sourcemap, minify=True, verbose=False):
if V(less_version) >= V(max_less_version): if V(less_version) >= V(max_less_version):
raise ValueError("lessc too new: %s >= %s. Use `$ npm install lesscss@X.Y.Z` to install a specific version of less" % (less_version, max_less_version)) raise ValueError("lessc too new: %s >= %s. Use `$ npm install lesscss@X.Y.Z` to install a specific version of less" % (less_version, max_less_version))
static_path = pjoin(os.getcwd(), static_dir) static_path = pjoin(here, static_dir)
with lcd(static_dir): with lcd(static_dir):
local('lessc {min_flag} {ver_flag} --source-map={sourcemap} --source-map-basepath={static_path} --source-map-rootpath="../" {source} {target}'.format(**locals())) local('lessc {min_flag} {ver_flag} --source-map={sourcemap} --source-map-basepath={static_path} --source-map-rootpath="../" {source} {target}'.format(**locals()))

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -3,7 +3,7 @@ git hooks for IPython
add these to your `.git/hooks` add these to your `.git/hooks`
For now, we just have `post-checkout` and `post-merge`, For now, we just have `post-checkout` and `post-merge`,
both of which just update submodules, both of which update submodules and attempt to rebuild css sourcemaps,
so make sure that you have a fully synced repo whenever you checkout or pull. so make sure that you have a fully synced repo whenever you checkout or pull.
To use these hooks, run `./install-hooks.sh`. To use these hooks, run `./install-hooks.sh`.

View File

@ -2,3 +2,16 @@
git submodule init git submodule init
git submodule update git submodule update
PREVIOUS_HEAD=$1
# if style changed (and less/fabric available), rebuild sourcemaps
if [[
! -z "$(git diff $PREVIOUS_HEAD IPython/html/static/style/ipython.min.css)"
&& ! -z "$(git diff $PREVIOUS_HEAD IPython/html/static/style/style.min.css)"
&& ! -z $(which 2>/dev/null lessc)
&& ! -z $(which 2>/dev/null fab)
]]; then
echo "rebuilding sourcemaps"
cd IPython/html
fab css
fi

View File

@ -1,4 +0,0 @@
#!/bin/sh
git submodule init
git submodule update

1
git-hooks/post-merge Symbolic link
View File

@ -0,0 +1 @@
post-checkout

View File

@ -72,6 +72,7 @@ from setupbase import (
get_bdist_wheel, get_bdist_wheel,
CompileCSS, CompileCSS,
JavascriptVersion, JavascriptVersion,
css_js_prerelease,
install_symlinked, install_symlinked,
install_lib_symlink, install_lib_symlink,
install_scripts_for_symlink, install_scripts_for_symlink,
@ -227,8 +228,10 @@ class UploadWindowsInstallers(upload):
self.upload_file('bdist_wininst', 'any', dist_file) self.upload_file('bdist_wininst', 'any', dist_file)
setup_args['cmdclass'] = { setup_args['cmdclass'] = {
'build_py': check_package_data_first(git_prebuild('IPython')), 'build_py': css_js_prerelease(
'sdist' : git_prebuild('IPython', sdist), check_package_data_first(git_prebuild('IPython')),
strict=False),
'sdist' : css_js_prerelease(git_prebuild('IPython', sdist)),
'upload_wininst' : UploadWindowsInstallers, 'upload_wininst' : UploadWindowsInstallers,
'submodule' : UpdateSubmodules, 'submodule' : UpdateSubmodules,
'css' : CompileCSS, 'css' : CompileCSS,
@ -302,7 +305,7 @@ if 'setuptools' in sys.modules:
# setup.py develop should check for submodules # setup.py develop should check for submodules
from setuptools.command.develop import develop from setuptools.command.develop import develop
setup_args['cmdclass']['develop'] = require_submodules(develop) setup_args['cmdclass']['develop'] = require_submodules(develop)
setup_args['cmdclass']['bdist_wheel'] = get_bdist_wheel() setup_args['cmdclass']['bdist_wheel'] = css_js_prerelease(get_bdist_wheel())
setuptools_extra_args['zip_safe'] = False setuptools_extra_args['zip_safe'] = False
setuptools_extra_args['entry_points'] = {'console_scripts':find_entry_points()} setuptools_extra_args['entry_points'] = {'console_scripts':find_entry_points()}

View File

@ -18,6 +18,7 @@ import errno
import os import os
import sys import sys
from distutils import log
from distutils.command.build_py import build_py from distutils.command.build_py import build_py
from distutils.command.build_scripts import build_scripts from distutils.command.build_scripts import build_scripts
from distutils.command.install import install from distutils.command.install import install
@ -25,7 +26,7 @@ from distutils.command.install_scripts import install_scripts
from distutils.cmd import Command from distutils.cmd import Command
from fnmatch import fnmatch from fnmatch import fnmatch
from glob import glob from glob import glob
from subprocess import call from subprocess import check_call
from setupext import install_data_ext from setupext import install_data_ext
@ -666,16 +667,26 @@ class CompileCSS(Command):
Requires various dev dependencies, such as fabric and lessc. Requires various dev dependencies, such as fabric and lessc.
""" """
description = "Recompile Notebook CSS" description = "Recompile Notebook CSS"
user_options = [] user_options = [
('minify', 'x', "minify CSS"),
('force', 'f', "force recompilation of CSS"),
]
def initialize_options(self): def initialize_options(self):
pass self.minify = False
self.force = False
def finalize_options(self): def finalize_options(self):
pass self.minify = bool(self.minify)
self.force = bool(self.force)
def run(self): def run(self):
call("fab css", shell=True, cwd=pjoin(repo_root, "IPython", "html")) check_call([
"fab",
"css:minify=%s,force=%s" % (self.minify, self.force),
], cwd=pjoin(repo_root, "IPython", "html"),
)
class JavascriptVersion(Command): class JavascriptVersion(Command):
"""write the javascript version to notebook javascript""" """write the javascript version to notebook javascript"""
@ -697,4 +708,21 @@ class JavascriptVersion(Command):
if line.startswith("IPython.version"): if line.startswith("IPython.version"):
line = 'IPython.version = "{0}";\n'.format(version) line = 'IPython.version = "{0}";\n'.format(version)
f.write(line) f.write(line)
def css_js_prerelease(command, strict=True):
"""decorator for building js/minified css prior to a release"""
class DecoratedCommand(command):
def run(self):
self.distribution.run_command('jsversion')
css = self.distribution.get_command_obj('css')
css.minify = True
try:
self.distribution.run_command('css')
except Exception as e:
if strict:
raise
else:
log.warn("Failed to build css sourcemaps: %s" % e)
command.run(self)
return DecoratedCommand