refactor(core): consolidate filesystem services (#30447)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { describe, expect } from "bun:test"
|
||||
import path from "path"
|
||||
import { Effect, Exit, Layer } from "effect"
|
||||
import { AppFileSystem } from "@opencode-ai/core/filesystem"
|
||||
import { FSUtil } from "@opencode-ai/core/fs-util"
|
||||
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
||||
import { Git } from "../../src/git"
|
||||
import { Global } from "@opencode-ai/core/global"
|
||||
@@ -11,11 +11,11 @@ import { testEffect } from "../lib/effect"
|
||||
|
||||
const dir = path.join(Global.Path.data, "storage")
|
||||
|
||||
const it = testEffect(Layer.mergeAll(Storage.defaultLayer, AppFileSystem.defaultLayer, CrossSpawnSpawner.defaultLayer))
|
||||
const it = testEffect(Layer.mergeAll(Storage.defaultLayer, FSUtil.defaultLayer, CrossSpawnSpawner.defaultLayer))
|
||||
|
||||
const scope = Effect.fnUntraced(function* () {
|
||||
const root = ["storage_test", crypto.randomUUID()]
|
||||
const fs = yield* AppFileSystem.Service
|
||||
const fs = yield* FSUtil.Service
|
||||
const svc = yield* Storage.Service
|
||||
yield* Effect.addFinalizer(() =>
|
||||
fs.remove(path.join(dir, ...root), { recursive: true, force: true }).pipe(Effect.ignore),
|
||||
@@ -24,10 +24,10 @@ const scope = Effect.fnUntraced(function* () {
|
||||
})
|
||||
|
||||
// remap(root) rewrites any path under Global.Path.data to live under `root` instead.
|
||||
// Used by remappedFs to build an AppFileSystem that Storage thinks is the real global
|
||||
// Used by remappedFs to build an FSUtil that Storage thinks is the real global
|
||||
// data dir but actually targets a tmp dir — letting migration tests stage legacy layouts.
|
||||
// NOTE: only the 6 methods below are intercepted. If Storage starts using a different
|
||||
// AppFileSystem method that touches Global.Path.data, add it here.
|
||||
// FSUtil method that touches Global.Path.data, add it here.
|
||||
function remap(root: string, file: string) {
|
||||
if (file === Global.Path.data) return root
|
||||
if (file.startsWith(Global.Path.data + path.sep)) return path.join(root, path.relative(Global.Path.data, file))
|
||||
@@ -36,10 +36,10 @@ function remap(root: string, file: string) {
|
||||
|
||||
function remappedFs(root: string) {
|
||||
return Layer.effect(
|
||||
AppFileSystem.Service,
|
||||
FSUtil.Service,
|
||||
Effect.gen(function* () {
|
||||
const fs = yield* AppFileSystem.Service
|
||||
return AppFileSystem.Service.of({
|
||||
const fs = yield* FSUtil.Service
|
||||
return FSUtil.Service.of({
|
||||
...fs,
|
||||
isDir: (file) => fs.isDir(remap(root, file)),
|
||||
readJson: (file) => fs.readJson(remap(root, file)),
|
||||
@@ -50,11 +50,11 @@ function remappedFs(root: string) {
|
||||
fs.glob(pattern, options?.cwd ? { ...options, cwd: remap(root, options.cwd) } : options),
|
||||
})
|
||||
}),
|
||||
).pipe(Layer.provide(AppFileSystem.defaultLayer))
|
||||
).pipe(Layer.provide(FSUtil.defaultLayer))
|
||||
}
|
||||
|
||||
// Layer.fresh forces a new Storage instance — without it, Effect's in-test layer cache
|
||||
// returns the outer testEffect's Storage (which uses the real AppFileSystem), not a new
|
||||
// returns the outer testEffect's Storage (which uses the real FSUtil), not a new
|
||||
// one built on top of remappedFs.
|
||||
const remappedStorage = (root: string) =>
|
||||
Layer.fresh(Storage.layer.pipe(Layer.provide(remappedFs(root)), Layer.provide(Git.defaultLayer)))
|
||||
@@ -191,7 +191,7 @@ describe("Storage", () => {
|
||||
|
||||
it.live("migration 2 runs when marker contents are invalid", () =>
|
||||
Effect.gen(function* () {
|
||||
const fs = yield* AppFileSystem.Service
|
||||
const fs = yield* FSUtil.Service
|
||||
const tmp = yield* tmpdirScoped()
|
||||
const storage = path.join(tmp, "storage")
|
||||
const diffs = [
|
||||
@@ -235,7 +235,7 @@ describe("Storage", () => {
|
||||
|
||||
it.live("migration 1 tolerates malformed legacy records", () =>
|
||||
Effect.gen(function* () {
|
||||
const fs = yield* AppFileSystem.Service
|
||||
const fs = yield* FSUtil.Service
|
||||
const tmp = yield* tmpdirScoped({ git: true })
|
||||
const storage = path.join(tmp, "storage")
|
||||
const legacy = path.join(tmp, "project", "legacy")
|
||||
@@ -277,7 +277,7 @@ describe("Storage", () => {
|
||||
|
||||
it.live("failed migrations do not advance the marker", () =>
|
||||
Effect.gen(function* () {
|
||||
const fs = yield* AppFileSystem.Service
|
||||
const fs = yield* FSUtil.Service
|
||||
const tmp = yield* tmpdirScoped()
|
||||
const storage = path.join(tmp, "storage")
|
||||
const legacy = path.join(tmp, "project", "legacy")
|
||||
|
||||
Reference in New Issue
Block a user