-
-
Notifications
You must be signed in to change notification settings - Fork 33.5k
fs: implement recursive (mkdirp) functionality #21875
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
Conversation
doc/api/fs.md
Outdated
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.
{Object|integer}
applies also to fs.mkdirSync and fsPromises.mkdir
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.
It's not clear that the integer value is still supported. It should.
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.
updating to rubys' suggestion of {Object|integer}, this was copy pasta on my part.
|
The design phase may be over, so I may have missed the boat. But I do find it surprising this implemented as a flag to This may just be familiarity with the existing patterns. But an explicit method, does have some value:
Ultimately, If I have to choose between it not existing, and being implemented as a flag. I would absolutely choose it existing as a flag. But I do believe my preference, if given the option, would be as a separate method. |
|
I would be curious, how this implementation compares performance wise to |
|
Also, I am super excited to see this be baked in! |
|
I agree with @stefanpenner in that I find If you continue down the road of |
|
Setting whether this should be in core aside (I am neural on this given how many times I need this in the user land), a few notes on the current design/implementation:
|
|
Sorry, missed the bits about C++ implementation in the OP
If I understand correctly this just DRYs the validation (but only if this is implemented as an option of EDIT: as for |
|
I'm the author of I don't think it should be a new method. The difference between I would be happy to donate |
src/node_file.cc
Outdated
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.
This has become an unrelated whitespace change :)
src/node_file.cc
Outdated
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.
I think the compiler could optimize the copy operation away here, but either way, it’s a bit more idiomatic to initialize this as FSContinuationData continuation_data(req, mode, cb); (i.e. without the assignment) 🙂
src/node_file.cc
Outdated
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.
style nit: new line for default (and/or just omit the break; and the braces here)
src/node_file.cc
Outdated
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.
I think this will lead to an infinite loop if there is no / or \ character?
This can happen if the current working directory does not exist anymore:
const fs = require('fs');
fs.mkdirSync('/tmp/foo');
process.chdir('/tmp/foo');
fs.rmdirSync('/tmp/foo');
fs.mkdirSync('X', { parent: 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.
added a test case for this.
src/node_file.cc
Outdated
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.
I just landed #21839 – can you use FSReqBase::from_req(req) here and below? :)
src/node_file.cc
Outdated
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
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.
we discussed out of band the problem with using req_wrap->Dispatch() and @addaleax and I came the the decision that using uv_fs_mkdir directly was sufficient.
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.
I think we need to call uv_fs_req_cleanup() after a uv_fs_mkdir call is done, but before we start the next one?
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.
I'm now calling uv_fs_req_cleanup() for all but the last fs operation, since it's called in the codebase already at the top level of the request wrap.
src/node_file.h
Outdated
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.
tiny style nit: We usually leave blank lines between methods
src/node_file.h
Outdated
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.
I think everywhere where this is called, the path parameter is not used afterwards in the caller. Currently, this creates a copy of path and then disposes the original – it might make sense to use std::string&& as the parameter and move the string rather than copying it? (i.e. use paths.emplace_back(std::move(path)); here and continuation_data->PushPath(std::move(str)); elsewhere)
src/node_file.h
Outdated
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.
Similarly, this also creates a copy but doesn’t really need to – I think path = std::move(paths.back()) works?
doc/api/fs.md
Outdated
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.
nit: there should be backticks around options here.
doc/api/fs.md
Outdated
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.
An example showing each variant would be nice.
doc/api/fs.md
Outdated
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.
Backticks around options here also.
lib/fs.js
Outdated
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.
likely should be 'options.parent' for the first argument here
src/node_file.cc
Outdated
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.
extreme nit: We generally put the body of if statements on a new line or within brackets.
|
Great to see this. Would like @addaleax's nits addressed then will sign off :-) |
|
If the current design is preserved. When we change a heading in the docs, we need to check if there are links to this outdated heading (to do so, copy the old hash from the old HTML doc and grep this hash in Currently, this fragment needs to be updated: https://github.com/nodejs/node/blame/6a99e3e21c5ce13eb079c5d29db4d4fe616802fc/doc/api/fs.md#L4630 |
doc/api/fs.md
Outdated
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.
A tiny nit: we usually add periods after the **Default:** ... parts only if they followed full sentences (the same for changes below).
test/parallel/test-fs-mkdir.js
Outdated
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.
Should this be something like ${tmpdir.path}/testX/testY/../
or even
${tmpdir.path}/testX/../testX/testY/
to make sure the directory created is under the temporary directory that gets cleaned up?
so that we know its creating
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.
I've updated both the ../ and ./ test accordingly, found a couple bugs in the process.
test/parallel/test-fs-promises.js
Outdated
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.
Should we have the ../ variant here as well.
|
Overall happy to see this, will sign off once comments from everybody so far have been addressed. |
|
@nodejs/fs |
|
@bcoe I'm all in favor of making this happen. Was there a public design phase by the way? I don't mind at all PRs coming in without it having been publicly discussed first, but now that it's here, the merits of one API over another should be discussed (if it hasn't happened yet). Could you link to some existing conversation if it exists? I'm with @joyeecheung that a pure JavaScript implementation would make sense, although performance may be reason to make an exception. A demonstration of performance would be nice; how does this implementation perform vs. a pure JS implementation that does the same operations? |
|
Based on nodejs/TSC#604, I'm removing the |
Implements mkdirp functionality in node_file.cc. The Benefit of implementing in C++ layer is that the logic is more easily shared between the Promise and callback implementation and there are notable performance improvements. This commit is part of the Tooling Group Initiative. Refs: nodejs/user-feedback#70 PR-URL: #21875 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Jon Moss <me@jonathanmoss.me> Reviewed-By: Ron Korving <ron@ronkorving.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Anatoli Papirovski <apapirovski@mac.com> Reviewed-By: Sam Ruby <rubys@intertwingly.net> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
|
Landed this and all others from #21875 (comment). |
Notable changes:
* assert
* The diff output is now a tiny bit improved by sorting object
properties when inspecting the values that are compared with each
other. #22788
* cli
* The options parser now normalizes `_` to `-` in all multi-word
command-line flags, e.g. `--no_warnings` has the same effect as
`--no-warnings`. #23020
* Added bash completion for the `node` binary. To generate a bash
completion script, run `node --completion-bash`. The output can be
saved to a file which can be sourced to enable completion.
#20713
* crypto
* Added support for PEM-level encryption.
#23151
* Added an API asymmetric key pair generation. The new methods
`crypto.generateKeyPair` and `crypto.generateKeyPairSync` can be
used to generate public and private key pairs. The API supports
RSA, DSA and EC and a variety of key encodings (both PEM and DER).
#22660
* fs
* Added a `recursive` option to `fs.mkdir` and `fs.mkdirSync`. If
this option is set to true, non-existing parent folders will be
automatically created. #21875
* http2
* Added a `'ping'` event to `Http2Session` that is emitted whenever a
non-ack `PING` is received.
#23009
* Added support for the `ORIGIN` frame.
#22956
* module
* Added `module.createRequireFromPath(filename)`. This new method can
be used to create a custom require function that will resolve
modules relative to the filename path.
#19360
* process
* Added a `'multipleResolves'` process event that is emitted whenever
a `Promise` is attempted to be resolved multiple times, e.g. if the
`resolve` and `reject` functions are both called in a `Promise`
executor. #22218
* **url**
* Added `url.fileURLToPath(url)` and `url.pathToFileURL(path)`. These
methods can be used to correctly convert between file: URLs and
absolute paths. #22506
* **util**
* Added the `sorted` option to `util.inspect()`. If set to `true`,
all properties of an object and Set and Map entries will be sorted
in the returned string. If set to a function, it is used as a
compare function. #22788
* The `util.instpect.custom` symbol is now defined in the global
symbol registry as `Symbol.for('nodejs.util.inspect.custom')`.
#20857
* **Windows**
* The Windows msi installer now provides an option to automatically
install the tools required to build native modules.
#22645
* **Added new collaborators**:
* digitalinfinity - Hitesh Kanwathirtha
PR-URL: #23313
Notable changes:
* assert
* The diff output is now a tiny bit improved by sorting object
properties when inspecting the values that are compared with each
other. #22788
* cli
* The options parser now normalizes `_` to `-` in all multi-word
command-line flags, e.g. `--no_warnings` has the same effect as
`--no-warnings`. #23020
* Added bash completion for the `node` binary. To generate a bash
completion script, run `node --completion-bash`. The output can be
saved to a file which can be sourced to enable completion.
#20713
* crypto
* Added support for PEM-level encryption.
#23151
* Added an API asymmetric key pair generation. The new methods
`crypto.generateKeyPair` and `crypto.generateKeyPairSync` can be
used to generate public and private key pairs. The API supports
RSA, DSA and EC and a variety of key encodings (both PEM and DER).
#22660
* fs
* Added a `recursive` option to `fs.mkdir` and `fs.mkdirSync`. If
this option is set to true, non-existing parent folders will be
automatically created. #21875
* http2
* Added a `'ping'` event to `Http2Session` that is emitted whenever a
non-ack `PING` is received.
#23009
* Added support for the `ORIGIN` frame.
#22956
* Updated nghttp2 to 1.34.0. This adds RFC 8441 extended connect
protocol support to allow use of WebSockets over HTTP/2.
#23284
* module
* Added `module.createRequireFromPath(filename)`. This new method can
be used to create a custom require function that will resolve
modules relative to the filename path.
#19360
* process
* Added a `'multipleResolves'` process event that is emitted whenever
a `Promise` is attempted to be resolved multiple times, e.g. if the
`resolve` and `reject` functions are both called in a `Promise`
executor. #22218
* url
* Added `url.fileURLToPath(url)` and `url.pathToFileURL(path)`. These
methods can be used to correctly convert between file: URLs and
absolute paths. #22506
* util
* Added the `sorted` option to `util.inspect()`. If set to `true`,
all properties of an object and Set and Map entries will be sorted
in the returned string. If set to a function, it is used as a
compare function. #22788
* The `util.instpect.custom` symbol is now defined in the global
symbol registry as `Symbol.for('nodejs.util.inspect.custom')`.
#20857
* Added support for `BigInt` numbers in `util.format()`.
#22097
* V8 API
* A number of V8 C++ APIs have been marked as deprecated since they
have been removed in the upstream repository. Replacement APIs
are added where necessary. #23159
* Windows
* The Windows msi installer now provides an option to automatically
install the tools required to build native modules.
#22645
* Workers
* Debugging support for Workers using the DevTools protocol has been
implemented. #21364
* The public `inspector` module is now enabled in Workers.
#22769
* Added new collaborators:
* digitalinfinity - Hitesh Kanwathirtha
PR-URL: #23313
Notable changes:
* assert
* The diff output is now a tiny bit improved by sorting object
properties when inspecting the values that are compared with each
other. #22788
* cli
* The options parser now normalizes `_` to `-` in all multi-word
command-line flags, e.g. `--no_warnings` has the same effect as
`--no-warnings`. #23020
* Added bash completion for the `node` binary. To generate a bash
completion script, run `node --completion-bash`. The output can be
saved to a file which can be sourced to enable completion.
#20713
* crypto
* Added support for PEM-level encryption.
#23151
* Added an API asymmetric key pair generation. The new methods
`crypto.generateKeyPair` and `crypto.generateKeyPairSync` can be
used to generate public and private key pairs. The API supports
RSA, DSA and EC and a variety of key encodings (both PEM and DER).
#22660
* fs
* Added a `recursive` option to `fs.mkdir` and `fs.mkdirSync`. If
this option is set to true, non-existing parent folders will be
automatically created. #21875
* http2
* Added a `'ping'` event to `Http2Session` that is emitted whenever a
non-ack `PING` is received.
#23009
* Added support for the `ORIGIN` frame.
#22956
* Updated nghttp2 to 1.34.0. This adds RFC 8441 extended connect
protocol support to allow use of WebSockets over HTTP/2.
#23284
* module
* Added `module.createRequireFromPath(filename)`. This new method can
be used to create a custom require function that will resolve
modules relative to the filename path.
#19360
* process
* Added a `'multipleResolves'` process event that is emitted whenever
a `Promise` is attempted to be resolved multiple times, e.g. if the
`resolve` and `reject` functions are both called in a `Promise`
executor. #22218
* url
* Added `url.fileURLToPath(url)` and `url.pathToFileURL(path)`. These
methods can be used to correctly convert between file: URLs and
absolute paths. #22506
* util
* Added the `sorted` option to `util.inspect()`. If set to `true`,
all properties of an object and Set and Map entries will be sorted
in the returned string. If set to a function, it is used as a
compare function. #22788
* The `util.instpect.custom` symbol is now defined in the global
symbol registry as `Symbol.for('nodejs.util.inspect.custom')`.
#20857
* Added support for `BigInt` numbers in `util.format()`.
#22097
* V8 API
* A number of V8 C++ APIs have been marked as deprecated since they
have been removed in the upstream repository. Replacement APIs
are added where necessary. #23159
* Windows
* The Windows msi installer now provides an option to automatically
install the tools required to build native modules.
#22645
* Workers
* Debugging support for Workers using the DevTools protocol has been
implemented. #21364
* The public `inspector` module is now enabled in Workers.
#22769
* Added new collaborators:
* digitalinfinity - Hitesh Kanwathirtha
PR-URL: #23313
Notable changes:
* assert
* The diff output is now a tiny bit improved by sorting object
properties when inspecting the values that are compared with each
other. #22788
* cli
* The options parser now normalizes `_` to `-` in all multi-word
command-line flags, e.g. `--no_warnings` has the same effect as
`--no-warnings`. #23020
* Added bash completion for the `node` binary. To generate a bash
completion script, run `node --completion-bash`. The output can be
saved to a file which can be sourced to enable completion.
#20713
* crypto
* Added support for PEM-level encryption.
#23151
* Added an API asymmetric key pair generation. The new methods
`crypto.generateKeyPair` and `crypto.generateKeyPairSync` can be
used to generate public and private key pairs. The API supports
RSA, DSA and EC and a variety of key encodings (both PEM and DER).
#22660
* fs
* Added a `recursive` option to `fs.mkdir` and `fs.mkdirSync`. If
this option is set to true, non-existing parent folders will be
automatically created. #21875
* http2
* Added a `'ping'` event to `Http2Session` that is emitted whenever a
non-ack `PING` is received.
#23009
* Added support for the `ORIGIN` frame.
#22956
* Updated nghttp2 to 1.34.0. This adds RFC 8441 extended connect
protocol support to allow use of WebSockets over HTTP/2.
#23284
* module
* Added `module.createRequireFromPath(filename)`. This new method can
be used to create a custom require function that will resolve
modules relative to the filename path.
#19360
* process
* Added a `'multipleResolves'` process event that is emitted whenever
a `Promise` is attempted to be resolved multiple times, e.g. if the
`resolve` and `reject` functions are both called in a `Promise`
executor. #22218
* url
* Added `url.fileURLToPath(url)` and `url.pathToFileURL(path)`. These
methods can be used to correctly convert between file: URLs and
absolute paths. #22506
* util
* Added the `sorted` option to `util.inspect()`. If set to `true`,
all properties of an object and Set and Map entries will be sorted
in the returned string. If set to a function, it is used as a
compare function. #22788
* The `util.instpect.custom` symbol is now defined in the global
symbol registry as `Symbol.for('nodejs.util.inspect.custom')`.
#20857
* Added support for `BigInt` numbers in `util.format()`.
#22097
* V8 API
* A number of V8 C++ APIs have been marked as deprecated since they
have been removed in the upstream repository. Replacement APIs
are added where necessary. #23159
* Windows
* The Windows msi installer now provides an option to automatically
install the tools required to build native modules.
#22645
* Workers
* Debugging support for Workers using the DevTools protocol has been
implemented. #21364
* The public `inspector` module is now enabled in Workers.
#22769
* Added new collaborators:
* digitalinfinity - Hitesh Kanwathirtha
PR-URL: #23313
Notable changes:
* assert
* The diff output is now a tiny bit improved by sorting object
properties when inspecting the values that are compared with each
other. #22788
* cli
* The options parser now normalizes `_` to `-` in all multi-word
command-line flags, e.g. `--no_warnings` has the same effect as
`--no-warnings`. #23020
* Added bash completion for the `node` binary. To generate a bash
completion script, run `node --completion-bash`. The output can be
saved to a file which can be sourced to enable completion.
#20713
* crypto
* Added support for PEM-level encryption.
#23151
* Added an API asymmetric key pair generation. The new methods
`crypto.generateKeyPair` and `crypto.generateKeyPairSync` can be
used to generate public and private key pairs. The API supports
RSA, DSA and EC and a variety of key encodings (both PEM and DER).
#22660
* fs
* Added a `recursive` option to `fs.mkdir` and `fs.mkdirSync`. If
this option is set to true, non-existing parent folders will be
automatically created. #21875
* http2
* Added a `'ping'` event to `Http2Session` that is emitted whenever a
non-ack `PING` is received.
#23009
* Added support for the `ORIGIN` frame.
#22956
* Updated nghttp2 to 1.34.0. This adds RFC 8441 extended connect
protocol support to allow use of WebSockets over HTTP/2.
#23284
* module
* Added `module.createRequireFromPath(filename)`. This new method can
be used to create a custom require function that will resolve
modules relative to the filename path.
#19360
* process
* Added a `'multipleResolves'` process event that is emitted whenever
a `Promise` is attempted to be resolved multiple times, e.g. if the
`resolve` and `reject` functions are both called in a `Promise`
executor. #22218
* url
* Added `url.fileURLToPath(url)` and `url.pathToFileURL(path)`. These
methods can be used to correctly convert between file: URLs and
absolute paths. #22506
* util
* Added the `sorted` option to `util.inspect()`. If set to `true`,
all properties of an object and Set and Map entries will be sorted
in the returned string. If set to a function, it is used as a
compare function. #22788
* The `util.instpect.custom` symbol is now defined in the global
symbol registry as `Symbol.for('nodejs.util.inspect.custom')`.
#20857
* Added support for `BigInt` numbers in `util.format()`.
#22097
* V8 API
* A number of V8 C++ APIs have been marked as deprecated since they
have been removed in the upstream repository. Replacement APIs
are added where necessary. #23159
* Windows
* The Windows msi installer now provides an option to automatically
install the tools required to build native modules.
#22645
* Workers
* Debugging support for Workers using the DevTools protocol has been
implemented. #21364
* The public `inspector` module is now enabled in Workers.
#22769
* Added new collaborators:
* digitalinfinity - Hitesh Kanwathirtha
PR-URL: #23313
I'm an advocate of a small core library (and this is a big part of why such an amazing ecosystem of modules has grown up around Node.js and JavaScript).
Having said this, I love the Tooling Group initiative being advocated by @boneskull; some modules are so prolific, and the behavior at this point in Node's history so standardized, that the functionality should probably simply be part of the core API.
Two great examples of this are
mkdirpandrimraf.mkdirpandrimrafget downloaded over8,000,000times a day, and are dependencies of some 250,000 applications on GitHub -- wow!.This pull request implements
mkdirpby adding aparent(make the parents) boolean option tomkdir,mkdirSync, andpromises.mkdirmethods.I've opted to implement the feature in C++ mainly because the codepath wasn't shared for
mkdirandpromises.mkdirand this felt like a good way to DRY things up a bit.Interested to hear what people think, and excited for future discussions around Node tooling.
CC: @stefanpenner, @cb1kenobi.
Checklist
make -j4 test(UNIX), orvcbuild test(Windows) passes