Add Package.upgrade option

This commit is contained in:
jpic 2020-05-30 18:32:00 +02:00
parent 8ab2fbcccd
commit b044dd015e
7 changed files with 96 additions and 45 deletions

View File

@ -187,12 +187,13 @@ class Docker(Target):
return await self.parent.exec(*['docker', 'exec', self.name] + args)
```
Don't worry about `self.parent` being set, it is enforced to `Localhost` if
unset so that we always have something that actually spawns a process in the
chain ;)
This also means that you always need a parent with an exec implementation,
there are two:
The result of that design is that the following use cases are open for
business:
- Localhost, executes on localhost
- Stub, for testing
The result of that design is that the following use cases are available:
```python
# This action installs my favorite package on any distro
@ -215,14 +216,48 @@ Ssh(host='yourhost')(build)
# Or on a server behingh a bastion:
# ssh yourbastion ssh yourhost build exec apt install python3
Ssh(host='bastion')(Ssh(host='yourhost')(build))
Localhost()(Ssh(host='bastion')(Ssh(host='yourhost')(build))
# That's going to do the same
Ssh(
Localhost(Ssh(
Ssh(
build,
host='yourhost'
),
host='bastion'
)()
))()
```
## CLI
You should build your CLI with your favorite CLI framework. Nonetheless, shlax
provides a ConsoleScript built on cli2 (a personnal experiment, still pre-alpha
stage) that will expose any callable you define in a script, for example:
```python
#!/usr/bin/env shlax
from shlax.shortcuts import *
webpack = Container(
build=Buildah(
Packages('npm')
)
)
django = Container(
build=Buildah(
Packages('python')
)
)
pod = Pod(
django=django,
webpack=webpack,
)
```
Running this file will output:
```
```

View File

@ -52,8 +52,9 @@ class Packages:
installed = []
def __init__(self, *packages):
def __init__(self, *packages, upgrade=True):
self.packages = []
self.upgrade = upgrade
for package in packages:
line = dedent(package).strip().replace('\n', ' ')
self.packages += line.split(' ')
@ -116,7 +117,8 @@ class Packages:
self.cmds = self.mgrs[self.mgr]
await self.update(target)
await target.rexec(self.cmds['upgrade'])
if self.upgrade:
await target.rexec(self.cmds['upgrade'])
packages = []
for package in self.packages:
@ -160,4 +162,4 @@ class Packages:
return self.cache_root + '/pacman'
def __repr__(self):
return f'Packages({self.packages})'
return f'Packages({self.packages}, upgrade={self.upgrade})'

View File

@ -5,6 +5,7 @@ Shlax executes mostly in 3 ways:
- With the name of a module in shlax.repo: a community maintained shlaxfile
"""
import ast
import asyncio
import cli2
import glob
import inspect
@ -49,7 +50,19 @@ class ConsoleScript(cli2.ConsoleScript):
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
for member in members:
from shlax.targets.localhost import Localhost
self[member] = cli2.Callable(member, Localhost(getattr(mod, member)))
subject = getattr(mod, member)
if callable(subject):
self[member] = cli2.Callable(member, subject)
else:
importable = cli2.Importable(member, subject)
self[member] = cli2.Group(member)
for cb in importable.get_callables():
self[member][cb.name] = cb
def call(self, command):
if command.name == 'help':
return super().call(command)
from shlax.targets.localhost import Localhost
asyncio.run(Localhost()(command.target))
cli = ConsoleScript(__doc__)

View File

@ -25,15 +25,14 @@ class Output:
def colorize(self, code, content):
return self.color(code) + content + self.color()
def colorized(self):
if hasattr(self.subject, 'colorized'):
return self.subject.colorized(self.colors)
def colorized(self, action):
if hasattr(action, 'colorized'):
return action.colorized(self.colors)
else:
return str(self.subject)
return str(action)
def __init__(
self,
subject=None,
prefix=None,
regexps=None,
debug='cmd,visit,out',
@ -41,7 +40,6 @@ class Output:
flush=None,
**kwargs
):
self.subject = subject
self.prefix = prefix
self.debug = debug
self.prefix_length = 0
@ -114,59 +112,59 @@ class Output:
return line
def test(self):
def test(self, action):
self(''.join([
self.colors['purplebold'],
'! TEST ',
self.colors['reset'],
self.colorized(),
self.colorized(action),
'\n',
]))
def clean(self):
def clean(self, action):
if self.debug:
self(''.join([
self.colors['bluebold'],
'+ CLEAN ',
self.colors['reset'],
self.colorized(),
self.colorized(action),
'\n',
]))
def start(self):
def start(self, action):
if self.debug is True or 'visit' in str(self.debug):
self(''.join([
self.colors['orangebold'],
'⚠ START ',
self.colors['reset'],
self.colorized(),
self.colorized(action),
'\n',
]))
def success(self):
def success(self, action):
if self.debug is True or 'visit' in str(self.debug):
self(''.join([
self.colors['greenbold'],
'✔ SUCCESS ',
self.colors['reset'],
self.colorized(),
self.colorized(action),
'\n',
]))
def fail(self, exception=None):
def fail(self, action, exception=None):
if self.debug is True or 'visit' in str(self.debug):
self(''.join([
self.colors['redbold'],
'✘ FAIL ',
self.colors['reset'],
self.colorized(),
self.colorized(action),
'\n',
]))
def results(self):
def results(self, action):
success = 0
fail = 0
for result in self.subject.results:
for result in action.results:
if result.status == 'success':
success += 1
if result.status == 'failure':

View File

@ -5,3 +5,8 @@ from .targets.stub import Stub
from .actions.packages import Packages
from .actions.run import Run
from .actions.pip import Pip
from .actions.parallel import Parallel
from .container import Container
from .pod import Pod

View File

@ -7,11 +7,10 @@ from ..result import Result, Results
class Target:
def __init__(self, *actions, **options):
def __init__(self, *actions):
self.actions = actions
self.options = options
self.results = []
self.output = Output(self, **self.options)
self.output = Output()
self.parent = None
@property
@ -32,13 +31,11 @@ class Target:
for action in actions or self.actions:
result = Result(self, action)
self.output = Output(action, **self.options)
self.output.start()
self.output.start(action)
try:
await action(target=self)
except Exception as e:
self.output.fail(e)
self.output.fail(action, e)
result.status = 'failure'
result.exception = e
if actions:
@ -47,7 +44,7 @@ class Target:
else:
break
else:
self.output.success()
self.output.success(action)
result.status = 'success'
finally:
self.caller.results.append(result)
@ -55,7 +52,7 @@ class Target:
clean = getattr(action, 'clean', None)
if clean:
action.result = result
self.output.clean()
self.output.clean(action)
await clean(self)
async def rexec(self, *args, **kwargs):
@ -77,4 +74,4 @@ class Target:
return result
async def exec(self, *args, **kwargs):
raise NotImplemented()
raise Exception(f'{self} should run in Localhost() or Stub()')

View File

@ -12,8 +12,7 @@ class Buildah(Target):
def __init__(self,
*actions,
base=None, commit=None,
cmd=None,
**options):
cmd=None):
self.base = base or 'alpine'
self.image = Image(commit) if commit else None
@ -28,7 +27,7 @@ class Buildah(Target):
# Always consider localhost as parent for now
self.parent = Target()
super().__init__(*actions, **options)
super().__init__(*actions)
def is_runnable(self):
return Proc.test or os.getuid() == 0
@ -39,7 +38,9 @@ class Buildah(Target):
return 'Buildah image builder'
async def __call__(self, *actions, target=None):
self.parent = target
if target:
self.parent = target
if not self.is_runnable():
os.execvp('buildah', ['buildah', 'unshare'] + sys.argv)
# program has been replaced