Initial commit
This commit is contained in:
commit
f9ba5a3cfd
14 changed files with 889 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
venv/
|
||||
__pycache__/
|
36
Dockerfile
Normal file
36
Dockerfile
Normal file
|
@ -0,0 +1,36 @@
|
|||
FROM archlinux:base-devel
|
||||
|
||||
RUN pacman -Syu --noconfirm \
|
||||
python python-pip \
|
||||
devtools rsync \
|
||||
aarch64-linux-gnu-gcc aarch64-linux-gnu-binutils aarch64-linux-gnu-glibc aarch64-linux-gnu-linux-api-headers \
|
||||
git
|
||||
|
||||
RUN sed -i "s/EUID == 0/EUID == -1/g" $(which makepkg)
|
||||
|
||||
RUN cd /tmp && \
|
||||
git clone https://aur.archlinux.org/aarch64-linux-gnu-pkg-config.git && \
|
||||
cd aarch64-linux-gnu-pkg-config && \
|
||||
makepkg -s --skippgpcheck && \
|
||||
pacman -U --noconfirm *.pkg*
|
||||
|
||||
RUN yes | pacman -Scc
|
||||
|
||||
RUN sed -i "s/SigLevel.*/SigLevel = Never/g" /etc/pacman.conf
|
||||
RUN sed -i "s|run_pacman |run_pacman --root \"/chroot/copy\" --arch aarch64 --config \"/app/src/pacman_copy.conf\" |g" $(which makepkg)
|
||||
RUN echo "Server = http://mirror.archlinuxarm.org/\$arch/\$repo" > /etc/pacman.d/aarch64_mirrorlist
|
||||
RUN mkdir -p /app/bin
|
||||
RUN ln -sf $(which aarch64-linux-gnu-strip) /app/bin/strip
|
||||
|
||||
RUN systemd-machine-id-setup
|
||||
|
||||
ENV KUPFERBOOTSTRAP_DOCKER=1
|
||||
WORKDIR /app
|
||||
ENV PATH=/app/bin:$PATH
|
||||
|
||||
COPY requirements.txt .
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
WORKDIR /src
|
8
README.md
Normal file
8
README.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
# kupferbootstrap
|
||||
|
||||
## Install
|
||||
Install Docker and Python 3 and put `bin/` into your `PATH`.
|
||||
Then use `kupferbootstrap`.
|
||||
|
||||
## Develop
|
||||
Put `dev` into `version.txt` to always rebuild kupferboostrap from this directory and use `kupferbootstrap` as normal.
|
4
bin/kupferbootstrap
Executable file
4
bin/kupferbootstrap
Executable file
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
|
||||
# shellcheck disable=SC2068
|
||||
python3 "$(dirname "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")")/wrapper.py" $@
|
26
cache.py
Normal file
26
cache.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
import shutil
|
||||
from logger import *
|
||||
import click
|
||||
import os
|
||||
|
||||
|
||||
@click.group(name='cache')
|
||||
def cmd_cache():
|
||||
pass
|
||||
|
||||
|
||||
@click.command(name='clean')
|
||||
@verbose_option
|
||||
def cmd_clean(verbose):
|
||||
setup_logging(verbose)
|
||||
|
||||
for dir in ['/chroot', '/var/cache/pacman/pkg']:
|
||||
for file in os.listdir(dir):
|
||||
path = os.path.join(dir, file)
|
||||
if os.path.isdir(path):
|
||||
shutil.rmtree(path)
|
||||
else:
|
||||
os.unlink(path)
|
||||
|
||||
|
||||
cmd_cache.add_command(cmd_clean)
|
23
logger.py
Normal file
23
logger.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
import click
|
||||
import logging
|
||||
import sys
|
||||
|
||||
|
||||
def setup_logging(verbose: bool):
|
||||
level = logging.INFO
|
||||
if verbose:
|
||||
level = logging.DEBUG
|
||||
logging.basicConfig(
|
||||
stream=sys.stdout,
|
||||
format='%(asctime)s %(levelname)s: %(message)s',
|
||||
datefmt='%m/%d/%Y %H:%M:%S',
|
||||
level=level
|
||||
)
|
||||
|
||||
|
||||
verbose_option = click.option(
|
||||
'-v',
|
||||
'--verbose',
|
||||
is_flag=True,
|
||||
help='Enables verbose logging'
|
||||
)
|
12
main.py
Normal file
12
main.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
from packages import cmd_packages
|
||||
from cache import cmd_cache
|
||||
import click
|
||||
|
||||
|
||||
@click.group()
|
||||
def cli():
|
||||
pass
|
||||
|
||||
|
||||
cli.add_command(cmd_cache)
|
||||
cli.add_command(cmd_packages)
|
431
packages.py
Normal file
431
packages.py
Normal file
|
@ -0,0 +1,431 @@
|
|||
from logger import *
|
||||
import atexit
|
||||
import click
|
||||
import logging
|
||||
import multiprocessing
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
makepkg_env = os.environ.copy() | {
|
||||
'LANG': 'C',
|
||||
'MAKEFLAGS': f'-j{multiprocessing.cpu_count()}',
|
||||
}
|
||||
|
||||
makepkg_cmd = ['makepkg',
|
||||
'--config', '/app/src/makepkg.conf',
|
||||
'--noconfirm',
|
||||
'--ignorearch',
|
||||
'--needed']
|
||||
|
||||
pacman_cmd = ['pacman',
|
||||
'--noconfirm',
|
||||
'--overwrite=*',
|
||||
'--needed', ]
|
||||
|
||||
|
||||
class Package:
|
||||
names = []
|
||||
depends = []
|
||||
local_depends = None
|
||||
repo = ''
|
||||
mode = ''
|
||||
has_pkgver = False
|
||||
|
||||
def __init__(self, path: str) -> None:
|
||||
self.path = path
|
||||
self._loadinfo()
|
||||
|
||||
def _loadinfo(self):
|
||||
result = subprocess.run(makepkg_cmd+['--printsrcinfo'],
|
||||
cwd=self.path,
|
||||
stdout=subprocess.PIPE)
|
||||
lines = result.stdout.decode('utf-8').split('\n')
|
||||
names = []
|
||||
depends = []
|
||||
for line in lines:
|
||||
if line.startswith('pkgbase') or line.startswith('\tpkgname') or line.startswith('\tprovides'):
|
||||
names.append(line.split(' = ')[1])
|
||||
if line.startswith('\tdepends') or line.startswith('\tmakedepends') or line.startswith('\tcheckdepends') or line.startswith('\toptdepends'):
|
||||
depends.append(line.split(' = ')[1].split('=')[0])
|
||||
self.names = list(set(names))
|
||||
self.depends = list(set(depends))
|
||||
|
||||
self.repo = self.path.split('/')[0]
|
||||
|
||||
mode = ''
|
||||
with open(os.path.join(self.path, 'PKGBUILD'), 'r') as file:
|
||||
for line in file.read().split('\n'):
|
||||
if line.startswith('_mode='):
|
||||
mode = line.split('=')[1]
|
||||
break
|
||||
if mode not in ['host', 'cross']:
|
||||
logging.fatal(
|
||||
f'Package {self.path} has an invalid mode configured: \'{mode}\'')
|
||||
exit(1)
|
||||
self.mode = mode
|
||||
|
||||
has_pkgver = False
|
||||
with open(os.path.join(self.path, 'PKGBUILD'), 'r') as file:
|
||||
for line in file.read().split('\n'):
|
||||
if line.startswith('pkgver()'):
|
||||
has_pkgver = True
|
||||
break
|
||||
self.has_pkgver = has_pkgver
|
||||
|
||||
|
||||
def check_prebuilts():
|
||||
if not os.path.exists('prebuilts'):
|
||||
os.makedirs('prebuilts')
|
||||
for repo in ['main', 'device']:
|
||||
if not os.path.exists(os.path.join('prebuilts', repo)):
|
||||
os.makedirs(os.path.join('prebuilts', repo))
|
||||
for ext1 in ['db', 'files']:
|
||||
for ext2 in ['', '.tar.xz']:
|
||||
if not os.path.exists(os.path.join('prebuilts', repo, f'{repo}.{ext1}{ext2}')):
|
||||
result = subprocess.run(['tar',
|
||||
'-czf',
|
||||
f'{repo}.{ext1}{ext2}',
|
||||
'-T', '/dev/null'],
|
||||
cwd=os.path.join('prebuilts', repo))
|
||||
if result.returncode != 0:
|
||||
logging.fatal('Failed create prebuilt repos')
|
||||
exit(1)
|
||||
|
||||
|
||||
def setup_chroot():
|
||||
if not os.path.exists('/chroot/root'):
|
||||
logging.info('Initializing root chroot')
|
||||
result = subprocess.run(['mkarchroot',
|
||||
'-s',
|
||||
'-C', '/app/src/pacman.conf',
|
||||
'-f', '/etc/locale.gen',
|
||||
'/chroot/root',
|
||||
'base-devel'])
|
||||
if result.returncode != 0:
|
||||
logging.fatal('Failed to initialize root chroot')
|
||||
shutil.rmtree('/chroot/root')
|
||||
exit(1)
|
||||
else:
|
||||
logging.info('Updating root chroot')
|
||||
result = subprocess.run(pacman_cmd +
|
||||
['-Syuu',
|
||||
'--root', '/chroot/root',
|
||||
'--arch', 'aarch64',
|
||||
'--config', '/app/src/pacman.conf'])
|
||||
if result.returncode != 0:
|
||||
logging.fatal('Failed to update root chroot')
|
||||
exit(1)
|
||||
|
||||
shutil.copyfile('/app/src/pacman.conf', '/app/src/pacman_copy.conf')
|
||||
with open('/app/src/pacman_copy.conf', 'a') as file:
|
||||
file.write('\n\n[main]\nServer = file:///src/prebuilts/main')
|
||||
file.write('\n\n[device]\nServer = file:///src/prebuilts/device')
|
||||
shutil.copyfile('/app/src/pacman_copy.conf',
|
||||
'/chroot/root/etc/pacman.conf')
|
||||
shutil.copyfile('/etc/pacman.d/aarch64_mirrorlist',
|
||||
'/chroot/root/etc/pacman.d/aarch64_mirrorlist')
|
||||
result = subprocess.run(pacman_cmd +
|
||||
['-Sy',
|
||||
'--root', '/chroot/root',
|
||||
'--arch', 'aarch64',
|
||||
'--config', '/chroot/root/etc/pacman.conf'])
|
||||
if result.returncode != 0:
|
||||
logging.fatal('Failed to update root chroot')
|
||||
exit(1)
|
||||
|
||||
with open('/chroot/root/usr/bin/makepkg', 'r') as file:
|
||||
data = file.read()
|
||||
data = data.replace('EUID == 0', 'EUID == -1')
|
||||
with open('/chroot/root/usr/bin/makepkg', 'w') as file:
|
||||
file.write(data)
|
||||
|
||||
with open('/chroot/root/etc/makepkg.conf', 'r') as file:
|
||||
data = file.read()
|
||||
data = data.replace('xz -c', 'xz -T0 -c')
|
||||
data = data.replace(' check ', ' !check ')
|
||||
with open('/chroot/root/etc/makepkg.conf', 'w') as file:
|
||||
file.write(data)
|
||||
|
||||
logging.info('Syncing chroot copy')
|
||||
result = subprocess.run(
|
||||
['rsync', '-a', '--delete', '-q', '-W', '-x', '/chroot/root/', '/chroot/copy'])
|
||||
if result.returncode != 0:
|
||||
logging.fatal('Failed to sync chroot copy')
|
||||
exit(1)
|
||||
|
||||
|
||||
def discover_packages() -> list[Package]:
|
||||
packages = []
|
||||
paths = []
|
||||
|
||||
for dir in os.listdir('main'):
|
||||
paths.append(os.path.join('main', dir))
|
||||
for dir1 in os.listdir('device'):
|
||||
for dir2 in os.listdir(os.path.join('device', dir1)):
|
||||
paths.append(os.path.join('device', dir1, dir2))
|
||||
|
||||
for path in paths:
|
||||
logging.debug(f'Discovered {path}')
|
||||
packages.append(Package(path))
|
||||
|
||||
# This filters the deps to only include the ones that are provided in this repo
|
||||
for package in packages:
|
||||
package.local_depends = package.depends.copy()
|
||||
for dep in package.depends.copy():
|
||||
found = False
|
||||
for p in packages:
|
||||
for name in p.names:
|
||||
if dep == name:
|
||||
found = True
|
||||
break
|
||||
if found:
|
||||
break
|
||||
if not found:
|
||||
package.local_depends.remove(dep)
|
||||
|
||||
return packages
|
||||
|
||||
|
||||
def generate_package_order(packages: list[Package]) -> list[Package]:
|
||||
unsorted = packages.copy()
|
||||
sorted = []
|
||||
|
||||
"""
|
||||
It goes through all unsorted packages and checks if the dependencies have already been sorted.
|
||||
If that is true, the package itself is added to the sorted packages
|
||||
"""
|
||||
while len(unsorted) > 0:
|
||||
for package in unsorted.copy():
|
||||
if len(package.local_depends) == 0:
|
||||
sorted.append(package)
|
||||
unsorted.remove(package)
|
||||
for package in sorted:
|
||||
for name in package.names:
|
||||
for p in unsorted:
|
||||
for dep in p.local_depends.copy():
|
||||
if name == dep:
|
||||
p.local_depends.remove(name)
|
||||
|
||||
return sorted
|
||||
|
||||
|
||||
def update_package_version_and_sources(package: Package):
|
||||
"""
|
||||
This updates the package version and the sources.
|
||||
It is done here already, because doing it while host-compiling takes longer.
|
||||
We decided to even pin the commit of every -git package so this won't update any version, but it would if possible.
|
||||
"""
|
||||
cmd = makepkg_cmd+['--nobuild', '--noprepare', '--nodeps', '--skipinteg']
|
||||
if not package.has_pkgver:
|
||||
cmd.append('--noextract')
|
||||
logging.info(f'Updating package version for {package.path}')
|
||||
result = subprocess.run(cmd,
|
||||
env=makepkg_env,
|
||||
cwd=package.path)
|
||||
if result.returncode != 0:
|
||||
logging.fatal(f'Failed to update package version for {package.path}')
|
||||
exit(1)
|
||||
|
||||
|
||||
def check_package_version_built(package: Package) -> bool:
|
||||
built = True
|
||||
|
||||
result = subprocess.run(makepkg_cmd +
|
||||
['--nobuild',
|
||||
'--noprepare',
|
||||
'--packagelist'],
|
||||
env=makepkg_env,
|
||||
cwd=package.path,
|
||||
capture_output=True)
|
||||
if result.returncode != 0:
|
||||
logging.fatal(f'Failed to get package list for {package.path}')
|
||||
exit(1)
|
||||
|
||||
for line in result.stdout.decode('utf-8').split('\n'):
|
||||
if line != "":
|
||||
file = os.path.basename(line)
|
||||
if not os.path.exists(os.path.join('prebuilts', package.repo, file)):
|
||||
built = False
|
||||
|
||||
return built
|
||||
|
||||
|
||||
def setup_dependencies_and_sources(package: Package):
|
||||
logging.info(f'Setting up dependencies and sources for {package.path}')
|
||||
|
||||
"""
|
||||
To make cross-compilation work for almost every package, the host needs to have the dependencies installed
|
||||
so that the build tools can be used
|
||||
"""
|
||||
if package.mode == 'cross':
|
||||
for p in package.depends:
|
||||
subprocess.run(pacman_cmd + ['-Sw', p],
|
||||
stderr=subprocess.DEVNULL)
|
||||
|
||||
result = subprocess.run(makepkg_cmd +
|
||||
['--nobuild',
|
||||
'--skipinteg',
|
||||
'--holdver',
|
||||
'--syncdeps'],
|
||||
env=makepkg_env,
|
||||
cwd=package.path)
|
||||
if result.returncode != 0:
|
||||
logging.fatal(
|
||||
f'Failed to setup dependencies and sources for {package.path}')
|
||||
exit(1)
|
||||
|
||||
|
||||
def build_package(package: Package):
|
||||
makepkg_compile_opts = ['--noextract',
|
||||
'--skipinteg',
|
||||
'--holdver',
|
||||
'--nodeps']
|
||||
|
||||
if package.mode == 'cross':
|
||||
logging.info(f'Cross-compiling {package.path}')
|
||||
result = subprocess.run(makepkg_cmd+makepkg_compile_opts,
|
||||
env=makepkg_env | {
|
||||
'QEMU_LD_PREFIX': '/usr/aarch64-linux-gnu'},
|
||||
cwd=package.path)
|
||||
if result.returncode != 0:
|
||||
logging.fatal(
|
||||
f'Failed to cross-compile package {package.path}')
|
||||
exit(1)
|
||||
else:
|
||||
logging.info(f'Host-compiling {package.path}')
|
||||
|
||||
def umount():
|
||||
subprocess.run(['umount', '-lc', '/chroot/copy'],
|
||||
stderr=subprocess.DEVNULL)
|
||||
atexit.register(umount)
|
||||
|
||||
result = subprocess.run(
|
||||
['mount', '-o', 'bind', '/chroot/copy', '/chroot/copy'])
|
||||
if result.returncode != 0:
|
||||
logging.fatal('Failed to bind mount chroot to itself')
|
||||
exit(1)
|
||||
|
||||
os.makedirs('/chroot/copy/src')
|
||||
result = subprocess.run(
|
||||
['mount', '-o', 'bind', '.', '/chroot/copy/src'])
|
||||
if result.returncode != 0:
|
||||
logging.fatal(
|
||||
f'Failed to bind mount folder to chroot')
|
||||
exit(1)
|
||||
|
||||
env = []
|
||||
for key in makepkg_env:
|
||||
env.append(f'{key}={makepkg_env[key]}')
|
||||
result = subprocess.run(
|
||||
['arch-chroot', '/chroot/copy', '/bin/bash', '-c', f'cd /src/{package.path} && {" ".join(env)} makepkg --noconfirm --ignorearch {" ".join(makepkg_compile_opts)}'])
|
||||
if result.returncode != 0:
|
||||
logging.fatal(f'Failed to host-compile package {package.path}')
|
||||
exit(1)
|
||||
|
||||
umount()
|
||||
|
||||
|
||||
def add_package_to_repo(package: Package):
|
||||
logging.info(f'Adding {package.path} to repo')
|
||||
dir = os.path.join('prebuilts', package.repo)
|
||||
if not os.path.exists(dir):
|
||||
os.mkdir(dir)
|
||||
|
||||
for file in os.listdir(package.path):
|
||||
# Forced extension by makepkg.conf
|
||||
if file.endswith('.pkg.tar.xz'):
|
||||
shutil.move(
|
||||
os.path.join(package.path, file),
|
||||
os.path.join(dir, file),
|
||||
)
|
||||
result = subprocess.run(['repo-add',
|
||||
'--remove',
|
||||
'--new',
|
||||
'--prevent-downgrade',
|
||||
os.path.join(
|
||||
'prebuilts',
|
||||
package.repo,
|
||||
f'{package.repo}.db.tar.xz',
|
||||
),
|
||||
os.path.join(dir, file),
|
||||
])
|
||||
if result.returncode != 0:
|
||||
logging.fatal(f'Failed add package {package.path} to repo')
|
||||
exit(1)
|
||||
for repo in ['main', 'device']:
|
||||
for ext in ['db', 'files']:
|
||||
if os.path.exists(os.path.join('prebuilts', repo, f'{repo}.{ext}.tar.xz')):
|
||||
os.unlink(os.path.join('prebuilts', repo, f'{repo}.{ext}'))
|
||||
shutil.copyfile(
|
||||
os.path.join('prebuilts', repo, f'{repo}.{ext}.tar.xz'),
|
||||
os.path.join('prebuilts', repo, f'{repo}.{ext}')
|
||||
)
|
||||
if os.path.exists(os.path.join('prebuilts', repo, f'{repo}.{ext}.tar.xz.old')):
|
||||
os.unlink(os.path.join('prebuilts', repo,
|
||||
f'{repo}.{ext}.tar.xz.old'))
|
||||
|
||||
|
||||
@click.group(name='packages')
|
||||
def cmd_packages():
|
||||
pass
|
||||
|
||||
|
||||
@click.command(name='build')
|
||||
@verbose_option
|
||||
@click.argument('path')
|
||||
def cmd_build(verbose, path):
|
||||
setup_logging(verbose)
|
||||
|
||||
check_prebuilts()
|
||||
|
||||
if path == 'all':
|
||||
packages = generate_package_order(discover_packages())
|
||||
need_build = []
|
||||
|
||||
for package in packages:
|
||||
update_package_version_and_sources(package)
|
||||
if not check_package_version_built(package):
|
||||
need_build.append(package)
|
||||
|
||||
if len(need_build) == 0:
|
||||
logging.info('Everything built already')
|
||||
return
|
||||
logging.info('Building %s', ', '.join(
|
||||
map(lambda x: x.path, need_build)))
|
||||
with open('.last_built', 'w') as file:
|
||||
file.write('\n'.join(
|
||||
map(lambda x: x.path, need_build)))
|
||||
|
||||
for package in need_build:
|
||||
setup_chroot()
|
||||
setup_dependencies_and_sources(package)
|
||||
build_package(package)
|
||||
add_package_to_repo(package)
|
||||
else:
|
||||
package = Package(path)
|
||||
update_package_version_and_sources(package)
|
||||
if not check_package_version_built(package):
|
||||
with open('.last_built', 'w') as file:
|
||||
file.write(package.path)
|
||||
setup_chroot()
|
||||
setup_dependencies_and_sources(package)
|
||||
build_package(package)
|
||||
add_package_to_repo(package)
|
||||
|
||||
|
||||
@click.command(name='clean')
|
||||
@verbose_option
|
||||
def cmd_clean(verbose):
|
||||
setup_logging(verbose)
|
||||
result = subprocess.run(['git',
|
||||
'clean',
|
||||
'-dffX',
|
||||
'main', 'device'])
|
||||
if result.returncode != 0:
|
||||
logging.fatal(f'Failed to git clean')
|
||||
exit(1)
|
||||
|
||||
|
||||
cmd_packages.add_command(cmd_build)
|
||||
cmd_packages.add_command(cmd_clean)
|
2
requirements.txt
Normal file
2
requirements.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
click==8.0.1
|
||||
appdirs==1.4.4
|
169
src/makepkg.conf
Normal file
169
src/makepkg.conf
Normal file
|
@ -0,0 +1,169 @@
|
|||
#!/hint/bash
|
||||
#
|
||||
# /etc/makepkg.conf
|
||||
#
|
||||
|
||||
#########################################################################
|
||||
# SOURCE ACQUISITION
|
||||
#########################################################################
|
||||
#
|
||||
#-- The download utilities that makepkg should use to acquire sources
|
||||
# Format: 'protocol::agent'
|
||||
DLAGENTS=('file::/usr/bin/curl -gqC - -o %o %u'
|
||||
'ftp::/usr/bin/curl -gqfC - --ftp-pasv --retry 3 --retry-delay 3 -o %o %u'
|
||||
'http::/usr/bin/curl -gqb "" -fLC - --retry 3 --retry-delay 3 -o %o %u'
|
||||
'https::/usr/bin/curl -gqb "" -fLC - --retry 3 --retry-delay 3 -o %o %u'
|
||||
'rsync::/usr/bin/rsync --no-motd -z %u %o'
|
||||
'scp::/usr/bin/scp -C %u %o')
|
||||
|
||||
# Other common tools:
|
||||
# /usr/bin/snarf
|
||||
# /usr/bin/lftpget -c
|
||||
# /usr/bin/wget
|
||||
|
||||
#-- The package required by makepkg to download VCS sources
|
||||
# Format: 'protocol::package'
|
||||
VCSCLIENTS=('bzr::bzr'
|
||||
'fossil::fossil'
|
||||
'git::git'
|
||||
'hg::mercurial'
|
||||
'svn::subversion')
|
||||
|
||||
#########################################################################
|
||||
# ARCHITECTURE, COMPILE FLAGS
|
||||
#########################################################################
|
||||
#
|
||||
CARCH="aarch64"
|
||||
CHOST="aarch64-unknown-linux-gnu"
|
||||
|
||||
#-- Compiler and Linker Flags
|
||||
# -march (or -mcpu) builds exclusively for an architecture
|
||||
# -mtune optimizes for an architecture, but builds for whole processor family
|
||||
CPPFLAGS=""
|
||||
CFLAGS="-march=armv8-a -O2 -pipe -fstack-protector-strong -fno-plt -fexceptions \
|
||||
-Wp,-D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security \
|
||||
-fstack-clash-protection"
|
||||
CXXFLAGS="$CFLAGS -Wp,-D_GLIBCXX_ASSERTIONS"
|
||||
LDFLAGS="-Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now"
|
||||
#RUSTFLAGS="-C opt-level=2"
|
||||
#-- Make Flags: change this for DistCC/SMP systems
|
||||
#MAKEFLAGS="-j2"
|
||||
#-- Debugging flags
|
||||
DEBUG_CFLAGS="-g -fvar-tracking-assignments"
|
||||
DEBUG_CXXFLAGS="-g -fvar-tracking-assignments"
|
||||
#DEBUG_RUSTFLAGS="-C debuginfo=2"
|
||||
|
||||
#########################################################################
|
||||
# BUILD ENVIRONMENT
|
||||
#########################################################################
|
||||
#
|
||||
# Makepkg defaults: BUILDENV=(!distcc !color !ccache !check !sign)
|
||||
# A negated environment option will do the opposite of the comments below.
|
||||
#
|
||||
#-- distcc: Use the Distributed C/C++/ObjC compiler
|
||||
#-- color: Colorize output messages
|
||||
#-- ccache: Use ccache to cache compilation
|
||||
#-- check: Run the check() function if present in the PKGBUILD
|
||||
#-- sign: Generate PGP signature file
|
||||
#
|
||||
BUILDENV=(!distcc color !ccache !check !sign)
|
||||
#
|
||||
#-- If using DistCC, your MAKEFLAGS will also need modification. In addition,
|
||||
#-- specify a space-delimited list of hosts running in the DistCC cluster.
|
||||
#DISTCC_HOSTS=""
|
||||
#
|
||||
#-- Specify a directory for package building.
|
||||
#BUILDDIR=/tmp/makepkg
|
||||
|
||||
#########################################################################
|
||||
# GLOBAL PACKAGE OPTIONS
|
||||
# These are default values for the options=() settings
|
||||
#########################################################################
|
||||
#
|
||||
# Makepkg defaults: OPTIONS=(!strip docs libtool staticlibs emptydirs !zipman !purge !debug !lto)
|
||||
# A negated option will do the opposite of the comments below.
|
||||
#
|
||||
#-- strip: Strip symbols from binaries/libraries
|
||||
#-- docs: Save doc directories specified by DOC_DIRS
|
||||
#-- libtool: Leave libtool (.la) files in packages
|
||||
#-- staticlibs: Leave static library (.a) files in packages
|
||||
#-- emptydirs: Leave empty directories in packages
|
||||
#-- zipman: Compress manual (man and info) pages in MAN_DIRS with gzip
|
||||
#-- purge: Remove files specified by PURGE_TARGETS
|
||||
#-- debug: Add debugging flags as specified in DEBUG_* variables
|
||||
#-- lto: Add compile flags for building with link time optimization
|
||||
#
|
||||
OPTIONS=(strip docs !libtool !staticlibs emptydirs zipman purge !debug !lto)
|
||||
|
||||
#-- File integrity checks to use. Valid: md5, sha1, sha224, sha256, sha384, sha512, b2
|
||||
INTEGRITY_CHECK=(sha256)
|
||||
#-- Options to be used when stripping binaries. See `man strip' for details.
|
||||
STRIP_BINARIES="--strip-all"
|
||||
#-- Options to be used when stripping shared libraries. See `man strip' for details.
|
||||
STRIP_SHARED="--strip-unneeded"
|
||||
#-- Options to be used when stripping static libraries. See `man strip' for details.
|
||||
STRIP_STATIC="--strip-debug"
|
||||
#-- Manual (man and info) directories to compress (if zipman is specified)
|
||||
MAN_DIRS=({usr{,/local}{,/share},opt/*}/{man,info})
|
||||
#-- Doc directories to remove (if !docs is specified)
|
||||
DOC_DIRS=(usr/{,local/}{,share/}{doc,gtk-doc} opt/*/{doc,gtk-doc})
|
||||
#-- Files to be removed from all packages (if purge is specified)
|
||||
PURGE_TARGETS=(usr/{,share}/info/dir .packlist *.pod)
|
||||
#-- Directory to store source code in for debug packages
|
||||
DBGSRCDIR="/usr/src/debug"
|
||||
|
||||
#########################################################################
|
||||
# PACKAGE OUTPUT
|
||||
#########################################################################
|
||||
#
|
||||
# Default: put built package and cached source in build directory
|
||||
#
|
||||
#-- Destination: specify a fixed directory where all packages will be placed
|
||||
#PKGDEST=/home/packages
|
||||
#-- Source cache: specify a fixed directory where source files will be cached
|
||||
#SRCDEST=/home/sources
|
||||
#-- Source packages: specify a fixed directory where all src packages will be placed
|
||||
#SRCPKGDEST=/home/srcpackages
|
||||
#-- Log files: specify a fixed directory where all log files will be placed
|
||||
#LOGDEST=/home/makepkglogs
|
||||
#-- Packager: name/email of the person or organization building packages
|
||||
#PACKAGER="John Doe <john@doe.com>"
|
||||
#-- Specify a key to use for package signing
|
||||
#GPGKEY=""
|
||||
|
||||
#########################################################################
|
||||
# COMPRESSION DEFAULTS
|
||||
#########################################################################
|
||||
#
|
||||
COMPRESSGZ=(gzip -c -f -n)
|
||||
COMPRESSBZ2=(bzip2 -c -f)
|
||||
COMPRESSXZ=(xz -T0 -c -z -)
|
||||
COMPRESSZST=(zstd -c -z -q -)
|
||||
COMPRESSLRZ=(lrzip -q)
|
||||
COMPRESSLZO=(lzop -q)
|
||||
COMPRESSZ=(compress -c -f)
|
||||
COMPRESSLZ4=(lz4 -q)
|
||||
COMPRESSLZ=(lzip -c -f)
|
||||
|
||||
#########################################################################
|
||||
# EXTENSION DEFAULTS
|
||||
#########################################################################
|
||||
#
|
||||
PKGEXT='.pkg.tar.xz'
|
||||
SRCEXT='.src.tar.gz'
|
||||
|
||||
#########################################################################
|
||||
# OTHER
|
||||
#########################################################################
|
||||
#
|
||||
#-- Command used to run pacman as root, instead of trying sudo and su
|
||||
#PACMAN_AUTH=()
|
||||
|
||||
export CROOT="/usr/aarch64-linux-gnu"
|
||||
export ARCH="arm64"
|
||||
export CROSS_COMPILE="aarch64-linux-gnu-"
|
||||
export CC="aarch64-linux-gnu-gcc -I${CROOT}/usr/include -I/chroot/copy/usr/include -L${CROOT}/lib -L/chroot/copy/usr/lib"
|
||||
export CXX="aarch64-linux-gnu-g++ -I${CROOT}/usr/include -I/chroot/copy/usr/include -L${CROOT}/lib -L/chroot/copy/usr/lib"
|
||||
export CFLAGS="$CFLAGS -I${CROOT}/usr/include -I/chroot/copy/usr/include"
|
||||
export CXXFLAGS="$CXXFLAGS -I${CROOT}/usr/include -I/chroot/copy/usr/include"
|
||||
export LDFLAGS="$LDFLAGS,-L${CROOT}/lib,-L/chroot/copy/usr/lib,-rpath-link,${CROOT}/lib,-rpath-link,/chroot/copy/usr/lib"
|
91
src/pacman.conf
Normal file
91
src/pacman.conf
Normal file
|
@ -0,0 +1,91 @@
|
|||
#
|
||||
# /etc/pacman.conf
|
||||
#
|
||||
# See the pacman.conf(5) manpage for option and repository directives
|
||||
|
||||
#
|
||||
# GENERAL OPTIONS
|
||||
#
|
||||
[options]
|
||||
# The following paths are commented out with their default values listed.
|
||||
# If you wish to use different paths, uncomment and update the paths.
|
||||
#RootDir = /
|
||||
#DBPath = /var/lib/pacman/
|
||||
#CacheDir = /var/cache/pacman/pkg/
|
||||
#LogFile = /var/log/pacman.log
|
||||
#GPGDir = /etc/pacman.d/gnupg/
|
||||
#HookDir = /etc/pacman.d/hooks/
|
||||
HoldPkg = pacman glibc
|
||||
#XferCommand = /usr/bin/curl -L -C - -f -o %o %u
|
||||
#XferCommand = /usr/bin/wget --passive-ftp -c -O %o %u
|
||||
#CleanMethod = KeepInstalled
|
||||
Architecture = aarch64
|
||||
|
||||
# Pacman won't upgrade packages listed in IgnorePkg and members of IgnoreGroup
|
||||
#IgnorePkg =
|
||||
#IgnoreGroup =
|
||||
|
||||
#NoUpgrade =
|
||||
#NoExtract =
|
||||
|
||||
# Misc options
|
||||
#UseSyslog
|
||||
#Color
|
||||
#NoProgressBar
|
||||
#CheckSpace
|
||||
#VerbosePkgLists
|
||||
ParallelDownloads = 8
|
||||
|
||||
# By default, pacman accepts packages signed by keys that its local keyring
|
||||
# trusts (see pacman-key and its man page), as well as unsigned packages.
|
||||
SigLevel = Never
|
||||
LocalFileSigLevel = Never
|
||||
#RemoteFileSigLevel = Never
|
||||
|
||||
# NOTE: You must run `pacman-key --init` before first using pacman; the local
|
||||
# keyring can then be populated with the keys of all official Arch Linux ARM
|
||||
# packagers with `pacman-key --populate archlinuxarm`.
|
||||
|
||||
#
|
||||
# REPOSITORIES
|
||||
# - can be defined here or included from another file
|
||||
# - pacman will search repositories in the order defined here
|
||||
# - local/custom mirrors can be added here or in separate files
|
||||
# - repositories listed first will take precedence when packages
|
||||
# have identical names, regardless of version number
|
||||
# - URLs will have $repo replaced by the name of the current repo
|
||||
# - URLs will have $arch replaced by the name of the architecture
|
||||
#
|
||||
# Repository entries are of the format:
|
||||
# [repo-name]
|
||||
# Server = ServerName
|
||||
# Include = IncludePath
|
||||
#
|
||||
# The header [repo-name] is crucial - it must be present and
|
||||
# uncommented to enable the repo.
|
||||
#
|
||||
|
||||
# The testing repositories are disabled by default. To enable, uncomment the
|
||||
# repo name header and Include lines. You can add preferred servers immediately
|
||||
# after the header, and they will be used before the default mirrors.
|
||||
|
||||
[core]
|
||||
Include = /etc/pacman.d/aarch64_mirrorlist
|
||||
|
||||
[extra]
|
||||
Include = /etc/pacman.d/aarch64_mirrorlist
|
||||
|
||||
[community]
|
||||
Include = /etc/pacman.d/aarch64_mirrorlist
|
||||
|
||||
[alarm]
|
||||
Include = /etc/pacman.d/aarch64_mirrorlist
|
||||
|
||||
[aur]
|
||||
Include = /etc/pacman.d/aarch64_mirrorlist
|
||||
|
||||
# An example of a custom package repository. See the pacman manpage for
|
||||
# tips on creating your own repositories.
|
||||
#[custom]
|
||||
#SigLevel = Never
|
||||
#Server = file:///home/custompkgs
|
31
src/update-pacman-files.sh
Executable file
31
src/update-pacman-files.sh
Executable file
|
@ -0,0 +1,31 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
wget https://raw.githubusercontent.com/archlinuxarm/PKGBUILDs/master/core/pacman/makepkg.conf -O makepkg.conf
|
||||
sed -i "s/@CARCH@/aarch64/g" makepkg.conf
|
||||
sed -i "s/@CHOST@/aarch64-unknown-linux-gnu/g" makepkg.conf
|
||||
sed -i "s/@CARCHFLAGS@/-march=armv8-a /g" makepkg.conf
|
||||
sed -i "s/xz /xz -T0 /g" makepkg.conf
|
||||
sed -i "s/ check / !check /g" makepkg.conf
|
||||
chroot="/chroot/copy"
|
||||
include="-I\${CROOT}/usr/include -I$chroot/usr/include"
|
||||
lib_croot="\${CROOT}/lib"
|
||||
lib_chroot="$chroot/usr/lib"
|
||||
cat >>makepkg.conf <<EOF
|
||||
|
||||
export CROOT="/usr/aarch64-linux-gnu"
|
||||
export ARCH="arm64"
|
||||
export CROSS_COMPILE="aarch64-linux-gnu-"
|
||||
export CC="aarch64-linux-gnu-gcc $include -L$lib_croot -L$lib_chroot"
|
||||
export CXX="aarch64-linux-gnu-g++ $include -L$lib_croot -L$lib_chroot"
|
||||
export CFLAGS="\$CFLAGS $include"
|
||||
export CXXFLAGS="\$CXXFLAGS $include"
|
||||
export LDFLAGS="\$LDFLAGS,-L$lib_croot,-L$lib_chroot,-rpath-link,$lib_croot,-rpath-link,$lib_chroot"
|
||||
EOF
|
||||
# TODO: Set PACKAGER
|
||||
wget https://raw.githubusercontent.com/archlinuxarm/PKGBUILDs/master/core/pacman/pacman.conf -O pacman.conf
|
||||
sed -i "s/@CARCH@/aarch64/g" pacman.conf
|
||||
sed -i "s/#ParallelDownloads.*/ParallelDownloads = 8/g" pacman.conf
|
||||
sed -i "s/SigLevel.*/SigLevel = Never/g" pacman.conf
|
||||
sed -i "s/^CheckSpace/#CheckSpace/g" pacman.conf
|
||||
sed -i "s|/mirrorlist|/aarch64_mirrorlist|g" pacman.conf
|
1
version.txt
Normal file
1
version.txt
Normal file
|
@ -0,0 +1 @@
|
|||
dev
|
53
wrapper.py
Normal file
53
wrapper.py
Normal file
|
@ -0,0 +1,53 @@
|
|||
import atexit
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import appdirs
|
||||
|
||||
if os.getenv('KUPFERBOOTSTRAP_DOCKER') == '1':
|
||||
from main import cli
|
||||
cli(prog_name='kupferbootstrap')
|
||||
else:
|
||||
script_path = os.path.dirname(os.path.abspath(__file__))
|
||||
with open(os.path.join(script_path, 'version.txt')) as version_file:
|
||||
version = version_file.read().replace('\n', '')
|
||||
tag = f'gitlab.com/kupfer/kupferbootstrap:{version}'
|
||||
if version == 'dev':
|
||||
result = subprocess.run([
|
||||
'docker',
|
||||
'build',
|
||||
'.',
|
||||
'-t', tag
|
||||
], cwd=script_path)
|
||||
if result.returncode != 0:
|
||||
print(f'Failed to build kupferbootstrap docker image')
|
||||
exit(1)
|
||||
else:
|
||||
# Check if the image for the version already exists
|
||||
result = subprocess.run(['docker', 'images', '-q', tag],
|
||||
capture_output=True)
|
||||
if result.stdout == b'':
|
||||
print(
|
||||
f'Pulling kupferbootstrap docker image version \'{version}\'')
|
||||
subprocess.run(['docker', 'pull', tag])
|
||||
|
||||
def at_exit():
|
||||
subprocess.run(['docker', 'kill', 'kupferbootstrap'],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,)
|
||||
atexit.register(at_exit)
|
||||
|
||||
# TODO: Remove the mount of /usr/share/i18n/locales. It's a trick so we don't need to generate the locales in the chroot.
|
||||
# Something like a prebuilt docker image as base or copying the files from it would be good.
|
||||
subprocess.run(['docker',
|
||||
'run',
|
||||
'--name', 'kupferbootstrap',
|
||||
'--rm',
|
||||
'--privileged',
|
||||
'-v', f'{os.getcwd()}:/src:z',
|
||||
'-v', f'{os.path.join(appdirs.user_cache_dir("kupfer"),"chroot")}:/chroot:z',
|
||||
'-v', f'{os.path.join(appdirs.user_cache_dir("kupfer"),"pacman")}:/var/cache/pacman/pkg:z',
|
||||
'-v', '/usr/share/i18n/locales:/usr/share/i18n/locales:ro'] +
|
||||
[tag,
|
||||
'kupferbootstrap']
|
||||
+ sys.argv[1:])
|
Loading…
Add table
Add a link
Reference in a new issue