From 0eac30352715fd84e6ac8ee395e8ec1720fdf224 Mon Sep 17 00:00:00 2001 From: Alexander Wunschik Date: Mon, 3 Feb 2020 12:02:21 +0100 Subject: [PATCH] Add windows support (#194) * fix: replace native tail with fs-tail-stream fixes #111 * fix: use options.buffer as start parameter * feat: add additional windows support * feat: add additional windows support --- README.md | 2 +- index.js | 8 +++--- lib/tail.js | 65 ++++++++++++++++++++++++++++------------------- package-lock.json | 29 ++++++++++++++------- package.json | 2 ++ 5 files changed, 66 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 03b9bc6..b4637ed 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ ## Features -* log rotation +* log rotation (not on windows!) * auto-scrolling * marking logs * pausing logs diff --git a/index.js b/index.js index eb658ff..5fda545 100644 --- a/index.js +++ b/index.js @@ -58,8 +58,8 @@ if (program.daemonize) { appBuilder.authorize(program.user, program.password); } appBuilder - .static(path.join(__dirname, 'web/assets')) - .index(path.join(__dirname, 'web/index.html'), files, filesNamespace, program.theme); + .static(path.join(__dirname, 'web', 'assets')) + .index(path.join(__dirname, 'web', 'index.html'), files, filesNamespace, program.theme); const builder = serverBuilder(); if (doSecure) { @@ -74,7 +74,7 @@ if (program.daemonize) { /** * socket.io setup */ - const io = new SocketIO({ path: path.join(urlPath, '/socket.io') }); + const io = new SocketIO({ path: `${urlPath}/socket.io` }); io.attach(server); if (doAuthorization) { @@ -105,7 +105,7 @@ if (program.daemonize) { let presetPath; if (!program.uiHighlightPreset) { - presetPath = path.join(__dirname, 'preset/default.json'); + presetPath = path.join(__dirname, 'preset', 'default.json'); } else { presetPath = path.resolve(untildify(program.uiHighlightPreset)); } diff --git a/lib/tail.js b/lib/tail.js index 339c3e2..8ffa4d3 100644 --- a/lib/tail.js +++ b/lib/tail.js @@ -4,9 +4,11 @@ const events = require('events'); const childProcess = require('child_process'); +const tailStream = require('fs-tail-stream'); const util = require('util'); const CBuffer = require('CBuffer'); const byline = require('byline'); +const commandExistsSync = require('command-exists').sync; function Tail(path, opts) { events.EventEmitter.call(this); @@ -16,38 +18,49 @@ function Tail(path, opts) { }; this._buffer = new CBuffer(options.buffer); + var stream; + if (path[0] === '-') { - byline(process.stdin, { keepEmptyLines: true }).on('data', (line) => { - const str = line.toString(); - this._buffer.push(str); - this.emit('line', str); - }); + stream = process.stdin; } else { - let followOpt = '-F'; - if (process.platform === 'openbsd') { - followOpt = '-f'; - } - - const tail = childProcess.spawn('tail', ['-n', options.buffer, followOpt].concat(path)); - tail.stderr.on('data', (data) => { - // If there is any important error then display it in the console. Tail will keep running. - // File can be truncated over network. - if (data.toString().indexOf('file truncated') === -1) { - console.error(data.toString()); + /* Check if this os provides the `tail` command. */ + const hasTailCommand = commandExistsSync('tail'); + if (hasTailCommand) { + + let followOpt = '-F'; + if (process.platform === 'openbsd') { + followOpt = '-f'; } - }); - byline(tail.stdout, { keepEmptyLines: true }).on('data', (line) => { - const str = line.toString(); - this._buffer.push(str); - this.emit('line', str); - }); + const cp = childProcess.spawn('tail', ['-n', options.buffer, followOpt].concat(path)); + cp.stderr.on('data', (data) => { + // If there is any important error then display it in the console. Tail will keep running. + // File can be truncated over network. + if (data.toString().indexOf('file truncated') === -1) { + console.error(data.toString()); + } + }); + stream = cp.stdout; - process.on('exit', () => { - tail.kill(); - }); + process.on('exit', () => { + cp.kill(); + }); + } else { + /* This is used if the os does not support the `tail`command. */ + stream = tailStream.createReadStream(path.join(), { + encoding: 'utf8', + start: options.buffer, + tail: true + }); + } } + + byline(stream, { keepEmptyLines: true }).on('data', (line) => { + const str = line.toString(); + this._buffer.push(str); + this.emit('line', str); + }); } util.inherits(Tail, events.EventEmitter); @@ -55,4 +68,4 @@ Tail.prototype.getBuffer = function getBuffer() { return this._buffer.toArray(); }; -module.exports = (path, options) => new Tail(path, options); +module.exports = (path, options) => new Tail(path, options); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index a3dbfd3..7380dcb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -653,10 +653,15 @@ "delayed-stream": "~1.0.0" } }, + "command-exists": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.8.tgz", + "integrity": "sha512-PM54PkseWbiiD/mMsbvW351/u+dafwTJ0ye2qB60G1aGQP9j3xK2gmMDc+R34L3nDtx4qMCitXT75mkbkGJDLw==" + }, "commander": { - "version": "3.0.0-0", - "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.0-0.tgz", - "integrity": "sha512-b/YlgJi4Nn53KWvxsOU9Mz1Lr+ZK4tMUyDOk2IvB+Hki5eefYZusNOvLls91HeI2oWLyxJ3KMEU9QeEaRtTPFQ==" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==" }, "component-bind": { "version": "1.0.0", @@ -1706,6 +1711,14 @@ "universalify": "^0.1.0" } }, + "fs-tail-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-tail-stream/-/fs-tail-stream-1.1.0.tgz", + "integrity": "sha1-ntJ2gs7mrjZX+EoL8P7bOxcSlac=", + "requires": { + "once": "^1.4.0" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2799,7 +2812,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } @@ -3191,9 +3203,9 @@ "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" }, "range-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", - "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "read-pkg": { "version": "2.0.0", @@ -4530,8 +4542,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write": { "version": "0.2.1", diff --git a/package.json b/package.json index 7394f62..97b57c4 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "CBuffer": "~0.1.4", "basic-auth-connect": "~1.0.0", "byline": "~5.0.0", + "command-exists": "^1.2.8", "commander": "~3.0.1", "configstore": "~4.0.0", "connect": "~3.6.6", @@ -17,6 +18,7 @@ "cookie-parser": "~1.4.3", "daemon-fix41": "~1.1.2", "express-session": "~1.15.6", + "fs-tail-stream": "^1.1.0", "is-docker": "~1.1.0", "serve-static": "~1.13.2", "socket.io": "^2.2.0",