2023-02-11 06:03:29 -06:00
#!/usr/bin/env python3
2023-04-17 02:26:58 -05:00
import os
import sys
import yaml
import time
2023-04-17 06:18:56 -05:00
import glob
2023-04-17 02:26:58 -05:00
import getpass
import fileinput
import subprocess
2023-02-11 06:03:29 -06:00
def get_containers():
2023-04-17 02:26:58 -05:00
container_list = subprocess.run(['sudo', '-u', user, 'podman', 'ps', '-a', '--no-trunc', '--sort=created', '--format',
2023-02-11 06:03:29 -06:00
'{{.Names}}'], stdout=subprocess.PIPE).stdout.decode('utf-8').strip().split('\n')
try:
with open(os.path.expanduser('~/.config/blend/config.yaml')) as config_file:
data = yaml.safe_load(config_file)
order = data['container_order'].copy()
order.reverse()
container_list.reverse()
for i in container_list:
if i.strip() not in order:
order.insert(0, i)
for i, o in enumerate(order):
if o not in container_list:
del order[i]
return order
except:
return container_list
2023-04-17 02:26:58 -05:00
2023-02-11 06:03:29 -06:00
def list_use_container_bin():
try:
with open(os.path.expanduser('~/.config/blend/config.yaml')) as config_file:
data = yaml.safe_load(config_file)
return data['use_container_bins']
except:
return []
2023-04-17 02:26:58 -05:00
2023-02-11 06:03:29 -06:00
def check_if_present(attr, desktop_str):
for l in desktop_str:
if l.startswith(attr + '='):
return True
return False
2023-04-17 02:26:58 -05:00
2023-02-11 06:03:29 -06:00
def which(bin):
results = []
for dir in os.environ.get('PATH').split(':'):
if os.path.isdir(dir):
2023-04-17 02:26:58 -05:00
if os.path.basename(bin) in os.listdir(dir):
results.append(os.path.join(dir, os.path.basename(bin)))
2023-02-11 06:03:29 -06:00
if results == []:
return None
return results
2023-04-17 02:26:58 -05:00
2023-02-11 06:03:29 -06:00
def create_container_binaries():
_binaries = []
remove_binaries = []
for c in _list:
c = c.strip()
for i in con_get_output(c, '''find /usr/bin -type f -printf "%P\n" 2>/dev/null;
2023-04-25 23:41:52 -05:00
find -L /usr/bin -xtype l -type f -printf "%P\n" 2>/dev/null;
find /usr/local/bin -type f -printf "%P\n" 2>/dev/null;
find -L /usr/local/bin -xtype l -type f -printf "%P\n" 2>/dev/null;''').split('\n'):
2023-02-11 06:03:29 -06:00
i = i.strip()
2023-04-17 02:26:58 -05:00
os.makedirs(os.path.expanduser(
f'~/.local/bin/blend_{c}'), exist_ok=True)
2023-02-11 06:03:29 -06:00
i_present = False
orig_which_out = which(os.path.basename(i))
which_out = None
if orig_which_out != None:
which_out = orig_which_out.copy()
try:
2023-04-17 02:26:58 -05:00
which_out.remove(os.path.expanduser(
f'~/.local/bin/blend_bin/{os.path.basename(i)}'))
2023-02-11 06:03:29 -06:00
except ValueError:
pass
if which_out == []:
which_out = None
if which_out != None and os.path.basename(i) not in _exceptions:
i_present = True
if os.path.basename(i) != 'host-spawn' and i != '' and not i_present:
with open(os.path.expanduser(f'~/.local/bin/blend_{c}/{os.path.basename(i)}.tmp'), 'w') as f:
2023-04-17 02:26:58 -05:00
f.write('#!/bin/bash\n')
f.write(f'# blend container: {c};{i}\n')
2023-02-11 06:03:29 -06:00
if os.path.basename(i) in _exceptions:
f.write(f'# EXCEPTION\n')
2023-04-17 02:26:58 -05:00
f.write('[ -f /run/.containerenv ] && { if [[ -e "/usr/bin/' + os.path.basename(i) + '" ]] || [[ -e "/usr/local/bin/' + os.path.basename(i) + '" ]]; then if [[ -e "/usr/bin/' + os.path.basename(i) + '" ]]; then /usr/bin/' + os.path.basename(
i) + ' "$@"; elif [[ -e "/usr/local/bin/' + os.path.basename(i) + '" ]]; then /usr/local/bin/' + os.path.basename(i) + ' "$@"; fi; exit $?; else echo "This command can be accessed from the host, or from the container \'' + c + '\'."; exit 127; fi } || :\n')
f.write(
f'BLEND_ALLOW_ROOT= BLEND_NO_CHECK= blend enter -cn {c} -- {os.path.basename(i)} "$@"\n')
2023-02-11 06:03:29 -06:00
# XXX: make this bit fully atomic
2023-04-17 02:26:58 -05:00
os.chmod(os.path.expanduser(
f'~/.local/bin/blend_{c}/{os.path.basename(i)}.tmp'), 0o775)
2023-02-11 06:03:29 -06:00
subprocess.call(['mv', os.path.expanduser(f'~/.local/bin/blend_{c}/{os.path.basename(i)}.tmp'),
os.path.expanduser(f'~/.local/bin/blend_{c}/{os.path.basename(i)}')])
_binaries.append((c, os.path.basename(os.path.basename(i))))
os.makedirs(os.path.expanduser(f'~/.local/bin/blend_bin'), exist_ok=True)
for c, i in _binaries:
try:
2023-04-17 02:26:58 -05:00
os.symlink(os.path.expanduser(
f'~/.local/bin/blend_{c}/{i}'), os.path.expanduser(f'~/.local/bin/blend_bin/{i}'))
2023-02-11 06:03:29 -06:00
except FileExistsError:
2023-04-17 02:26:58 -05:00
if subprocess.call(['grep', '-q', f'^# container: {c};{i}$', os.path.expanduser(f'~/.local/bin/blend_bin/{i}')], shell=False):
2023-02-11 06:03:29 -06:00
os.remove(os.path.expanduser(f'~/.local/bin/blend_bin/{i}'))
2023-04-17 02:26:58 -05:00
os.symlink(os.path.expanduser(
f'~/.local/bin/blend_{c}/{i}'), os.path.expanduser(f'~/.local/bin/blend_bin/{i}'))
2023-02-11 06:03:29 -06:00
for i in remove_binaries:
try:
os.remove(i)
except:
pass
for b in os.listdir(os.path.expanduser(f'~/.local/bin/blend_bin')):
if [_b for _b in _binaries if _b[1] == b] == []:
2023-04-17 02:26:58 -05:00
os.remove(os.path.join(os.path.expanduser(
f'~/.local/bin/blend_bin'), b))
2023-04-17 06:18:56 -05:00
for b_dir in glob.glob(os.path.expanduser(f'~/.local/bin/blend_*')):
if os.path.basename(b_dir) != 'blend_bin' and os.path.basename(b_dir)[6:] not in _list:
subprocess.call(['rm', '-rf', b_dir], shell=False)
2023-02-11 06:03:29 -06:00
def create_container_applications():
_apps = []
2023-04-17 02:26:58 -05:00
os.makedirs(os.path.expanduser(
f'~/.local/share/applications'), exist_ok=True)
2023-02-11 06:03:29 -06:00
for c in _list:
c = c.strip()
for i in con_get_output(c, 'find /usr/share/applications -type f 2>/dev/null; find /usr/local/share/applications -type f 2>/dev/null').split('\n'):
orig_path = i.strip()
i = os.path.basename(orig_path)
i_present = (os.path.isfile(f'/usr/share/applications/{i}') or os.path.isfile(f'/usr/local/share/applications/{i}')
2023-04-17 02:26:58 -05:00
or os.path.isfile(os.path.expanduser(f'~/.local/share/applications/{i}')))
2023-02-11 06:03:29 -06:00
if i != '' and not i_present:
with open(os.path.expanduser(f'~/.local/share/applications/blend;{i}'), 'w') as f:
2023-04-17 02:26:58 -05:00
_ = con_get_output(
c, f"sudo sed -i '/^DBusActivatable=/d' {orig_path}")
_ = con_get_output(
c, f"sudo sed -i '/^TryExec=/d' {orig_path}")
2023-02-11 06:03:29 -06:00
contents = con_get_output(c, f'cat {orig_path}')
f.write(contents)
for line in fileinput.input(os.path.expanduser(f'~/.local/share/applications/blend;{i}'), inplace=True):
if line.strip().startswith('Exec='):
line = f'Exec=env BLEND_NO_CHECK= blend enter -cn {c} -- {line[5:]}\n'
elif line.strip().startswith('Icon='):
if '/' in line:
line = line.strip()
2023-04-17 02:26:58 -05:00
_ = con_get_output(
c, f"mkdir -p ~/.local/share/blend/icons/file/\"{c}_{i}\"; cp {line[5:]} ~/.local/share/blend/icons/file/\"{c}_{i}\"")
2023-02-11 06:03:29 -06:00
line = f'Icon={os.path.expanduser("~/.local/share/blend/icons/file/" + c + "_" + i + "/" + os.path.basename(line[5:]))}\n'
else:
line = line.strip()
icons = con_get_output(c, f'''find /usr/share/icons /usr/share/pixmaps /var/lib/flatpak/exports/share/icons \\
-type f -iname "*{line[5:]}*" 2> /dev/null | sort''').split('\r\n')
2023-04-17 02:26:58 -05:00
_ = con_get_output(
c, f"mkdir -p ~/.local/share/blend/icons/\"{c}_{i}\"; cp {icons[0]} ~/.local/share/blend/icons/\"{c}_{i}\"")
2023-02-11 06:03:29 -06:00
line = f'Icon={os.path.expanduser("~/.local/share/blend/icons/" + c + "_" + i + "/" + os.path.basename(icons[0]))}\n'
sys.stdout.write(line)
2023-04-17 02:26:58 -05:00
os.chmod(os.path.expanduser(
f'~/.local/share/applications/blend;{i}'), 0o775)
2023-02-11 06:03:29 -06:00
_apps.append((c, i))
del _
for a in os.listdir(os.path.expanduser(f'~/.local/share/applications')):
if a.startswith('blend;'):
a = a.removeprefix('blend;')
if [_a for _a in _apps if _a[1] == a] == []:
2023-04-17 02:26:58 -05:00
os.remove(os.path.expanduser(
f'~/.local/share/applications/blend;{a}'))
2023-02-11 06:03:29 -06:00
def create_container_sessions(type='xsessions'):
session_dir = f'/usr/share/{type}'
os.makedirs('/usr/share/xsessions', exist_ok=True)
for session in os.listdir(session_dir):
if session.startswith(os.path.join(session_dir, 'blend-')):
os.remove(os.path.join(session_dir, session))
for c in _list:
c = c.strip()
for i in con_get_output(c, f'find {session_dir} -type f 2>/dev/null').split('\n'):
orig_path = i.strip()
i = os.path.basename(orig_path)
if i != '':
with open(os.path.expanduser(f'{session_dir}/blend-{c};{i}'), 'w') as f:
contents = con_get_output(c, f'cat {orig_path}')
f.write(contents)
for line in fileinput.input(os.path.expanduser(f'/{session_dir}/blend-{c};{i}'), inplace=True):
if line.strip().startswith('Name'):
name = line.split('=')[1]
line = f'Name=Container {c}: {name}'
elif line.strip().startswith('Exec='):
line = f'Exec=blend enter -cn {c} -- {line[5:]}'
elif line.strip().startswith('TryExec='):
continue
sys.stdout.write(line)
2023-04-17 02:26:58 -05:00
os.chmod(os.path.expanduser(
f'{session_dir}/blend-{c};{i}'), 0o775)
2023-04-21 08:43:54 -05:00
def con_get_output(name, cmd):
try:
return subprocess.run(['sudo', '-u', user, 'podman', 'exec', '--user', getpass.getuser(), '-it', name, 'bash', '-c', cmd],
stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, timeout=5).stdout.decode('UTF-8').strip()
except subprocess.TimeoutExpired:
return ''
2023-02-11 06:03:29 -06:00
user = getpass.getuser()
try:
user = sys.argv[2]
except:
pass
for c in get_containers():
c = c.strip()
subprocess.call(['podman', 'start', c])
while True:
_list = get_containers()
_exceptions = list_use_container_bin()
create_container_binaries()
create_container_applications()
2023-04-17 13:45:09 -05:00
time.sleep(1)