No need for background in cmd output

This commit is contained in:
jpic 2020-02-15 19:01:21 +01:00
parent bd64a0fa3a
commit 67aca9de44
5 changed files with 91 additions and 54 deletions

View File

@ -105,7 +105,10 @@ class Action:
self.output_fail(e) self.output_fail(e)
self.status = 'fail' self.status = 'fail'
proc = getattr(e, 'proc', None) proc = getattr(e, 'proc', None)
result = proc.rc if proc else 1 if proc:
result = proc.rc
else:
raise
else: else:
self.output_success() self.output_success()
if self.status == 'running': if self.status == 'running':
@ -155,3 +158,11 @@ class Action:
def kwargs_output(self): def kwargs_output(self):
return self.kwargs return self.kwargs
def action(self, action, *args, **kwargs):
p = action(*args, **kwargs)
for parent in self.parents():
if hasattr(parent, 'actions'):
break
p.parent = parent
return p

View File

@ -53,12 +53,10 @@ class Packages(Action):
def __init__(self, *packages, **kwargs): def __init__(self, *packages, **kwargs):
self.packages = [] self.packages = []
for package in packages: for package in packages:
line = dedent(package).strip().replace('\n', ' ') line = dedent(package).strip().replace('\n', ' ')
self.packages += line.split(' ') self.packages += line.split(' ')
super().__init__(*packages, **kwargs)
self.mgr = kwargs.pop('mgr') if 'mgr' in kwargs else None
@property @property
def cache_root(self): def cache_root(self):
@ -109,7 +107,7 @@ class Packages(Action):
if cached: if cached:
self.mgr = cached self.mgr = cached
else: else:
mgr = await self.which(*self.mgrs.values()) mgr = await self.which(*self.mgrs.keys())
if mgr: if mgr:
self.mgr = mgr.split('/')[-1] self.mgr = mgr.split('/')[-1]
@ -120,20 +118,18 @@ class Packages(Action):
if not getattr(self, '_packages_upgraded', None): if not getattr(self, '_packages_upgraded', None):
await self.update() await self.update()
await self.rexec(self.cmds['upgrade']) await self.rexec(self.cmds['upgrade'])
# first run on container means inject visitor packages
packages = []
for sibbling in self.sibblings:
pp = getattr(sibbling, 'packages', None)
if pp:
if isinstance(pp, list):
packages += pp
elif self.mgr in pp:
packages += pp[self.mgr]
self._packages_upgraded = True self._packages_upgraded = True
else:
packages = self.packages packages = []
for package in self.packages:
if ',' in package:
parts = package.split(',')
package = parts[0]
if self.mgr in parts[1:]:
# include apt on apt
packages.append(package)
else:
packages.append(package)
await self.rexec(*self.cmds['install'].split(' ') + packages) await self.rexec(*self.cmds['install'].split(' ') + packages)

View File

@ -17,35 +17,36 @@ class Pip(Action):
async def call(self, *args, **kwargs): async def call(self, *args, **kwargs):
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') from .packages import Packages
action = self.action(Packages, 'python3,apk', 'python3-pip,apt', args=args, kwargs=kwargs)
await action(*args, **kwargs)
self.pip = await self.which('pip3', 'pip', 'pip2')
if not self.pip:
raise Exception('Could not install a pip command')
if 'CACHE_DIR' in os.environ: if 'CACHE_DIR' in os.environ:
cache = os.path.join(os.getenv('CACHE_DIR'), 'pip') cache = os.path.join(os.getenv('CACHE_DIR'), 'pip')
else: else:
cache = os.path.join(os.getenv('HOME'), '.cache', 'pip') cache = os.path.join(os.getenv('HOME'), '.cache', 'pip')
await script.mount(cache, '/root/.cache/pip') if getattr(self, 'mount', None):
await script.crexec(f'{self.pip} install --upgrade pip') # we are in a target which shares a mount command
await self.mount(cache, '/root/.cache/pip')
await self.exec(f'{self.pip} install --upgrade pip')
# https://github.com/pypa/pip/issues/5599 # https://github.com/pypa/pip/issues/5599
self.pip = 'python3 -m pip' self.pip = 'python3 -m pip'
pip_packages = [] source = [p for p in self.pip_packages if p.startswith('/')]
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: if source:
await script.crexec( await self.exec(
f'{self.pip} install --upgrade --editable {" ".join(source)}' f'{self.pip} install --upgrade --editable {" ".join(source)}'
) )
nonsource = [p for p in pip_packages if not p.startswith('/')] nonsource = [p for p in self.pip_packages if not p.startswith('/')]
if nonsource: if nonsource:
await script.crexec(f'{self.pip} install --upgrade {" ".join(nonsource)}') await self.exec(f'{self.pip} install --upgrade {" ".join(nonsource)}')
if self.requirements: if self.requirements:
await script.crexec(f'{self.pip} install --upgrade -r {self.requirements}') await self.exec(f'{self.pip} install --upgrade -r {self.requirements}')

View File

@ -59,7 +59,7 @@ 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;15m'
+ ' ' + ' '
+ self.highlight(line, 'bash') + self.highlight(line, 'bash')
+ self.colors['reset'], + self.colors['reset'],

View File

@ -18,15 +18,16 @@ class Buildah(Localhost):
The build script iterates over visitors and runs the build functions, it The build script iterates over visitors and runs the build functions, it
also provides wrappers around the buildah command. also provides wrappers around the buildah command.
""" """
contextualize = Localhost.contextualize + ['mnt', 'ctr'] contextualize = Localhost.contextualize + ['mnt', 'ctr', 'mount']
def __init__(self, base, *args, commit=None, **kwargs): def __init__(self, base, *args, commit=None, push=False, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.base = base self.base = base
self.mounts = dict() self.mounts = dict()
self.ctr = None self.ctr = None
self.mnt = None self.mnt = None
self.commit = commit self.image = Image(commit) if commit else None
self.push = push or os.getenv('CI')
def shargs(self, *args, user=None, buildah=True, **kwargs): def shargs(self, *args, user=None, buildah=True, **kwargs):
if not buildah: if not buildah:
@ -68,20 +69,10 @@ class Buildah(Localhost):
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 self.exec(f'mkdir -p {src} {target}') await self.exec(f'mkdir -p {src} {target}', buildah=False)
await self.exec(f'mount -o bind {src} {target}') await self.exec(f'mount -o bind {src} {target}', buildah=False)
self.mounts[src] = dst self.mounts[src] = dst
async def umounts(self):
"""Unmount all mounted directories from the container."""
for src, dst in self.mounts.items():
await super().exec('umount', self.mnt / str(dst)[1:])
async def umount(self):
"""Unmount the buildah container with buildah unmount."""
if self.ctr:
await super().exec(f'buildah unmount {self.ctr}')
async def which(self, *cmd): async def which(self, *cmd):
""" """
Return the first path to the cmd in the container. Return the first path to the cmd in the container.
@ -95,9 +86,6 @@ class Buildah(Localhost):
if os.path.exists(p): if os.path.exists(p):
return p[len(str(self.mnt)):] return p[len(str(self.mnt)):]
def __repr__(self):
return f'Build'
@property @property
def _compatible(self): def _compatible(self):
return Proc.test or os.getuid() == 0 or getattr(self.parent, 'parent', None) return Proc.test or os.getuid() == 0 or getattr(self.parent, 'parent', None)
@ -106,8 +94,8 @@ class Buildah(Localhost):
if self._compatible: 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) return result
from shlax.cli import cli from shlax.cli import cli
debug = kwargs.get('debug', False) debug = kwargs.get('debug', False)
@ -135,8 +123,49 @@ class Buildah(Localhost):
await proc.communicate() await proc.communicate()
cli.exit_code = await proc.wait() cli.exit_code = await proc.wait()
async def commit(self):
self.sha = (await self.exec(
'buildah',
'commit',
'--format=' + self.image.format,
self.ctr,
buildah=False,
)).out
if self.image.tags:
tags = ' '.join([f'{self.image.repository}:{tag}' for tag in self.image.tags])
await self.exec('buildah', 'tag', self.sha, self.image.repository, tags, buildah=False)
if self.push:
user = os.getenv('DOCKER_USER')
passwd = os.getenv('DOCKER_PASS')
if user and passwd and os.getenv('CI') and self.registry:
await self.exec(
'podman',
'login',
'-u',
user,
'-p',
passwd,
self.registry,
buildah=False,
)
for tag in self.image.tags:
await self.exec('podman', 'push', f'{self.image.repository}:{tag}', buildah=False)
async def clean(self, *args, **kwargs): async def clean(self, *args, **kwargs):
if not self._compatible:
return
for src, dst in self.mounts.items():
await self.exec('umount', self.mnt / str(dst)[1:], buildah=False)
if self.status == 'success':
await self.commit()
if self.mnt is not None: if self.mnt is not None:
await self.exec('buildah', 'umount', self.ctr, buildah=False) await self.exec('buildah', 'umount', self.ctr, buildah=False)
if self.ctr is not None: if self.ctr is not None:
await self.exec('buildah', 'rm', self.ctr, buildah=False) await self.exec('buildah', 'rm', self.ctr, buildah=False)