Validate all nine RIDs and NuGet with persistent Woodpecker caches
ci/woodpecker/push/woodpecker Pipeline failed
ci/woodpecker/push/woodpecker Pipeline failed
This commit is contained in:
1 parent
1f23aff5e2
commit
6e5cd77713
4 files changed
+108
-16
No files matched your search
+1
-1
@@ -16,7 +16,7 @@ steps:
|
||||
- git -C source remote add origin https://git.oeo.one/greepar/StaticLink.Avalonia.git
|
||||
- git -C source fetch --depth=1 origin "$CI_COMMIT_SHA"
|
||||
- git -C source checkout --detach FETCH_HEAD
|
||||
- name: environment-and-linux-x64
|
||||
- name: nine-platform-build-link-and-pack
|
||||
image: bash
|
||||
commands:
|
||||
- bash source/scripts/woodpecker-cross-test.sh
|
||||
@@ -173,7 +173,10 @@ def execute(config, tool, incoming):
|
||||
inputs.append(flag)
|
||||
if not output:
|
||||
raise SystemExit("Darwin libtool adapter needs -o")
|
||||
command = [config["zig"], "ar", "--format=darwin", "rcs", output, *inputs]
|
||||
libtool = shutil.which('llvm-libtool-darwin') or shutil.which('llvm-libtool-darwin-16')
|
||||
if not libtool:
|
||||
raise SystemExit('The pinned image must provide llvm-libtool-darwin to flatten archive dependencies')
|
||||
command = [libtool, '-static', '-o', output, *inputs]
|
||||
if tool in ('ar', 'libtool'):
|
||||
# Never leave a truncated archive behind when disk/network/job failures
|
||||
# interrupt archiving. GN response files contain a complete member list.
|
||||
|
||||
@@ -19,7 +19,7 @@ if [ ! -d "$CACHE_ROOT/source/.git" ]; then
|
||||
git clone --no-hardlinks "$SCRIPT_ROOT" "$CACHE_ROOT/source"
|
||||
fi
|
||||
git -C "$CACHE_ROOT/source" fetch --depth=1 "$SCRIPT_ROOT" HEAD
|
||||
git -C "$CACHE_ROOT/source" checkout --detach FETCH_HEAD
|
||||
git -C "$CACHE_ROOT/source" checkout --force --detach FETCH_HEAD
|
||||
cd "$CACHE_ROOT/source"
|
||||
cp build/linux-toolchain/sources.lock.json build/linux-toolchain/release.lock.json
|
||||
mkdir -p "$RESULTS/environment"
|
||||
@@ -38,7 +38,7 @@ if [ "$AVAILABLE_KB" -lt 41943040 ]; then
|
||||
fi
|
||||
echo "Persistent test results: $RESULTS"
|
||||
exec > >(tee "$RESULTS/build.log") 2>&1
|
||||
trap 'result=$?; trap - EXIT; if [ "$result" -eq 0 ] && [ -d External/NativeStatic/linux-x64/native ]; then mkdir -p "$RESULTS/native"; cp -a External/NativeStatic/linux-x64/native/. "$RESULTS/native/"; fi; printf "%s\n" "$result" > "$RESULTS/exit-code"; echo "Results retained at $RESULTS"; exit "$result"' EXIT
|
||||
trap 'result=$?; trap - EXIT; printf "%s\n" "$result" > "$RESULTS/exit-code"; echo "Results retained at $RESULTS"; exit "$result"' EXIT
|
||||
git rev-parse HEAD > "$RESULTS/commit"
|
||||
printf '%s\n' "$TOOLCHAIN_IMAGE" > "$RESULTS/toolchain-image"
|
||||
docker pull "$TOOLCHAIN_IMAGE"
|
||||
@@ -46,24 +46,16 @@ docker run --rm --user "$(id -u):$(id -g)" \
|
||||
-e HOME=/tmp -e DOTNET_CLI_HOME=/tmp -e ZIG_GLOBAL_CACHE_DIR=/tmp/zig-cache \
|
||||
-v "$RESULTS/environment:/validation" --entrypoint python3 \
|
||||
"$TOOLCHAIN_IMAGE" /opt/staticlink/validate-toolchain.py \
|
||||
--output /validation --rids '["linux-x64"]'
|
||||
--output /validation --rids '[]'
|
||||
mkdir -p External/NativeStatic/.work/home
|
||||
docker run --rm --user "$(id -u):$(id -g)" \
|
||||
-e HOME=/src/External/NativeStatic/.work/home -e CROSS_RID \
|
||||
-e CCACHE_DIR=/src/External/NativeStatic/.work/ccache -e CCACHE_MAXSIZE=1G \
|
||||
-e ZIG_GLOBAL_CACHE_DIR=/src/External/NativeStatic/.work/zig-global \
|
||||
-v "$PWD:/src" -w /src --entrypoint bash "$TOOLCHAIN_IMAGE" -c '
|
||||
-v "$PWD:/src" -v "$RESULTS:/results" -w /src --entrypoint bash "$TOOLCHAIN_IMAGE" -c '
|
||||
set -euo pipefail
|
||||
export SOURCE_LOCK=/src/build/linux-toolchain/release.lock.json
|
||||
source scripts/prepare-cross-sources.sh
|
||||
BUILD_JOBS="$(nproc)"
|
||||
echo "Full CPU parallelism: $BUILD_JOBS compilation jobs"
|
||||
python3 build/linux-toolchain/build-cross.py \
|
||||
--target "$CROSS_RID" --sources-manifest "$WORK_DIR/cross-sources.json" \
|
||||
--work /src/External/NativeStatic/.work/toolchains \
|
||||
--output "/src/External/NativeStatic/zig-cross/$SKIASHARP_VERSION/$CROSS_RID" --jobs "$BUILD_JOBS"
|
||||
python3 build/linux-toolchain/package-zig.py \
|
||||
--rid "$CROSS_RID" \
|
||||
--input "/src/External/NativeStatic/zig-cross/$SKIASHARP_VERSION/$CROSS_RID" \
|
||||
--output "/src/External/NativeStatic/$CROSS_RID/native"
|
||||
python3 scripts/woodpecker-nine-platforms.py \
|
||||
--sources-manifest "$WORK_DIR/cross-sources.json" --results /results
|
||||
'
|
||||
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import zipfile
|
||||
|
||||
RIDS = (
|
||||
'osx-arm64', 'osx-x64', 'linux-x64', 'linux-arm64',
|
||||
'linux-musl-x64', 'linux-musl-arm64', 'win-x64', 'win-x86', 'win-arm64',
|
||||
)
|
||||
|
||||
|
||||
def run(command, logfile):
|
||||
print('+', ' '.join(map(str, command)), flush=True)
|
||||
with logfile.open('a') as output:
|
||||
process = subprocess.Popen(list(map(str, command)), stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT, text=True)
|
||||
for line in process.stdout:
|
||||
print(line, end='', flush=True)
|
||||
output.write(line)
|
||||
return process.wait()
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--sources-manifest', type=Path, required=True)
|
||||
parser.add_argument('--results', type=Path, required=True)
|
||||
args = parser.parse_args()
|
||||
args.results.mkdir(parents=True, exist_ok=True)
|
||||
lock = json.loads(Path('build/linux-toolchain/release.lock.json').read_text())
|
||||
jobs = subprocess.check_output(['nproc'], text=True).strip()
|
||||
report = {'sources': lock, 'jobs': int(jobs), 'targets': {}, 'package': 'not-built',
|
||||
'runtime_tests': 'not performed; cross compilation and executable linking only'}
|
||||
descriptor = args.results / 'nine-platform-results.json'
|
||||
|
||||
def save():
|
||||
descriptor.write_text(json.dumps(report, indent=2) + '\n')
|
||||
|
||||
save()
|
||||
for rid in RIDS:
|
||||
print(f'=== {rid}: compile and link with {jobs} jobs ===', flush=True)
|
||||
started = time.monotonic()
|
||||
logfile = args.results / (rid + '.log')
|
||||
libraries = Path('External/NativeStatic/zig-cross') / lock['skiasharp_version'] / rid
|
||||
native = Path('External/NativeStatic') / rid / 'native'
|
||||
command = [sys.executable, 'build/linux-toolchain/build-cross.py',
|
||||
'--target', rid, '--sources-manifest', args.sources_manifest,
|
||||
'--work', 'External/NativeStatic/.work/toolchains',
|
||||
'--output', libraries, '--jobs', jobs]
|
||||
status = run(command, logfile)
|
||||
if status == 0:
|
||||
status = run([sys.executable, 'build/linux-toolchain/package-zig.py',
|
||||
'--rid', rid, '--input', libraries, '--output', native], logfile)
|
||||
if status == 0:
|
||||
shutil.copytree(native, args.results / rid / 'native', dirs_exist_ok=True)
|
||||
shutil.copytree(libraries / 'link-tests', args.results / rid / 'link-tests',
|
||||
dirs_exist_ok=True)
|
||||
report['targets'][rid] = {'exit_code': status, 'passed': status == 0,
|
||||
'elapsed_seconds': round(time.monotonic() - started, 1)}
|
||||
save()
|
||||
print(f'=== {rid}: {"PASS" if status == 0 else "FAIL"} ===', flush=True)
|
||||
|
||||
failed = [rid for rid in RIDS if not report['targets'][rid]['passed']]
|
||||
if failed:
|
||||
print('Failed platforms: ' + ', '.join(failed), flush=True)
|
||||
return 1
|
||||
os.environ['SOURCE_LOCK_JSON'] = json.dumps(lock)
|
||||
os.environ['PACKAGE_VERSION'] = lock['skiasharp_version'] + '-' + lock['angle_branch'] + '.2'
|
||||
logfile = args.results / 'pack.log'
|
||||
status = run([sys.executable, 'scripts/apply-release-version.py'], logfile)
|
||||
if status == 0:
|
||||
status = run(['dotnet', 'pack', 'NuGet/StaticGraphics/StaticLink.Avalonia.csproj',
|
||||
'-c', 'Release', '-o', args.results / 'nuget'], logfile)
|
||||
if status == 0:
|
||||
package = next((args.results / 'nuget').glob('*.nupkg'))
|
||||
with zipfile.ZipFile(package) as archive:
|
||||
names = set(archive.namelist())
|
||||
required = {'buildTransitive/StaticLink.Avalonia.props',
|
||||
'buildTransitive/StaticLink.Avalonia.targets'}
|
||||
required.update('static/' + rid + '/native/' +
|
||||
('skia.lib' if rid.startswith('win-') else 'libskia.a') for rid in RIDS)
|
||||
if not required.issubset(names) or any('\\' in name for name in names):
|
||||
print('NuGet package is missing target archives or has non-portable paths', flush=True)
|
||||
status = 1
|
||||
report['package'] = 'passed' if status == 0 else 'failed'
|
||||
save()
|
||||
print('Nine-platform build/link/package: ' + report['package'], flush=True)
|
||||
return status
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
raise SystemExit(main())
|
||||
Reference in new issue
Block a user