Fix cli that would play all scripts
This commit is contained in:
parent
1ceee0dee6
commit
638f0fa690
@ -1,6 +1,7 @@
|
||||
from .actions import *
|
||||
from .image import Image
|
||||
from .strategies import *
|
||||
from .output import Output
|
||||
from .proc import Proc
|
||||
from .targets import *
|
||||
from .shlaxfile import Shlaxfile
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
from .commit import Commit
|
||||
from .copy import Copy
|
||||
from .packages import Packages # noqa
|
||||
from .base import Action # noqa
|
||||
from .run import Run # noqa
|
||||
from .pip import Pip
|
||||
from .service import Service
|
||||
|
||||
@ -8,6 +8,9 @@ from ..exceptions import WrongResult
|
||||
class Action:
|
||||
parent = None
|
||||
contextualize = []
|
||||
colorize = {
|
||||
'[^ ]*([^:]*):': {1: 0},
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.args = args
|
||||
@ -84,7 +87,8 @@ class Action:
|
||||
sys.exit(1)
|
||||
|
||||
def output_factory(self, *args, **kwargs):
|
||||
return Output(*args, kwargs)
|
||||
kwargs.setdefault('regexps', self.colorize)
|
||||
return Output(*args, **kwargs)
|
||||
|
||||
async def __call__(self, *args, **kwargs):
|
||||
self.status = 'running'
|
||||
@ -98,3 +102,8 @@ class Action:
|
||||
if self.status == 'running':
|
||||
self.status = 'success'
|
||||
return result
|
||||
|
||||
def callable(self):
|
||||
async def cb(*a, **k):
|
||||
return await self(*a, **k)
|
||||
return cb
|
||||
|
||||
10
shlax/actions/copy.py
Normal file
10
shlax/actions/copy.py
Normal file
@ -0,0 +1,10 @@
|
||||
from .base import Action
|
||||
|
||||
|
||||
class Copy(Action):
|
||||
def __init__(self, *args):
|
||||
self.src = args[:-1]
|
||||
self.dst = args[-1]
|
||||
|
||||
def call(self, *args, **kwargs):
|
||||
self.copy(self.src, self.dst)
|
||||
51
shlax/actions/pip.py
Normal file
51
shlax/actions/pip.py
Normal file
@ -0,0 +1,51 @@
|
||||
from glob import glob
|
||||
import os
|
||||
|
||||
from .base import Action
|
||||
|
||||
|
||||
class Pip(Action):
|
||||
packages = dict(
|
||||
apt=['python3-pip'],
|
||||
)
|
||||
|
||||
def __init__(self, *pip_packages, pip=None, requirements=None):
|
||||
self.pip_packages = pip_packages
|
||||
self.requirements = requirements
|
||||
|
||||
async def call(self, *args, **kwargs):
|
||||
breakpoint()
|
||||
self.pip = await self.which(('pip3', 'pip', 'pip2'))
|
||||
if not self.pip:
|
||||
raise Exception('Could not find pip command')
|
||||
|
||||
if 'CACHE_DIR' in os.environ:
|
||||
cache = os.path.join(os.getenv('CACHE_DIR'), 'pip')
|
||||
else:
|
||||
cache = os.path.join(os.getenv('HOME'), '.cache', 'pip')
|
||||
|
||||
await script.mount(cache, '/root/.cache/pip')
|
||||
await script.crexec(f'{self.pip} install --upgrade pip')
|
||||
|
||||
# https://github.com/pypa/pip/issues/5599
|
||||
self.pip = 'python3 -m pip'
|
||||
|
||||
pip_packages = []
|
||||
for visitor in script.container.visitors:
|
||||
pp = getattr(visitor, 'pip_packages', None)
|
||||
if not pp:
|
||||
continue
|
||||
pip_packages += pip_packages
|
||||
|
||||
source = [p for p in pip_packages if p.startswith('/')]
|
||||
if source:
|
||||
await script.crexec(
|
||||
f'{self.pip} install --upgrade --editable {" ".join(source)}'
|
||||
)
|
||||
|
||||
nonsource = [p for p in pip_packages if not p.startswith('/')]
|
||||
if nonsource:
|
||||
await script.crexec(f'{self.pip} install --upgrade {" ".join(nonsource)}')
|
||||
|
||||
if self.requirements:
|
||||
await script.crexec(f'{self.pip} install --upgrade -r {self.requirements}')
|
||||
13
shlax/cli.py
13
shlax/cli.py
@ -24,7 +24,6 @@ async def runall(*args, **kwargs):
|
||||
|
||||
@cli2.option('debug', alias='d', help='Display debug output.')
|
||||
async def test(*args, **kwargs):
|
||||
breakpoint()
|
||||
"""Run podctl test over a bunch of paths."""
|
||||
report = []
|
||||
|
||||
@ -112,28 +111,20 @@ async def test(*args, **kwargs):
|
||||
|
||||
|
||||
class ConsoleScript(cli2.ConsoleScript):
|
||||
def call(self, *args, **kwargs):
|
||||
def __call__(self, *args, **kwargs):
|
||||
self.shlaxfile = None
|
||||
shlaxfile = sys.argv.pop(1) if len(sys.argv) > 1 else ''
|
||||
if os.path.exists(shlaxfile.split('::')[0]):
|
||||
self.shlaxfile = Shlaxfile()
|
||||
self.shlaxfile.parse(shlaxfile)
|
||||
for name, action in self.shlaxfile.actions.items():
|
||||
async def cb(*args, **kwargs):
|
||||
return await Localhost(action)(*args, **kwargs)
|
||||
self[name] = cli2.Callable(
|
||||
name,
|
||||
cb,
|
||||
action.callable(),
|
||||
color=getattr(action, 'color', cli2.YELLOW),
|
||||
)
|
||||
return super().__call__(*args, **kwargs)
|
||||
|
||||
def __call__(self, command):
|
||||
args = self.parser.funcargs
|
||||
kwargs = self.parser.funckwargs
|
||||
breakpoint()
|
||||
return command(*args, **kwargs)
|
||||
|
||||
def call(self, command):
|
||||
try:
|
||||
return super().call(command)
|
||||
|
||||
@ -5,12 +5,12 @@ from shlax import *
|
||||
|
||||
class GitLabCIConfig(Script):
|
||||
async def call(self, *args, write=True, **kwargs):
|
||||
await super().__call__(*args, **kwargs)
|
||||
await super().call(*args, **kwargs)
|
||||
self.kwargs = kwargs
|
||||
for name, definition in self.context.items():
|
||||
self.kwargs[name] = definition
|
||||
output = yaml.dump(self.kwargs)
|
||||
print(output)
|
||||
self.output(output)
|
||||
if write:
|
||||
with open('.gitlab-ci.yml', 'w+') as f:
|
||||
f.write(output)
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
class Output:
|
||||
prefixes = dict()
|
||||
colors = (
|
||||
'\x1b[1;36;45m',
|
||||
'\x1b[1;36;41m',
|
||||
@ -8,53 +11,59 @@ class Output:
|
||||
'\x1b[1;37;45m',
|
||||
'\x1b[1;32m',
|
||||
'\x1b[1;37;44m',
|
||||
'\u001b[30;1m',
|
||||
)
|
||||
|
||||
def __init__(self, prefix=None):
|
||||
self.prefix = prefix
|
||||
self.prefixes = dict()
|
||||
self.prefix_length = 0
|
||||
def color(self, code=None):
|
||||
if not code:
|
||||
return '\u001b[0m'
|
||||
code = str(code)
|
||||
return u"\u001b[38;5;" + code + "m"
|
||||
|
||||
def call(self, line, prefix, highlight=True, flush=True):
|
||||
if prefix and prefix not in self.prefixes:
|
||||
self.prefixes[prefix] = (
|
||||
def colorize(self, code, content):
|
||||
return self.color(code) + content + self.color()
|
||||
|
||||
def __init__(self, prefix=None, regexps=None, debug=True, write=None, flush=None):
|
||||
self.prefix = prefix
|
||||
self.debug = debug
|
||||
self.prefix_length = 0
|
||||
self.regexps = regexps or dict()
|
||||
self.write = write or sys.stdout.buffer.write
|
||||
self.flush = flush or sys.stdout.flush
|
||||
|
||||
def __call__(self, line, highlight=True, flush=True):
|
||||
if self.prefix and self.prefix not in self.prefixes:
|
||||
self.prefixes[self.prefix] = (
|
||||
self.colors[len([*self.prefixes.keys()]) - 1]
|
||||
)
|
||||
if len(prefix) > self.prefix_length:
|
||||
self.prefix_length = len(prefix)
|
||||
if len(self.prefix) > self.prefix_length:
|
||||
self.prefix_length = len(self.prefix)
|
||||
|
||||
prefix_color = self.prefixes[prefix] if prefix else ''
|
||||
prefix_padding = '.' * (self.prefix_length - len(prefix) - 2) if prefix else ''
|
||||
prefix_color = self.prefixes[self.prefix] if self.prefix else ''
|
||||
prefix_padding = '.' * (self.prefix_length - len(self.prefix) - 2) if self.prefix else ''
|
||||
if prefix_padding:
|
||||
prefix_padding = ' ' + prefix_padding + ' '
|
||||
|
||||
sys.stdout.buffer.write((
|
||||
self.write((
|
||||
(
|
||||
prefix_color
|
||||
+ prefix_padding
|
||||
+ prefix
|
||||
+ self.prefix
|
||||
+ ' '
|
||||
+ Back.RESET
|
||||
+ Style.RESET_ALL
|
||||
+ Fore.LIGHTBLACK_EX
|
||||
+ '| '
|
||||
+ Style.RESET_ALL
|
||||
if prefix
|
||||
if self.prefix
|
||||
else ''
|
||||
)
|
||||
+ self.highlight(line, highlight)
|
||||
).encode('utf8'))
|
||||
|
||||
if flush:
|
||||
sys.stdout.flush()
|
||||
self.flush()
|
||||
|
||||
def cmd(self, line, prefix):
|
||||
def cmd(self, line):
|
||||
self(
|
||||
Fore.LIGHTBLACK_EX
|
||||
+ '+ '
|
||||
+ Style.RESET_ALL
|
||||
self.colorize(251, '+ ')
|
||||
+ self.highlight(line, 'bash'),
|
||||
prefix,
|
||||
highlight=False
|
||||
)
|
||||
|
||||
@ -73,4 +82,16 @@ class Output:
|
||||
or '\\e[' in line
|
||||
):
|
||||
return line
|
||||
|
||||
for regexp, colors in self.regexps.items():
|
||||
match = re.match(regexp, line)
|
||||
if not match:
|
||||
continue
|
||||
|
||||
for group, color in colors.items():
|
||||
res = match.group(group)
|
||||
if not res:
|
||||
continue
|
||||
line = line.replace(res, self.colorize(color, res))
|
||||
|
||||
return line
|
||||
|
||||
@ -22,16 +22,16 @@ class PrefixStreamProtocol(asyncio.subprocess.SubprocessStreamProtocol):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def pipe_data_received(self, fd, data):
|
||||
if (self.debug is True or 'out' in str(self.debug)) and fd in (1, 2):
|
||||
if (self.output.debug is True or 'out' in str(self.output.debug)) and fd in (1, 2):
|
||||
self.output(data, flush=False)
|
||||
sys.stdout.flush()
|
||||
super().pipe_data_received(fd, data)
|
||||
|
||||
|
||||
def protocol_factory(prefix):
|
||||
def protocol_factory(output):
|
||||
def _p():
|
||||
return PrefixStreamProtocol(
|
||||
prefix,
|
||||
output,
|
||||
limit=asyncio.streams._DEFAULT_LIMIT,
|
||||
loop=asyncio.events.get_event_loop()
|
||||
)
|
||||
@ -79,12 +79,16 @@ class Proc:
|
||||
args = ['sh', '-euc', ' '.join(args)]
|
||||
return args
|
||||
|
||||
def output_factory(self, *args, **kwargs):
|
||||
args = tuple(self.prefix) + args
|
||||
return Output(*args, kwargs)
|
||||
|
||||
async def __call__(self, wait=True):
|
||||
if self.called:
|
||||
raise Exception('Already called: ' + self.cmd)
|
||||
|
||||
if self.debug is True or 'cmd' in str(self.debug):
|
||||
output.cmd(self.cmd, self.prefix)
|
||||
self.output.cmd(self.cmd)
|
||||
|
||||
if self.test:
|
||||
if self.test is True:
|
||||
@ -94,7 +98,7 @@ class Proc:
|
||||
|
||||
loop = asyncio.events.get_event_loop()
|
||||
transport, protocol = await loop.subprocess_exec(
|
||||
protocol_factory(self.prefix), *self.args)
|
||||
protocol_factory(self.output), *self.args)
|
||||
self.proc = asyncio.subprocess.Process(transport, protocol, loop)
|
||||
self.called = True
|
||||
|
||||
|
||||
@ -53,7 +53,7 @@ class Buildah(Localhost):
|
||||
|
||||
async def copy(self, src, dst):
|
||||
"""Run buildah copy to copy a file from host into container."""
|
||||
return await self.exec(f'buildah copy {self.ctr} {src} {dst}')
|
||||
return await self.exec(f'buildah copy {self.ctr} {src} {self.mnt}{dst}')
|
||||
|
||||
async def mount(self, src, dst):
|
||||
"""Mount a host directory into the container."""
|
||||
|
||||
@ -3,6 +3,12 @@ from shlax.contrib.gitlab import *
|
||||
|
||||
PYTEST = 'py.test -svv tests'
|
||||
|
||||
build = Buildah('alpine',
|
||||
Copy('shlax', 'setup.py', '/app'),
|
||||
Pip('/app'),
|
||||
commit='yourlabs/shlax',
|
||||
)
|
||||
|
||||
gitlabci = GitLabCIConfig(
|
||||
Job('test',
|
||||
stage='test',
|
||||
|
||||
24
tests/test_output.py
Normal file
24
tests/test_output.py
Normal file
@ -0,0 +1,24 @@
|
||||
import pytest
|
||||
from shlax import Output
|
||||
|
||||
|
||||
class Write:
|
||||
def __init__(self):
|
||||
self.output = ''
|
||||
def __call__(self, out):
|
||||
self.output += out.decode('utf8')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def write():
|
||||
return Write()
|
||||
|
||||
|
||||
def test_output_regexps(write):
|
||||
output = Output(
|
||||
regexps={'.*': {0: 0}},
|
||||
write=write,
|
||||
flush=lambda: None,
|
||||
)
|
||||
output('foo')
|
||||
assert write.output == output.colorize(0, 'foo')
|
||||
Loading…
x
Reference in New Issue
Block a user