From 27f170f9645735ac4b91ec0cdd84337c4b630690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20G=C3=A9rard?= Date: Fri, 28 Jun 2024 16:25:30 +0200 Subject: [PATCH] chore: handle better build errors --- .github/workflows/test.yml | 1 + src/build.js | 5 ++- src/kindlegen.js | 15 ++++++-- src/message.js | 4 +++ src/node-pandoc-promise.js | 71 ++++++++++++++++++-------------------- 5 files changed, 54 insertions(+), 42 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3076e01..a2c227e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,6 +20,7 @@ jobs: distribution: 'temurin' java-version: '17' - run: | + sudo apt-get install -y texlive texlive-xetex PANDOC_URL=$(curl https://api.github.com/repos/jgm/pandoc/releases/latest | jq -r ".assets[] | select(.name | test(\"amd64.deb$\")) | .browser_download_url") curl --silent --show-error --location --fail --retry 4 --retry-delay 5 --output pandoc.deb $PANDOC_URL sudo dpkg -i pandoc.deb diff --git a/src/build.js b/src/build.js index de30bd0..2e47c2b 100644 --- a/src/build.js +++ b/src/build.js @@ -87,6 +87,9 @@ module.exports = async (config, options = {}) => { let args = config.files + // Suppress warning messages + args.push('--quiet') + if (config.format === 'epub' || config.format === 'mobi') { // add stylesheet let cssContent = '' @@ -179,7 +182,7 @@ module.exports = async (config, options = {}) => { args.push('-o', outputFile) // compile with pandoc - await nodePandoc('', args, { cwd }) + await nodePandoc('', args, { cwd }, undefined, { debug: options.debug }) if (config.format === 'epub' || config.format === 'mobi') { // Automatically edit epub: apply substitutions, append extra metadata diff --git a/src/kindlegen.js b/src/kindlegen.js index 925b0ff..fcbe48a 100644 --- a/src/kindlegen.js +++ b/src/kindlegen.js @@ -8,7 +8,7 @@ const { spawn } = require('child_process') const tar = require('tar') const unzipper = require('unzipper') -const { log, warn } = require('./message') +const { debug, log, warn } = require('./message') const { humanizePlatformArch } = require('./utils') const kindlegenFilename = () => (process.platform === 'win32' ? 'kindlegen.exe' : 'kindlegen') @@ -95,12 +95,21 @@ const extractKindleGen = (file) => { module.exports.epubToMobi = (input, output, options = {}) => { let kindlegenPath = options.kindlegenPath || localKindlegenPath() return new Promise((resolve, reject) => { - let opts = ['-c2', '-dont_append_source'] + const opts = ['-c2', '-dont_append_source'] + if (options.debug) { opts.push('-verbose') } + opts.push(input) - let kindlegen = spawn(kindlegenPath, opts) + + if (options.debug) { + debug('*** mobi build') + debug(`${kindlegenPath} ${opts.join(' ')}`) + } + + const kindlegen = spawn(kindlegenPath, opts) + kindlegen.on('close', async (code) => { if (code !== 0 && code !== 1) { reject(`KindleGen returned error ${code}`) diff --git a/src/message.js b/src/message.js index 95689e7..854f097 100644 --- a/src/message.js +++ b/src/message.js @@ -23,6 +23,10 @@ module.exports.error = (message, icon = '📕') => { console.error(chalk.red(`${icon} ${message}`)) } +module.exports.debug = (message, icon = '⚙️') => { + console.log(chalk.gray(`${icon} ${message}`)) +} + module.exports.log = (message = '') => { console.log(message) } diff --git a/src/node-pandoc-promise.js b/src/node-pandoc-promise.js index d4d449d..1368776 100644 --- a/src/node-pandoc-promise.js +++ b/src/node-pandoc-promise.js @@ -1,58 +1,53 @@ const stat = require('fs').stat const spawn = require('child_process').spawn +const { debug, log } = require('./message') -module.exports = function (src, args = [], options = {}, pandocPath = 'pandoc') { - return new Promise((resolve, reject) => { - let pdSpawn - let result = '' - let isURL - - // Event Handlers - let onStdOutData - let onStdOutEnd - let onStdErrData - let onStatCheck - - isURL = function (src) { - return /^(https?|ftp):\/\//i.test(src) - } - - onStdOutData = function (data) { - result += data - } - - onStdOutEnd = function () { - resolve(result) - } +module.exports = function (src, args = [], spawnOptions = {}, pandocPath = 'pandoc', options = {}) { + if (options.debug) { + debug('*** pandoc build') + debug(JSON.stringify(spawnOptions, 0, 2)) + debug(`${pandocPath} ${args.join(' ')}`) + } - onStdErrData = function (err) { - reject(new Error(err)) - } + return new Promise((resolve, reject) => { + // Check file status of src + stat(src, (_err, stats) => { + // Check if src is URL match. + const isURL = /^(https?|ftp):\/\//i.test(src) - onStatCheck = function (err, stats) { // If src is a file or valid web URL, push the src back into args array if ((stats && stats.isFile()) || isURL) { args.unshift(src) } - // Create child_process.spawn - pdSpawn = spawn(pandocPath, args, options) + const pdSpawn = spawn(pandocPath, args, spawnOptions) // If src is not a file, assume a string input. if (typeof stats === 'undefined' && !isURL) { pdSpawn.stdin.end(src, 'utf-8') } - // Set handlers... - pdSpawn.stdout.on('data', onStdOutData) - pdSpawn.stdout.on('end', onStdOutEnd) - pdSpawn.on('error', onStdErrData) - } + let result = '' + let error = '' - // Check if src is URL match. - isURL = isURL(src) + pdSpawn.stdout.on('data', (data) => { + result += data + if (options.debug) { + log(data) + } + }) - // Check file status of src - stat(src, onStatCheck) + pdSpawn.stderr.on('data', (data) => { + error += data + }) + + pdSpawn.on('close', (code) => { + if (code !== 0 || error !== '') { + reject(new Error(`pandoc returned error ${code}: ${error}`)) + } + + resolve(result) + }) + }) }) }