mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-17 10:02:51 +00:00
fix(watcher): resolve symlinked .git path before subscribing (#27016)
Co-authored-by: Simon Klee <hello@simonklee.dk>
This commit is contained in:
@@ -2,7 +2,7 @@ import { Cause, Effect, Layer, Context, Schema } from "effect"
|
||||
// @ts-ignore
|
||||
import { createWrapper } from "@parcel/watcher/wrapper"
|
||||
import type ParcelWatcher from "@parcel/watcher"
|
||||
import { readdir } from "fs/promises"
|
||||
import { readdir, realpath } from "fs/promises"
|
||||
import path from "path"
|
||||
import { Bus } from "@/bus"
|
||||
import { BusEvent } from "@/bus/bus-event"
|
||||
@@ -131,8 +131,11 @@ export const layer = Layer.effect(
|
||||
const result = yield* git.run(["rev-parse", "--git-dir"], {
|
||||
cwd: ctx.worktree,
|
||||
})
|
||||
const vcsDir = result.exitCode === 0 ? path.resolve(ctx.worktree, result.text().trim()) : undefined
|
||||
if (vcsDir && !cfgIgnores.includes(".git") && !cfgIgnores.includes(vcsDir)) {
|
||||
const resolved = result.exitCode === 0 ? path.resolve(ctx.worktree, result.text().trim()) : undefined
|
||||
const vcsDir = resolved
|
||||
? yield* Effect.promise(() => realpath(resolved).catch(() => resolved))
|
||||
: undefined
|
||||
if (vcsDir && !cfgIgnores.includes(".git") && !cfgIgnores.includes(vcsDir) && (!resolved || !cfgIgnores.includes(resolved))) {
|
||||
const ignore = (yield* Effect.promise(() => readdir(vcsDir).catch(() => []))).filter(
|
||||
(entry) => entry !== "HEAD",
|
||||
)
|
||||
|
||||
@@ -260,4 +260,57 @@ describeWatcher("FileWatcher", () => {
|
||||
}),
|
||||
{ git: true },
|
||||
)
|
||||
|
||||
// Symlink support varies by platform; skip where unavailable
|
||||
const describeSymlink = process.platform !== "win32" ? describe : describe.skip
|
||||
|
||||
describeSymlink("symlinked .git", () => {
|
||||
it.instance(
|
||||
"publishes .git/HEAD events through a symlinked .git directory",
|
||||
() =>
|
||||
Effect.gen(function* () {
|
||||
const test = yield* TestInstance
|
||||
const fs = yield* AppFileSystem.Service
|
||||
const git = yield* Git.Service
|
||||
const dir = test.directory
|
||||
const actualGit = path.join(dir, "..", "tmp_actual_git_" + Math.random().toString(36).slice(2))
|
||||
|
||||
// Move .git to a sibling directory and replace with a symlink
|
||||
yield* Effect.promise(() => import("fs")).pipe(
|
||||
Effect.flatMap((nodeFs) =>
|
||||
Effect.all([
|
||||
Effect.promise(() => nodeFs.promises.rename(path.join(dir, ".git"), actualGit)),
|
||||
Effect.promise(() => nodeFs.promises.symlink(actualGit, path.join(dir, ".git"))),
|
||||
]),
|
||||
),
|
||||
)
|
||||
|
||||
yield* Effect.acquireRelease(
|
||||
Effect.succeed(actualGit),
|
||||
(p) => Effect.promise(() => import("fs").then((f) => f.promises.rm(p, { recursive: true, force: true }).catch(() => undefined))),
|
||||
)
|
||||
|
||||
const head = path.join(dir, ".git", "HEAD")
|
||||
const branch = `watch-${Math.random().toString(36).slice(2)}`
|
||||
yield* git.run(["branch", branch], { cwd: dir })
|
||||
|
||||
yield* withWatcher(
|
||||
dir,
|
||||
nextUpdate(
|
||||
dir,
|
||||
(evt) => evt.file === path.join(actualGit, "HEAD") && evt.event !== "unlink",
|
||||
fs.writeFileString(head, `ref: refs/heads/${branch}\n`),
|
||||
).pipe(
|
||||
Effect.tap((evt) =>
|
||||
Effect.sync(() => {
|
||||
expect(evt.file).toBe(path.join(actualGit, "HEAD"))
|
||||
expect(["add", "change"]).toContain(evt.event)
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
}),
|
||||
{ git: true },
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user