From f323ad5ad9b2e49aa133c89e14adf1ab42e08cd0 Mon Sep 17 00:00:00 2001 From: Kunam Balaram Reddy Date: Sun, 18 Aug 2024 07:20:40 +0530 Subject: [PATCH] fix: tailcall server run via npx command --- .github/build-matrix.yaml | 80 +++++++++++++++++++++++++++++ .github/workflows/build_matrix.yml | 82 +----------------------------- npm/gen-root.ts | 52 +++++++------------ npm/package.json | 3 +- npm/post-install.js | 65 ++++++++++++++++++----- npm/pre-install.js | 19 +++++-- npm/utils.js | 25 +++++++++ 7 files changed, 194 insertions(+), 132 deletions(-) create mode 100644 .github/build-matrix.yaml create mode 100644 npm/utils.js diff --git a/.github/build-matrix.yaml b/.github/build-matrix.yaml new file mode 100644 index 0000000000..ebca4d6146 --- /dev/null +++ b/.github/build-matrix.yaml @@ -0,0 +1,80 @@ +build: + [ + linux-x64-gnu, + linux-x64-musl, + linux-arm64-gnu, + linux-arm64-musl, + linux-ia32-gnu, + darwin-arm64, + darwin-x64, + win32-x64-msvc, + win32-arm64-msvc, + win32-ia32-msvc, + ] +include: + - build: linux-x64-gnu + os: ubuntu-latest + rust: stable + target: x86_64-unknown-linux-gnu + libc: glibc + + - build: linux-x64-musl + os: ubuntu-latest + rust: stable + target: x86_64-unknown-linux-musl + libc: musl + cross: true + + - build: linux-arm64-gnu + os: ubuntu-latest + rust: stable + target: aarch64-unknown-linux-gnu + libc: glibc + cross: true + + - build: linux-arm64-musl + os: ubuntu-latest + rust: stable + target: aarch64-unknown-linux-musl + libc: musl + cross: true + + - build: linux-ia32-gnu + os: ubuntu-latest + rust: stable + target: i686-unknown-linux-gnu + libc: glibc + cross: true + + - build: darwin-arm64 + os: macos-latest + rust: stable + target: aarch64-apple-darwin + + - build: darwin-x64 + os: macos-latest + rust: stable + target: x86_64-apple-darwin + + - build: win32-x64-msvc + os: windows-latest + rust: stable + target: x86_64-pc-windows-msvc + libc: msvc + ext: ".exe" + + - build: win32-arm64-msvc + os: windows-latest + rust: stable + target: aarch64-pc-windows-msvc + features: --no-default-features --features cli + libc: msvc + ext: ".exe" + test: false # TODO: tests are broken without default features + + - build: win32-ia32-msvc + os: windows-latest + rust: stable + target: i686-pc-windows-msvc + libc: msvc + ext: ".exe" diff --git a/.github/workflows/build_matrix.yml b/.github/workflows/build_matrix.yml index b8c47d2f52..48cdf52fba 100644 --- a/.github/workflows/build_matrix.yml +++ b/.github/workflows/build_matrix.yml @@ -17,84 +17,4 @@ jobs: - id: setup-matrix uses: druzsan/setup-matrix@v2 with: - matrix: | - build: - [ - linux-x64-gnu, - linux-x64-musl, - linux-arm64-gnu, - linux-arm64-musl, - linux-ia32-gnu, - darwin-arm64, - darwin-x64, - win32-x64-msvc, - win32-arm64-msvc, - win32-ia32-msvc, - ] - include: - - build: linux-x64-gnu - os: ubuntu-latest - rust: stable - target: x86_64-unknown-linux-gnu - libc: glibc - - - build: linux-x64-musl - os: ubuntu-latest - rust: stable - target: x86_64-unknown-linux-musl - libc: musl - cross: true - - - build: linux-arm64-gnu - os: ubuntu-latest - rust: stable - target: aarch64-unknown-linux-gnu - libc: glibc - cross: true - - - build: linux-arm64-musl - os: ubuntu-latest - rust: stable - target: aarch64-unknown-linux-musl - libc: musl - cross: true - - - build: linux-ia32-gnu - os: ubuntu-latest - rust: stable - target: i686-unknown-linux-gnu - libc: glibc - cross: true - - - build: darwin-arm64 - os: macos-latest - rust: stable - target: aarch64-apple-darwin - - - build: darwin-x64 - os: macos-latest - rust: stable - target: x86_64-apple-darwin - - - build: win32-x64-msvc - os: windows-latest - rust: stable - target: x86_64-pc-windows-msvc - libc: msvc - ext: ".exe" - - - build: win32-arm64-msvc - os: windows-latest - rust: stable - target: aarch64-pc-windows-msvc - features: --no-default-features --features cli - libc: msvc - ext: ".exe" - test: false # TODO: tests are broken without default features - - - build: win32-ia32-msvc - os: windows-latest - rust: stable - target: i686-pc-windows-msvc - libc: msvc - ext: ".exe" + matrix: ${{ fromFile('../build-matrix.yaml') }} \ No newline at end of file diff --git a/npm/gen-root.ts b/npm/gen-root.ts index c5cfbd5ae2..c2360ce0eb 100644 --- a/npm/gen-root.ts +++ b/npm/gen-root.ts @@ -15,38 +15,15 @@ interface ICLI { const options = parse({ version: {alias: "v", type: String}, name: {alias: "n", type: String}, -}) +}); -async function getBuildDefinitions(): Promise { - const ciYMLPath = resolve(__dirname, "../.github/workflows/build_matrix.yml") - const ciYML = await fs.readFile(ciYMLPath, "utf8").then(yml.parse) - const steps = ciYML.jobs["setup-matrix"].steps - for (const step of steps) { - const matrix = step?.with?.matrix - - if (matrix) { - // Parse yaml again since matrix is defined as string inside setup-matrix - return yml.parse(matrix).build - } - } - - throw new Error("Cannot find matrix definition in workflow file") -} - -async function genServerPackage(buildDefinitions: string[]) { +async function genServerPackage() { const packageVersion = options.version || "0.1.0" const name = options.name || "@tailcallhq/tailcall" console.log(`Generating package.json with version ${packageVersion}`) - // Construct the optionalDependencies object with the provided version - const optionalDependencies: Record = {} - - for (const buildDef of buildDefinitions) { - optionalDependencies[`@tailcallhq/core-${buildDef}`] = packageVersion - } - const packageJson = await fs.readFile(resolve(__dirname, "./package.json"), "utf8") const basePackage = JSON.parse(packageJson) as IPackageJSON const {description, license, repository, homepage, keywords} = basePackage @@ -60,7 +37,6 @@ async function genServerPackage(buildDefinitions: string[]) { name: name, type: "module", version: packageVersion, - optionalDependencies, scarfSettings: { defaultOptIn: true, allowTopLevel: true, @@ -68,34 +44,44 @@ async function genServerPackage(buildDefinitions: string[]) { dependencies: { "detect-libc": "^2.0.2", "@scarf/scarf": "^1.3.0", + "yaml": "^2.3.3", + "axios":"^1.7.4" }, scripts: { postinstall: "node ./scripts/post-install.js", preinstall: "node ./scripts/pre-install.js", }, + bin: { + tailcall: "bin/tailcall", // will replace with respective platform binary later. + } } // Define the directory path where the package.json should be created - const directoryPath = resolve(__dirname, "@tailcallhq/tailcall") + const directoryPath = resolve(__dirname, "@webbdays/tailcall") const scriptsPath = resolve(directoryPath, "./scripts") + const binPath = resolve(directoryPath, "./bin") await fs.mkdir(scriptsPath, {recursive: true}) + await fs.mkdir(binPath, {recursive: true}) await fs.mkdir(directoryPath, {recursive: true}) + const postInstallScript = await fs.readFile(resolve(__dirname, "./post-install.js"), "utf8") const preInstallScript = await fs.readFile(resolve(__dirname, "./pre-install.js"), "utf8") + const utilsScript = await fs.readFile(resolve(__dirname, "./utils.js"), "utf8") + const buildMatrix = await fs.readFile(resolve(__dirname, "../.github/build-matrix.yaml"), "utf8") + const postInstallScriptContent = `const version = "${packageVersion}";\n${postInstallScript}` - const preInstallScriptContent = `const optionalDependencies = ${JSON.stringify( - optionalDependencies, - )};\n${preInstallScript}` await fs.writeFile(resolve(scriptsPath, "post-install.js"), postInstallScriptContent, "utf8") - await fs.writeFile(resolve(scriptsPath, "pre-install.js"), preInstallScriptContent, "utf8") + await fs.writeFile(resolve(scriptsPath, "pre-install.js"), preInstallScript, "utf8") + await fs.writeFile(resolve(scriptsPath, "utils.js"), utilsScript, "utf8") + await fs.writeFile(resolve(directoryPath, "./build-matrix.yaml"), buildMatrix, "utf8") + await fs.writeFile(resolve(directoryPath, "./package.json"), JSON.stringify(tailcallPackage, null, 2), "utf8") await fs.copyFile(resolve(__dirname, "../README.md"), resolve(directoryPath, "./README.md")) } -const buildDefinitions = await getBuildDefinitions() -await genServerPackage(buildDefinitions) +await genServerPackage() diff --git a/npm/package.json b/npm/package.json index 82cebc7e53..964ef3e926 100644 --- a/npm/package.json +++ b/npm/package.json @@ -29,8 +29,7 @@ "dependencies": { "ts-command-line-args": "^2.5.1", "type-fest": "^4.7.1", - "yaml": "^2.3.3", - "yml": "^1.0.0" + "yaml": "^2.3.3" }, "devDependencies": { "tsx": "^4.1.0" diff --git a/npm/post-install.js b/npm/post-install.js index 365f6dfad2..11f9787188 100644 --- a/npm/post-install.js +++ b/npm/post-install.js @@ -2,25 +2,64 @@ import {familySync, GLIBC, MUSL} from "detect-libc" import {exec} from "child_process" import util from "util" +import get_matched_platform from "./utils.js" +import fs from "fs" +import axios from "axios" +import {resolve, dirname} from "path" +import { fileURLToPath } from "url" const execa = util.promisify(exec) -const platform = process.platform +const os = process.platform const arch = process.arch - const libcFamily = familySync() -let libc -if (platform === "win32") { - libc = "-msvc" + +let libc = "" +if (os === "win32") { + libc = "msvc" } else { - libc = libcFamily === GLIBC ? "-gnu" : libcFamily === MUSL ? "-musl" : "" + libc = libcFamily === GLIBC ? "gnu" : libcFamily === MUSL ? "musl" : "" } -const pkg = `@tailcallhq/core-${platform}-${arch}${libc}` +const matched_platform = get_matched_platform(os, arch, libc) +if (matched_platform != null) { + const targetPlatform = matched_platform + + let targetPlatformExt = "" + if (Object.keys(targetPlatform).includes("ext")) { + targetPlatformExt = "." + targetPlatform.get("ext") + } + + const pkg_download_base_url = "https://github.com/tailcallhq/tailcall/releases/download/" + const specific_url = `v${version}/tailcall-${targetPlatform.get("target")}${targetPlatformExt}` + const full_url = pkg_download_base_url + specific_url + + console.log(`Downloading Tailcall for ${targetPlatform.get("target")}${targetPlatformExt} ...`) -try { - // @ts-ignore - const {stdout, stderr} = await execa(`npm install ${pkg}@${version} --no-save`) - stderr ? console.log(stderr) : console.log(`Successfully installed optional dependency: ${pkg}`, stdout) -} catch (error) { - console.error(`Failed to install optional dependency: ${pkg}`, error.stderr) + const output_path = `bin/tailcall-${targetPlatform.get("target")}${targetPlatformExt}`; + download_binary(full_url, output_path) } + +async function download_binary(full_url, output_path) { + const file = fs.createWriteStream(output_path) + axios({ + url: full_url, + method: "GET", + responseType: "stream", + }).then((response) => { + response.data.pipe(file) + file.on("finish", async () => { + + + + const __dirname = dirname(fileURLToPath(import.meta.url)); + + const directoryPath = resolve(__dirname, "../") + const packageJsonString = fs.readFileSync(resolve(directoryPath, "./package.json"), "utf8"); + const packageJson = JSON.parse(packageJsonString); + packageJson.bin = {tailcall: output_path}; + fs.writeFileSync(resolve(directoryPath, "./package.json"), JSON.stringify(packageJson, null, 2), "utf8"); + + console.log("Tailcall binary downloaded successfully") + }) + }) +} \ No newline at end of file diff --git a/npm/pre-install.js b/npm/pre-install.js index 6d008b256b..1c8cc12a00 100644 --- a/npm/pre-install.js +++ b/npm/pre-install.js @@ -1,10 +1,23 @@ +// @ts-check +import {familySync, GLIBC, MUSL} from "detect-libc" +import get_matched_platform from "./utils.js" + const os = process.platform const arch = process.arch +const libcFamily =familySync(); + +let libc = "" +if (os === "win32") { + libc = "msvc" +} else { + libc = libcFamily === GLIBC ? "gnu" : libcFamily === MUSL ? "musl" : "" +} + +const matched_platform = get_matched_platform(os, arch, libc) -const dependency = Object.keys(optionalDependencies).find((name) => name.includes(`${os}-${arch}`)) -if (!dependency) { +if (matched_platform==null) { const redColor = "\x1b[31m" const resetColor = "\x1b[0m" - console.error(`${redColor} Tailcall does not support platform ${os} arch ${arch} ${resetColor}`) + console.error(`${redColor} Tailcall does not support platform - ${os}, arch - ${arch}, libc - ${libc} ${resetColor}`) process.exit(1) } diff --git a/npm/utils.js b/npm/utils.js new file mode 100644 index 0000000000..517b7e1699 --- /dev/null +++ b/npm/utils.js @@ -0,0 +1,25 @@ +import fs from "fs" +import { dirname, resolve } from "path"; +import { fileURLToPath } from "url"; +import YML from "yaml" + +const __dirname = dirname(fileURLToPath(import.meta.url)) + +export default function get_matched_platform(os, arch, libc) { + + const directoryPath = resolve(__dirname, "../") + const file = fs.readFileSync(resolve(directoryPath, "./build-matrix.yaml"), "utf8") + const build_matrix = YML.parse(file,{mapAsMap:true}); + + let found = null; + build_matrix.get("include").forEach((platform) => { + const split = platform.get("build").split("-"); + const platform_arch = split.at(1) + const platform_os = split.at(0) + const platform_libc = split.at(-1); + if (platform_arch == arch && platform_os == os && platform_libc == libc) { + found = platform; + } + }) + return found; +}