foreach-cli
Version:
CLI util to execute a command for each file matching a glob
107 lines (65 loc) • 2.71 kB
text/coffeescript
fs = require('fs')
path = require('path')
glob = require('glob')
chalk = require('chalk')
Listr = require '@danielkalen/listr'
exec = require('child_process').exec
regEx = require './regex'
module.exports = (options)-> new Promise (finish)->
finalLogs = 'log':{}, 'error':{}
globOptions = {}
if options.ignore then globOptions.ignore = options.ignore
if options.nodir then globOptions.nodir = options.nodir
glob options.glob, globOptions, (err, files)-> if err then return console.error(err) else
tasks = new Listr files.map((file)=>
title: "Executing command: #{chalk.dim(file)}"
task: ()=> executeCommand(file)
), options # same as {concurrent:options.concurrent}
tasks.run().then(outputFinalLogs, outputFinalLogs)
executeCommand = (filePath)-> new Promise (resolve, reject)->
pathParams = path.parse path.resolve(filePath)
pathParams.reldir = getDirName(pathParams, path.resolve(filePath))
command = options.command.replace regEx.placeholder, (entire, placeholder)-> switch
when placeholder is 'path' then filePath
when pathParams[placeholder]? then pathParams[placeholder]
else entire
if options.forceColor and process.platform isnt 'win32'
command = "FORCE_COLOR=true #{command}"
exec command, (err, stdout, stderr)->
if isValidOutput(stdout) then finalLogs.log[filePath] = stdout
if isValidOutput(stderr) and not isValidOutput(err)
finalLogs.log[filePath] = stderr
else if isValidOutput(err)
finalLogs.error[filePath] = stderr or err
if isValidOutput(err) then reject() else resolve()
## ==========================================================================
## Helpers
## ==========================================================================
getDirName = (pathParams, filePath)->
dirInGlob = options.glob.match(/^[^\*\/]*/)[0]
dirInGlob += if dirInGlob then '/' else ''
filePath
.replace pathParams.base, ''
.replace process.cwd()+"/#{dirInGlob}", ''
.slice(0, -1)
isValidOutput = (output)->
output and
output isnt 'null' and
(
(typeof output is 'string' and output.length >= 1) or
(typeof output is 'object')
)
formatOutputMessage = (message)->
if options.trim
message.slice(0, options.trim)
else
message
outputFinalLogs = ()-> if Object.keys(finalLogs.log).length or Object.keys(finalLogs.error).length
process.stdout.write '\n\n'
for file,message of finalLogs.log
console.log chalk.bgWhite.black.bold("Output")+' '+chalk.dim(file)
console.log formatOutputMessage(message)
for file,message of finalLogs.error
console.log chalk.bgRed.white.bold("Error")+' '+chalk.dim(file)
console.log formatOutputMessage(message)
finish()