refactor(vcs): replace async git() with ChildProcessSpawner (#19361)
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
import { Effect, Layer, ServiceMap, Stream } from "effect"
|
import { Effect, Layer, ServiceMap, Stream } from "effect"
|
||||||
|
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
|
||||||
import { Bus } from "@/bus"
|
import { Bus } from "@/bus"
|
||||||
import { BusEvent } from "@/bus/bus-event"
|
import { BusEvent } from "@/bus/bus-event"
|
||||||
|
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 { FileWatcher } from "@/file/watcher"
|
import { FileWatcher } from "@/file/watcher"
|
||||||
import { Log } from "@/util/log"
|
import { Log } from "@/util/log"
|
||||||
import { git } from "@/util/git"
|
|
||||||
import { Instance } from "./instance"
|
|
||||||
import z from "zod"
|
import z from "zod"
|
||||||
|
|
||||||
export namespace Vcs {
|
export namespace Vcs {
|
||||||
@@ -41,10 +41,25 @@ export namespace Vcs {
|
|||||||
|
|
||||||
export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Vcs") {}
|
export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Vcs") {}
|
||||||
|
|
||||||
export const layer: Layer.Layer<Service, never, Bus.Service> = Layer.effect(
|
export const layer: Layer.Layer<Service, never, Bus.Service | ChildProcessSpawner.ChildProcessSpawner> = Layer.effect(
|
||||||
Service,
|
Service,
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const bus = yield* Bus.Service
|
const bus = yield* Bus.Service
|
||||||
|
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner
|
||||||
|
|
||||||
|
const git = Effect.fnUntraced(
|
||||||
|
function* (args: string[], opts: { cwd: string }) {
|
||||||
|
const handle = yield* spawner.spawn(
|
||||||
|
ChildProcess.make("git", args, { cwd: opts.cwd, extendEnv: true, stdin: "ignore" }),
|
||||||
|
)
|
||||||
|
const text = yield* Stream.mkString(Stream.decodeText(handle.stdout))
|
||||||
|
const code = yield* handle.exitCode
|
||||||
|
return { code, text }
|
||||||
|
},
|
||||||
|
Effect.scoped,
|
||||||
|
Effect.catch(() => Effect.succeed({ code: ChildProcessSpawner.ExitCode(1), text: "" })),
|
||||||
|
)
|
||||||
|
|
||||||
const state = yield* InstanceState.make<State>(
|
const state = yield* InstanceState.make<State>(
|
||||||
Effect.fn("Vcs.state")((ctx) =>
|
Effect.fn("Vcs.state")((ctx) =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
@@ -52,17 +67,15 @@ export namespace Vcs {
|
|||||||
return { current: undefined }
|
return { current: undefined }
|
||||||
}
|
}
|
||||||
|
|
||||||
const get = async () => {
|
const getBranch = Effect.fnUntraced(function* () {
|
||||||
const result = await git(["rev-parse", "--abbrev-ref", "HEAD"], {
|
const result = yield* git(["rev-parse", "--abbrev-ref", "HEAD"], { cwd: ctx.worktree })
|
||||||
cwd: ctx.worktree,
|
if (result.code !== 0) return undefined
|
||||||
})
|
const text = result.text.trim()
|
||||||
if (result.exitCode !== 0) return undefined
|
|
||||||
const text = result.text().trim()
|
|
||||||
return text || undefined
|
return text || undefined
|
||||||
}
|
})
|
||||||
|
|
||||||
const value = {
|
const value = {
|
||||||
current: yield* Effect.promise(() => get()),
|
current: yield* getBranch(),
|
||||||
}
|
}
|
||||||
log.info("initialized", { branch: value.current })
|
log.info("initialized", { branch: value.current })
|
||||||
|
|
||||||
@@ -70,7 +83,7 @@ export namespace Vcs {
|
|||||||
Stream.filter((evt) => evt.properties.file.endsWith("HEAD")),
|
Stream.filter((evt) => evt.properties.file.endsWith("HEAD")),
|
||||||
Stream.runForEach(() =>
|
Stream.runForEach(() =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const next = yield* Effect.promise(() => get())
|
const next = yield* getBranch()
|
||||||
if (next !== value.current) {
|
if (next !== value.current) {
|
||||||
log.info("branch changed", { from: value.current, to: next })
|
log.info("branch changed", { from: value.current, to: next })
|
||||||
value.current = next
|
value.current = next
|
||||||
@@ -97,7 +110,7 @@ export namespace Vcs {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
export const defaultLayer = layer.pipe(Layer.provide(Bus.layer))
|
export const defaultLayer = layer.pipe(Layer.provide(Bus.layer), Layer.provide(CrossSpawnSpawner.defaultLayer))
|
||||||
|
|
||||||
const { runPromise } = makeRuntime(Service, defaultLayer)
|
const { runPromise } = makeRuntime(Service, defaultLayer)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user