| ... | @@ -1,7 +1,6 @@ | ... | @@ -1,7 +1,6 @@ |
| 1 | #!/usr/bin/env node | 1 | #!/usr/bin/env node |
| 2 | import * as NodeRuntime from "@effect/platform-node/NodeRuntime"; | 2 | import * as NodeRuntime from "@effect/platform-node/NodeRuntime"; |
| 3 | import * as NodeServices from "@effect/platform-node/NodeServices"; | 3 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 4 | import * as Data from "effect/Data"; | | |
| 5 | import * as Effect from "effect/Effect"; | 4 | import * as Effect from "effect/Effect"; |
| 6 | import * as FileSystem from "effect/FileSystem"; | 5 | import * as FileSystem from "effect/FileSystem"; |
| 7 | import * as Logger from "effect/Logger"; | 6 | import * as Logger from "effect/Logger"; |
| ... | @@ -20,6 +19,14 @@ import { fromJsonStringPretty } from "@t3tools/shared/schemaJson"; | ... | @@ -20,6 +19,14 @@ import { fromJsonStringPretty } from "@t3tools/shared/schemaJson"; |
| 20 | import { fromYaml } from "@t3tools/shared/schemaYaml"; | 19 | import { fromYaml } from "@t3tools/shared/schemaYaml"; |
| 21 | import { resolveSpawnCommand } from "@t3tools/shared/shell"; | 20 | import { resolveSpawnCommand } from "@t3tools/shared/shell"; |
| 22 | import serverPackageJson from "../package.json" with { type: "json" }; | 21 | import serverPackageJson from "../package.json" with { type: "json" }; |
| | 22 | import { |
| | 23 | ServerCliBuildAssetMissingError, |
| | 24 | ServerCliCommandExitError, |
| | 25 | ServerCliDevelopmentIconSourceMissingError, |
| | 26 | ServerCliDevelopmentIconTargetMissingError, |
| | 27 | ServerCliPublishIconSourceMissingError, |
| | 28 | ServerCliPublishIconTargetMissingError, |
| | 29 | } from "./cliErrors.ts"; |
| 23 | | 30 | |
| 24 | interface PackageJson { | 31 | interface PackageJson { |
| 25 | name: string; | 32 | name: string; |
| ... | @@ -47,11 +54,6 @@ const WorkspaceConfig = Schema.Struct({ | ... | @@ -47,11 +54,6 @@ const WorkspaceConfig = Schema.Struct({ |
| 47 | type WorkspaceConfig = typeof WorkspaceConfig.Type; | 54 | type WorkspaceConfig = typeof WorkspaceConfig.Type; |
| 48 | const decodeWorkspaceConfig = Schema.decodeEffect(fromYaml(WorkspaceConfig)); | 55 | const decodeWorkspaceConfig = Schema.decodeEffect(fromYaml(WorkspaceConfig)); |
| 49 | | 56 | |
| 50 | class CliError extends Data.TaggedError("CliError")<{ | | |
| 51 | readonly message: string; | | |
| 52 | readonly cause?: unknown; | | |
| 53 | }> {} | | |
| 54 | | | |
| 55 | const RepoRoot = Effect.service(Path.Path).pipe( | 57 | const RepoRoot = Effect.service(Path.Path).pipe( |
| 56 | Effect.flatMap((path) => path.fromFileUrl(new URL("../../..", import.meta.url))), | 58 | Effect.flatMap((path) => path.fromFileUrl(new URL("../../..", import.meta.url))), |
| 57 | ); | 59 | ); |
| ... | @@ -64,14 +66,17 @@ const readWorkspaceConfig = Effect.fn("readWorkspaceConfig")(function* () { | ... | @@ -64,14 +66,17 @@ const readWorkspaceConfig = Effect.fn("readWorkspaceConfig")(function* () { |
| 64 | return yield* decodeWorkspaceConfig(workspaceYaml); | 66 | return yield* decodeWorkspaceConfig(workspaceYaml); |
| 65 | }); | 67 | }); |
| 66 | | 68 | |
| 67 | const runCommand = Effect.fn("runCommand")(function* (command: ChildProcess.Command) { | 69 | const runCommand = Effect.fn("runCommand")(function* (command: ChildProcess.StandardCommand) { |
| 68 | const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; | 70 | const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; |
| 69 | const child = yield* spawner.spawn(command); | 71 | const child = yield* spawner.spawn(command); |
| 70 | const exitCode = yield* child.exitCode; | 72 | const exitCode = yield* child.exitCode; |
| 71 | | 73 | |
| 72 | if (exitCode !== 0) { | 74 | if (exitCode !== 0) { |
| 73 | return yield* new CliError({ | 75 | return yield* new ServerCliCommandExitError({ |
| 74 | message: `Command exited with non-zero exit code (${exitCode})`, | 76 | command: command.command, |
| | 77 | args: command.args, |
| | 78 | cwd: command.options.cwd, |
| | 79 | exitCode, |
| 75 | }); | 80 | }); |
| 76 | } | 81 | } |
| 77 | }); | 82 | }); |
| ... | @@ -95,14 +100,10 @@ const applyPublishIconOverrides = Effect.fn("applyPublishIconOverrides")(functio | ... | @@ -95,14 +100,10 @@ const applyPublishIconOverrides = Effect.fn("applyPublishIconOverrides")(functio |
| 95 | const backupPath = `${targetPath}.publish-bak`; | 100 | const backupPath = `${targetPath}.publish-bak`; |
| 96 | | 101 | |
| 97 | if (!(yield* fs.exists(sourcePath))) { | 102 | if (!(yield* fs.exists(sourcePath))) { |
| 98 | return yield* new CliError({ | 103 | return yield* new ServerCliPublishIconSourceMissingError({ sourcePath }); |
| 99 | message: `Missing publish icon source: ${sourcePath}`, | | |
| 100 | }); | | |
| 101 | } | 104 | } |
| 102 | if (!(yield* fs.exists(targetPath))) { | 105 | if (!(yield* fs.exists(targetPath))) { |
| 103 | return yield* new CliError({ | 106 | return yield* new ServerCliPublishIconTargetMissingError({ targetPath }); |
| 104 | message: `Missing publish icon target: ${targetPath}. Run the build subcommand first.`, | | |
| 105 | }); | | |
| 106 | } | 107 | } |
| 107 | | 108 | |
| 108 | yield* fs.copyFile(targetPath, backupPath); | 109 | yield* fs.copyFile(targetPath, backupPath); |
| ... | @@ -138,14 +139,10 @@ const applyDevelopmentIconOverrides = Effect.fn("applyDevelopmentIconOverrides") | ... | @@ -138,14 +139,10 @@ const applyDevelopmentIconOverrides = Effect.fn("applyDevelopmentIconOverrides") |
| 138 | const targetPath = path.join(serverDir, override.targetRelativePath); | 139 | const targetPath = path.join(serverDir, override.targetRelativePath); |
| 139 | | 140 | |
| 140 | if (!(yield* fs.exists(sourcePath))) { | 141 | if (!(yield* fs.exists(sourcePath))) { |
| 141 | return yield* new CliError({ | 142 | return yield* new ServerCliDevelopmentIconSourceMissingError({ sourcePath }); |
| 142 | message: `Missing development icon source: ${sourcePath}`, | | |
| 143 | }); | | |
| 144 | } | 143 | } |
| 145 | if (!(yield* fs.exists(targetPath))) { | 144 | if (!(yield* fs.exists(targetPath))) { |
| 146 | return yield* new CliError({ | 145 | return yield* new ServerCliDevelopmentIconTargetMissingError({ targetPath }); |
| 147 | message: `Missing development icon target: ${targetPath}. Build web first.`, | | |
| 148 | }); | | |
| 149 | } | 146 | } |
| 150 | | 147 | |
| 151 | yield* fs.copyFile(sourcePath, targetPath); | 148 | yield* fs.copyFile(sourcePath, targetPath); |
| ... | @@ -245,9 +242,7 @@ const publishCmd = Command.make( | ... | @@ -245,9 +242,7 @@ const publishCmd = Command.make( |
| 245 | for (const relPath of ["dist/bin.mjs", "dist/client/index.html"]) { | 242 | for (const relPath of ["dist/bin.mjs", "dist/client/index.html"]) { |
| 246 | const abs = path.join(serverDir, relPath); | 243 | const abs = path.join(serverDir, relPath); |
| 247 | if (!(yield* fs.exists(abs))) { | 244 | if (!(yield* fs.exists(abs))) { |
| 248 | return yield* new CliError({ | 245 | return yield* new ServerCliBuildAssetMissingError({ assetPath: abs }); |
| 249 | message: `Missing build asset: ${abs}. Run the build subcommand first.`, | | |
| 250 | }); | | |
| 251 | } | 246 | } |
| 252 | } | 247 | } |
| 253 | | 248 | |