-
Notifications
You must be signed in to change notification settings - Fork 1
/
Cakefile
262 lines (225 loc) · 8.37 KB
/
Cakefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
fs = require 'fs'
ps = require 'path'
{exec,spawn} = require 'child_process'
util = require 'util'
watch = require 'watch'
glob = require 'glob'
Q = require 'q'
coffee = require 'coffee-script'
mkdirp = require 'mkdirp'
Mocha = require 'mocha'
rimraf = require 'rimraf'
require 'colors'
#config
fichierATester = 'svg-def-cleaner'
appSourceDir = 'src/'
appCompiledDir = 'bin/'
specDir = 'test/spec/'
specCompiledDir = 'bin/test/'
testConfigFile = './test/config.coffee'
oneShotReporter = 'nyan' #"progress"
watchReporter = 'min' #"dot"
runTestDelay = 500 # latence entre la détection d'un fichier modifié et l'execution des test (pour éviter les test en cascade lors des enregistrement de masse)
###
Reporters mocha pour le cakefile
dot - dot matrix
doc - html documentation
spec - hierarchical spec list
json - single json object
progress - progress bar
list - spec-style listing
tap - test-anything-protocol
landing - unicode landing strip
xunit - xunit reporter
teamcity - teamcity ci support
html-cov - HTML test coverage
json-cov - JSON test coverage
min - minimal reporter (great with --watch)
json-stream - newline delimited json events
markdown - markdown documentation (github flavour)
nyan - nyan cat!
###
# internal globals
untestedChange = false
verbose = false
debug = false
option '-v', '--verbose', 'affichage détaillé'
option '-V', '--veryverbose', 'affichage très détaillé (debug)'
task 'dummy', 'sandbox task for building process experiment'.cyan, (options)->
setGlobalOptions options
console.log 'dummy is dummy'.rainbow.bold
task 'watch', "A chaque changement sauvegardé, recompile les fichiers concernés et exécute les tests".cyan, (options)->
watchTask options
watchTask = (options)->
setGlobalOptions options
Q(buildTask options).then ->
testTask options
new Monitor(appSourceDir,appFileChange,appFileChange,rmAppFile)
new Monitor(specDir,specFileChange,specFileChange,rmSpecFile)
task "test", "exécute les tests".cyan, (options)->
testTask options
testTask = (options, reporter=oneShotReporter)->
q = Q.defer()
setGlobalOptions options
util.log 'Préparation des tests'.cyan if debug
require testConfigFile
util.log testConfigFile + ' chargé'.yellow if debug
# TODO: arboressance applicative à inclure pour lancer les test dessus.
delete require.cache[ps.resolve('.', appCompiledDir+fichierATester+'.js')] # chemin absolue nécessaire
#require './'+appCompiledDir+fichierATester+'.js'
mocha = new Mocha
mocha.reporter reporter
testFilesPattern = specCompiledDir+'**/*.js'
util.log 'Liste les fichiers répondant au motif '.cyan + testFilesPattern if debug
glob testFilesPattern, (err, fileList)->
for file in fileList
util.log 'spec : '.cyan + file if debug
delete require.cache[ps.resolve('.', file)] # chemin absolue nécessaire
mocha.addFile file
util.log 'Execution des tests'.cyan if verbose
mocha.run ->
util.log 'Tests terminés'.cyan if verbose
q.resolve()
q.promise
task 'build', 'compile tous les fichiers des dossiers '.cyan + appSourceDir + ' dans '.cyan + appCompiledDir + ' et '.cyan + specDir + ' dans '.cyan + specCompiledDir, (options)->
buildTask options
buildTask = (options)->
q = Q.defer()
setGlobalOptions options
util.log "Vous utilisez Node.js version ".cyan + process.version + ' sous '.cyan + process.platform + ' ' + process.arch if verbose
util.log "NODE_PATH: ".cyan + process.env.NODE_PATH
Q.all([
coffee2jsTree specDir, specCompiledDir
coffee2jsTree appSourceDir, appCompiledDir
]).done ->
util.log 'Compilation terminée'.cyan
q.resolve()
q.promise
task "clean", "supprime les dossiers ".cyan + specDir + ' et '.cyan + appSourceDir, (options)->
cleanTask options
cleanTask = (options)->
setGlobalOptions options
util.log "Nétoyage du projet...".cyan
Q.all([
rmRecursive specCompiledDir
rmRecursive appCompiledDir
]).done ->
util.log "Nétoyage Terminé".cyan
appFileChange = (file) ->
# recompiler puis lancer les test
coffee2js(file, coffee2jsChPathName file, appSourceDir, appCompiledDir).then ->
untestedChange = true
setTimeout runTestIfChange, runTestDelay
specFileChange = (file) ->
# recompiler puis lancer les test
coffee2js(file, coffee2jsChPathName(file, specDir, specCompiledDir)).then ->
untestedChange = true
setTimeout runTestIfChange, runTestDelay
rmSpecFile = (file) ->
# supprimer la version compiler puis lancer les test
rmRecursive(coffee2jsChPathName file, specDir, specCompiledDir).then ->
untestedChange = true
setTimeout runTestIfChange, runTestDelay
rmAppFile = (file) ->
# supprimer la version compiler puis lancer les test
rmRecursive(coffee2jsChPathName file, appSourceDir, appCompiledDir).then ->
untestedChange = true
setTimeout runTestIfChange, runTestDelay
coffee2js = (coffeeFile, jsFile) ->
# si le js n'existe pas ou est plus vieux, compiler, sinon, ne rien faire.
q = Q.defer()
Q.allSettled([
fs_stat coffeeFile
fs_stat jsFile
]).then (res)->
if res[0].state is "fulfilled"
coffeeTime = res[0].value.mtime
else
q.reject res[0].reason
if res[1].state is "fulfilled"
jsTime = res[1].value.mtime
if !jsTime or jsTime < coffeeTime
util.log 'Compile '.yellow + coffeeFile + ' to '.yellow + jsFile if verbose
# open file
fs.readFile coffeeFile, 'utf8', (err, data) ->
q.reject err if err
# compile file
compiled = coffee.compile data
# extract path from path+filename
path = jsFile.split('/')
path.pop()
path = path.join('/')
# create dir if not exist
mkdirp path, (err)->
q.reject err if err
# write file
fs.writeFile jsFile, compiled, (err) ->
q.reject err if err
q.resolve()
else
util.log jsFile + ' déjà à jour'.grey if debug
q.resolve()
q.promise
coffee2jsTree = (coffeeFolder, jsFolder) ->
q = Q.defer()
pattern = coffeeFolder+'**/*.coffee'
util.log 'liste les fichiers répondant au motif '.cyan + pattern if debug
glob pattern, (err, fileList)->
q.reject err if err
promesse = []
for file in fileList
promesse.push coffee2js file, coffee2jsChPathName file, coffeeFolder, jsFolder
Q.all(promesse).then ->
q.resolve coffeeFolder + ' -> ' + jsFolder + ' OK'
q.promise
coffee2jsChPathName = (file, coffeeFolder, jsFolder)->
file.replace(/\\/g,'/').replace(coffeeFolder, jsFolder).replace '.coffee', '.js'
# correction de la coloration syntaxique de sublime text 2 '
Monitor = (folder, changeCallBack, newCallBack, rmCallBack) ->
this.lastStamp = 'static var'
this.lastFileList = []
watch.watchTree folder, (file, curr, prev) ->
this.lastFileList = [] if this.lastStamp isnt (new Date).toLocaleTimeString()
this.lastStamp = (new Date).toLocaleTimeString()
if prev is null and curr is null and file instanceof Object
util.log "Finished walking ".cyan + folder + " tree".cyan if debug
else
if lastFileList[file]
util.log ('echo '+file).grey if debug
else
if prev is null
util.log 'new '.green + file if verbose
newCallBack(file)
else if curr.nlink is 0
util.log 'rm '.red + file if verbose
rmCallBack(file)
else
util.log 'change '.yellow + file if verbose
changeCallBack(file)
this.lastFileList[file]=true
setGlobalOptions = (options) ->
if options
if options.verbose then verbose = true
if options.veryverbose
verbose = true
debug = true
delay = (ms, func) -> setTimeout func, ms
fs_stat = (file)->
q = Q.defer()
fs.stat file, (err, stat)->
q.reject err if err
q.resolve stat
q.promise
rmRecursive = (folder)->
q = Q.defer()
rimraf folder, (err)->
if err
q.reject err
else
util.log folder + ' supprimé'.yellow if verbose
q.resolve()
q.promise
runTestIfChange = ->
if untestedChange
untestedChange = false
testTask null, watchReporter