Skip to content
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

refactor(mkdir): consistent error handling #854

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

nfischer
Copy link
Member

@nfischer nfischer commented Jun 3, 2018

This refactors mkdir() to (for the most part) invoke mkdirSync() and
catch any exceptions, instead of the error-prone approach of trying to
predict when specific errors would happen.

This adds two new tests for "name too long" and that it's OK to mkdir -p a directory which already exists. The latter was implicitly covered
by another test case, but this should be explicit.

Lastly, this changes error messages to be more consistent with Linux
mkdir, and adds the "avoid-escape" rule in the test directory to allow
using double-quoted strings when it aids readability.

Fixes #722

This refactors mkdir() to (for the most part) invoke mkdirSync() and
catch any exceptions, instead of the error-prone approach of trying to
predict when specific errors would happen.

This adds two new tests for "name too long" and that it's OK to `mkdir
-p` a directory which already exists. The latter was implicitly covered
by another test case, but this should be explicit.

Lastly, this changes error messages to be more consistent with Linux
mkdir, and adds the "avoid-escape" rule in the test directory to allow
using double-quoted strings when it aids readability.

Fixes #722
@nfischer nfischer added refactor bash compat Compatibility issues with bash or POSIX behavior breaking Breaking change labels Jun 3, 2018
@nfischer nfischer requested a review from freitagbr June 3, 2018 01:47
@nfischer
Copy link
Member Author

nfischer commented Jun 3, 2018

@freitagbr take a look, but this should probably be considered as a breaking change because it changes error messages.

@@ -51,29 +51,13 @@ function mkdirSyncRecursive(dir) {
function _mkdir(options, dirs) {
if (!dirs) common.error('no paths given');

if (typeof dirs === 'string') {
Copy link
Member Author

Choose a reason for hiding this comment

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

I think the type is always string. We introduced some code to flatten out arrays. Even in the case of ShellStrings, I think we also convert those into bare strings.

var reason;
if (e.code === 'EACCES') {
reason = 'Permission denied';
} else if (e.code === 'ENOTDIR' || e.code === 'ENOENT') {
Copy link
Member Author

Choose a reason for hiding this comment

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

I think ENOENT should be handled distinctly from ENOTDIR, not sure why they're in the same branch here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmmm this is weird. On unix, ENNOTDIR and ENOENT are for different reasons. On appveyor, I see ENOENT when part of the path is a regular file. Not sure yet how we should handle this.

Copy link
Contributor

Choose a reason for hiding this comment

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

Is this still causing the appveyor CI to fail?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes. I haven't fixed this yet.

src/mkdir.js Outdated
EEXIST: 'File exists',
ENAMETOOLONG: 'File name too long',
ENOENT: 'No such file or directory',
ENOTDIR: 'Not a directory',
Copy link
Member Author

Choose a reason for hiding this comment

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

I limited this to the list of error codes I could repro locally. I think that's fine for now, and we can add more later.

Copy link
Contributor

Choose a reason for hiding this comment

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

Is this enum something that should be declared globally? Perhaps in src/common.js?

Copy link
Member Author

Choose a reason for hiding this comment

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

Some of the error codes can be shared (e.g., EEXIST). However, there's no real advantage to moving these to common.js. It's the difference between common.codes.EEXIST and 'EEXIST'.

When it comes to user-facing error messages, I think each command wants a different message as it sees fit.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, makes sense. This enum could at least be declared globally in this file.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

@@ -11,6 +11,7 @@
"no-param-reassign": "off",
"no-console": "off",
"curly": "off",
"quotes": ["error", "single", "avoid-escape"],
Copy link
Member Author

Choose a reason for hiding this comment

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

Let me know if you'd like to promote this to the top-level config.

Copy link
Contributor

Choose a reason for hiding this comment

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

Are there any escaped quotes outside of test/? I can't find any in src/.

Copy link
Member Author

Choose a reason for hiding this comment

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

Guess there's not. Let's keep it here then.

@@ -145,6 +159,21 @@ test('-p flag', t => {
shell.rm('-Rf', `${t.context.tmp}/a`); // revert
});

test('create same dir twice with -p flag', t => {
Copy link
Member Author

Choose a reason for hiding this comment

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

This is implicitly covered in the "globbed dir" test, but this merits explicit coverage.

src/mkdir.js Outdated
EEXIST: 'File exists',
ENAMETOOLONG: 'File name too long',
ENOENT: 'No such file or directory',
ENOTDIR: 'Not a directory',
Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, makes sense. This enum could at least be declared globally in this file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bash compat Compatibility issues with bash or POSIX behavior breaking Breaking change refactor
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants