-
Notifications
You must be signed in to change notification settings - Fork 29.7k
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
fs: expose Stats times as Numbers #13173
Conversation
test/parallel/test-fs-stat.js
Outdated
})); | ||
|
||
fs.stat(__filename, common.mustCall(function(err, s) { | ||
const json = JSON.parse(JSON.stringify(s)); | ||
const deJsoned = JSON.parse(JSON.stringify(s)); |
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: I think just parsed
or similar would be a better variable name.
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.
Ack
test/parallel/test-fs-stat.js
Outdated
@@ -102,22 +102,26 @@ fs.stat(__filename, common.mustCall(function(err, s) { | |||
assert.ok(s.mtime instanceof Date); | |||
assert.ok(s.ctime instanceof Date); | |||
assert.ok(s.birthtime instanceof Date); | |||
assert.strictEqual(typeof s.atime_msec, "number"); |
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.
Single quotes should be used for string literals.
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.
These tests are failing because they're using "atime_msec" rather than "atim_msec", btw.
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.
Ack. (actual lint)
lib/fs.js
Outdated
this._mtim_msec = mtim_msec; | ||
this._ctim_msec = ctim_msec; | ||
this._birthtim_msec = birthtim_msec; | ||
this.atim_msec = atim_msec; |
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.
Also, can we change these names to add the missing 'e' (e.g. atim_msec
-> atime_msec
)?
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 feel like snake_case is pretty uncommon in node, so should maybe be changed.. but mtimeMsec
is kinda ugly, so I'm not going to suggest it.
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 agree and tend to favor camel-case for js stuff, but I'm not sure about it in this case. I guess it's because the second part is an abbreviation. mtimeMs
looks a little better 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.
Just so you know, this is/was named this way because it derives from the POSIX stat
struct that has existed with these names for a long time; I think it’s okay to keep the underscore here.
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.
isn't posix just atim, mtim and ctim? but sure, timespec has tv_nsec etc.. and it doesn't matter.
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 guess, yeah. If you want to go with mtimeMs
, I’m not going to stand in your way or anything :)
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.
@refack can decide, i'm good with whatever he prefers.
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.
ack
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've had the posix/non-posix discussion before for another feature in core, although I think that PR ended up dying because we couldn't decide ;-)
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.
Went with camelCase Ms
suffix.
LGTM once @mscdex’s comments have been addressed. Also, CI failure (I assume that would fail with a local
|
lib/fs.js
Outdated
atime_msec: this.atime, | ||
ctime_msec: this.ctime, | ||
mtime_msec: this.mtime, | ||
birthtime_msec: this.birthtime, |
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 these not get this.birthtim_msec
etc instead of the Date
values?
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.
Yep, they should be birthtime_msec
, etc.
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.
atime_msec: this._atime || atime_msec: this.atime
would be better?`
Ack
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 just be, atime_msec: this.atime_msec,
, I think? this is in the toJSON
function, so I figure it should just expose that value.
@addaleax Sorry I didn't label this |
doc/api/fs.md
Outdated
@@ -959,7 +968,7 @@ The "not recommended" examples above check for existence and then use the | |||
file; the "recommended" examples are better because they use the file directly | |||
and handle the error, if any. | |||
|
|||
In general, check for the existence of a file only if the file won’t be | |||
In general, check for the existence of a file only if the file won?t be |
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'll fix this after the CI passes
doc/api/fs.md
Outdated
@@ -527,7 +536,7 @@ The "not recommended" examples above check for accessibility and then use the | |||
file; the "recommended" examples are better because they use the file directly | |||
and handle the error, if any. | |||
|
|||
In general, check for the accessibility of a file only if the file won’t be | |||
In general, check for the accessibility of a file only if the file won?t be |
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.
ditto
test/parallel/test-fs-stat.js
Outdated
k + ' should not be null or undefined' | ||
); | ||
}); | ||
|
||
const newFields = ['atimeMs', 'mtimeMs', 'ctimeMs', 'birthtimeMs']; |
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.
Really tiny nit, but could you pick a different name for this variable.
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 the name I came up with is numerFields
I decided to add all the number fields, so 👍
test/parallel/test-fs-stat.js
Outdated
|
||
const newFields = ['atimeMs', 'mtimeMs', 'ctimeMs', 'birthtimeMs']; | ||
newFields.forEach(function(k) { | ||
assert.strictEqual(typeof s.birthtimeMs, 'number', `${k} should a number`); |
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 a" -> "should be a"
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.
Ack.
But we both missed the bug: typeof s.birthtimeMs
was not parameterized 🤦♂️
doc/api/fs.md
Outdated
atimeMs: 1495555358452, | ||
mtimeMs: 1495571896565, | ||
ctimeMs: 1495571896565, | ||
birthtimeMs: 1491689434171, |
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.
These values don't agree with the Date-based fields shown below here.
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.
Ack.
But that's a very nice nit 😄
doc/api/fs.md
Outdated
any comparison, however there are additional methods which can be used for | ||
displaying fuzzy information. More details can be found in the | ||
[MDN JavaScript Reference][MDN-Date] page. | ||
*Note*: `atime`, `mtime`, `birthtime`, and `ctime` are instances of |
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: s/instances of/instances of 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.
Ack.
(That was there before, I just had to rewrap because of **Note:**
)
doc/api/fs.md
Outdated
[MDN JavaScript Reference][MDN-Date] page. | ||
*Note*: `atime`, `mtime`, `birthtime`, and `ctime` are instances of | ||
[`Date`][MDN-Date] object and appropriate methods should be used to compare the | ||
values of these objects. For most general uses [`getTime()`][MDN-Date-getTime] |
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.
Perhaps this note about using .getTime()
on the Date
-based fields should be changed to suggest using the .*Ms
fields instead.
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.
Or maybe this whole paragraph should be rewritten to make note of the .*Ms
fields first and then simply say that the non--Ms
fields are simply Date
s that use the .*Ms
values? Hopefully that would simplify the wording a bit?
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.
Working on it.
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.
But Date
s are easier to mutate, hence the bug.
doc/api/fs.md
Outdated
UTC_ and this integer should be sufficient for any comparison, however there are | ||
additional methods which can be used for displaying fuzzy information. More | ||
details can be found in the [MDN JavaScript Reference][MDN-Date] page. | ||
`atimeMs`, `mtimeMs`, `ctimeMs`, `birthtimeMs` are of [numbers][MDN-Number] |
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.
s/of//
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.
Ack
doc/api/fs.md
Outdated
additional methods which can be used for displaying fuzzy information. More | ||
details can be found in the [MDN JavaScript Reference][MDN-Date] page. | ||
`atimeMs`, `mtimeMs`, `ctimeMs`, `birthtimeMs` are of [numbers][MDN-Number] | ||
that hold the corresponding times. Their precision is platform specific. |
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.
s/times/times in milliseconds/.
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.
Ack
lib/fs.js
Outdated
ctimeMs: this.ctimeMs, | ||
mtimeMs: this.mtimeMs, | ||
birthtimeMs: this.birthtimeMs, | ||
atime: this._ctime || this.atime, |
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 isn't right. We should have tests to cover these to make sure the fields are what they should be.
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.
Removed this low quality optimization all together.
@mscdex and others. I've found a design bug: set(value) {
this.atimeMs = Number(value);
return this._atime = value;
} but mutations like const old = s.mtime;
s.mtimeMs = newValue;
s.mtimeMs !== s.mtime;
s.mtime === old; |
I would just make note of it in the documentation that they are not linked together and are merely separate values that are initialized using the same set of data. Making the |
Just realized that we don't accept a |
573025e
to
c1210b4
Compare
lib/fs.js
Outdated
}, | ||
set(value) { return this._ctime = value; } | ||
set(value) { | ||
this.ctimeMs = Number(value); |
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 don't think this is a good idea since we don't update _ctime
when ctimeMs
is changed by end users and as I mentioned earlier, setting up a getter and setter for each number field to be able to do bidirectional updating is going to add noticeable overhead.
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.
So you suggest break the connection completely, instead of this one way idiosyncrasy?
... thinking ...
Ok. Makes sense. (also congruent with the Note:)
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.
Yes, that is what I'm suggesting.
lib/fs.js
Outdated
[util.inspect.custom]: { | ||
configurable: true, | ||
enumerable: false, | ||
value: function() {return this.toJSON();} |
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 pretty sure the linter complains about this; also, prefer the value() { return this.toJSON(); }
shorthand
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 doesn't, but Ack.
I wanted to ask about the general approach of adding a [util.inspect.custom], is it Ok?
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 wanted to ask about the general approach of adding a [util.inspect.custom], is it Ok?
Yes, I think that makes sense.
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.
P.S. shorthand form lexical binds this
so it should be linted for.
|
"Dry run" CI:https://ci.nodejs.org/job/node-test-commit/10276/ |
ping @mscdex @sciolist @thefourtheye @cjihrig @addaleax |
LGTM if CI is ok: https://ci.nodejs.org/job/node-test-pull-request/8494/ |
d8525d7
to
cedc47d
Compare
PR-URL: nodejs#13173 Fixes: nodejs#8276 Refs: nodejs#12607 Refs: nodejs#12818 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Brian White <mscdex@mscdex.net>
cedc47d
to
47b9772
Compare
Landed in 47b9772 |
Extra sanity run on |
* **Async Hooks** * When one `Promise` leads to the creation of a new `Promise`, the parent `Promise` will be identified as the trigger [[`135f4e6643`](nodejs@135f4e6643)] [nodejs#13367](nodejs#13367). * **Dependencies** * libuv has been updated to 1.12.0 [[`968596ec77`](nodejs@968596ec77)] [nodejs#13306](nodejs#13306). * npm has been updated to 5.0.3 [[`ffa7debd7a`](nodejs@ffa7debd7a)] [nodejs#13487](nodejs#13487). * **File system** * The `fs.exists()` function now works correctly with `util.promisify()` [[`6e0eccd7a1`](nodejs@6e0eccd7a1)] [nodejs#13316](nodejs#13316). * fs.Stats times are now also available as numbers [[`c756efb25a`](nodejs@c756efb25a)] [nodejs#13173](nodejs#13173). * **Inspector** * It is now possible to bind to a random port using `--inspect=0` [[`cc6ec2fb27`](nodejs@cc6ec2fb27)] [nodejs#5025](nodejs#5025). * **Zlib** * A regression in the Zlib module that made it impossible to properly subclasses `zlib.Deflate` and other Zlib classes has been fixed. [[`6aeb555cc4`](nodejs@6aeb555cc4)] [nodejs#13374](nodejs#13374).
* **Async Hooks** * When one `Promise` leads to the creation of a new `Promise`, the parent `Promise` will be identified as the trigger [[`135f4e6643`](135f4e6643)] [#13367](#13367). * **Dependencies** * libuv has been updated to 1.12.0 [[`968596ec77`](968596ec77)] [#13306](#13306). * npm has been updated to 5.0.3 [[`ffa7debd7a`](ffa7debd7a)] [#13487](#13487). * **File system** * The `fs.exists()` function now works correctly with `util.promisify()` [[`6e0eccd7a1`](6e0eccd7a1)] [#13316](#13316). * fs.Stats times are now also available as numbers [[`c756efb25a`](c756efb25a)] [#13173](#13173). * **Inspector** * It is now possible to bind to a random port using `--inspect=0` [[`cc6ec2fb27`](cc6ec2fb27)] [#5025](#5025). * **Zlib** * A regression in the Zlib module that made it impossible to properly subclasses `zlib.Deflate` and other Zlib classes has been fixed. [[`6aeb555cc4`](6aeb555cc4)] [#13374](#13374).
* **Async Hooks** * When one `Promise` leads to the creation of a new `Promise`, the parent `Promise` will be identified as the trigger [[`135f4e6643`](135f4e6643)] [#13367](#13367). * **Dependencies** * libuv has been updated to 1.12.0 [[`968596ec77`](968596ec77)] [#13306](#13306). * npm has been updated to 5.0.3 [[`ffa7debd7a`](ffa7debd7a)] [#13487](#13487). * **File system** * The `fs.exists()` function now works correctly with `util.promisify()` [[`6e0eccd7a1`](6e0eccd7a1)] [#13316](#13316). * fs.Stats times are now also available as numbers [[`c756efb25a`](c756efb25a)] [#13173](#13173). * **Inspector** * It is now possible to bind to a random port using `--inspect=0` [[`cc6ec2fb27`](cc6ec2fb27)] [#5025](#5025). * **Zlib** * A regression in the Zlib module that made it impossible to properly subclasses `zlib.Deflate` and other Zlib classes has been fixed. [[`6aeb555cc4`](6aeb555cc4)] [#13374](#13374).
@nodejs/lts should we backport this to v6.x in a future minor? |
This is a follow-on to #12818, which is semver-major, so unbackportable. But, this PR seems to try to make things more "backwards" compatible, right, by adding accessor properties? I think doing that kind of thing has itself been considered semver-major in the past. Or perhaps I'm a bit lost in all the related issues, and also don't have time to read the epic commentary on this PR. @refack what is the case for this being safe to backport? what are its dependent PRs, if any? |
It's not based on #12818, there just used to be a reference to it in some documentation. #12818 was reverted as it caused issues that were likely not fixable. This PR indirectly depends on #13281 and #12607. (It will work without them, just won't be very useful.) What it does is expose a few extra numbers on the Stats object, I don't think there's much reason to believe it's unsafe. |
@nodejs/lts Adding fields to a object returned by node (stats) could confuse some existing code if it was very poorly written, but it is good to keep API continuity between 6.x and later. I think I'm +1. What do you all think? |
Expose Stats times as Numbers
also set Date cache fields in constructor
Fixes: #8276
Fixes: npm/npm#16734
Ref: #12607
Ref: #12818
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
fs