From 30bce4aace6395cb8ca41d61f0d406a82aadcf9d Mon Sep 17 00:00:00 2001 From: Rudra Saraswat Date: Fri, 9 Feb 2024 21:45:59 +0530 Subject: [PATCH 01/10] feat: focus exclusively on core distros --- blend | 19 +++++++------------ blend-settings/src/pages/containers.html | 10 ++-------- init-blend | 24 +----------------------- 3 files changed, 10 insertions(+), 43 deletions(-) diff --git a/blend b/blend index 4328181..88b4424 100755 --- a/blend +++ b/blend @@ -87,19 +87,14 @@ def error(err): distro_map = { - 'arch': 'docker.io/library/archlinux', - 'almalinux-9': 'quay.io/almalinux/almalinux:9', - 'crystal-linux': 'registry.getcryst.al/crystal/misc/docker:latest', - 'debian': 'docker.io/library/debian:latest', - 'fedora-38': 'docker.io/library/fedora:38', - 'kali-linux': 'docker.io/kalilinux/kali-rolling', - 'neurodebian-bookworm': 'docker.io/library/neurodebian:nd120', - 'rocky-linux': 'docker.io/rockylinux/rockylinux:9', - 'ubuntu-22.04': 'docker.io/library/ubuntu:22.04', - 'ubuntu-23.04': 'docker.io/library/ubuntu:23.04' + 'arch-linux': 'docker.io/library/archlinux', + 'debian': 'quay.io/toolbx-images/debian-toolbox:testing', + 'fedora-39': 'registry.fedoraproject.org/fedora-toolbox:39', + 'centos': 'quay.io/toolbx-images/centos-toolbox:latest', + 'ubuntu-22.04': 'quay.io/toolbx/ubuntu-toolbox:22.04', } -default_distro = 'arch' +default_distro = 'arch-linux' def get_distro(): @@ -152,7 +147,7 @@ def core_start_container(name, new_container=False): 'podman', args=['logs', '-f', '--since', str(start_time), name], timeout=300) logproc.logfile_read = sys.stdout.buffer - logproc.expect('Completed container setup.') + logproc.expect('Started container.') logproc.terminate() diff --git a/blend-settings/src/pages/containers.html b/blend-settings/src/pages/containers.html index d7bf67b..dccb3ba 100644 --- a/blend-settings/src/pages/containers.html +++ b/blend-settings/src/pages/containers.html @@ -10,16 +10,10 @@
diff --git a/init-blend b/init-blend index ed00527..0b71ab2 100755 --- a/init-blend +++ b/init-blend @@ -62,29 +62,7 @@ while true; do esac done -cat << 'EOF' - - - ▄▄▄▄ ██▓ ▓█████ ███▄ █ ▓█████▄ -▓█████▄ ▓██▒ ▓█ ▀ ██ ▀█ █ ▒██▀ ██▌ -▒██▒ ▄██▒██░ ▒███ ▓██ ▀█ ██▒░██ █▌ -▒██░█▀ ▒██░ ▒▓█ ▄ ▓██▒ ▐▌██▒░▓█▄ ▌ -░▓█ ▀█▓░██████▒░▒████▒▒██░ ▓██░░▒████▓ -░▒▓███▀▒░ ▒░▓ ░░░ ▒░ ░░ ▒░ ▒ ▒ ▒▒▓ ▒ -▒░▒ ░ ░ ░ ▒ ░ ░ ░ ░░ ░░ ░ ▒░ ░ ▒ ▒ - ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ - ░ ░ ░ ░ ░ ░ ░ - ░ ░ - -=================== - Credits -=================== - -* NVIDIA driver support - Luca Di Maio (from Distrobox) -EOF - -echo -echo 'Starting blend... (this may take a few minutes)' +echo 'Starting container... (this may take a few minutes)' echo bmount() { From 6589caf322a5219b8f5249625b550209939da9a8 Mon Sep 17 00:00:00 2001 From: Rudra Saraswat Date: Fri, 9 Feb 2024 21:46:29 +0530 Subject: [PATCH 02/10] feat: add CentOS --- blend-settings/src/pages/containers.html | 1 + 1 file changed, 1 insertion(+) diff --git a/blend-settings/src/pages/containers.html b/blend-settings/src/pages/containers.html index dccb3ba..54806c2 100644 --- a/blend-settings/src/pages/containers.html +++ b/blend-settings/src/pages/containers.html @@ -12,6 +12,7 @@ From 1840bdab957a0336caa735768c0bde967c06735e Mon Sep 17 00:00:00 2001 From: Rudra Saraswat Date: Fri, 9 Feb 2024 23:16:52 +0530 Subject: [PATCH 03/10] chore: update distros in package installer --- blend | 2 +- blend-settings/src/internal/js/android.js | 2 +- blend-settings/src/internal/js/system.js | 7 +++++++ blend-settings/src/package-installer.html | 13 ++++--------- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/blend b/blend index 88b4424..f34eb5f 100755 --- a/blend +++ b/blend @@ -144,7 +144,7 @@ def core_start_container(name, new_container=False): exit(1) logproc = pexpect.spawn( - 'podman', args=['logs', '-f', '--since', str(start_time), name], timeout=300) + 'podman', args=['logs', '-f', '--since', str(start_time), name], timeout=3600) logproc.logfile_read = sys.stdout.buffer logproc.expect('Started container.') diff --git a/blend-settings/src/internal/js/android.js b/blend-settings/src/internal/js/android.js index f999b58..ba2a955 100644 --- a/blend-settings/src/internal/js/android.js +++ b/blend-settings/src/internal/js/android.js @@ -50,7 +50,7 @@ function install_aurora_store() { let aurora_store_worker = new Worker( `data:text/javascript, require('child_process').spawnSync('sh', ['-c', 'mkdir -p ~/.cache/blend-settings; rm -f ~/.cache/blend-settings/aurora.apk']) - let s1 = require('child_process').spawnSync('sh', ['-c', 'wget -O ~/.cache/blend-settings/aurora.apk https://gitlab.com/AuroraOSS/AuroraStore/uploads/bbc1bd5a77ab2b40bbf288ccbef8d1f0/AuroraStore_4.1.1.apk']).status + let s1 = require('child_process').spawnSync('sh', ['-c', 'wget -O ~/.cache/blend-settings/aurora.apk https://auroraoss.com/AuroraStore/Stable/AuroraStore_4.4.1.apk']).status if (s1 != 0) { postMessage('failed') } else { diff --git a/blend-settings/src/internal/js/system.js b/blend-settings/src/internal/js/system.js index ef7f3c5..c47b719 100644 --- a/blend-settings/src/internal/js/system.js +++ b/blend-settings/src/internal/js/system.js @@ -18,6 +18,13 @@ function update_system() { } function check_system_update() { + if (require('fs').existsSync('/.update')) { + document.getElementById('update-btn').onclick = () => { + require('child_process').spawnSync('reboot') + } + document.getElementById('update-btn').textContent = 'Reboot' + document.getElementById('update-btn').disabled = false + } let start_update_worker = new Worker( `data:text/javascript, let s = require('child_process').spawnSync('systemctl', ['is-active', '--quiet', 'akshara-system-update']).status diff --git a/blend-settings/src/package-installer.html b/blend-settings/src/package-installer.html index e70380f..a20640b 100644 --- a/blend-settings/src/package-installer.html +++ b/blend-settings/src/package-installer.html @@ -97,18 +97,14 @@ document.getElementById('source_select').innerHTML = ` - - - ` } else if (package_name.endsWith('.rpm')) { document.getElementById('packaging-format').src = '../static/RPM.svg' package_type = 'rpm' document.getElementById('source_select').innerHTML = ` - - - + + ` } else if (package_name.endsWith('.apk')) { document.getElementById('packaging-format').src = '../static/APK.svg' @@ -117,15 +113,14 @@ require('fs').stat('/var/lib/waydroid/waydroid.prop', (err, stat) => { if (err != null) { - document.getElementById('install-button').outerHTML = "

You'll need to initialize Android app support from the blendOS Settings app first.

" + document.getElementById('install-button').outerHTML = "

You'll need to initialize Android app support from the System app first.

" } }) } else if (package_name.includes('.pkg.tar')) { document.getElementById('packaging-format').src = '../static/PKG.svg' package_type = 'pkg' document.getElementById('source_select').innerHTML = ` - - + ` } From 11bd0c28b4270bac8156aa31629135d013a6a8f9 Mon Sep 17 00:00:00 2001 From: Rudra Saraswat Date: Fri, 9 Feb 2024 23:24:53 +0530 Subject: [PATCH 04/10] chore: show reboot button on update --- blend-settings/src/internal/js/system.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/blend-settings/src/internal/js/system.js b/blend-settings/src/internal/js/system.js index c47b719..25644ab 100644 --- a/blend-settings/src/internal/js/system.js +++ b/blend-settings/src/internal/js/system.js @@ -22,8 +22,11 @@ function check_system_update() { document.getElementById('update-btn').onclick = () => { require('child_process').spawnSync('reboot') } + document.getElementById('update-btn').textContent = 'Reboot' document.getElementById('update-btn').disabled = false + + return; } let start_update_worker = new Worker( `data:text/javascript, From 9d93042e1f91bd0fda7af6456b35097de9a3169d Mon Sep 17 00:00:00 2001 From: Rudra Saraswat Date: Fri, 9 Feb 2024 23:50:48 +0530 Subject: [PATCH 05/10] fix: logproc term string --- init-blend | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/init-blend b/init-blend index 0b71ab2..ecad72e 100755 --- a/init-blend +++ b/init-blend @@ -386,7 +386,7 @@ for full_file in /usr/share/applications/*.desktop; do chmod 755 "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}" done -echo "Completed container setup." +echo "Started container." mkdir -p /usr/share/applications /usr/bin inotifywait -m /usr/share/applications /usr/bin -e create,delete,move 2>/dev/null | From f1bf3d7e1dd03016667495926df902ed23376987 Mon Sep 17 00:00:00 2001 From: Rudra Saraswat Date: Sat, 10 Feb 2024 10:24:51 +0530 Subject: [PATCH 06/10] feat: allow running binaries with sudo --- blend | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/blend b/blend index f34eb5f..b7fc1ab 100755 --- a/blend +++ b/blend @@ -128,11 +128,17 @@ def check_container(name): def check_container_status(name): - return host_get_output("podman inspect --type container " + name + " --format \"{{.State.Status}}\"") + if os.environ.get('SUDO_USER') == None: + return host_get_output("podman inspect --type container " + name + " --format \"{{.State.Status}}\"") + else: + return host_get_output(f"sudo -u {os.environ.get('SUDO_USER')} podman inspect --type container " + name + " --format \"{{.State.Status}}\"") def core_start_container(name, new_container=False): - subprocess.call(['podman', 'start', name], + sudo = [] + if os.environ.get('SUDO_USER') != None: + sudo = ['sudo', '-u', os.environ.get('SUDO_USER')] + subprocess.call([*sudo, 'podman', 'start', name], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) start_time = time.time() - 1000 # workaround From d1baddc06d8e20021493f260a2315ab01cf770b7 Mon Sep 17 00:00:00 2001 From: Rudra Saraswat Date: Sun, 11 Feb 2024 12:36:19 +0530 Subject: [PATCH 07/10] fix: SUDO_USER not used when starting container --- blend | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/blend b/blend index b7fc1ab..570a068 100755 --- a/blend +++ b/blend @@ -149,8 +149,12 @@ def core_start_container(name, new_container=False): subprocess.call(['podman', 'logs', '--since', str(start_time), name]) exit(1) - logproc = pexpect.spawn( - 'podman', args=['logs', '-f', '--since', str(start_time), name], timeout=3600) + if os.environ.get('SUDO_USER') == None: + logproc = pexpect.spawn( + 'podman', args=['logs', '-f', '--since', str(start_time), name], timeout=3600) + else: + logproc = pexpect.spawn( + 'sudo', args=['-u', os.environ.get('SUDO_USER'), 'podman', 'logs', '-f', '--since', str(start_time), name], timeout=3600) logproc.logfile_read = sys.stdout.buffer logproc.expect('Started container.') From 90bf64f87a3de373cdb27434615f077cdb874299 Mon Sep 17 00:00:00 2001 From: Rudra Saraswat Date: Mon, 3 Jun 2024 18:48:46 +0000 Subject: [PATCH 08/10] feat: include a stripped-down version of the user utility --- user | 252 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100755 user diff --git a/user b/user new file mode 100755 index 0000000..b6624f0 --- /dev/null +++ b/user @@ -0,0 +1,252 @@ +#!/usr/bin/python3 + +import os +import yaml +import click +import subprocess + +from urllib.request import urlopen + + +class colors: + reset = '\033[0m' + bold = '\033[01m' + disable = '\033[02m' + underline = '\033[04m' + reverse = '\033[07m' + strikethrough = '\033[09m' + invisible = '\033[08m' + + class fg: + black = '\033[30m' + red = '\033[31m' + green = '\033[32m' + orange = '\033[33m' + blue = '\033[34m' + purple = '\033[35m' + cyan = '\033[36m' + lightgrey = '\033[37m' + darkgrey = '\033[90m' + lightred = '\033[91m' + lightgreen = '\033[92m' + yellow = '\033[93m' + lightblue = '\033[94m' + pink = '\033[95m' + lightcyan = '\033[96m' + + rainbow = [lightred, orange, yellow, + lightgreen, lightcyan, blue, purple] + seq = 0 + + def random(self): + if self.seq == 7: + self.seq = 0 + self.seq += 1 + return self.rainbow[self.seq - 1] + + def clear_seq(self): + self.seq = 0 + + class bg: + black = '\033[40m' + red = '\033[41m' + green = '\033[42m' + orange = '\033[43m' + blue = '\033[44m' + purple = '\033[45m' + cyan = '\033[46m' + lightgrey = '\033[47m' + + +fg = colors.fg() + + +def info(msg): + print(colors.bold + fg.cyan + '[INFO] ' + + colors.reset + msg + colors.reset) + + +def print_list(msg): + print(colors.bold + fg.random() + '[LIST] ' + + colors.reset + msg + colors.reset) + + +def modrun(msg): + print(colors.bold + fg.green + '[MODRUN] ' + + colors.reset + msg + colors.reset) + + +def container_msg(msg): + print(colors.bold + fg.purple + '[CONTAINER] ' + + colors.reset + msg + colors.reset) + + +def association_msg(msg): + print(colors.bold + fg.random() + '[ASSOCIATION] ' + + colors.reset + msg + colors.reset) + + +def warn(warning): + print(colors.bold + fg.yellow + '[WARNING] ' + + colors.reset + warning + colors.reset) + + +def error(err): + print(colors.bold + fg.red + '[ERROR] ' + + colors.reset + err + colors.reset) + + +def proceed(): + print(colors.bold + fg.red + '[QUESTION] ' + + colors.reset + 'would you like to proceed?' + colors.reset) + info(f'(press {colors.bold}ENTER{colors.reset} to proceed, or {colors.bold}^C{colors.reset}/{colors.bold}^D{colors.reset} to cancel)') + input() + + +@click.group("cli") +def cli(): + """Manage user operations using the user utility on blendOS.""" + + +def main(): + cli(prog_name="user") + + +@cli.command("associate") +@click.argument('association') +@click.argument('container') +def associate_binary(association, container): + ''' + Create an association (for example, apt -> ubuntu) + ''' + + if not os.path.exists(os.path.expanduser(f'~/.local/bin/blend_bin/{association}.{container}')): + error(f'{colors.bold}{association}.{container}{colors.reset} does not exist') + exit() + if os.path.isfile(os.path.expanduser('~/.local/bin/blend_bin/.associations')): + subprocess.run(['sed', '-i', f's/^{association}\\x0//g', + os.path.expanduser('~/.local/bin/blend_bin/.associations')]) + with open(os.path.expanduser('~/.local/bin/blend_bin/.associations'), 'a+') as f: + f.write(f'{association}\0{container}\n') + _exists = os.path.exists(os.path.expanduser( + f'~/.local/bin/blend_bin/{association}')) + subprocess.run(['ln', '-sf', f'{association}.{container}', + os.path.expanduser(f'~/.local/bin/blend_bin/{association}')]) + association_msg(('modified' if _exists else 'created') + + f' {colors.bold}{association} -> {container}{colors.reset}') + + +@cli.command("dissociate") +@click.argument('association') +def associate_binary(association): + ''' + Remove an association + ''' + + if not os.path.exists(os.path.expanduser(f'~/.local/bin/blend_bin/{association}')): + error(f'{colors.bold}{association}{colors.reset} does not exist') + exit() + if os.path.isfile(os.path.expanduser('~/.local/bin/blend_bin/.associations')): + subprocess.run(['sed', '-i', f's/^{association}\\x0//g', + os.path.expanduser('~/.local/bin/blend_bin/.associations')]) + subprocess.run( + ['rm', '-f', os.path.expanduser(f'~/.local/bin/blend_bin/{association}')]) + association_msg(f'dissociated {colors.bold}{association}') + + +@cli.command("create-container") +@click.argument('container_name') +@click.argument('distro', default='arch') +def create_container(container_name, distro): + ''' + Create a container + ''' + if distro not in ('arch', 'almalinux-9', 'crystal-linux', 'debian', 'fedora-38', 'kali-linux', 'neurodebian-bookworm', 'rocky-linux', 'ubuntu-22.04', 'ubuntu-23.04'): + error( + f'distro {colors.bold}{distro}{colors.reset} not supported') + if subprocess.run(['podman', 'container', 'exists', container_name], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0: + error(f'container {colors.bold}{container_name}{colors.reset} already exists') + exit(1) + subprocess.run(['blend', 'create-container', '-cn', container_name, '-d', distro]) + + +@cli.command("delete-container") +@click.argument('container') +def delete_container(container): + ''' + Delete a container + ''' + if subprocess.run(['podman', 'container', 'exists', container], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode != 0: + error(f'container {colors.bold}{container}{colors.reset} does not exist') + exit(1) + subprocess.run(['blend', 'remove-container', container]) + + +@cli.command("shell") +@click.argument('container') +def shell(container): + ''' + Enter a shell inside a container + ''' + if subprocess.run(['podman', 'container', 'exists', container], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode != 0: + error(f'container {colors.bold}{container}{colors.reset} does not exist') + exit(1) + creation_env = os.environ.copy() + creation_env['BLEND_NO_CHECK'] = 'true' + subprocess.run(['blend', 'enter', '-cn', container], env=creation_env) + + +@cli.command("exec") +@click.argument('container') +@click.argument('cmds', nargs=-1, required=True) +def exec_c(container, cmds): + ''' + Run a command inside a container + ''' + if subprocess.run(['podman', 'container', 'exists', container], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode != 0: + error(f'container {colors.bold}{container}{colors.reset} does not exist') + exit(1) + creation_env = os.environ.copy() + creation_env['BLEND_NO_CHECK'] = 'true' + subprocess.run(['blend', 'enter', '-cn', container, '--', *cmds], env=creation_env) + + +@cli.command("install") +@click.argument('container') +@click.argument('pkgs', nargs=-1, required=True) +def install_c(container, pkgs): + ''' + Install a package inside a container + ''' + if os.path.isfile(os.path.expanduser(f'~/.local/bin/blend_bin/apt.{container}')): + subprocess.run([f'sudo.{container}', 'apt', 'update']) + subprocess.run([f'sudo.{container}', 'apt', 'install', *pkgs]) + elif os.path.isfile(os.path.expanduser(f'~/.local/bin/blend_bin/dnf.{container}')): + subprocess.run([f'sudo.{container}', 'dnf', 'install', *pkgs]) + elif os.path.isfile(os.path.expanduser(f'~/.local/bin/blend_bin/pacman.{container}')): + subprocess.run([f'sudo.{container}', 'pacman', '-Syu', *pkgs]) + else: + error(f'container {colors.bold}{container}{colors.reset} does not exist') + exit(1) + + +@cli.command("remove") +@click.argument('container') +@click.argument('pkgs', nargs=-1, required=True) +def remove_c(container, pkgs): + ''' + Remove a package inside a container + ''' + if os.path.isfile(os.path.expanduser(f'~/.local/bin/blend_bin/apt.{container}')): + subprocess.run([f'sudo.{container}', 'apt', 'purge', *pkgs]) + elif os.path.isfile(os.path.expanduser(f'~/.local/bin/blend_bin/dnf.{container}')): + subprocess.run([f'sudo.{container}', 'dnf', 'remove', *pkgs]) + elif os.path.isfile(os.path.expanduser(f'~/.local/bin/blend_bin/pacman.{container}')): + subprocess.run([f'sudo.{container}', 'pacman', '-Rcns', *pkgs]) + else: + error(f'container {colors.bold}{container}{colors.reset} does not exist') + exit(1) + + +if __name__ == '__main__': + main() From 5115de41c19e3b3c4452385b232ac0f8579667d8 Mon Sep 17 00:00:00 2001 From: Rudra Saraswat Date: Wed, 5 Jun 2024 22:30:44 +0000 Subject: [PATCH 09/10] feat: change aurora store download link --- blend-settings/src/internal/js/android.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/blend-settings/src/internal/js/android.js b/blend-settings/src/internal/js/android.js index ba2a955..ae216b3 100644 --- a/blend-settings/src/internal/js/android.js +++ b/blend-settings/src/internal/js/android.js @@ -50,7 +50,7 @@ function install_aurora_store() { let aurora_store_worker = new Worker( `data:text/javascript, require('child_process').spawnSync('sh', ['-c', 'mkdir -p ~/.cache/blend-settings; rm -f ~/.cache/blend-settings/aurora.apk']) - let s1 = require('child_process').spawnSync('sh', ['-c', 'wget -O ~/.cache/blend-settings/aurora.apk https://auroraoss.com/AuroraStore/Stable/AuroraStore_4.4.1.apk']).status + let s1 = require('child_process').spawnSync('sh', ['-c', 'wget -O ~/.cache/blend-settings/aurora.apk https://f-droid.org/repo/com.aurora.store_58.apk']).status if (s1 != 0) { postMessage('failed') } else { @@ -194,4 +194,4 @@ $('#automatic-state-toggle').on('change', () => { } } } -}); \ No newline at end of file +}); From 4dc80a30d7e0cff86fbfa1c46072856dd3f67c08 Mon Sep 17 00:00:00 2001 From: askiiart Date: Tue, 1 Oct 2024 12:02:25 -0500 Subject: [PATCH 10/10] allow arguments for commands running in containers --- user | 1 + 1 file changed, 1 insertion(+) diff --git a/user b/user index b6624f0..ed8d6a4 100755 --- a/user +++ b/user @@ -208,6 +208,7 @@ def exec_c(container, cmds): exit(1) creation_env = os.environ.copy() creation_env['BLEND_NO_CHECK'] = 'true' + cmds = [ cmd.replace('\\-', '-') for cmd in cmds] subprocess.run(['blend', 'enter', '-cn', container, '--', *cmds], env=creation_env)