| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | // @effect-diagnostics nodeBuiltinImport:off | 1 | // @effect-diagnostics nodeBuiltinImport:off |
| 2 | import { expect, it } from "@effect/vitest"; | 2 | import { expect, it } from "@effect/vitest"; |
| 3 | import * as NodeFS from "node:fs"; | 3 | import * as NodeFS from "node:fs"; |
| | 4 | import * as NodeChildProcess from "node:child_process"; |
| 4 | import * as NodeServices from "@effect/platform-node/NodeServices"; | 5 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 5 | import * as NodeOS from "node:os"; | 6 | import * as NodeOS from "node:os"; |
| 6 | import * as NodePath from "node:path"; | 7 | import * as NodePath from "node:path"; |
| ... | @@ -8,6 +9,7 @@ import { ProviderDriverKind, ProviderInstanceId, type ServerProvider } from "@t3 | ... | @@ -8,6 +9,7 @@ import { ProviderDriverKind, ProviderInstanceId, type ServerProvider } from "@t3 |
| 8 | import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; | 9 | import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; |
| 9 | import * as Crypto from "effect/Crypto"; | 10 | import * as Crypto from "effect/Crypto"; |
| 10 | import * as Effect from "effect/Effect"; | 11 | import * as Effect from "effect/Effect"; |
| | 12 | import * as FileSystem from "effect/FileSystem"; |
| 11 | import { HttpClient } from "effect/unstable/http"; | 13 | import { HttpClient } from "effect/unstable/http"; |
| 12 | import { | 14 | import { |
| 13 | createProviderVersionAdvisory, | 15 | createProviderVersionAdvisory, |
| ... | @@ -362,9 +364,9 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { | ... | @@ -362,9 +364,9 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { |
| 362 | provider: driver("nativePackageTool"), | 364 | provider: driver("nativePackageTool"), |
| 363 | packageName: "@example/native-package-tool", | 365 | packageName: "@example/native-package-tool", |
| 364 | update: { | 366 | update: { |
| 365 | command: "native-package-tool update", | 367 | command: `${nativePackageToolPath} update`, |
| 366 | | 368 | |
| 367 | executable: "native-package-tool", | 369 | executable: nativePackageToolPath, |
| 368 | | 370 | |
| 369 | args: ["update"], | 371 | args: ["update"], |
| 370 | | 372 | |
| ... | @@ -399,9 +401,9 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { | ... | @@ -399,9 +401,9 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { |
| 399 | provider: driver("scopedPackageTool"), | 401 | provider: driver("scopedPackageTool"), |
| 400 | packageName: "@example/scoped-package-tool", | 402 | packageName: "@example/scoped-package-tool", |
| 401 | update: { | 403 | update: { |
| 402 | command: "scoped-package-tool upgrade", | 404 | command: `${scopedPackageToolPath} upgrade`, |
| 403 | | 405 | |
| 404 | executable: "scoped-package-tool", | 406 | executable: scopedPackageToolPath, |
| 405 | | 407 | |
| 406 | args: ["upgrade"], | 408 | args: ["upgrade"], |
| 407 | | 409 | |
| ... | @@ -411,6 +413,50 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { | ... | @@ -411,6 +413,50 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { |
| 411 | }), | 413 | }), |
| 412 | ); | 414 | ); |
| 413 | | 415 | |
| | 416 | it.effect.skipIf(windowsHost)("runs an explicit native updater outside PATH", () => |
| | 417 | Effect.gen(function* () { |
| | 418 | const fs = yield* FileSystem.FileSystem; |
| | 419 | const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-native-update-" }); |
| | 420 | const nativeBinDir = NodePath.join(tempDir, "with spaces", ".scoped-package-tool", "bin"); |
| | 421 | yield* fs.makeDirectory(nativeBinDir, { recursive: true }); |
| | 422 | const binaryPath = NodePath.join(nativeBinDir, "scoped-package-tool"); |
| | 423 | yield* fs.writeFileString(binaryPath, "#!/bin/sh\nprintf '%s' \"$1\"\n"); |
| | 424 | yield* fs.chmod(binaryPath, 0o755); |
| | 425 | |
| | 426 | const capabilities = yield* resolveProviderMaintenanceCapabilitiesEffect( |
| | 427 | scopedPackageToolUpdate, |
| | 428 | { binaryPath, env: { PATH: "" } }, |
| | 429 | ); |
| | 430 | const update = capabilities.update; |
| | 431 | expect(update).not.toBeNull(); |
| | 432 | if (!update) return; |
| | 433 | const result = NodeChildProcess.spawnSync(update.executable, update.args, { |
| | 434 | env: { PATH: "" }, |
| | 435 | encoding: "utf8", |
| | 436 | }); |
| | 437 | expect(result.error).toBeUndefined(); |
| | 438 | expect(result.status).toBe(0); |
| | 439 | expect(result.stdout).toBe("upgrade"); |
| | 440 | }).pipe(Effect.scoped), |
| | 441 | ); |
| | 442 | |
| | 443 | it.each([ |
| | 444 | "/Users/example/.local/bin/native-package-tool", |
| | 445 | "C:\\Users\\Example User\\.local\\bin\\native-package-tool.exe", |
| | 446 | ])("preserves a configured native executable path: %s", (binaryPath) => { |
| | 447 | expect(nativePackageToolUpdate.resolve({ binaryPath }).update?.executable).toBe(binaryPath); |
| | 448 | }); |
| | 449 | |
| | 450 | it("uses the resolved launcher when its symlink target identifies a native install", () => { |
| | 451 | const launcher = "/custom tools/native-launcher"; |
| | 452 | const capabilities = nativePackageToolUpdate.resolve({ |
| | 453 | binaryPath: launcher, |
| | 454 | resolvedCommandPath: launcher, |
| | 455 | realCommandPath: "/Users/example/.local/bin/native-package-tool", |
| | 456 | }); |
| | 457 | expect(capabilities.update?.executable).toBe(launcher); |
| | 458 | }); |
| | 459 | |
| 414 | it("switches native-package-tool to Homebrew updates when the binary resolves through Homebrew", () => { | 460 | it("switches native-package-tool to Homebrew updates when the binary resolves through Homebrew", () => { |
| 415 | expect( | 461 | expect( |
| 416 | nativePackageToolUpdate.resolve({ | 462 | nativePackageToolUpdate.resolve({ |