From b055980103a81dddba3dcb322f0b09b7d88af4b3 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Fri, 3 Jan 2025 10:20:33 -0500 Subject: [PATCH] JS-Ify Dependency Installation --- .gitea/workflows/build.yml | 6 +- dependencies/LIEF/src | 2 +- scripts/build.mjs | 24 ++--- scripts/fix-appimage-for-docker.sh | 1 - scripts/install-dependencies.mjs | 150 +++++++++++++++++++++++++++++ scripts/install-dependencies.sh | 109 --------------------- scripts/lib/options.mjs | 8 +- scripts/lib/util.mjs | 36 +++++++ 8 files changed, 202 insertions(+), 134 deletions(-) create mode 100755 scripts/install-dependencies.mjs delete mode 100755 scripts/install-dependencies.sh diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 34998a54f..c7b9a4b53 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -28,7 +28,7 @@ jobs: submodules: true # Dependencies - name: Install Dependencies - run: ./scripts/install-dependencies.sh build ${{ matrix.arch }} + run: ./scripts/install-dependencies.mjs build ${{ matrix.arch }} # Build - name: Build run: ./scripts/build.mjs appimage ${{ matrix.arch }} @@ -61,7 +61,7 @@ jobs: submodules: false # Dependencies - name: Install Dependencies - run: ./scripts/install-dependencies.sh test ${{ matrix.arch }} + run: ./scripts/install-dependencies.mjs test ${{ matrix.arch }} # Download Artifact - name: Download Artifact uses: actions/download-artifact@v3 @@ -84,7 +84,7 @@ jobs: submodules: false # Dependencies - name: Install Dependencies - run: ./scripts/install-dependencies.sh example_mods amd64 + run: ./scripts/install-dependencies.mjs sdk amd64 # SDK - name: Download SDK uses: actions/download-artifact@v3 diff --git a/dependencies/LIEF/src b/dependencies/LIEF/src index 441bb4620..d4900dab6 160000 --- a/dependencies/LIEF/src +++ b/dependencies/LIEF/src @@ -1 +1 @@ -Subproject commit 441bb4620bc7242a822b7cb4419c965d76119f6b +Subproject commit d4900dab6a9eea864fb14ed1ff7ea5b9f8678e04 diff --git a/scripts/build.mjs b/scripts/build.mjs index 87a9696f0..39ac5f79a 100755 --- a/scripts/build.mjs +++ b/scripts/build.mjs @@ -1,17 +1,9 @@ #!/usr/bin/env node import * as path from 'node:path'; -import * as url from 'node:url'; import * as fs from 'node:fs'; -import { info, err, run } from './lib/util.mjs'; +import { info, err, run, createDir, getScriptsDir } from './lib/util.mjs'; import { parseOptions, Enum, Architectures } from './lib/options.mjs'; -// Enums -const PackageTypes = new Enum([ - 'None', - 'AppImage', - 'Flatpak' -]); - // CMake Options const cmakeArgPrefix = '-D'; const cmakeArgSeparator = '='; @@ -41,6 +33,11 @@ function parseCMakeOption(arg) { } // Options +const PackageTypes = new Enum([ + 'None', + 'AppImage', + 'Flatpak' +]); const options = parseOptions([ ['packageType', PackageTypes], ['architecture', Architectures] @@ -59,8 +56,7 @@ if (options.packageType === PackageTypes.AppImage && options.install) { } // Folders -const __filename = url.fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); +const __dirname = getScriptsDir(); const root = path.join(__dirname, '..'); let build = path.join(root, 'build'); let out = path.join(root, 'out'); @@ -97,12 +93,6 @@ if (options.architecture !== Architectures.Host) { } // Make Build Directory -function createDir(dir, clean) { - if (clean) { - fs.rmSync(dir, {recursive: true, force: true}); - } - fs.mkdirSync(dir, {recursive: true}); -} createDir(build, options.clean); if (!options.install) { createDir(out, !useOutRoot); diff --git a/scripts/fix-appimage-for-docker.sh b/scripts/fix-appimage-for-docker.sh index 1c9988dea..12232ef12 100755 --- a/scripts/fix-appimage-for-docker.sh +++ b/scripts/fix-appimage-for-docker.sh @@ -1,3 +1,2 @@ #!/bin/sh - exec sed -i '0,/AI\x02/{s|AI\x02|\x00\x00\x00|}' "$1" \ No newline at end of file diff --git a/scripts/install-dependencies.mjs b/scripts/install-dependencies.mjs new file mode 100755 index 000000000..846f69eef --- /dev/null +++ b/scripts/install-dependencies.mjs @@ -0,0 +1,150 @@ +#!/usr/bin/env node +import * as path from 'node:path'; +import * as fs from 'node:fs'; +import { err, run, makeExecutable, getDebianVersion, getScriptsDir, info } from './lib/util.mjs'; +import { parseOptions, Enum, Architectures } from './lib/options.mjs'; + +// Check System +if (process.getuid() !== 0) { + err("Must Run As Root!"); +} +if (!fs.existsSync('/etc/debian_version')) { + err('Non-Debian OS Detected'); +} + +// Options +const Modes = new Enum([ + 'Build', + 'Test', + 'SDK' +]); +const options = parseOptions([ + ['mode', Modes], + ['architecture', Architectures] +], [], null); + +// Setup Backports If Needed +const debianVersion = getDebianVersion(); +info('OS Version: ' + debianVersion); +let backportsSuffix = ''; +if (debianVersion === 'bullseye') { + const repo = debianVersion + '-backports'; + const source = `deb http://deb.debian.org/debian ${repo} main\n`; + fs.writeFileSync(`/etc/apt/sources.list.d/${repo}.list`, source); + backportsSuffix = '/' + repo; +} + +// Update APT +let archSuffix = ''; +if (options.architecture !== Architectures.Host) { + const arch = options.architecture.name; + run(['dpkg', '--add-architecture', arch]); + archSuffix = ':' + arch; +} +run(['apt-get', 'update']); +run(['apt-get', 'dist-upgrade', '-y']); + +// Install Packages +const packages = []; +function addPackageForBuild(...arr) { + // The machine the package is built on. + packages.push(...arr); +} +function addPackageForHost(...arr) { + // The machine the package is built for. + for (const name of arr) { + packages.push(name + archSuffix); + } +} + +// Build Dependencies +const handlers = new Map(); +handlers.set(Modes.Build, function () { + // Build Dependencies + addPackageForBuild( + 'git', + 'cmake' + backportsSuffix, + 'ninja-build' + ); + + // Compiler + if (options.architecture === Architectures.Host) { + addPackageForBuild('gcc', 'g++'); + } else { + addPackageForBuild('crossbuild-essential-' + options.architecture.name); + } + + // Main Dependencies + addPackageForHost('libopenal-dev'); + + // GLFW Dependencies + addPackageForBuild('libwayland-bin'); + addPackageForHost( + 'libwayland-dev', + 'libxkbcommon-dev', + 'libx11-dev', + 'libxcursor-dev', + 'libxi-dev', + 'libxinerama-dev', + 'libxrandr-dev', + 'libxext-dev' + ); + + // QEMU Dependencies + addPackageForBuild( + 'python3', + 'python3-venv', + `python3-tomli` + backportsSuffix + ); + addPackageForHost('libglib2.0-dev'); + + // AppImage Dependencies + addPackageForBuild( + 'appstream', + 'zsync' + ); + + // Download AppImageTool + function getAppImageArch() { + switch (process.arch) { + case 'x64': return 'x86_64'; + case 'arm64': return 'aarch64'; + case 'arm': return 'armhf'; + default: err('Unsupported Build Architecture'); + } + } + let appimagetool = '/opt/appimagetool'; + run(['wget', '-O', appimagetool, `https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-${getAppImageArch()}.AppImage`]); + makeExecutable(appimagetool); + run([getScriptsDir() + '/fix-appimage-for-docker.sh', appimagetool]); + const script = `#!/bin/sh\nexec ${appimagetool} --appimage-extract-and-run "$@"\n`; + appimagetool = '/usr/local/bin/' + path.basename(appimagetool); + fs.writeFileSync(appimagetool, script); + makeExecutable(appimagetool); +}); + +// Testing Dependencies +handlers.set(Modes.Test, function () { + addPackageForHost( + 'libc6', + 'libstdc++6', + 'libopenal1', + 'libglib2.0-0' + ); +}); + +// SDK Usage Dependencies +handlers.set(Modes.SDK, function () { + addPackageForBuild( + 'cmake' + backportsSuffix, + 'ninja-build', + 'g++-arm-linux-gnueabihf', + 'gcc-arm-linux-gnueabihf' + ); +}); + +// Run +handlers.get(options.mode)(); + +// Install Packages +run(['apt-get', 'install', '--no-install-recommends', '-y', ...packages]); \ No newline at end of file diff --git a/scripts/install-dependencies.sh b/scripts/install-dependencies.sh deleted file mode 100755 index 9490c5e43..000000000 --- a/scripts/install-dependencies.sh +++ /dev/null @@ -1,109 +0,0 @@ -#!/bin/sh - -set -e - -# Don't Use Sudo When Running As Root -if [ "$(id -u)" -eq 0 ]; then - sudo() { - "$@" - } -fi - -# Setup Backports -CODENAME="$(. /etc/os-release && echo "${VERSION_CODENAME}")" -BACKPORTS='' -if [ "${CODENAME}" = 'bullseye' ]; then - BACKPORTS="${CODENAME}-backports" - echo "deb http://deb.debian.org/debian ${BACKPORTS} main" | sudo tee "/etc/apt/sources.list.d/${BACKPORTS}.list" > /dev/null - BACKPORTS="/${BACKPORTS}" -fi - -# Variables -MODE="$1" -ARCH="$(echo "$2" | tr '[:upper:]' '[:lower:]')" - -# Add ARM Repository -sudo dpkg --add-architecture "${ARCH}" - -# Update APT -sudo apt-get update -sudo apt-get dist-upgrade -y - -# Run APT -install_pkg() { - sudo apt-get install --no-install-recommends -y "$@" -} - -# Build Dependencies -run_build() { - install_pkg \ - `# Build System` \ - git \ - "cmake${BACKPORTS}" \ - ninja-build \ - python3 \ - python3-venv \ - "python3-tomli${BACKPORTS}" \ - `# Host Dependencies Needed For Compile` \ - libwayland-bin \ - `# Compiler` \ - "crossbuild-essential-$1" \ - `# Main Dependencies` \ - "libopenal-dev:$1" \ - `# GLFW Dependencies` \ - "libwayland-dev:$1" \ - "libxkbcommon-dev:$1" \ - "libx11-dev:$1" \ - "libxcursor-dev:$1" \ - "libxi-dev:$1" \ - "libxinerama-dev:$1" \ - "libxrandr-dev:$1" \ - "libxext-dev:$1" \ - `# QEMU Dependencies` \ - "libglib2.0-dev:$1" \ - `# AppImage` \ - appstream \ - zsync - - # Install appimagetool - sudo rm -rf /opt/squashfs-root /opt/appimagetool /usr/local/bin/appimagetool - case "$(dpkg --print-architecture)" in - 'armhf') APPIMAGE_ARCH='armhf';; - 'arm64') APPIMAGE_ARCH='aarch64';; - 'amd64') APPIMAGE_ARCH='x86_64';; - esac - sudo mkdir -p /opt - sudo wget -O /opt/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-${APPIMAGE_ARCH}.AppImage" - sudo chmod +x /opt/appimagetool - # Workaround AppImage Issues With Docker - sudo ./scripts/fix-appimage-for-docker.sh /opt/appimagetool - # Extract - cd /opt - sudo ./appimagetool --appimage-extract > /dev/null - sudo rm -f ./appimagetool - # Link - sudo mv ./squashfs-root ./appimagetool - printf '#!/bin/sh\nexec /opt/appimagetool/AppRun "$@"\n' | sudo tee /usr/local/bin/appimagetool > /dev/null - sudo chmod +x /usr/local/bin/appimagetool -} - -# Test Dependencies -run_test() { - install_pkg \ - "libc6:$1" \ - "libstdc++6:$1" \ - "libopenal1:$1" \ - "libglib2.0-0:$1" -} - -# Example Mods Dependencies -run_example_mods() { - install_pkg \ - cmake \ - ninja-build \ - g++-arm-linux-gnueabihf \ - gcc-arm-linux-gnueabihf -} - -# Install Packages -"run_${MODE}" "${ARCH}" diff --git a/scripts/lib/options.mjs b/scripts/lib/options.mjs index 1fcd11800..1c4323fff 100644 --- a/scripts/lib/options.mjs +++ b/scripts/lib/options.mjs @@ -36,7 +36,7 @@ function formatFlag(name) { return '--' + name; } function formatOptionalArg(arg) { - return '[' + arg + '] ';; + return '[' + arg + '] '; } export function parseOptions(positionalArgs, flags, customHandler) { // Usage Text @@ -52,7 +52,9 @@ export function parseOptions(positionalArgs, flags, customHandler) { for (const flag of flags) { usage += formatOptionalArg(formatFlag(flag)); } - usage += formatOptionalArg(customHandler(null)); + if (customHandler) { + usage += formatOptionalArg(customHandler(null)); + } usage = usage.trim(); // Copy Arguments @@ -81,7 +83,7 @@ export function parseOptions(positionalArgs, flags, customHandler) { // Unknown Arguments for (const arg of args) { - if (!customHandler(arg)) { + if (!customHandler || !customHandler(arg)) { fail(usage); } } diff --git a/scripts/lib/util.mjs b/scripts/lib/util.mjs index d2c751968..2fb743831 100644 --- a/scripts/lib/util.mjs +++ b/scripts/lib/util.mjs @@ -1,4 +1,7 @@ import * as child_process from 'node:child_process'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import * as url from 'node:url'; // Logging const EXIT_FAILURE = 1; @@ -21,4 +24,37 @@ export function run(command) { } catch (e) { err(e); } +} + +// Create Directory +export function createDir(dir, clean) { + if (clean) { + fs.rmSync(dir, {recursive: true, force: true}); + } + fs.mkdirSync(dir, {recursive: true}); +} + +// Get System Information +export function getDebianVersion() { + const info = fs.readFileSync('/etc/os-release', 'utf8'); + const lines = info.split('\n'); + const prefix = 'VERSION_CODENAME='; + for (const line of lines) { + if (line.startsWith(prefix)) { + return line.substring(prefix.length); + } + } + return 'unknown'; +} + +// Make File Executable +export function makeExecutable(path) { + fs.chmodSync(path, 0o755); +} + +// Get Scripts Directory +export function getScriptsDir() { + const __filename = url.fileURLToPath(import.meta.url); + const __dirname = path.dirname(__filename); + return path.join(__dirname, '..'); } \ No newline at end of file