tasks.py
83 lines
| 3.1 KiB
| text/x-python
|
PythonLexer
|
r18351 | """invoke task file to build CSS""" | ||
|
r9299 | |||
|
r18351 | from invoke import task, run | ||
|
r9299 | import os | ||
|
r15059 | from distutils.version import LooseVersion as V | ||
from subprocess import check_output | ||||
|
r9299 | |||
|
r11337 | pjoin = os.path.join | ||
|
r9299 | static_dir = 'static' | ||
|
r17344 | components_dir = pjoin(static_dir, 'components') | ||
here = os.path.dirname(__file__) | ||||
|
r9299 | |||
|
r17290 | min_less_version = '1.7.0' | ||
|
r18197 | max_less_version = '1.7.5' # exclusive | ||
|
r11337 | |||
|
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 | ||||
|
r18351 | @task | ||
|
r17344 | def css(minify=False, verbose=False, force=False): | ||
|
r9299 | """generate the css from less files""" | ||
|
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 | ||||
|
r11337 | for name in ('style', 'ipython'): | ||
source = pjoin('style', "%s.less" % name) | ||||
target = pjoin('style', "%s.min.css" % name) | ||||
|
r17290 | sourcemap = pjoin('style', "%s.min.css.map" % name) | ||
_compile_less(source, target, sourcemap, minify, verbose) | ||||
|
r10713 | |||
|
r17290 | def _compile_less(source, target, sourcemap, minify=True, verbose=False): | ||
|
r11337 | """Compile a less file by source and target relative to static_dir""" | ||
|
r18351 | min_flag = '-x' if minify else '' | ||
ver_flag = '--verbose' if verbose else '' | ||||
|
r15059 | |||
|
r17290 | # pin less to version number from above | ||
|
r16291 | try: | ||
out = check_output(['lessc', '--version']) | ||||
except OSError as err: | ||||
raise ValueError("Unable to find lessc. Please install lessc >= %s and < %s " \ | ||||
% (min_less_version, max_less_version)) | ||||
|
r15059 | out = out.decode('utf8', 'replace') | ||
less_version = out.split()[1] | ||||
if V(less_version) < V(min_less_version): | ||||
|
r16996 | raise ValueError("lessc too old: %s < %s. Use `$ npm install lesscss@X.Y.Z` to install a specific version of less" % (less_version, min_less_version)) | ||
|
r16291 | if V(less_version) >= V(max_less_version): | ||
|
r16996 | 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)) | ||
|
r15059 | |||
|
r17344 | static_path = pjoin(here, static_dir) | ||
|
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) | ||||
|
r9299 | |||