1
0
mirror of https://github.com/JuanCanham/HackMyResume.git synced 2024-11-25 01:40:10 +00:00

Fix generation glitches.

Fix output file name glitch, writing CSS files to destination folder,
and an issue where the process would evaporate before PDF/PNG generation
could complete.
This commit is contained in:
hacksalot 2016-02-13 03:27:11 -05:00
parent 9927e79900
commit 3f8e795c61
11 changed files with 59 additions and 41 deletions

4
dist/cli/main.js vendored
View File

@ -224,9 +224,7 @@ Definition of the `main` function.
/* Success handler for verb invocations. Calls process.exit by default */ /* Success handler for verb invocations. Calls process.exit by default */
executeSuccess = function(obj) { executeSuccess = function(obj) {};
_exitCallback(0);
};
/* Failure handler for verb invocations. Calls process.exit by default */ /* Failure handler for verb invocations. Calls process.exit by default */

View File

@ -131,11 +131,12 @@ Definition of the FRESHTheme class.
/* Load a single theme file. */ /* Load a single theme file. */
_loadOne = function(absPath, formatsHash, tplFolder) { _loadOne = function(absPath, formatsHash, tplFolder) {
var absPathSafe, act, idx, obj, outFmt, pathInfo, portion, ref, ref1, reg, res; var absPathSafe, act, defFormats, idx, isPrimary, obj, outFmt, pathInfo, portion, ref, ref1, reg, res;
pathInfo = parsePath(absPath); pathInfo = parsePath(absPath);
absPathSafe = absPath.trim().toLowerCase(); absPathSafe = absPath.trim().toLowerCase();
outFmt = ''; outFmt = '';
act = 'copy'; act = 'copy';
isPrimary = false;
if (this.explicit) { if (this.explicit) {
outFmt = _.find(Object.keys(this.formats), function(fmtKey) { outFmt = _.find(Object.keys(this.formats), function(fmtKey) {
var fmtVal; var fmtVal;
@ -181,6 +182,10 @@ Definition of the FRESHTheme class.
if (!this.explicit) { if (!this.explicit) {
act = 'transform'; act = 'transform';
} }
defFormats = require('./default-formats');
isPrimary = _.some(defFormats, function(form) {
return form.name === outFmt && pathInfo.extname !== '.css';
});
} }
formatsHash[outFmt] = formatsHash[outFmt] || { formatsHash[outFmt] = formatsHash[outFmt] || {
outFormat: outFmt, outFormat: outFmt,
@ -191,6 +196,7 @@ Definition of the FRESHTheme class.
} }
obj = { obj = {
action: act, action: act,
primary: isPrimary,
path: absPath, path: absPath,
orgPath: PATH.relative(tplFolder, absPath), orgPath: PATH.relative(tplFolder, absPath),
ext: pathInfo.extname.slice(1), ext: pathInfo.extname.slice(1),

View File

@ -6,7 +6,7 @@ Definition of the HtmlPdfCLIGenerator class.
*/ */
(function() { (function() {
var FS, HMSTATUS, HtmlPdfCLIGenerator, PATH, SLASH, TemplateGenerator, _, engines, var FS, HMSTATUS, HtmlPdfCLIGenerator, PATH, SLASH, SPAWN, TemplateGenerator, _, engines,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty; hasProp = {}.hasOwnProperty;
@ -22,6 +22,8 @@ Definition of the HtmlPdfCLIGenerator class.
HMSTATUS = require('../core/status-codes'); HMSTATUS = require('../core/status-codes');
SPAWN = require('../utils/safe-spawn');
/** /**
An HTML-driven PDF resume generator for HackMyResume. Talks to Phantom, An HTML-driven PDF resume generator for HackMyResume. Talks to Phantom,
@ -41,12 +43,14 @@ Definition of the HtmlPdfCLIGenerator class.
HtmlPdfCLIGenerator.prototype.onBeforeSave = function(info) { HtmlPdfCLIGenerator.prototype.onBeforeSave = function(info) {
var safe_eng; var safe_eng;
if (info.ext !== 'html') {
return info.mk;
}
safe_eng = info.opts.pdf || 'wkhtmltopdf'; safe_eng = info.opts.pdf || 'wkhtmltopdf';
if (safe_eng === 'phantom') { if (safe_eng === 'phantom') {
safe_eng = 'phantomjs'; safe_eng = 'phantomjs';
} }
if (_.has(engines, safe_eng)) { if (_.has(engines, safe_eng)) {
this.SPAWN = require('../utils/safe-spawn');
this.errHandler = info.opts.errHandler; this.errHandler = info.opts.errHandler;
engines[safe_eng].call(this, info.mk, info.outputFile, this.onError); engines[safe_eng].call(this, info.mk, info.outputFile, this.onError);
return null; return null;
@ -86,7 +90,7 @@ Definition of the HtmlPdfCLIGenerator class.
var tempFile; var tempFile;
tempFile = fOut.replace(/\.pdf$/i, '.pdf.html'); tempFile = fOut.replace(/\.pdf$/i, '.pdf.html');
FS.writeFileSync(tempFile, markup, 'utf8'); FS.writeFileSync(tempFile, markup, 'utf8');
return this.SPAWN('wkhtmltopdf', [tempFile, fOut], false, on_error, this); SPAWN('wkhtmltopdf', [tempFile, fOut], false, on_error, this);
}, },
/** /**
@ -100,10 +104,11 @@ Definition of the HtmlPdfCLIGenerator class.
var destPath, scriptPath, sourcePath, tempFile; var destPath, scriptPath, sourcePath, tempFile;
tempFile = fOut.replace(/\.pdf$/i, '.pdf.html'); tempFile = fOut.replace(/\.pdf$/i, '.pdf.html');
FS.writeFileSync(tempFile, markup, 'utf8'); FS.writeFileSync(tempFile, markup, 'utf8');
scriptPath = SLASH(PATH.relative(process.cwd(), PATH.resolve(__dirname, '../utils/rasterize.js'))); scriptPath = PATH.relative(process.cwd(), PATH.resolve(__dirname, '../utils/rasterize.js'));
scriptPath = SLASH(scriptPath);
sourcePath = SLASH(PATH.relative(process.cwd(), tempFile)); sourcePath = SLASH(PATH.relative(process.cwd(), tempFile));
destPath = SLASH(PATH.relative(process.cwd(), fOut)); destPath = SLASH(PATH.relative(process.cwd(), fOut));
return this.SPAWN('phantomjs', [scriptPath, sourcePath, destPath], false, on_error, this); SPAWN('phantomjs', [scriptPath, sourcePath, destPath], false, on_error, this);
} }
}; };

View File

@ -115,13 +115,14 @@ Definition of the TemplateGenerator class. TODO: Refactor
genInfo.files.forEach(function(file) { genInfo.files.forEach(function(file) {
var thisFilePath; var thisFilePath;
file.info.orgPath = file.info.orgPath || ''; file.info.orgPath = file.info.orgPath || '';
thisFilePath = PATH.join(outFolder, file.info.orgPath); thisFilePath = file.info.primary ? f : PATH.join(outFolder, file.info.orgPath);
if (file.info.action !== 'copy' && this.onBeforeSave) { if (file.info.action !== 'copy' && this.onBeforeSave) {
file.data = this.onBeforeSave({ file.data = this.onBeforeSave({
theme: opts.themeObj, theme: opts.themeObj,
outputFile: thisFilePath, outputFile: thisFilePath,
mk: file.data, mk: file.data,
opts: this.opts opts: this.opts,
ext: file.info.ext
}); });
if (!file.data) { if (!file.data) {
return; return;

View File

@ -128,7 +128,7 @@ main = module.exports = ( rawArgs, exitCallback ) ->
program.parse( args ) program.parse( args )
if !program.args.length if !program.args.length
throw { fluenterror: 4 } throw fluenterror: 4
@ -256,13 +256,14 @@ execute = ( src, dst, opts, log ) ->
# Invoke the verb using promise syntax # Invoke the verb using promise syntax
prom = v.invoke.call v, src, dst, _opts, log prom = v.invoke.call v, src, dst, _opts, log
prom.then executeSuccess, executeFail prom.then executeSuccess, executeFail
return return
### Success handler for verb invocations. Calls process.exit by default ### ### Success handler for verb invocations. Calls process.exit by default ###
executeSuccess = (obj) -> _exitCallback 0; return executeSuccess = (obj) ->
# Can't call _exitCallback here (process.exit) when PDF is running in BK
#_exitCallback 0; return

View File

@ -29,7 +29,7 @@ class FRESHTheme
### Open and parse the specified theme. ### ### Open and parse the specified theme. ###
open: ( themeFolder ) -> open: ( themeFolder ) ->
this.folder = themeFolder; @folder = themeFolder
# Open the [theme-name].json file; should have the same name as folder # Open the [theme-name].json file; should have the same name as folder
pathInfo = parsePath themeFolder pathInfo = parsePath themeFolder
@ -126,6 +126,7 @@ _loadOne = ( absPath, formatsHash, tplFolder ) ->
absPathSafe = absPath.trim().toLowerCase() absPathSafe = absPath.trim().toLowerCase()
outFmt = '' outFmt = ''
act = 'copy' act = 'copy'
isPrimary = false
# If this is an "explicit" theme, all files of importance are specified in # If this is an "explicit" theme, all files of importance are specified in
# the "transform" section of the theme.json file. # the "transform" section of the theme.json file.
@ -164,6 +165,9 @@ _loadOne = ( absPath, formatsHash, tplFolder ) ->
idx = pathInfo.name.lastIndexOf '-' idx = pathInfo.name.lastIndexOf '-'
outFmt = if idx == -1 then pathInfo.name else pathInfo.name.substr idx+1 outFmt = if idx == -1 then pathInfo.name else pathInfo.name.substr idx+1
act = 'transform' if !@explicit act = 'transform' if !@explicit
defFormats = require './default-formats'
isPrimary = _.some defFormats, (form) ->
form.name == outFmt and pathInfo.extname != '.css'
# Make sure we have a valid formatsHash # Make sure we have a valid formatsHash
formatsHash[ outFmt ] = formatsHash[outFmt] || { formatsHash[ outFmt ] = formatsHash[outFmt] || {
@ -178,6 +182,7 @@ _loadOne = ( absPath, formatsHash, tplFolder ) ->
# Create the file representation object # Create the file representation object
obj = obj =
action: act action: act
primary: isPrimary
path: absPath path: absPath
orgPath: PATH.relative tplFolder, absPath orgPath: PATH.relative tplFolder, absPath
ext: pathInfo.extname.slice 1 ext: pathInfo.extname.slice 1

View File

@ -12,7 +12,7 @@ PATH = require 'path'
SLASH = require 'slash' SLASH = require 'slash'
_ = require 'underscore' _ = require 'underscore'
HMSTATUS = require '../core/status-codes' HMSTATUS = require '../core/status-codes'
SPAWN = require '../utils/safe-spawn'
###* ###*
@ -31,11 +31,10 @@ module.exports = class HtmlPdfCLIGenerator extends TemplateGenerator
###* Generate the binary PDF. ### ###* Generate the binary PDF. ###
onBeforeSave: ( info ) -> onBeforeSave: ( info ) ->
safe_eng = info.opts.pdf || 'wkhtmltopdf'; return info.mk if info.ext != 'html'
if safe_eng == 'phantom' safe_eng = info.opts.pdf || 'wkhtmltopdf'
safe_eng = 'phantomjs' safe_eng = 'phantomjs' if safe_eng == 'phantom'
if _.has engines, safe_eng if _.has engines, safe_eng
@SPAWN = require '../utils/safe-spawn'
@errHandler = info.opts.errHandler @errHandler = info.opts.errHandler
engines[ safe_eng ].call @, info.mk, info.outputFile, @onError engines[ safe_eng ].call @, info.mk, info.outputFile, @onError
return null # halt further processing return null # halt further processing
@ -68,7 +67,8 @@ engines =
# Save the markup to a temporary file # Save the markup to a temporary file
tempFile = fOut.replace /\.pdf$/i, '.pdf.html' tempFile = fOut.replace /\.pdf$/i, '.pdf.html'
FS.writeFileSync tempFile, markup, 'utf8' FS.writeFileSync tempFile, markup, 'utf8'
@SPAWN 'wkhtmltopdf', [ tempFile, fOut ], false, on_error, @ SPAWN 'wkhtmltopdf', [ tempFile, fOut ], false, on_error, @
return
@ -80,12 +80,12 @@ engines =
TODO: Local web server to ease Phantom rendering TODO: Local web server to ease Phantom rendering
### ###
phantomjs: ( markup, fOut, on_error ) -> phantomjs: ( markup, fOut, on_error ) ->
# Save the markup to a temporary file # Save the markup to a temporary file
tempFile = fOut.replace(/\.pdf$/i, '.pdf.html'); tempFile = fOut.replace /\.pdf$/i, '.pdf.html'
FS.writeFileSync tempFile, markup, 'utf8' FS.writeFileSync tempFile, markup, 'utf8'
scriptPath = SLASH( PATH.relative( process.cwd(), scriptPath = PATH.relative process.cwd(), PATH.resolve( __dirname, '../utils/rasterize.js' )
PATH.resolve( __dirname, '../utils/rasterize.js' ) ) ); scriptPath = SLASH scriptPath
sourcePath = SLASH( PATH.relative( process.cwd(), tempFile) ); sourcePath = SLASH PATH.relative( process.cwd(), tempFile)
destPath = SLASH( PATH.relative( process.cwd(), fOut) ); destPath = SLASH PATH.relative( process.cwd(), fOut)
@SPAWN 'phantomjs', [ scriptPath, sourcePath, destPath ], false, on_error, @ SPAWN 'phantomjs', [ scriptPath, sourcePath, destPath ], false, on_error, @
return

View File

@ -54,8 +54,8 @@ module.exports = class TemplateGenerator extends BaseGenerator
opts = opts =
if opts if opts
then (this.opts = EXTEND( true, { }, _defaultOpts, opts )) then (@opts = EXTEND( true, { }, _defaultOpts, opts ))
else this.opts else @opts
# Sort such that CSS files are processed before others # Sort such that CSS files are processed before others
curFmt = opts.themeObj.getFormat( this.format ) curFmt = opts.themeObj.getFormat( this.format )
@ -102,29 +102,33 @@ module.exports = class TemplateGenerator extends BaseGenerator
# etc. Process them here. # etc. Process them here.
genInfo.files.forEach ( file ) -> genInfo.files.forEach ( file ) ->
# console.dir _.omit(file.info,'cssData','data','css' )
# Pre-processing # Pre-processing
file.info.orgPath = file.info.orgPath || '' file.info.orgPath = file.info.orgPath || ''
thisFilePath = PATH.join( outFolder, file.info.orgPath ) thisFilePath =
if file.info.primary
then f
else PATH.join outFolder, file.info.orgPath
if file.info.action != 'copy' and @onBeforeSave if file.info.action != 'copy' and @onBeforeSave
file.data = this.onBeforeSave file.data = this.onBeforeSave
theme: opts.themeObj theme: opts.themeObj
outputFile: thisFilePath outputFile: thisFilePath
mk: file.data mk: file.data
opts: this.opts opts: @opts,
ext: file.info.ext
if !file.data if !file.data
return return
# Write the file # Write the file
opts.beforeWrite? thisFilePath opts.beforeWrite? thisFilePath
MKDIRP.sync PATH.dirname( thisFilePath ) MKDIRP.sync PATH.dirname( thisFilePath )
if file.info.action != 'copy' if file.info.action != 'copy'
FS.writeFileSync thisFilePath, file.data, encoding: 'utf8', flags: 'w' FS.writeFileSync thisFilePath, file.data, encoding: 'utf8', flags: 'w'
else else
FS.copySync file.info.path, thisFilePath FS.copySync file.info.path, thisFilePath
opts.afterWrite? thisFilePath opts.afterWrite? thisFilePath
# Post-processing # Post-processing

View File

@ -9,9 +9,8 @@ exception ###
module.exports = ( cmd, args, isSync, callback, param ) -> module.exports = ( cmd, args, isSync, callback, param ) ->
try try
# .spawnSync not available on earlier Node.js, so default to .spawn # .spawnSync not available on earlier Node.js, so default to .spawn
spawn = require('child_process')[ if isSync then 'spawnSync' else 'spawn']; spawn = require('child_process')[ if isSync then 'spawnSync' else 'spawn']
info = spawn cmd, args info = spawn cmd, args
# Check for error depending on whether we're sync or async TODO: Promises # Check for error depending on whether we're sync or async TODO: Promises

View File

@ -154,6 +154,7 @@ _build = ( src, dst, opts ) ->
@reject results @reject results
else if !@hasError() else if !@hasError()
@resolve results @resolve results
results results
@ -258,12 +259,10 @@ _single = ( targInfo, theme, finished ) ->
###* Ensure that user-specified outputs/targets are valid. ### ###* Ensure that user-specified outputs/targets are valid. ###
_verifyOutputs = ( targets, theme ) -> _verifyOutputs = ( targets, theme ) ->
@stat HMEVENT.verifyOutputs, { targets: targets, theme: theme } @stat HMEVENT.verifyOutputs, targets: targets, theme: theme
_.reject targets.map( ( t ) -> _.reject targets.map( ( t ) ->
pathInfo = parsePath t pathInfo = parsePath t
{ format: pathInfo.extname.substr(1) ),
format: pathInfo.extname.substr(1)
}),
(t) -> t.format == 'all' || theme.hasFormat( t.format ) (t) -> t.format == 'all' || theme.hasFormat( t.format )

View File

@ -18,7 +18,7 @@ var chai = require('chai')
describe('Testing CLI interface', function () { describe('Testing CLI interface', function () {
this.timeout(5000); this.timeout(10000);
function run( args, expErr ) { function run( args, expErr ) {
var title = args; var title = args;