Compare commits

..

10 commits

Author SHA1 Message Date
askiiart
ed115df979
initial commit - switches to rate-mirrors, some minor updates, etc 2024-10-01 12:24:46 -05:00
Rudra Saraswat
ac44379453 Merge branch 'multilib' into 'main'
feat: enable multilib by default and add README

See merge request blendOS/system-tools/akshara!4
2024-09-05 04:10:59 +00:00
Asterisk
e2adf15f42 Update README.md 2024-08-28 00:41:45 +00:00
Asterisk
4057162e15 Update README.md 2024-08-28 00:23:28 +00:00
Asterisk
11b62648b1 Update README.md 2024-08-27 21:36:37 +00:00
Asterisk
5200aa1897 Update file README.md 2024-08-27 21:35:41 +00:00
Asterisk
3175518459 Make akshara enable multilib 2024-08-27 21:27:57 +00:00
Rudra Saraswat
a9dfa3c3fa Merge branch 'pkgbuild-mirror' into 'main'
Change default mirror to geo.mirror.pkgbuild.com

See merge request blendOS/system-tools/akshara!3
2024-07-06 18:20:20 +00:00
Asterisk
c47b5ff316 fix dual https:// 2024-06-15 12:42:56 +00:00
Asterisk
bcf8abf874 Change default mirror to geo.mirror.pkgbuild.com 2024-06-15 12:41:31 +00:00
2 changed files with 55 additions and 25 deletions

15
README.md Normal file
View file

@ -0,0 +1,15 @@
# akshara
A simple system builder and immutability layer.
## Development
To test a modified copy of `akshara`, run the following on a working blendOS install:
```sh
umount -l /usr && sudo mv ./akshara /usr/bin/akshara && sudo chmod +x /usr/bin/akshara
```
Replace `./akshara` with wherever your modified copy of `akshara` is.
**ANY CHANGES TO `/usr/bin/akshara` WILL BE REVERTED AFTER EVERY UPDATE!**

65
akshara
View file

@ -19,15 +19,11 @@
import os import os
import sys import sys
import time
import yaml import yaml
import shutil
import filecmp import filecmp
import argparse import argparse
import requests import requests
import platform
import fasteners import fasteners
from threading import Event
import subprocess import subprocess
__version = '1.0.0' __version = '1.0.0'
@ -137,33 +133,43 @@ def update_system():
blend_release = yaml.load( blend_release = yaml.load(
blend_release_file, Loader=yaml.FullLoader) blend_release_file, Loader=yaml.FullLoader)
# TODO: Add check that all packages actually exist
info('downloading Arch tarball...') 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
# 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 not os.path.isfile('/.update.tar.zst'):
if exec('wget', '-q', '--show-progress', 'https://geo.mirror.pkgbuild.com/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') warn('failed download')
print() print()
info('trying download again...') info('trying download again...')
print() print()
exec('rm', '-f', '/.update.tar.zst') exec('rm', '-f', '/.update.tar.zst')
if exec('wget', '-q', '--show-progress', 'https://geo.mirror.pkgbuild.com/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') error('failed download')
print() print()
error('update failed') error('update failed')
sys.exit(50) sys.exit(50)
if exec('bash', '-c', 'sha256sum -c --ignore-missing <(wget -qO- https://geo.mirror.pkgbuild.com/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') error('failed checksum verification')
print() print()
info('trying download again...') info('trying download again...')
exec('rm', '-f', '/.update.tar.zst') exec('rm', '-f', '/.update.tar.zst')
if exec('wget', '-q', '--show-progress', 'https://geo.mirror.pkgbuild.com/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') error('failed download')
print() print()
error('update failed') error('update failed')
sys.exit(50) sys.exit(50)
return return
if exec('bash', '-c', 'sha256sum -c --ignore-missing <(wget -qO- https://geo.mirror.pkgbuild.com/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') error('failed checksum verification')
print() print()
error('update failed') error('update failed')
@ -196,9 +202,7 @@ def update_system():
'blend-files' 'blend-files'
] ]
keep = [ persistent_files = []
'/usr/share'
]
if (type(blend_release.get('impl')) == str and if (type(blend_release.get('impl')) == str and
type(blend_release.get('track')) != 'custom'): type(blend_release.get('track')) != 'custom'):
@ -224,6 +228,9 @@ def update_system():
if type(blend_release.get('user-services')) == list: if type(blend_release.get('user-services')) == list:
user_services += blend_release.get('user-services') 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') exec_chroot('rm', '-f', '/.new_rootfs/etc/resolv.conf')
with open('/.new_rootfs/etc/resolv.conf', 'w') as pacman_mirrorlist_conf: with open('/.new_rootfs/etc/resolv.conf', 'w') as pacman_mirrorlist_conf:
@ -233,7 +240,7 @@ def update_system():
if type(blend_release.get('arch-repo')) == str: if type(blend_release.get('arch-repo')) == str:
pacman_mirrorlist_conf.write(f'Server = {blend_release.get("arch-repo")}/$repo/os/$arch\n') pacman_mirrorlist_conf.write(f'Server = {blend_release.get("arch-repo")}/$repo/os/$arch\n')
else: else:
pacman_mirrorlist_conf.write('Server = https://cloudflaremirrors.com/archlinux/$repo/os/$arch\n') pacman_mirrorlist_conf.write('Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch\n')
exec_chroot('mkdir', '-p', '/var/cache/pacman/pkg') exec_chroot('mkdir', '-p', '/var/cache/pacman/pkg')
exec_chroot('rm', '-rf', '/var/cache/pacman/pkg') exec_chroot('rm', '-rf', '/var/cache/pacman/pkg')
@ -243,23 +250,15 @@ def update_system():
exec_chroot('pacman-key', '--init') exec_chroot('pacman-key', '--init')
exec_chroot('pacman-key', '--populate') exec_chroot('pacman-key', '--populate')
counter = 0 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 \\")')
while True: 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 | sudo tee /etc/pacman.d/mirrorlist')
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
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('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('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', '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("[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: with open('/.new_rootfs/etc/pacman.conf', 'a') as pacman_conf:
pacman_conf.write(f''' pacman_conf.write(f'''
@ -292,6 +291,7 @@ Server = {package_repo["repo-url"]}
counter = 0 counter = 0
while True: while True:
print('running packages again')
return_val = exec_chroot('pacman', '-S', '--ask=4', *packages) return_val = exec_chroot('pacman', '-S', '--ask=4', *packages)
counter += 1 counter += 1
if counter > 30: if counter > 30:
@ -303,6 +303,7 @@ Server = {package_repo["repo-url"]}
counter = 0 counter = 0
if aur_packages != []: if aur_packages != []:
while True: while True:
print('running aur_packages again')
exec_chroot('useradd', '-m', '-G', 'wheel', '-s', '/bin/bash', 'aur') exec_chroot('useradd', '-m', '-G', 'wheel', '-s', '/bin/bash', 'aur')
exec_chroot('bash', '-c', 'echo "aur ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/aur') exec_chroot('bash', '-c', 'echo "aur ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/aur')
return_val = exec_chroot( return_val = exec_chroot(
@ -326,6 +327,12 @@ Server = {package_repo["repo-url"]}
if type(user_service) is str: if type(user_service) is str:
exec_chroot('systemctl', 'enable', '--global', user_service) 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: if type(blend_release.get('commands')) == list:
for command in blend_release.get('commands'): for command in blend_release.get('commands'):
if type(command) == str: if type(command) == str:
@ -402,7 +409,8 @@ Server = {package_repo["repo-url"]}
exec('cp', '-ax', '/.new_rootfs/var/lib/pacman', '/.new.var.lib/pacman') exec('cp', '-ax', '/.new_rootfs/var/lib/pacman', '/.new.var.lib/pacman')
exec('mv', '.new_rootfs', '.update_rootfs') exec('mv', '.new_rootfs', '.update_rootfs')
exec('cp', '-ax', '/.update_rootfs/etc', '/.update_rootfs/usr/etc') # don't move /etc/shells to /usr/etc
exec('bash', '-c', 'shopt -s extglob; cd /.update_rootfs/etc; cp -ax !(shells) /.update_rootfs/usr/etc; cd -')
new_boot_files = [] new_boot_files = []
@ -491,3 +499,10 @@ try:
command() command()
except KeyboardInterrupt: except KeyboardInterrupt:
error('aborting') error('aborting')
# remove update and akshara stuff if the program is exited
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')
# TODO: add similar handling for errors, and an option to not delete stuff on error/early exit