|
@@ -33,9 +33,11 @@ export type Resolved =
|
|
|
type State = {
|
|
type State = {
|
|
|
references: Resolved[]
|
|
references: Resolved[]
|
|
|
materializeAll: Effect.Effect<void>
|
|
materializeAll: Effect.Effect<void>
|
|
|
- materializeByPath: { path: string; run: Effect.Effect<void> }[]
|
|
|
|
|
|
|
+ materializeByPath: Materializer[]
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+type Materializer = { path: string; run: Effect.Effect<void> }
|
|
|
|
|
+
|
|
|
export interface Interface {
|
|
export interface Interface {
|
|
|
readonly init: () => Effect.Effect<void>
|
|
readonly init: () => Effect.Effect<void>
|
|
|
readonly list: () => Effect.Effect<Resolved[]>
|
|
readonly list: () => Effect.Effect<Resolved[]>
|
|
@@ -88,6 +90,59 @@ function containsReferencePath(referencePath: string, target: string) {
|
|
|
return AppFileSystem.contains(normalizedTarget(referencePath) ?? referencePath, target)
|
|
return AppFileSystem.contains(normalizedTarget(referencePath) ?? referencePath, target)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+function uniqueGitReferences(references: Resolved[]) {
|
|
|
|
|
+ const seenPath = new Set<string>()
|
|
|
|
|
+ return references.filter((reference): reference is Extract<Resolved, { kind: "git" }> => {
|
|
|
|
|
+ if (reference.kind !== "git") return false
|
|
|
|
|
+ if (seenPath.has(reference.path)) return false
|
|
|
|
|
+ seenPath.add(reference.path)
|
|
|
|
|
+ return true
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function materializeReference(cache: RepositoryCache.Interface, reference: Extract<Resolved, { kind: "git" }>) {
|
|
|
|
|
+ return cache.ensure({ reference: reference.reference, branch: reference.branch, refresh: true }).pipe(
|
|
|
|
|
+ Effect.asVoid,
|
|
|
|
|
+ Effect.catchCause((cause) =>
|
|
|
|
|
+ Effect.logWarning("failed to materialize reference repository").pipe(
|
|
|
|
|
+ Effect.annotateLogs({ name: reference.name, cause }),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ )
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const materializers = Effect.fn("Reference.materializers")(function* (
|
|
|
|
|
+ cache: RepositoryCache.Interface,
|
|
|
|
|
+ references: Resolved[],
|
|
|
|
|
+) {
|
|
|
|
|
+ return yield* Effect.forEach(
|
|
|
|
|
+ uniqueGitReferences(references),
|
|
|
|
|
+ Effect.fnUntraced(function* (reference) {
|
|
|
|
|
+ return { path: reference.path, run: yield* Effect.cached(materializeReference(cache, reference)) }
|
|
|
|
|
+ }),
|
|
|
|
|
+ { concurrency: "unbounded" },
|
|
|
|
|
+ )
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+function materializeAll(input: { flags: RuntimeFlags.Info; materializers: Materializer[] }) {
|
|
|
|
|
+ if (!input.flags.experimentalScout) return Effect.void
|
|
|
|
|
+ return Effect.forEach(
|
|
|
|
|
+ input.materializers,
|
|
|
|
|
+ Effect.fnUntraced(function* (item) {
|
|
|
|
|
+ yield* item.run
|
|
|
|
|
+ }),
|
|
|
|
|
+ { concurrency: 4, discard: true },
|
|
|
|
|
+ )
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function materializeByPath(materializers: Materializer[], target: string) {
|
|
|
|
|
+ return materializers.find((item) => containsReferencePath(item.path, target))?.run ?? Effect.void
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function containsGitReferencePath(references: Resolved[], target: string) {
|
|
|
|
|
+ return references.some((reference) => reference.kind === "git" && containsReferencePath(reference.path, target))
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
export function resolve(input: {
|
|
export function resolve(input: {
|
|
|
name: string
|
|
name: string
|
|
|
reference: ConfigReference.NormalizedEntry
|
|
reference: ConfigReference.NormalizedEntry
|
|
@@ -141,46 +196,10 @@ export const layer = Layer.effect(
|
|
|
directory: ctx.directory,
|
|
directory: ctx.directory,
|
|
|
worktree: ctx.worktree,
|
|
worktree: ctx.worktree,
|
|
|
})
|
|
})
|
|
|
- const seenPath = new Set<string>()
|
|
|
|
|
- const gitReferences = references.filter((reference): reference is Extract<Resolved, { kind: "git" }> => {
|
|
|
|
|
- if (reference.kind !== "git") return false
|
|
|
|
|
- if (seenPath.has(reference.path)) return false
|
|
|
|
|
- seenPath.add(reference.path)
|
|
|
|
|
- return true
|
|
|
|
|
- })
|
|
|
|
|
- const materializeByPath = yield* Effect.forEach(
|
|
|
|
|
- gitReferences,
|
|
|
|
|
- Effect.fnUntraced(function* (reference) {
|
|
|
|
|
- const run = yield* Effect.cached(
|
|
|
|
|
- cache.ensure({ reference: reference.reference, branch: reference.branch, refresh: true }).pipe(
|
|
|
|
|
- Effect.asVoid,
|
|
|
|
|
- Effect.catchCause((cause) =>
|
|
|
|
|
- Effect.logWarning("failed to materialize reference repository").pipe(
|
|
|
|
|
- Effect.annotateLogs({ name: reference.name, cause }),
|
|
|
|
|
- ),
|
|
|
|
|
- ),
|
|
|
|
|
- ),
|
|
|
|
|
- )
|
|
|
|
|
- return { path: reference.path, run }
|
|
|
|
|
- }),
|
|
|
|
|
- { concurrency: "unbounded" },
|
|
|
|
|
- )
|
|
|
|
|
-
|
|
|
|
|
- const materializeAll = yield* Effect.cached(
|
|
|
|
|
- flags.experimentalScout
|
|
|
|
|
- ? Effect.gen(function* () {
|
|
|
|
|
- yield* Effect.forEach(
|
|
|
|
|
- materializeByPath,
|
|
|
|
|
- Effect.fnUntraced(function* (item) {
|
|
|
|
|
- yield* item.run
|
|
|
|
|
- }),
|
|
|
|
|
- { concurrency: 4, discard: true },
|
|
|
|
|
- )
|
|
|
|
|
- })
|
|
|
|
|
- : Effect.void,
|
|
|
|
|
- )
|
|
|
|
|
-
|
|
|
|
|
- return { references, materializeAll, materializeByPath }
|
|
|
|
|
|
|
+ const materializeByPath = yield* materializers(cache, references)
|
|
|
|
|
+ const materializeAllCached = yield* Effect.cached(materializeAll({ flags, materializers: materializeByPath }))
|
|
|
|
|
+
|
|
|
|
|
+ return { references, materializeAll: materializeAllCached, materializeByPath }
|
|
|
}),
|
|
}),
|
|
|
)
|
|
)
|
|
|
|
|
|
|
@@ -199,18 +218,13 @@ export const layer = Layer.effect(
|
|
|
if (!flags.experimentalScout) return
|
|
if (!flags.experimentalScout) return
|
|
|
const full = normalizedTarget(target)
|
|
const full = normalizedTarget(target)
|
|
|
if (!full) return yield* InstanceState.useEffect(state, (s) => s.materializeAll)
|
|
if (!full) return yield* InstanceState.useEffect(state, (s) => s.materializeAll)
|
|
|
- return yield* InstanceState.useEffect(
|
|
|
|
|
- state,
|
|
|
|
|
- (s) => s.materializeByPath.find((item) => containsReferencePath(item.path, full))?.run ?? Effect.void,
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ return yield* InstanceState.useEffect(state, (s) => materializeByPath(s.materializeByPath, full))
|
|
|
}),
|
|
}),
|
|
|
contains: Effect.fn("Reference.contains")(function* (target?: string) {
|
|
contains: Effect.fn("Reference.contains")(function* (target?: string) {
|
|
|
if (!flags.experimentalScout) return false
|
|
if (!flags.experimentalScout) return false
|
|
|
const full = normalizedTarget(target)
|
|
const full = normalizedTarget(target)
|
|
|
if (!full) return false
|
|
if (!full) return false
|
|
|
- return yield* InstanceState.use(state, (s) =>
|
|
|
|
|
- s.references.some((reference) => reference.kind === "git" && containsReferencePath(reference.path, full)),
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ return yield* InstanceState.use(state, (s) => containsGitReferencePath(s.references, full))
|
|
|
}),
|
|
}),
|
|
|
})
|
|
})
|
|
|
}),
|
|
}),
|