-
-
Notifications
You must be signed in to change notification settings - Fork 22
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
Add progress reporting #9
Conversation
Tests pass locally without |
var remains = progress.stat.size - write.bytesWritten; | ||
var percent = ((written / progress.stat.size) * 100).toPrecision(2); | ||
opts.onProgress({ | ||
file: src, |
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.
maybe add both files here like src
+ dest
?
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.
👍 src
and dest
instead of file
return new Promise(function startRead(resolve, reject) { | ||
var read = fs.createReadStream(src); | ||
function createReadPromise(src) { | ||
var read = fs.createReadStream(src); |
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.
Move this back into the Promise constructor argument (line 26), because fs.createReadStream
might throw some error (maybe in the future), e.g.
fs.createReadStream('/dev/null', {flags: 'unicorns'})
|
I think I can fix all of them, since I'm here anyway. |
|
@schnittstabil I'd kept percent, but made it between |
file: src, | ||
written: written, | ||
remains: remains, | ||
percent: percent |
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.
size
would be nice, to calculate the total e.g. in cpy
– or eion
of course
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.
that would also allow to drop remains
, since that would be very easy to calc it yourself.
Updated. Will take a look at 0.10 failure a bit later. |
I have no idea what happens with 0.10 to be honest. Seems like something with encodings? |
@sindresorhus @schnittstabil fixed 0.10 by using |
return fsP.stat(src).then(function (stat) { | ||
progress.stat = stat; | ||
}).catch(function (err) { | ||
Promise.reject(new CpFileError('NO_ENTRY', err)); |
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 doing anything as it's not returned. Needs a regression test for that.
The correct solution is to just throw
the error.
@sindresorhus now that I tried this, I would say that maybe |
I would personally prefer EventEmitter as it's more Node'y. |
@sindresorhus Re-implemented with I wonder if we can somehow make return values of Edit: something like |
@@ -80,6 +119,10 @@ module.exports = function (src, dest, opts) { | |||
}); | |||
} | |||
}); | |||
|
|||
promise.events = progress.emitter; |
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.
As far as I understand, @sindresorhus suggested sth. like (sindresorhus/cpy#33 (comment)):
promise.on = progress.emitter.on.bind(progress.emitter);
So, one can use it that way:
const p = cpFile(…);
p.on(…);
p.then(…)
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 may also do this:
promise.on = function () {
progress.emitter.on.apply(progress.emitter, arguments);
return promise;
};
So, one can use it this way:
cpFile(…)
.on(…)
.then(…);
// but not this way (!)
cpFile(…)
.then(…)
.on(…);
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.
👍
Implemented @schnittstabil suggestions. |
var progress = { | ||
stat: null, | ||
emitter: new EventEmitter() | ||
}; |
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.
Hence we have cpFile.on(…)
, stat
and emitter
aren't intended only for progress stuff anymore.
We should drop progress.…
by:
var stat = null;
var eventEmitter = new EventEmitter();
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 if I drop stat
event, it would be the only for progress, right?
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, but IMO it is easier to read and to maintain, e.g. we may emit other events in the future...
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.
As we shouldn't reuse stat
for updating the access-times etc., we may use only the size:
- var stat = null;
+ var size = null;
// …
var promise = fsP.stat(src).then(function (stat) {
+ size = stat.size;
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.
maybe init it with 0
then? :)
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 should have thought first – the right thing would be simply:
var size;
0
means the file is emptynull
means we don't careundefined
means the size is not yet known
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.
@schnittstabil while this is nice, I have question if we want to optimize for this at all, is 1 stat
call worth additional branching and checking? I'm ok with either answer, just wanted to raise a question. Even if it is, we might be able to avoid it in some other way.
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 thought about that, but we have:
cpFile(…) // returns the promise
.on(…) // but the listeners are added afterwards
Therefore, a workaround to avoid the stat call would be rather awkward IMO, but if you have an idea…
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.
that way, if we have to do stat
anyway, why check?
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.
, why check?
I do not know if I have understood you correctly.
I think we should always fs.lstat
to determine the size. The alternative would be to postpone the call until a listener is added, which I think is too cumbersome.
Checking emitter.listenerCount('progress') > 0
before emitting is double workload, emitter.emit
does a similar check.
Checking size !== null
before emitting was based on a misconception (mentioned below), which have worked well in case of opts.onProgress
😒
Hence, I don't think we should check before emitting progress at all.
@schnittstabil Updated.
|
@YurySolovyov Sorry for the delay. LGTM, only documentation of |
@schnittstabil Added docs |
@sindresorhus Do you have further suggestions? |
dest: dest, | ||
size: size, | ||
written: written, | ||
percent: percent |
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 should round this to 2 decimals. E.g. 0.45
.
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.
What if user wants a better precision?
Say if you have a progress bar with value in pixels, and you calc done
value like
const done = progress * fullWidth;
Given that file can be big, you can have multiple progress events that rounds for same 0.45
value, making it stay at same position during multiple progress events.
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.
Yeah, sure, not a big deal.
@sindresorhus Updated. |
Awesome! Thanks for working on this @YurySolovyov. It turned out great :) |
@sindresorhus and @schnittstabil, thanks for your patience! |
3.2.0 published. Now on to |
Thanks a lot for your thorough work @YurySolovyov! |
API is likely to change, submitting PR to get some feedback.
Related to sindresorhus/cpy#33