Thread safety, cleaning

This commit is contained in:
jpic 2020-02-15 16:59:36 +01:00
parent 3afc739a1e
commit c96d2494d2
7 changed files with 60 additions and 27 deletions

View File

@ -85,7 +85,7 @@ class Action:
for a in self.parents() + self.sibblings() + self.children(): for a in self.parents() + self.sibblings() + self.children():
if name in a.contextualize: if name in a.contextualize:
return getattr(a, name) return getattr(a, name)
raise AttributeError(name) raise AttributeError(f'{type(self).__name__} has no {name}')
async def call(self, *args, **kwargs): async def call(self, *args, **kwargs):
print(f'{self}.call(*args, **kwargs) not implemented') print(f'{self}.call(*args, **kwargs) not implemented')
@ -101,23 +101,34 @@ class Action:
self.status = 'running' self.status = 'running'
try: try:
result = await self.call(*args, **kwargs) result = await self.call(*args, **kwargs)
except WrongResult as e: except Exception as e:
self.output_fail(e) self.output_fail(e)
self.status = 'fail' self.status = 'fail'
result = e.proc.rc proc = getattr(e, 'proc', None)
result = proc.rc if proc else 1
else: else:
self.output_success() self.output_success()
if self.status == 'running': if self.status == 'running':
self.status = 'success' self.status = 'success'
finally:
clean = getattr(self, 'clean', None)
if clean:
await clean(*args, **kwargs)
return result return result
def output_start(self): def output_start(self):
if self.kwargs.get('quiet', False):
return
self.output.start(self) self.output.start(self)
def output_fail(self, exception=None): def output_fail(self, exception=None):
if self.kwargs.get('quiet', False):
return
self.output.fail(self, exception) self.output.fail(self, exception)
def output_success(self): def output_success(self):
if self.kwargs.get('quiet', False):
return
self.output.success(self) self.output.success(self)
def __repr__(self): def __repr__(self):
@ -130,15 +141,16 @@ class Action:
return ' '.join([ return ' '.join([
self.output.colors['pink1'] self.output.colors['pink1']
+ type(self).__name__ + type(self).__name__
+ self.output.colors['reset'] + self.output.colors['yellow']
] + list(self.args) + [ ] + list(self.args) + [
f'{self.output.colors["blue"]}{k}{self.output.colors["gray"]}={self.output.colors["green2"]}{v}' f'{self.output.colors["blue"]}{k}{self.output.colors["gray"]}={self.output.colors["green2"]}{v}'
for k, v in self.kwargs_output().items() for k, v in self.kwargs_output().items()
] + [self.output.colors['reset']]) ] + [self.output.colors['reset']])
def callable(self): def callable(self):
from ..targets import Localhost
async def cb(*a, **k): async def cb(*a, **k):
return await self(*a, **k) return await Localhost(self, quiet=True)(*a, **k)
return cb return cb
def kwargs_output(self): def kwargs_output(self):

View File

@ -2,9 +2,5 @@ from .base import Action
class Copy(Action): class Copy(Action):
def __init__(self, *args): async def call(self, *args, **kwargs):
self.src = args[:-1] await self.copy(*self.args)
self.dst = args[-1]
def call(self, *args, **kwargs):
self.copy(self.src, self.dst)

View File

@ -12,10 +12,10 @@ class Pip(Action):
def __init__(self, *pip_packages, pip=None, requirements=None): def __init__(self, *pip_packages, pip=None, requirements=None):
self.pip_packages = pip_packages self.pip_packages = pip_packages
self.requirements = requirements self.requirements = requirements
super().__init__(*pip_packages, pip=pip, requirements=requirements)
async def call(self, *args, **kwargs): async def call(self, *args, **kwargs):
breakpoint() self.pip = await self.which('pip3', 'pip', 'pip2')
self.pip = await self.which(('pip3', 'pip', 'pip2'))
if not self.pip: if not self.pip:
raise Exception('Could not find pip command') raise Exception('Could not find pip command')

View File

@ -58,8 +58,9 @@ class Output:
def cmd(self, line): def cmd(self, line):
self( self(
self.colorize(251, '+ ') self.colorize(251, '+')
+ '\x1b[1;38;5;15;48;5;244m' + '\x1b[1;38;5;15;48;5;244m'
+ ' '
+ self.highlight(line, 'bash') + self.highlight(line, 'bash')
+ self.colors['reset'], + self.colors['reset'],
highlight=False highlight=False

View File

@ -14,6 +14,7 @@ class Actions(list):
self.append(action) self.append(action)
def append(self, value): def append(self, value):
value = copy.deepcopy(value)
value.parent = self.owner value.parent = self.owner
value.status = 'pending' value.status = 'pending'
super().append(value) super().append(value)
@ -21,7 +22,7 @@ class Actions(list):
class Script(Action): class Script(Action):
root = '/' root = '/'
contextualize = ['shargs', 'exec', 'rexec', 'env', 'which'] contextualize = ['shargs', 'exec', 'rexec', 'env', 'which', 'copy']
def __init__(self, *actions, **kwargs): def __init__(self, *actions, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
@ -77,3 +78,7 @@ class Script(Action):
p = os.path.join(self.root, path[1:], c) p = os.path.join(self.root, path[1:], c)
if os.path.exists(p): if os.path.exists(p):
return p[len(str(self.root)):] return p[len(str(self.root)):]
async def copy(self, *args):
args = ['cp', '-ra'] + list(args)
return await self.exec(*args)

View File

@ -49,17 +49,27 @@ class Buildah(Localhost):
async def config(self, line): async def config(self, line):
"""Run buildah config.""" """Run buildah config."""
return await self.exec(f'buildah config {line} {self.ctr}') return await self.exec(f'buildah config {line} {self.ctr}', buildah=False)
async def copy(self, src, dst): async def mkdir(self, *dirs):
return await self.exec(*['mkdir', '-p'] + list(dirs))
async def copy(self, *args):
"""Run buildah copy to copy a file from host into container.""" """Run buildah copy to copy a file from host into container."""
return await self.exec(f'buildah copy {self.ctr} {src} {self.mnt}{dst}') src = args[:-1]
dst = args[-1]
await self.mkdir(dst)
args = ['buildah', 'copy', self.ctr] + list(
[str(a) for a in src]
) + [str(dst)]
return await self.exec(*args, buildah=False)
async def mount(self, src, dst): async def mount(self, src, dst):
"""Mount a host directory into the container.""" """Mount a host directory into the container."""
target = self.mnt / str(dst)[1:] target = self.mnt / str(dst)[1:]
await super().exec(f'mkdir -p {src} {target}') await self.exec(f'mkdir -p {src} {target}')
await super().exec(f'mount -o bind {src} {target}') await self.exec(f'mount -o bind {src} {target}')
self.mounts[src] = dst self.mounts[src] = dst
async def umounts(self): async def umounts(self):
@ -88,18 +98,19 @@ class Buildah(Localhost):
def __repr__(self): def __repr__(self):
return f'Build' return f'Build'
async def call(self, *args, debug=False, **kwargs): @property
if Proc.test or os.getuid() == 0 or self.parent.parent: def _compatible(self):
return Proc.test or os.getuid() == 0 or getattr(self.parent, 'parent', None)
async def call(self, *args, **kwargs):
if self._compatible:
self.ctr = (await self.exec('buildah', 'from', self.base, buildah=False)).out self.ctr = (await self.exec('buildah', 'from', self.base, buildah=False)).out
self.mnt = Path((await self.exec('buildah', 'mount', self.ctr, buildah=False)).out) self.mnt = Path((await self.exec('buildah', 'mount', self.ctr, buildah=False)).out)
result = await super().call(*args, **kwargs) return await super().call(*args, **kwargs)
#await self.umounts()
#await self.umount()
await self.exec('buildah', 'rm', self.ctr, raises=False, buildah=False)
return result
from shlax.cli import cli from shlax.cli import cli
debug = kwargs.get('debug', False)
# restart under buildah unshare environment # restart under buildah unshare environment
argv = [ argv = [
'buildah', 'unshare', 'buildah', 'unshare',
@ -123,3 +134,8 @@ class Buildah(Localhost):
) )
await proc.communicate() await proc.communicate()
cli.exit_code = await proc.wait() cli.exit_code = await proc.wait()
async def clean(self, *args, **kwargs):
#await self.umounts()
#await self.umount()
await self.exec('buildah', 'rm', self.ctr, raises=False, buildah=False)

View File

@ -4,6 +4,9 @@ inner = Run()
other = Run('ls') other = Run('ls')
middle = Buildah('alpine', inner, other) middle = Buildah('alpine', inner, other)
outer = Localhost(middle) outer = Localhost(middle)
middle = outer.actions[0]
other = middle.actions[1]
inner = middle.actions[0]
def test_action_init_args(): def test_action_init_args():