|
1 | 1 | import type { PlatformError } from "@effect/platform/Error" |
| 2 | +import { Match } from "effect" |
2 | 3 | import { type ParseError } from "../core/domain.js" |
3 | 4 | import { formatParseError } from "../core/parse-errors.js" |
4 | 5 | import type { |
@@ -51,65 +52,48 @@ const renderDockerAccessHeadline = (issue: DockerAccessError["issue"]): string = |
51 | 52 | ? "Cannot access Docker daemon socket: permission denied." |
52 | 53 | : "Cannot connect to Docker daemon." |
53 | 54 |
|
54 | | -const renderPrimaryError = (error: NonParseError): string | null => { |
55 | | - if (error._tag === "FileExistsError") { |
56 | | - return `File already exists: ${error.path} (use --force to overwrite)` |
57 | | - } |
58 | | - |
59 | | - if (error._tag === "DockerCommandError") { |
60 | | - return [ |
61 | | - `docker compose failed with exit code ${error.exitCode}`, |
62 | | - "Hint: ensure Docker daemon is running and current user can access /var/run/docker.sock (for example via the docker group)." |
63 | | - ].join("\n") |
64 | | - } |
65 | | - |
66 | | - if (error._tag === "DockerAccessError") { |
67 | | - return [ |
68 | | - renderDockerAccessHeadline(error.issue), |
69 | | - "Hint: ensure Docker daemon is running and current user can access the docker socket.", |
70 | | - "Hint: if you use rootless Docker, set DOCKER_HOST to your user socket (for example unix:///run/user/$UID/docker.sock).", |
71 | | - `Details: ${error.details}` |
72 | | - ].join("\n") |
73 | | - } |
74 | | - |
75 | | - if (error._tag === "CloneFailedError") { |
76 | | - return `Clone failed for ${error.repoUrl} (${error.repoRef}) into ${error.targetDir}` |
77 | | - } |
78 | | - |
79 | | - if (error._tag === "PortProbeError") { |
80 | | - return `SSH port check failed for ${error.port}: ${error.message}` |
81 | | - } |
82 | | - |
83 | | - if (error._tag === "CommandFailedError") { |
84 | | - return `${error.command} failed with exit code ${error.exitCode}` |
85 | | - } |
86 | | - |
87 | | - if (error._tag === "ScrapArchiveNotFoundError") { |
88 | | - return `Scrap archive not found: ${error.path} (run docker-git scrap export first)` |
89 | | - } |
90 | | - |
91 | | - if (error._tag === "ScrapTargetDirUnsupportedError") { |
92 | | - return [ |
93 | | - `Cannot use scrap with targetDir ${error.targetDir}.`, |
94 | | - `Reason: ${error.reason}`, |
95 | | - `Hint: scrap currently supports workspaces under /home/${error.sshUser}/... only.` |
96 | | - ].join("\n") |
97 | | - } |
98 | | - |
99 | | - if (error._tag === "ScrapWipeRefusedError") { |
100 | | - return [ |
101 | | - `Refusing to wipe workspace for scrap import (targetDir ${error.targetDir}).`, |
102 | | - `Reason: ${error.reason}`, |
103 | | - "Hint: re-run with --no-wipe, or set a narrower --target-dir when creating the project." |
104 | | - ].join("\n") |
105 | | - } |
106 | | - |
107 | | - if (error._tag === "AuthError") { |
108 | | - return error.message |
109 | | - } |
110 | | - |
111 | | - return null |
112 | | -} |
| 55 | +const renderPrimaryError = (error: NonParseError): string | null => |
| 56 | + Match.value(error).pipe( |
| 57 | + Match.when({ _tag: "FileExistsError" }, ({ path }) => `File already exists: ${path} (use --force to overwrite)`), |
| 58 | + Match.when({ _tag: "DockerCommandError" }, ({ exitCode }) => |
| 59 | + [ |
| 60 | + `docker compose failed with exit code ${exitCode}`, |
| 61 | + "Hint: ensure Docker daemon is running and current user can access /var/run/docker.sock (for example via the docker group)." |
| 62 | + ].join("\n")), |
| 63 | + Match.when({ _tag: "DockerAccessError" }, ({ details, issue }) => |
| 64 | + [ |
| 65 | + renderDockerAccessHeadline(issue), |
| 66 | + "Hint: ensure Docker daemon is running and current user can access the docker socket.", |
| 67 | + "Hint: if you use rootless Docker, set DOCKER_HOST to your user socket (for example unix:///run/user/$UID/docker.sock).", |
| 68 | + `Details: ${details}` |
| 69 | + ].join("\n")), |
| 70 | + Match.when({ _tag: "CloneFailedError" }, ({ repoRef, repoUrl, targetDir }) => |
| 71 | + `Clone failed for ${repoUrl} (${repoRef}) into ${targetDir}`), |
| 72 | + Match.when({ _tag: "PortProbeError" }, ({ message, port }) => |
| 73 | + `SSH port check failed for ${port}: ${message}`), |
| 74 | + Match.when( |
| 75 | + { _tag: "CommandFailedError" }, |
| 76 | + ({ command, exitCode }) => `${command} failed with exit code ${exitCode}` |
| 77 | + ), |
| 78 | + Match.when( |
| 79 | + { _tag: "ScrapArchiveNotFoundError" }, |
| 80 | + ({ path }) => `Scrap archive not found: ${path} (run docker-git scrap export first)` |
| 81 | + ), |
| 82 | + Match.when({ _tag: "ScrapTargetDirUnsupportedError" }, ({ reason, sshUser, targetDir }) => |
| 83 | + [ |
| 84 | + `Cannot use scrap with targetDir ${targetDir}.`, |
| 85 | + `Reason: ${reason}`, |
| 86 | + `Hint: scrap currently supports workspaces under /home/${sshUser}/... only.` |
| 87 | + ].join("\n")), |
| 88 | + Match.when({ _tag: "ScrapWipeRefusedError" }, ({ reason, targetDir }) => |
| 89 | + [ |
| 90 | + `Refusing to wipe workspace for scrap import (targetDir ${targetDir}).`, |
| 91 | + `Reason: ${reason}`, |
| 92 | + "Hint: re-run with --no-wipe, or set a narrower --target-dir when creating the project." |
| 93 | + ].join("\n")), |
| 94 | + Match.when({ _tag: "AuthError" }, ({ message }) => message), |
| 95 | + Match.orElse(() => null) |
| 96 | + ) |
113 | 97 |
|
114 | 98 | const renderConfigError = (error: NonParseError): string | null => { |
115 | 99 | if (error._tag === "ConfigNotFoundError") { |
|
0 commit comments