Refactor Cake tasks (#4440)
* Node comes with NPM nowadays, so there’s not really a reason to install CoffeeScript the non-NPM way * The cake documentation tasks should each have build and watch modes following the same form * Refactor the build tasks to be more foolproof, including the parser unless it’s explicitly excluded * Abstract out testing built code, to prepare for watching the build task * Cake task to cut a new release * cake build:watch, based on https://github.com/GeoffreyBooth/coffeescript-gulp * Coding style * Tests shouldn’t write files in a watched folder * Don’t crash if the REPL test history file is already gone by the time we try to delete it
This commit is contained in:
parent
d84c94dc6d
commit
98c1a3a045
179
Cakefile
179
Cakefile
|
@ -24,65 +24,31 @@ header = """
|
|||
*/
|
||||
"""
|
||||
|
||||
# Used in folder names like docs/v1
|
||||
# Used in folder names like `docs/v1`.
|
||||
majorVersion = parseInt CoffeeScript.VERSION.split('.')[0], 10
|
||||
|
||||
# Build the CoffeeScript language from source.
|
||||
build = (cb) ->
|
||||
files = fs.readdirSync 'src'
|
||||
files = ('src/' + file for file in files when file.match(/\.(lit)?coffee$/))
|
||||
run ['-c', '-o', 'lib/coffee-script'].concat(files), cb
|
||||
|
||||
# Run a CoffeeScript through our node/coffee interpreter.
|
||||
run = (args, cb) ->
|
||||
proc = spawn 'node', ['bin/coffee'].concat(args)
|
||||
proc.stderr.on 'data', (buffer) -> console.log buffer.toString()
|
||||
proc.on 'exit', (status) ->
|
||||
process.exit(1) if status isnt 0
|
||||
cb() if typeof cb is 'function'
|
||||
|
||||
# Log a message with a color.
|
||||
log = (message, color, explanation) ->
|
||||
console.log color + message + reset + ' ' + (explanation or '')
|
||||
|
||||
option '-p', '--prefix [DIR]', 'set the installation prefix for `cake install`'
|
||||
|
||||
task 'install', 'install CoffeeScript into /usr/local (or --prefix)', (options) ->
|
||||
base = options.prefix or '/usr/local'
|
||||
lib = "#{base}/lib/coffee-script"
|
||||
bin = "#{base}/bin"
|
||||
node = "~/.node_libraries/coffee-script"
|
||||
console.log "Installing CoffeeScript to #{lib}"
|
||||
console.log "Linking to #{node}"
|
||||
console.log "Linking 'coffee' to #{bin}/coffee"
|
||||
exec([
|
||||
"mkdir -p #{lib} #{bin}"
|
||||
"cp -rf bin lib LICENSE README.md package.json src #{lib}"
|
||||
"ln -sfn #{lib}/bin/coffee #{bin}/coffee"
|
||||
"ln -sfn #{lib}/bin/cake #{bin}/cake"
|
||||
"mkdir -p ~/.node_libraries"
|
||||
"ln -sfn #{lib}/lib/coffee-script #{node}"
|
||||
].join(' && '), (err, stdout, stderr) ->
|
||||
if err then console.log stderr.trim() else log 'done', green
|
||||
)
|
||||
spawnNodeProcess = (args, output = 'stderr', callback) ->
|
||||
relayOutput = (buffer) -> console.log buffer.toString()
|
||||
proc = spawn 'node', args
|
||||
proc.stdout.on 'data', relayOutput if output is 'both' or output is 'stdout'
|
||||
proc.stderr.on 'data', relayOutput if output is 'both' or output is 'stderr'
|
||||
proc.on 'exit', (status) -> callback(status) if typeof callback is 'function'
|
||||
|
||||
# Run a CoffeeScript through our node/coffee interpreter.
|
||||
run = (args, callback) ->
|
||||
spawnNodeProcess ['bin/coffee'].concat(args), 'stderr', (status) ->
|
||||
process.exit(1) if status isnt 0
|
||||
callback() if typeof callback is 'function'
|
||||
|
||||
|
||||
task 'build', 'build the CoffeeScript language from source', build
|
||||
|
||||
task 'build:full', 'rebuild the source twice, and run the tests', ->
|
||||
build ->
|
||||
build ->
|
||||
csPath = './lib/coffee-script'
|
||||
csDir = path.dirname require.resolve csPath
|
||||
|
||||
for mod of require.cache when csDir is mod[0 ... csDir.length]
|
||||
delete require.cache[mod]
|
||||
|
||||
unless runTests require csPath
|
||||
process.exit 1
|
||||
|
||||
|
||||
task 'build:parser', 'rebuild the Jison parser (run build first)', ->
|
||||
# Build the CoffeeScript language from source.
|
||||
buildParser = ->
|
||||
helpers.extend global, require 'util'
|
||||
require 'jison'
|
||||
parser = require('./lib/coffee-script/grammar').parser.generate()
|
||||
|
@ -95,8 +61,62 @@ task 'build:parser', 'rebuild the Jison parser (run build first)', ->
|
|||
source = fs"""
|
||||
fs.writeFileSync 'lib/coffee-script/parser.js', parser
|
||||
|
||||
buildExceptParser = (callback) ->
|
||||
files = fs.readdirSync 'src'
|
||||
files = ('src/' + file for file in files when file.match(/\.(lit)?coffee$/))
|
||||
run ['-c', '-o', 'lib/coffee-script'].concat(files), callback
|
||||
|
||||
task 'build:browser', 'rebuild the merged script for inclusion in the browser', ->
|
||||
build = (callback) ->
|
||||
buildParser()
|
||||
buildExceptParser callback
|
||||
|
||||
testBuiltCode = (watch = no) ->
|
||||
csPath = './lib/coffee-script'
|
||||
csDir = path.dirname require.resolve csPath
|
||||
|
||||
for mod of require.cache when csDir is mod[0 ... csDir.length]
|
||||
delete require.cache[mod]
|
||||
|
||||
testResults = runTests require csPath
|
||||
unless watch
|
||||
process.exit 1 unless testResults
|
||||
|
||||
buildAndTest = (includingParser = yes, harmony = no) ->
|
||||
process.stdout.write '\x1Bc' # Clear terminal screen.
|
||||
execSync 'git checkout lib/*', stdio: [0,1,2] # Reset the generated compiler.
|
||||
|
||||
buildArgs = ['bin/cake']
|
||||
buildArgs.push if includingParser then 'build' else 'build:except-parser'
|
||||
log "building#{if includingParser then ', including parser' else ''}...", green
|
||||
spawnNodeProcess buildArgs, 'both', ->
|
||||
log 'testing...', green
|
||||
testArgs = if harmony then ['--harmony'] else []
|
||||
testArgs = testArgs.concat ['bin/cake', 'test']
|
||||
spawnNodeProcess testArgs, 'both'
|
||||
|
||||
watchAndBuildAndTest = (harmony = no) ->
|
||||
buildAndTest yes, harmony
|
||||
fs.watch 'src/', interval: 200, (eventType, filename) ->
|
||||
if eventType is 'change'
|
||||
log "src/#{filename} changed, rebuilding..."
|
||||
buildAndTest (filename is 'grammar.coffee'), harmony
|
||||
fs.watch 'test/', {interval: 200, recursive: yes}, (eventType, filename) ->
|
||||
if eventType is 'change'
|
||||
log "test/#{filename} changed, rebuilding..."
|
||||
buildAndTest no, harmony
|
||||
|
||||
|
||||
task 'build', 'build the CoffeeScript compiler from source', build
|
||||
|
||||
task 'build:parser', 'build the Jison parser only', buildParser
|
||||
|
||||
task 'build:except-parser', 'build the CoffeeScript compiler, except for the Jison parser', buildExceptParser
|
||||
|
||||
task 'build:full', 'build the CoffeeScript compiler from source twice, and run the tests', ->
|
||||
build ->
|
||||
build testBuiltCode
|
||||
|
||||
task 'build:browser', 'build the merged script for inclusion in the browser', ->
|
||||
code = """
|
||||
require['../../package.json'] = (function() {
|
||||
return #{fs.readFileSync "./package.json"};
|
||||
|
@ -137,8 +157,14 @@ task 'build:browser', 'rebuild the merged script for inclusion in the browser',
|
|||
console.log "built ... running browser tests:"
|
||||
invoke 'test:browser'
|
||||
|
||||
task 'build:watch', 'watch and continually rebuild the CoffeeScript compiler, running tests on each build', ->
|
||||
watchAndBuildAndTest()
|
||||
|
||||
task 'doc:site', 'watch and continually rebuild the documentation for the website', ->
|
||||
task 'build:watch:harmony', 'watch and continually rebuild the CoffeeScript compiler, running harmony tests on each build', ->
|
||||
watchAndBuildAndTest yes
|
||||
|
||||
|
||||
buildDocs = (watch = no) ->
|
||||
# Constants
|
||||
indexFile = 'documentation/index.html'
|
||||
versionedSourceFolder = "documentation/v#{majorVersion}"
|
||||
|
@ -211,12 +237,19 @@ task 'doc:site', 'watch and continually rebuild the documentation for the websit
|
|||
fs.symlinkSync "v#{majorVersion}/index.html", 'docs/index.html'
|
||||
catch exception
|
||||
|
||||
for target in [indexFile, versionedSourceFolder, examplesSourceFolder, sectionsSourceFolder]
|
||||
fs.watch target, interval: 200, renderIndex
|
||||
log 'watching...' , green
|
||||
if watch
|
||||
for target in [indexFile, versionedSourceFolder, examplesSourceFolder, sectionsSourceFolder]
|
||||
fs.watch target, interval: 200, renderIndex
|
||||
log 'watching...', green
|
||||
|
||||
task 'doc:site', 'build the documentation for the website', ->
|
||||
buildDocs()
|
||||
|
||||
task 'doc:site:watch', 'watch and continually rebuild the documentation for the website', ->
|
||||
buildDocs yes
|
||||
|
||||
|
||||
task 'doc:test', 'watch and continually rebuild the browser-based tests', ->
|
||||
buildDocTests = (watch = no) ->
|
||||
# Constants
|
||||
testFile = 'documentation/test.html'
|
||||
testsSourceFolder = 'test'
|
||||
|
@ -254,14 +287,40 @@ task 'doc:test', 'watch and continually rebuild the browser-based tests', ->
|
|||
fs.writeFileSync "#{outputFolder}/test.html", output
|
||||
log 'compiled', green, "#{testFile} → #{outputFolder}/test.html"
|
||||
|
||||
for target in [testFile, testsSourceFolder]
|
||||
fs.watch target, interval: 200, renderTest
|
||||
log 'watching...' , green
|
||||
if watch
|
||||
for target in [testFile, testsSourceFolder]
|
||||
fs.watch target, interval: 200, renderTest
|
||||
log 'watching...', green
|
||||
|
||||
task 'doc:test', 'build the browser-based tests', ->
|
||||
buildDocTests()
|
||||
|
||||
task 'doc:test:watch', 'watch and continually rebuild the browser-based tests', ->
|
||||
buildDocTests yes
|
||||
|
||||
|
||||
task 'doc:source', 'rebuild the annotated source documentation', ->
|
||||
exec "node_modules/docco/bin/docco src/*.*coffee --output docs/v#{majorVersion}/annotated-source", (err) -> throw err if err
|
||||
buildAnnotatedSource = (watch = no) ->
|
||||
do generateAnnotatedSource = ->
|
||||
exec "node_modules/docco/bin/docco src/*.*coffee --output docs/v#{majorVersion}/annotated-source", (err) -> throw err if err
|
||||
log 'generated', green, "annotated source in docs/v#{majorVersion}/annotated-source/"
|
||||
|
||||
if watch
|
||||
fs.watch 'src/', interval: 200, generateAnnotatedSource
|
||||
log 'watching...', green
|
||||
|
||||
task 'doc:source', 'build the annotated source documentation', ->
|
||||
buildAnnotatedSource()
|
||||
|
||||
task 'doc:source:watch', 'watch and continually rebuild the annotated source documentation', ->
|
||||
buildAnnotatedSource yes
|
||||
|
||||
|
||||
task 'release', 'build and test the CoffeeScript source, and build the documentation', ->
|
||||
invoke 'build:full'
|
||||
invoke 'build:browser'
|
||||
invoke 'doc:site'
|
||||
invoke 'doc:test'
|
||||
invoke 'doc:source'
|
||||
|
||||
task 'bench', 'quick benchmark of compilation time', ->
|
||||
{Rewriter} = require './lib/coffee-script/rewriter'
|
||||
|
|
11
README.md
11
README.md
|
@ -25,15 +25,10 @@ CoffeeScript is a little language that compiles into JavaScript.
|
|||
If you have the node package manager, npm, installed:
|
||||
|
||||
```shell
|
||||
npm install -g coffee-script
|
||||
npm install --global coffee-script
|
||||
```
|
||||
|
||||
Leave off the `-g` if you don't wish to install globally. If you don't wish to use npm:
|
||||
|
||||
```shell
|
||||
git clone https://github.com/jashkenas/coffeescript.git
|
||||
sudo coffeescript/bin/cake install
|
||||
```
|
||||
Leave off the `--global` if you don’t wish to install globally.
|
||||
|
||||
## Getting Started
|
||||
|
||||
|
@ -53,7 +48,7 @@ For documentation, usage, and examples, see: http://coffeescript.org/
|
|||
|
||||
To suggest a feature or report a bug: http://github.com/jashkenas/coffeescript/issues
|
||||
|
||||
If you'd like to chat, drop by #coffeescript on Freenode IRC.
|
||||
If you’d like to chat, drop by #coffeescript on Freenode IRC.
|
||||
|
||||
The source repository: https://github.com/jashkenas/coffeescript.git
|
||||
|
||||
|
|
|
@ -2584,9 +2584,9 @@ task(<span class="string">'build:parser'</span>, <span class="string">'rebuild t
|
|||
<li><p><a href="http://github.com/jashkenas/coffeescript/">Source Code</a><br>
|
||||
Use <code>bin/coffee</code> to test your changes,<br>
|
||||
<code>bin/cake test</code> to run the test suite,<br>
|
||||
<code>bin/cake build</code> to rebuild the CoffeeScript compiler, and<br>
|
||||
<code>bin/cake build:parser</code> to regenerate the Jison parser if you’re working on the grammar.</p>
|
||||
<p><code>git checkout lib && bin/cake build:full</code> is a good command to run when you’re working on the core language. It’ll refresh the lib directory (in case you broke something), build your altered compiler, use that to rebuild itself (a good sanity test) and then run all of the tests. If they pass, there’s a good chance you’ve made a successful change.</p>
|
||||
<code>bin/cake build</code> to rebuild the full CoffeeScript compiler, and<br>
|
||||
<code>bin/cake build:except-parser</code> to recompile much faster if you’re not editing <code>grammar.coffee</code>.</p>
|
||||
<p><code>git checkout lib && bin/cake build:full</code> is a good command to run when you’re working on the core language. It’ll refresh the <code>lib</code> folder (in case you broke something), build your altered compiler, use that to rebuild itself (a good sanity test) and then run all of the tests. If they pass, there’s a good chance you’ve made a successful change.</p>
|
||||
</li>
|
||||
<li><a href="v1/test.html">Browser Tests</a><br>
|
||||
Run CoffeeScript’s test suite in your current browser.</li>
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
* [Source Code](http://github.com/jashkenas/coffeescript/)<br>
|
||||
Use `bin/coffee` to test your changes,<br>
|
||||
`bin/cake test` to run the test suite,<br>
|
||||
`bin/cake build` to rebuild the CoffeeScript compiler, and<br>
|
||||
`bin/cake build:parser` to regenerate the Jison parser if you’re working on the grammar.
|
||||
`bin/cake build` to rebuild the full CoffeeScript compiler, and<br>
|
||||
`bin/cake build:except-parser` to recompile much faster if you’re not editing `grammar.coffee`.
|
||||
|
||||
`git checkout lib && bin/cake build:full` is a good command to run when you’re working on the core language. It’ll refresh the lib directory (in case you broke something), build your altered compiler, use that to rebuild itself (a good sanity test) and then run all of the tests. If they pass, there’s a good chance you’ve made a successful change.
|
||||
`git checkout lib && bin/cake build:full` is a good command to run when you’re working on the core language. It’ll refresh the `lib` folder (in case you broke something), build your altered compiler, use that to rebuild itself (a good sanity test) and then run all of the tests. If they pass, there’s a good chance you’ve made a successful change.
|
||||
* [Browser Tests](v<%= majorVersion %>/test.html)<br>
|
||||
Run CoffeeScript’s test suite in your current browser.
|
||||
* [CoffeeScript Issues](http://github.com/jashkenas/coffeescript/issues)<br>
|
||||
|
|
|
@ -71,20 +71,21 @@ if require?
|
|||
|
||||
test "#2849: compilation error in a require()d file", ->
|
||||
# Create a temporary file to require().
|
||||
ok not fs.existsSync 'test/syntax-error.coffee'
|
||||
fs.writeFileSync 'test/syntax-error.coffee', 'foo in bar or in baz'
|
||||
tempFile = path.join os.tmpdir(), 'syntax-error.coffee'
|
||||
ok not fs.existsSync tempFile
|
||||
fs.writeFileSync tempFile, 'foo in bar or in baz'
|
||||
|
||||
try
|
||||
assertErrorFormat '''
|
||||
require './test/syntax-error'
|
||||
''',
|
||||
assertErrorFormat """
|
||||
require '#{tempFile}'
|
||||
""",
|
||||
"""
|
||||
#{path.join __dirname, 'syntax-error.coffee'}:1:15: error: unexpected in
|
||||
#{fs.realpathSync tempFile}:1:15: error: unexpected in
|
||||
foo in bar or in baz
|
||||
^^
|
||||
"""
|
||||
finally
|
||||
fs.unlinkSync 'test/syntax-error.coffee'
|
||||
fs.unlinkSync tempFile
|
||||
|
||||
test "#3890 Error.prepareStackTrace doesn't throw an error if a compiled file is deleted", ->
|
||||
# Adapted from https://github.com/atom/coffee-cash/blob/master/spec/coffee-cash-spec.coffee
|
||||
|
|
|
@ -109,4 +109,6 @@ testRepl "keeps running after runtime error", (input, output) ->
|
|||
eq 'undefined', output.lastWrite()
|
||||
|
||||
process.on 'exit', ->
|
||||
fs.unlinkSync historyFile
|
||||
try
|
||||
fs.unlinkSync historyFile
|
||||
catch exception # Already deleted, nothing else to do.
|
||||
|
|
Loading…
Reference in New Issue