|
@@ -1,4 +1,6 @@
|
|
|
import { Effect, Layer, ServiceMap } from "effect"
|
|
import { Effect, Layer, ServiceMap } from "effect"
|
|
|
|
|
+import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
|
|
|
|
|
+import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
|
|
|
import { InstanceState } from "@/effect/instance-state"
|
|
import { InstanceState } from "@/effect/instance-state"
|
|
|
import { makeRuntime } from "@/effect/run-service"
|
|
import { makeRuntime } from "@/effect/run-service"
|
|
|
import path from "path"
|
|
import path from "path"
|
|
@@ -6,7 +8,6 @@ import { mergeDeep } from "remeda"
|
|
|
import z from "zod"
|
|
import z from "zod"
|
|
|
import { Config } from "../config/config"
|
|
import { Config } from "../config/config"
|
|
|
import { Instance } from "../project/instance"
|
|
import { Instance } from "../project/instance"
|
|
|
-import { Process } from "../util/process"
|
|
|
|
|
import { Log } from "../util/log"
|
|
import { Log } from "../util/log"
|
|
|
import * as Formatter from "./formatter"
|
|
import * as Formatter from "./formatter"
|
|
|
|
|
|
|
@@ -36,6 +37,7 @@ export namespace Format {
|
|
|
Service,
|
|
Service,
|
|
|
Effect.gen(function* () {
|
|
Effect.gen(function* () {
|
|
|
const config = yield* Config.Service
|
|
const config = yield* Config.Service
|
|
|
|
|
+ const spawner = yield* ChildProcessSpawner.ChildProcessSpawner
|
|
|
|
|
|
|
|
const state = yield* InstanceState.make(
|
|
const state = yield* InstanceState.make(
|
|
|
Effect.fn("Format.state")(function* (_ctx) {
|
|
Effect.fn("Format.state")(function* (_ctx) {
|
|
@@ -98,38 +100,45 @@ export namespace Format {
|
|
|
return checks.filter((x) => x.enabled).map((x) => x.item)
|
|
return checks.filter((x) => x.enabled).map((x) => x.item)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- async function formatFile(filepath: string) {
|
|
|
|
|
- log.info("formatting", { file: filepath })
|
|
|
|
|
- const ext = path.extname(filepath)
|
|
|
|
|
-
|
|
|
|
|
- for (const item of await getFormatter(ext)) {
|
|
|
|
|
- log.info("running", { command: item.command })
|
|
|
|
|
- try {
|
|
|
|
|
- const proc = Process.spawn(
|
|
|
|
|
- item.command.map((x) => x.replace("$FILE", filepath)),
|
|
|
|
|
- {
|
|
|
|
|
- cwd: Instance.directory,
|
|
|
|
|
- env: { ...process.env, ...item.environment },
|
|
|
|
|
- stdout: "ignore",
|
|
|
|
|
- stderr: "ignore",
|
|
|
|
|
- },
|
|
|
|
|
- )
|
|
|
|
|
- const exit = await proc.exited
|
|
|
|
|
- if (exit !== 0) {
|
|
|
|
|
|
|
+ function formatFile(filepath: string) {
|
|
|
|
|
+ return Effect.gen(function* () {
|
|
|
|
|
+ log.info("formatting", { file: filepath })
|
|
|
|
|
+ const ext = path.extname(filepath)
|
|
|
|
|
+
|
|
|
|
|
+ for (const item of yield* Effect.promise(() => getFormatter(ext))) {
|
|
|
|
|
+ log.info("running", { command: item.command })
|
|
|
|
|
+ const cmd = item.command.map((x) => x.replace("$FILE", filepath))
|
|
|
|
|
+ const code = yield* spawner
|
|
|
|
|
+ .spawn(
|
|
|
|
|
+ ChildProcess.make(cmd[0]!, cmd.slice(1), {
|
|
|
|
|
+ cwd: Instance.directory,
|
|
|
|
|
+ env: item.environment,
|
|
|
|
|
+ extendEnv: true,
|
|
|
|
|
+ }),
|
|
|
|
|
+ )
|
|
|
|
|
+ .pipe(
|
|
|
|
|
+ Effect.flatMap((handle) => handle.exitCode),
|
|
|
|
|
+ Effect.scoped,
|
|
|
|
|
+ Effect.catch(() =>
|
|
|
|
|
+ Effect.sync(() => {
|
|
|
|
|
+ log.error("failed to format file", {
|
|
|
|
|
+ error: "spawn failed",
|
|
|
|
|
+ command: item.command,
|
|
|
|
|
+ ...item.environment,
|
|
|
|
|
+ file: filepath,
|
|
|
|
|
+ })
|
|
|
|
|
+ return ChildProcessSpawner.ExitCode(1)
|
|
|
|
|
+ }),
|
|
|
|
|
+ ),
|
|
|
|
|
+ )
|
|
|
|
|
+ if (code !== 0) {
|
|
|
log.error("failed", {
|
|
log.error("failed", {
|
|
|
command: item.command,
|
|
command: item.command,
|
|
|
...item.environment,
|
|
...item.environment,
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
- } catch (error) {
|
|
|
|
|
- log.error("failed to format file", {
|
|
|
|
|
- error,
|
|
|
|
|
- command: item.command,
|
|
|
|
|
- ...item.environment,
|
|
|
|
|
- file: filepath,
|
|
|
|
|
- })
|
|
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
|
|
+ })
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
log.info("init")
|
|
log.info("init")
|
|
@@ -162,14 +171,14 @@ export namespace Format {
|
|
|
|
|
|
|
|
const file = Effect.fn("Format.file")(function* (filepath: string) {
|
|
const file = Effect.fn("Format.file")(function* (filepath: string) {
|
|
|
const { formatFile } = yield* InstanceState.get(state)
|
|
const { formatFile } = yield* InstanceState.get(state)
|
|
|
- yield* Effect.promise(() => formatFile(filepath))
|
|
|
|
|
|
|
+ yield* formatFile(filepath)
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
return Service.of({ init, status, file })
|
|
return Service.of({ init, status, file })
|
|
|
}),
|
|
}),
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
- export const defaultLayer = layer.pipe(Layer.provide(Config.defaultLayer))
|
|
|
|
|
|
|
+ export const defaultLayer = layer.pipe(Layer.provide(Config.defaultLayer), Layer.provide(CrossSpawnSpawner.defaultLayer))
|
|
|
|
|
|
|
|
const { runPromise } = makeRuntime(Service, defaultLayer)
|
|
const { runPromise } = makeRuntime(Service, defaultLayer)
|
|
|
|
|
|