( server: LspServerDefinition, mode: "install" | "update" = "install", )
| 478 | } |
| 479 | |
| 480 | function buildInstallCommand( |
| 481 | server: LspServerDefinition, |
| 482 | mode: "install" | "update" = "install", |
| 483 | ): string | null { |
| 484 | const spec = normalizeInstallSpec(server); |
| 485 | if (!spec) return null; |
| 486 | |
| 487 | if (mode === "update" && spec.updateCommand) { |
| 488 | return spec.updateCommand; |
| 489 | } |
| 490 | |
| 491 | switch (spec.kind) { |
| 492 | case "apk": |
| 493 | return spec.packages.length |
| 494 | ? `apk add --no-cache ${spec.packages.map((entry) => quoteArg(entry)).join(" ")}` |
| 495 | : null; |
| 496 | case "npm": { |
| 497 | if (!spec.packages.length) return null; |
| 498 | const npmCommand = spec.npmCommand || "npm"; |
| 499 | const installFlags = spec.global !== false ? "install -g" : "install"; |
| 500 | return `apk add --no-cache nodejs npm && ${npmCommand} ${installFlags} ${spec.packages.map((entry) => quoteArg(entry)).join(" ")}`; |
| 501 | } |
| 502 | case "pip": { |
| 503 | if (!spec.packages.length) return null; |
| 504 | const pipCommand = spec.pipCommand || "pip"; |
| 505 | const breakPackages = |
| 506 | spec.breakSystemPackages !== false |
| 507 | ? "PIP_BREAK_SYSTEM_PACKAGES=1 " |
| 508 | : ""; |
| 509 | return `apk add --no-cache python3 py3-pip && ${breakPackages}${pipCommand} install ${spec.packages.map((entry) => quoteArg(entry)).join(" ")}`; |
| 510 | } |
| 511 | case "cargo": |
| 512 | return spec.packages.length |
| 513 | ? `apk add --no-cache rust cargo && cargo install ${spec.packages.map((entry) => quoteArg(entry)).join(" ")}` |
| 514 | : null; |
| 515 | case "github-release": { |
| 516 | if (!spec.repo || !spec.binaryPath) return null; |
| 517 | const caseLines = buildShellArchCase(spec.assetNames, quoteArg); |
| 518 | if (!caseLines) return null; |
| 519 | const archivePath = '"$TMP_DIR/$ASSET"'; |
| 520 | const extractedFile = quoteArg(spec.extractFile || "luau-lsp"); |
| 521 | const installTarget = quoteArg(spec.binaryPath); |
| 522 | const downloadUrl = `https://github.com/${spec.repo}/releases/latest/download/$ASSET`; |
| 523 | |
| 524 | if (spec.archiveType === "binary") { |
| 525 | return `apk add --no-cache curl && ARCH="$(uname -m)" && case "$ARCH" in\n${caseLines}\n\t*) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;;\nesac && TMP_DIR="$(mktemp -d)" && cleanup() { rm -rf "$TMP_DIR"; } && trap cleanup EXIT && curl -fsSL "${downloadUrl}" -o ${archivePath} && install -Dm755 ${archivePath} ${installTarget}`; |
| 526 | } |
| 527 | |
| 528 | return `apk add --no-cache curl unzip && ARCH="$(uname -m)" && case "$ARCH" in\n${caseLines}\n\t*) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;;\nesac && TMP_DIR="$(mktemp -d)" && cleanup() { rm -rf "$TMP_DIR"; } && trap cleanup EXIT && curl -fsSL "${downloadUrl}" -o ${archivePath} && unzip -oq ${archivePath} -d "$TMP_DIR" && install -Dm755 "$TMP_DIR"/${extractedFile} ${installTarget}`; |
| 529 | } |
| 530 | case "manual": |
| 531 | return null; |
| 532 | default: |
| 533 | return spec.command || null; |
| 534 | } |
| 535 | } |
| 536 | |
| 537 | function buildDerivedCheckCommand(server: LspServerDefinition): string | null { |
no test coverage detected