-
Notifications
You must be signed in to change notification settings - Fork 24.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[local-cli] Support symlinks-to-symlinks #9792
Conversation
By analyzing the blame information on this pull request, we identified @Kureev to be a potential reviewer. |
Thanks for the PR. I'll let @Kureev take a look as he's added the symlink support (thank you for doing that!). |
So, recursive lookup for symlinks? Nice idea!
offtopic: haven't seen do...while for a errrm while already
|
IMHO, do {
symlink = path.resolve(process.cwd(), fs.readlinkSync(symlink));
} while (fs.lstatSync(symlink).isSymbolicLink()); is a bit harder to grasp than var recursiveSymlink;
while (fs.lstatSync(symlink).isSymbolicLink()) {
recursiveSymlink = path.resolve(process.cwd(), fs.readlinkSync(symlink))
}; this version has two improvements from my perspective:
Also, if you want to solve recursive symlink problem, you probably have to think about loops: What do you think, guys? Does it make any sense to you? |
@aleclarson updated the pull request - view changes |
|
||
prevSymlink = nextSymlink; | ||
nextSymlink = path.resolve( | ||
path.dirname(prevSymlink), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: Symlinks are now resolved relative to their parent directory. This is the correct behavior, because symlinks aren't aware of process.cwd()
and thus could be resolved into the wrong path.
const symlinkCache = new Set(); | ||
let prevSymlink; | ||
let nextSymlink = symlink; | ||
while (true) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
while (true)
is used here because we know for a fact that symlink
is a symlink.
At the end of each loop, !fs.lstatSync(nextSymlink).isSymbolicLink()
determines when to stop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not
while (fs.lstatSync(nextSymlink).isSymbolicLink()) {...}
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems redundant, no? We already do the filter
call to make sure only symlinks are present.
@Kureev Let me know what you think of the new changes. 😄 I'll squash the commits once everything is okay'd. |
let nextSymlink = symlink; | ||
while (true) { | ||
if (symlinkCache.has(nextSymlink)) { | ||
throw Error(`Symlink recursion detected:\n ${nextSymlink}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will be really great if we can throw an error with the whole sequence that leads to the recursion. Like "Symlink recursion detected: A -> B -> C -> B"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Truth. I'll just switch to using an Array
and then use slice
to get the relevant sequence.
Though it could get a little messy if the sequence is long.
In general, looks really good. I think we can merge it in once we agree on some minor details |
@aleclarson updated the pull request - view changes |
); | ||
} | ||
|
||
if (visited.length) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we no longer call folders.filter
to guarantee each item is a symlink, we need to protect against while (fs.lstatSync(symlink).isSymbolicLink())
doing zero loops.
if (index !== -1) { | ||
throw Error( | ||
`Infinite symlink recursion detected:\n ` + | ||
visited.slice(index).join(`\n `) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: This prints the symlink sequence in order, as opposed to being reversed.
Not sure which way is optimal, though.
@facebook-github-bot shipit |
Thank you for your contribution, @aleclarson! I think it's good to go now 👍 |
e27139a
to
165f1ba
Compare
@facebook-github-bot shipit |
Could you be so kind to take a look why import fails, @bestander? |
Thanks for importing. If you are an FB employee go to Phabricator to review internal test results. |
Will do |
I tried to merge this pull request into the Facebook internal repo but some checks failed. To unblock yourself please check the following: Does this pull request pass all open source tests on GitHub? If not please fix those. Does the code still apply cleanly on top of GitHub master? If not can please rebase. In all other cases this means some internal test failed, for example a part of a fb app won't work with this pull request. I've added the Import Failed label to this pull request so it is easy for someone at fb to find the pull request and check what failed. If you don't see anyone comment in a few days feel free to comment mentioning one of the core contributors to the project so they get a notification. |
This file was changed in #9819. |
- Throw an error for circular symlinks - Rename (and simplify) `isSubPathOfPath` to `isDescendant` - Rename `isSubPathOfPaths` to `rootExists` - Rename var `existingSearchPaths` to `ignoredRoots` - Squash symlink resolution into a single `forEach` - Pass both `args.projectRoots` and `args.root` to `findSymlinksPaths`
165f1ba
to
817f7f8
Compare
@aleclarson updated the pull request - view changes - changes since last import |
1 similar comment
@aleclarson updated the pull request - view changes - changes since last import |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! 👍
@facebook-github-bot shipit |
Thanks for importing. If you are an FB employee go to Phabricator to review internal test results. |
fa6191f
@aleclarson nice work! Sorry I was MIA for a bit on my other PR but then this came along 😄 . Stoked! |
I see this is closed, but symlinks are still not working for me. Did we have a regression? |
Summary: In response to [this comment](facebook/react-native#9009 (comment)). I could be wrong here, but I think Watchman can't handle symlinks, so we need to make sure symlinks-to-symlinks are handled up front. Closes facebook/react-native#9792 Differential Revision: D3858349 Pulled By: bestander fbshipit-source-id: f3a34dae90ed9a7004a03158288db5e1932bfc69
In response to this comment.
I could be wrong here, but I think Watchman can't handle symlinks, so we need to make sure symlinks-to-symlinks are handled up front.
edit: Here's a summary of the changes made by this commit:
forEach
lookupFolder
to resolvefolder
(instead ofprocess.cwd()
)isSubPathOfPath
function (and rename toisDescendant
)isSubPathOfPaths
function torootExists
existingSearchPaths
argument toignoredRoots
args.projectRoots
andargs.root
tofindSymlinksPaths