Source code for dktasklib.executables
# -*- coding: utf-8 -*-
import sys
import invoke
from dkfileutils.which import get_executable
from dktasklib import Package
from dktasklib.utils import win32
from dktasklib import runners
[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
# try $PKG/node_modules/.bin/<exe|cmd>
noderoot = Package().root / 'node_modules/.bin'
if name + '.cmd' in noderoot:
return str(noderoot / (name + '.cmd'))
if not install_txt: # pragma: nocover
install_txt = "Missing command: %r" % name
if requires:
install_txt += " [requires: %s]" % requires
raise MissingCommand(install_txt)
return fexe
[docs] def find_wheel(self):
exename = 'wheel'
exepath = get_executable(exename)
if not exepath:
pip = get_executable('pip')
cmd = pip + ' install wheel[signatures]'
if win32:
# self.ctx.run(cmd, echo=True)
runners.run(cmd)
wheel = get_executable(exename)
# generate signing key if downloading wheel
runners.run(wheel + ' keygen')
else:
raise MissingCommand("Missing wheel (%s)" % cmd)
print 'Your ~/.pypirc file should have a [pypi] section instead of a [server-login] section'
return exepath
[docs] def find_twine(self):
exename = 'twine'
exepath = get_executable(exename)
if not exepath:
pip = get_executable('pip')
cmd = pip + ' install twine'
if win32:
# self.ctx.run(cmd, echo=True)
runners.run(cmd)
exepath = get_executable(exename)
else:
raise MissingCommand("Missing twine (%s)" % cmd)
print 'Your ~/.pypirc file should have a [pypi] section instead of a [server-login] section'
return exepath
[docs] 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
[docs] 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")
self.ctx.run(npminstall, echo=True, encoding="utf-8")
exepath = get_executable(exename)
else:
raise MissingCommand("Missing browserify (%s)" % npminstall)
return exepath
[docs] def find_babili(self):
exename = 'babili'
exepath = get_executable(exename)
npminstall = "npm install -g babili --no-color"
if not exepath:
if win32:
self.ctx.run(npminstall, echo=False, encoding="utf-8")
exepath = get_executable(exename)
else:
raise MissingCommand("Missing babili (%s)" % npminstall)
return exepath
[docs] def find_babel(self):
exename = 'babel'
exepath = get_executable(exename)
npminstall = "npm install -g babel-cli --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
# 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