Compare commits
11 Commits
cb688bf72b
...
2320c3e37b
Author | SHA1 | Date |
---|---|---|
Gilles Grandou | 2320c3e37b | |
Gilles Grandou | 541b5bf453 | |
Gilles Grandou | 964b72815f | |
Gilles Grandou | 9f1ba0eae6 | |
Gilles Grandou | 71924f0643 | |
Gilles Grandou | 23ca603fa4 | |
Gilles Grandou | 7d559d2f97 | |
Gilles Grandou | da19e96f5c | |
Gilles Grandou | a5db878e51 | |
Gilles Grandou | 78d2185d6c | |
Gilles Grandou | 92551a5687 |
134
install
134
install
|
@ -1,103 +1,41 @@
|
|||
#!/usr/bin/bash
|
||||
#!/bin/bash
|
||||
|
||||
local_bin_dir=~/local/bin
|
||||
local_config_dir=~/.config/runon
|
||||
system_bin_dir=/usr/local/bin
|
||||
system_config_dir=/etc/runon
|
||||
srcdir=$(dirname $(readlink -f $0))
|
||||
venvdir=~/.local/lib/runon
|
||||
bindir=~/.local/bin
|
||||
configdir=~/.config/runon
|
||||
|
||||
op=install
|
||||
bin_dir=$local_bin_dir
|
||||
config_dir=$local_config_dir
|
||||
|
||||
function usage
|
||||
{
|
||||
echo "$0 [local|system] [-u|--uninstall] [<dest>]"
|
||||
echo
|
||||
echo " local install for local user, by default"
|
||||
echo " system install for all users"
|
||||
echo " dev install in dev mode (create links to source)"
|
||||
echo " -u, --uninstall local or system uninstall"
|
||||
echo " <dest> destination dir for binary"
|
||||
echo
|
||||
echo "default local paths:"
|
||||
echo " binary: $local_bin_dir"
|
||||
echo " config: $local_config_dir"
|
||||
echo
|
||||
echo "default system paths:"
|
||||
echo " binary: $system_bin_dir"
|
||||
echo " config: $system_config_dir"
|
||||
echo
|
||||
}
|
||||
|
||||
function do_exec
|
||||
{
|
||||
echo "$@"
|
||||
"$@"
|
||||
}
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case $1 in
|
||||
local)
|
||||
bin_dir=$local_bin_dir
|
||||
config_dir=$local_config_dir
|
||||
;;
|
||||
system)
|
||||
bin_dir=$system_bin_dir
|
||||
config_dir=$system_config_dir
|
||||
;;
|
||||
dev)
|
||||
bin_dir=$local_bin_dir
|
||||
config_dir=$local_config_dir
|
||||
op=installdev
|
||||
;;
|
||||
-u)
|
||||
op=uninstall
|
||||
;;
|
||||
--uninstall)
|
||||
op=uninstall
|
||||
;;
|
||||
-h*)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*) bin_dir=$1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
bin_dir=$(realpath $bin_dir)
|
||||
config_dir=$(realpath $config_dir)
|
||||
|
||||
if [[ ":$PATH:" != *":$bin_dir:"* ]]; then
|
||||
echo "WARNING: $bin_dir is not in your PATH, runon will not be automatically found."
|
||||
echo
|
||||
if [ "$1" == "--dev" ]; then
|
||||
editable=--editable
|
||||
devmode=1
|
||||
fi
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$op" = "install" ]; then
|
||||
do_exec install -d $bin_dir
|
||||
do_exec install -d $config_dir
|
||||
#rm -f $bin_dir/runon
|
||||
#rm -f $config_dir/runon
|
||||
do_exec install runon $bin_dir
|
||||
do_exec install runon.conf $config_dir
|
||||
elif [ "$op" = "installdev" ]; then
|
||||
do_exec install -d $bin_dir
|
||||
do_exec install -d $config_dir
|
||||
do_exec ln -s -f $(realpath runon) $bin_dir/
|
||||
do_exec ln -s -f $(realpath runon.conf) $config_dir/
|
||||
elif [ "$op" = "uninstall" ]; then
|
||||
# find all symlinks targetting to runon, and remove them
|
||||
find $bin_dir -type l | while read l; do
|
||||
if [ "$(readlink $l)" = "runon" ]; then
|
||||
do_exec rm $l
|
||||
fi
|
||||
done
|
||||
|
||||
do_exec rm -f $bin_dir/runon
|
||||
do_exec rm -f $config_dir/runon.conf
|
||||
test -d $bin_dir && do_exec rmdir --parents --ignore-fail-on-non-empty $bin_dir 2> /dev/null
|
||||
test -d $config_dir && do_exec rmdir --parents --ignore-fail-on-non-empty $config_dir 2> /dev/null
|
||||
if [ ! -d $venvdir/bin/activate ]; then
|
||||
echo "create virtualenv $venvdir..."
|
||||
python3 -m venv $venvdir
|
||||
fi
|
||||
source $venvdir/bin/activate
|
||||
|
||||
echo "populate $venvdir..."
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install wheel
|
||||
python3 -m pip install $editable $srcdir
|
||||
|
||||
echo "create links in $bindir..."
|
||||
mkdir -p $bindir
|
||||
ln -sf $venvdir/bin/runon $bindir/
|
||||
|
||||
echo "install base config in $configdir..."
|
||||
mkdir -p $configdir
|
||||
if [ -n "$devmode" ]; then
|
||||
ln -s $srcdir/runon.default.yaml $configdir/
|
||||
else
|
||||
cp -p $srcdir/runon.default.yaml $configdir/
|
||||
fi
|
||||
|
||||
echo "done."
|
||||
|
||||
if [[ ":$PATH:" != *":$(readlink -f $bindir):"* ]]; then
|
||||
echo ""
|
||||
echo "WARNING: $bindir is not in your PATH"
|
||||
fi
|
||||
|
|
110
runon.conf
110
runon.conf
|
@ -1,110 +0,0 @@
|
|||
[DEFAULT]
|
||||
environment =
|
||||
HOME
|
||||
USER
|
||||
DISPLAY
|
||||
TERM
|
||||
debian_chroot=${osname}
|
||||
|
||||
binds =
|
||||
/etc/timezone:ro
|
||||
/etc/localtime:ro
|
||||
/etc/passwd:ro
|
||||
/etc/group:ro
|
||||
/etc/shadow:ro
|
||||
/tmp/.X11-unix:ro
|
||||
/home/${user}
|
||||
|
||||
[centos7]
|
||||
dockerfile =
|
||||
FROM centos:7
|
||||
RUN yum install sudo -y
|
||||
RUN echo "Defaults lecture = never" >> /etc/sudoers
|
||||
RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
|
||||
pkginstall = RUN yum install {} -y
|
||||
packages = ksh csh xterm xorg-x11-apps xkeyboard-config git glibc-devel gtk2 gtk3 alsa-lib python2 python3 bash-completion redhat-lsb-core environment-modules
|
||||
|
||||
[centos8]
|
||||
dockerfile =
|
||||
FROM centos:8
|
||||
RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
|
||||
RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
|
||||
RUN yum install dnf-plugins-core -y
|
||||
RUN yum config-manager --set-enabled powertools -y
|
||||
RUN yum install sudo -y
|
||||
RUN echo "Defaults lecture = never" >> /etc/sudoers
|
||||
RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
|
||||
pkginstall = RUN yum install {} -y
|
||||
packages = ksh csh xterm xorg-x11-apps xkeyboard-config git glibc-devel gtk2 gtk3 alsa-lib python2 python3 bash-completion environment-modules
|
||||
|
||||
[debian8]
|
||||
dockerfile =
|
||||
FROM debian:8
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update
|
||||
RUN apt-get -y install apt-utils
|
||||
RUN apt-get -y upgrade
|
||||
RUN apt-get -y install sudo
|
||||
RUN echo "Defaults lecture = never" >> /etc/sudoers
|
||||
RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
|
||||
pkginstall = RUN apt-get -y install {}
|
||||
packages = ksh csh xterm x11-apps build-essential git libgtk2.0 libgtk-3-0 bash-completion tcl environment-modules
|
||||
|
||||
[debian9]
|
||||
dockerfile =
|
||||
FROM debian:9
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update
|
||||
RUN apt-get -y install apt-utils
|
||||
RUN apt-get -y upgrade
|
||||
RUN apt-get -y install sudo
|
||||
RUN echo "Defaults lecture = never" >> /etc/sudoers
|
||||
RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
|
||||
pkginstall = RUN apt-get -y install {}
|
||||
packages = ksh csh xterm x11-apps build-essential git libgtk2.0 libgtk-3-0 bash-completion tcl environment-modules
|
||||
|
||||
[debian10]
|
||||
dockerfile =
|
||||
FROM debian:10
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update
|
||||
RUN apt-get -y install apt-utils
|
||||
RUN apt-get -y upgrade
|
||||
RUN apt-get -y install sudo
|
||||
RUN echo "Defaults lecture = never" >> /etc/sudoers
|
||||
RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
|
||||
pkginstall = RUN apt-get -y install {}
|
||||
packages = ksh csh xterm x11-apps build-essential git libgtk2.0 libgtk-3-0 bash-completion tcl environment-modules
|
||||
|
||||
[debian11]
|
||||
dockerfile =
|
||||
FROM debian:bullseye
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update
|
||||
RUN apt-get -y install apt-utils
|
||||
RUN apt-get -y install sudo
|
||||
RUN echo "Defaults lecture = never" >> /etc/sudoers
|
||||
pkginstall = RUN apt-get -y install {}
|
||||
packages = ksh csh xterm x11-apps build-essential git libgtk2.0 libgtk-3-0 bash-completion tcl environment-modules
|
||||
|
||||
[ubuntu20.04]
|
||||
dockerfile =
|
||||
FROM ubuntu:20.04
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update
|
||||
RUN apt-get -y install apt-utils
|
||||
RUN apt-get -y install sudo
|
||||
pkginstall = RUN apt-get -y install {}
|
||||
packages = ksh csh xterm x11-apps build-essential git libgtk2.0 libgtk-3.0 bash-completion tcl environment-modules
|
||||
|
||||
|
||||
[ubuntu22.04]
|
||||
dockerfile =
|
||||
FROM ubuntu:22.04
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update
|
||||
RUN apt-get -y install apt-utils
|
||||
RUN apt-get -y install sudo
|
||||
pkginstall = RUN apt-get -y install {}
|
||||
packages = ksh csh xterm x11-apps build-essential git libgtk2.0 libgtk-3.0 bash-completion tcl environment-modules
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
|
||||
debian_base: &debian_base
|
||||
dockerfile:
|
||||
- ARG DEBIAN_FRONTEND=noninteractive
|
||||
- RUN apt-get update
|
||||
- RUN apt-get -y install apt-utils
|
||||
- RUN apt-get -y upgrade
|
||||
- RUN apt-get -y install sudo
|
||||
- RUN echo "Defaults lecture = never" >> /etc/sudoers
|
||||
- RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
|
||||
pkginstall:
|
||||
"RUN apt-get -y install {}"
|
||||
packages:
|
||||
- xterm
|
||||
- x11-apps
|
||||
- vim-gtk3
|
||||
- git
|
||||
- build-essential
|
||||
- python3
|
||||
- bash-completion
|
||||
binds:
|
||||
- /etc/timezone:ro
|
||||
- /etc/localtime:ro
|
||||
- "{home}"
|
||||
environment:
|
||||
- USER
|
||||
- DISPLAY
|
||||
- TERM
|
||||
- container={osname}
|
||||
|
||||
debian9:
|
||||
<<: *debian_base
|
||||
image: docker.io/debian:9
|
||||
dockerfile:
|
||||
- ARG DEBIAN_FRONTEND=noninteractive
|
||||
- RUN echo "deb http://archive.debian.org/debian stretch main" > /etc/apt/sources.list
|
||||
- RUN apt-get update
|
||||
- RUN apt-get -y upgrade
|
||||
- RUN apt install -y --allow-downgrades libnettle6=3.3-1+b2 # default libnettle6 conflicts with libgtk-3.0
|
||||
- RUN apt-get -y install sudo
|
||||
- RUN echo "Defaults lecture = never" >> /etc/sudoers
|
||||
- RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
|
||||
|
||||
debian10:
|
||||
<<: *debian_base
|
||||
image: docker.io/debian:10
|
||||
|
||||
debian11:
|
||||
<<: *debian_base
|
||||
image: docker.io/debian:11
|
||||
|
||||
debian12:
|
||||
<<: *debian_base
|
||||
image: docker.io/debian:12
|
||||
|
||||
ubuntu20.04:
|
||||
<<: *debian_base
|
||||
image: docker.io/ubuntu:20.04
|
||||
|
||||
ubuntu22.04:
|
||||
<<: *debian_base
|
||||
image: docker.io/ubuntu:22.04
|
||||
|
||||
rh_base: &rh_base
|
||||
dockerfile:
|
||||
- RUN dnf install -y sudo
|
||||
- RUN echo "Defaults lecture = never" >> /etc/sudoers
|
||||
- RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
|
||||
- RUN dnf group install -y "Development Tools"
|
||||
pkginstall:
|
||||
"RUN dnf install -y {}"
|
||||
packages:
|
||||
- xterm
|
||||
- vim-X11
|
||||
- git
|
||||
- python3
|
||||
- bash-completion
|
||||
binds:
|
||||
- /etc/timezone:ro
|
||||
- /etc/localtime:ro
|
||||
- "{home}"
|
||||
environment:
|
||||
- USER
|
||||
- DISPLAY
|
||||
- TERM
|
||||
- container={osname}
|
||||
|
||||
|
||||
centos7:
|
||||
<<: *rh_base
|
||||
image: docker.io/centos:7
|
||||
dockerfile:
|
||||
- RUN yum install -y sudo
|
||||
- RUN echo "Defaults lecture = never" >> /etc/sudoers
|
||||
- RUN echo "ALL ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
|
||||
- RUN yum group install -y "Development Tools"
|
||||
pkginstall:
|
||||
"RUN yum install -y {}"
|
||||
|
||||
rocky8:
|
||||
<<: *rh_base
|
||||
image: docker.io/rockylinux:8
|
||||
|
||||
rocky9:
|
||||
<<: *rh_base
|
||||
image: docker.io/rockylinux:9
|
||||
|
307
runon/runon.py
307
runon/runon.py
|
@ -1,60 +1,73 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
import docker
|
||||
import dockerpty
|
||||
import io
|
||||
import json
|
||||
import getpass
|
||||
import platform
|
||||
import os
|
||||
import re
|
||||
import argparse
|
||||
import getpass
|
||||
import pathlib
|
||||
import xdg.BaseDirectory
|
||||
import configparser
|
||||
import yaml
|
||||
import json
|
||||
import datetime
|
||||
import pytz
|
||||
import subprocess
|
||||
from pprint import pprint
|
||||
|
||||
|
||||
def natural_sortkey(string):
|
||||
tokenize = re.compile(r'(\d+)|(\D+)').findall
|
||||
return tuple(int(num) if num else alpha for num, alpha in tokenize(string))
|
||||
def find_config_file(user_conf):
|
||||
conf_list = [
|
||||
'runon.yaml',
|
||||
'.runon.yaml',
|
||||
os.path.join(xdg.BaseDirectory.xdg_config_home, 'runon', 'runon.yaml'),
|
||||
os.path.join(xdg.BaseDirectory.xdg_config_home, 'runon', 'runon.default.yaml')
|
||||
]
|
||||
if user_conf:
|
||||
conf_list = [ user_conf ]
|
||||
for conf in conf_list:
|
||||
if os.path.exists(conf):
|
||||
return conf
|
||||
return None
|
||||
|
||||
def read_ini(user_confname, osname=''):
|
||||
ini_list = [ 'runon.conf', '.runon.conf', os.path.join(xdg.BaseDirectory.xdg_config_home, 'runon', 'runon.conf'), '/etc/runon/runon.conf' ]
|
||||
defaults = {
|
||||
'osname': osname,
|
||||
'user': getpass.getuser()
|
||||
}
|
||||
if user_confname:
|
||||
ini_list.insert(0, user_confname)
|
||||
ini = configparser.ConfigParser(defaults=defaults, interpolation=configparser.ExtendedInterpolation())
|
||||
ini.read(ini_list)
|
||||
return ini
|
||||
|
||||
def list_osnames(user_confname):
|
||||
ini = read_ini(user_confname)
|
||||
return ini.sections()
|
||||
|
||||
def load_config(user_confname, osname):
|
||||
ini = read_ini(user_confname, osname)
|
||||
if not ini.has_section(osname):
|
||||
print('ERROR: cannot find configuration for distribution "{}"'.format(osname))
|
||||
sys.exit(1)
|
||||
conf = {}
|
||||
fields = [ 'dockerfile', 'pkginstall', 'packages', 'environment', 'binds', 'user', 'osname' ]
|
||||
def read_yaml(conf_file):
|
||||
try:
|
||||
for f in fields:
|
||||
conf[f] = ini.get(osname, f)
|
||||
except configparser.NoOptionError as e:
|
||||
print('ERROR: {}'.format(e))
|
||||
with open(conf_file, 'r') as file:
|
||||
conf = yaml.safe_load(file)
|
||||
conf['stamp'] = datetime.datetime.fromtimestamp(os.path.getmtime(conf_file), tz=pytz.UTC)
|
||||
return conf
|
||||
except yaml.YAMLError as e:
|
||||
print(f'ERROR: bad configuration file:')
|
||||
print(e)
|
||||
sys.exit(1)
|
||||
for f in [ 'dockerfile', 'environment', 'binds' ]:
|
||||
conf[f] = [ i for i in conf[f].split('\n') if i ]
|
||||
for f in [ 'packages' ]:
|
||||
conf[f] = conf[f].split()
|
||||
return conf
|
||||
|
||||
def list_osnames(conf_file):
|
||||
conf = read_yaml(conf_file)
|
||||
osnames = []
|
||||
for key in conf:
|
||||
if (type(conf[key]) is dict) and conf[key].get('image'):
|
||||
osnames.append(key)
|
||||
return osnames
|
||||
|
||||
|
||||
def load_config(conf_file, osname):
|
||||
user_vars = {
|
||||
'osname': osname,
|
||||
'user': getpass.getuser(),
|
||||
'uid': os.getuid(),
|
||||
'home': pathlib.Path.home(),
|
||||
}
|
||||
conf = read_yaml(conf_file)
|
||||
osconf = conf.get(osname)
|
||||
if not osconf:
|
||||
print(f"ERROR: cannot find configuration for distribution {osname}")
|
||||
sys.exit(1)
|
||||
|
||||
osconf['stamp'] = conf.get('stamp')
|
||||
osconf['osname'] = osname
|
||||
for k in [ 'dockerfile', 'packages', 'environment', 'binds' ]:
|
||||
if osconf.get(k):
|
||||
osconf[k] = [ s.format(**user_vars) for s in osconf[k]]
|
||||
return osconf
|
||||
|
||||
|
||||
def make_osname_link(binpath, osname):
|
||||
link = os.path.join(os.path.dirname(binpath), osname)
|
||||
|
@ -63,106 +76,104 @@ def make_osname_link(binpath, osname):
|
|||
except FileExistsError:
|
||||
pass
|
||||
|
||||
def make_image_name(osname):
|
||||
user = getpass.getuser()
|
||||
name = 'runon-{}-{}'.format(osname, user)
|
||||
return name
|
||||
def build_image(conf, update, verbose):
|
||||
osname = conf.get('osname')
|
||||
image_name = 'runon-{}'.format(osname)
|
||||
cache_dir = os.path.join(xdg.BaseDirectory.xdg_cache_home, 'runon')
|
||||
cache_file = os.path.join(cache_dir, image_name)
|
||||
|
||||
|
||||
def build_image(client, conf, update, verbose):
|
||||
packages = conf['packages']
|
||||
dockerfile = conf['dockerfile']
|
||||
pkginstall = conf['pkginstall']
|
||||
for p in packages:
|
||||
dockerfile.append(pkginstall.format(p))
|
||||
tag = make_image_name(conf['osname'])
|
||||
try:
|
||||
if not update and os.path.exists(cache_file):
|
||||
ts_image = datetime.datetime.fromtimestamp(os.path.getmtime(cache_file), tz=pytz.UTC)
|
||||
ts_conf = conf.get('stamp')
|
||||
if verbose:
|
||||
# fallback to external command 'docker build' as there is
|
||||
# no way to follow the build progress with API.
|
||||
print('Building image {} ...'.format(tag))
|
||||
cmd = ['docker', 'build']
|
||||
if update:
|
||||
cmd.append('--no-cache')
|
||||
cmd += ['-t', tag, '-']
|
||||
ret = subprocess.run(cmd,
|
||||
input='\n'.join(dockerfile).encode('utf-8'),
|
||||
stderr=subprocess.STDOUT, check=True)
|
||||
image = client.images.get(tag)
|
||||
else:
|
||||
with io.BytesIO('\n'.join(dockerfile).encode('utf-8')) as fd:
|
||||
image, logs = client.images.build(tag=tag, fileobj=fd, rm=True, nocache=update)
|
||||
print('config: {}'.format(ts_conf))
|
||||
print('image: {}'.format(ts_image))
|
||||
if ts_image and ts_image > ts_conf:
|
||||
if verbose:
|
||||
print('Built image {} / {}'.format(image.tags[0], image.short_id))
|
||||
for l in logs:
|
||||
print(l.get('stream', '').strip('\n'))
|
||||
except (docker.errors.BuildError, KeyboardInterrupt, subprocess.CalledProcessError, docker.errors.ImageNotFound) as e:
|
||||
print('Build Error: {}'.format(e))
|
||||
print()
|
||||
print('with dockerfile:')
|
||||
for line in dockerfile:
|
||||
print(' {}'.format(line))
|
||||
sys.exit(1)
|
||||
return image
|
||||
print('image: {} up-to-date'.format(image_name))
|
||||
return image_name
|
||||
|
||||
image = conf.get('image')
|
||||
dockerfile = conf.get('dockerfile')
|
||||
pkginstall = conf.get('pkginstall')
|
||||
packages = conf.get('packages')
|
||||
if not dockerfile:
|
||||
dockerfile = []
|
||||
if image:
|
||||
dockerfile.insert(0, 'FROM {}'.format(image))
|
||||
if packages:
|
||||
for p in packages:
|
||||
dockerfile.append(pkginstall.format(p))
|
||||
|
||||
if verbose:
|
||||
print('Dockerfile:')
|
||||
for l in dockerfile:
|
||||
print(' * {}'.format(l))
|
||||
print('Building image {} ...'.format(image_name))
|
||||
cmd = ['podman', 'build']
|
||||
if update:
|
||||
cmd.append('--no-cache')
|
||||
cmd += ['-t', image_name, '-']
|
||||
ret = subprocess.run(cmd,
|
||||
input='\n'.join(dockerfile).encode('utf-8'),
|
||||
stderr=subprocess.STDOUT, check=True)
|
||||
|
||||
if not os.path.exists(cache_dir):
|
||||
os.mkdir(cache_dir)
|
||||
with open(cache_file, 'w') as file:
|
||||
if verbose:
|
||||
print('cache: {}'.format(cache_file))
|
||||
file.write('')
|
||||
|
||||
return image_name
|
||||
|
||||
|
||||
def create_container(client, image, conf, command, verbose):
|
||||
volumes = {}
|
||||
def run_image(name, conf, command, verbose):
|
||||
volumes = {
|
||||
}
|
||||
environment = {}
|
||||
for mnt in conf['binds']:
|
||||
mnt = mnt.split(':')
|
||||
if mnt[-1] in ['ro','rw']:
|
||||
mode = mnt[-1]
|
||||
del mnt[-1]
|
||||
else:
|
||||
mode = 'rw'
|
||||
mnt = mnt[:2]
|
||||
bind = mnt[-1]
|
||||
vol = mnt[0]
|
||||
volumes[vol] = { 'bind': bind, 'mode': mode }
|
||||
hostname = platform.node()
|
||||
for v in conf['environment']:
|
||||
e = v.split('=')
|
||||
if len(e) == 1:
|
||||
e.append(os.getenv(e[0]))
|
||||
environment[e[0]] = e[1]
|
||||
#environment['debian_chroot']=conf['osname']
|
||||
user='{}:{}'.format(os.getuid(), os.getgid())
|
||||
pwd=os.getcwd()
|
||||
if conf.get('binds'):
|
||||
for mnt in conf['binds']:
|
||||
mnt = mnt.split(':')
|
||||
if mnt[-1] in ['ro','rw']:
|
||||
mode = mnt[-1]
|
||||
del mnt[-1]
|
||||
else:
|
||||
mode = 'rw'
|
||||
mnt = mnt[:2]
|
||||
bind = mnt[-1]
|
||||
vol = mnt[0]
|
||||
if os.path.exists(vol):
|
||||
volumes[vol] = { 'bind': bind, 'mode': mode }
|
||||
if conf.get('environment'):
|
||||
for v in conf['environment']:
|
||||
e = v.split('=')
|
||||
if len(e) == 1:
|
||||
e.append(os.getenv(e[0]))
|
||||
environment[e[0]] = e[1]
|
||||
|
||||
container = client.containers.create(image, command,
|
||||
detach=False, stdin_open=True, tty=True,
|
||||
auto_remove=True,
|
||||
hostname=hostname,
|
||||
volumes=volumes,
|
||||
environment=environment,
|
||||
user=user,
|
||||
network_mode='host',
|
||||
working_dir=pwd
|
||||
)
|
||||
return container
|
||||
|
||||
|
||||
def run_container(client, container):
|
||||
try:
|
||||
dockerpty.start(client.api, container.id)
|
||||
container.reload() # to update attrs fields
|
||||
except docker.errors.APIError as e:
|
||||
print('ERROR: {}'.format(e))
|
||||
sys.exit(1)
|
||||
ret = container.attrs['State']['ExitCode']
|
||||
return ret
|
||||
cmd = ['podman', 'run', '--rm', '--interactive', '--tty', '--userns=keep-id', '--net=host' ]
|
||||
for e in environment:
|
||||
cmd += [ '-e', '{}={}'.format(e, environment[e]) ]
|
||||
for v in volumes:
|
||||
cmd += [ '-v', ':'.join([v, volumes[v]['bind'], volumes[v]['mode']]) ]
|
||||
cmd += [ '--workdir', os.getcwd() ]
|
||||
cmd += [ name ]
|
||||
if command:
|
||||
cmd += command
|
||||
if verbose:
|
||||
print('executing: {}\n'.format(' '.join(cmd)))
|
||||
ret = subprocess.run(cmd)
|
||||
return ret.returncode
|
||||
|
||||
|
||||
def main():
|
||||
osname = None
|
||||
run_name = os.path.basename(os.sys.argv[0])
|
||||
if run_name == 'runos':
|
||||
if run_name == "runon":
|
||||
pass
|
||||
elif run_name.startswith('runon'):
|
||||
m = re.match('runon[-_]?(.*)$', run_name)
|
||||
if m:
|
||||
osname = m[1]
|
||||
elif run_name.startswith("runon_"):
|
||||
osname = run_name[len("runon_"):]
|
||||
else:
|
||||
osname = run_name
|
||||
|
||||
|
@ -173,7 +184,8 @@ def main():
|
|||
parser.description = 'run commands on any distribution'
|
||||
parser.add_argument('osname',
|
||||
help = 'distribution name to run on, '
|
||||
'"list" to dump all available distributions')
|
||||
'"list" to dump all available distributions, '
|
||||
'"edit" to open the current config file in a text editor.')
|
||||
parser.epilog = '(c) 2021 Gilles Grandou <gilles@grandou.net>'
|
||||
|
||||
parser.add_argument('-v', '--verbose', action='store_true',
|
||||
|
@ -191,27 +203,28 @@ def main():
|
|||
if osname:
|
||||
args.osname = osname
|
||||
|
||||
conf_file = find_config_file(args.config)
|
||||
if not conf_file:
|
||||
print('ERROR: config file not found')
|
||||
sys.exit(1)
|
||||
|
||||
if args.osname == 'list':
|
||||
osnames = list_osnames(args.config)
|
||||
osnames = list_osnames(conf_file)
|
||||
print('Available distributions:')
|
||||
for o in sorted(osnames, key=natural_sortkey):
|
||||
for o in sorted(osnames):
|
||||
print(' {}'.format(o))
|
||||
print()
|
||||
if args.link:
|
||||
for o in osnames:
|
||||
make_osname_link(sys.argv[0], args.osname)
|
||||
return 0
|
||||
elif args.osname == 'edit':
|
||||
cmd = [ 'xdg-open', conf_file ]
|
||||
ret = subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL);
|
||||
return 0
|
||||
|
||||
client = docker.from_env()
|
||||
conf = load_config(args.config, args.osname)
|
||||
if args.link:
|
||||
make_osname_link(sys.argv[0], args.osname)
|
||||
image = build_image(client, conf, args.update, args.verbose)
|
||||
container = create_container(client, image, conf, args.command, args.verbose)
|
||||
ret = run_container(client, container)
|
||||
|
||||
conf = load_config(conf_file, args.osname)
|
||||
image_name = build_image(conf, args.update, args.verbose)
|
||||
ret = run_image(image_name, conf, args.command, args.verbose)
|
||||
return ret
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
ret = main()
|
||||
sys.exit(ret)
|
||||
#
|
||||
|
|
6
setup.py
6
setup.py
|
@ -9,10 +9,10 @@ setup(
|
|||
packages = find_packages(),
|
||||
python_requires = ">=3.6",
|
||||
install_requires = [
|
||||
"docker",
|
||||
"dockerpty",
|
||||
"pathlib",
|
||||
"pyxdg",
|
||||
|
||||
"pyyaml",
|
||||
"pytz",
|
||||
],
|
||||
entry_points={
|
||||
"console_scripts": [
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
cat /etc/os-release
|
||||
echo
|
||||
|
||||
set -x
|
||||
sudo id
|
||||
python3 --version
|
||||
g++ --version | head -1
|
||||
gvim --version | head -1
|
||||
xterm -e /bin/bash -c "sleep 1"
|
||||
date
|
||||
set +x
|
||||
|
||||
echo "[OK]"
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#!/bin/bash
|
||||
|
||||
srcdir=$(dirname $(readlink -f $0))
|
||||
venvdir=~/.local/lib/runon
|
||||
bindir=~/.local/bin
|
||||
configdir=~/.config/runon
|
||||
|
||||
if [ -e $venvdir/bin/runon ]; then
|
||||
echo "remove links from $bindir"
|
||||
find -L $bindir -samefile $bindir/runon -exec rm -v {} \;
|
||||
find -L $bindir -samefile $venvdir/bin/runon -exec rm -v {} \;
|
||||
fi
|
||||
|
||||
if [ -d $venvdir ]; then
|
||||
echo "remove virtualenv $venvdir"
|
||||
rm -rf $venvdir
|
||||
fi
|
||||
|
||||
if [ -e $configdir ]; then
|
||||
echo "remove configs"
|
||||
rm -vf $configdir/runon.default.yaml
|
||||
rmdir -v $configdir || true
|
||||
fi
|
||||
|
||||
echo "done."
|
Loading…
Reference in New Issue