diff --git a/gulpfile.esm.js b/gulpfile.esm.js index c03d6053bd427b71caf0339f90bf9e106bc02e30..c2f73efbc9b0ca0714e4d4fa52d40334bf0cca21 100644 --- a/gulpfile.esm.js +++ b/gulpfile.esm.js @@ -17,12 +17,12 @@ const PREZ_GLOB = `${SRC_DIR}/**/index.md`; const GRAPH_GLOB = `${SRC_DIR}/**/*.drawio`; const PDF_GLOB = `${DEST_DIR}/**/index.html`; -export const clean = () => del(`${DEST_DIR}/**`); +export const clean = () => del(`${DEST_DIR}/**`, { force: true }); export const assets = () => src(ASSET_GLOB).pipe(dest(DEST_DIR)); -export const graphs = () => src(GRAPH_GLOB).pipe(drawio()).pipe(dest(DEST_DIR)); export const prez = () => src(PREZ_GLOB).pipe(index()).pipe(pandoc()).pipe(dest(DEST_DIR)); +export const graphs = () => src(GRAPH_GLOB).pipe(drawio()).pipe(dest(DEST_DIR)); export const pdf = () => src(PDF_GLOB).pipe(wkhtmltopdf()).pipe(dest(DEST_DIR)); export const build = series(clean, parallel(assets, prez, graphs), pdf); diff --git a/lib/drawio.js b/lib/drawio.js index 5851a282d9af0f2110ab7f7c12bcdee7ed37f781..873c43f85189a2cc74172565a8d7574cdcba9a0b 100644 --- a/lib/drawio.js +++ b/lib/drawio.js @@ -5,47 +5,55 @@ import logger from "gulplog"; import { mkTempFile } from "./tempdir"; import { obj } from "through2"; import PluginError from "plugin-error"; +import { withBinary } from "./optional"; const PLUGIN_NAME = "drawio"; -const DRAWIO_BINARY = process.env.DRAWIO_BINARY || "drawio"; - const execFile = promisify(child_process.execFile); -export default function drawio() { - return obj( - callbackify(async function (input) { - try { - const output = await mkTempFile(input); - output.extname = ".svg"; - - const args = [ - "--export", - "--format", - "svg", - "--width", - "1024", - "--output", - output.path, - input.path, - ]; - - const { stdout, stderr } = await execFile(DRAWIO_BINARY, args); - logger.info("%s: generated %s", PLUGIN_NAME, output.relative); - if (stdout.length > 0) { - logger.debug(PLUGIN_NAME, "stdout:", stdout); - } - if (stderr.length > 0) { - logger.info(PLUGIN_NAME, "stderr:", stderr); - } - - output.contents = fs.createReadStream(output.path, { - encoding: "UTF-8", - }); - this.push(output); - } catch (error) { - throw new PluginError(PLUGIN_NAME, error); - } - }) - ); -} +const drawio = withBinary( + "DRAWIO_BINARY", + "drawio", + (DRAWIO_BINARY) => + function drawio() { + return obj( + callbackify(async function (input) { + try { + const output = await mkTempFile(input); + output.extname = ".svg"; + + const args = [ + "--export", + "--format", + "svg", + "--width", + "1024", + "--output", + output.path, + input.path, + ]; + + const { stdout, stderr } = await execFile(DRAWIO_BINARY, args); + if (stdout.length > 0) { + logger.info(PLUGIN_NAME, "stdout:", stdout); + } + if (stderr.length > 0) { + logger.info(PLUGIN_NAME, "command:", DRAWIO_BINARY, args); + logger.info(PLUGIN_NAME, "stderr:", stderr); + } + + output.contents = fs.createReadStream(output.path, { + encoding: "UTF-8", + }); + logger.info("%s: generated %s", PLUGIN_NAME, output.relative); + + this.push(output); + } catch (error) { + throw new PluginError(PLUGIN_NAME, error); + } + }) + ); + } +); + +export default drawio; diff --git a/lib/index.js b/lib/index.js index 3447e07567892b181b22c16c4ba7dde9aeaf9e52..23ac1717536a486f552c21b4cd0323dbcec86737 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,5 +1,6 @@ import { callbackify } from "util"; import File from "vinyl"; +import { getPDFOutput } from "./wkhtmltopdf"; import logger from "gulplog"; import { obj } from "through2"; import PluginError from "plugin-error"; @@ -75,18 +76,6 @@ function getPrezFilename(input) { return prez.relative; } -/** - * @param {File} input - * @return {string} - */ -function getPdfFilename(input) { - const parent = new File({ path: input.dirname }); - const pdf = input.clone({ deep: false, contents: false }); - pdf.stem = parent.stem; - pdf.extname = ".pdf"; - return pdf.relative; -} - function renderIndex(inputs) { return `% Présentations % Dev@Science @@ -108,7 +97,9 @@ ${inputs .map( (input) => `- [${input.titleBlock.title}](${getPrezFilename(input)})` + - `[<img class="plain icon" src="file_pdf.png"/>](${getPdfFilename(input)})` + `[<img class="plain icon" src="file_pdf.png"/>](${ + getPDFOutput(input).relative + })` ) .join("\n")}`; } diff --git a/lib/optional.js b/lib/optional.js new file mode 100644 index 0000000000000000000000000000000000000000..8c8e33ddf665c8218eac1b72f7460df9c301c9da --- /dev/null +++ b/lib/optional.js @@ -0,0 +1,29 @@ +import logger from "gulplog"; +import { obj } from "through2"; +import which from "which"; + +function noop() { + return obj((_file, _enc, done) => done()); +} + +/** + * + * @param {string} envName + * @param {any} + * @param {*} resolve + */ +export function withBinary(envName, execName, resolve) { + const setting = process.env[envName] || execName; + const binary = which.sync(setting, { nothrow: true }); + if (!binary) { + logger.info("%s not found (configure with %s)", execName, envName); + return noop; + } + logger.info( + "Using `%s` for %s (configure with %s)", + binary, + execName, + envName + ); + return resolve(binary); +} diff --git a/lib/wkhtmltopdf.js b/lib/wkhtmltopdf.js index b0f520a8b2b060888b5a8bb97895ec71701db075..33febcdae0873d9fcf7e3c70e3e57c9e5287e717 100644 --- a/lib/wkhtmltopdf.js +++ b/lib/wkhtmltopdf.js @@ -1,11 +1,12 @@ import { callbackify, promisify } from "util"; import child_process from "child_process"; import { createReadStream } from "fs"; -import File from "vinyl"; import logger from "gulplog"; import { mkTempFile } from "./tempdir"; import { obj } from "through2"; +import path from "path"; import PluginError from "plugin-error"; +import { withBinary } from "./optional"; const execFile = promisify(child_process.execFile); @@ -32,37 +33,52 @@ const DEFAULT_OPTIONS = { ], }; -const WKHTMLTOPDF_BINARY = process.env.WKHTMLTOPDF_BINARY || "wkhtmltopdf"; +/** + * @param {File} input + * @return {string} + */ +export function getPDFOutput(input) { + const output = input.clone({ deep: false, contents: false }); + output.basename = path.basename(input.dirname, ".md") + ".pdf"; + return output; +} -export default function wkhtmltopdf(options = {}) { - const { args } = Object.assign({}, DEFAULT_OPTIONS, options); - return obj( - callbackify(async function (input) { - try { - const output = await mkTempFile(input); - const parent = new File({ path: input.dirname }); - output.stem = parent.stem; - output.extname = ".pdf"; - const execArgs = [ - ...args, - `file://${input.path}?print-pdf`, - output.path, - ]; +export const wkhtmltopdf = withBinary( + "WKHTMLTOPDF_BINARY", + "wkhtmltopdf", + (WKHTMLTOPDF_BINARY) => + function wkhtmltopdf(options = {}) { + const { args } = Object.assign({}, DEFAULT_OPTIONS, options); + return obj( + callbackify(async function (input) { + try { + const output = await mkTempFile(getPDFOutput(input)); + const execArgs = [ + ...args, + `file://${input.path}?print-pdf`, + output.path, + ]; - const { stdout, stderr } = await execFile(WKHTMLTOPDF_BINARY, execArgs); - logger.info("%s: generated %s", PLUGIN_NAME, output.relative); - if (stdout.length > 0) { - logger.debug(PLUGIN_NAME, "stdout:", stdout); - } - if (stderr.length > 0) { - logger.debug(PLUGIN_NAME, "stderr:", stderr); - } + const { stdout, stderr } = await execFile( + WKHTMLTOPDF_BINARY, + execArgs + ); + logger.info("%s: generated %s", PLUGIN_NAME, output.relative); + if (stdout.length > 0) { + logger.debug(PLUGIN_NAME, "stdout:", stdout); + } + if (stderr.length > 0) { + logger.debug(PLUGIN_NAME, "stderr:", stderr); + } - output.contents = createReadStream(output.path); - this.push(output); - } catch (err) { - throw new PluginError(PLUGIN_NAME, err, { filename: input.path }); - } - }) - ); -} + output.contents = createReadStream(output.path); + this.push(output); + } catch (err) { + throw new PluginError(PLUGIN_NAME, err, { filename: input.path }); + } + }) + ); + } +); + +export default wkhtmltopdf; diff --git a/package-lock.json b/package-lock.json index f9483d3501bd0a10e137dfe078f5a00c81d56287..3ccac86c5868281f871c46eb81660f3de4b7bf80 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1033,6 +1033,17 @@ "semver": "^5.5.0", "shebang-command": "^1.2.0", "which": "^1.2.9" + }, + "dependencies": { + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } } }, "currently-unhandled": { @@ -2836,6 +2847,16 @@ "ini": "^1.3.4", "is-windows": "^1.0.1", "which": "^1.2.14" + }, + "dependencies": { + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + } } }, "globals": { @@ -6870,9 +6891,9 @@ } }, "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "requires": { "isexe": "^2.0.0" } diff --git a/package.json b/package.json index ec1f010f205b28096d89f2e9787a2dfd3d403811..474dcd1d8c0d8603fe054dca29e96ccce2ad19ce 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "gulplog": "^1.0.0", "plugin-error": "^1.0.1", "through2": "^3.0.1", - "vinyl": "^2.2.0" + "vinyl": "^2.2.0", + "which": "^2.0.2" }, "devDependencies": { "eslint": "^6.8.0",