From 7f59891a4e6e3657c3625126102c79fc9397e5c5 Mon Sep 17 00:00:00 2001 From: askiiart Date: Wed, 23 Apr 2025 13:42:17 -0500 Subject: [PATCH 1/6] only use `-it` for ttys --- blend | 63 +++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/blend b/blend index 98335d7..716ddef 100755 --- a/blend +++ b/blend @@ -19,7 +19,7 @@ import os import sys -import glob +from sys import stdout import time import shutil import socket @@ -238,14 +238,22 @@ def host_get_output(cmd): return subprocess.run(['bash', '-c', cmd], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout.decode('UTF-8').strip() -def core_get_retcode(cmd): return subprocess.run(['podman', 'exec', '--user', getpass.getuser(), '-it', args.container_name, 'bash', '-c', cmd], - stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode +def core_get_retcode(cmd): + # only use `-it` if stdout is a tty + cmd = ['podman', 'exec', '--user', getpass.getuser(), '-it', + args.container_name, 'bash', '-c', cmd] + cmd = [x for x in cmd if x != '-it' or stdout.isatty()] + return subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode def core_run_container(cmd): if os.getcwd() == os.path.expanduser('~') or os.getcwd().startswith(os.path.expanduser('~') + '/'): - subprocess.call(['podman', 'exec', '--user', getpass.getuser(), - '-w', os.getcwd(), '-it', args.container_name, 'bash', '-c', cmd]) + # only use `-it` if stdout is a tty + cmd = ['podman', 'exec', '--user', getpass.getuser(), + '-w', os.getcwd(), '-it', args.container_name, 'bash', '-c', cmd] + cmd = [x for x in cmd if x != '-it' or stdout.isatty()] + + subprocess.call(cmd) def core_install_pkg(pkg): @@ -424,25 +432,46 @@ def enter_container(): if not os.environ.get('BLEND_COMMAND'): if args.pkg == []: if os.getcwd() == os.path.expanduser('~') or os.getcwd().startswith(os.path.expanduser('~') + '/'): - exit(subprocess.call([*sudo, 'podman', 'exec', *podman_args, - '-w', os.getcwd(), '-it', args.container_name, 'bash'])) + # only use `-it` if stdout is a tty + cmd = [*sudo, 'podman', 'exec', *podman_args, + '-w', os.getcwd(), '-it', args.container_name, 'bash'] + cmd = [x for x in cmd if x != '-it' or stdout.isatty()] + exit(subprocess.call(cmd)) + else: - exit(subprocess.call([*sudo, 'podman', 'exec', *podman_args, '-w', - '/run/host' + os.getcwd(), '-it', args.container_name, 'bash'])) + # only use `-it` if stdout is a tty + cmd = [*sudo, 'podman', 'exec', *podman_args, '-w', + '/run/host' + os.getcwd(), '-it', args.container_name, 'bash'] + cmd = [x for x in cmd if x != '-it' or stdout.isatty()] + exit(subprocess.call(cmd)) else: if os.getcwd() == os.path.expanduser('~') or os.getcwd().startswith(os.path.expanduser('~') + '/'): - exit(subprocess.call([*sudo, 'podman', 'exec', *podman_args, - '-w', os.getcwd(), '-it', args.container_name, *args.pkg])) + # only use `-it` if stdout is a tty + cmd = [*sudo, 'podman', 'exec', *podman_args, + '-w', os.getcwd(), '-it', args.container_name, *args.pkg] + cmd = [x for x in cmd if x != '-it' or stdout.isatty()] + exit(subprocess.call(cmd)) else: - exit(subprocess.call([*sudo, 'podman', 'exec', *podman_args, '-w', - '/run/host' + os.getcwd(), '-it', args.container_name, *args.pkg])) + # only use `-it` if stdout is a tty + cmd = [*sudo, 'podman', 'exec', *podman_args, '-w', + '/run/host' + os.getcwd(), '-it', args.container_name, *args.pkg] + cmd = [x for x in cmd if x != '-it' or stdout.isatty()] + exit(subprocess.call(cmd)) + else: if os.getcwd() == os.path.expanduser('~') or os.getcwd().startswith(os.path.expanduser('~') + '/'): - exit(subprocess.call([*sudo, 'podman', 'exec', *podman_args, '-w', os.getcwd( - ), '-it', args.container_name, 'bash', '-c', os.environ.get('BLEND_COMMAND')])) + # only use `-it` if stdout is a tty + cmd = [*sudo, 'podman', 'exec', *podman_args, '-w', os.getcwd(), '-it', + args.container_name, 'bash', '-c', os.environ.get('BLEND_COMMAND')] + cmd = [x for x in cmd if x != '-it' or stdout.isatty()] + exit(subprocess.call(cmd)) + else: - exit(subprocess.call([*sudo, 'podman', 'exec', *podman_args, '-w', - '/run/host' + os.getcwd(), '-it', args.container_name, 'bash'])) + # only use `-it` if stdout is a tty + cmd = [*sudo, 'podman', 'exec', *podman_args, '-w', + '/run/host' + os.getcwd(), '-it', args.container_name, 'bash'] + cmd = [x for x in cmd if x != '-it' or stdout.isatty()] + exit(subprocess.call(cmd)) def create_container(): From 6a6680403fb39782b87e13bd49996dc5a87a440b Mon Sep 17 00:00:00 2001 From: askiiart Date: Thu, 24 Apr 2025 11:15:12 -0500 Subject: [PATCH 2/6] DRY --- blend | 65 ++++++++++++++++++++++------------------------------------- 1 file changed, 24 insertions(+), 41 deletions(-) diff --git a/blend b/blend index 716ddef..3d20d54 100755 --- a/blend +++ b/blend @@ -83,6 +83,13 @@ def error(err): print(colors.bold + colors.fg.red + '>> e: ' + colors.reset + colors.bold + err + colors.reset) + +def podman_it_remover(cmd: list): + ''' + Removes `-it` from a podman command if stdout is not a tty + ''' + return [x for x in cmd if x != '-it' or stdout.isatty()] + # END @@ -239,21 +246,15 @@ def host_get_output(cmd): return subprocess.run(['bash', '-c', cmd], def core_get_retcode(cmd): - # only use `-it` if stdout is a tty - cmd = ['podman', 'exec', '--user', getpass.getuser(), '-it', - args.container_name, 'bash', '-c', cmd] - cmd = [x for x in cmd if x != '-it' or stdout.isatty()] - return subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode + podman_command = podman_it_remover(['podman', 'exec', '--user', getpass.getuser(), '-it', + args.container_name, 'bash', '-c', cmd]) + return subprocess.run(podman_command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode def core_run_container(cmd): if os.getcwd() == os.path.expanduser('~') or os.getcwd().startswith(os.path.expanduser('~') + '/'): - # only use `-it` if stdout is a tty - cmd = ['podman', 'exec', '--user', getpass.getuser(), - '-w', os.getcwd(), '-it', args.container_name, 'bash', '-c', cmd] - cmd = [x for x in cmd if x != '-it' or stdout.isatty()] - - subprocess.call(cmd) + subprocess.call(podman_it_remover(['podman', 'exec', '--user', getpass.getuser(), + '-w', os.getcwd(), '-it', args.container_name, 'bash', '-c', cmd])) def core_install_pkg(pkg): @@ -432,46 +433,28 @@ def enter_container(): if not os.environ.get('BLEND_COMMAND'): if args.pkg == []: if os.getcwd() == os.path.expanduser('~') or os.getcwd().startswith(os.path.expanduser('~') + '/'): - # only use `-it` if stdout is a tty - cmd = [*sudo, 'podman', 'exec', *podman_args, - '-w', os.getcwd(), '-it', args.container_name, 'bash'] - cmd = [x for x in cmd if x != '-it' or stdout.isatty()] - exit(subprocess.call(cmd)) + exit(subprocess.call(podman_it_remover([*sudo, 'podman', 'exec', *podman_args, + '-w', os.getcwd(), '-it', args.container_name, 'bash']))) else: - # only use `-it` if stdout is a tty - cmd = [*sudo, 'podman', 'exec', *podman_args, '-w', - '/run/host' + os.getcwd(), '-it', args.container_name, 'bash'] - cmd = [x for x in cmd if x != '-it' or stdout.isatty()] - exit(subprocess.call(cmd)) + exit(subprocess.call(podman_it_remover([*sudo, 'podman', 'exec', *podman_args, '-w', + '/run/host' + os.getcwd(), '-it', args.container_name, 'bash']))) else: if os.getcwd() == os.path.expanduser('~') or os.getcwd().startswith(os.path.expanduser('~') + '/'): - # only use `-it` if stdout is a tty - cmd = [*sudo, 'podman', 'exec', *podman_args, - '-w', os.getcwd(), '-it', args.container_name, *args.pkg] - cmd = [x for x in cmd if x != '-it' or stdout.isatty()] - exit(subprocess.call(cmd)) + exit(subprocess.call(podman_it_remover([*sudo, 'podman', 'exec', *podman_args, + '-w', os.getcwd(), '-it', args.container_name, *args.pkg]))) else: - # only use `-it` if stdout is a tty - cmd = [*sudo, 'podman', 'exec', *podman_args, '-w', - '/run/host' + os.getcwd(), '-it', args.container_name, *args.pkg] - cmd = [x for x in cmd if x != '-it' or stdout.isatty()] - exit(subprocess.call(cmd)) + exit(subprocess.call(podman_it_remover([*sudo, 'podman', 'exec', *podman_args, '-w', + '/run/host' + os.getcwd(), '-it', args.container_name, *args.pkg]))) else: if os.getcwd() == os.path.expanduser('~') or os.getcwd().startswith(os.path.expanduser('~') + '/'): - # only use `-it` if stdout is a tty - cmd = [*sudo, 'podman', 'exec', *podman_args, '-w', os.getcwd(), '-it', - args.container_name, 'bash', '-c', os.environ.get('BLEND_COMMAND')] - cmd = [x for x in cmd if x != '-it' or stdout.isatty()] - exit(subprocess.call(cmd)) + exit(subprocess.call(podman_it_remover([*sudo, 'podman', 'exec', *podman_args, '-w', os.getcwd(), '-it', + args.container_name, 'bash', '-c', os.environ.get('BLEND_COMMAND')]))) else: - # only use `-it` if stdout is a tty - cmd = [*sudo, 'podman', 'exec', *podman_args, '-w', - '/run/host' + os.getcwd(), '-it', args.container_name, 'bash'] - cmd = [x for x in cmd if x != '-it' or stdout.isatty()] - exit(subprocess.call(cmd)) + exit(subprocess.call(podman_it_remover([*sudo, 'podman', 'exec', *podman_args, '-w', + '/run/host' + os.getcwd(), '-it', args.container_name, 'bash']))) def create_container(): From 021d2f0aa5e80b7df9f0e1486157b33b9965816e Mon Sep 17 00:00:00 2001 From: askiiart Date: Fri, 25 Apr 2025 08:52:44 -0500 Subject: [PATCH 3/6] add ability to load custom images from file (also not hardcoded anymore) --- blend | 17 +++++++++-------- images.example.yaml | 3 +++ images.yaml | 6 ++++++ 3 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 images.example.yaml create mode 100644 images.yaml diff --git a/blend b/blend index 3d20d54..a5f8ecb 100755 --- a/blend +++ b/blend @@ -27,6 +27,7 @@ import getpass import pexpect import argparse import subprocess +import yaml __version = '2.0.0' @@ -93,14 +94,14 @@ def podman_it_remover(cmd: list): # END -distro_map = { - 'arch-linux': 'quay.io/toolbx/arch-toolbox:latest', - 'debian': 'quay.io/toolbx-images/debian-toolbox:testing', - 'fedora-42': 'quay.io/fedora/fedora-toolbox:42', - 'centos': 'quay.io/toolbx-images/centos-toolbox:latest', - 'ubuntu-22.04': 'quay.io/toolbx/ubuntu-toolbox:22.04', - 'ubuntu-24.04': 'quay.io/toolbx/ubuntu-toolbox:24.04', -} +distro_map = yaml.safe_load(open('/usr/share/blend/images.yaml')) +if os.path.exists(f'/etc/blend/images.yaml'): + distro_map += yaml.safe_load( + open(f'{os.getenv('XDG_CONFIG_HOME')}/blend/images.yaml')) + +if os.path.exists(f'{os.getenv('XDG_CONFIG_HOME')}/blend/images.yaml'): + distro_map += yaml.safe_load( + open(f'{os.getenv('XDG_CONFIG_HOME')}/blend/images.yaml')) default_distro = 'arch-linux' diff --git a/images.example.yaml b/images.example.yaml new file mode 100644 index 0000000..1927866 --- /dev/null +++ b/images.example.yaml @@ -0,0 +1,3 @@ +# Here you can put custom images to be used for blend +# for example: +# opensuse: quay.io/exampleauthor/opensuse:15 diff --git a/images.yaml b/images.yaml new file mode 100644 index 0000000..84a9f79 --- /dev/null +++ b/images.yaml @@ -0,0 +1,6 @@ +arch-linux: quay.io/toolbx/arch-toolbox:latest +debian: quay.io/toolbx-images/debian-toolbox:testing +fedora-42: quay.io/fedora/fedora-toolbox:42 +centos: quay.io/toolbx-images/centos-toolbox:latest +ubuntu-22.04: quay.io/toolbx/ubuntu-toolbox:22.04 +ubuntu-24.04: quay.io/toolbx/ubuntu-toolbox:24.04 From b771df150efd2fff1ff80c42fb0c5adff11db06b Mon Sep 17 00:00:00 2001 From: askiiart Date: Fri, 25 Apr 2025 10:39:14 -0500 Subject: [PATCH 4/6] add aliases and redo the format a bunch --- blend | 51 +++++++++++++++++++++++++++++++++++++-------- images.example.yaml | 3 --- images.yaml | 24 +++++++++++++++------ 3 files changed, 60 insertions(+), 18 deletions(-) delete mode 100644 images.example.yaml diff --git a/blend b/blend index a5f8ecb..204e5af 100755 --- a/blend +++ b/blend @@ -93,20 +93,53 @@ def podman_it_remover(cmd: list): # END +# TODO: fix temp paths before committing -distro_map = yaml.safe_load(open('/usr/share/blend/images.yaml')) -if os.path.exists(f'/etc/blend/images.yaml'): - distro_map += yaml.safe_load( - open(f'{os.getenv('XDG_CONFIG_HOME')}/blend/images.yaml')) -if os.path.exists(f'{os.getenv('XDG_CONFIG_HOME')}/blend/images.yaml'): - distro_map += yaml.safe_load( - open(f'{os.getenv('XDG_CONFIG_HOME')}/blend/images.yaml')) +def image_data_from_dict(dictionary): + ''' + Returns a distro map and aliases from a dict in this format: + + ``` + {'arch-linux': {'image': 'quay.io/toolbx/arch-toolbox:latest', 'aliases': ['arch']}} + ``` + + which is loaded in from yaml config files in this format: + + ```yaml + arch-linux: + image: "quay.io/toolbx/arch-toolbox:latest" + aliases: + - arch + ``` + ''' + distro_map = {} + aliases = {} + + for distro in dictionary.keys(): + distro_map[distro] = dictionary[distro]['image'] + try: + aliases[distro] = dictionary[distro]['aliases'] + except KeyError: + pass + + return (distro_map, aliases) + + +distro_map, aliases = image_data_from_dict( + yaml.safe_load(open('/usr/share/blend/images.yaml'))) +tmp = image_data_from_dict(yaml.safe_load(open('system.yaml'))['images']) +distro_map += tmp[0] +aliases += tmp[1] +tmp += image_data_from_dict(yaml.safe_load( + open(f'{os.getenv('XDG_CONFIG_HOME')}/blend/images.yaml'))) +distro_map += tmp[0] +aliases += tmp[1] default_distro = 'arch-linux' -def get_distro(): +def get_image(): try: return distro_map[args.distro] except: @@ -222,7 +255,7 @@ def core_create_container(): '--userns', 'keep-id', '--annotation', 'run.oci.keep_original_groups=1']) - podman_command.extend([get_distro()]) + podman_command.extend([get_image()]) # User (for init-blend) podman_command.extend(['--uid', str(os.geteuid())]) diff --git a/images.example.yaml b/images.example.yaml deleted file mode 100644 index 1927866..0000000 --- a/images.example.yaml +++ /dev/null @@ -1,3 +0,0 @@ -# Here you can put custom images to be used for blend -# for example: -# opensuse: quay.io/exampleauthor/opensuse:15 diff --git a/images.yaml b/images.yaml index 84a9f79..8753f84 100644 --- a/images.yaml +++ b/images.yaml @@ -1,6 +1,18 @@ -arch-linux: quay.io/toolbx/arch-toolbox:latest -debian: quay.io/toolbx-images/debian-toolbox:testing -fedora-42: quay.io/fedora/fedora-toolbox:42 -centos: quay.io/toolbx-images/centos-toolbox:latest -ubuntu-22.04: quay.io/toolbx/ubuntu-toolbox:22.04 -ubuntu-24.04: quay.io/toolbx/ubuntu-toolbox:24.04 +arch-linux: + image: quay.io/toolbx/arch-toolbox:latest + aliases: + - arch +debian: + image: quay.io/toolbx-images/debian-toolbox:testing +fedora-42: + image: quay.io/fedora/fedora-toolbox:42 + aliases: + - fedora +centos: + image: quay.io/toolbx-images/centos-toolbox:latest +ubuntu-22.04: + image: quay.io/toolbx/ubuntu-toolbox:22.04 +ubuntu-24.04: + image: quay.io/toolbx/ubuntu-toolbox:24.04 + aliases: + - ubuntu From da373914d68273cd77035a29b49f552de917cd6f Mon Sep 17 00:00:00 2001 From: askiiart Date: Fri, 25 Apr 2025 10:40:10 -0500 Subject: [PATCH 5/6] fix paths --- blend | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/blend b/blend index 204e5af..58a18b2 100755 --- a/blend +++ b/blend @@ -128,13 +128,14 @@ def image_data_from_dict(dictionary): distro_map, aliases = image_data_from_dict( yaml.safe_load(open('/usr/share/blend/images.yaml'))) -tmp = image_data_from_dict(yaml.safe_load(open('system.yaml'))['images']) -distro_map += tmp[0] -aliases += tmp[1] -tmp += image_data_from_dict(yaml.safe_load( - open(f'{os.getenv('XDG_CONFIG_HOME')}/blend/images.yaml'))) +tmp = image_data_from_dict(yaml.safe_load(open('/system.yaml'))['images']) distro_map += tmp[0] aliases += tmp[1] +if os.path.exists(f'{os.getenv('XDG_CONFIG_HOME')}/blend/images.yaml'): + tmp = image_data_from_dict(yaml.safe_load( + open(f'{os.getenv('XDG_CONFIG_HOME')}/blend/images.yaml'))) + distro_map += tmp[0] + aliases += tmp[1] default_distro = 'arch-linux' From f5bd881b5d547cb1d2e53be079ae24405014a04e Mon Sep 17 00:00:00 2001 From: askiiart Date: Fri, 25 Apr 2025 10:49:37 -0500 Subject: [PATCH 6/6] handle aliases --- blend | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/blend b/blend index 58a18b2..32de591 100755 --- a/blend +++ b/blend @@ -293,9 +293,6 @@ def core_run_container(cmd): def core_install_pkg(pkg): - if args.distro == 'arch': - args.distro = 'arch-linux' - if args.distro.startswith('fedora-'): if args.noconfirm == True: core_run_container(f'sudo dnf -y install {pkg}') @@ -322,9 +319,6 @@ def core_install_pkg(pkg): def core_remove_pkg(pkg): - if args.distro == 'arch': - args.distro = 'arch-linux' - if args.distro.startswith('fedora-'): if args.noconfirm == True: core_run_container(f'sudo dnf -y remove {pkg}') @@ -344,9 +338,6 @@ def core_remove_pkg(pkg): def core_search_pkg(pkg): - if args.distro == 'arch': - args.distro = 'arch-linux' - if args.distro.startswith('fedora-'): core_run_container(f'dnf search {pkg}') elif args.distro == 'arch-linux': @@ -358,9 +349,6 @@ def core_search_pkg(pkg): def core_show_pkg(pkg): - if args.distro == 'arch': - args.distro = 'arch-linux' - if args.distro.startswith('fedora-'): core_run_container(f'dnf info {pkg}') elif args.distro == 'arch-linux': @@ -415,9 +403,6 @@ def show_blend(): def sync_blends(): - if args.distro == 'arch': - args.distro = 'arch-linux' - if args.distro.startswith('fedora-'): core_run_container(f'dnf makecache') elif args.distro == 'arch-linux': @@ -427,9 +412,6 @@ def sync_blends(): def update_blends(): - if args.distro == 'arch': - args.distro = 'arch-linux' - if args.distro.startswith('fedora-'): if args.noconfirm == True: core_run_container(f'sudo dnf -y upgrade') @@ -494,7 +476,6 @@ def enter_container(): def create_container(): for container in args.pkg: - container = 'ubuntu-24.04' if container == 'ubuntu-24.04-lts' else container args.container_name = container if container in distro_map.keys() and distro_input == None: args.distro = container @@ -578,6 +559,10 @@ if len(sys.argv) == 1: exit() args = parser.parse_intermixed_args() +if args.distro not in distro_map.keys(): + for (distro, al) in aliases: + if args.distro in al: + args.distro = distro command = command_map[args.command]