Skip to content

Instantly share code, notes, and snippets.

@Leko
Created August 20, 2018 11:11
Show Gist options
  • Save Leko/4176a52c027954863cbd9a1517d2de4b to your computer and use it in GitHub Desktop.
Save Leko/4176a52c027954863cbd9a1517d2de4b to your computer and use it in GitHub Desktop.
// @flow
import { h, render, Text, Fragment, Component } from "ink";
import Spinner from "ink-spinner";
import chalk from "chalk";
import emoji from "node-emoji";
import { Provider, connect } from "ink-redux";
import { createStore } from "redux";
const Line = ({ text }) => (
<div>
<Spinner />
<Text> {text}</Text>
</div>
);
type Props = {|
[string]: string
|};
const MultiLine = ({ logs }: Props) => {
const lines = Object.entries(logs);
if (lines.length === 0) {
return null;
}
return (
<Fragment>
{lines.map(([key, log]) => <Line key={key} text={log} />)}
</Fragment>
);
};
const mapStateToProps = ({ logs }) => ({
logs
});
const MultiLineLog = connect(mapStateToProps)(MultiLine);
class MultiLineLogger {
store: {
dispatch: (action: any) => void
};
unmount: () => void;
constructor(size: number) {
this.store = this.createStore(size);
this.unmount = render(
<Provider store={this.store}>
<MultiLineLog />
</Provider>
);
}
createStore(size: number) {
const initialState = { logs: {} };
for (let i = 0; i < size; i++) {
initialState.logs[i] = "waiting...";
}
return createStore((state = initialState, action) => {
switch (action.type) {
case "LOG": {
const { index, text } = action;
return {
...state,
logs: {
...state.logs,
[index]: text
}
};
}
case "CLEAR": {
return {
...state,
logs: {}
};
}
default:
return state;
}
});
}
setText(index: number, text: string) {
this.store.dispatch({ type: "LOG", index, text });
}
tearDown(): Promise<void> {
// this.store.dispatch({ type: "CLEAR" });
return new Promise((resolve, reject) => {
setTimeout(() => {
try {
this.unmount();
resolve();
} catch (e) {
reject(e);
}
}, 0);
});
}
}
class StepLogger {
cursor: number;
size: number;
stream: stream$Writable;
constructor(size: number, stream?: stream$Writable = process.stdout) {
this.cursor = 0;
this.size = size;
this.stream = stream;
}
increment(emojiType: string, title: string) {
this.cursor++;
const indicator = chalk.dim(`[${this.cursor}/${this.size}]`);
const icon = emoji.get(emojiType);
this.stream.write(`${indicator} ${icon} ${title}\n`);
}
}
const steps = [
{
step: "Collect packages",
emoji: "mag",
timeout: 100
},
{
step: "Fetching updates",
emoji: "truck",
timeout: 1000,
fn: () => {
const SIZE = 6;
const words = [
"hothouse",
"@hothouse/client-npm",
"@hothouse/client-yarn",
"@hothouse/monorepo-lerna",
"@hothouse/monorepo-yarn-workspaces",
"@hothouse/step-logger",
"@hothouse/types"
];
const logger = new MultiLineLogger(SIZE);
const tid = setInterval(() => {
const index = ~~(Math.random() * SIZE);
const word = words[~~(Math.random() * words.length)];
logger.setText(index, `Fetching ${word}`);
}, 1000 / 60);
setTimeout(() => {
clearInterval(tid);
logger.tearDown();
}, 900);
}
},
{
step: "Fetching release metadata",
emoji: "bookmark",
timeout: 1000,
fn: () => {
const SIZE = 6;
const {
dependencies,
devDependencies
} = require("../../../../package.json");
const words = Object.keys(dependencies || {}).concat(
Object.keys(devDependencies || {})
);
const logger = new MultiLineLogger(SIZE);
const tid = setInterval(() => {
const index = ~~(Math.random() * SIZE);
const word = words[~~(Math.random() * words.length)];
logger.setText(index, `Fetching ${word}`);
}, 1000 / 60);
setTimeout(() => {
clearInterval(tid);
logger.tearDown();
}, 900);
}
},
{
step: "Sending pull requests",
emoji: "honeybee",
timeout: 1000,
fn: () => {
const SIZE = 6;
const words = [
"hothouse",
"@hothouse/client-npm",
"@hothouse/client-yarn",
"@hothouse/monorepo-lerna",
"@hothouse/monorepo-yarn-workspaces",
"@hothouse/step-logger",
"@hothouse/types"
];
const logger = new MultiLineLogger(SIZE);
const tid = setInterval(() => {
const index = ~~(Math.random() * SIZE);
const word = words[~~(Math.random() * words.length)];
logger.setText(index, `Fetching ${word}`);
}, 200);
setTimeout(() => {
clearInterval(tid);
logger.tearDown();
}, 900);
}
}
];
const logger = new StepLogger(steps.length);
const next = cursor => {
const { step, emoji, timeout, fn } = steps[cursor];
logger.increment(emoji, step);
fn && fn();
if (cursor + 1 < steps.length) {
setTimeout(() => next(cursor + 1), timeout);
}
};
next(0);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment