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) return await self.parent.exec(*['docker', 'exec', self.name] + args)
``` ```
Don't worry about `self.parent` being set, it is enforced to `Localhost` if This also means that you always need a parent with an exec implementation,
unset so that we always have something that actually spawns a process in the there are two:
chain ;)
The result of that design is that the following use cases are open for - Localhost, executes on localhost
business: - Stub, for testing
The result of that design is that the following use cases are available:
```python ```python
# This action installs my favorite package on any distro # This action installs my favorite package on any distro
@ -215,14 +216,48 @@ Ssh(host='yourhost')(build)
# Or on a server behingh a bastion: # Or on a server behingh a bastion:
# ssh yourbastion ssh yourhost build exec apt install python3 # 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 # That's going to do the same
Ssh( Localhost(Ssh(
Ssh( Ssh(
build, build,
host='yourhost' host='yourhost'
), ),
host='bastion' 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 = [] installed = []
def __init__(self, *packages): def __init__(self, *packages, upgrade=True):
self.packages = [] self.packages = []
self.upgrade = upgrade
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(' ')
@ -116,6 +117,7 @@ class Packages:
self.cmds = self.mgrs[self.mgr] self.cmds = self.mgrs[self.mgr]
await self.update(target) await self.update(target)
if self.upgrade:
await target.rexec(self.cmds['upgrade']) await target.rexec(self.cmds['upgrade'])
packages = [] packages = []
@ -160,4 +162,4 @@ class Packages:
return self.cache_root + '/pacman' return self.cache_root + '/pacman'
def __repr__(self): 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 - With the name of a module in shlax.repo: a community maintained shlaxfile
""" """
import ast import ast
import asyncio
import cli2 import cli2
import glob import glob
import inspect import inspect
@ -49,7 +50,19 @@ class ConsoleScript(cli2.ConsoleScript):
mod = importlib.util.module_from_spec(spec) mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod) spec.loader.exec_module(mod)
for member in members: for member in members:
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 from shlax.targets.localhost import Localhost
self[member] = cli2.Callable(member, Localhost(getattr(mod, member))) asyncio.run(Localhost()(command.target))
cli = ConsoleScript(__doc__) cli = ConsoleScript(__doc__)

View File

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

View File

@ -5,3 +5,8 @@ from .targets.stub import Stub
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.parallel import Parallel
from .container import Container
from .pod import Pod

View File

@ -7,11 +7,10 @@ from ..result import Result, Results
class Target: class Target:
def __init__(self, *actions, **options): def __init__(self, *actions):
self.actions = actions self.actions = actions
self.options = options
self.results = [] self.results = []
self.output = Output(self, **self.options) self.output = Output()
self.parent = None self.parent = None
@property @property
@ -32,13 +31,11 @@ class Target:
for action in actions or self.actions: for action in actions or self.actions:
result = Result(self, action) result = Result(self, action)
self.output.start(action)
self.output = Output(action, **self.options)
self.output.start()
try: try:
await action(target=self) await action(target=self)
except Exception as e: except Exception as e:
self.output.fail(e) self.output.fail(action, e)
result.status = 'failure' result.status = 'failure'
result.exception = e result.exception = e
if actions: if actions:
@ -47,7 +44,7 @@ class Target:
else: else:
break break
else: else:
self.output.success() self.output.success(action)
result.status = 'success' result.status = 'success'
finally: finally:
self.caller.results.append(result) self.caller.results.append(result)
@ -55,7 +52,7 @@ class Target:
clean = getattr(action, 'clean', None) clean = getattr(action, 'clean', None)
if clean: if clean:
action.result = result action.result = result
self.output.clean() self.output.clean(action)
await clean(self) await clean(self)
async def rexec(self, *args, **kwargs): async def rexec(self, *args, **kwargs):
@ -77,4 +74,4 @@ class Target:
return result return result
async def exec(self, *args, **kwargs): 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, def __init__(self,
*actions, *actions,
base=None, commit=None, base=None, commit=None,
cmd=None, cmd=None):
**options):
self.base = base or 'alpine' self.base = base or 'alpine'
self.image = Image(commit) if commit else None self.image = Image(commit) if commit else None
@ -28,7 +27,7 @@ class Buildah(Target):
# Always consider localhost as parent for now # Always consider localhost as parent for now
self.parent = Target() self.parent = Target()
super().__init__(*actions, **options) super().__init__(*actions)
def is_runnable(self): def is_runnable(self):
return Proc.test or os.getuid() == 0 return Proc.test or os.getuid() == 0
@ -39,7 +38,9 @@ class Buildah(Target):
return 'Buildah image builder' return 'Buildah image builder'
async def __call__(self, *actions, target=None): async def __call__(self, *actions, target=None):
if target:
self.parent = target self.parent = target
if not self.is_runnable(): if not self.is_runnable():
os.execvp('buildah', ['buildah', 'unshare'] + sys.argv) os.execvp('buildah', ['buildah', 'unshare'] + sys.argv)
# program has been replaced # program has been replaced