Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
pieh committed Mar 7, 2019
1 parent fd12550 commit e3e739a
Show file tree
Hide file tree
Showing 6 changed files with 401 additions and 29 deletions.
255 changes: 255 additions & 0 deletions packages/gatsby-cli/lib/reporter/ink/cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
const { h, Color, Text, Component, Fragment } = require(`ink`)
const Spinner = require(`ink-spinner`)
const tracer = require(`opentracing`).globalTracer()
const convertHrtime = require(`convert-hrtime`)

const methods = [
`activityTimer`,
`log`,
`info`,
`error`,
`warn`,
`panic`,
`panicOnBuild`,
]

const handler = {
hijackReporter(reporter) {
methods.forEach(method => {
reporter[method] = (...args) => handler.on(method, ...args)
})
},
}

class Activity extends Component {
render() {
const { active, name, status, elapsedTime } = this.props

return (
<div>
{active ? <Spinner green /> : <Color green>success</Color>} {name}
{elapsedTime ? ` - ${elapsedTime}` : ``}
{status ? ` - ${status}` : ``}
</div>
)
}
}

class Log extends Component {
render() {
const { type, content } = this.props

let prefix = null
if (type === `info`) {
prefix = <Color blue>info </Color>
} else if (type === `warn`) {
prefix = <Color yellow>warning </Color>
}

return (
<div>
{prefix}
{this.props.content.map(a => a.toString()).join(` `)}
</div>
)
}
}

class ErrorLog extends Component {
render() {
const { message, error } = this.props
return (
<div>
<Color red>error</Color> {message}
</div>
)
}
}

const typeToComponent = {
activity: Activity,
log: Log,
info: Log,
warn: Log,
error: ErrorLog,
}

class Item extends Component {
render() {
return h(typeToComponent[this.props.type], this.props)
}
}

class CLI extends Component {
constructor(props) {
super(props)

// this.state = {
// items: []
// }
this.items = []
this.error = this.error.bind(this)
this.panicOnBuild = this.panicOnBuild.bind(this)
this.panic = this.panic.bind(this)
}
componentDidMount() {
handler.on = (method, ...args) => this[method](...args)
}

getActivity(name, createIfNeeded = true) {
let activity = this.items.find(
item => item.type === `activity` && item.name === name
)
if (activity || !createIfNeeded) {
return activity
}

activity = {
type: `activity`,
name,
status: ``,
}
return activity
}

scheduleUpdate() {
this.setState({
beat: Date.now(),
})
}

addItem(item) {
this.items = [...this.items, item]

this.scheduleUpdate()
}

setActivity(activity) {
let stored = this.getActivity(activity.name, false)
if (!stored) {
this.addItem(activity)
} else {
this.scheduleUpdate()
// this.setState(state => ({
// items: state.items

// }))
}
}

log(...args) {
this.addItem({
type: `log`,
content: args,
})
}

info(...args) {
this.addItem({
type: `info`,
content: args,
})
}

warn(...args) {
this.addItem({
type: `warn`,
content: args,
})
}

exit(code) {
// this.setState({
// exitAfterUpdate: true,
// exitCode: code,
// })
// this.exitAfterUpdate = true
// this.exitCode = code
// this.scheduleUpdate()
}

componentDidUpdate() {
if (this.state.exitAfterUpdate) {
process.exit(this.state.exitCode)
}
}

panic(...args) {
this.error(...args)
this.exit(1)
}

panicOnBuild(...args) {
this.error(...args)
if (process.env.gatsby_executing_command === `build`) {
this.exit(1)
}
}

error(message, error) {
if (arguments.length === 1 && typeof message !== `string`) {
error = message
message = error.message
}

this.addItem({
type: `error`,
message,
error,
})
// console.error(args)
}

activityTimer(name, activityArgs = {}) {
let start = process.hrtime()
const elapsedTime = () => {
var elapsed = process.hrtime(start)
return `${convertHrtime(elapsed)[`seconds`].toFixed(3)} s`
}

const { parentSpan } = activityArgs
const spanArgs = parentSpan ? { childOf: parentSpan } : {}
const span = tracer.startSpan(name, spanArgs)

const updateActivity = update => {
let activity = this.getActivity(name)
update(activity)
this.setActivity(activity)
}

return {
start: () => {
updateActivity(activity => (activity.active = true))
},
setStatus: s => {
updateActivity(activity => (activity.status = s))
},
end: () => {
updateActivity(activity => {
activity.active = false
activity.elapsedTime = elapsedTime()
})
},
span,
}
}

render() {
// const { items } = this.state
// return null
return (
<Fragment>
<div>We are rendering with Ink</div>
{this.items.map(item => (
<Item {...item} />
))}
</Fragment>
)
}
}

module.exports = {
CLI,
handler,
methods,
}
3 changes: 3 additions & 0 deletions packages/gatsby-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
"fs-exists-cached": "^1.0.0",
"fs-extra": "^4.0.1",
"hosted-git-info": "^2.6.0",
"import-jsx": "^1.3.0",
"ink": "^0.5.1",
"ink-spinner": "^2.0.0",
"lodash": "^4.17.10",
"opentracing": "^0.14.3",
"pretty-error": "^2.1.1",
Expand Down
5 changes: 4 additions & 1 deletion packages/gatsby-cli/src/reporter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const { stripIndent } = require(`common-tags`)
const convertHrtime = require(`convert-hrtime`)
const tracer = require(`opentracing`).globalTracer()
const { getErrorFormatter } = require(`./errors`)

const { initInk } = require(`./ink`)
const VERBOSE = process.env.gatsby_log_level === `verbose`

const errorFormatter = getErrorFormatter()
Expand All @@ -25,6 +25,9 @@ module.exports = Object.assign(reporter, {
* Strip initial indentation template function.
*/
stripIndent,
switchToInk() {
initInk(this)
},
/**
* Toggle verbosity.
* @param {boolean} [isVerbose=true]
Expand Down
30 changes: 30 additions & 0 deletions packages/gatsby-cli/src/reporter/ink/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const importJsx = require(`import-jsx`)
const { render, h } = require(`ink`)

const { CLI, handler } = importJsx(`./cli`)
// const { createElement } = require(`react`)

const noOp = () => {}

exports.initInk = reporter => {
// const oldActivityTimer = reporter.activityTimer

// [`activityTimer`].forEach(field => {
// reporter[field] = (...args) => {

// }
// })
handler.console = { log: console.log }
// console.log = noOp
// console.error = noOp
// console.warn = noOp

// reporter.activityTimer = (name, activityArgs = {}) => {

// }
// console.log(`we are intercepting`)
// oldActivityTimer(...args)

handler.hijackReporter(reporter)
render(h(CLI))
}
1 change: 1 addition & 0 deletions packages/gatsby/src/commands/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type BuildArgs = {
}

module.exports = async function build(program: BuildArgs) {
report.switchToInk()
initTracer(program.openTracingConfigFile)

const buildSpan = tracer.startSpan(`build`)
Expand Down
Loading

0 comments on commit e3e739a

Please sign in to comment.