Adding Copy/User/Pip actions again
This commit is contained in:
parent
3eb0f22ef9
commit
6a6e474a1e
19
shlax/actions/copy.py
Normal file
19
shlax/actions/copy.py
Normal 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)
|
||||||
@ -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
59
shlax/actions/pip.py
Normal 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
32
shlax/actions/user.py
Normal 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
|
||||||
|
)
|
||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
)
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
15
shlaxfile.py
15
shlaxfile.py
@ -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 *
|
||||||
|
|
||||||
|
shlax = Container(
|
||||||
build=Buildah(
|
build=Buildah(
|
||||||
Run('echo hi'),
|
User('app', '/app', getenv('_CONTAINERS_ROOTLESS_UID')),
|
||||||
Packages('python38'),
|
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())
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user