dthree / vorpal

Node's framework for interactive CLIs
http://vorpal.js.org
MIT License
5.64k stars 280 forks source link

Progress bars within vorpal #176

Open chrisui opened 8 years ago

chrisui commented 8 years ago

Hey! Firstly, to the maintainers and contributors, awesome library. This is my first time venturing into making any sort of cli tooling and vorpal has made it an absolute dream to work on - so much fun!

Secondly I was wondering if anyone have any recommendations for handling progress bars within my vorpal commands? I am using progress and it seems to work fine however I am a little concious of the fact it is not logging via vorpal.log after reading the logging documentation.

Am I going to run into issues down the line? Is there already an awesome vorpal progress plugin? If not and I am going to run into issues down the line perhaps there is a way we could implement this as a plugin/extension easily?

tobilg commented 8 years ago

I also use progress for progress bars together with vorpal. So far, I didn't encounter any problem, but also would appreciate a way to integrate this better...

tobilg commented 8 years ago

I had a look at the sources, and you can pass the progress module a stream property, which it will then use as output stream.

Unfortunately I didn't find way to access the console.log stream of vorpal because IMO it's not exposed.

LongLiveCHIEF commented 8 years ago

I had this use case a few months ago, and wrote a binary downloader that output progress to the vorpal console, using the stream method @tobilg mentioned, although I did it without using the progress module, and simply returned writeStream.byesWritten on each tick. Here's what I did (I used rxjs to add some helper methods, but this can be done w/out that dependency):

The main trick here is to use the vorpal.ui.redraw command:

// file:  /lib/commands/update.js
var fs = require('fs');
var path = require('path');
require('rxjs/add/operator/filter');
var updateBinaries = require('../update-binaries');

module.exports = function(vorpal){
  vorpal
    .command('update')
    .description('update core binaries')
    .action(function(args, callback){
      updateBinaries(needsInstalled)
        .subscribe(
          function(update){
            vorpal.ui.redraw(update);
          },
          function(){
            vorpal.ui.redraw.done();
            vorpal.log('there was an error while downloading file')
          },
          function(){
            vorpal.ui.redraw.done();
            vorpal.log("download completed");
          }
        );
      callback();
    });
}

// file: ../update-binaries.js

var request = require('request');
var fs = require('fs');
var path = require('path');
var {Observable} = require('rxjs/Observable');

var Download = function binaryDownloadObservable(url, downloadPath){

  return Observable.create(function(observer){
    var stream = request;
    var fileWriter = fs.createWriteStream(downloadPath);

    stream
      .get(url)
      .on('response', function(response){
        observer.next({
          "event": "response",
          "data": response.headers['content-length']
        });
      })
      .on('data', function(data){
        observer.next({
          "event": "chunk",
          "data": fileWriter.bytesWritten
        })
      })
      .on('error', function(error){
        observer.error(error);
      })
      .on('end', function(){
        observer.complete();
      })
      .pipe(fileWriter);

      return function(){
        fileWriter.end();
      }
  });
}