mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-08 09:37:47 +03:00
fix(core): capture snapshots for a Location opened through a symlink (#61546)
This commit is contained in:
committed by
GitHub
Unverified
parent
0c4dd78fd6
commit
77264eb66e
@@ -105,10 +105,15 @@ const layer = Layer.effect(
|
||||
)
|
||||
const repository = repositoryFiber.pipe(Effect.uninterruptible, Effect.flatMap(Fiber.join))
|
||||
|
||||
// The worktree is a real path, so the Location must be one too: a symlinked or junctioned path would fall outside
|
||||
// it, and a path in another letter case would become a pathspec that matches nothing.
|
||||
const scope = Effect.fnUntraced(function* (worktree: AbsolutePath) {
|
||||
if (!FSUtil.contains(worktree, location.directory))
|
||||
const directory = yield* fs
|
||||
.realPath(location.directory)
|
||||
.pipe(Effect.mapError((cause) => failure("capture", cause)))
|
||||
if (!FSUtil.contains(worktree, directory))
|
||||
return yield* new Error({ operation: "capture", message: "Location is outside the project" })
|
||||
return RelativePath.make(path.relative(worktree, location.directory).replaceAll("\\", "/") || ".")
|
||||
return RelativePath.make(path.relative(worktree, directory).replaceAll("\\", "/") || ".")
|
||||
})
|
||||
|
||||
const enabled = () => location.vcs?.type === "git" && state.get().enabled
|
||||
|
||||
@@ -216,6 +216,58 @@ describe("Snapshot", () => {
|
||||
),
|
||||
)
|
||||
|
||||
testEffect(Layer.empty).live("captures and restores a Location opened through a symlinked path", () =>
|
||||
withTempDir((tmp) =>
|
||||
Effect.gen(function* () {
|
||||
const project = path.join(tmp.path, "project")
|
||||
const link = path.join(tmp.path, "link")
|
||||
yield* Effect.promise(async () => {
|
||||
await fs.mkdir(path.join(project, "scope"), { recursive: true })
|
||||
await fs.writeFile(path.join(project, "scope", "tracked.txt"), "one\n")
|
||||
await initGit(project)
|
||||
// A junction needs no privilege on Windows; other platforms ignore the type.
|
||||
await fs.symlink(project, link, "junction")
|
||||
})
|
||||
yield* Effect.gen(function* () {
|
||||
const snapshot = yield* Snapshot.Service
|
||||
const before = yield* snapshot.capture()
|
||||
yield* Effect.promise(() => fs.writeFile(path.join(link, "scope", "tracked.txt"), "two\n"))
|
||||
const after = yield* snapshot.capture()
|
||||
expect(before).toBeDefined()
|
||||
expect(after).toBeDefined()
|
||||
if (!before || !after) return
|
||||
expect(yield* snapshot.files({ from: before, to: after })).toEqual([RelativePath.make("scope/tracked.txt")])
|
||||
yield* snapshot.restore({ files: new Map([[RelativePath.make("scope/tracked.txt"), before]]) })
|
||||
expect(yield* read(path.join(project, "scope", "tracked.txt"))).toBe("one\n")
|
||||
}).pipe(Effect.provide(snapshotLayer(tmp.path, path.join(link, "scope"))))
|
||||
}),
|
||||
),
|
||||
)
|
||||
;(process.platform === "win32" ? testEffect(Layer.empty).live : testEffect(Layer.empty).live.skip)(
|
||||
"captures a Location opened with different letter case",
|
||||
() =>
|
||||
withTempDir((tmp) =>
|
||||
Effect.gen(function* () {
|
||||
const project = path.join(tmp.path, "project")
|
||||
yield* Effect.promise(async () => {
|
||||
await fs.mkdir(path.join(project, "scope"), { recursive: true })
|
||||
await fs.writeFile(path.join(project, "scope", "tracked.txt"), "one\n")
|
||||
await initGit(project)
|
||||
})
|
||||
yield* Effect.gen(function* () {
|
||||
const snapshot = yield* Snapshot.Service
|
||||
const before = yield* snapshot.capture()
|
||||
yield* Effect.promise(() => fs.writeFile(path.join(project, "scope", "tracked.txt"), "two\n"))
|
||||
const after = yield* snapshot.capture()
|
||||
expect(before).toBeDefined()
|
||||
expect(after).toBeDefined()
|
||||
if (!before || !after) return
|
||||
expect(yield* snapshot.files({ from: before, to: after })).toEqual([RelativePath.make("scope/tracked.txt")])
|
||||
}).pipe(Effect.provide(snapshotLayer(tmp.path, path.join(project, "SCOPE"))))
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
testEffect(Layer.empty).live("restores many files from several trees and removes paths absent from them", () =>
|
||||
withTempDir((tmp) =>
|
||||
Effect.gen(function* () {
|
||||
|
||||
Reference in New Issue
Block a user