-
Notifications
You must be signed in to change notification settings - Fork 30k
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
lib: port rimraf to core as shutil.rmtree #28208
Conversation
not sure why this is labeled |
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 need the license from rimraf copied over
The bot added that label because the PR modifies |
@iansu I ticked the "tests are included" checkbox, since some tests are included, but unsure if you intended to add more? |
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.
Needs documentation. I assume it's not present because this is a work-in-progress and I will label it as such. If that's wrong, please comment.
I'm a-gonna ping @nodejs/tsc on this one because I'm pretty sure there will be strong opinions and lots of conversation. (Any links to existing previous conversations in the tooling group that might help us avoid rehashing stuff that's already been worked out might be useful.) |
nodejs/tooling#13 nodejs/tooling#23 and otherwise much discussion during meetings (in the |
to expand on "why the new module name", it's to clearly differentiate high-level fs operations (such as rimraf--mkdirp probably should have been done this way) from low-level, atomic operations (the entirety of |
Thanks for the detailed explanation in the description of the PR. Am I reading it correctly that the main reason to choose Also, if there are any comments that could be made that might pre-empt "why not |
Unfortunately, Fortunately, it's not widely-used nor actively-maintained. So creating an internal |
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.
IMO this should just be part of fs
, whether rmdir
recursive
or fs.rimraf
or something.
@Fishrock123, I'm in agreement with @sam-github (who commented on @zero1five's PR) and with @refack who encouraged using I personally wish it could be in a |
lib/internal/shutil.js
Outdated
@@ -0,0 +1,310 @@ | |||
'use strict'; |
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.
ISC license and copyright is missing, isn't it?
It's ISC for a reason, so you of course already have permission to take the code, as long as the copyright and permission stick around. If it's easier for Node.js to relicense it as MIT, that's probably doable.
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 wasn't sure about the correct way to incorporate them so that's why they're missing. It's on the todo list though.
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 it should be enough to add it to LICENSE
like this, no need to litter files with licensing comments.
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.
if we are going to vendor rimraf could we do it similarly to how we've vendored other modules. Please look at the experimental fetch PR for an example of how to do this (including the license)
Documentation and incorporating the rimraf license are on the todo list. There are some tests already but I'd like to port whatever we can from rimraf as well to cover as much as possible. |
I'm less opinionated on whether this should be in its own module, or some as-of-yet-unknown other namespace, or live in |
Just because it isn't just a fs operation at an os level doesn't mean that it shouldn't logically be grouped with other file system operations in order to be less confusing to users...
That's cool and all but it may be hard or impossible to move later. |
@iansu you might want to wait a bit before doing all the cleanup, it would be a shame to spend the time if it doesn't land. Not that I am predicting whether it will land or not, I don't know. I personally am an unapologetic fan of node+npm. I've used multiple languages with "batteries included" standard libraries. There is a short-term pleasure from having so much functionality immediately availlable, but I have watched them struggle to keep both backwards compatible and relevant over time. I think treating a registry (or federation of registries it that is what happens) as a semvered source of features is a strength of node, not a weakness. I prefer for node core to focus on runtime features that enable the ecosystem, rather than absorbing the ecosystem. I won't try to block this if its what people want, but for the record, I prefer it not to be. This doesn't do anything better than the external The sole benefit to node users is to avoid having to do I understand why non-node developers unfamiliar with an easy-to-use and powerful dependency management tool don't understand why node has a small builtin library, but I genuinely don't understand why node developers would be adverse to using |
Might be something for a future optimization but we can likely eliminate the extra What does |
@joyeecheung Thanks for pointing that out. I'm definitely in favour of using that if we're going to end up adding a |
Ah right right. Sorry, scratch what I've said about ISC, I was mentally confusing it with the Artistic License 2 that npm uses. ISC is perfectly fine but the other technical issues still stand :) |
@jasnell One issue at a time... 🙂 |
New core modules should NOT be added, pending the outcome of #21552. Separately this is a filesystem action - conceptually imo it belongs on fs, whether it’s a separate function or an option. |
The link to rimraf in the original post is broken btw Also I agree on not getting another core module The |
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 similarly -1 on a new module... I think this makes a ton of sense as an option to fs.rmdir
. We could still vendor rimraf to do so and use that code path when the option is passed.
I'd prefer to see vendored external code done explicitly, similar to how we've vendored eslint. Please take a look at my fetch PR for an example of how to vendor including updating the license and providing a script for future updates
lib/internal/shutil.js
Outdated
@@ -0,0 +1,310 @@ | |||
'use strict'; |
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.
if we are going to vendor rimraf could we do it similarly to how we've vendored other modules. Please look at the experimental fetch PR for an example of how to do this (including the license)
I'm not opposed to moving this into |
What about we call it |
@targos |
@MylesBorins The idea of vendoring I think long term the thinking was that |
I like the idea of a Regarding fork vs. vendoring: I think we want to fork given the reasons above as well as to open the way for further optimization (like removing |
Regarding Small Core@sam-github I care deeply about keeping encouraging a vibrant npm ecosystem. I'm in @sindresorhus' camp however, that there's a small minority of utility modules ( a tooling author almost always needs these dependencies (which has lead to dependency counts in the millions if you look on GitHub):
I don't think these numbers are a measure of popularity (in the same way that the community knows about a module like React, or WebPack) it's a measure of the fact that these modules are core building blocks for JavaScript infrastructure. Given that @isaacs is supportive of moving Regarding Naming ThingsIt sounds like folks are more in favor of an
And we can revisit whether we add a |
@bcoe I'm in favour of moving ahead with |
I don't think Node.js should have multiple ways to do the exact same thing. So we should go with either a
|
I'm still very bullish on making it an option. I also have significant reservations about doing a fork over vendoring. There obviously are extra bits that we may not want in core... but it is a much larger maintenance burden for us to keep that up to date and fix bugs, whereas if we simply vendor we can just work upstream and upgrade as neccessary. |
I spent some time this weekend working on vendoring Is there a strategy for handling this kind of thing with other vendored packages? Another option would be to patch I should also mention that I'm planning to move |
👍
I don't think |
@sindresorhus python uses rmtree, as does ruby, I think this is a reasonable compromise (even if underneath the hood the vendored package is
Let's work with @isaacs' and see if we can support this in an elegant way; I'm wondering if we could refactor A good place to get @isaacs' attention might be in this slack. |
I personally prefer the name Not having to make a patch and keep it updated is appealing. I will try reaching out to @isaacs on Slack. |
@isaacs published a new version of I've updated this PR to vendor If people are happy with this approach I'll be working on porting some of the existing |
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 OK with vendoring in rimraf, but I think it should be a one time thing.
- rimraf doesn't seem to require a lot of maintenance. It doesn't look like any of the changes in ~2 years would require changes to the vendored code.
- The source code is only 300-400 lines of JavaScript, which I expect the core team could easily maintain. If bugs are fixed in the rimraf module, I'm sure they would be cherry-picked.
- My biggest complaint - ongoing vendoring of rimraf would give a slightly inconsistent user experience, mainly around error handling. We've put in a lot of effort to rolling out a new error system, which wouldn't be part of the vendored code. We could also eliminate dead code, such as the handling of the glob dependency.
If no one wants to do the porting of the rimraf codebase to better fit into core, I'll happily take a shot at it.
@cjihrig porting rimraf to Node core was actually the approach I originally took in this PR. There was some criticism of that (I think rightly so). It's mostly in this thread but I think the main arguments were:
As far as this being a separate function or an option to |
Since #29168 has been merged I'm going to close this PR. |
The @nodejs/tooling group has been working on porting rimraf into Node.js Core: nodejs/tooling#13. We've spoken with @isaacs and this is done with his cooperation: iansu#1 (comment). We've chosen to implement this in a new module called
shutil
rather than adding it to the existingfs.rmdir
code. There seems to be interest in this as a similar PR was recently opened: #28171.1. Why?
rimraf
is one of the most popular third-party modules and is used in millions of projects. The Tooling Group thinks this kind of commonly used module should be included in Node.js Core and not require a third-party package.2. Why not add a
recursive
option tofs.rmdir
?By adding a flag rather than a new function feature detection becomes difficult. People have requested a way to detect the recursive option of
mkdir
for example.3. Why port
rimraf
directly?The
rimraf
code contains a number of workarounds for bugs and edge cases in platforms like Windows and sunos. These are the result of many issues and bugfixes over the years and we don't want to lose this functionality.4. Why
shutil
?The name itself comes from Python. Something like
rimraf
is not a filesystem primitive, instead it's an algorithm that is built on top of filesystem primitives. On other platforms these kind of utilities are often grouped under a "shell" namespace, and the Tooling team can imagine several additional utilities added to this module in the future.5. Why is this not implemented in C++?
Like the recursive mkdir operation, recursive rmdir is not atomic. Unlike recursive mkdir, the number of operations is not bounded by the directory depth; instead, it's one operation for each file and directory encountered. Recursive mkdir cannot run its operations in parallel, either; it must create directories in serial, in descending order.
Recursive rmdir, on the other hand, would benefit from removing files in parallel--userland rimraf takes this strategy to remove files quickly as libuv's fs thread pool can handle it. There's no precedent, AFAIK, for running batch operations across multiple libuv threads in Node.js core. The problem is compounded by the necessity to implement a synchronous version of the API; consider execSync's implementation.
Several attempts have been made at implementing recursive rmdir in C++, but none so far have executed these operations using multiple threads. Because of this, a serial C++ implementation is significantly slower (@boneskull benchmarked his own implementation against userland rimraf) than a parallel, JS implementation.
In addition, a C++ implementation would need to consider the workarounds for various filesystems to provide a builtin on-par with userland rimraf. So far, no C++ implementation has attempted this.
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesrimraf
license to combined license