Adding Copy/User/Pip actions again

This commit is contained in:
jpic 2020-05-30 23:54:10 +02:00
parent 3eb0f22ef9
commit 6a6e474a1e
8 changed files with 180 additions and 13 deletions

19
shlax/actions/copy.py Normal file
View File

@ -0,0 +1,19 @@
class Copy:
def __init__(self, *args):
self.src = args[:-1]
self.dst = args[-1]
@property
def files(self):
for root, dirs, files in os.walk(self.dst):
pass
async def __call__(self, target):
await target.copy(*self.args)
def __str__(self):
return f'Copy(*{self.src}, {self.dst})'
def cachehash(self):
return str(self)

View File

@ -161,5 +161,5 @@ class Packages:
async def pacman_setup(self, target): async def pacman_setup(self, target):
return self.cache_root + '/pacman' return self.cache_root + '/pacman'
def __repr__(self): def __str__(self):
return f'Packages({self.packages}, upgrade={self.upgrade})' return f'Packages({self.packages}, upgrade={self.upgrade})'

59
shlax/actions/pip.py Normal file
View File

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

32
shlax/actions/user.py Normal file
View File

@ -0,0 +1,32 @@
import os
import re
from .packages import Packages
class User:
def __init__(self, username, home, uid):
self.username = username
self.home = home
self.uid = uid
def __str__(self):
return f'User({self.username}, {self.home}, {self.uid})'
async def __call__(self, target):
result = await target.rexec('id', self.uid)
if result.rc == 0:
old = re.match('.*\(([^)]*)\).*', result.out).group(1)
await target.rexec(
'usermod',
'-d', self.home,
'-l', self.username,
old
)
else:
await target.rexec(
'useradd',
'-d', self.home,
'-u', self.uid,
self.username
)

View File

@ -3,10 +3,16 @@ from .targets.buildah import Buildah
from .targets.localhost import Localhost from .targets.localhost import Localhost
from .targets.stub import Stub from .targets.stub import Stub
from .actions.copy import Copy
from .actions.packages import Packages from .actions.packages import Packages
from .actions.run import Run from .actions.run import Run
from .actions.pip import Pip from .actions.pip import Pip
from .actions.parallel import Parallel from .actions.parallel import Parallel
from .actions.user import User
from .cli import Command, Group
from .container import Container from .container import Container
from .pod import Pod from .pod import Pod
from os import getenv, environ

View File

@ -1,4 +1,6 @@
import copy import copy
from pathlib import Path
import os
import re import re
from ..output import Output from ..output import Output
@ -7,11 +9,12 @@ from ..result import Result, Results
class Target: class Target:
def __init__(self, *actions): def __init__(self, *actions, root=None):
self.actions = actions self.actions = actions
self.results = [] self.results = []
self.output = Output() self.output = Output()
self.parent = None self.parent = None
self.root = root or os.getcwd()
@property @property
def parent(self): def parent(self):
@ -54,6 +57,8 @@ class Target:
# nested call, re-raise # nested call, re-raise
raise raise
else: else:
import traceback
traceback.print_exception(type(e), e, None)
return True return True
else: else:
self.output.success(action) self.output.success(action)
@ -114,3 +119,28 @@ class Target:
if kwargs.get('wait', True): if kwargs.get('wait', True):
await proc.wait() await proc.wait()
return proc return proc
@property
def root(self):
return self._root
@root.setter
def root(self, value):
self._root = Path(value or os.getcwd())
def path(self, path):
if str(path).startswith('/'):
path = str(path)[1:]
return self.root / path
async def mkdir(self, path):
return await self.exec('mkdir -p ' + str(path))
async def copy(self, *args):
src = args[:-1]
dst = self.path(args[-1])
await self.mkdir(dst)
return await self.exec(
*('cp', '-av') + src,
dst
)

View File

@ -22,7 +22,7 @@ class Buildah(Target):
self.image = Image(commit) if commit else None self.image = Image(commit) if commit else None
self.ctr = None self.ctr = None
self.mnt = None self.root = None
self.mounts = dict() self.mounts = dict()
self.config = dict( self.config = dict(
@ -66,7 +66,7 @@ class Buildah(Target):
return return
self.ctr = (await self.parent.exec('buildah', 'from', self.base)).out self.ctr = (await self.parent.exec('buildah', 'from', self.base)).out
self.mnt = Path((await self.parent.exec('buildah', 'mount', self.ctr)).out) self.root = Path((await self.parent.exec('buildah', 'mount', self.ctr)).out)
await super().__call__(*actions) await super().__call__(*actions)
async def images(self): async def images(self):
@ -96,7 +96,11 @@ class Buildah(Target):
prefix = self.image_previous.tags[0] prefix = self.image_previous.tags[0]
else: else:
prefix = self.base prefix = self.base
key = prefix + repr(action) if hasattr(action, 'cachehash'):
action_key = action.cachehash()
else:
action_key = str(action)
key = prefix + action_key
sha1 = hashlib.sha1(key.encode('ascii')) sha1 = hashlib.sha1(key.encode('ascii'))
return self.image.layer(sha1.hexdigest()) return self.image.layer(sha1.hexdigest())
@ -109,7 +113,7 @@ class Buildah(Target):
async def clean(self, target): async def clean(self, target):
for src, dst in self.mounts.items(): for src, dst in self.mounts.items():
await self.parent.exec('umount', self.mnt / str(dst)[1:]) await self.parent.exec('umount', self.root / str(dst)[1:])
else: else:
return return
@ -118,7 +122,7 @@ class Buildah(Target):
if os.getenv('BUILDAH_PUSH'): if os.getenv('BUILDAH_PUSH'):
await self.image.push(target) await self.image.push(target)
if self.mnt is not None: if self.root is not None:
await self.parent.exec('buildah', 'umount', self.ctr) await self.parent.exec('buildah', 'umount', self.ctr)
if self.ctr is not None: if self.ctr is not None:
@ -126,7 +130,7 @@ class Buildah(Target):
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.root / str(dst)[1:]
await self.parent.exec(f'mkdir -p {src} {target}') await self.parent.exec(f'mkdir -p {src} {target}')
await self.parent.exec(f'mount -o bind {src} {target}') await self.parent.exec(f'mount -o bind {src} {target}')
self.mounts[src] = dst self.mounts[src] = dst
@ -163,3 +167,11 @@ class Buildah(Target):
for tag in tags: for tag in tags:
await self.parent.exec('buildah', 'tag', self.sha, tag) await self.parent.exec('buildah', 'tag', self.sha, tag)
async def mkdir(self, path):
return await self.parent.mkdir(self.root / path)
async def copy(self, *args):
args = list(args)
args[-1] = self.path(args[-1])
return await self.parent.copy(*args)

View File

@ -1,12 +1,21 @@
#!/usr/bin/env shlax #!/usr/bin/env python
""" """
Shlaxfile for shlax itself. Shlaxfile for shlax itself.
""" """
from shlax.shortcuts import * from shlax.shortcuts import *
build = Buildah( shlax = Container(
Run('echo hi'), build=Buildah(
Packages('python38'), User('app', '/app', getenv('_CONTAINERS_ROOTLESS_UID')),
Packages('python38', 'buildah', 'unzip', 'findutils'),
Copy('setup.py', 'shlax', '/app'),
#Pip('/app', pip='pip3.8'),
base='quay.io/podman/stable', base='quay.io/podman/stable',
commit='shlax',
),
) )
if __name__ == '__main__':
print(Group(doc=__doc__).load(shlax).entry_point())