Add packages sideload feature
This commit is contained in:
parent
135ffc5def
commit
0e07a33968
5 changed files with 137 additions and 12 deletions
11
constants.py
11
constants.py
|
@ -131,3 +131,14 @@ CFLAGS_ARCHES: dict[Arch, list[str]] = {
|
||||||
}
|
}
|
||||||
|
|
||||||
CROSSDIRECT_PKGS = ['crossdirect', 'qemu-user-static-bin', 'binfmt-qemu-static']
|
CROSSDIRECT_PKGS = ['crossdirect', 'qemu-user-static-bin', 'binfmt-qemu-static']
|
||||||
|
|
||||||
|
SSH_DEFAULT_HOST = '172.16.42.1'
|
||||||
|
SSH_DEFAULT_PORT = 22
|
||||||
|
SSH_COMMON_OPTIONS = [
|
||||||
|
'-o',
|
||||||
|
'GlobalKnownHostsFile=/dev/null',
|
||||||
|
'-o',
|
||||||
|
'UserKnownHostsFile=/dev/null',
|
||||||
|
'-o',
|
||||||
|
'StrictHostKeyChecking=no',
|
||||||
|
]
|
||||||
|
|
5
image.py
5
image.py
|
@ -7,6 +7,7 @@ from chroot import create_chroot, create_chroot_user, get_chroot_path, run_chroo
|
||||||
from constants import BASE_PACKAGES, DEVICES, FLAVOURS
|
from constants import BASE_PACKAGES, DEVICES, FLAVOURS
|
||||||
from config import config
|
from config import config
|
||||||
from distro import get_base_distro, get_kupfer_https, get_kupfer_local
|
from distro import get_base_distro, get_kupfer_https, get_kupfer_local
|
||||||
|
from ssh import copy_ssh_keys
|
||||||
from wrapper import enforce_wrap
|
from wrapper import enforce_wrap
|
||||||
from signal import pause
|
from signal import pause
|
||||||
|
|
||||||
|
@ -181,6 +182,10 @@ def cmd_build():
|
||||||
password=profile['password'],
|
password=profile['password'],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
copy_ssh_keys(
|
||||||
|
rootfs_mount,
|
||||||
|
user=profile['username'],
|
||||||
|
)
|
||||||
with open(os.path.join(rootfs_mount, 'etc', 'pacman.conf'), 'w') as file:
|
with open(os.path.join(rootfs_mount, 'etc', 'pacman.conf'), 'w') as file:
|
||||||
file.write(get_base_distro(arch).get_pacman_conf(check_space=True, extra_repos=get_kupfer_https(arch).repos))
|
file.write(get_base_distro(arch).get_pacman_conf(check_space=True, extra_repos=get_kupfer_https(arch).repos))
|
||||||
if post_cmds:
|
if post_cmds:
|
||||||
|
|
34
packages.py
34
packages.py
|
@ -11,6 +11,7 @@ from constants import REPOSITORIES, CROSSDIRECT_PKGS, GCC_HOSTSPECS, ARCHES
|
||||||
from config import config
|
from config import config
|
||||||
from chroot import create_chroot, run_chroot_cmd, try_install_packages, mount_crossdirect, write_cross_makepkg_conf, mount_packages, mount_pacman_cache
|
from chroot import create_chroot, run_chroot_cmd, try_install_packages, mount_crossdirect, write_cross_makepkg_conf, mount_packages, mount_pacman_cache
|
||||||
from distro import get_kupfer_local
|
from distro import get_kupfer_local
|
||||||
|
from ssh import run_ssh_command, scp_put_files
|
||||||
from wrapper import enforce_wrap
|
from wrapper import enforce_wrap
|
||||||
from utils import mount, umount, git
|
from utils import mount, umount, git
|
||||||
from binfmt import register as binfmt_register
|
from binfmt import register as binfmt_register
|
||||||
|
@ -348,10 +349,14 @@ def add_package_to_repo(package: Package, arch: str):
|
||||||
logging.info(f'Adding {package.path} to repo {package.repo}')
|
logging.info(f'Adding {package.path} to repo {package.repo}')
|
||||||
pkgbuild_dir = os.path.join(config.get_path('pkgbuilds'), package.path)
|
pkgbuild_dir = os.path.join(config.get_path('pkgbuilds'), package.path)
|
||||||
|
|
||||||
|
files = []
|
||||||
for file in os.listdir(pkgbuild_dir):
|
for file in os.listdir(pkgbuild_dir):
|
||||||
# Forced extension by makepkg.conf
|
# Forced extension by makepkg.conf
|
||||||
if file.endswith('.pkg.tar.xz') or file.endswith('.pkg.tar.zst'):
|
if file.endswith('.pkg.tar.xz') or file.endswith('.pkg.tar.zst'):
|
||||||
|
repo_dir = os.path.join(config.get_package_dir(arch), package.repo)
|
||||||
|
files.append(os.path.join(repo_dir, file))
|
||||||
add_file_to_repo(os.path.join(pkgbuild_dir, file), package.repo, arch)
|
add_file_to_repo(os.path.join(pkgbuild_dir, file), package.repo, arch)
|
||||||
|
return files
|
||||||
|
|
||||||
|
|
||||||
def check_package_version_built(package: Package, arch) -> bool:
|
def check_package_version_built(package: Package, arch) -> bool:
|
||||||
|
@ -555,6 +560,8 @@ def build_packages(
|
||||||
if not build_levels:
|
if not build_levels:
|
||||||
logging.info('Everything built already')
|
logging.info('Everything built already')
|
||||||
return
|
return
|
||||||
|
|
||||||
|
files = []
|
||||||
for level, need_build in enumerate(build_levels):
|
for level, need_build in enumerate(build_levels):
|
||||||
logging.info(f"(Level {level}) Building {', '.join([x.name for x in need_build])}")
|
logging.info(f"(Level {level}) Building {', '.join([x.name for x in need_build])}")
|
||||||
for package in need_build:
|
for package in need_build:
|
||||||
|
@ -565,7 +572,8 @@ def build_packages(
|
||||||
enable_crossdirect=enable_crossdirect,
|
enable_crossdirect=enable_crossdirect,
|
||||||
enable_ccache=enable_ccache,
|
enable_ccache=enable_ccache,
|
||||||
)
|
)
|
||||||
add_package_to_repo(package, arch)
|
files += add_package_to_repo(package, arch)
|
||||||
|
return files
|
||||||
|
|
||||||
|
|
||||||
def build_packages_by_paths(
|
def build_packages_by_paths(
|
||||||
|
@ -583,7 +591,7 @@ def build_packages_by_paths(
|
||||||
for _arch in set([arch, config.runtime['arch']]):
|
for _arch in set([arch, config.runtime['arch']]):
|
||||||
init_prebuilts(_arch)
|
init_prebuilts(_arch)
|
||||||
packages = filter_packages_by_paths(repo, paths)
|
packages = filter_packages_by_paths(repo, paths)
|
||||||
build_packages(
|
return build_packages(
|
||||||
repo,
|
repo,
|
||||||
packages,
|
packages,
|
||||||
arch,
|
arch,
|
||||||
|
@ -611,6 +619,10 @@ def cmd_update(non_interactive: bool = False):
|
||||||
@click.option('--arch', default=None)
|
@click.option('--arch', default=None)
|
||||||
@click.argument('paths', nargs=-1)
|
@click.argument('paths', nargs=-1)
|
||||||
def cmd_build(paths: list[str], force=False, arch=None):
|
def cmd_build(paths: list[str], force=False, arch=None):
|
||||||
|
build(paths, force, arch)
|
||||||
|
|
||||||
|
|
||||||
|
def build(paths: list[str], force: bool, arch: str):
|
||||||
if arch is None:
|
if arch is None:
|
||||||
# TODO: arch = config.get_profile()...
|
# TODO: arch = config.get_profile()...
|
||||||
arch = 'aarch64'
|
arch = 'aarch64'
|
||||||
|
@ -634,7 +646,7 @@ def cmd_build(paths: list[str], force=False, arch=None):
|
||||||
subprocess.run(['pacman', '-Syy', '--noconfirm', '--needed'] + CROSSDIRECT_PKGS)
|
subprocess.run(['pacman', '-Syy', '--noconfirm', '--needed'] + CROSSDIRECT_PKGS)
|
||||||
binfmt_register(arch)
|
binfmt_register(arch)
|
||||||
|
|
||||||
build_packages_by_paths(
|
return build_packages_by_paths(
|
||||||
paths,
|
paths,
|
||||||
arch,
|
arch,
|
||||||
repo,
|
repo,
|
||||||
|
@ -645,6 +657,22 @@ def cmd_build(paths: list[str], force=False, arch=None):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@cmd_packages.command(name='sideload')
|
||||||
|
@click.argument('paths', nargs=-1)
|
||||||
|
def cmd_sideload(paths: list[str]):
|
||||||
|
files = build(paths, True, None)
|
||||||
|
scp_put_files(files, '/tmp')
|
||||||
|
run_ssh_command([
|
||||||
|
'sudo',
|
||||||
|
'-S',
|
||||||
|
'pacman',
|
||||||
|
'-U',
|
||||||
|
] + [os.path.join('/tmp', os.path.basename(file)) for file in files] + [
|
||||||
|
'--noconfirm',
|
||||||
|
'--overwrite=*',
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
@cmd_packages.command(name='clean')
|
@cmd_packages.command(name='clean')
|
||||||
def cmd_clean():
|
def cmd_clean():
|
||||||
enforce_wrap()
|
enforce_wrap()
|
||||||
|
|
94
ssh.py
94
ssh.py
|
@ -1,25 +1,101 @@
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
import subprocess
|
import subprocess
|
||||||
import click
|
import click
|
||||||
from wrapper import check_programs_wrap
|
from config import config
|
||||||
|
from constants import SSH_COMMON_OPTIONS, SSH_DEFAULT_HOST, SSH_DEFAULT_PORT
|
||||||
|
from wrapper import enforce_wrap
|
||||||
|
|
||||||
|
|
||||||
@click.command(name='ssh')
|
@click.command(name='ssh')
|
||||||
def cmd_ssh():
|
def cmd_ssh():
|
||||||
check_programs_wrap('ssh')
|
enforce_wrap()
|
||||||
run_ssh_command()
|
run_ssh_command()
|
||||||
|
|
||||||
|
|
||||||
def run_ssh_command(cmd: list[str] = [], host: str = '172.16.42.1', user: str = 'kupfer', port: int = 22):
|
def run_ssh_command(cmd: list[str] = [], user: str = None, host: str = SSH_DEFAULT_HOST, port: int = SSH_DEFAULT_PORT):
|
||||||
|
if not user:
|
||||||
|
user = config.get_profile()['username']
|
||||||
|
keys = find_ssh_keys()
|
||||||
|
key_args = []
|
||||||
|
if len(keys) > 0:
|
||||||
|
key_args = ['-i', keys[0]]
|
||||||
return subprocess.run([
|
return subprocess.run([
|
||||||
'ssh',
|
'ssh',
|
||||||
'-o',
|
] + key_args + SSH_COMMON_OPTIONS + [
|
||||||
'GlobalKnownHostsFile=/dev/null',
|
|
||||||
'-o',
|
|
||||||
'UserKnownHostsFile=/dev/null',
|
|
||||||
'-o',
|
|
||||||
'StrictHostKeyChecking=no',
|
|
||||||
'-p',
|
'-p',
|
||||||
str(port),
|
str(port),
|
||||||
f'{user}@{host}',
|
f'{user}@{host}',
|
||||||
'--',
|
'--',
|
||||||
] + cmd)
|
] + cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def scp_put_files(src: list[str], dst: str, user: str = None, host: str = SSH_DEFAULT_HOST, port: int = SSH_DEFAULT_PORT):
|
||||||
|
if not user:
|
||||||
|
user = config.get_profile()['username']
|
||||||
|
keys = find_ssh_keys()
|
||||||
|
key_args = []
|
||||||
|
if len(keys) > 0:
|
||||||
|
key_args = ['-i', keys[0]]
|
||||||
|
return subprocess.run([
|
||||||
|
'scp',
|
||||||
|
] + key_args + SSH_COMMON_OPTIONS + [
|
||||||
|
'-P',
|
||||||
|
str(port),
|
||||||
|
] + src + [
|
||||||
|
f'{user}@{host}:{dst}',
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
def find_ssh_keys():
|
||||||
|
dir = os.path.join(pathlib.Path.home(), '.ssh')
|
||||||
|
if not os.path.exists(dir):
|
||||||
|
return []
|
||||||
|
keys = []
|
||||||
|
for file in os.listdir(dir):
|
||||||
|
if file.startswith('id_') and not file.endswith('.pub'):
|
||||||
|
keys.append(os.path.join(dir, file))
|
||||||
|
return keys
|
||||||
|
|
||||||
|
|
||||||
|
def copy_ssh_keys(root_dir: str, user: str):
|
||||||
|
authorized_keys_file = os.path.join(
|
||||||
|
root_dir,
|
||||||
|
'home',
|
||||||
|
user,
|
||||||
|
'.ssh',
|
||||||
|
'authorized_keys',
|
||||||
|
)
|
||||||
|
if os.path.exists(authorized_keys_file):
|
||||||
|
os.unlink(authorized_keys_file)
|
||||||
|
|
||||||
|
keys = find_ssh_keys()
|
||||||
|
if len(keys) == 0:
|
||||||
|
logging.info("Could not find any ssh key to copy")
|
||||||
|
create = click.confirm("Do you want me to generate an ssh key for you?", True)
|
||||||
|
if not create:
|
||||||
|
return
|
||||||
|
result = subprocess.run([
|
||||||
|
'ssh-keygen',
|
||||||
|
'-f',
|
||||||
|
os.path.join(pathlib.Path.home(), '.ssh', 'id_ed25519_kupfer'),
|
||||||
|
'-t',
|
||||||
|
'ed25519',
|
||||||
|
'-C',
|
||||||
|
'kupfer',
|
||||||
|
'-N',
|
||||||
|
'',
|
||||||
|
])
|
||||||
|
if result.returncode != 0:
|
||||||
|
logging.fatal("Failed to generate ssh key")
|
||||||
|
keys = find_ssh_keys()
|
||||||
|
|
||||||
|
ssh_dir = os.path.join(root_dir, 'home', user, '.ssh')
|
||||||
|
if not os.path.exists(ssh_dir):
|
||||||
|
os.makedirs(ssh_dir, exist_ok=True)
|
||||||
|
|
||||||
|
with open(authorized_keys_file, 'a') as authorized_keys:
|
||||||
|
for key in keys:
|
||||||
|
with open(f'{key}.pub', 'r') as file:
|
||||||
|
authorized_keys.write(file.read())
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import atexit
|
import atexit
|
||||||
import os
|
import os
|
||||||
|
import pathlib
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import uuid
|
import uuid
|
||||||
|
@ -102,10 +103,14 @@ def wrap_docker():
|
||||||
atexit.register(at_exit)
|
atexit.register(at_exit)
|
||||||
|
|
||||||
dump_config_file(file_path=wrapped_config, config=(config.file | {'paths': DOCKER_PATHS}))
|
dump_config_file(file_path=wrapped_config, config=(config.file | {'paths': DOCKER_PATHS}))
|
||||||
|
ssh_dir = os.path.join(pathlib.Path.home(), '.ssh')
|
||||||
|
if not os.path.exists(ssh_dir):
|
||||||
|
os.makedirs(ssh_dir)
|
||||||
volumes = {
|
volumes = {
|
||||||
'/dev': '/dev',
|
'/dev': '/dev',
|
||||||
os.getcwd(): '/src',
|
os.getcwd(): '/src',
|
||||||
wrapped_config: '/root/.config/kupfer/kupferbootstrap.toml',
|
wrapped_config: '/root/.config/kupfer/kupferbootstrap.toml',
|
||||||
|
ssh_dir: '/root/.ssh',
|
||||||
}
|
}
|
||||||
volumes |= dict({config.get_path(vol_name): vol_dest for vol_name, vol_dest in DOCKER_PATHS.items()})
|
volumes |= dict({config.get_path(vol_name): vol_dest for vol_name, vol_dest in DOCKER_PATHS.items()})
|
||||||
docker_cmd = [
|
docker_cmd = [
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue