Skip to content

Conversation

sethamus
Copy link
Contributor

@sethamus sethamus commented Apr 22, 2025

Prerequisites checklist

What is the purpose of this pull request? (put an "X" next to an item)

[ ] Documentation update
[x] Bug fix (template)
[ ] New rule (template)
[ ] Changes an existing rule (template)
[ ] Add autofix to a rule
[ ] Add a CLI option
[ ] Add something to the core
[ ] Other, please explain:

What changes did you make? (Give an overview)

This PR modifies the cache file deletion logic to check if the cache file exists before attempting to delete it.

Closes #19647

Is there anything you'd like reviewers to focus on?

@sethamus sethamus requested a review from a team as a code owner April 22, 2025 16:01
@github-project-automation github-project-automation bot moved this to Needs Triage in Triage Apr 22, 2025
@eslint-github-bot eslint-github-bot bot added the bug ESLint is working incorrectly label Apr 22, 2025
@github-actions github-actions bot added cli Relates to ESLint's command-line interface core Relates to ESLint's core APIs and features labels Apr 22, 2025
Copy link

netlify bot commented Apr 22, 2025

Deploy Preview for docs-eslint canceled.

Name Link
🔨 Latest commit 0408ec3
🔍 Latest deploy log https://app.netlify.com/sites/docs-eslint/deploys/680d8738432ee70008ad4ae4

@sethamus sethamus marked this pull request as draft April 22, 2025 16:02
@mdjermanovic mdjermanovic added accepted There is consensus among the team that this change meets the criteria for inclusion contributor pool labels Apr 22, 2025
@mdjermanovic mdjermanovic moved this from Needs Triage to Implementing in Triage Apr 22, 2025
@sethamus sethamus marked this pull request as ready for review April 22, 2025 16:37
@sethamus
Copy link
Contributor Author

CI is failing because of this PR

@mdjermanovic
Copy link
Member

CI is failing because of this PR

It's passing now, seems like it has been fixed by another PR.

@sethamus
Copy link
Contributor Author

Yeah he reverted the change and released a new version 🎉

fsp.unlink.calledWithExactly(cacheFilePath),
fsp.unlink.notCalled,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, for this particular test case, we'd now need the cache file to exist, and write another test for the change made in this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But if the cache file existed then it will throw an error? I pushed a test case to demonstrate this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it generally should throw an error, but when we set unlink to throw EROFS, we're simulating the case where the cache file has been removed in the meantime (assuming we want to keep supporting that scenario, as being discussed in #19648 (comment)), in which case it shouldn't throw.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see now. We should additionally make sure that the file has been removed if we want to test the code in catch.

Comment on lines 705 to 709
try {
await fs.unlink(cacheFilePath);
if (existsSync(cacheFilePath)) {
await fs.unlink(cacheFilePath);
}
} catch (error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if the try-catch is still necessary after this change. It looks like the situations the catch block was intended to address—when the cache file was missing on a writable file system or when it was missing on a read-only file system—are now both handled by the existsSync check.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first version of this code (in cli-engine.js) was actually a simple if (!options.cache && fs.existsSync(cacheFile)) { fs.unlinkSync(cacheFile); } without try-catch, but has been changed to the try-catch version in #11546, I believe for the reasons explained in #11946 (comment) in a later PR (the original commit is gone, but it seems the comment is under code that was intending to remove try-catch). My understanding of the reasoning is that if it happens that the cache file disappears between two fs commands, this should not throw an error.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding of the reasoning is that if it happens that the cache file disappears between two fs commands, this should not throw an error.

Yes, I also think that's what that comment is saying. I was actually considering that the existsSync check will skip nearly all cases where unlink would currently reject with an error, including, but not limited, to those tested in the try-catch block. So for example existsSync will return false if a user has no permission to read a directory, or if a network drive is not found on Windows, or if an I/O error (e.g. a hardware problem) occurs, etc. By contrast, unlink rejects with different error codes in all these cases. This means that by checking existsSync in advance as it's done in this PR, these cases will no longer produce an error. It seems redundant at this point to test for error codes ENOENT and EROFS specifically in the catch block, when other errors are supposed to be swallowed as well. If a concern is that the file system could change during fs calls then maybe we could repeat the existsSync in the catch block:

			try {
				if (existsSync(cacheFilePath)) {
					await fs.unlink(cacheFilePath);
				}
			} catch (error) {
				if (existsSync(cacheFilePath)) {
					throw error;
				}
			}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My opinion aligns with fasttime's entirely.

Copy link
Member

@fasttime fasttime left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM if we want to catch race conditions when attempting to delete the file. Leaving open for @mdjermanovic to review.

@sethamus sethamus requested a review from mdjermanovic April 30, 2025 04:55
Copy link
Member

@mdjermanovic mdjermanovic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

@mdjermanovic mdjermanovic merged commit 96e84de into eslint:main May 2, 2025
31 checks passed
@github-project-automation github-project-automation bot moved this from Implementing to Complete in Triage May 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accepted There is consensus among the team that this change meets the criteria for inclusion bug ESLint is working incorrectly cli Relates to ESLint's command-line interface contributor pool core Relates to ESLint's core APIs and features
Projects
Status: Complete
Development

Successfully merging this pull request may close these issues.

Bug: ESLint crashes with --permission when it tries to delete cache
3 participants