Source code for dktasklib.executables
# -*- coding: utf-8 -*-
import sys
import invoke
from dkfileutils.which import get_executable
from dktasklib.utils import win32
[docs]class MissingCommand(Exception):
"""Exception thrown when a command (executable) is not found.
"""
pass
# noinspection PyShadowingNames
[docs]class Executables(object):
"""Class for finding executables on the host system.
"""
def __init__(self):
self._cache = {}
self._ctx = None
@property
def ctx(self):
if self._ctx is None:
self._ctx = invoke.Context()
return self._ctx
[docs] def require(self, *dependencies):
"""Ensure that all dependencies are available.
You should not need to call this yourself, use the :func:`requires`
decorator instead.
"""
for dep in dependencies:
self.find(dep)
[docs] def find(self, name, requires=(), install_txt=''):
"""Find the executable named ``name`` on the :envvar:`PATH`.
Args:
name (str):
name of executable to find.
requires (List[str]):
list of executables to find first.
install_txt (str):
instructions for how to install the
executable if it is not found.
"""
if name not in self._cache:
self.require(*requires)
if hasattr(self, 'find_' + name):
self._cache[name] = getattr(self, 'find_' + name)()
else:
self._cache[name] = self._find_exe(name, requires, install_txt)
return self._cache[name]
def _find_exe(self, name, requires=(), install_txt=None):
fexe = get_executable(name)
if not fexe: # pragma: nocover
if not install_txt: # pragma: nocover
install_txt = "Missing command: %r [requires: %s]" % (name, requires)
raise MissingCommand(install_txt)
return fexe
def find_uglify(self):
exename = 'uglifyjs'
exepath = get_executable(exename)
if not exepath:
npminstall = "npm install -g uglify-js --no-color"
if win32:
self.ctx.run(npminstall, echo=False, encoding="utf-8")
exepath = get_executable(exename)
else:
raise MissingCommand("Missing uglifyjs (%s)" % npminstall)
return exepath
def find_browserify(self):
exename = 'browserify'
exepath = get_executable(exename)
npminstall = "npm install -g browserify --no-color"
if not exepath:
if win32:
self.ctx.run(npminstall, echo=False, encoding="utf-8")
exepath = get_executable(exename)
else:
raise MissingCommand("Missing browserify (%s)" % npminstall)
return exepath
def find_babel(self):
exename = 'babel'
exepath = get_executable(exename)
npminstall = "npm install -g babel --no-color"
if not exepath:
if win32:
self.ctx.run(npminstall, echo=False, encoding="utf-8")
exepath = get_executable(exename)
else:
raise MissingCommand("Missing babel (%s)" % npminstall)
return exepath
[docs] def find_nodejs(self): # pragma: nocover
"""Find :program:`node`.
"""
if sys.platform == 'win32':
node_exe = get_executable('node')
else:
node_exe = get_executable('nodejs') or get_executable('node')
if not node_exe: # pragma: nocover
raise MissingCommand("""
Install Node.js using your OS package manager
https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager
""")
return node_exe
[docs] def find_npm(self):
"""Find the node package manager (:program:`npm`).
"""
npm_exe = get_executable('npm')
if not npm_exe: # pragma: nocover
raise MissingCommand("""
Install Node.js using your OS package manager
https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager
""")
return npm_exe
#: public interface to the :py:class:`Executables` class
exe = Executables()
[docs]def requires(*deps):
"""Decorator to declare global dependencies/requirements.
Usage (``@task`` must be last)::
@requires('nodejs', 'npm', 'lessc')
@task
def mytask(..)
"""
def _wrapper(fn):
exe.require(*deps)
return fn
return _wrapper