Improve immutability and snapshots, blend-settings; Revamp blend
This commit is contained in:
parent
9f7dee08a8
commit
de7e60e65e
13 changed files with 288 additions and 247 deletions
|
@ -7,7 +7,9 @@ This repository also contains **blend-settings**, a tool for configuring blend a
|
|||
|
||||
## Credits
|
||||
|
||||
The `init-blend` file in this repository uses a few lines (two sections) uses from distrobox's init script. These lines have been marked and attributed appropriately, and are licensed under [the GPL-3.0 license](https://github.com/89luca89/distrobox/blob/main/COPYING.md).
|
||||
The `init-blend` file in this repository uses a few lines (the sections have been clearly) uses from distrobox's init script. These lines have been marked and attributed appropriately, and are licensed under [the GPL-3.0 license](https://github.com/89luca89/distrobox/blob/main/COPYING.md).
|
||||
|
||||
I would also like to thank Luca Di Maio from Distrobox for NVIDIA driver support in containers.
|
||||
|
||||
Aside from these lines, all the other code in this repository has been written by me (rs2009). `blend-settings` is based on [Modren](https://github.com/RudraSwat/modren), a software store I (rs2009) had written long ago, and is licensed under the same license as the rest of the code in this repository, [the GPL-3.0 license](https://github.com/blend-os/blend/blob/main/LICENSE).
|
||||
|
||||
|
|
65
blend
65
blend
|
@ -128,7 +128,7 @@ def core_start_container(name):
|
|||
logproc = pexpect.spawn('podman', args=['logs', '-f', '--since', str(start_time), name], timeout=300)
|
||||
logproc.logfile_read = sys.stdout.buffer
|
||||
|
||||
logproc.expect('Completed container setup')
|
||||
logproc.expect('Completed container setup.')
|
||||
logproc.terminate()
|
||||
|
||||
def core_create_container():
|
||||
|
@ -189,11 +189,6 @@ def core_create_container():
|
|||
|
||||
core_start_container(name)
|
||||
|
||||
if distro == 'arch':
|
||||
core_run_container('sudo pacman -Sy')
|
||||
core_run_container('sudo pacman --noconfirm -Syu --needed git base-devel')
|
||||
core_run_container('TEMP_DIR="$(mktemp -d)"; cd "${TEMP_DIR}"; git clone https://aur.archlinux.org/yay.git; cd yay; makepkg --noconfirm -si; rm -rf "${TEMP_DIR}"')
|
||||
|
||||
core_get_output = lambda cmd: subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout.decode('UTF-8').strip()
|
||||
|
||||
host_get_output = lambda cmd: subprocess.run(['bash', '-c', cmd],
|
||||
|
@ -399,57 +394,11 @@ if os.geteuid() == 0 and os.environ['BLEND_ALLOW_ROOT'] == None:
|
|||
exit(1)
|
||||
|
||||
description = f'''
|
||||
{colors.bold}{colors.fg.purple}Usage:{colors.reset}
|
||||
blend [command] [options] [arguments]
|
||||
|
||||
{colors.bold}{colors.fg.purple}Version:{colors.reset} {__version}{colors.bold}
|
||||
|
||||
{colors.bold}{colors.bg.purple}blend{colors.reset}{colors.bold} is a package manager for {colors.bg.purple}blendOS{colors.reset}{colors.bold}, which includes support for Arch, Ubuntu and Fedora packages.{colors.reset}
|
||||
Use the 'blendOS Settings' app to create and manage Linux containers, Android apps and immutability configuration.
|
||||
|
||||
{colors.bold}{colors.fg.purple}default distro{colors.reset}: {colors.bold}{colors.fg.lightblue}arch{colors.reset} (default container's name is the same as that of the default distro)
|
||||
|
||||
Here's a list of the supported distros:
|
||||
{colors.bold}1.{colors.reset} arch
|
||||
{colors.bold}2.{colors.reset} fedora-rawhide
|
||||
{colors.bold}3.{colors.reset} ubuntu-22.04
|
||||
{colors.bold}4.{colors.reset} ubuntu-22.10
|
||||
(debian support is coming soon)
|
||||
|
||||
You can use any of these distros by passing the option {colors.bold}--distro=[NAME OF THE DISTRO]{colors.reset}.
|
||||
|
||||
You can even install a supported desktop environment in a blend container (run `blend install-de [DESKTOP ENVIRONMENT NAME]` to install your favorite desktop environment).
|
||||
|
||||
However, this feature is still somewhat experimental, and some apps might be buggy.
|
||||
|
||||
Here's a list of the supported desktop environments:
|
||||
{colors.bold}1.{colors.reset} gnome
|
||||
{colors.bold}2.{colors.reset} mate
|
||||
(support for many more DEs is coming soon)
|
||||
|
||||
{colors.bold}{colors.fg.lightblue}arch{colors.reset} also supports AUR packages, for an extremely large app catalog.
|
||||
|
||||
{colors.bold}{colors.fg.purple}available commands{colors.reset}:
|
||||
{colors.bold}help{colors.reset} Show this help message and exit.
|
||||
{colors.bold}version{colors.reset} Show version information and exit.
|
||||
{colors.bold}enter{colors.reset} Enter the container shell.
|
||||
{colors.bold}install{colors.reset} Install packages inside a container.
|
||||
{colors.bold}remove{colors.reset} Remove packages inside a managed container.
|
||||
{colors.bold}create-container{colors.reset} Create a container managed by blend.
|
||||
{colors.bold}remove-container{colors.reset} Remove a container managed by blend.
|
||||
{colors.bold}list-containers{colors.reset} List all the containers managed by blend.
|
||||
{colors.bold}start-containers{colors.reset} Start all the container managed by blend.
|
||||
{colors.bold}sync{colors.reset} Sync list of available packages from repository.
|
||||
{colors.bold}search{colors.reset} Search for packages in a managed container.
|
||||
{colors.bold}show{colors.reset} Show details about a package.
|
||||
{colors.bold}update{colors.reset} Update all the packages in a managed container.
|
||||
|
||||
{colors.bold}{colors.fg.purple}options for commands{colors.reset}:
|
||||
{colors.bold}-cn CONTAINER NAME, --container-name CONTAINER NAME{colors.reset}
|
||||
set the container name (the default is the name of the distro)
|
||||
{colors.bold}-d DISTRO, --distro DISTRO{colors.reset}
|
||||
set the distro name (supported: arch fedora-rawhide ubuntu-22.04 ubuntu-22.10; default is arch)
|
||||
{colors.bold}-y, --noconfirm{colors.reset} assume yes for all questions
|
||||
{colors.bold}-v, --version{colors.reset} show version information and exit
|
||||
You can install and submit web apps from the Web Store.
|
||||
'''
|
||||
|
||||
epilog = f'''
|
||||
|
@ -458,17 +407,13 @@ epilog = f'''
|
|||
|
||||
parser = argparse.ArgumentParser(description=description, usage=argparse.SUPPRESS,
|
||||
epilog=epilog, formatter_class=argparse.RawTextHelpFormatter)
|
||||
command_map = { 'install': install_blend,
|
||||
'remove': remove_blend,
|
||||
'enter': enter_container,
|
||||
command_map = { 'enter': enter_container,
|
||||
'exec': enter_container,
|
||||
'create-container': core_create_container,
|
||||
'remove-container': remove_container,
|
||||
'list-containers': list_containers,
|
||||
'start-containers': start_containers,
|
||||
'sync': sync_blends,
|
||||
'update': update_blends,
|
||||
'search': search_blend,
|
||||
'show': show_blend,
|
||||
'help': 'help',
|
||||
'version': 'version' }
|
||||
parser.add_argument('command', choices=command_map.keys(), help=argparse.SUPPRESS)
|
||||
|
|
96
blend-files
96
blend-files
|
@ -1,9 +1,17 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os, sys, yaml, time, getpass, shutil, fileinput, subprocess
|
||||
import os
|
||||
import sys
|
||||
import yaml
|
||||
import time
|
||||
import getpass
|
||||
import shutil
|
||||
import fileinput
|
||||
import subprocess
|
||||
|
||||
|
||||
def get_containers():
|
||||
container_list = subprocess.run(['sudo', '-u', user, 'podman', 'ps', '-a', '--no-trunc', '--size', '--sort=created', '--format',
|
||||
container_list = subprocess.run(['sudo', '-u', user, 'podman', 'ps', '-a', '--no-trunc', '--sort=created', '--format',
|
||||
'{{.Names}}'], stdout=subprocess.PIPE).stdout.decode('utf-8').strip().split('\n')
|
||||
|
||||
try:
|
||||
|
@ -22,6 +30,7 @@ def get_containers():
|
|||
except:
|
||||
return container_list
|
||||
|
||||
|
||||
def list_use_container_bin():
|
||||
try:
|
||||
with open(os.path.expanduser('~/.config/blend/config.yaml')) as config_file:
|
||||
|
@ -30,23 +39,25 @@ def list_use_container_bin():
|
|||
except:
|
||||
return []
|
||||
|
||||
|
||||
def check_if_present(attr, desktop_str):
|
||||
for l in desktop_str:
|
||||
if l.startswith(attr + '='):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def which(bin):
|
||||
results = []
|
||||
for dir in os.environ.get('PATH').split(':'):
|
||||
if os.path.isdir(dir):
|
||||
for i in os.listdir(dir):
|
||||
if os.path.basename(bin) == i:
|
||||
results.append(os.path.join(dir, i))
|
||||
if os.path.basename(bin) in os.listdir(dir):
|
||||
results.append(os.path.join(dir, os.path.basename(bin)))
|
||||
if results == []:
|
||||
return None
|
||||
return results
|
||||
|
||||
|
||||
def create_container_binaries():
|
||||
_binaries = []
|
||||
remove_binaries = []
|
||||
|
@ -54,17 +65,18 @@ def create_container_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;
|
||||
find /usr/local/bin -type f -printf "%P\n" 2>/dev/null;
|
||||
find /usr/sbin -type f -printf "%P\n" 2>/dev/null;''').split('\n'):
|
||||
find /usr/local/bin -type f -printf "%P\n" 2>/dev/null;''').split('\n'):
|
||||
i = i.strip()
|
||||
os.makedirs(os.path.expanduser(f'~/.local/bin/blend_{c}'), exist_ok=True)
|
||||
os.makedirs(os.path.expanduser(
|
||||
f'~/.local/bin/blend_{c}'), exist_ok=True)
|
||||
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:
|
||||
which_out.remove(os.path.expanduser(f'~/.local/bin/blend_bin/{os.path.basename(i)}'))
|
||||
which_out.remove(os.path.expanduser(
|
||||
f'~/.local/bin/blend_bin/{os.path.basename(i)}'))
|
||||
except ValueError:
|
||||
pass
|
||||
if which_out == []:
|
||||
|
@ -74,13 +86,17 @@ def create_container_binaries():
|
|||
|
||||
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:
|
||||
f.write('#!/bin/sh\n')
|
||||
f.write(f'# blend container: {i}\n')
|
||||
f.write('#!/bin/bash\n')
|
||||
f.write(f'# blend container: {c};{i}\n')
|
||||
if os.path.basename(i) in _exceptions:
|
||||
f.write(f'# EXCEPTION\n')
|
||||
f.write(f'BLEND_ALLOW_ROOT= BLEND_NO_CHECK= blend enter -cn {c} -- {i} "$@"\n')
|
||||
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')
|
||||
# XXX: make this bit fully atomic
|
||||
os.chmod(os.path.expanduser(f'~/.local/bin/blend_{c}/{os.path.basename(i)}.tmp'), 0o775)
|
||||
os.chmod(os.path.expanduser(
|
||||
f'~/.local/bin/blend_{c}/{os.path.basename(i)}.tmp'), 0o775)
|
||||
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))))
|
||||
|
@ -89,11 +105,15 @@ def create_container_binaries():
|
|||
|
||||
for c, i in _binaries:
|
||||
try:
|
||||
os.symlink(os.path.expanduser(f'~/.local/bin/blend_{c}/{i}'), os.path.expanduser(f'~/.local/bin/blend_bin/{i}'))
|
||||
if i == 'apt':
|
||||
print(c, i)
|
||||
os.symlink(os.path.expanduser(
|
||||
f'~/.local/bin/blend_{c}/{i}'), os.path.expanduser(f'~/.local/bin/blend_bin/{i}'))
|
||||
except FileExistsError:
|
||||
if not subprocess.call(['grep', '-q', f'^# container: {c}$', os.path.expanduser(f'~/.local/bin/blend_bin/{i}')]):
|
||||
if subprocess.call(['grep', '-q', f'^# container: {c};{i}$', os.path.expanduser(f'~/.local/bin/blend_bin/{i}')], shell=False):
|
||||
os.remove(os.path.expanduser(f'~/.local/bin/blend_bin/{i}'))
|
||||
os.symlink(os.path.expanduser(f'~/.local/bin/blend_{c}/{i}'), os.path.expanduser(f'~/.local/bin/blend_bin/{i}'))
|
||||
os.symlink(os.path.expanduser(
|
||||
f'~/.local/bin/blend_{c}/{i}'), os.path.expanduser(f'~/.local/bin/blend_bin/{i}'))
|
||||
|
||||
for i in remove_binaries:
|
||||
try:
|
||||
|
@ -103,12 +123,15 @@ def create_container_binaries():
|
|||
|
||||
for b in os.listdir(os.path.expanduser(f'~/.local/bin/blend_bin')):
|
||||
if [_b for _b in _binaries if _b[1] == b] == []:
|
||||
os.remove(os.path.join(os.path.expanduser(f'~/.local/bin/blend_bin'), b))
|
||||
os.remove(os.path.join(os.path.expanduser(
|
||||
f'~/.local/bin/blend_bin'), b))
|
||||
|
||||
|
||||
def create_container_applications():
|
||||
_apps = []
|
||||
|
||||
os.makedirs(os.path.expanduser(f'~/.local/share/applications'), exist_ok=True)
|
||||
os.makedirs(os.path.expanduser(
|
||||
f'~/.local/share/applications'), exist_ok=True)
|
||||
|
||||
for c in _list:
|
||||
c = c.strip()
|
||||
|
@ -119,8 +142,10 @@ def create_container_applications():
|
|||
or os.path.isfile(os.path.expanduser(f'~/.local/share/applications/{i}')))
|
||||
if i != '' and not i_present:
|
||||
with open(os.path.expanduser(f'~/.local/share/applications/blend;{i}'), 'w') as f:
|
||||
_ = con_get_output(c, f"sudo sed -i '/^DBusActivatable=/d' {orig_path}")
|
||||
_ = con_get_output(c, f"sudo sed -i '/^TryExec=/d' {orig_path}")
|
||||
_ = con_get_output(
|
||||
c, f"sudo sed -i '/^DBusActivatable=/d' {orig_path}")
|
||||
_ = con_get_output(
|
||||
c, f"sudo sed -i '/^TryExec=/d' {orig_path}")
|
||||
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):
|
||||
|
@ -129,16 +154,19 @@ def create_container_applications():
|
|||
elif line.strip().startswith('Icon='):
|
||||
if '/' in line:
|
||||
line = line.strip()
|
||||
_ = con_get_output(c, f"mkdir -p ~/.local/share/blend/icons/file/\"{c}_{i}\"; cp {line[5:]} ~/.local/share/blend/icons/file/\"{c}_{i}\"")
|
||||
_ = con_get_output(
|
||||
c, f"mkdir -p ~/.local/share/blend/icons/file/\"{c}_{i}\"; cp {line[5:]} ~/.local/share/blend/icons/file/\"{c}_{i}\"")
|
||||
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')
|
||||
_ = con_get_output(c, f"mkdir -p ~/.local/share/blend/icons/\"{c}_{i}\"; cp {icons[0]} ~/.local/share/blend/icons/\"{c}_{i}\"")
|
||||
_ = con_get_output(
|
||||
c, f"mkdir -p ~/.local/share/blend/icons/\"{c}_{i}\"; cp {icons[0]} ~/.local/share/blend/icons/\"{c}_{i}\"")
|
||||
line = f'Icon={os.path.expanduser("~/.local/share/blend/icons/" + c + "_" + i + "/" + os.path.basename(icons[0]))}\n'
|
||||
sys.stdout.write(line)
|
||||
os.chmod(os.path.expanduser(f'~/.local/share/applications/blend;{i}'), 0o775)
|
||||
os.chmod(os.path.expanduser(
|
||||
f'~/.local/share/applications/blend;{i}'), 0o775)
|
||||
_apps.append((c, i))
|
||||
del _
|
||||
|
||||
|
@ -146,7 +174,9 @@ def create_container_applications():
|
|||
if a.startswith('blend;'):
|
||||
a = a.removeprefix('blend;')
|
||||
if [_a for _a in _apps if _a[1] == a] == []:
|
||||
os.remove(os.path.expanduser(f'~/.local/share/applications/blend;{a}'))
|
||||
os.remove(os.path.expanduser(
|
||||
f'~/.local/share/applications/blend;{a}'))
|
||||
|
||||
|
||||
def create_container_sessions(type='xsessions'):
|
||||
session_dir = f'/usr/share/{type}'
|
||||
|
@ -176,11 +206,14 @@ def create_container_sessions(type='xsessions'):
|
|||
continue
|
||||
|
||||
sys.stdout.write(line)
|
||||
os.chmod(os.path.expanduser(f'{session_dir}/blend-{c};{i}'), 0o775)
|
||||
os.chmod(os.path.expanduser(
|
||||
f'{session_dir}/blend-{c};{i}'), 0o775)
|
||||
|
||||
con_get_output = lambda name, cmd: subprocess.run(['sudo', '-u', user, 'podman', 'exec', '--user', getpass.getuser(), '-it', name, 'bash', '-c', cmd],
|
||||
|
||||
def con_get_output(name, cmd): return subprocess.run(['sudo', '-u', user, 'podman', 'exec', '--user', getpass.getuser(), '-it', name, 'bash', '-c', cmd],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout.decode('UTF-8').strip()
|
||||
|
||||
|
||||
user = getpass.getuser()
|
||||
|
||||
try:
|
||||
|
@ -188,15 +221,6 @@ try:
|
|||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
if sys.argv[1] == 'sessions':
|
||||
_list = get_containers()
|
||||
create_container_sessions(type='xsessions')
|
||||
create_container_sessions(type='wayland-sessions')
|
||||
exit(0)
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
for c in get_containers():
|
||||
c = c.strip()
|
||||
subprocess.call(['podman', 'start', c])
|
||||
|
@ -207,4 +231,4 @@ while True:
|
|||
|
||||
create_container_binaries()
|
||||
create_container_applications()
|
||||
time.sleep(6)
|
||||
time.sleep(15)
|
||||
|
|
|
@ -13,10 +13,10 @@
|
|||
<body style="height: 100%;">
|
||||
<br>
|
||||
<div class="topnav">
|
||||
<div class="btn-group" role="group" aria-label="Stores">
|
||||
<div class="btn-group" id="settings-tabs" role="group" aria-label="Stores">
|
||||
<button class="btn btn-outline-light active shadow-none" id="containers-button" onclick="page('containers')">Linux
|
||||
Containers</button>
|
||||
<button class="btn btn-outline-light shadow-none" id="android-button" onclick="page('android')">Android
|
||||
<button class="btn btn-outline-light shadow-none d-none" id="android-button" onclick="page('android')">Android
|
||||
Apps</button>
|
||||
<button class="btn btn-outline-light shadow-none" id="system-button" onclick="page('system')">System</button>
|
||||
</div>
|
||||
|
@ -41,6 +41,10 @@
|
|||
|
||||
const $ = require("jquery")
|
||||
|
||||
if (fs.existsSync('/usr/bin/waydroid')) {
|
||||
document.getElementById('android-button').classList.remove('d-none')
|
||||
}
|
||||
|
||||
function page(page) {
|
||||
switch (page) {
|
||||
case 'containers':
|
||||
|
|
|
@ -1,135 +1,136 @@
|
|||
function rollback() {
|
||||
let rollback_worker = new Worker(
|
||||
`data:text/javascript,
|
||||
let s = require('child_process').spawnSync('pkexec', ['blend-system', 'rollback']).status
|
||||
if (s === 0) {
|
||||
postMessage('success')
|
||||
} else {
|
||||
postMessage('failure')
|
||||
}
|
||||
`
|
||||
)
|
||||
rollback_worker.onmessage = e => {
|
||||
if (e.data == 'success') {
|
||||
document.getElementById('rollback-btn').outerHTML =
|
||||
'<button type="button" class="btn btn-danger" onclick="undo_rollback()" id="rollback-btn">Cancel rollback</button>'
|
||||
} else {
|
||||
document.getElementById('rollback-btn').outerHTML =
|
||||
'<button type="button" class="btn btn-danger" id="rollback-btn" disabled>Failed</button>'
|
||||
setTimeout(() => document.getElementById('rollback-btn').outerHTML =
|
||||
'<button type="button" class="btn btn-danger" onclick="rollback()" id="rollback-btn">Rollback</button>', 2000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function undo_rollback() {
|
||||
let undo_rollback_worker = new Worker(
|
||||
`data:text/javascript,
|
||||
let s = require('child_process').spawnSync('pkexec', ['rm', '-f', '/blend/states/.load_prev_state']).status
|
||||
if (s === 0) {
|
||||
postMessage('success')
|
||||
} else {
|
||||
postMessage('failure')
|
||||
}
|
||||
`
|
||||
)
|
||||
undo_rollback_worker.onmessage = e => {
|
||||
if (e.data == 'success') {
|
||||
document.getElementById('rollback-btn').outerHTML =
|
||||
'<button type="button" class="btn btn-danger" onclick="rollback()" id="rollback-btn">Rollback</button>'
|
||||
} else {
|
||||
document.getElementById('rollback-btn').outerHTML =
|
||||
'<button type="button" class="btn btn-danger" id="rollback-btn" disabled>Failed</button>'
|
||||
setTimeout(() => document.getElementById('rollback-btn').outerHTML =
|
||||
'<button type="button" class="btn btn-danger" onclick="undo_rollback()" id="rollback-btn">Cancel rollback</button>', 2000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function init_waydroid() {
|
||||
document.getElementById('initialize-btn').outerHTML =
|
||||
'<button type="button" id="initialize-btn" onclick="init_waydroid()" class="btn btn-primary" disabled>Initializing...</button>'
|
||||
let init_worker = new Worker(
|
||||
`data:text/javascript,
|
||||
require('child_process').spawnSync('pkexec', ['waydroid', 'init'])
|
||||
require('child_process').spawnSync('pkexec', ['systemctl', 'enable', '--now', 'waydroid-container'])
|
||||
require('child_process').spawn('sh', ['-c', 'waydroid session start & disown'])
|
||||
setTimeout(() => {
|
||||
require('child_process').spawnSync('pkexec', ['waydroid', 'shell', 'pm', 'disable', 'com.android.inputmethod.latin'])
|
||||
require('child_process').spawnSync('waydroid', ['prop', 'set', 'persist.waydroid.multi_windows', 'true'])
|
||||
postMessage('success')
|
||||
if (require('child_process').spawnSync('sh', ['-c', 'LC_ALL=C glxinfo | grep "^OpenGL renderer string: "']).stdout.includes('NVIDIA')) {
|
||||
require('child_process').spawnSync('sh', ['-c', 'echo "ro.hardware.gralloc=default" | pkexec tee -a /var/lib/waydroid/waydroid.cfg'])
|
||||
require('child_process').spawnSync('sh', ['-c', 'echo "ro.hardware.egl=swiftshader" | pkexec tee -a /var/lib/waydroid/waydroid.cfg'])
|
||||
}
|
||||
require('child_process').spawn('sh', ['-c', 'pkexec waydroid upgrade -o; waydroid session stop; waydroid session start'])
|
||||
setTimeout(() => { postMessage('success') }, 1000)
|
||||
}, 2000)
|
||||
`
|
||||
)
|
||||
init_worker.onmessage = e => {
|
||||
if (e.data == 'success') {
|
||||
document.getElementById('init-waydroid').classList.add('d-none')
|
||||
document.getElementById('waydroid-initialize-settings').classList.add('d-none')
|
||||
document.getElementById('waydroid-initialized-settings').classList.remove('d-none')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function enable_multi_window() {
|
||||
document.getElementById('multiwindow-btn').outerHTML =
|
||||
'<button type="button" id="multiwindow-btn" onclick="enable_multi_window()" class="btn btn-primary" disabled>Enabling...</button>'
|
||||
let multi_window_worker = new Worker(
|
||||
function install_aurora_store() {
|
||||
document.getElementById('aurora-store-btn').outerHTML =
|
||||
`<button type="button" id="aurora-store-btn" onclick="install_aurora_store()"
|
||||
class="btn btn-success" disabled>Installing...</button>`
|
||||
let aurora_store_worker = new Worker(
|
||||
`data:text/javascript,
|
||||
require('child_process').spawn('sh', ['-c', 'waydroid session start & disown'])
|
||||
setTimeout(() => { require('child_process').spawnSync('waydroid', ['prop', 'set', 'persist.waydroid.multi_windows', 'true']); require('child_process').spawn('sh', ['-c', 'waydroid session stop']); postMessage('success') }, 500)
|
||||
`
|
||||
)
|
||||
multi_window_worker.onmessage = e => {
|
||||
if (e.data == 'success') {
|
||||
document.getElementById('multiwindow-btn').outerHTML =
|
||||
'<button type="button" id="multiwindow-btn" onclick="disable_multi_window()" class="btn btn-primary">Disable</button>'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function disable_multi_window() {
|
||||
document.getElementById('multiwindow-btn').outerHTML =
|
||||
'<button type="button" id="multiwindow-btn" onclick="enable_multi_window()" class="btn btn-primary" disabled>Disabling...</button>'
|
||||
let multi_window_worker = new Worker(
|
||||
`data:text/javascript,
|
||||
require('child_process').spawn('sh', ['-c', 'waydroid session start & disown'])
|
||||
setTimeout(() => { require('child_process').spawnSync('waydroid', ['prop', 'set', 'persist.waydroid.multi_windows', 'false']); require('child_process').spawn('sh', ['-c', 'waydroid session stop']); postMessage('success') }, 500)
|
||||
`
|
||||
)
|
||||
multi_window_worker.onmessage = e => {
|
||||
if (e.data == 'success') {
|
||||
document.getElementById('multiwindow-btn').outerHTML =
|
||||
'<button type="button" id="multiwindow-btn" onclick="enable_multi_window()" class="btn btn-primary">Enable</button>'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function check_multi_window_enabled() {
|
||||
let check_worker = new Worker(
|
||||
`data:text/javascript,
|
||||
require('child_process').spawn('sh', ['-c', 'waydroid session start & disown'])
|
||||
setTimeout(() => { let val = require('child_process').spawnSync('waydroid', ['prop', 'get', 'persist.waydroid.multi_windows']).stdout; postMessage(val) }, 500)
|
||||
`
|
||||
)
|
||||
check_worker.onmessage = e => {
|
||||
if (new TextDecoder("utf-8").decode(e.data).trim() == 'true') {
|
||||
document.getElementById('multiwindow-btn').outerHTML =
|
||||
'<button type="button" id="multiwindow-btn" onclick="disable_multi_window()" class="btn btn-primary">Disable</button>'
|
||||
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
|
||||
if (s1 != 0) {
|
||||
postMessage('failed')
|
||||
} else {
|
||||
document.getElementById('multiwindow-btn').outerHTML =
|
||||
'<button type="button" id="multiwindow-btn" onclick="enable_multi_window()" class="btn btn-primary">Enable</button>'
|
||||
require('child_process').spawn('waydroid', ['session', 'start'])
|
||||
setTimeout(() => {
|
||||
require('child_process').spawnSync('sh', ['-c', 'waydroid app install ~/.cache/blend-settings/aurora.apk'])
|
||||
setTimeout(() => postMessage('success'), 200)
|
||||
}, 2000)
|
||||
}
|
||||
`
|
||||
)
|
||||
aurora_store_worker.onmessage = e => {
|
||||
if (e.data == 'success') {
|
||||
document.getElementById('aurora-store-btn').outerHTML =
|
||||
`<button type="button btn-success" id="aurora-store-btn" onclick="install_aurora_store()"
|
||||
class="btn btn-success" disabled>Installed</button>`
|
||||
} else if (e.data == 'failed') {
|
||||
document.getElementById('aurora-store-btn').outerHTML =
|
||||
`<button type="button btn-success" id="aurora-store-btn" onclick="install_aurora_store()"
|
||||
class="btn btn-success" disabled>Failed</button>`
|
||||
setTimeout(() => {
|
||||
document.getElementById('aurora-store-btn').outerHTML =
|
||||
`<button type="button btn-success" id="aurora-store-btn" onclick="install_aurora_store()"
|
||||
class="btn btn-success">Install</button>`
|
||||
}, 2000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function install_f_droid() {
|
||||
document.getElementById('f-droid-btn').outerHTML =
|
||||
`<button type="button" id="f-droid-btn" onclick="install_f_droid()"
|
||||
class="btn btn-primary" disabled>Installing...</button>`
|
||||
let f_droid_worker = new Worker(
|
||||
`data:text/javascript,
|
||||
require('child_process').spawnSync('sh', ['-c', 'mkdir -p ~/.cache/blend-settings; rm -f ~/.cache/blend-settings/f-droid.apk'])
|
||||
let s1 = require('child_process').spawnSync('sh', ['-c', 'wget -O ~/.cache/blend-settings/f-droid.apk https://f-droid.org/F-Droid.apk']).status
|
||||
if (s1 != 0) {
|
||||
postMessage('failed')
|
||||
} else {
|
||||
require('child_process').spawn('waydroid', ['session', 'start'])
|
||||
setTimeout(() => {
|
||||
require('child_process').spawnSync('sh', ['-c', 'waydroid app install ~/.cache/blend-settings/f-droid.apk'])
|
||||
setTimeout(() => postMessage('success'), 200)
|
||||
}, 2000)
|
||||
}
|
||||
`
|
||||
)
|
||||
f_droid_worker.onmessage = e => {
|
||||
if (e.data == 'success') {
|
||||
document.getElementById('f-droid-btn').outerHTML =
|
||||
`<button type="button btn-success" id="f-droid-btn" onclick="install_f_droid()"
|
||||
class="btn btn-primary" disabled>Installed</button>`
|
||||
} else if (e.data == 'failed') {
|
||||
document.getElementById('f-droid-btn').outerHTML =
|
||||
`<button type="button btn-success" id="f-droid-btn" onclick="install_f_droid()"
|
||||
class="btn btn-primary" disabled>Failed</button>`
|
||||
setTimeout(() => {
|
||||
document.getElementById('f-droid-btn').outerHTML =
|
||||
`<button type="button btn-success" id="f-droid-btn" onclick="install_f_droid()"
|
||||
class="btn btn-primary">Install</button>`
|
||||
}, 2000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function waydroid_open_settings() {
|
||||
require('child_process').spawn('waydroid', ['app', 'launch', 'com.android.settings'])
|
||||
}
|
||||
|
||||
require('fs').stat('/var/lib/waydroid', (err, stat) => {
|
||||
if (err == null) {
|
||||
document.getElementById('waydroid-initialize-settings').classList.add('d-none')
|
||||
document.getElementById('waydroid-initialized-settings').classList.remove('d-none')
|
||||
if (require('child_process').spawnSync('sh', ['-c', 'LC_ALL=C glxinfo | grep "^OpenGL renderer string: "']).stdout.includes('NVIDIA')) {
|
||||
document.getElementById('nvidia-warning-installed').classList.remove('d-none')
|
||||
}
|
||||
require('child_process').spawn('waydroid', ['session', 'start'])
|
||||
setTimeout(() => {
|
||||
if (require('child_process').spawnSync('waydroid', ['app', 'list']).stdout.includes('com.aurora.store')) {
|
||||
document.getElementById('aurora-store-btn').outerHTML =
|
||||
`<button type="button btn-success" id="aurora-store-btn" onclick="install_aurora_store()"
|
||||
class="btn btn-success" disabled>Installed</button>`
|
||||
}
|
||||
if (require('child_process').spawnSync('waydroid', ['app', 'list']).stdout.includes('org.fdroid.fdroid')) {
|
||||
document.getElementById('f-droid-btn').outerHTML =
|
||||
`<button type="button btn-success" id="fdroid-btn" onclick="install_f_droid()"
|
||||
class="btn btn-primary" disabled>Installed</button>`
|
||||
}
|
||||
}, 1000)
|
||||
} else {
|
||||
if (require('child_process').spawnSync('sh', ['-c', 'LC_ALL=C glxinfo | grep "^OpenGL renderer string: "']).stdout.includes('NVIDIA')) {
|
||||
document.getElementById('nvidia-warning').classList.remove('d-none')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
check_state_creation()
|
||||
check_rollback()
|
||||
|
||||
$('#automatic-state-toggle').on('change', () => {
|
||||
if (!document.getElementById('automatic-state-toggle').checked) {
|
||||
let enable_autostate_worker = new Worker(
|
||||
|
|
|
@ -47,6 +47,8 @@ function undo_rollback() {
|
|||
}
|
||||
|
||||
function save_state() {
|
||||
$("#settings-tabs").find("*").prop('disabled', true)
|
||||
|
||||
let save_state_worker = new Worker(
|
||||
`data:text/javascript,
|
||||
let s = require('child_process').spawnSync('pkexec', ['blend-system', 'save-state']).status
|
||||
|
@ -61,11 +63,13 @@ function save_state() {
|
|||
if (e.data == 'success') {
|
||||
document.getElementById('save-state-btn').outerHTML =
|
||||
'<button type="button" class="btn btn-success" id="save-state-btn" disabled>Saved state</button>'
|
||||
$("#settings-tabs").find("*").prop('disabled', false)
|
||||
setTimeout(() => document.getElementById('save-state-btn').outerHTML =
|
||||
'<button type="button" id="save-state-btn" onclick="save_state()" class="btn btn-success">Save state</button>', 2000)
|
||||
} else {
|
||||
document.getElementById('save-state-btn').outerHTML =
|
||||
'<button type="button" class="btn btn-success" id="save-state-btn" disabled>Failed</button>'
|
||||
$("#settings-tabs").find("*").prop('disabled', false)
|
||||
setTimeout(() => document.getElementById('save-state-btn').outerHTML =
|
||||
'<button type="button" id="save-state-btn" onclick="save_state()" class="btn btn-success">Save state</button>', 2000)
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<div class="container-fluid d-flex justify-content-center">
|
||||
<div class="col-12 col-lg-10 col-xl-8 mx-auto">
|
||||
<div id="waydroid-initialize-settings">
|
||||
<div class="list-group mt-3 mb-5 shadow" id="waydroid-initialize-settings">
|
||||
<div class="list-group-item">
|
||||
<div class="list-group mt-3 mb-5" id="waydroid-initialize-settings">
|
||||
<div class="list-group-item shadow">
|
||||
<div class="row align-items-center">
|
||||
<div class="col">
|
||||
<strong class="mb-0">Initialize Android App Support</strong>
|
||||
<p class="text-muted mb-0">Initialize WayDroid to be able to run Android apps.</p>
|
||||
<strong class="mb-0">Initialize Android app support</strong>
|
||||
<p class="text-muted mb-0">You may be asked to enter your password repeatedly to initialize WayDroid.</p>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="form-check form-switch align-middle">
|
||||
|
@ -16,57 +16,34 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<p id="nvidia-warning" class="d-none">Since you're using an <b style="color: lightgreen;">NVIDIA</b> GPU,
|
||||
Android apps will use software rendering.</p>
|
||||
<p>After initializing WayDroid, you can install a store (or many) of your choice.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-none" id="waydroid-initialized-settings">
|
||||
<div id="main-list" class="mb-3">
|
||||
<div class="list-group-item" id="">
|
||||
<div class="row align-items-center">
|
||||
<div class="col">
|
||||
<strong class="mb-0">App Lounge (/e/)</strong>
|
||||
<p class="text-muted mb-0">An installable catalogue of FOSS Android applications.</p>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="form-check form-switch align-middle">
|
||||
<button type="button" id="e-applounge-inst-btn" onclick="install_e_applounge()" class="btn btn-primary"
|
||||
disabled>Checking status...</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p>Android app support (WayDroid) has successfully been initialized.<span id="nvidia-warning-installed"
|
||||
class="d-none"> Since you're using an <b style="color: lightgreen;">NVIDIA</b> GPU, apps will use software
|
||||
rendering.</span></p>
|
||||
<strong>Install a store</strong>
|
||||
<div class="list-group mt-3 mb-4 shadow">
|
||||
<div>
|
||||
<div class="list-group-item" id="multi-window">
|
||||
<div class="list-group-item" id="aurora-store-item">
|
||||
<div class="row align-items-center">
|
||||
<div class="col">
|
||||
<strong class="mb-0">App Lounge (/e/)</strong>
|
||||
<p class="text-muted mb-0">An installable catalogue of FOSS Android applications.</p>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="form-check form-switch align-middle">
|
||||
<button type="button" id="e-applounge-inst-btn" onclick="install_e_applounge()"
|
||||
class="btn btn-primary" disabled>Checking status...</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-group-item" id="multi-window">
|
||||
<div class="row align-items-center">
|
||||
<div class="col">
|
||||
<strong class="mb-0">Aurora Store (Nightly)</strong>
|
||||
<strong class="mb-0">Aurora Store</strong>
|
||||
<p class="text-muted mb-0">An open-source Google Play Store client.</p>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="form-check form-switch align-middle">
|
||||
<button type="button" id="aurora-store-inst-btn" onclick="install_aurora_store()"
|
||||
class="btn btn-primary" disabled>Checking status...</button>
|
||||
<button type="button" id="aurora-store-btn" onclick="install_aurora_store()"
|
||||
class="btn btn-success" disabled>Checking status...</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-group-item" id="multi-window">
|
||||
<div class="list-group-item" id="f-droid-item">
|
||||
<div class="row align-items-center">
|
||||
<div class="col">
|
||||
<strong class="mb-0">F-Droid</strong>
|
||||
|
@ -74,14 +51,19 @@
|
|||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="form-check form-switch align-middle">
|
||||
<button type="button" id="f-droid-btn" onclick="install_f_droid()" class="btn btn-primary"
|
||||
disabled>Checking status...</button>
|
||||
<button type="button" id="f-droid-btn" onclick="install_f_droid()"
|
||||
class="btn btn-primary" disabled>Checking status...</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" id="f-droid-btn" onclick="waydroid_open_settings()"
|
||||
class="btn btn-primary">Open Settings</button>
|
||||
<br><br>
|
||||
<strong>Useful information</strong>
|
||||
<p>In the event that an app you regularly use on your phone is broken on blendOS, you could install MicroG from F-Droid by following the instructions <a href="javascript:void()" onclick="require('electron').shell.openExternal('https://microg.org/download.html')">here</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<div class="container-fluid d-flex justify-content-center">
|
||||
<div class="col-12 col-lg-10 col-xl-8 mx-auto">
|
||||
<strong class="mb-0">Containers</strong>
|
||||
<p>You can install any app from any of the supported distributions (Arch, Fedora, and Ubuntu). Any apps you install in them will appear as regular applications on your system, and so will any binaries. In case a binary is common between two containers, the binary from the most recently created container will be exported. You can override this by rearranging (dragging) the containers below to select the priority that should be assigned to each container.</p>
|
||||
<div class="list-group mb-5 shadow" id="container-list">
|
||||
<p>You can install any app from any of the supported distributions (<b>Arch</b>, <b>Fedora</b>, and <b>Ubuntu</b>). Apps you install will appear as regular applications on your system (as well as binaries and package managers). You can override the priority in which common binaries are made available on the system by rearranging (dragging) the containers below to select the priority that should be assigned to each container.</p>
|
||||
<div class="list-group mb-4 shadow" id="container-list">
|
||||
<div class="list-group-item">
|
||||
<div class="row align-items-center">
|
||||
<div class="col">
|
||||
|
@ -18,6 +18,7 @@
|
|||
<div class="container-fluid d-flex justify-content-center">
|
||||
<div class="col-12 col-lg-10 col-xl-8 mx-auto">
|
||||
<strong class="mb-0">Create new container</strong>
|
||||
<p>Create a container for each distribution to be able to use their package managers and other binaries directly from a terminal.</p>
|
||||
<form onsubmit="create_container(); return false">
|
||||
<div class="form-group row">
|
||||
<label for="inputContainerName" class="col-sm-3 col-form-label">Container name</label>
|
||||
|
|
|
@ -7,13 +7,12 @@
|
|||
<div class="row align-items-center">
|
||||
<div class="col">
|
||||
<strong class="mb-0">Disable automatic state creation</strong>
|
||||
<p class="text-muted mb-0">blendOS creates copies of apps and config every 6 hours (and keeps the
|
||||
last two).</p>
|
||||
<p class="text-muted mb-0">blendOS creates copies of apps and config every 12 hours (and keeps the
|
||||
previous one).</p>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="form-check form-switch align-middle">
|
||||
<input class="form-check-input align-middle" type="checkbox" role="switch"
|
||||
id="automatic-state-toggle">
|
||||
<input class="form-check-input align-middle" type="checkbox" role="switch" id="automatic-state-toggle">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -26,7 +25,8 @@
|
|||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="form-check form-switch align-middle">
|
||||
<button type="button" id="save-state-btn" onclick="save_state()" class="btn btn-success">Save state</button>
|
||||
<button type="button" id="save-state-btn" onclick="save_state()" class="btn btn-success">Save
|
||||
state</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -80,6 +80,10 @@
|
|||
fit.fit()
|
||||
|
||||
ipc.on("terminal.incomingData", (event, data) => {
|
||||
fit.fit();
|
||||
term.resize(term.cols, term.rows)
|
||||
ipc.send("terminal.resize", [term.cols, term.rows])
|
||||
|
||||
term.write(data);
|
||||
});
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ def autosave_state():
|
|||
while True:
|
||||
if not os.path.isfile('/blend/states/.disable_states'):
|
||||
save_state()
|
||||
time.sleep(6*60*60) # XXX: make this configurable
|
||||
time.sleep(12*60*60) # XXX: make this configurable
|
||||
|
||||
def toggle_states():
|
||||
if os.path.isfile('/blend/states/.disable_states'):
|
||||
|
@ -125,7 +125,6 @@ description = f'''
|
|||
{colors.bold}{colors.fg.purple}available commands{colors.reset}:
|
||||
{colors.bold}help{colors.reset} Show this help message and exit.
|
||||
{colors.bold}version{colors.reset} Show version information and exit.
|
||||
{colors.bold}load-overlay{colors.reset} Load the current overlay.
|
||||
{colors.bold}save-state{colors.reset} Save the current state (backup).
|
||||
{colors.bold}toggle-states{colors.reset} Enable/disable automatic state creation (you can still manually save states).
|
||||
{colors.bold}rollback{colors.reset} Rollback to previous state.
|
||||
|
@ -142,7 +141,6 @@ parser = argparse.ArgumentParser(description=description, usage=argparse.SUPPRES
|
|||
epilog=epilog, formatter_class=argparse.RawTextHelpFormatter)
|
||||
command_map = { 'help': 'help',
|
||||
'version': 'version',
|
||||
'load-overlay': load_overlay,
|
||||
'save-state': save_state,
|
||||
'toggle-states': toggle_states,
|
||||
'autosave-state': autosave_state,
|
||||
|
|
|
@ -17,14 +17,14 @@ run_latehook() {
|
|||
|
||||
mkdir -p /new_root/blend/overlay/current/usr/bin \
|
||||
/new_root/blend/overlay/current/usr/sbin \
|
||||
/new_root/blend/overlay/current/usr/share/plymouth
|
||||
/new_root/blend/overlay/current/usr/share
|
||||
|
||||
mkdir -p /new_root/usr/bin \
|
||||
/new_root/usr/sbin \
|
||||
/new_root/usr/share/plymouth
|
||||
/new_root/usr/share
|
||||
rm -rf /new_root/blend/overlay/workdir_1 /new_root/blend/overlay/workdir_2 /new_root/blend/overlay/workdir_3
|
||||
mkdir -p /new_root/blend/overlay/workdir_1 /new_root/blend/overlay/workdir_2 /new_root/blend/overlay/workdir_3
|
||||
mount -t overlay overlay -o 'lowerdir=/new_root/usr/bin,upperdir=/new_root/blend/overlay/current/usr/bin,workdir=/new_root/blend/overlay/workdir_1' /new_root/usr/bin -o index=off
|
||||
mount -t overlay overlay -o 'lowerdir=/new_root/usr/sbin,upperdir=/new_root/blend/overlay/current/usr/sbin,workdir=/new_root/blend/overlay/workdir_2' /new_root/usr/sbin -o index=off
|
||||
mount -t overlay overlay -o 'lowerdir=/new_root/usr/share/plymouth,upperdir=/new_root/blend/overlay/current/usr/share/plymouth,workdir=/new_root/blend/overlay/workdir_3' /new_root/usr/share/plymouth -o index=off
|
||||
mount -t overlay overlay -o 'lowerdir=/new_root/usr/share,upperdir=/new_root/blend/overlay/current/usr/share,workdir=/new_root/blend/overlay/workdir_3' /new_root/usr/share -o index=off
|
||||
}
|
||||
|
|
82
init-blend
82
init-blend
|
@ -21,6 +21,8 @@ if [ ! -f '/run/.containerenv' ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
shopt -s extglob
|
||||
|
||||
while true; do
|
||||
case $1 in
|
||||
--uid)
|
||||
|
@ -74,6 +76,11 @@ cat << 'EOF'
|
|||
░ ░ ░ ░ ░ ░ ░
|
||||
░ ░
|
||||
|
||||
===================
|
||||
Credits
|
||||
===================
|
||||
|
||||
* NVIDIA driver support - Luca Di Maio (from Distrobox)
|
||||
EOF
|
||||
|
||||
echo
|
||||
|
@ -85,7 +92,7 @@ bmount() {
|
|||
! [[ -e "$2" ]] && findmnt "$2" &>/dev/null && umount "$2" # unmount target dir if a mount
|
||||
|
||||
[[ -d "$1" ]] && mkdir -p "$2" # create target dir if source is a dir
|
||||
[[ -f "$1" ]] && touch "$2" # create target file if source is a file
|
||||
[[ -f "$1" ]] && mkdir -p "$(dirname "$2")"; touch "$2" # create target file if source is a file
|
||||
|
||||
mountflags="rslave"
|
||||
|
||||
|
@ -104,10 +111,12 @@ if command -v apt-get &>/dev/null; then
|
|||
diffutils findutils gnupg2 sudo time util-linux libnss-myhostname \
|
||||
libvte-2.9[0-9]-common libvte-common lsof ncurses-base passwd \
|
||||
pinentry-curses libegl1-mesa libgl1-mesa-glx libvulkan1 mesa-vulkan-drivers &>/dev/null
|
||||
|
||||
elif command -v pacman &>/dev/null; then
|
||||
pacman --noconfirm -Syyu &>/dev/null
|
||||
pacman --noconfirm -Sy bash bc curl wget diffutils findutils gnupg sudo time util-linux vte-common lsof ncurses pinentry \
|
||||
mesa opengl-driver vulkan-intel vulkan-radeon &>/dev/null
|
||||
mesa opengl-driver vulkan-intel vulkan-radeon base-devel git &>/dev/null
|
||||
|
||||
elif command -v dnf &>/dev/null; then
|
||||
dnf install -y --allowerasing bash bc curl wget diffutils findutils dnf-plugins-core gnupg2 less lsof passwd pinentry \
|
||||
procps-ng vte-profile ncurses util-linux sudo time shadow-utils vulkan mesa-vulkan-drivers \
|
||||
|
@ -173,6 +182,62 @@ bmount "/usr/bin/host-blend" "/usr/bin/blend" ro
|
|||
|
||||
if [[ ! -f '/.init_blend.lock' ]]; then
|
||||
|
||||
#######################################################################
|
||||
|
||||
# NVIDIA driver integration. This is straight from https://github.com/89luca89/distrobox/blob/main/distrobox-init#L816,
|
||||
# entirely thanks to an effort by Luca Di Maio, save for a few tweaks for init-blend. Thanks, in case you're reading this!
|
||||
|
||||
NVIDIA_FILES="$(find /run/host/usr/ \
|
||||
-path "/run/host/usr/share/doc*" -prune -o \
|
||||
-path "/run/host/usr/src*" -prune -o \
|
||||
-path "/run/host/usr/lib*/modules*" -prune -o \
|
||||
-path "/run/host/usr/share/man*" -prune -o \
|
||||
-path "/run/host/usr/lib*" -prune -o \
|
||||
-type f -iname "*nvidia*" -print 2</dev/null || :)"
|
||||
for nvidia_file in ${NVIDIA_FILES}; do
|
||||
dest_file="$(printf "%s" "${nvidia_file}" | sed 's|/run/host||g')"
|
||||
bmount "${nvidia_file}" "${dest_file}" ro
|
||||
done
|
||||
|
||||
# Then we find all the ".so" libraries, there are searched separately
|
||||
# because we need to extract the relative path to mount them in the
|
||||
# correct path based on the guest's setup
|
||||
NVIDIA_LIBS="$(find /run/host/usr/lib* \
|
||||
-iname "*nvidia*.so*" \
|
||||
-o -iname "libcuda*.so*" \
|
||||
-o -iname "libnvcuvid*.so*" \
|
||||
-o -iname "libnvoptix*.so*" ||
|
||||
:)"
|
||||
for nvidia_lib in ${NVIDIA_LIBS}; do
|
||||
dest_file="$(printf "%s" "${nvidia_lib}" |
|
||||
sed 's|/run/host/usr/lib/x86_64-linux-gnu/||g' |
|
||||
sed 's|/run/host/usr/lib64/||g' |
|
||||
sed 's|/run/host/usr/lib/||g')"
|
||||
|
||||
# In the guest we need to adjust the destination path, so if we're on
|
||||
# debian based containers, we need to target /usr/lib/x86_64-linux-gnu/
|
||||
if [ -e "/usr/lib/x86_64-linux-gnu/" ]; then
|
||||
bmount "${nvidia_lib}" "/usr/lib/x86_64-linux-gnu/${dest_file}" ro
|
||||
# /usr/lib64 is common in rpm based distros
|
||||
elif [ -e "/usr/lib64" ]; then
|
||||
bmount "${nvidia_lib}" "/usr/lib64/${dest_file}" ro
|
||||
# fallback to /usr/lib if none of the previous
|
||||
else
|
||||
bmount "${nvidia_lib}" "/usr/lib/${dest_file}" ro
|
||||
fi
|
||||
done
|
||||
|
||||
# Refresh ldconfig cache, also detect if there are empty files remaining
|
||||
# and clean them.
|
||||
# This could happen when upgrading drivers and changing versions.
|
||||
empty_libs="$(ldconfig 2>&1 | grep -Eo "File.*is empty" | cut -d' ' -f2)"
|
||||
if [ -n "${empty_libs}" ]; then
|
||||
# shellcheck disable=SC2086
|
||||
rm -f ${empty_libs}
|
||||
fi
|
||||
|
||||
#######################################################################
|
||||
|
||||
### Section START (based on https://github.com/89luca89/distrobox/blob/main/distrobox-init#L816)
|
||||
|
||||
if [ -d "/usr/lib/rpm/" ]; then
|
||||
|
@ -210,7 +275,7 @@ elif [ -d "/usr/share/libalpm/scripts" ]; then
|
|||
|
||||
chmod 755 /usr/share/libalpm/scripts/*blend*.sh
|
||||
|
||||
for p in 00_blend_pre_hook 01_blend_post_hook.sh 02_blend_post_hook; do
|
||||
for p in 00_blend_pre_hook 01_blend_post_hook 02_blend_post_hook; do
|
||||
when=PostTransaction
|
||||
|
||||
[[ -z "${p##*pre*}" ]] && when=PreTransaction
|
||||
|
@ -242,9 +307,20 @@ if ! grep -q "^${_uname}:" /etc/group; then
|
|||
fi
|
||||
useradd --uid "$_cuid" --gid "$_cgid" --shell "/bin/bash" --no-create-home --home "$_uhome" "$_uname" &>/dev/null
|
||||
|
||||
chown root /etc/sudo.conf
|
||||
chown root /usr/bin/sudo
|
||||
chmod 4755 /usr/bin/sudo
|
||||
|
||||
fi
|
||||
|
||||
if [[ ! -f '/.init_blend.lock' ]] && command -v pacman &>/dev/null; then
|
||||
cd /; git clone https://aur.archlinux.org/yay.git &>/dev/null; cd yay
|
||||
chown -R "$_uname" . &>/log
|
||||
sudo -u "$_uname" makepkg --noconfirm -si &>/dev/null
|
||||
cd /; rm -rf yay
|
||||
|
||||
touch /.init_blend.lock
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "Completed container setup."
|
||||
|
|
Loading…
Reference in a new issue