63 lines
2.3 KiB
TypeScript
63 lines
2.3 KiB
TypeScript
import { YAML } from "bun";
|
|
import { Array as EffectArray, Console, Data, Effect, pipe, Record, Schema, SchemaIssue } from "effect";
|
|
import { NoSuchElementError } from "effect/Cause";
|
|
import { type ReadonlyRecord } from "effect/Record";
|
|
import { SchemaError } from "effect/Schema";
|
|
|
|
const COMPOSE_PATH = "compose.yaml";
|
|
|
|
class ScriptError extends Data.TaggedError("ScriptError")<{ cause: unknown }> {}
|
|
|
|
const ComposeSchema = Schema.Record(Schema.Union([Schema.String, Schema.Symbol]), Schema.Any);
|
|
|
|
type ComposeYaml = ReadonlyRecord<string | symbol, any>;
|
|
|
|
const getObjectKey = (key: string, yaml: ComposeYaml): Effect.Effect<ReadonlyArray<string>, ScriptError> =>
|
|
pipe(
|
|
Record.get(key)(yaml),
|
|
Effect.fromOption,
|
|
Effect.map((yaml: any) => Record.keys(yaml)),
|
|
Effect.mapError((e: NoSuchElementError) => new ScriptError({ cause: e })),
|
|
);
|
|
|
|
const getFileContent = Effect.fn("getFileContent")(function* (filePath: string) {
|
|
const fileRef = Bun.file(filePath);
|
|
|
|
yield* Effect.tryPromise({
|
|
try: () => fileRef.exists(),
|
|
catch: (_) => new ScriptError({ cause: "The wanted file does not exist." }),
|
|
});
|
|
|
|
return yield* Effect.tryPromise({
|
|
try: () => fileRef.text(),
|
|
catch: (_) => new ScriptError({ cause: "Can't retrieve the file's text content." }),
|
|
});
|
|
});
|
|
|
|
const getComposeYaml = <A>(filePath: string, schema: Schema.Schema<A>) =>
|
|
pipe(
|
|
getFileContent(filePath),
|
|
Effect.map((text: string) => YAML.parse(text)),
|
|
Effect.flatMap((yaml: unknown) => Schema.decodeUnknownEffect(schema)(yaml, { errors: "all" })),
|
|
Effect.mapError((error) => {
|
|
if (error instanceof SchemaError) {
|
|
return new ScriptError({ cause: SchemaIssue.makeFormatterStandardSchemaV1()(error.issue) });
|
|
} else {
|
|
return error;
|
|
}
|
|
}),
|
|
);
|
|
|
|
const program: Effect.Effect<ReadonlyArray<string>, ScriptError> = pipe(
|
|
getComposeYaml(COMPOSE_PATH, ComposeSchema),
|
|
Effect.flatMap((yaml: ComposeYaml) => getObjectKey("services", yaml)),
|
|
Effect.map((keys: ReadonlyArray<string>) => EffectArray.filter(keys, (key) => key !== "wordpress")),
|
|
Effect.orElseSucceed(() => [""]),
|
|
Effect.tap((services: ReadonlyArray<string>) => {
|
|
Bun.spawn({ cmd: ["podman", "compose", "pull", ...services], timeout: 10000 });
|
|
return Effect.succeed(services);
|
|
}),
|
|
Effect.tapCause(Console.error),
|
|
);
|
|
|
|
Effect.runFork(program);
|