Compare commits
10 commits
5bf806eea0
...
278b3ef2a8
Author | SHA1 | Date | |
---|---|---|---|
278b3ef2a8 | |||
|
541589ca19 | ||
|
c968609b60 | ||
|
08c7a4d235 | ||
|
4e1977087e | ||
|
efa4c78976 | ||
|
2d1b46aa40 | ||
b08d876b53 | |||
|
73d9f01926 | ||
|
ed115df979 |
1 changed files with 81 additions and 88 deletions
151
akshara
Normal file → Executable file
151
akshara
Normal file → Executable file
|
@ -19,17 +19,13 @@
|
|||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import yaml
|
||||
import shutil
|
||||
import filecmp
|
||||
import argparse
|
||||
import requests
|
||||
import platform
|
||||
import fasteners
|
||||
from threading import Event
|
||||
import subprocess
|
||||
|
||||
from datetime import datetime
|
||||
__version = '1.0.0'
|
||||
|
||||
|
||||
|
@ -103,8 +99,7 @@ def error(err):
|
|||
|
||||
|
||||
def interpret_track(blend_release):
|
||||
result = yaml.safe_load(requests.get(blend_release.get(
|
||||
'impl') + '/' + blend_release.get('track') + '.yaml', allow_redirects=True).content.decode())
|
||||
result = yaml.safe_load(requests.get(blend_release.get('impl') + '/' + blend_release.get('track') + '.yaml', allow_redirects=True).content.decode())
|
||||
|
||||
if (type(result.get('impl')) == str and
|
||||
type(result.get('track')) != 'custom'):
|
||||
|
@ -119,6 +114,8 @@ def interpret_track(blend_release):
|
|||
|
||||
|
||||
def update_system():
|
||||
benchmark = True
|
||||
|
||||
if os.path.isdir('/.update_rootfs'):
|
||||
error('update already downloaded, you must reboot first')
|
||||
sys.exit(75)
|
||||
|
@ -138,60 +135,43 @@ def update_system():
|
|||
blend_release = yaml.load(
|
||||
blend_release_file, Loader=yaml.FullLoader)
|
||||
|
||||
|
||||
|
||||
# TODO: Add check that all packages actually exist
|
||||
|
||||
info('downloading Arch tarball...')
|
||||
|
||||
# TODO: currently it errors if it doesn't have arch-repo anyways, so this doesn't need any extra checking, maybe add a check for that later though
|
||||
# The mirror to use for downloading the bootstrap image
|
||||
# For example, for the Arch mirror at mirrors.acm.wpi.edu, you'd use https://mirrors.acm.wpi.edu/archlinux
|
||||
arch_repo = blend_release.get("arch-repo")
|
||||
if type(arch_repo) != str:
|
||||
# default arch and bootstrap repo
|
||||
arch_repo = "geo.mirror.pkgbuild.com"
|
||||
|
||||
bootstrap_repo = blend_release.get("bootstrap-repo")
|
||||
if type(bootstrap_repo) != str:
|
||||
bootstrap_repo = arch_repo
|
||||
|
||||
# TODO: default to https if http/https isn't listed
|
||||
# keeping disabled for consistency because i can't find `repo` to add it (and to add a fallback)
|
||||
if not (arch_repo.startswith("https://") or arch_repo.startswith("http://")):
|
||||
arch_repo = "https://" + arch_repo
|
||||
if not (bootstrap_repo.startswith("https://") or bootstrap_repo.startswith("http://")):
|
||||
bootstrap_repo = "https://" + bootstrap_repo
|
||||
|
||||
# same (fallback and https) for repo
|
||||
repo = blend_release.get("repo")
|
||||
if type(repo) != str:
|
||||
repo = "https://pkg-repo.blendos.co"
|
||||
elif not (repo.startswith("https://") or repo.startswith("http://")):
|
||||
repo = "https://" + repo
|
||||
# Not sure why this wouldn't just use `arch-repo` but whatever
|
||||
bootstrap_mirror = blend_release.get("arch-repo")
|
||||
|
||||
if not os.path.isfile('/.update.tar.zst'):
|
||||
if exec('wget', '-q', '--show-progress', f'{bootstrap_repo}/iso/latest/archlinux-bootstrap-x86_64.tar.zst', '-O', '/.update.tar.zst') != 0:
|
||||
if exec('wget', '-q', '--show-progress', f'{bootstrap_mirror}/iso/latest/archlinux-bootstrap-x86_64.tar.zst', '-O', '/.update.tar.zst') != 0:
|
||||
warn('failed download')
|
||||
print()
|
||||
info('trying download again...')
|
||||
print()
|
||||
exec('rm', '-f', '/.update.tar.zst')
|
||||
if exec('wget', '-q', '--show-progress', f'{bootstrap_repo}/iso/latest/archlinux-bootstrap-x86_64.tar.zst', '-O', '/.update.tar.zst') != 0:
|
||||
if exec('wget', '-q', '--show-progress', f'{bootstrap_mirror}/iso/latest/archlinux-bootstrap-x86_64.tar.zst', '-O', '/.update.tar.zst') != 0:
|
||||
error('failed download')
|
||||
print()
|
||||
error('update failed')
|
||||
sys.exit(50)
|
||||
|
||||
if exec('bash', '-c', f'sha256sum -c --ignore-missing <(wget -qO- {bootstrap_repo}/iso/latest/sha256sums.txt | sed "s/archlinux-bootstrap-x86_64\\.tar\\.zst/.update.tar.zst/g") 2>/dev/null') != 0:
|
||||
if exec('bash', '-c', f'sha256sum -c --ignore-missing <(wget -qO- {bootstrap_mirror}/iso/latest/sha256sums.txt | sed "s/archlinux-bootstrap-x86_64\\.tar\\.zst/.update.tar.zst/g") 2>/dev/null') != 0:
|
||||
error('failed checksum verification')
|
||||
print()
|
||||
info('trying download again...')
|
||||
exec('rm', '-f', '/.update.tar.zst')
|
||||
if exec('wget', '-q', '--show-progress', f'{bootstrap_repo}/iso/latest/archlinux-bootstrap-x86_64.tar.zst', '-O', '/.update.tar.zst') != 0:
|
||||
if exec('wget', '-q', '--show-progress', f'{bootstrap_mirror}/iso/latest/archlinux-bootstrap-x86_64.tar.zst', '-O', '/.update.tar.zst') != 0:
|
||||
error('failed download')
|
||||
print()
|
||||
error('update failed')
|
||||
sys.exit(50)
|
||||
return
|
||||
if exec('bash', '-c', f'sha256sum -c --ignore-missing <(wget -qO- {bootstrap_repo}/iso/latest/sha256sums.txt | sed "s/archlinux-bootstrap-x86_64\\.tar\\.zst/.update.tar.zst/g") 2>/dev/null') != 0:
|
||||
if exec('bash', '-c', f'sha256sum -c --ignore-missing <(wget -qO- {bootstrap_mirror}/iso/latest/sha256sums.txt | sed "s/archlinux-bootstrap-x86_64\\.tar\\.zst/.update.tar.zst/g") 2>/dev/null') != 0:
|
||||
error('failed checksum verification')
|
||||
print()
|
||||
error('update failed')
|
||||
|
@ -204,7 +184,11 @@ def update_system():
|
|||
|
||||
info('generating new system...')
|
||||
|
||||
before = datetime.now()
|
||||
exec('tar', '--acls', '--xattrs', '-xf', '.update.tar.zst')
|
||||
after = datetime.now()
|
||||
if benchmark:
|
||||
print(f'[BENCH]: {(before - after).seconds} seconds to extract tarball')
|
||||
exec('mv', 'root.x86_64', '.new_rootfs')
|
||||
exec('rm', '-f', '/.new_rootfs/pkglist.x86_64.txt')
|
||||
exec('rm', '-f', '/.new_rootfs/version')
|
||||
|
@ -224,9 +208,7 @@ def update_system():
|
|||
'blend-files'
|
||||
]
|
||||
|
||||
keep = [
|
||||
'/usr/share'
|
||||
]
|
||||
persistent_files = []
|
||||
|
||||
if (type(blend_release.get('impl')) == str and
|
||||
type(blend_release.get('track')) != 'custom'):
|
||||
|
@ -252,54 +234,46 @@ def update_system():
|
|||
if type(blend_release.get('user-services')) == list:
|
||||
user_services += blend_release.get('user-services')
|
||||
|
||||
if type(blend_release.get('persistent-files')) == list:
|
||||
persistent_files += blend_release.get('persistent-files')
|
||||
|
||||
exec_chroot('rm', '-f', '/.new_rootfs/etc/resolv.conf')
|
||||
|
||||
with open('/.new_rootfs/etc/resolv.conf', 'w') as pacman_mirrorlist_conf:
|
||||
pacman_mirrorlist_conf.write('nameserver 1.1.1.1\n')
|
||||
|
||||
with open('/.new_rootfs/etc/pacman.d/mirrorlist', 'w') as pacman_mirrorlist_conf:
|
||||
pacman_mirrorlist_conf.write(
|
||||
f'Server = {arch_repo}/$repo/os/$arch\n')
|
||||
if type(blend_release.get('arch-repo')) == str:
|
||||
pacman_mirrorlist_conf.write(f'Server = {blend_release.get("arch-repo")}/$repo/os/$arch\n')
|
||||
else:
|
||||
pacman_mirrorlist_conf.write('Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch\n')
|
||||
|
||||
exec_chroot('mkdir', '-p', '/var/cache/pacman/pkg')
|
||||
exec_chroot('rm', '-rf', '/var/cache/pacman/pkg')
|
||||
exec('cp', '-r', '/var/cache/pacman/pkg',
|
||||
'/.new_rootfs/var/cache/pacman')
|
||||
exec('cp', '-r', '/var/cache/pacman/pkg', '/.new_rootfs/var/cache/pacman')
|
||||
|
||||
# update packages
|
||||
exec_chroot('pacman-key', '--init')
|
||||
exec_chroot('pacman-key', '--populate')
|
||||
|
||||
counter = 0
|
||||
while True:
|
||||
return_val = exec_chroot('pacman', '-Sy', '--ask=4', 'reflector')
|
||||
counter += 1
|
||||
if counter > 30:
|
||||
error('failed to download packages')
|
||||
exit(50)
|
||||
if return_val == 0:
|
||||
break
|
||||
# If the GitHub API is down or something, this completely breaks
|
||||
# also it's broken currently and reflector is working now anyways soooooo
|
||||
# commented out
|
||||
#exec_chroot('sh', '-c', 'mkdir /tmp/rate-mirrors/; cd /tmp/rate-mirrors/; curl -LO $(curl -s https://api.github.com/repos/westandskif/rate-mirrors/releases/latest | grep "browser_download_url.*rate-mirrors-v.*-x86_64-unknown-linux-musl.tar.gz" | cut -d : -f 2,3 | tr -d \\" | tr -d " ")')
|
||||
#exec_chroot('bash', '-c', 'cd /tmp/rate-mirrors/; tar -xzf rate-mirrors*; cd $(find /tmp/rate-mirrors/ -mindepth 1 -maxdepth 1 -type d); ./rate_mirrors --disable-comments-in-file --entry-country=US --protocol=https arch --max-delay 7200 > /etc/pacman.d/mirrorlist')
|
||||
|
||||
exec_chroot('reflector', '--latest', '5', '--protocol', 'https',
|
||||
'--sort', 'rate', '--save', '/etc/pacman.d/mirrorlist')
|
||||
#exec_chroot('sed', 's/#//g', '-i', '/etc/pacman.d/mirrorlist')
|
||||
#exec_chroot('bash', '-c', 'grep "^Server =" /etc/pacman.d/mirrorlist > /etc/pacman.d/mirrorlist.tmp; mv /etc/pacman.d/mirrorlist.tmp /etc/pacman.d/mirrorlist')
|
||||
|
||||
# exec_chroot('sed', 's/#//g', '-i', '/etc/pacman.d/mirrorlist')
|
||||
# exec_chroot('bash', '-c', 'grep "^Server =" /etc/pacman.d/mirrorlist > /etc/pacman.d/mirrorlist.tmp; mv /etc/pacman.d/mirrorlist.tmp /etc/pacman.d/mirrorlist')
|
||||
|
||||
with open('/.new_rootfs/etc/pacman.conf', 'r') as original:
|
||||
data = original.read()
|
||||
with open('/.new_rootfs/etc/pacman.conf', 'w') as modified:
|
||||
modified.write(data.replace(
|
||||
"[options]", "[options]\nParallelDownloads = 32\n"))
|
||||
with open('/.new_rootfs/etc/pacman.conf', 'w') as modified:
|
||||
modified.write(data.replace(
|
||||
"#[multilib]\n#Include = /etc/pacman.d/mirrorlist", "[multilib]\nInclude = /etc/pacman.d/mirrorlist"))
|
||||
with open('/.new_rootfs/etc/pacman.conf', 'r') as original: data = original.read()
|
||||
with open('/.new_rootfs/etc/pacman.conf', 'w') as modified: modified.write(data.replace("[options]", "[options]\nParallelDownloads = 32\n"))
|
||||
with open('/.new_rootfs/etc/pacman.conf', 'w') as modified: modified.write(data.replace("#[multilib]\n#Include = /etc/pacman.d/mirrorlist", "[multilib]\nInclude = /etc/pacman.d/mirrorlist"))
|
||||
|
||||
with open('/.new_rootfs/etc/pacman.conf', 'a') as pacman_conf:
|
||||
pacman_conf.write(f'''
|
||||
[breakfast]
|
||||
SigLevel = Never
|
||||
Server = {repo}
|
||||
Server = {blend_release['repo']}
|
||||
''')
|
||||
|
||||
if type(blend_release.get('package-repos')) == list:
|
||||
|
@ -312,6 +286,7 @@ SigLevel = Never
|
|||
Server = {package_repo["repo-url"]}
|
||||
''')
|
||||
|
||||
before = datetime.now()
|
||||
counter = 0
|
||||
while True:
|
||||
return_val = exec_chroot('pacman', '-Syu', '--noconfirm')
|
||||
|
@ -321,11 +296,16 @@ Server = {package_repo["repo-url"]}
|
|||
exit(50)
|
||||
if return_val == 0:
|
||||
break
|
||||
after = datetime.now()
|
||||
if benchmark:
|
||||
print(f'[BENCH]: {(before - after).seconds} seconds to update packages')
|
||||
|
||||
exec('cp', '/etc/mkinitcpio.conf', '/.new_rootfs/etc/mkinitcpio.conf')
|
||||
|
||||
before = datetime.now()
|
||||
counter = 0
|
||||
while True:
|
||||
print('running packages again')
|
||||
return_val = exec_chroot('pacman', '-S', '--ask=4', *packages)
|
||||
counter += 1
|
||||
if counter > 30:
|
||||
|
@ -333,18 +313,24 @@ Server = {package_repo["repo-url"]}
|
|||
exit(50)
|
||||
if return_val == 0:
|
||||
break
|
||||
after = datetime.now()
|
||||
if benchmark:
|
||||
print(f'[BENCH]: {(before - after).seconds} seconds to install packages')
|
||||
|
||||
counter = 0
|
||||
if aur_packages != []:
|
||||
while True:
|
||||
exec_chroot('useradd', '-m', '-G', 'wheel',
|
||||
'-s', '/bin/bash', 'aur')
|
||||
exec_chroot(
|
||||
'bash', '-c', 'echo "aur ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/aur')
|
||||
print('running aur_packages again')
|
||||
exec_chroot('useradd', '-m', '-G', 'wheel', '-s', '/bin/bash', 'aur')
|
||||
exec_chroot('bash', '-c', 'echo "aur ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/aur')
|
||||
before = datetime.now()
|
||||
return_val = exec_chroot(
|
||||
'runuser', '-u', 'aur', '--', 'paru', '-Sy', '--noconfirm', '--needed',
|
||||
'--noprogressbar', '--skipreview', '--removemake', '--cleanafter', '--ask=4',
|
||||
*aur_packages)
|
||||
after = datetime.now()
|
||||
if benchmark:
|
||||
print(f'[BENCH]: {(before - after).seconds} seconds to install AUR packages')
|
||||
exec_chroot('userdel', '-r', 'aur')
|
||||
exec_chroot('rm', '-f', '/etc/sudoers.d/aur')
|
||||
counter += 1
|
||||
|
@ -354,6 +340,7 @@ Server = {package_repo["repo-url"]}
|
|||
if return_val == 0:
|
||||
break
|
||||
|
||||
|
||||
for service in services:
|
||||
if type(service) is str:
|
||||
exec_chroot('systemctl', 'enable', service)
|
||||
|
@ -362,6 +349,12 @@ Server = {package_repo["repo-url"]}
|
|||
if type(user_service) is str:
|
||||
exec_chroot('systemctl', 'enable', '--global', user_service)
|
||||
|
||||
for persistent_file in persistent_files:
|
||||
if type(persistent_file) is str:
|
||||
if os.path.exists(persistent_file):
|
||||
exec('mkdir', '-p', '/.new_rootfs/'+ os.path.dirname(persistent_file))
|
||||
exec('cp', persistent_file, '/.new_rootfs/'+ persistent_file)
|
||||
|
||||
if type(blend_release.get('commands')) == list:
|
||||
for command in blend_release.get('commands'):
|
||||
if type(command) == str:
|
||||
|
@ -412,8 +405,7 @@ Server = {package_repo["repo-url"]}
|
|||
|
||||
exec('cp', '-ax', '/var/lib', '/.new.var.lib')
|
||||
|
||||
var_lib_diff = filecmp.dircmp(
|
||||
'/.new_rootfs/var/lib/', '/.new.var.lib/')
|
||||
var_lib_diff = filecmp.dircmp('/.new_rootfs/var/lib/', '/.new.var.lib/')
|
||||
|
||||
dir_name = '/.new.var.lib/'
|
||||
for name in var_lib_diff.left_only:
|
||||
|
@ -439,7 +431,6 @@ Server = {package_repo["repo-url"]}
|
|||
exec('cp', '-ax', '/.new_rootfs/var/lib/pacman', '/.new.var.lib/pacman')
|
||||
|
||||
exec('mv', '.new_rootfs', '.update_rootfs')
|
||||
exec('cp', '-ax', '/.update_rootfs/etc', '/.update_rootfs/usr/etc')
|
||||
|
||||
new_boot_files = []
|
||||
|
||||
|
@ -494,8 +485,10 @@ command_map = {'help': 'help',
|
|||
'daemon': daemon}
|
||||
parser.add_argument('command', choices=command_map.keys(),
|
||||
help=argparse.SUPPRESS)
|
||||
parser.add_argument('--keep-files-on-error',
|
||||
action='store_true', help="keep working files on error")
|
||||
parser.add_argument('pkg', action='store', type=str,
|
||||
nargs='*', help=argparse.SUPPRESS)
|
||||
parser.add_argument('--headless',
|
||||
action='store_true', help=argparse.SUPPRESS)
|
||||
parser.add_argument('-v', '--version', action='version',
|
||||
version=f'%(prog)s {__version}', help=argparse.SUPPRESS)
|
||||
|
||||
|
@ -518,8 +511,7 @@ try:
|
|||
parser.parse_args(['--version'])
|
||||
elif command == update_system:
|
||||
exec('touch', '/var/lib/.akshara-system-lock')
|
||||
system_lock = fasteners.InterProcessLock(
|
||||
'/var/lib/.akshara-system-lock')
|
||||
system_lock = fasteners.InterProcessLock('/var/lib/.akshara-system-lock')
|
||||
info('attempting to acquire system lock')
|
||||
with system_lock:
|
||||
command()
|
||||
|
@ -527,11 +519,12 @@ try:
|
|||
command()
|
||||
except:
|
||||
error('aborting')
|
||||
# remove update and akshara stuff if the program errors (either exited by the user or an error) and is updating
|
||||
if command == update_system and not args.keep_files_on_error:
|
||||
# remove update and akshara stuff if the program is exited
|
||||
exec('umount', '-rf', '/.new_rootfs/')
|
||||
exec('rmdir', '/.new_rootfs/')
|
||||
exec('rm', '-rf', '/.new_rootfs')
|
||||
exec('rm', '-rf', '/.update_rootfs')
|
||||
# it's basically impossible to ^C before akshara has exited but after it's created this file
|
||||
# and i don't *think* that "update" would be destructive at all (unless it failed to run and would't boot), but i don't quite understand it soooo just to be on the safe side
|
||||
exec('rm', '-f', '/.update')
|
||||
else:
|
||||
print("--keep-files-on-error specified, not deleting files (/.new_rootfs/, /.update_rootfs/, /.update)")
|
||||
# TODO: add similar handling for errors, and an option to not delete stuff on error/early exit
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue