Skip to content

Commit

Permalink
fix: allow type changes (e.g. replacing a file with a symlink)
Browse files Browse the repository at this point in the history
  • Loading branch information
stefreak committed Sep 25, 2024
1 parent b03c343 commit a55f485
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 3 deletions.
6 changes: 4 additions & 2 deletions core/src/build-staging/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,10 @@ export function cloneFile(
}
}

// if the target path exists, and it is a symlink, we must remove it first
if (toStats?.isSymbolicLink()) {
// if we are about to copy a symlink, and the target path exists, we must remove it first
// this allows for type changes (e.g. replacing a file with a symlink, then running garden build)
// at this point we know the target is a file or a symlink, so we can do this even if allowDelete=false (copy also overwrites the target)
if (fromStats.isSymbolicLink()) {
return remove(to, (removeErr) => {
if (removeErr) {
return done(removeErr)
Expand Down
21 changes: 20 additions & 1 deletion core/test/unit/src/build-staging/build-staging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { BuildTask } from "../../../../src/tasks/build.js"
import type { ConfigGraph } from "../../../../src/graph/config-graph.js"
import type { BuildAction } from "../../../../src/actions/build.js"
import { DOCS_BASE_URL } from "../../../../src/constants.js"
import { lstat, readlink, symlink } from "fs/promises"
import { lstat, readlink, rm, symlink } from "fs/promises"

// TODO-G2: rename test cases to match the new graph model semantics

Expand Down Expand Up @@ -189,6 +189,25 @@ describe("BuildStaging", () => {
await assertIdentical(sourceRoot, targetRoot, expectedFiles)
})

it("should allow type changes between symlink and file", async () => {
const sourceRoot = join(tmpPath, "source")
const targetRoot = join(tmpPath, "target")
const file = "foo"

await ensureDir(sourceRoot)
await populateDirectory(sourceRoot, [file])

await sync({ log, sourceRoot, targetRoot, withDelete: false })
await assertIdentical(sourceRoot, targetRoot, [file])

await rm(join(sourceRoot, file))
await symlink("targetDoesNotMatter", join(sourceRoot, file))

// the target now must be replaced with a symlink
await sync({ log, sourceRoot, targetRoot, withDelete: false })
await assertIdentical(sourceRoot, targetRoot, [file])
})

it("throws if source relative path is absolute", async () => {
await expectError(
() => sync({ log, sourceRoot: tmpPath, targetRoot: tmpPath, sourceRelPath: "/foo", withDelete: false }),
Expand Down

0 comments on commit a55f485

Please sign in to comment.