Skip to content

Commit

Permalink
fix #766: support recursive symlinks in resolver
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Feb 8, 2021
1 parent dbc35ad commit cdb8e64
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 16 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@

It would be a change in semantics to minify this code to either `--some-var:;` or `var(--some-var,)` due to the whitespace significance of CSS variables, so such transformations are invalid. With this release, esbuild should now preserve whitespace in these two situations (CSS variable declarations and CSS variable references).

* Add support for recursive symlinks during path resolution ([#766](https://github.com/evanw/esbuild/issues/766))

Previously recursive symlinks (a symlink that points to another symlink) were an unhandled case in the path resolution algorithm. Now these cases should be supported up to a depth of 256 symlinks. This means esbuild's path resolution should now work with multi-level `yarn link` scenarios.

## 0.8.42

* Fix crash with block-level function declaration and `--keep-names` ([#755](https://github.com/evanw/esbuild/issues/755))
Expand Down
41 changes: 25 additions & 16 deletions internal/fs/fs_real.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,23 +310,32 @@ func (fs *realFS) kind(dir string, base string) (symlink string, kind EntryKind)

// Follow symlinks now so the cache contains the translation
if (mode & os.ModeSymlink) != 0 {
link, err := os.Readlink(entryPath)
if err != nil {
return // Skip over this entry
}
if !fs.fp.isAbs(link) {
link = fs.fp.join([]string{dir, link})
}
symlink = fs.fp.clean(link)
symlink = entryPath
linksWalked := 0
for {
linksWalked++
if linksWalked > 255 {
return // Error: too many links
}
link, err := os.Readlink(symlink)
if err != nil {
return // Skip over this entry
}
if !fs.fp.isAbs(link) {
link = fs.fp.join([]string{dir, link})
}
symlink = fs.fp.clean(link)

// Re-run "lstat" on the symlink target
stat2, err2 := os.Lstat(symlink)
if err2 != nil {
return // Skip over this entry
}
mode = stat2.Mode()
if (mode & os.ModeSymlink) != 0 {
return // Symlink chains are not supported
// Re-run "lstat" on the symlink target
stat2, err2 := os.Lstat(symlink)
if err2 != nil {
return // Skip over this entry
}
mode = stat2.Mode()
if (mode & os.ModeSymlink) == 0 {
break
}
dir = fs.fp.dir(symlink)
}
}

Expand Down
19 changes: 19 additions & 0 deletions scripts/end-to-end-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,25 @@
`,
'c': { symlink: `a/b` },
}, { cwd: 'c' }),

// This is a test for https://github.com/evanw/esbuild/issues/766
test(['--bundle', 'impl/index.mjs', '--outfile=node.js', '--format=cjs'], {
'config/yarn/link/@monorepo-source/a': { symlink: `../../../../monorepo-source/packages/a` },
'config/yarn/link/@monorepo-source/b': { symlink: `../../../../monorepo-source/packages/b` },
'impl/node_modules/@monorepo-source/b': { symlink: `../../../config/yarn/link/@monorepo-source/b` },
'impl/index.mjs': `
import { fn } from '@monorepo-source/b';
if (fn() !== 123) throw 'fail';
`,
'monorepo-source/packages/a/index.mjs': `
export function foo() { return 123; }
`,
'monorepo-source/packages/b/node_modules/@monorepo-source/a': { symlink: `../../../../../config/yarn/link/@monorepo-source/a` },
'monorepo-source/packages/b/index.mjs': `
import { foo } from '@monorepo-source/a';
export function fn() { return foo(); }
`,
}),
)
}

Expand Down

0 comments on commit cdb8e64

Please sign in to comment.