capt
Version:
Command line tool for creating backbone.js applications with coffeescript
277 lines (208 loc) • 8.52 kB
text/coffeescript
fs = require('fs')
sys = require('sys')
Path = require("path")
Glob = require("glob").globSync
root = __dirname + "/../"
router = require("#{root}/lib/router")
request = require("#{root}/lib/request")
_ = require("#{root}/lib/underscore")
yaml = require("#{root}/lib/yaml")
server = router.getServer()
Project = require("#{root}/src/project").Project
String.prototype.capitalize = ->
this.charAt(0).toUpperCase() + this.substring(1).toLowerCase()
OptionParser = require("#{root}/lib/parseopt").OptionParser
parser = new OptionParser {
minargs : 0
maxargs : 10
}
$usage = '''
Usage:
capt new projectname
- create a new project
capt server
- serve the current project on port 3000
capt watch
- watch the current project and recompile as needed
Code generators:
* capt generate model post
* capt generate router posts
* capt generate view posts show
'''
# Parse command line
data = parser.parse()
#
# Raise an error
#
raise = (error) ->
sys.puts error
process.exit()
task = (command, description, func) ->
length = command.split(' ').length
if data.arguments.slice(0,length).join(" ") == command
func(data.arguments.slice(length))
task.done = true
#
# Start the server
#
task 'server', 'start a webserver', (arguments) ->
project = new Project(process.cwd())
server.get "/", (req, res, match) ->
ejs = fs.readFileSync("#{project.root}/index.jst") + ""
_.template(ejs, { project : project })
server.get "/spec/", (req, res) ->
ejs = fs.readFileSync("#{project.root}/spec/index.jst") + ""
_.template(ejs, { project : project })
server.get /(.*)/, router.staticDirHandler(project.root, '/')
project.watchAndBuild()
server.listen(3000)
task 'build', 'concatenate and minify all javascript and stylesheets for production', (arguments) ->
project = new Project(process.cwd())
sys.puts "Building #{project.name()}..."
try
fs.mkdirSync "#{project.root}/build", 0755
catch e
# .. ok ..
output = "#{project.root}/build"
try
fs.mkdirSync output, 0755
catch e
# .. ok ..
sys.puts " * Building css and js componenets"
# Todo - emit an event from project when the build is complete
project.build()
setTimeout( =>
sys.puts " * #{output}/bundled-javascript.js"
project.bundleJavascript("#{output}/bundled-javascript.js")
project.bundleStylesheet("#{output}/bundled-stylesheet.css")
# Recompile the index.html to use the bundled urls
sys.puts " * #{output}/index.html"
project.scriptIncludes = ->
project.getScriptTagFor('./build/bundled-javascript.js')
project.stylesheetIncludes = ->
project.getStyleTagFor('./build/bundled-stylesheet.css')
for file in project.getDependencies('static')
project.compileFile(file)
# ejs = fs.readFileSync("#{project.root}/index.jst") + ""
# fs.writeFileSync("#{output}/index.html", _.template(ejs, { project : project }))
, 2000)
# sys.puts " * #{output}/bundled-stylesheet.css"
# sys.puts " - " + project.getStylesheetDependencies().join("\n - ")
#
# project.bundleStylesheet("#{output}/bundled-stylesheet.css")
#
task 'watch', 'watch files and compile as needed', (arguments) ->
project = new Project(process.cwd())
project.watchAndBuild()
task 'new', 'create a new project', (arguments) ->
project = arguments[0] or raise("Must supply a name for new project.")
sys.puts " * Creating folders"
dirs = ["", "spec", "spec/jasmine", "spec/models", "spec/routers", "spec/views", "app", "app/views", "app/templates", "app/routers", "app/models", "lib", "public", "public/stylesheets", "spec/fixtures"]
for dir in dirs
fs.mkdirSync "#{project}/#{dir}", 0755
sys.puts " * Creating directory structure"
libs = {
"lib/jquery.js" : "lib/jquery.js",
"lib/underscore.js" : "lib/underscore.js"
"lib/backbone.js" : "lib/backbone.js"
"lib/less.js" : "lib/less.js"
"app/routers/application.coffee" : "routers/application.coffee"
"spec/jasmine/jasmine-html.js" : "lib/jasmine-html.js"
"spec/jasmine/jasmine.css" : "lib/jasmine.css"
"spec/jasmine/jasmine.js" : "lib/jasmine.js"
"config.yml" : "config.yml"
"index.jst" : "html/index.jst"
"spec/index.jst" : "html/runner.jst"
}
downloadLibrary = (path, lib) ->
request { uri : lib }, (error, response, body) ->
if (!error && response.statusCode == 200)
sys.puts " * " + Path.basename(path)
fs.writeFileSync("#{project}/#{path}", body)
else
sys.puts " * [ERROR] Could not download " + Path.basename(path)
copyLibrary = (path, lib) ->
fs.writeFileSync(Path.join(project, path), fs.readFileSync(lib) + "")
for path, lib of libs
if lib.match(/^http/)
downloadLibrary(path, lib)
else
copyLibrary(path, Path.join(root, "templates/", lib))
task 'generate model', 'create a new model', (arguments) ->
project = new Project(process.cwd())
if arguments[0]
model = arguments[0].toLowerCase()
else
raise("Must supply a name for the model")
copyFile = (from, to) ->
ejs = fs.readFileSync(from) + ""
fs.writeFileSync(Path.join(project.root, to), _.template(ejs, { project : project, model : model }))
sys.puts " * Created #{to}"
copyFile "#{root}/templates/models/model.coffee", "app/models/#{model}.#{project.language()}"
copyFile "#{root}/templates/models/spec.coffee", "spec/models/#{model}.#{project.language()}"
task 'generate collection', 'create a new collection', (arguments) ->
project = new Project(process.cwd())
if arguments[0]
model = arguments[0].toLowerCase()
else
raise("Must supply a name for the model")
copyFile = (from, to) ->
ejs = fs.readFileSync(from) + ""
fs.writeFileSync(Path.join(project.root, to), _.template(ejs, { project : project, model : model }))
sys.puts " * Created #{to}"
copyFile "#{root}/templates/collection/collection.coffee", "app/models/#{model}_collection.#{project.language()}"
copyFile "#{root}/templates/collection/spec.coffee", "spec/models/#{model}_collection.#{project.language()}"
task 'generate router', 'create a new router', (arguments) ->
project = new Project(process.cwd())
if arguments[0]
router = arguments[0].toLowerCase()
else
raise("Must supply a name for the router")
copyFile = (from, to) ->
ejs = fs.readFileSync(from) + ""
fs.writeFileSync(Path.join(project.root, to), _.template(ejs, { project : project, router : router }))
sys.puts " * Created #{to}"
try
fs.mkdirSync "#{project.root}/app/views/#{router}", 0755
fs.mkdirSync "#{project.root}/spec/views/#{router}", 0755
fs.mkdirSync "#{project.root}/app/templates/#{router}", 0755
catch e
# ...
copyFile "#{root}/templates/routers/router.coffee", "app/routers/#{router}_router.#{project.language()}"
copyFile "#{root}/templates/routers/spec.coffee", "spec/routers/#{router}_router.#{project.language()}"
task 'generate view', 'create a new view', (arguments) ->
project = new Project(process.cwd())
if arguments[0] and arguments[1]
router = arguments[0].toLowerCase()
view = arguments[1].toLowerCase()
else
raise("Must supply a name for the router and then view")
copyFile = (from, to) ->
ejs = fs.readFileSync(from).toString()
fs.writeFileSync(Path.join(project.root, to), _.template(ejs, { project : project, router: router, view : view }))
sys.puts " * Created #{to}"
if !Path.existsSync("#{project.root}/app/views/#{router}")
fs.mkdirSync "#{project.root}/app/views/#{router}", 0755
if !Path.existsSync("#{project.root}/app/templates/#{router}")
fs.mkdirSync "#{project.root}/app/templates/#{router}", 0755
copyFile "#{root}/templates/views/view.coffee", "app/views/#{router}/#{view}.#{project.language()}"
copyFile "#{root}/templates/templates/template.eco", "app/templates/#{router}/#{view}.eco"
copyFile "#{root}/templates/views/spec.coffee", "spec/views/#{router}/#{view}.#{project.language()}"
# task 'spec', 'run the specs', (arguments) ->
# project = new Project(process.cwd())
#
# sys.puts " * Running specs..."
#
# jasmine = require('jasmine-node')
#
# runLogger = (runner, log) ->
# if runner.results().failedCount == 0
# process.exit 0
# else
# process.exit 1
#
# jasmine.executeSpecsInFolder "spec/models", runLogger, true, true
# No task was specified...
if !task.done
sys.puts $usage
process.exit()