commit 2a0ce7c5c2535644e99d61bdeddafdb6e4aa24cd Author: Jan Staněk Date: Tue Oct 3 14:04:54 2023 +0200 initial package import diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1141526 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/undici-5.26.4-stripped.tar.gz +/undici-5.26.4-nm-prod.tgz +/undici-5.26.4-nm-dev.tgz +/undici-5.26.4-bundled-licenses.txt diff --git a/0001-feat-allow-customization-of-build-environment.patch b/0001-feat-allow-customization-of-build-environment.patch new file mode 100644 index 0000000..63e013e --- /dev/null +++ b/0001-feat-allow-customization-of-build-environment.patch @@ -0,0 +1,123 @@ +From 9dfb61b331b09552250cea7268fc632335816661 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jan=20Stan=C4=9Bk?= +Date: Thu, 2 Nov 2023 15:09:10 +0100 +Subject: [PATCH] feat: allow customization of build environment +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows for the WASM artifacts to be built elsewhere than only in +the alpine-based node container. + +Signed-off-by: Jan Staněk +--- + build/wasm.js | 72 +++++++++++++++++++++------------------------------ + 1 file changed, 29 insertions(+), 43 deletions(-) + +diff --git a/build/wasm.js b/build/wasm.js +index fd90ac26..2b63f3c7 100644 +--- a/build/wasm.js ++++ b/build/wasm.js +@@ -9,6 +9,18 @@ const WASM_SRC = resolve(__dirname, '../deps/llhttp') + const WASM_OUT = resolve(__dirname, '../lib/llhttp') + const DOCKERFILE = resolve(__dirname, './Dockerfile') + ++// These are defined by build environment ++const WASM_CC = process.env.WASM_CC || 'clang' ++let WASM_CFLAGS = process.env.WASM_CFLAGS || '--sysroot=/usr/share/wasi-sysroot -target wasm32-unknown-wasi' ++let WASM_LDFLAGS = process.env.WASM_LDFLAGS || '' ++const WASM_LDLIBS = process.env.WASM_LDLIBS || '' ++ ++// These are relevant for undici and should not be overridden ++WASM_CFLAGS += ' -Ofast -fno-exceptions -fvisibility=hidden -mexec-model=reactor' ++WASM_LDFLAGS += ' -Wl,-error-limit=0 -Wl,-O3 -Wl,--lto-O3 -Wl,--strip-all' ++WASM_LDFLAGS += ' -Wl,--allow-undefined -Wl,--export-dynamic -Wl,--export-table' ++WASM_LDFLAGS += ' -Wl,--export=malloc -Wl,--export=free -Wl,--no-entry' ++ + let platform = process.env.WASM_PLATFORM + if (!platform && process.argv[2]) { + platform = execSync('docker info -f "{{.OSType}}/{{.Architecture}}"').toString().trim() +@@ -35,35 +47,25 @@ if (process.argv[2] === '--docker') { + process.exit(0) + } + +-// Gather information about the tools used for the build +-const buildInfo = execSync('apk info -v').toString() +-if (!buildInfo.includes('wasi-sdk')) { +- console.log('Failed to generate build environment information') +- process.exit(-1) ++const hasApk = (function () { ++ try { execSync('command -v apk'); return true } catch (error) { return false } ++})() ++if (hasApk) { ++ // Gather information about the tools used for the build ++ const buildInfo = execSync('apk info -v').toString() ++ if (!buildInfo.includes('wasi-sdk')) { ++ console.log('Failed to generate build environment information') ++ process.exit(-1) ++ } ++ writeFileSync(join(WASM_OUT, 'wasm_build_env.txt'), buildInfo) + } +-writeFileSync(join(WASM_OUT, 'wasm_build_env.txt'), buildInfo) + + // Build wasm binary +-execSync(`clang \ +- --sysroot=/usr/share/wasi-sysroot \ +- -target wasm32-unknown-wasi \ +- -Ofast \ +- -fno-exceptions \ +- -fvisibility=hidden \ +- -mexec-model=reactor \ +- -Wl,-error-limit=0 \ +- -Wl,-O3 \ +- -Wl,--lto-O3 \ +- -Wl,--strip-all \ +- -Wl,--allow-undefined \ +- -Wl,--export-dynamic \ +- -Wl,--export-table \ +- -Wl,--export=malloc \ +- -Wl,--export=free \ +- -Wl,--no-entry \ ++execSync(`${WASM_CC} ${WASM_CFLAGS} ${WASM_LDFLAGS} \ + ${join(WASM_SRC, 'src')}/*.c \ + -I${join(WASM_SRC, 'include')} \ +- -o ${join(WASM_OUT, 'llhttp.wasm')}`, { stdio: 'inherit' }) ++ -o ${join(WASM_OUT, 'llhttp.wasm')} \ ++ ${WASM_LDLIBS}`, { stdio: 'inherit' }) + + const base64Wasm = readFileSync(join(WASM_OUT, 'llhttp.wasm')).toString('base64') + writeFileSync( +@@ -72,27 +74,11 @@ writeFileSync( + ) + + // Build wasm simd binary +-execSync(`clang \ +- --sysroot=/usr/share/wasi-sysroot \ +- -target wasm32-unknown-wasi \ +- -msimd128 \ +- -Ofast \ +- -fno-exceptions \ +- -fvisibility=hidden \ +- -mexec-model=reactor \ +- -Wl,-error-limit=0 \ +- -Wl,-O3 \ +- -Wl,--lto-O3 \ +- -Wl,--strip-all \ +- -Wl,--allow-undefined \ +- -Wl,--export-dynamic \ +- -Wl,--export-table \ +- -Wl,--export=malloc \ +- -Wl,--export=free \ +- -Wl,--no-entry \ ++execSync(`${WASM_CC} ${WASM_CFLAGS} -msimd128 ${WASM_LDFLAGS} \ + ${join(WASM_SRC, 'src')}/*.c \ + -I${join(WASM_SRC, 'include')} \ +- -o ${join(WASM_OUT, 'llhttp_simd.wasm')}`, { stdio: 'inherit' }) ++ -o ${join(WASM_OUT, 'llhttp_simd.wasm')} \ ++ ${WASM_LDLIBS}`, { stdio: 'inherit' }) + + const base64WasmSimd = readFileSync(join(WASM_OUT, 'llhttp_simd.wasm')).toString('base64') + writeFileSync( +-- +2.41.0 + diff --git a/nodejs-undici.spec b/nodejs-undici.spec new file mode 100644 index 0000000..7fdfc3b --- /dev/null +++ b/nodejs-undici.spec @@ -0,0 +1,87 @@ +%global npm_name undici + +%global llhttp_version_major 8 +%global llhttp_version_minor 1 +%global llhttp_version_patch 0 + +Name: nodejs-%{npm_name} +Summary: An HTTP/1.1 client, written from scratch for Node.js +Version: 5.26.4 +Release: %autorelease + +License: MIT +URL: https://undici.nodejs.org +# See Source4 on how these archives were generated +Source0: %{npm_name}-%{version}-stripped.tar.gz +Source1: %{npm_name}-%{version}-nm-prod.tgz +Source2: %{npm_name}-%{version}-nm-dev.tgz +Source3: %{npm_name}-%{version}-bundled-licenses.txt +Source4: %{npm_name}-sources.sh + +Patch: 0001-feat-allow-customization-of-build-environment.patch + +# Binary artifacts in this package are aimed at the wasm32-wasi "architecture". +%global _binaries_in_noarch_packages_terminate_build 0 +BuildArch: noarch +ExclusiveArch: %{nodejs_arches} noarch + +BuildRequires: clang lld wasi-libc-devel +BuildRequires: nodejs-devel npm +# for autosetup -S git_am +BuildRequires: git-core + +# This package bundles it's own copy of llhttp +Provides: bundled(llhttp) = %{llhttp_version_major}.%{llhttp_version_minor}.%{llhttp_version_patch} + +%description +An HTTP/1.1 client, written from scratch for Node.js. + +%prep +%autosetup -n %{npm_name}-%{version} -S git_am +cp -p %{S:3} . + +# Check for bundled llhttp version +if ! grep -q 'LLHTTP_VERSION_MAJOR %{llhttp_version_major}' deps/llhttp/include/llhttp.h \ +|| ! grep -q 'LLHTTP_VERSION_MINOR %{llhttp_version_minor}' deps/llhttp/include/llhttp.h \ +|| ! grep -q 'LLHTTP_VERSION_PATCH %{llhttp_version_patch}' deps/llhttp/include/llhttp.h +then + echo 'llhttp version mismatch' >&2; exit 2 +fi + +# Link node_modules +mkdir -p node_modules/.bin/ +tar -xzf %{S:1} +ln -srt node_modules/ node_modules_prod/* +ln -srt node_modules/.bin/ node_modules_prod/.bin + +%build +export WASM_CC=clang +export WASM_CFLAGS='--target=wasm32-wasi --sysroot=/usr/wasm32-wasi' +export WASM_LDFLAGS='-nodefaultlibs' +export WASM_LDLIBS='-lc' + +# `npm run build` uses docker; invoke the build script directly +%{__nodejs} build/wasm.js +npm --offline pack + +%install +mkdir -p %{buildroot}%{nodejs_sitelib}/%{npm_name} +tar -C %{buildroot}%{nodejs_sitelib}/%{npm_name} -xzf %{npm_name}-%{version}.tgz --strip-components=1 +cp -prt %{buildroot}%{nodejs_sitelib}/%{npm_name} node_modules_prod node_modules + +%check +%{__nodejs} -e 'require("./")' + +tar -xzf %{S:2} +ln -fsrt node_modules/ node_modules_dev/* +ln -fsrt node_modules/.bin/ node_modules_dev/.bin/* +# Depends on the environment/OpenSSL version, etc. Informational only. +npm --offline run test || : + +%files +%doc README.md +%license LICENSE %{npm_name}-%{version}-bundled-licenses.txt +%{nodejs_sitelib}/%{npm_name} + +%changelog +%autochangelog diff --git a/sources b/sources new file mode 100644 index 0000000..c51268c --- /dev/null +++ b/sources @@ -0,0 +1,4 @@ +SHA512 (undici-5.26.4-stripped.tar.gz) = f50c3c731dc7cd8af9646fd7abd13e452ba258f66dc53be07feba827475828a16a7641934ae283cc9ca11bc8d0e348c0bfcb8ecccda2bb7afb6bdb01f5ddde63 +SHA512 (undici-5.26.4-nm-prod.tgz) = 2b6d0a2728289a91331314d7c40515a784d5d22dcc538fcbf33ffa09c826afd07c5605dff50d54d09b8010b9acdc1b00637e84461c274046ffbcb77bcbeda9a6 +SHA512 (undici-5.26.4-nm-dev.tgz) = 67bcd32c485c0385a4e7d9b1c703a23367c05438c6f6c34ac986056e4110b92d107fc7b0eec6d2dfb5036c7120d769fb2694cfd9dcccb3403ed639b9c993a9af +SHA512 (undici-5.26.4-bundled-licenses.txt) = 3e591adb16e09b1c6fb75eb97a6ac51cd06e0aeae2bd5950a15902346e2c9626cb50203bfd0e15c7e8c98af8f24b81c1ce6617c359e7c0e7d0a6366457c844ba diff --git a/undici-sources.sh b/undici-sources.sh new file mode 100755 index 0000000..c46e62a --- /dev/null +++ b/undici-sources.sh @@ -0,0 +1,104 @@ +#!/bin/sh +# deps: curl rpm npm nodejs-packaging-bundler +set -e + +UNDICI_VERSION="$(rpm --specfile nodejs-undici.spec --qf '%{VERSION}\n')"; readonly UNDICI_VERSION + +RPKG=fedpkg +RELEASE="" +OFFLINE=false + +usage() { + echo "${0##*/} - download and re-package upstream undici sources." + echo + echo Options: + printf '\t%s\n' '-h, --help: Show this info and exit.' + printf '\t%s\n' '-r, --rpkg=: Use for dist-git interaction [default: fedpkg].' + printf '\t%s\n' '--release=: Tell to assume working on [default: detected from current branch].' + printf '\t%s\n' '-n, --offline: Do not upload prepared sources to lookaside cache.' +} + +# Construct upstream archive URL +github_archive_url() { + readonly gh_version="${1-${UNDICI_VERSION}}" + printf 'https://github.com/nodejs/undici/archive/v%s/undici-v%s.tar.gz' "${gh_version}" "${gh_version}" +} + +# Fetch upstream release +# stdout: name of the original/upstream archive +fetch() { + readonly fetch_version="${1-${UNDICI_VERSION}}" + # npm archive does not contain everything (i.e. build scripts). + # Fetch the github archive instead. + fetch_url="$(github_archive_url "${fetch_version}")"; readonly fetch_url + curl --location --remote-name "${fetch_url}" + printf '%s\n' "${fetch_url##*/}" +} + +# Delete any file where a WASM blob is detected +# stdout: relative paths to deleted files +nuke_wasm() { + find "${1-.}" -type f \ + -exec grep -q --text -Pe '\x{0}asm|AGFzb' '{}' \; \ + -print \ + -delete +} + +# Remove husky (git hook manager) from prepare scripts +remove_husky() { + cd "${1-undici-v${UNDICI_VERSION}/}" >/dev/null + if grep -q 'husky install' package.json; then + npm pkg delete scripts.prepare + fi + cd - >/dev/null +} + +# Package the sources into stripped archive +repackage() { + readonly repackage_version="${1-${UNDICI_VERSION}}" + readonly repackage_rootdir="${2-undici-v${repackage_version}/}" + + tar -czf "undici-${repackage_version}-stripped.tar.gz" "${repackage_rootdir}" + rm -rf "${repackage_rootdir}" + echo "undici-${repackage_version}-stripped.tar.gz" +} + +# shellcheck disable=SC2046 +set -- $(getopt -n "${0##*/}" --unquoted -o hr:n -l help,rpkg:,release:,offline -- "$@") +while test -n "$1"; do + case "$1" in + -h|--help) usage >&2 && exit;; + -r|--rpkg) RPKG="$2"; shift 2;; + -n|--offline) OFFLINE=true; shift 1;; + --release) RELEASE="$2"; shift 2;; + --) break;; + *) printf 'Unknown argument: %s\n' "$1" >&2; exit 2;; + esac +done + +printf '=== %s ===\n' 'Fetching and unpacking upstream tarball' >&2 +original="$(fetch "${UNDICI_VERSION}")"; readonly original +tar -xzf "${original}" +rootdir="$(ls -d "undici-${UNDICI_VERSION}/")"; readonly rootdir +rm -rf "${original}" + +printf '=== %s ===\n' 'Removing following WASM blobs' >&2 +nuke_wasm "${rootdir}" >&2 + +printf '=== %s ===\n' 'Cleaning package scripts' >&2 +remove_husky "${rootdir}" + +printf '=== %s ===\n' 'Re-packaging clean archive' >&2 +repackage "${UNDICI_VERSION}" "${rootdir}" + +printf '=== %s ===\n' 'Bundling dependencies' >&2 +nodejs-packaging-bundler undici "${UNDICI_VERSION}" "undici-${UNDICI_VERSION}-stripped.tar.gz" +install -p -m0644 -t "${PWD}" "$(rpm -E '%{_sourcedir}')"/undici-"${UNDICI_VERSION}"-* + +printf '=== %s ===\n' 'Updating dist-git sources' >&2 +# shellcheck disable=SC2086,SC2046 +${RPKG} $(test -n "${RELEASE}" && echo --release="${RELEASE}") new-sources $("$OFFLINE" && echo --offline) \ + "undici-${UNDICI_VERSION}-stripped.tar.gz" \ + "undici-${UNDICI_VERSION}-nm-prod.tgz" \ + "undici-${UNDICI_VERSION}-nm-dev.tgz" \ + "undici-${UNDICI_VERSION}-bundled-licenses.txt"