Compare commits
No commits in common. "master" and "ci" have entirely different histories.
19
README.rst
19
README.rst
@ -7,7 +7,8 @@ Why?
|
||||
In Python we now have async subprocesses which allows to execute several
|
||||
subprocesses at the same time. The purpose of this library is to:
|
||||
|
||||
- stream stderr and stdout in real time while capturing it,
|
||||
- provide an acceptable asyncio subprocess wrapper for my syntaxic taste,
|
||||
- can stream stderr and stdout in real time while capturing it,
|
||||
- real time output must be prefixed for when you execute several commands at
|
||||
the time so that you know which line is for which process, like with
|
||||
docker-compose logs,
|
||||
@ -15,13 +16,6 @@ subprocesses at the same time. The purpose of this library is to:
|
||||
|
||||
This code was copy/pasted between projects and finally extracted on its own.
|
||||
|
||||
Demo
|
||||
====
|
||||
|
||||
.. image:: https://yourlabs.io/oss/shlax/-/raw/master/demo.png
|
||||
|
||||
You will find the demo script in demo.py in this repository.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
@ -102,9 +96,8 @@ will be applied line by line:
|
||||
Where is the rest?
|
||||
==================
|
||||
|
||||
Shlax used to be the name of a much more ambitious poc-project, that you can
|
||||
still find in the ``OLD`` branch of this repository. It has been extracted in
|
||||
two projects with clear boundaries, namely `sysplan
|
||||
Shlax used to be the name of a much more ambitious poc-project that has been
|
||||
extracted in two projects with clear boundaries, namely `sysplan
|
||||
<https://yourlabs.io/oss/sysplan>`_ and `podplan
|
||||
<https://yourlabs.io/oss/podplan>`_ which are still in alpha state, although
|
||||
Shlax as it now, is feature complete and stable.
|
||||
<https://yourlabs.io/oss/podplan>`_ which are still in alpha state, but Shlax
|
||||
as it is feature complete and stable.
|
||||
|
||||
24
demo.py
24
demo.py
@ -1,24 +0,0 @@
|
||||
import asyncio
|
||||
|
||||
from shlax import Subprocess
|
||||
|
||||
|
||||
async def main():
|
||||
colors = {
|
||||
'^(.*).txt$': '{green}\\1.txt',
|
||||
'^(.*).py$': '{bred}\\1.py',
|
||||
}
|
||||
await asyncio.gather(
|
||||
Subprocess(
|
||||
'for i in $(find .. | head); do echo $i; sleep .2; done',
|
||||
regexps=colors,
|
||||
prefix='parent',
|
||||
).wait(),
|
||||
Subprocess(
|
||||
'for i in $(find . | head); do echo $i; sleep .3; done',
|
||||
regexps=colors,
|
||||
prefix='cwd',
|
||||
).wait(),
|
||||
)
|
||||
|
||||
asyncio.run(main())
|
||||
@ -1,7 +1,6 @@
|
||||
import asyncio
|
||||
import functools
|
||||
import re
|
||||
import shlex
|
||||
import sys
|
||||
|
||||
from .colors import colors
|
||||
@ -55,6 +54,7 @@ class Subprocess:
|
||||
if len(args) == 1 and ' ' in args[0]:
|
||||
args = ['sh', '-euc', args[0]]
|
||||
|
||||
self.cmd = ' '.join(args)
|
||||
self.args = args
|
||||
self.quiet = quiet if quiet is not None else False
|
||||
self.prefix = prefix
|
||||
@ -75,18 +75,6 @@ class Subprocess:
|
||||
self.regexps[search] = replace
|
||||
|
||||
async def start(self, wait=True):
|
||||
if not self.quiet:
|
||||
self.output(
|
||||
self.colors.bgray.encode()
|
||||
+ b'+ '
|
||||
+ shlex.join([
|
||||
arg.replace('\n', '\\n')
|
||||
for arg in self.args
|
||||
]).encode()
|
||||
+ self.colors.reset.encode(),
|
||||
highlight=False
|
||||
)
|
||||
|
||||
# Get a reference to the event loop as we plan to use
|
||||
# low-level APIs.
|
||||
loop = asyncio.get_running_loop()
|
||||
|
||||
@ -37,10 +37,12 @@ async def test_wait_unbound():
|
||||
async def test_rc_1():
|
||||
proc = await Proc(
|
||||
'NON EXISTING COMMAND',
|
||||
quiet=True,
|
||||
write=Mock(),
|
||||
).wait()
|
||||
assert proc.rc != 0
|
||||
assert proc.err == 'sh: line 1: NON: command not found'
|
||||
proc.write.assert_called_once_with(
|
||||
b'sh: line 1: NON: command not found\x1b[0m\n'
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@ -68,16 +70,6 @@ async def test_prefix():
|
||||
).wait()
|
||||
|
||||
assert write.mock_calls == [
|
||||
call(
|
||||
Proc.prefix_colors[0].encode()
|
||||
+ b'test_prefix '
|
||||
+ Proc.colors.reset.encode()
|
||||
+ b'| '
|
||||
+ Proc.colors.bgray.encode()
|
||||
+ b'+ sh -euc \'echo hi\''
|
||||
+ Proc.colors.reset.encode()
|
||||
+ b'\n'
|
||||
),
|
||||
call(
|
||||
Proc.prefix_colors[0].encode()
|
||||
+ b'test_prefix '
|
||||
@ -86,16 +78,6 @@ async def test_prefix():
|
||||
+ Proc.colors.reset.encode()
|
||||
+ b'\n'
|
||||
),
|
||||
call(
|
||||
Proc.prefix_colors[1].encode()
|
||||
+ b'test_prefix_1 '
|
||||
+ Proc.colors.reset.encode()
|
||||
+ b'| '
|
||||
+ Proc.colors.bgray.encode()
|
||||
+ b'+ sh -euc \'echo hi\''
|
||||
+ Proc.colors.reset.encode()
|
||||
+ b'\n'
|
||||
),
|
||||
call(
|
||||
Proc.prefix_colors[1].encode()
|
||||
# padding has been added because of output1
|
||||
@ -105,17 +87,6 @@ async def test_prefix():
|
||||
+ Proc.colors.reset.encode()
|
||||
+ b'\n'
|
||||
),
|
||||
call(
|
||||
Proc.prefix_colors[0].encode()
|
||||
# padding has been added because of output1
|
||||
+ b' test_prefix '
|
||||
+ Proc.colors.reset.encode()
|
||||
+ b'| '
|
||||
+ Proc.colors.bgray.encode()
|
||||
+ b'+ sh -euc \'echo hi\''
|
||||
+ Proc.colors.reset.encode()
|
||||
+ b'\n'
|
||||
),
|
||||
call(
|
||||
Proc.prefix_colors[0].encode()
|
||||
# padding has been added because of output1
|
||||
@ -137,16 +108,6 @@ async def test_prefix_multiline():
|
||||
prefix='test_prefix',
|
||||
).wait()
|
||||
assert proc.write.mock_calls == [
|
||||
call(
|
||||
Proc.prefix_colors[0].encode()
|
||||
+ b'test_prefix '
|
||||
+ Proc.colors.reset.encode()
|
||||
+ b'| '
|
||||
+ Proc.colors.bgray.encode()
|
||||
+ b'+ sh -euc \'echo -e "a\\nb"\''
|
||||
+ Proc.colors.reset.encode()
|
||||
+ b'\n'
|
||||
),
|
||||
call(
|
||||
Proc.prefix_colors[0].encode()
|
||||
+ b'test_prefix '
|
||||
@ -179,7 +140,7 @@ async def test_highlight():
|
||||
r'h([\w\d-]+)': 'h{cyan}\\1',
|
||||
}
|
||||
).wait()
|
||||
proc.write.assert_called_with(b'h\x1b[38;5;51mi\x1b[0m\n')
|
||||
proc.write.assert_called_once_with(b'h\x1b[38;5;51mi\x1b[0m\n')
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@ -194,4 +155,4 @@ async def test_highlight_if_not_colored():
|
||||
r'h([\w\d-]+)': 'h{cyan}\\1',
|
||||
}
|
||||
).wait()
|
||||
proc.write.assert_called_with(b'h\x1b[31mi\n')
|
||||
proc.write.assert_called_once_with(b'h\x1b[31mi\n')
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user