Compare commits

...
Sign in to create a new pull request.

6 commits

Author SHA1 Message Date
InsanePrawn
a28550825f image/image: tolerate pub-key copying to fail during image build 2024-03-23 17:53:59 +00:00
InsanePrawn
a176fad05a net/ssh: copy_ssh_keys(): pass chroot for uid resolution 2024-03-23 17:53:59 +00:00
InsanePrawn
a4cfc3c3e5 exec/file: makedir(): add mode=None arg 2024-03-23 17:53:59 +00:00
Syboxez Blank
cebac83186 packages/pkgbuild: parse_pkgbuild(): Reuse pkgbase's makedepends as dependencies
Authored-by: InsanePrawn <insane.prawny@gmail.com>
2024-03-23 17:48:38 +00:00
InsanePrawn
f05de7738a integration_tests: test importing main.cli 2024-01-08 04:25:42 +01:00
InsanePrawn
b006cd8f4d packages/pkgbuild: support new key "_crossdirect" to enable/disable crossdirect for single packages 2024-01-08 03:04:43 +01:00
8 changed files with 80 additions and 31 deletions

View file

@ -144,7 +144,13 @@ def remove_file(path: str, recursive=False):
raise Exception(f"Unable to remove {path}: cmd returned {rc}")
def makedir(path, user: Optional[Union[str, int]] = None, group: Optional[Union[str, int]] = None, parents: bool = True):
def makedir(
path,
user: Optional[Union[str, int]] = None,
group: Optional[Union[str, int]] = None,
parents: bool = True,
mode: Optional[Union[int, str]] = None,
):
if not root_check_exists(path):
try:
if parents:
@ -153,6 +159,8 @@ def makedir(path, user: Optional[Union[str, int]] = None, group: Optional[Union[
os.mkdir(path)
except:
run_root_cmd(['mkdir'] + (['-p'] if parents else []) + [path])
if mode is not None:
chmod(path, mode=mode)
chown(path, user, group)

View file

@ -333,8 +333,9 @@ def install_rootfs(
)
chroot.add_sudo_config(config_name='wheel', privilegee='%wheel', password_required=True)
copy_ssh_keys(
chroot.path,
chroot,
user=user,
allow_fail=True,
)
files = {
'etc/pacman.conf': get_base_distro(arch).get_pacman_conf(

View file

@ -37,6 +37,11 @@ def ctx() -> click.Context:
return click.Context(click.Command('integration_tests'))
def test_main_import():
from main import cli
assert cli
def test_config_load(ctx: click.Context):
path = config.runtime.config_file
assert path

View file

@ -6,7 +6,9 @@ import click
from config.state import config
from constants import SSH_COMMON_OPTIONS, SSH_DEFAULT_HOST, SSH_DEFAULT_PORT
from chroot.abstract import Chroot
from exec.cmd import run_cmd
from exec.file import write_file
from wrapper import check_programs_wrap
@ -83,21 +85,16 @@ def find_ssh_keys():
return keys
def copy_ssh_keys(root_dir: str, user: str):
def copy_ssh_keys(chroot: Chroot, user: str, allow_fail: bool = False):
check_programs_wrap(['ssh-keygen'])
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)
ssh_dir_relative = os.path.join('/home', user, '.ssh')
ssh_dir = chroot.get_path(ssh_dir_relative)
authorized_keys_file_rel = os.path.join(ssh_dir_relative, 'authorized_keys')
authorized_keys_file = chroot.get_path(authorized_keys_file_rel)
keys = find_ssh_keys()
if len(keys) == 0:
logging.info("Could not find any ssh key to copy")
logging.warning("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
@ -116,15 +113,34 @@ def copy_ssh_keys(root_dir: str, user: str):
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, mode=0o700)
if not keys:
logging.warning("No SSH keys to be copied. Skipping.")
return
with open(authorized_keys_file, 'a') as authorized_keys:
for key in keys:
pub = f'{key}.pub'
if not os.path.exists(pub):
logging.debug(f'Skipping key {key}: {pub} not found')
continue
auth_key_lines = []
for key in keys:
pub = f'{key}.pub'
if not os.path.exists(pub):
logging.debug(f'Skipping key {key}: {pub} not found')
continue
try:
with open(pub, 'r') as file:
authorized_keys.write(file.read())
contents = file.read()
if not contents.strip():
continue
auth_key_lines.append(contents)
except Exception as ex:
logging.warning(f"Could not read ssh pub key {pub}", exc_info=ex)
continue
if not os.path.exists(ssh_dir):
logging.info(f"Creating {ssh_dir_relative!r} dir in chroot {chroot.path!r}")
chroot.run_cmd(["mkdir", "-p", "-m", "700", ssh_dir_relative], switch_user=user)
logging.info(f"Writing SSH pub keys to {authorized_keys_file}")
try:
write_file(authorized_keys_file, "\n".join(auth_key_lines), user=str(chroot.get_uid(user)), mode="644")
except Exception as ex:
logging.error(f"Failed to write SSH authorized_keys_file at {authorized_keys_file!r}:", exc_info=ex)
if allow_fail:
return
raise ex from ex

View file

@ -575,7 +575,7 @@ def build_package(
build_root = target_chroot
makepkg_compile_opts += ['--nodeps' if package.nodeps else '--syncdeps']
env = deepcopy(get_makepkg_env(arch))
if foreign_arch and enable_crossdirect and package.name not in CROSSDIRECT_PKGS:
if foreign_arch and package.crossdirect and enable_crossdirect and package.name not in CROSSDIRECT_PKGS:
env['PATH'] = f"/native/usr/lib/crossdirect/{arch}:{env['PATH']}"
target_chroot.mount_crossdirect(native_chroot)
else:

View file

@ -313,7 +313,7 @@ def cmd_list():
logging.info(f'Done! {len(packages)} Pkgbuilds:')
for name in sorted(packages.keys()):
p = packages[name]
print(f'name: {p.name}; ver: {p.version}; mode: {p.mode}; provides: {p.provides}; replaces: {p.replaces};'
print(f'name: {p.name}; ver: {p.version}; mode: {p.mode}; crossdirect: {p.crossdirect} provides: {p.provides}; replaces: {p.replaces};'
f'local_depends: {p.local_depends}; depends: {p.depends}')
@ -346,6 +346,7 @@ def cmd_check(paths):
mode_key = '_mode'
nodeps_key = '_nodeps'
crossdirect_key = '_crossdirect'
pkgbase_key = 'pkgbase'
pkgname_key = 'pkgname'
arches_key = '_arches'
@ -356,6 +357,7 @@ def cmd_check(paths):
required = {
mode_key: True,
nodeps_key: False,
crossdirect_key: False,
pkgbase_key: False,
pkgname_key: True,
'pkgdesc': False,

View file

@ -156,6 +156,7 @@ class Pkgbuild(PackageInfo):
repo: str
mode: str
nodeps: bool
crossdirect: bool
path: str
pkgver: str
pkgrel: str
@ -190,6 +191,7 @@ class Pkgbuild(PackageInfo):
self.repo = repo or ''
self.mode = ''
self.nodeps = False
self.crossdirect = True
self.path = relative_path
self.pkgver = ''
self.pkgrel = ''
@ -223,6 +225,7 @@ class Pkgbuild(PackageInfo):
self.repo = pkg.repo
self.mode = pkg.mode
self.nodeps = pkg.nodeps
self.crossdirect = pkg.crossdirect
self.path = pkg.path
self.pkgver = pkg.pkgver
self.pkgrel = pkg.pkgrel
@ -357,7 +360,11 @@ def parse_pkgbuild(
else:
raise Exception(msg)
# if _crossdirect is unset (None), it defaults to True
crossdirect_enabled = srcinfo_cache.build_crossdirect in (None, True)
base_package = Pkgbase(relative_pkg_dir, sources_refreshed=sources_refreshed, srcinfo_cache=srcinfo_cache)
base_package.crossdirect = crossdirect_enabled
base_package.mode = mode
base_package.nodeps = nodeps
base_package.repo = relative_pkg_dir.split('/')[0]
@ -396,7 +403,7 @@ def parse_pkgbuild(
elif splits[0] in ['depends', 'makedepends', 'checkdepends', 'optdepends']:
spec = splits[1].split(': ', 1)[0]
if not current.depends:
current.depends = {}
current.depends = (base_package.makedepends or {}).copy()
current.depends = get_version_specs(spec, current.depends)
if splits[0] == 'makedepends':
if not current.makedepends:

View file

@ -68,11 +68,19 @@ class SrcInitialisedFile(JsonFile):
raise ex
srcinfo_meta_defaults = {
'build_mode': None,
"build_nodeps": None,
"build_crossdirect": None,
}
class SrcinfoMetaFile(JsonFile):
checksums: dict[str, str]
build_mode: Optional[str]
build_nodeps: Optional[bool]
build_crossdirect: Optional[bool]
_changed: bool
_filename: ClassVar[str] = SRCINFO_METADATA_FILE
@ -92,9 +100,8 @@ class SrcinfoMetaFile(JsonFile):
s = SrcinfoMetaFile({
'_relative_path': relative_pkg_dir,
'_changed': True,
'build_mode': '',
'build_nodeps': None,
'checksums': {},
**srcinfo_meta_defaults,
})
return s, s.refresh_all()
@ -120,9 +127,11 @@ class SrcinfoMetaFile(JsonFile):
if not force_refresh:
logging.debug(f'{metadata._relative_path}: srcinfo checksums match!')
lines = lines or metadata.read_srcinfo_file()
for build_field in ['build_mode', 'build_nodeps']:
for build_field in srcinfo_meta_defaults.keys():
if build_field not in metadata:
metadata.refresh_build_fields()
if write:
metadata.write()
break
else:
lines = metadata.refresh_all(write=write)
@ -143,8 +152,7 @@ class SrcinfoMetaFile(JsonFile):
self._changed = True
def refresh_build_fields(self):
self['build_mode'] = None
self['build_nodeps'] = None
self.update(srcinfo_meta_defaults)
with open(os.path.join(config.get_path('pkgbuilds'), self._relative_path, 'PKGBUILD'), 'r') as file:
lines = file.read().split('\n')
for line in lines:
@ -156,6 +164,8 @@ class SrcinfoMetaFile(JsonFile):
self.build_mode = val
elif key == '_nodeps':
self.build_nodeps = val.lower() == 'true'
elif key == '_crossdirect':
self.build_crossdirect = val.lower() == 'true'
else:
continue