diff --git a/.gitignore b/.gitignore index 65b85ce..064485c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules/ test/ +lib/ bin/ diff --git a/build.sh b/build.sh deleted file mode 100755 index bfad41d..0000000 --- a/build.sh +++ /dev/null @@ -1,4 +0,0 @@ -mkdir -p bin -echo '#!/usr/bin/env node' > bin/pert -coffee -b -c --no-header -p src/pert.coffee >> bin/pert -chmod +x bin/pert diff --git a/package.json b/package.json index b87a59b..a09ab9a 100644 --- a/package.json +++ b/package.json @@ -2,13 +2,14 @@ "name": "pert", "version": "0.1.0", "description": "pert diagram calculator", - "main": "pert.coffee", + "main": "lib/pert.js", "bin": { "pert": "./bin/pert" }, "scripts": { - "prepublish": "./build.sh", - "build": "./build.sh" + "prepublish": "scripts/build.sh", + "build": "scripts/build.sh", + "clean": "scripts/clean.sh" }, "repository": { "type": "git", diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..c2eb0c7 --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,5 @@ +mkdir -p bin lib +echo '#!/usr/bin/env node' > bin/pert +coffee -b -c --no-header -p src/pert-cli.coffee >> bin/pert +chmod +x bin/pert +coffee -b -c --no-header -p src/pert.coffee > lib/pert.js diff --git a/scripts/clean.sh b/scripts/clean.sh new file mode 100755 index 0000000..3263499 --- /dev/null +++ b/scripts/clean.sh @@ -0,0 +1,2 @@ +#!/bin/bash +rm -rf bin lib diff --git a/src/pert-cli.coffee b/src/pert-cli.coffee new file mode 100755 index 0000000..6ffc38c --- /dev/null +++ b/src/pert-cli.coffee @@ -0,0 +1,40 @@ +#!/usr/bin/env coffee +chalk = require 'chalk' +cli = require 'commander' +fs = require 'fs' +pert = require '../lib/pert.js' + +ex = [{id: 0, depends: [], duration: 2}, { id: 1, depends: [0], duration: 3},{id: 2, depends: [0,1], duration: 4}] + +cli + .version '0.1' + .usage 'loads activity data from JSON and computes the possible activity delays' + .option '--verbose', 'be verbose (for debugging)' + +didSomething = no + +cli + .command 'example' + .description 'show an example of the JSON data format' + .action -> + didSomething = yes + console.log chalk.bold.green('Before:'), ex + console.log chalk.bold.green('After calculations:'), pert.calculate ex + console.log chalk.green 'Tip:',chalk.bold 'optional fields can be freely included in the input data' + +cli + .command 'calculate ' + .description 'calculate data on given JSON document' + .alias 'c' + .option '-j, --json', 'output json data' + .action (file,options) -> + didSomething = yes + fs.readFile file, (error,content) -> + if error then err error + else + if options.json then console.log JSON.stringify (pert.calculate JSON.parse(content)) + else console.log pert.calculate JSON.parse(content) + +cli.parse process.argv + +if !didSomething then console.log chalk.green('Tip:'), 'see', chalk.bold(cli.name()+' --help') diff --git a/src/pert.coffee b/src/pert.coffee index 4719945..c5f8b74 100755 --- a/src/pert.coffee +++ b/src/pert.coffee @@ -1,85 +1,52 @@ -#!/usr/bin/env coffee chalk = require 'chalk' -cli = require 'commander' fs = require 'fs' -log = (x...) -> if cli.verbose then console.log chalk.bold("Log:"), x... -err = (x...) -> console.log chalk.bold (chalk.red "Error:"), x... +pert = + log: (x...) -> if @verbose then console.log chalk.bold("Pert:"), x... + err: (x...) -> console.log chalk.bold (chalk.red "Pert:"), x... -# Returns the highest number in an array of numbers -maxa = (l) -> return Math.max.apply null, l + # Returns the highest number in an array of numbers + maxa: (l) -> return Math.max.apply null, l -# Find the activity with given id -toActivity = (id,list) -> - if !list? then err "list is",list - item = {} - list.forEach (x) -> if x.id is id then item = x - return item + # Find the activity with given id + toActivity: (id,list) -> + if !list? then pert.err "list is",list + item = {} + list.forEach (x) -> if x.id is id then item = x + return item -# Find the item -calculateEndDay = (item,list) -> - if !item.startDay? - log "calculating start day of",item.id - item.startDay = calculateStartDay item, list - log "start day of",item.id,"is",item.startDay - item.endDay = item.startDay + item.duration - log "end day of",item.id,"is",item.endDay - return item.endDay + # Find the item + calculateEndDay: (item,list) -> + if !item.startDay? + pert.log "calculating start day of",item.id + item.startDay = pert.calculateStartDay item, list + pert.log "start day of",item.id,"is",item.startDay + item.endDay = item.startDay + item.duration + pert.log "end day of",item.id,"is",item.endDay + return item.endDay -# Find out which day the activity starts -calculateStartDay = (item,list) -> - if !item.depends? or item.depends.length is 0 then return item.startDay = 0 - item.startDay = maxa item.depends.map((x) -> toActivity x,list).map((x) -> calculateEndDay x, list) - log "start day of",item.id,"is",item.startDay - # write max delay time to each depend - item.depends.forEach (x) -> - log "checking permittedDelay to dependency", x, "of", item - i = toActivity x, list - if !i.permittedDelay? - i.permittedDelay = item.startDay - calculateEndDay i, list - log "written permittedDelay to dependency", x, "of", item, "as", i.permittedDelay - else log "aborting permittedDelay: already calculated" - log "permitted delay of",x,"is",i.permittedDelay - return item.startDay + # Find out which day the activity starts + calculateStartDay: (item,list) -> + if !item.depends? or item.depends.length is 0 then return item.startDay = 0 + item.startDay = pert.maxa item.depends.map((x) -> pert.toActivity x,list).map((x) -> pert.calculateEndDay x, list) + pert.log "start day of",item.id,"is",item.startDay + # write max delay time to each depend + item.depends.forEach (x) -> + pert.log "checking permittedDelay to dependency", x, "of", item + i = pert.toActivity x, list + if !i.permittedDelay? + i.permittedDelay = item.startDay - pert.calculateEndDay i, list + pert.log "written permittedDelay to dependency", x, "of", item, "as", i.permittedDelay + else pert.log "aborting permittedDelay: already calculated" + pert.log "permitted delay of",x,"is",i.permittedDelay + return item.startDay -# Find out which activity has the highest id -highestID = (list) -> return maxa(list.map (x) -> x.id) + # Find out which activity has the highest id + highestID: (list) -> return pert.maxa(list.map (x) -> x.id) -calculate = (list) -> - calculateEndDay (toActivity highestID(list), list), list - return list + calculate: (list,verbose) -> + pert.verbose = verbose + pert.calculateEndDay (pert.toActivity pert.highestID(list), list), list + return list -ex = [{id: 0, depends: [], duration: 2}, { id: 1, depends: [0], duration: 3},{id: 2, depends: [0,1], duration: 4}] - -cli - .version '0.1' - .usage 'loads activity data from JSON and computes the possible activity delays' - .option '--verbose', 'be verbose (for debugging)' - -didSomething = no - -cli - .command 'example' - .description 'show an example of the JSON data format' - .action -> - didSomething = yes - console.log chalk.bold.green('Before:'), ex - console.log chalk.bold.green('After calculations:'), calculate ex - console.log chalk.green 'Tip:',chalk.bold 'optional fields can be freely included in the input data' - -cli - .command 'calculate ' - .description 'calculate data on given JSON document' - .alias 'c' - .option '-j, --json', 'output json data' - .action (file,options) -> - didSomething = yes - fs.readFile file, (error,content) -> - if error then err error - else - if options.json then console.log JSON.stringify (calculate JSON.parse(content)) - else console.log calculate JSON.parse(content) - -cli.parse process.argv - -if !didSomething then console.log chalk.green('Tip:'), 'see', chalk.bold(cli.name()+' --help') +module.exports = pert