From ab6dfe70439739d452fb250891ca29515a551fff Mon Sep 17 00:00:00 2001 From: Chris Davies Date: Wed, 30 May 2018 11:37:01 -0400 Subject: [PATCH] Tweak repl to be a bit more useful (#19395) * Tweak repl to be a bit more useful: - Start it earlier so it can be used to diagnose server boot bugs - Retain kbnServer, etc when repl is cleared (`.clear`) - Change default print depth so it doesn't bomb when printing kbnServer - Allow print depth to be changed as previous bullet may be annoying --- src/cli/repl/__snapshots__/repl.test.js.snap | 38 ++-------------- src/cli/repl/index.js | 35 +++++++++----- src/cli/repl/repl.test.js | 48 +++++++++++++++++++- src/cli/serve/serve.js | 7 ++- 4 files changed, 78 insertions(+), 50 deletions(-) diff --git a/src/cli/repl/__snapshots__/repl.test.js.snap b/src/cli/repl/__snapshots__/repl.test.js.snap index beab8226480c..7171e99dbcc0 100644 --- a/src/cli/repl/__snapshots__/repl.test.js.snap +++ b/src/cli/repl/__snapshots__/repl.test.js.snap @@ -1,19 +1,11 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`repl it allows print depth to be specified 1`] = `"{ '0': { '1': { '2': [Object] } }, whoops: [Circular] }"`; + exports[`repl it colorizes raw values 1`] = `"{ meaning: 42 }"`; exports[`repl it handles deep and recursive objects 1`] = ` -"{ '0': - { '1': - { '2': - { '3': - { '4': - { '5': - { '6': - { '7': - { '8': - { '9': - { '10': { '11': { '12': { '13': { '14': { '15': [Object] } } } } } } } } } } } } } } }, +"{ '0': { '1': { '2': { '3': { '4': { '5': [Object] } } } } }, whoops: [Circular] }" `; @@ -53,17 +45,7 @@ Array [ Array [ "Promise Rejected: ", - "{ '0': - { '1': - { '2': - { '3': - { '4': - { '5': - { '6': - { '7': - { '8': - { '9': - { '10': { '11': { '12': { '13': { '14': { '15': [Object] } } } } } } } } } } } } } } }, + "{ '0': { '1': { '2': { '3': { '4': { '5': [Object] } } } } }, whoops: [Circular] }", ], ] @@ -77,17 +59,7 @@ Array [ Array [ "Promise Resolved: ", - "{ '0': - { '1': - { '2': - { '3': - { '4': - { '5': - { '6': - { '7': - { '8': - { '9': - { '10': { '11': { '12': { '13': { '14': { '15': [Object] } } } } } } } } } } } } } } }, + "{ '0': { '1': { '2': { '3': { '4': { '5': [Object] } } } } }, whoops: [Circular] }", ], ] diff --git a/src/cli/repl/index.js b/src/cli/repl/index.js index 1e32ed10d0de..01d66d14d9ef 100644 --- a/src/cli/repl/index.js +++ b/src/cli/repl/index.js @@ -20,6 +20,8 @@ import repl from 'repl'; import util from 'util'; +const PRINT_DEPTH = 5; + /** * Starts an interactive REPL with a global `server` object. * @@ -29,18 +31,27 @@ export function startRepl(kbnServer) { const replServer = repl.start({ prompt: 'Kibana> ', useColors: true, - writer: promiseFriendlyWriter(() => replServer.displayPrompt()), + writer: promiseFriendlyWriter({ + displayPrompt: () => replServer.displayPrompt(), + getPrintDepth: () => replServer.context.repl.printDepth, + }), }); - replServer.context.kbnServer = kbnServer; - replServer.context.server = kbnServer.server; - replServer.context.repl = { - print(obj, depth = null) { - console.log(promisePrint(obj, () => replServer.displayPrompt(), depth)); - return ''; - }, + const initializeContext = () => { + replServer.context.kbnServer = kbnServer; + replServer.context.server = kbnServer.server; + replServer.context.repl = { + printDepth: PRINT_DEPTH, + print(obj, depth = null) { + console.log(promisePrint(obj, () => replServer.displayPrompt(), () => depth)); + return ''; + }, + }; }; + initializeContext(); + replServer.on('reset', initializeContext); + return replServer; } @@ -54,12 +65,12 @@ function prettyPrint(text, o, depth) { // This lets us handle promises more gracefully than the default REPL, // which doesn't show the results. -function promiseFriendlyWriter(displayPrompt) { - const PRINT_DEPTH = 15; - return (result) => promisePrint(result, displayPrompt, PRINT_DEPTH); +function promiseFriendlyWriter({ displayPrompt, getPrintDepth }) { + return (result) => promisePrint(result, displayPrompt, getPrintDepth); } -function promisePrint(result, displayPrompt, depth) { +function promisePrint(result, displayPrompt, getPrintDepth) { + const depth = getPrintDepth(); if (result && typeof result.then === 'function') { // Bit of a hack to encourage the user to wait for the result of a promise // by printing text out beside the current prompt. diff --git a/src/cli/repl/repl.test.js b/src/cli/repl/repl.test.js index cf20d61e3ebf..77e4020bf4b6 100644 --- a/src/cli/repl/repl.test.js +++ b/src/cli/repl/repl.test.js @@ -21,14 +21,29 @@ jest.mock('repl', () => ({ start: (opts) => ({ opts, context: {} }) }), { virtua describe('repl', () => { const originalConsoleLog = console.log; + let mockRepl; beforeEach(() => { global.console.log = jest.fn(); require('repl').start = (opts) => { - return { + let resetHandler; + const replServer = { opts, context: { }, + on: jest.fn((eventName, handler) => { + expect(eventName).toBe('reset'); + resetHandler = handler; + }), }; + + mockRepl = { + replServer, + clear() { + replServer.context = {}; + resetHandler(replServer.context); + }, + }; + return replServer; }; }); @@ -79,6 +94,37 @@ describe('repl', () => { .toMatchSnapshot(); }); + test('it allows print depth to be specified', () => { + const { startRepl } = require('.'); + const replServer = startRepl({}); + const splosion = {}; + let child = splosion; + for (let i = 0; i < 2000; ++i) { + child[i] = {}; + child = child[i]; + } + splosion.whoops = splosion; + replServer.context.repl.printDepth = 2; + expect(replServer.opts.writer(splosion)) + .toMatchSnapshot(); + }); + + test('resets context to original when reset', () => { + const { startRepl } = require('.'); + const testServer = { + server: { }, + }; + const replServer = startRepl(testServer); + replServer.context.foo = 'bar'; + expect(replServer.context.server).toBe(testServer.server); + expect(replServer.context.kbnServer).toBe(testServer); + expect(replServer.context.foo).toBe('bar'); + mockRepl.clear(); + expect(replServer.context.server).toBe(testServer.server); + expect(replServer.context.kbnServer).toBe(testServer); + expect(replServer.context.foo).toBeUndefined(); + }); + test('it prints promise resolves', async () => { const { startRepl } = require('.'); const replServer = startRepl({}); diff --git a/src/cli/serve/serve.js b/src/cli/serve/serve.js index c017339a98f5..e046438b6e3f 100644 --- a/src/cli/serve/serve.js +++ b/src/cli/serve/serve.js @@ -217,6 +217,9 @@ export default function (program) { const KbnServer = require('../../server/kbn_server'); try { kbnServer = new KbnServer(settings); + if (shouldStartRepl(opts)) { + startRepl(kbnServer); + } await kbnServer.ready(); } catch (error) { const { server } = kbnServer; @@ -248,10 +251,6 @@ export default function (program) { kbnServer.server.log(['info', 'config'], 'Reloaded logging configuration due to SIGHUP.'); }); - if (shouldStartRepl(opts)) { - startRepl(kbnServer); - } - return kbnServer; }); }