tasks.py
108 lines
| 3.6 KiB
| text/x-python
|
PythonLexer
MinRK
|
r18351 | """invoke task file to build CSS""" | ||
Matthias BUSSONNIER
|
r9299 | |||
Min RK
|
r19731 | from __future__ import print_function | ||
Matthias BUSSONNIER
|
r9299 | import os | ||
Min RK
|
r19731 | import sys | ||
MinRK
|
r15059 | from distutils.version import LooseVersion as V | ||
from subprocess import check_output | ||||
Matthias BUSSONNIER
|
r9299 | |||
Min RK
|
r19731 | from invoke import task, run | ||
from invoke.runner import Result | ||||
from invoke.exceptions import Failure | ||||
MinRK
|
r11337 | pjoin = os.path.join | ||
Matthias BUSSONNIER
|
r9299 | static_dir = 'static' | ||
MinRK
|
r17344 | components_dir = pjoin(static_dir, 'components') | ||
here = os.path.dirname(__file__) | ||||
Matthias BUSSONNIER
|
r9299 | |||
Min RK
|
r19435 | min_less_version = '2.0' | ||
max_less_version = '3.0' # exclusive if string | ||||
MinRK
|
r11337 | |||
Min RK
|
r19731 | |||
def _fail(msg=''): | ||||
"""Fail a task, logging a message to stderr | ||||
raises a special Failure Exception from invoke. | ||||
""" | ||||
if msg: | ||||
print(msg, file=sys.stderr) | ||||
# raising a Failure allows us to avoid a traceback | ||||
# we only care about exited, but stdout, stderr, pty are required args | ||||
raise Failure(Result(stdout='', stderr='', pty=False, exited=1)) | ||||
MinRK
|
r17344 | 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 | ||||
MinRK
|
r18351 | @task | ||
MinRK
|
r17344 | def css(minify=False, verbose=False, force=False): | ||
Matthias BUSSONNIER
|
r9299 | """generate the css from less files""" | ||
MinRK
|
r17344 | # 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 | ||||
MinRK
|
r11337 | for name in ('style', 'ipython'): | ||
source = pjoin('style', "%s.less" % name) | ||||
target = pjoin('style', "%s.min.css" % name) | ||||
Jason Grout
|
r17290 | sourcemap = pjoin('style', "%s.min.css.map" % name) | ||
_compile_less(source, target, sourcemap, minify, verbose) | ||||
Brian E. Granger
|
r10713 | |||
Min RK
|
r19731 | |||
Jason Grout
|
r17290 | def _compile_less(source, target, sourcemap, minify=True, verbose=False): | ||
MinRK
|
r11337 | """Compile a less file by source and target relative to static_dir""" | ||
MinRK
|
r18351 | min_flag = '-x' if minify else '' | ||
ver_flag = '--verbose' if verbose else '' | ||||
MinRK
|
r15059 | |||
Min RK
|
r19731 | install = "(npm install -g 'less@<{}')".format(max_less_version) | ||
Jason Grout
|
r17290 | # pin less to version number from above | ||
Aron Ahmadia
|
r16291 | try: | ||
out = check_output(['lessc', '--version']) | ||||
except OSError as err: | ||||
Min RK
|
r19731 | _fail("Unable to find lessc. Rebuilding css requires less >= {0} and < {1} {2}".format( | ||
min_less_version, max_less_version, install | ||||
)) | ||||
MinRK
|
r15059 | out = out.decode('utf8', 'replace') | ||
less_version = out.split()[1] | ||||
Bussonnier Matthias
|
r19124 | if min_less_version and V(less_version) < V(min_less_version): | ||
Min RK
|
r19731 | _fail("lessc too old: {} < {} {}".format( | ||
less_version, min_less_version, install, | ||||
)) | ||||
Bussonnier Matthias
|
r19124 | if max_less_version and V(less_version) >= V(max_less_version): | ||
Min RK
|
r19731 | _fail("lessc too new: {} >= {} {}".format( | ||
less_version, max_less_version, install, | ||||
)) | ||||
MinRK
|
r15059 | |||
MinRK
|
r17344 | static_path = pjoin(here, static_dir) | ||
MinRK
|
r18351 | cwd = os.getcwd() | ||
try: | ||||
os.chdir(static_dir) | ||||
run('lessc {min_flag} {ver_flag} --source-map={sourcemap} --source-map-basepath={static_path} --source-map-rootpath="../" {source} {target}'.format(**locals()), | ||||
echo=True, | ||||
) | ||||
finally: | ||||
os.chdir(cwd) | ||||
Matthias BUSSONNIER
|
r9299 | |||