Skip to content

Commit

Permalink
fix(start): fix stdio freezing issue on Windows (#3725)
Browse files Browse the repository at this point in the history
Any time BottomBar is used, it uses a readline instance which hijacks
the stdio streams and has some strange issues on Windows. log-update
uses terminal ANSI codes to clear the line--should be the same
functionality without the readline weirdness.
  • Loading branch information
imhoffd committed Nov 4, 2018
1 parent 78dbda8 commit a570770
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 6 deletions.
2 changes: 2 additions & 0 deletions packages/@ionic/cli-framework/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"debug": "^4.0.0",
"inquirer": "^6.0.0",
"lodash": "^4.17.5",
"log-update": "^2.3.0",
"minimist": "^1.2.0",
"rimraf": "^2.6.2",
"slice-ansi": "^2.0.0",
Expand All @@ -50,6 +51,7 @@
"@types/inquirer": "0.0.43",
"@types/jest": "^23.3.5",
"@types/lodash": "^4.14.104",
"@types/log-update": "^2.0.0",
"@types/minimist": "^1.2.0",
"@types/node": "^6.0.101",
"@types/rimraf": "^2.0.2",
Expand Down
62 changes: 59 additions & 3 deletions packages/@ionic/cli-framework/src/lib/output.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as Debug from 'debug';
import * as ζinquirer from 'inquirer';
import * as ζlogUpdate from 'log-update';

import { Colors, DEFAULT_COLORS } from './colors';
import { ICON_FAILURE, ICON_SUCCESS, Spinner, TaskChain } from './tasks';
Expand All @@ -13,8 +14,6 @@ export interface OutputStrategy {

export interface RedrawLine {
redrawLine(msg?: string): void;
open(): void;
close(): void;
}

export interface StreamOutputStrategyOptions {
Expand Down Expand Up @@ -50,6 +49,63 @@ export class StreamOutputStrategy implements OutputStrategy {
}
}

export interface LogUpdateOutputStrategyOptions {
readonly LogUpdate: typeof ζlogUpdate;
readonly stream?: NodeJS.WritableStream;
readonly colors?: Colors;
}

export class LogUpdateOutputStrategy implements OutputStrategy, RedrawLine {
readonly stream: NodeJS.WritableStream;

protected readonly colors: Colors;
protected readonly logUpdate: typeof ζlogUpdate;

constructor({ LogUpdate, stream = process.stdout, colors = DEFAULT_COLORS }: LogUpdateOutputStrategyOptions) {
this.stream = stream;
this.colors = colors;
this.logUpdate = LogUpdate.create(stream);
}

redrawLine(msg = ''): void {
this.logUpdate(msg);
}

createTaskChain(): TaskChain {
const { failure, strong, success } = this.colors;
const chain = new TaskChain({ taskOptions: { tickInterval: 50 } });

chain.on('next', task => {
task.on('success', () => {
this.stream.write(`${success(ICON_SUCCESS)} ${task.msg} - done!\n`);
});

task.on('failure', () => {
this.stream.write(`${failure(ICON_FAILURE)} ${task.msg} - failed!\n`);
});

const spinner = new Spinner();

task.on('tick', () => {
const progress = task.progressRatio ? (task.progressRatio * 100).toFixed(2) : '';
const frame = spinner.frame();

this.redrawLine(`${strong(frame)} ${task.msg}${progress ? ' (' + strong(String(progress) + '%') + ')' : ''} `);
});

task.on('clear', () => {
this.logUpdate.clear();
});
});

chain.on('end', () => {
this.logUpdate.done();
});

return chain;
}
}

export interface BottomBarOutputStrategyOptions {
readonly BottomBar: typeof ζinquirer.ui.BottomBar;
readonly input?: NodeJS.ReadableStream;
Expand Down Expand Up @@ -112,7 +168,7 @@ export class BottomBarOutputStrategy implements OutputStrategy, RedrawLine {
}
}

createTaskChain() {
createTaskChain(): TaskChain {
const { failure, strong, success } = this.colors;
const chain = new TaskChain({ taskOptions: { tickInterval: 50 } });

Expand Down
2 changes: 2 additions & 0 deletions packages/ionic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"elementtree": "^0.1.7",
"leek": "0.0.24",
"lodash": "^4.17.5",
"log-update": "^2.3.0",
"opn": "^5.2.0",
"os-name": "^2.0.1",
"semver": "^5.5.0",
Expand All @@ -78,6 +79,7 @@
"@types/elementtree": "^0.1.0",
"@types/jest": "^23.3.5",
"@types/lodash": "^4.14.104",
"@types/log-update": "^2.0.0",
"@types/node": "^6.0.101",
"@types/opn": "^5.1.0",
"@types/os-name": "^2.0.0",
Expand Down
6 changes: 3 additions & 3 deletions packages/ionic/src/lib/command.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { BaseCommand, BottomBarOutputStrategy, LOGGER_LEVELS, OutputStrategy, StreamHandler, StreamOutputStrategy, TaskChain, generateCommandPath, unparseArgs } from '@ionic/cli-framework';
import { BaseCommand, LOGGER_LEVELS, LogUpdateOutputStrategy, OutputStrategy, StreamHandler, StreamOutputStrategy, TaskChain, generateCommandPath, unparseArgs } from '@ionic/cli-framework';
import chalk from 'chalk';
import * as LogUpdate from 'log-update';

import { CommandInstanceInfo, CommandLineInputs, CommandLineOptions, CommandMetadata, CommandMetadataInput, CommandMetadataOption, ICommand, INamespace, IProject, IonicEnvironment } from '../definitions';
import { isCommandPreRun } from '../guards';
Expand Down Expand Up @@ -27,8 +28,7 @@ export abstract class Command extends BaseCommand<ICommand, INamespace, CommandM
const formatter = createFormatter();

if (this.env.flags.interactive) {
const { ui: { BottomBar } } = this.env.prompt._inquirer;
output = new BottomBarOutputStrategy({ BottomBar });
output = new LogUpdateOutputStrategy({ LogUpdate });
this.env.log.handlers = new Set([new StreamHandler({ stream: output.stream, formatter })]);
} else {
this.env.log.handlers = createDefaultLoggerHandlers();
Expand Down

0 comments on commit a570770

Please sign in to comment.