├── README.md ├── externs └── jquery-mobile.js └── jzbuild.py /README.md: -------------------------------------------------------------------------------- 1 | I love languages where you need years of experience to write code that works, 2 | and languages where if you don't do everything exactly right, you will shoot 3 | yourself in the foot. (See my article [C++: A language for 4 | next generation web apps](http://stevehanov.ca/blog/?id=95). Naturally, I love 5 | javascript. 6 | 7 | Fortunately, Javascript has tools that will help catch bugs before you run it. 8 | One is JsLint. Following Douglas Crockford's crazy rules eliminates many 9 | cross-browser compatablility problems, and it syntax-checks the code too. The 10 | Google Closure compiler performs static analysis of the code to catch a few 11 | more problems, and as a bonus it will compress and obfuscate your code for you. 12 | 13 | JZBUILD is a build system to simplify the process. 14 | 15 | [Download JZBUILD](http://github.com/smhanov/jzbuild/raw/master/jzbuild.py) 16 | 17 | JZBUILD will: 18 | 19 | * Run all of your javascript through a built-in copy of jslint for error 20 | checking. 21 | * Convert Coffeescript files to Javascript. 22 | * Concatenate files together and feed them into the Closure compiler or YUI 23 | compressor, without sending your code over the web. 24 | * Process include directives. JZBUILD resolves dependencies so your files 25 | will be included in the proper order. 26 | * Include files from other folders. For example, you might have a folder full 27 | of re-usable javascript components that are used in several projects. JZBUILD 28 | will let you pull these files into your current project. 29 | 30 | JZBUILD is designed to be easy to use. 31 | 32 | * JZBUILD only requires python and Java to run. If you don't have another 33 | tool that it needs, it will download it automatically. 34 | * You don't need any configuration file. By default, JZBUILD will process all 35 | files in the current folder. 36 | * JZBUILD includes built-in "externs" for the closure compiler, so it will 37 | work with projects that use the jquery javascript library. It includes other tricks to make the compiler work on your code. 38 | * It works on Linux and Windows 39 | 40 | ## Tutorial 41 | 42 | Although this example is in Windows, JZBUILD works equally well on Linux. 43 | 44 | Suppose you have a folder full of javascript files -- eg, foo.js, and bar.js. 45 | 46 |
 47 |  Directory of H:\demo
 48 | 
 49 | 07/29/2010  09:25    <DIR>          .
 50 | 07/29/2010  09:25    <DIR>          ..
 51 | 07/29/2010  09:26              8392 foo.js
 52 | 07/29/2010  09:26              2303 bar.js
 53 |                2 File(s)           10293 bytes
 54 |                2 Dir(s)     377,483,264 bytes free
 55 | 
56 | 57 | 58 | Run JsLint on them: 59 | 60 |
 61 | jzbuild.py
 62 | 
63 | 64 | Run JsLint and concatenate them together into MyWebApplication.js: 65 | 66 |
 67 | jzbuild.py --out MyWebApplication.js
 68 | 
69 | 70 | Run JsLint and compress them using the YUI compressor into MyWebApplication.js. The YUI compressor will be downloaded for you. 71 | 72 |
 73 | jzbuild.py --out MyWebApplication.js --compiler yui
 74 | 
75 | 76 | Run JsLint and compress them using the Google closure compiler into 77 | MyWebApplication.js. The compiler will be downloaded for you. 78 | 79 |
 80 | jzbuild.py --out MyWebApplication.js --compiler closure
 81 | 
82 | 83 | ### Included files 84 | 85 | JZBUILD processes include directives by searching the current folder and any 86 | included files. Suppose foo.bar contained a line like this: 87 | 88 |
 89 | //#include <bar.js>
 90 | 
91 | 92 | And bar.js contained a line like this: 93 | 94 |
 95 | //#include <MyUsefulFunctions.js>
 96 | 
97 | 98 | Where MyUsefulFunctions.js is in the folder ../shared. Then you can 99 | compile your whole web application by specifying only "foo.js" on the command 100 | line: 101 | 102 |
103 | jzbuild.py --out MyWebApplication.js --compiler closure -I../shared foo.js
104 | 
105 | 106 | The -I option says to search the given path for input or included files. 107 | JZBUILD takes a list of input files on the command line. It reads each of them 108 | and processes included files as well, and sticks all of them together before 109 | sending them to the output file. 110 | 111 | Note: It is incorrect to say JZBUILD "includes" files. The files are only included once, no matter how many times you specify "#include". This directive will be renamed "@require" in a future version. 112 | 113 | ## Advanced Usage 114 | 115 | When it starts, and you didn't specify "--out" on the command line, JZBUILD 116 | will look for a file named "makefile.jz" in the current folder. 117 | 118 | ## Example makefile.jz 119 | 120 | Here's an example makefile.jz. In it, we specify two projects to build. The 121 | "release" project will use the closure compiler to create MyWebApplication.js 122 | from "foo.js" and all files that it includes, searching in the folder 123 | "../shared" for any included files. It will also prepend "license.js" to the 124 | output. 125 | 126 | It also specifies a second project, called "debug". The "debug" project 127 | contains the option "base: release", which means to inherit all the settings 128 | from the "release" project. 129 | 130 | When this makefile is in the current folder, you can build a specific project 131 | by specifying its name on the command line. For example, to build the release 132 | project, use: 133 | 134 |
135 | jzbuild.py release
136 | 
137 | 138 |
139 | // You can use comments in a JZBUILD makefile.jz. The file format is exactly like
140 | // JSON, except that quotes and commas are optional.
141 | // A file is an object of projects. Each project produces one output file.
142 | // When you invoke JZBUILD you must specify a project to build unless there
143 | // is only one in the file.
144 | {
145 |     // Here is a project description. You only need one project but we will
146 |     // define several for completeness.
147 | 
148 |     // You can give a project a name. You can use it to refer to the project
149 |     // from other projects.
150 |     release: {
151 |         // The output file will be created from the input files. It is a
152 |         // string with the path to the output file.
153 |         output: MyWebApplication.js
154 | 
155 |         // 'input' is an array of input files. You should use only the filename
156 |         // and not the path. When jsbuild starts it will automatically find
157 |         // the files it needs from the include path. It will also expand this
158 |         // list based on any //#include  directives.
159 |         input: [foo.js]
160 | 
161 |         prepend: [license.js]
162 | 
163 |         // The include path specifies an array of paths to search for files.
164 |         // It always includes the current folder.
165 |         include: [../shared]
166 | 
167 |         // The compiler specifies the compiler to use. The default compiler is
168 |         // 'cat' which simply appends files together. The other
169 |         // option is 'closure' which refers to Google's closure compiler. If
170 |         // you do not have the closure compiler JZBUILD will download it for
171 |         // you. However you will need to have Java installed to use it.
172 |         compiler: closure
173 | 
174 |         // Here are the options to the closure compiler.
175 |         compilerOptions: [
176 |             --compilation_level ADVANCED_OPTIMIZATIONS
177 |             --warning_level VERBOSE
178 |         ]
179 |     }
180 | 
181 |     // Here is a second project.
182 |     debug: {
183 | 
184 |         // This project is special because it inherits all the properties from
185 |         // its parent project. It specifies the parent by name.
186 |         base: release
187 | 
188 |         // Here we override the options to the closure compiler to include
189 |         // pretty-printing so we can easily see what it is doing.
190 |         compilerOptions: [
191 |             --compilation_level ADVANCED_OPTIMIZATIONS
192 |             --warning_level VERBOSE
193 |             --define=ENABLE_DEBUG=true
194 |             --formatting PRETTY_PRINT
195 |         ]
196 |     }
197 | }
198 | 
199 | 200 | ## Coffeescript support 201 | If any .coffee files are specified as input, JZBUILD will download Coffeescript and use it to convert them to 202 | Javascript. It stores the result in the same location as the original .coffee file, except with a .js extension. 203 | 204 | A special version of coffeescript is used that works with the Google closure compiler, and does not depend on 205 | Google libraries. 206 | 207 | If you specify the --closure compiler on the command line, the code will be type checked for you. To get the maximum 208 | benefit from the type checking, you can annotate your code with types. Refer to 209 | [Google's Closure Annotation page](http://code.google.com/closure/compiler/docs/js-for-compiler.html) for examples. 210 | Enclose closure annotations between ###* ### comments. For example: 211 | 212 |
213 | 
214 | ###* @param {number} count
215 |      @return {string} 
216 | ###
217 | makeSpaces: (count) ->
218 |     result = []
219 |     result.push " " for i in count
220 |     result.join ""
221 |       
222 | 
223 | 224 | ## Goodies to make the Closure compiler work properly 225 | 226 | ### Built in externs 227 | 228 | An externs file is built in to JZBUILD, so you can use the jquery library with the closure compiler, and it will give you useful warnings when you call the functions with the wrong parameter types. 229 | 230 | ### @export annotation 231 | A painful reality (and the whole point) of using the advanced compilation mode of the closure compiler is that it renames everything, so if you need to refer to a property of an object from HTML then it won't work unless you "export" it as described here. 232 | 233 | JZBUILD makes this easy using the @export annotation. For example: 234 | 235 |
236 | //@export MyGreatObject
237 | /** @constructor */
238 | function MyGreatObject()
239 | {
240 | 
241 | }
242 | 
243 | //@export MyGreatObject.prototype.dostuff
244 | MyGreatObject.prototype.dostuff = function()
245 | {
246 | 
247 | }
248 | 
249 | 250 | When the compiler is set to "closure", the above will cause JZBUILD to add the required exports to the code. Specifically: 251 | 252 |
253 | window["MyGreatObject"] = MyGreatObject;
254 | MyGreatObject.prototype["dostuff"] = MyGreatObject.prototype.dostuff;
255 | 
256 | 257 | ## License 258 | The JZBUILD system is open source. It is released to the public domain. However, it contains portions of code that fall under other licenses. The full license information is found in the source code. 259 | 260 | 261 | 262 | 263 | 264 | -------------------------------------------------------------------------------- /externs/jquery-mobile.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | */ 4 | jQuery.prototype.mobile = {}; 5 | 6 | /** 7 | @param {jQuery|string} to 8 | @param {string=} transition 9 | @param {boolean=} back 10 | @param {string=} changeHash 11 | */ 12 | jQuery.prototype.mobile.changePage = function(to, transition, back, changeHash 13 | ) 14 | { 15 | } 16 | 17 | /** 18 | @param {string} arg 19 | */ 20 | jQuery.prototype.listview = function(arg) {} 21 | 22 | 23 | -------------------------------------------------------------------------------- /jzbuild.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | """ 3 | JZBUILD Javascript build system 4 | 5 | By Steve Hanov (steve.hanov@gmail.com) 6 | 7 | This is free software. It is released to the public domain. 8 | 9 | ------------------------------------------------------------------------------ 10 | ------------------------------------------------------------------------------ 11 | ------------------------------------------------------------------------------ 12 | The JZBUILD software may include jslint software, which is covered under the 13 | following license. 14 | 15 | /* 16 | Copyright (c) 2002 Douglas Crockford (www.JSLint.com) 17 | 18 | Permission is hereby granted, free of charge, to any person obtaining a copy of 19 | this software and associated documentation files (the "Software"), to deal in 20 | the Software without restriction, including without limitation the rights to 21 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 22 | of the Software, and to permit persons to whom the Software is furnished to do 23 | so, subject to the following conditions: 24 | 25 | The above copyright notice and this permission notice shall be included in all 26 | copies or substantial portions of the Software. 27 | 28 | The Software shall be used for Good, not Evil. 29 | 30 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 31 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 32 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 33 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 34 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 35 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 36 | SOFTWARE. 37 | */ 38 | 39 | ------------------------------------------------------------------------------ 40 | ------------------------------------------------------------------------------ 41 | ------------------------------------------------------------------------------ 42 | Coffeescript is covered under the following license. 43 | 44 | Copyright (c) 2011 Jeremy Ashkenas 45 | 46 | Permission is hereby granted, free of charge, to any person 47 | obtaining a copy of this software and associated documentation 48 | files (the "Software"), to deal in the Software without 49 | restriction, including without limitation the rights to use, 50 | copy, modify, merge, publish, distribute, sublicense, and/or sell 51 | copies of the Software, and to permit persons to whom the 52 | Software is furnished to do so, subject to the following 53 | conditions: 54 | 55 | The above copyright notice and this permission notice shall be 56 | included in all copies or substantial portions of the Software. 57 | 58 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 59 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 60 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 61 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 62 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 63 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 64 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 65 | OTHER DEALINGS IN THE SOFTWARE. 66 | ------------------------------------------------------------------------------ 67 | ------------------------------------------------------------------------------ 68 | ------------------------------------------------------------------------------ 69 | JCoffeeScript is covered under the following license: 70 | /* 71 | * Copyright 2010 David Yeung 72 | * 73 | * Licensed under the Apache License, Version 2.0 (the "License"); 74 | * you may not use this file except in compliance with the License. 75 | * You may obtain a copy of the License at 76 | * 77 | * http://www.apache.org/licenses/LICENSE-2.0 78 | * 79 | * Unless required by applicable law or agreed to in writing, software 80 | * distributed under the License is distributed on an "AS IS" BASIS, 81 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 82 | * See the License for the specific language governing permissions and 83 | * limitations under the License. 84 | */ 85 | """ 86 | 87 | import sys 88 | if sys.version_info < (3, 0): 89 | import urllib 90 | import urllib2 91 | import httplib 92 | else: 93 | # for python 3, make the adaptations here and then code as if 94 | # we are in python 2.7 95 | import http.client as httplib 96 | import urllib.request as urllib2 97 | import urllib.parse as urllib_parse 98 | 99 | class urllib: pass 100 | urllib.urlencode = urllib_parse.urlencode 101 | import atexit 102 | import base64 103 | import fnmatch 104 | import glob 105 | import gzip 106 | import io 107 | import json 108 | import os 109 | import platform 110 | import re 111 | import subprocess 112 | import time 113 | import tempfile 114 | import sys 115 | import zipfile 116 | import zlib 117 | 118 | MAKEFILE_NAME = "makefile.jz" 119 | 120 | NEVER_CHECK_THESE_FILES = """ 121 | jquery.min.js 122 | jquery.js 123 | prototype.js 124 | """.split("\n") 125 | 126 | COMPILERS = { 127 | # Name of the compiler, as specified in the makefile and the --compiler 128 | # option. 129 | "closure": { 130 | # URL at which to download a zipfile of the compiler 131 | # USed to be at: "http://dl.google.com/closure-compiler/compiler-latest.zip" 132 | "download": 133 | "http://www.hanovsolutions.com/build/compiler-20180910.zip", 134 | 135 | # full path in the zip file of the compiler. 136 | "filename": 137 | "closure-compiler*.jar", 138 | 139 | # These options are always specified. 140 | "requiredOptions": ['--process_common_js_modules', '--module_resolution', 'node'], 141 | 142 | # Command line option that must precede each input filename 143 | "inputOption": 144 | "--js", 145 | 146 | # Command line option to specify the output file 147 | "outputOption": 148 | "--js_output_file", 149 | 150 | # Default options to use if none are specified 151 | "defaultOptions": [ 152 | "--compilation_level", "SIMPLE_OPTIMIZATIONS", 153 | "--warning_level", "VERBOSE" ], 154 | 155 | # Options to use if none are specified and user is doing a --release 156 | # build. 157 | "releaseOptions": [ 158 | "--compilation_level", "ADVANCED_OPTIMIZATIONS", 159 | "--warning_level", "VERBOSE" ], 160 | 161 | # Set this to True if the tool can't take the input on the command 162 | # line, and instead requires input to be concatenated together and 163 | # piped to its standard input. 164 | "requiresStdin": False, 165 | 166 | }, 167 | 168 | "yui": { 169 | "download": 170 | "http://yui.zenfs.com/releases/yuicompressor/yuicompressor-2.4.2.zip", 171 | "filename": 172 | "yuicompressor-2.4.2/build/yuicompressor-2.4.2.jar", 173 | "requiredOptions": ["--type", "js"], 174 | "inputOption": "", 175 | "outputOption": "-o", 176 | "defaultOptions": [], 177 | "requiresStdin": True, 178 | }, 179 | } 180 | 181 | EXTERNS = { 182 | "jquery-1.5.js": 183 | "http://closure-compiler.googlecode.com/svn/trunk/contrib/externs/jquery-1.5.js", 184 | "jquery-mobile.js": 185 | "http://github.com/smhanov/jzbuild/raw/master/externs/jquery-mobile.js", 186 | } 187 | 188 | JCOFFEESCRIPT_URL = \ 189 | "http://www.hanovsolutions.com/build/jcoffeescript-1.1.jar" 190 | COFFEESCRIPT_URL = \ 191 | "https://raw.githubusercontent.com/smhanov/coffee-script/master/extras/coffee-script.js" 192 | def GetStorageFolder(): 193 | """Returns the path to a location where we can store downloads""" 194 | 195 | # Seems to work on windows 7 too 196 | path = os.path.join(os.path.expanduser("~"), ".jzbuild") 197 | if not os.path.isdir(path): 198 | print("Creating %s" % path) 199 | os.mkdir(path) 200 | return path 201 | 202 | JAVA_PATH='java' 203 | 204 | JCOFFEESCRIPT_PATH = \ 205 | os.path.join(GetStorageFolder(), os.path.basename( JCOFFEESCRIPT_URL ) ) 206 | 207 | COFFEESCRIPT_PATH = \ 208 | os.path.join(GetStorageFolder(), os.path.basename( COFFEESCRIPT_URL ) ) 209 | 210 | COFFEESCRIPT_NODEJS_PATH = \ 211 | os.path.join(GetStorageFolder(), "coffee-script-node.js" ) 212 | 213 | TYPESCRIPT_URL = "http://www.hanovsolutions.com/build/tsc.js" 214 | 215 | VALID_COMPILERS = list(COMPILERS.keys()); 216 | VALID_COMPILERS.append("cat") 217 | 218 | # Path to node js, if found on system. This is used to run coffeescript much 219 | # faster then java. 220 | PATH_TO_NODEJS = None 221 | 222 | MAN_PAGE = """ 223 | NAME 224 | 225 | jzbuild - The easy Javascript build system 226 | 227 | SYNOPSIS 228 | 229 | jzbuild [files or projects] 230 | 231 | DESCRIPTION 232 | 233 | Runs jslint and joins together javascript input files, optionally using the 234 | Google closure compiler or YUI compressor to reduce file size and find more 235 | errors. 236 | 237 | Jzbuild looks for a file named "makefile.jz" in the current folder. If 238 | found, it reads the list of projects and options from that file. Otherwise, 239 | it uses the options given from the command line, or defaults. 240 | 241 | Jzbuild will download and use the Coffeescript compiler to seemlessly 242 | handle files ending in ".coffee". 243 | 244 | If node.js is installed on your non-windows system, jzbuild will use it to 245 | compile coffeescript much faster. 246 | 247 | [files] 248 | 249 | If no filenames are given and no makefile is present, Jzbuild will 250 | run jslint on all files matching the pattern "*.js" in the current 251 | folder. 252 | 253 | [projects] 254 | 255 | If a makefile is present, the names given on the command line refer to 256 | projects in the makefile. 257 | 258 | --out 259 | 260 | Specifies output file name. If an output file is given, the makefile is 261 | ignored. This option is called "output" in the makefile. 262 | 263 | --prepend 264 | 265 | Specifies a file for prepending. The include path will be searched for 266 | the file, and it will be prepended to the output. This option may be 267 | specified multiple times. This option is ignored if a makefile is 268 | resent. 269 | 270 | -I 271 | 272 | Specifies a folder to be searched for included files. This option may 273 | be specified multiple times. The current folder is always in the 274 | include path. This option is ignored if a makefile is present. 275 | 276 | --compiler 277 | 278 | Specifies the compiler to use. This option is ignored if a makefile is 279 | present. Valid options are VALID_COMPILERS. If you do not have the 280 | given compiler, it will be downloaded. 281 | 282 | --cloud 283 | 284 | If specified, then the Google closure compiler service is used. Your 285 | code will be sent over the internet to be compiled. 286 | 287 | --release 288 | 289 | Specifies that we should use a advanced compilation options, such 290 | as minification, if available. 291 | 292 | --watch 293 | After compiling, monitor files for changes and recompile whenever one 294 | changes. 295 | 296 | clean 297 | 298 | If the word "clean" is given as an option, the output file is erased 299 | instead of created, and JSLINT is not run. 300 | 301 | MAKEFILE FORMAT 302 | 303 | When jzbuild starts, it runs in one of two modes -- 304 | 305 | 1. If the '--out' option is not specified, it searches the current 306 | folder for a file named "MAKEFILE_JZ". If it is found, the settings 307 | are processed as described below. 308 | 309 | 2. If the "--out" option is given, or MAKEFILE_JZ is not found, then it 310 | builds a list of input files from '*.js', excluding any common 311 | javascript libraries such as jquery. 312 | 313 | The makefile is formatted in Lazy JSON. This is exactly like JSON, except 314 | that quotes and commas are optional. The Makefile consists of a single 315 | object whos keys are project names. For example: 316 | 317 | { 318 | release: { 319 | input: [ foo.js bar.js ] 320 | include: [ ../shared ] 321 | output: foo-compressed.js 322 | compiler: closure 323 | } 324 | 325 | yui { 326 | base: release 327 | output: foo-yui-compressed.js 328 | compiler: yui 329 | } 330 | } 331 | 332 | The above defines two projects named "release", and "yui". The release 333 | project consists of foo.js and bar.js, as well as any files that they 334 | include. The include path searched is the current folder as well as 335 | "../shared". 336 | 337 | The yui project specifies "base: release". That means that it inherits any 338 | unset properties from the project named "release". 339 | 340 | Here is a list of valid options for a project: 341 | 342 | input 343 | A string or array of files that will be compiled together, along 344 | with any files they include. 345 | 346 | output 347 | The output filename. If none is given, the compiler will not run. 348 | Only JSLINT checking will be performed. 349 | 350 | include 351 | A single string, or array of strings that specify the paths to 352 | search when looking for input files, or the files that they 353 | include. The current folder is always part of the include path. 354 | 355 | compiler 356 | The name of the compiler to use. Valid compilers are 357 | VALID_COMPILERS. The default is "cat" 358 | 359 | compilerOptions 360 | Compiler options to use. Jzbuild contains suitable defaults for 361 | each compiler. But they can be overridden. 362 | 363 | base 364 | Specifies another project from which to inherit the above settings. 365 | 366 | prepend 367 | A single string, or array of strings specifying the names of files 368 | which are prepended to the output. No error checking is performed 369 | on these files, and they are not compiled. 370 | 371 | """.replace("VALID_COMPILERS", 372 | ",".join(VALID_COMPILERS)).replace("MAKEFILE_JZ", MAKEFILE_NAME) 373 | 374 | # Make these variables global, and set them later. 375 | RHINO_CMD = "" 376 | JSLINT_RHINO = "" 377 | CLOSURE_EXTERNS = "" 378 | 379 | # Keep temporary files here so they are not deleted until program exit. 380 | # There are problems with using NamedTemporaryFile delete=True on windows, so 381 | # do it manually. 382 | TemporaryFiles = [] 383 | 384 | def cleanupBeforeExit(): 385 | for temp in TemporaryFiles: 386 | if os.path.exists( temp.name ): 387 | temp.close() 388 | os.unlink( temp.name ) 389 | 390 | atexit.register( cleanupBeforeExit ) 391 | 392 | 393 | class LazyJsonParser: 394 | """This class parses Lazy JSON. Currently it does not take advantage of 395 | python language features such as generators or regular expressions. It 396 | is designed to be a reference decoder that is easily portable to other 397 | languages such as Javascript and C. 398 | """ 399 | 400 | class Token: 401 | def __init__(self, type, start, length): 402 | self.type = type 403 | self.start = start 404 | self.length = length 405 | 406 | def getText( self, text ): 407 | return text[self.start:self.start + self.length] 408 | 409 | def __init__(self, text): 410 | self.text = text 411 | self.pos = -1 412 | 413 | # Possible token types 414 | self.TOKEN_EOF = -2 415 | self.TOKEN_ERROR = -1 416 | self.TOKEN_LEFT_BRACE = 0 417 | self.TOKEN_RIGHT_BRACE = 1 418 | self.TOKEN_LEFT_BRACKET = 2 419 | self.TOKEN_RIGHT_BRACKET = 3 420 | self.TOKEN_STRING = 4 421 | self.TOKEN_COLON = 5 422 | 423 | # Possible values of STATE 424 | self.STATE_START = 0 425 | self.STATE_WHITESPACE = 1 426 | self.STATE_SLASH = 2 427 | self.STATE_SLASH_SLASH = 3 428 | self.STATE_SLASH_STAR = 4 429 | self.STATE_SLASH_STAR_STAR = 5 430 | self.STATE_STRING = 6 431 | self.STATE_SQUOTED_STRING = 7 432 | self.STATE_SQUOTED_STRING2 = 8 433 | self.STATE_SESCAPE = 9 434 | self.STATE_DQUOTED_STRING = 10 435 | self.STATE_DQUOTED_STRING2 = 11 436 | self.STATE_DESCAPE = 12 437 | 438 | self.ACTION_SINGLE_CHAR = 1 439 | self.ACTION_SUBTRACT_1 = 2 440 | self.ACTION_SUBTRACT_2 = 4 441 | self.ACTION_STORE_POS = 8 442 | self.ACTION_TOKEN = 16 443 | self.ACTION_ERROR = 17 444 | 445 | # Represents any character in the state machine transition table. 446 | self.ANY = '' 447 | 448 | # Represents whitespace in the state machine transition table. 449 | WS = "\n\r\t ," 450 | 451 | # There are better ways of writing a tokenizer in python. However, I 452 | # wanted a parser for Lazy JSON that is easily portable to other languages such as C. 453 | self.fsm = [ 454 | # in state, when we get this char, switch to state, perform these actions, action data 455 | [ self.STATE_START, '{', self.STATE_START, self.ACTION_SINGLE_CHAR, self.TOKEN_LEFT_BRACE ], 456 | [ self.STATE_START, '}', self.STATE_START, self.ACTION_SINGLE_CHAR, self.TOKEN_RIGHT_BRACE ], 457 | [ self.STATE_START, '[', self.STATE_START, self.ACTION_SINGLE_CHAR, self.TOKEN_LEFT_BRACKET ], 458 | [ self.STATE_START, ']', self.STATE_START, self.ACTION_SINGLE_CHAR, self.TOKEN_RIGHT_BRACKET ], 459 | [ self.STATE_START, ':', self.STATE_START, self.ACTION_SINGLE_CHAR, self.TOKEN_COLON ], 460 | [ self.STATE_START, WS, self.STATE_WHITESPACE, 0 ], 461 | [ self.STATE_START, '/', self.STATE_SLASH, 0 ], 462 | [ self.STATE_START, '"', self.STATE_DQUOTED_STRING, 0 ], 463 | [ self.STATE_START, "'", self.STATE_SQUOTED_STRING, 0 ], 464 | [ self.STATE_START, self.ANY, self.STATE_STRING, self.ACTION_STORE_POS | self.ACTION_SUBTRACT_1 ], 465 | [ self.STATE_WHITESPACE, WS, self.STATE_WHITESPACE, 0 ], 466 | [ self.STATE_WHITESPACE, self.ANY, self.STATE_START, self.ACTION_SUBTRACT_1 ], 467 | [ self.STATE_SLASH, '/', self.STATE_SLASH_SLASH, 0 ], 468 | [ self.STATE_SLASH, '*', self.STATE_SLASH_STAR, 0 ], 469 | [ self.STATE_SLASH, self.ANY, self.STATE_STRING, self.ACTION_SUBTRACT_2 | self.ACTION_STORE_POS ], 470 | [ self.STATE_SLASH_SLASH, '\n', self.STATE_START, 0 ], 471 | [ self.STATE_SLASH_SLASH, self.ANY, self.STATE_SLASH_SLASH, 0 ], 472 | [ self.STATE_SLASH_STAR, '*', self.STATE_SLASH_STAR_STAR, 0 ], 473 | [ self.STATE_SLASH_STAR, self.ANY, self.STATE_SLASH_STAR, 0 ], 474 | [ self.STATE_SLASH_STAR_STAR, '/', self.STATE_START, 0 ], 475 | [ self.STATE_SLASH_STAR_STAR, self.ANY, self.STATE_SLASH_STAR, 0 ], 476 | [ self.STATE_STRING, "[]{}:"+WS, self.STATE_START, self.ACTION_TOKEN | self.ACTION_SUBTRACT_1, self.TOKEN_STRING ], 477 | [ self.STATE_STRING, self.ANY, self.STATE_STRING, 0 ], 478 | [ self.STATE_DQUOTED_STRING, self.ANY, self.STATE_DQUOTED_STRING2, self.ACTION_STORE_POS | self.ACTION_SUBTRACT_1 ], 479 | [ self.STATE_DQUOTED_STRING2, '\n', self.STATE_DQUOTED_STRING2, self.ACTION_ERROR, "Newline in string"], 480 | [ self.STATE_DQUOTED_STRING2, '\\', self.STATE_DESCAPE, 0 ], 481 | [ self.STATE_DQUOTED_STRING2, '"', self.STATE_START, self.ACTION_TOKEN, self.TOKEN_STRING ], 482 | [ self.STATE_DQUOTED_STRING2, self.ANY, self.STATE_DQUOTED_STRING2, 0 ], 483 | [ self.STATE_DESCAPE, self.ANY, self.STATE_DQUOTED_STRING2, 0 ], 484 | [ self.STATE_SQUOTED_STRING, self.ANY, self.STATE_SQUOTED_STRING2, self.ACTION_STORE_POS | self.ACTION_SUBTRACT_1 ], 485 | [ self.STATE_SQUOTED_STRING2, '\n', self.STATE_SQUOTED_STRING2, self.ACTION_ERROR, "Newline in string"], 486 | [ self.STATE_SQUOTED_STRING2, '\\', self.STATE_SESCAPE, 0 ], 487 | [ self.STATE_SQUOTED_STRING2, "'", self.STATE_START, self.ACTION_TOKEN, self.TOKEN_STRING ], 488 | [ self.STATE_SQUOTED_STRING2, self.ANY, self.STATE_SQUOTED_STRING2, 0 ], 489 | [ self.STATE_SESCAPE, self.ANY, self.STATE_SQUOTED_STRING2, 0 ], 490 | ] 491 | 492 | # One previous token is allowed to be unshifted back. Store that token here. 493 | self.unshifted = None 494 | 495 | def unshift(self, token): 496 | self.unshifted = token 497 | 498 | def next(self): 499 | """Get the next token. Returns an object with the type, start, and 500 | length of the token in the text.""" 501 | 502 | # Return the unshifted token if there is one. 503 | if self.unshifted != None: 504 | token = self.unshifted 505 | self.unshifted = None 506 | return token 507 | 508 | state = self.STATE_START 509 | storedPos = 0 510 | 511 | while 1: 512 | self.pos = self.pos + 1 513 | #print "%c: %d" % (self.text[self.pos], state) 514 | 515 | if self.pos >= len(self.text): 516 | if state == self.STATE_START: 517 | return LazyJsonParser.Token(self.TOKEN_EOF, self.pos, 0) 518 | else: 519 | return LazyJsonParser.Token(self.TOKEN_ERROR, self.pos, 0) 520 | 521 | for transition in self.fsm: 522 | if transition[0] == state and (transition[1] == self.ANY 523 | or self.text[self.pos] in transition[1]): 524 | originalPos = self.pos 525 | 526 | if transition[3] & self.ACTION_STORE_POS: 527 | storedPos = self.pos 528 | 529 | if transition[3] & self.ACTION_SUBTRACT_1: 530 | self.pos -= 1 531 | 532 | if transition[3] & self.ACTION_SUBTRACT_2: 533 | self.pos -= 2 534 | 535 | if transition[3] & self.ACTION_SINGLE_CHAR: 536 | return LazyJsonParser.Token( transition[4], originalPos, 1 ) 537 | 538 | if transition[3] & self.ACTION_TOKEN: 539 | pos = self.pos 540 | return LazyJsonParser.Token( transition[4], storedPos, originalPos - 541 | storedPos ) 542 | 543 | if transition[3] & self.ACTION_ERROR: 544 | self.error( LazyJsonParser.Token( self.TOKEN_ERROR, 545 | originalPos, transition[4] ) ) 546 | 547 | state = transition[2] 548 | break 549 | else: 550 | return LazyJsonParser.Token( self.TOKEN_ERROR, self.pos, 1 ) 551 | 552 | def unescape( self, str ): 553 | """Unescape JSON string""" 554 | 555 | ret = "" 556 | i = 0 557 | while i < len( str ): 558 | if i < len( str ) - 1 and str[i] == '\\': 559 | i += 1 560 | if str[i] == 'b': 561 | ret += '\b' 562 | elif str[i] == 'f': 563 | ret += '\f' 564 | elif str[i] == 'n': 565 | ret += '\n' 566 | elif str[i] == 'r': 567 | ret += '\r' 568 | elif str[i] == 't': 569 | ret += '\t' 570 | else: 571 | ret += str[i] 572 | else: 573 | ret += str[i] 574 | i += 1 575 | return ret 576 | 577 | def parse( self ): 578 | """ Parse a single item, which may contain other items """ 579 | 580 | token = self.next() 581 | if token.type == self.TOKEN_EOF: 582 | return None 583 | 584 | if token.type == self.TOKEN_LEFT_BRACE: 585 | # Parse a list of string : item, followed by brace 586 | value = {} 587 | while 1: 588 | token = self.next() 589 | if token.type == self.TOKEN_RIGHT_BRACE: 590 | break 591 | elif token.type == self.TOKEN_STRING: 592 | key = self.unescape(token.getText(self.text)) 593 | else: 594 | self.error( token, "Expected a string" ) 595 | 596 | token = self.next() 597 | if token.type != self.TOKEN_COLON: 598 | self.error( token, "Expected ':'" ) 599 | 600 | value[key] = self.parse() 601 | 602 | elif token.type == self.TOKEN_LEFT_BRACKET: 603 | # Parse list of strings followed by bracket 604 | value = [] 605 | while 1: 606 | token = self.next() 607 | if token.type == self.TOKEN_RIGHT_BRACKET: 608 | break 609 | elif token.type < 0: 610 | self.error( token, "Expected ']'" ) 611 | self.unshift( token ) 612 | item = self.parse() 613 | value.append( item ) 614 | 615 | elif token.type == self.TOKEN_STRING: 616 | # Just a string. 617 | value = self.unescape(token.getText(self.text)) 618 | 619 | else: 620 | self.error( token, "Expected: '{', '[', or string" ) 621 | 622 | return value 623 | 624 | def error( self, token, message ): 625 | line = 1 626 | pos = 1 627 | for i in range( token.start ): 628 | if self.text[i] == '\n': 629 | line += 1 630 | pos = 1 631 | else: 632 | pos += 1 633 | raise Exception( "Error on line %d:%d: %s" % (line, pos, message) ) 634 | 635 | def ParseLazyJson( text ): 636 | """Wrapper for LazyJsonParser class that transforms Lazy JSON or JSON text 637 | into a python object.""" 638 | return LazyJsonParser(text).parse(); 639 | 640 | # Global variable to say whether we are on windows. 641 | IsWindows = platform.system() == "Windows" 642 | 643 | def ReplaceSlashes(list): 644 | """Transform unix style slashes into the path separator of the system that 645 | we are running on""" 646 | 647 | if os.path.sep == '/': return list 648 | newList = [] 649 | for item in list: 650 | newList.append( item.replace( "/", os.path.sep ) ) 651 | return newList 652 | 653 | 654 | class DependencyGraph: 655 | """ Represents a dependency graph. A dependency graph contains items that 656 | depend on other items. After adding all of the nodes, you can call the 657 | walk() method to get a list of the items in topological order. 658 | """ 659 | def __init__(self): 660 | self.nodes = {} 661 | 662 | def addDependency(self, child, parent): 663 | """Add a dependency to the graph. The child and parent nodes are added to 664 | the graph if not already present. Then, the child depends on the 665 | parent. It is not necessary to call the addNode() method to add the nodes 666 | first. 667 | """ 668 | child = self.__getNodeFor( child ) 669 | parent = self.__getNodeFor( parent ) 670 | 671 | if not self.__find( child, parent ): 672 | parent.children.append( child ) 673 | child.parents.append( parent ) 674 | return True 675 | else: 676 | return False 677 | 678 | def __find( self, parent, node ): 679 | """Searches the parent for the given node, and if found, returns True 680 | """ 681 | if parent == node: return True 682 | for child in parent.children: 683 | if self.__find( child, node ): 684 | return True 685 | return False 686 | 687 | def addNode( self, data ): 688 | """Adds a single node to the graph with no dependencies. Dependencies may 689 | be added afterward using the addDepenency() method. If no dependencies are 690 | added, then the node will appear early in the topological sort. 691 | """ 692 | 693 | self.__getNodeFor( data ) 694 | 695 | def walk( self ): 696 | """Returns the topological sort of the nodes. 697 | """ 698 | 699 | L = [] 700 | S = [n for n in self.nodes.values() if len(n.parents) == 0] 701 | # sorting them preserves the order as much as possible. 702 | S.sort(key = lambda a: a.index, reverse=True) 703 | 704 | while len(S) > 0: 705 | n = S.pop() 706 | L.append( n ) 707 | for m in n.children[:]: 708 | del n.children[n.children.index(m)] 709 | del m.parents[m.parents.index(n)] 710 | if len( m.parents ) == 0: 711 | S.append( m ) 712 | 713 | return [s.data for s in L] 714 | 715 | def __getNodeFor( self, data ): 716 | if data in self.nodes: 717 | return self.nodes[data] 718 | 719 | self.nodes[data] = self.__DependencyNode( data, len(self.nodes) ) 720 | return self.nodes[data] 721 | 722 | class __DependencyNode: 723 | """ Represents a node in the dependency graph. This class is used 724 | internally in the dependency graph. """ 725 | 726 | def __init__(self, data, index): 727 | 728 | self.data = data 729 | self.parents = [] 730 | self.children = [] 731 | self.index = index 732 | 733 | def __repr__(self): 734 | return str(self.index) 735 | 736 | class Analysis: 737 | """ 738 | Analyses the javascript files and stores the result. The analysis includes 739 | a topological sort of included files as well as a list of exports. 740 | 741 | fileListIn specifies a list of files 742 | 743 | vpath is a list of folders in which to search for the files in the file list 744 | as well as any included files. 745 | """ 746 | def __init__(self, fileListIn, vpath): 747 | graph = DependencyGraph() 748 | 749 | # Are we missing any files that were included? 750 | self._isMissingFiles = False 751 | 752 | # Set of fully qualified paths that we have already processed. 753 | filesProcessed = {} 754 | 755 | # List of files awaiting processing 756 | filesToProcess = [] 757 | 758 | self.exports = [] 759 | 760 | includeRe_js = re.compile(r"""\/\/#include\s+[<"]([^>"]+)[>"]""") 761 | exportRe_js = re.compile(r"""@export ([A-Za-z_\$][A-Za-z_0-9\.\$]*)""") 762 | 763 | includeRe_coffee = re.compile(r"""#include\s+[<"]([^>"]+)[>"]""") 764 | exportRe_coffee = re.compile(r"""@export ([A-Za-z_\$][A-Za-z_0-9\.\$]*)""") 765 | 766 | includeRe_ts = re.compile(r""" from '([^']+)'""") 767 | 768 | self.vpath = vpath 769 | 770 | # contains named temporary files. They will be automatically deleted by 771 | # python when the Analysis goes out of scope. 772 | self.tempFiles = [] 773 | 774 | # contains the input files for the project. 775 | self.inputFiles = [] 776 | 777 | # Contains list of files that comprise the project, after replacements 778 | # have been made. 779 | self.fileList = [] 780 | 781 | # If this is non-empty, then an error occurred and compilation cannot 782 | # continue. 783 | self.errors = [] 784 | 785 | def processFile( path ): 786 | """Given the full path to a file, open it and look for includes. For 787 | each include found, add it to the file list and update the dependency 788 | graph with the dependency. 789 | """ 790 | contents = open( path, "r" ).readlines() 791 | graph.addNode( path ) 792 | filesProcessed[path] = 1; 793 | 794 | if path.endswith(".coffee"): 795 | includeRe = includeRe_coffee 796 | exportRe = exportRe_coffee 797 | else: 798 | includeRe = includeRe_js 799 | exportRe = exportRe_js 800 | 801 | for line in contents: 802 | 803 | m = exportRe.search( line ) 804 | if m: 805 | self.exports.append( m.group(1) ) 806 | 807 | m = includeRe.search( line ) 808 | 809 | if not m: 810 | m = includeRe_ts.search( line ) 811 | 812 | if not m: continue 813 | 814 | includedPath = self.__findFile( m.group(1) ) 815 | 816 | if includedPath: 817 | if includedPath not in filesProcessed: 818 | filesToProcess.append( includedPath ) 819 | graph.addDependency( path, includedPath ) 820 | else: 821 | print('Error: Could not find file "%s" included from "%s"' % \ 822 | (m.group(1), path )) 823 | self._isMissingFiles = True 824 | 825 | # Augment each file passed in with full path information. 826 | for name in fileListIn: 827 | path = self.__findFile( name ) 828 | if path: 829 | filesToProcess.append( path ) 830 | else: 831 | print("File not found: " + name) 832 | 833 | # while the file list is not empty, remove and process a file. 834 | while len( filesToProcess ): 835 | processFile( filesToProcess.pop() ) 836 | 837 | # spit out dependencies... 838 | self.fileList = graph.walk() 839 | self.inputFiles.extend(self.fileList) 840 | 841 | def addFileToStart( self, filename ): 842 | """ 843 | Add a file to the start. This is used to place the coffee script 844 | utilities at the top of the compiled output. It is different from 845 | prepended files because the contents are passed to the compiler, 846 | whereas prepended files are not. 847 | """ 848 | self.fileList = [filename] + self.fileList 849 | 850 | def addContentToStart( self, contents ): 851 | temp = tempfile.NamedTemporaryFile( mode="w", delete=False ) 852 | temp.write(contents) 853 | self.tempFiles.append( temp.name ) 854 | self.addFileToStart( temp.name ) 855 | 856 | def prependFiles( self, fileNames ): 857 | """Search for each file in the vpath and prepend its path to the 858 | filelist returned by getFileList() 859 | """ 860 | 861 | files = [] 862 | for name in fileNames: 863 | path = self.__findFile( name ) 864 | if path != none: 865 | files.append( path ) 866 | else: 867 | print("File not found: {0}".format(name)) 868 | 869 | files.extend( self.fileList ) 870 | self.fileList = files 871 | 872 | def __findFile( self, file ): 873 | # for each vpath entry, 874 | for path in self.vpath: 875 | # join it with the filename 876 | fullname = os.path.join(path, file) 877 | (base, ext) = os.path.splitext(fullname) 878 | 879 | # if it exists, return it. 880 | if os.path.exists( base + ".coffee" ): 881 | return base + ".coffee" 882 | elif os.path.exists( base + ".ts" ): 883 | return base + ".ts" 884 | elif os.path.exists( base + ".txt" ): 885 | return base + ".txt" 886 | elif os.path.exists( fullname ): 887 | return fullname 888 | 889 | else: 890 | return None 891 | 892 | def getFileList(self): 893 | return self.fileList 894 | 895 | def getInputFiles(self): 896 | return self.inputFiles 897 | 898 | def replaceFile(self, source, destination): 899 | for i in range(len(self.fileList)): 900 | if self.fileList[i] == source: 901 | self.fileList[i] = destination 902 | return 903 | 904 | def getExports(self): 905 | # keep track of exports already written. 906 | written = {} 907 | str = "" 908 | 909 | # for each export, 910 | for export in self.exports: 911 | 912 | if export in written: continue 913 | written[export] = 1 914 | 915 | # split into . components. 916 | names = export.split(".") 917 | 918 | if len(names) == 1: 919 | # one component. use window["name"] = name; 920 | str += 'window["%s"] = %s;\n' % (names[0], export ) 921 | else: 922 | # more that one component. Only the last is exported. 923 | str += (".".join(names[:-1]) + 924 | '["%s"] = %s;\n' % (names[-1], export ) ) 925 | 926 | return str 927 | 928 | def getInputFilesEndingWith( self, extension ): 929 | return filter( lambda f: f.endswith( extension), self.fileList ) 930 | 931 | def isMissingFiles(self): 932 | return self._isMissingFiles 933 | 934 | def ConvertTextFiles(analysis, targetTime, options): 935 | """Convert files of the form filename.txt into a javascript file, 936 | containing a single variable var FILENAME="" 937 | followed by the text string. 938 | """ 939 | for f in analysis.getFileList(): 940 | if not f.lower().endswith(".txt"): continue 941 | destination = f + ".js"; 942 | if not os.path.exists(destination) or \ 943 | os.path.getmtime(f) > os.path.getmtime(destination): 944 | print("Converting %s->%s" % (f, destination)) 945 | input = open(f, "r") 946 | output = open(destination, "wb"); 947 | varname = os.path.splitext(os.path.basename(f))[0].upper() 948 | output.write("var {0} =\n".format(varname).encode("utf8")) 949 | first = True 950 | for line in input: 951 | if first: 952 | output.write(" ".encode("utf-8")) 953 | first = False; 954 | else: 955 | output.write(" +\n ".encode("utf-8")) 956 | json.dump(line, output) 957 | if first: 958 | output.write(""); #empty file 959 | output.write(";\n") 960 | analysis.replaceFile(f, destination) 961 | 962 | def RunJsLint(files, targetTime, options): 963 | """Run Jslint on each file in the list that has a modification time greater 964 | than the targetTime. Returns the number of files processed. 965 | 966 | If jslint is not available in the storage folder, then create it. 967 | """ 968 | 969 | storagePath = GetStorageFolder() 970 | 971 | numProcessed = 0 972 | 973 | # Create the jslint-rhino file if it does not exist. 974 | jslint = os.path.join( storagePath, "jslint-rhino.js" ); 975 | if not os.path.exists( jslint ): 976 | print("%s not found. Creating." % jslint) 977 | f = open(jslint, "wb") 978 | f.write(zlib.decompress(base64.b64decode(JSLINT_RHINO))) 979 | f.close() 980 | 981 | # run the JSlint-rhino file on any files which are newer than the 982 | # target. 983 | cmd = [] 984 | cmd.extend(RHINO_CMD) 985 | cmd.append( jslint ) 986 | 987 | for f in files: 988 | if not f.endswith(".js"): continue 989 | if os.path.getmtime(f) > targetTime: 990 | cmd.append(f); 991 | numProcessed += 1 992 | 993 | if numProcessed > 0: 994 | subprocess.call(cmd) 995 | 996 | return numProcessed 997 | 998 | def CompileCoffeeScript( analysis, options, compiler, joined, targetTime ): 999 | """ 1000 | For files that end in .coffee, compile them to .coffee.js if they are 1001 | newer than the existing .js file. 1002 | 1003 | compiler is the name of the compiler that will be used. 1004 | 1005 | noJoin is specified when there is no output file. In that case, all the 1006 | coffeescript files will be translated, but they will not be joined 1007 | together later. That affects the options that we use. 1008 | 1009 | Only files newer than the targetTime or the .coffee file are compiled. 1010 | """ 1011 | anyCoffee = False 1012 | 1013 | closureMode = compiler == 'closure' or joined 1014 | typeScriptFiles = [] 1015 | 1016 | for filename in analysis.getFileList(): 1017 | (path, ext) = os.path.splitext(filename) 1018 | if ext == ".coffee": 1019 | destination = path + ".coffee.js" 1020 | anyCoffee = True 1021 | success = True 1022 | if not os.path.exists(destination) or \ 1023 | os.path.getmtime(filename) > os.path.getmtime(destination): 1024 | success = RunCoffeeScript( filename, destination, closureMode ) 1025 | 1026 | if success: 1027 | analysis.replaceFile( filename, destination ) 1028 | else: 1029 | analysis.errors.append("Error in " + filename + 1030 | ": Coffeescript compiler failed") 1031 | elif ext == '.ts': 1032 | destination = path + ".js" 1033 | success = True 1034 | if not os.path.exists(destination) or \ 1035 | os.path.getmtime(filename) > os.path.getmtime(destination): 1036 | typeScriptFiles.append((filename, destination)) 1037 | analysis.replaceFile(filename, destination) 1038 | 1039 | if anyCoffee: 1040 | analysis.addContentToStart( COFFEESCRIPT_UTILITIES ) 1041 | 1042 | if typeScriptFiles: 1043 | cmd = ["tsc"] 1044 | for filename, destination in typeScriptFiles: 1045 | cmd.append(filename) 1046 | if 0 != subprocess.call(cmd): 1047 | analysis.errors.append("Typescript failed.") 1048 | 1049 | def DownloadProgram(url, fileInZip, outputPath): 1050 | """Given a url to a zip file, a path to a file within that zip file, and an 1051 | output file, it downloads the zip and extracts it to the given path. 1052 | 1053 | If the target file already exists it does nothing.""" 1054 | 1055 | if not list(glob.glob(outputPath )): 1056 | print("%s not found! Downloading from %s" % (outputPath, url)) 1057 | 1058 | url = urllib2.urlopen( url ) 1059 | dataFile = bytes() 1060 | while 1: 1061 | data = url.read( 1024 ) 1062 | if len(data) == 0: break 1063 | dataFile += data 1064 | sys.stdout.write("Read %d bytes\r" % len(dataFile)) 1065 | 1066 | zip = zipfile.ZipFile( io.BytesIO( dataFile ), "r" ) 1067 | for info in zip.infolist(): 1068 | print("file={}, basename={}, fileInZip={}".format(info.filename, os.path.basename(info.filename), fileInZip)) 1069 | if fileInZip == info.filename or fnmatch.fnmatch(os.path.basename(info.filename), fileInZip): 1070 | open(outputPath, "wb").write(zip.read(info.filename)) 1071 | 1072 | return True 1073 | 1074 | HaveCoffeeScript = os.path.exists( JCOFFEESCRIPT_PATH ) 1075 | 1076 | def DownloadCoffeeScript(): 1077 | global HaveCoffeeScript 1078 | if not HaveCoffeeScript: 1079 | print("Downloading JCoffeescript...") 1080 | try: 1081 | open(JCOFFEESCRIPT_PATH, "wb").write( urllib2.urlopen(JCOFFEESCRIPT_URL).read() ) 1082 | print(COFFEESCRIPT_URL) 1083 | open(COFFEESCRIPT_PATH, "wb").write( urllib2.urlopen(COFFEESCRIPT_URL).read() ) 1084 | except: 1085 | for name in [JCOFFEESCRIPT_PATH, COFFEESCRIPT_PATH]: 1086 | if os.path.exists(name): 1087 | os.unlink(name) 1088 | raise 1089 | HaveCoffeeScript = True 1090 | 1091 | if not os.path.exists(COFFEESCRIPT_NODEJS_PATH): 1092 | # This little driver is added to the stock coffeescript to get it to 1093 | # run from node.js 1094 | append = """ 1095 | var fs = require('fs') 1096 | var args = process.argv; 1097 | var errors = false; 1098 | var options = {}; 1099 | var files = []; // 0th and every even one is input, odd ones are output. 1100 | for(var i = 2; i < args.length; i++ ) { 1101 | // the special options added for jzbuild 1102 | if (args[i] == "--bare") 1103 | options.bare = true; 1104 | else if (args[i] == "--noutil") 1105 | options.noutil = true; 1106 | else if (args[i] == "--closure") 1107 | options.closure = true; 1108 | else 1109 | files.push(args[i]) 1110 | } 1111 | 1112 | for (i = 0; i < files.length; i += 2 ) { 1113 | var jsContents= fs.readFileSync(files[i], "utf-8"); 1114 | try { 1115 | var coffeeContent = this.CoffeeScript.compile(jsContents, 1116 | options); 1117 | fs.writeFileSync(files[i+1], coffeeContent, "utf-8"); 1118 | } catch(e) { 1119 | process.stderr.write("" + e + "\\n"); 1120 | errors = true; 1121 | } 1122 | } 1123 | 1124 | process.exit(errors ? 1 : 0); 1125 | """ 1126 | 1127 | coffeescript = open(COFFEESCRIPT_PATH, "r").read() + append 1128 | open(COFFEESCRIPT_NODEJS_PATH, "w").write(coffeescript) 1129 | 1130 | def RunCoffeeScript( source, destination, closureMode ): 1131 | DownloadCoffeeScript() 1132 | 1133 | if PATH_TO_NODEJS != None: 1134 | # Use the fast node.js version 1135 | commands = [ PATH_TO_NODEJS, COFFEESCRIPT_NODEJS_PATH ] 1136 | 1137 | if closureMode: 1138 | # Add closure annotations 1139 | commands.extend( ["--bare", "--noutil", "--closure"] ) 1140 | 1141 | commands.extend([source, destination]) 1142 | 1143 | print("Compiling %s -> %s" % (source, destination)) 1144 | return 0 == subprocess.call(commands) 1145 | 1146 | else: 1147 | # use the slow java version 1148 | commands = [ JAVA_PATH, "-jar", JCOFFEESCRIPT_PATH, 1149 | "--coffeescriptjs", COFFEESCRIPT_PATH ] 1150 | 1151 | if closureMode: 1152 | # Add closure annotations 1153 | commands.extend( ["--bare", "--noutil", "--closure"] ) 1154 | 1155 | commands.extend([source, destination]) 1156 | print("Compiling %s -> %s" % (source, destination)) 1157 | 1158 | output = open(destination, "wb") 1159 | process = \ 1160 | subprocess.Popen(commands, stdout=output, stdin=subprocess.PIPE) 1161 | 1162 | process.stdin.write( open( source, "rb" ).read() ) 1163 | process.stdin.close() 1164 | process.wait() 1165 | 1166 | # The compiler silently fails if anything is wrong, leaving a zero-length 1167 | # file. 1168 | output.close() 1169 | 1170 | if os.path.getsize(destination) == 0: 1171 | os.unlink(destination) 1172 | return False 1173 | else: 1174 | return True 1175 | 1176 | 1177 | def DownloadExterns(): 1178 | """Downloads Closure compiler externs files, if necessary.""" 1179 | for (extern,url) in EXTERNS.items(): 1180 | path = os.path.join( GetStorageFolder(), extern ) 1181 | if not os.path.exists( path ): 1182 | print("Fetching %s" % url) 1183 | open(path,"wb").write(urllib2.urlopen(url).read()) 1184 | 1185 | def RunCompiler(type, files, output, compilerOptions, prepend, exports, 1186 | useEnclosure, options, useExterns): 1187 | """Downloads and runs the compiler of the given type. 1188 | 1189 | type is a key to the compiler information in the global map COMPILERS 1190 | 1191 | files is the list of files to run the compiler on 1192 | 1193 | compilerOptions is the list of options to the compiler, specified before 1194 | the input files 1195 | 1196 | prepend is the list of files to prepend to the output, without 1197 | processing them by the compiler 1198 | 1199 | exports is extra code added to the end as input to the compiler and is 1200 | intended to export names to the closure compiler. 1201 | 1202 | if useEnclosure is True, then the entire thing except for prepended file 1203 | is surrounded with (function(){...}()); 1204 | """ 1205 | compiler = COMPILERS[type] 1206 | compilerFileName = os.path.join( GetStorageFolder(), 1207 | os.path.basename(compiler["filename"] ) ) 1208 | 1209 | needsStdin = \ 1210 | "requiresStdin" in compiler and \ 1211 | compiler["requiresStdin"] == True 1212 | 1213 | DownloadProgram( compiler["download"], compiler["filename"], 1214 | compilerFileName ) 1215 | 1216 | print("Running %s compiler." % type) 1217 | 1218 | cmdLine = [ JAVA_PATH, "-jar", compilerFileName ] 1219 | cmdLine.extend( compilerOptions ) 1220 | if "requiredOptions" in compiler: 1221 | cmdLine.extend( compiler["requiredOptions"] ) 1222 | 1223 | if type == "closure" and useExterns: 1224 | DownloadExterns() 1225 | for extern in EXTERNS.keys(): 1226 | cmdLine.extend( ["--externs", os.path.join( GetStorageFolder(), 1227 | extern ) ] ) 1228 | 1229 | if not needsStdin: 1230 | for f in files: 1231 | if compiler["inputOption"] != "": 1232 | cmdLine.append( compiler["inputOption"] ) 1233 | cmdLine.append(f) 1234 | 1235 | if type == 'closure': 1236 | exportFile = tempfile.NamedTemporaryFile(suffix=".js", delete=False) 1237 | TemporaryFiles.append( exportFile ) 1238 | exportFileName = exportFile.name 1239 | exportFile.write(exports.encode()) 1240 | exportFile.flush() 1241 | cmdLine.extend([ "--js", exportFileName]) 1242 | 1243 | outputFile = open(output, "w") 1244 | for f in prepend: 1245 | print("Prepending %s" % f) 1246 | outputFile.write(open(f, "r").read()) 1247 | 1248 | if useEnclosure: outputFile.write("(function(){\n\"use strict\";"); 1249 | 1250 | outputFile.flush() 1251 | 1252 | if type == "closure" and options.cloud: 1253 | if CallClosureService(cmdLine, outputFile, files): 1254 | if useEnclosure: outputFile.write("\n}).call(this);\n"); 1255 | return 1256 | 1257 | print(" ".join(cmdLine)) 1258 | 1259 | if needsStdin: 1260 | process = \ 1261 | subprocess.Popen(cmdLine, stdout=outputFile, stdin=subprocess.PIPE) 1262 | 1263 | for f in files: 1264 | print(" Reading %s" % f) 1265 | process.stdin.write( open( f, "rb" ).read() ) 1266 | process.stdin.close() 1267 | process.wait() 1268 | else: 1269 | subprocess.call(cmdLine, stdout=outputFile) 1270 | 1271 | if useEnclosure: outputFile.write("\n}).call(this);\n"); 1272 | 1273 | def CallClosureService(cmdline, outputFileHandle, filenames): 1274 | 1275 | print("Sending your code to Google Closure Service...") 1276 | 1277 | code = [] 1278 | # convert the closure compiler command line to their web api 1279 | i = 0 1280 | params = [] 1281 | while i < len(cmdline): 1282 | arg = cmdline[i] 1283 | if arg == '--js': 1284 | params.append(("js_code", open(cmdline[i+1], "r").read())) 1285 | i += 1 1286 | elif arg == "--externs": 1287 | params.append(("js_externs", open(cmdline[i+1], "r").read())) 1288 | elif arg.startswith("--"): 1289 | params.append((arg[2:], cmdline[i+1])) 1290 | i += 1 1291 | 1292 | i += 1 1293 | 1294 | params.append(("output_format", "json")) 1295 | params.append(("output_info", "compiled_code")) 1296 | params.append(("output_info", "errors")) 1297 | params.append(("output_info", "warnings")) 1298 | params.append(("output_info", "statistics")) 1299 | params = urllib.urlencode(params) 1300 | 1301 | # Always use the following value for the Content-type header. 1302 | headers = { "Content-type": "application/x-www-form-urlencoded" } 1303 | headers["Content-encoding"] = "gzip" 1304 | 1305 | compressedStream = io.BytesIO() 1306 | compressor = gzip.GzipFile(mode="wb", fileobj=compressedStream) 1307 | compressor.write(params.encode()) 1308 | compressor.close() 1309 | 1310 | try: 1311 | conn = httplib.HTTPConnection('closure-compiler.appspot.com') 1312 | conn.request('POST', '/compile', compressedStream.getvalue(), headers) 1313 | response = conn.getresponse() 1314 | data = response.read() 1315 | conn.close() 1316 | js = json.loads(data.decode()) 1317 | 1318 | if "compiledCode" not in js: 1319 | raise Exception("Invalid response") 1320 | except: 1321 | print("Unexpected error:", sys.exc_info()[0]) 1322 | print("Request to closure service failed. Falling back to local compilation.") 1323 | return False 1324 | 1325 | if "warnings" in js: 1326 | for warning in js["warnings"]: 1327 | filename = warning["file"] 1328 | if filename.startswith("Input_"): 1329 | index = int(filename[6:]) 1330 | filename = filenames[index] 1331 | print("WARNING: {0}:{1}: {2}".format(filename, warning["lineno"], 1332 | warning["warning"])) 1333 | 1334 | if "errors" in js: 1335 | for error in js["errors"]: 1336 | filename = error["file"] 1337 | if filename.startswith("Input_"): 1338 | index = int(filename[6:]) 1339 | filename = filenames[index] 1340 | print("ERROR: {0}:{1}: {2}".format(filename, error["lineno"], 1341 | error["error"])) 1342 | 1343 | if "compiledCode" in js: 1344 | outputFileHandle.write(js["compiledCode"]) 1345 | 1346 | 1347 | return True 1348 | 1349 | def JoinFiles( prepended, sources, outputFile, useEnclosure, exports ): 1350 | """Concatenates the contents of the given files and writes the output to 1351 | the outputFile. 1352 | """ 1353 | sys.stderr.write("Joining " + " ".join(sources) + "\n" ) 1354 | output = open(outputFile, "w") 1355 | for inputName in prepended: 1356 | output.write(open(inputName, "r").read()) 1357 | if useEnclosure: output.write("(function(){\n \"use strict\";\n") 1358 | for inputName in sources: 1359 | output.write(open(inputName, "r").read()) 1360 | if useEnclosure: 1361 | output.write(exports) 1362 | output.write("\n}).call(this);") 1363 | 1364 | def GetKey( projects, name, key, makeArray=False ): 1365 | """Returns the key of the project, following any bases""" 1366 | 1367 | # Keep track of bases already encountered. 1368 | bases = { name: 1 } 1369 | project = projects[name] 1370 | 1371 | while 1: 1372 | if key in project: 1373 | if makeArray and isinstance(project[key], str): 1374 | return [ project[key] ] 1375 | else: 1376 | return project[key] 1377 | 1378 | if "base" in project: 1379 | base = project["base"] 1380 | if base in bases: 1381 | raise "Circular dependency encountered. %s depends on %s" % ( 1382 | name, base ) 1383 | if base not in projects: 1384 | raise "Cannot find project %s, referred to by project %s" % ( 1385 | base, name ) 1386 | 1387 | name = base 1388 | 1389 | bases[name] = 1 1390 | project = projects[name] 1391 | elif makeArray: 1392 | return [] 1393 | else: 1394 | return None 1395 | 1396 | def InstallRhino(outputPath): 1397 | return DownloadProgram( 1398 | "https://ftp.mozilla.org/pub/js/rhino1_7R2.zip", 1399 | "rhino1_7R2/js.jar", outputPath) 1400 | 1401 | def CheckEnvironment(projects, names): 1402 | """Determine if the program will run, by checking the system for all 1403 | required files. 1404 | """ 1405 | okay = True 1406 | needJava = True # Need java for coffeescript 1407 | haveJava = False 1408 | haveRhino = False 1409 | needRhino = not IsWindows 1410 | needJava = needJava or (not IsWindows) 1411 | 1412 | # Check if any projects use the closure compiler. If so, we need java 1413 | for name in names: 1414 | compiler = GetKey( projects, name, "compiler" ) 1415 | if compiler == None: compiler = "cat" 1416 | if compiler == "closure": needJava = True 1417 | 1418 | if IsWindows: 1419 | global JAVA_PATH 1420 | # We need java to run. Search the path for it. 1421 | path = os.environ["PATH"].split(";") 1422 | if needJava: 1423 | for folder in path: 1424 | java = os.path.join(folder, "java.exe") 1425 | if os.path.isfile( java ): 1426 | haveJava = True 1427 | JAVA_PATH=java 1428 | break 1429 | # Handle Windows System File Redirection when 1430 | # running 32-bit python on 64-bit Windows 1431 | if java.find("system32") != -1: 1432 | java = java.replace("system32", "SysWOW64") 1433 | java = java.replace("System32", "SysWOW64") 1434 | if os.path.isfile( java ): 1435 | haveJava = True 1436 | JAVA_PATH=java 1437 | break 1438 | 1439 | if not haveJava: 1440 | print("Cannot find Java. Please install it from www.java.com.") 1441 | os.system("start http://www.java.com") 1442 | okay = False 1443 | elif needJava: 1444 | path = os.environ["PATH"].split(":") 1445 | for folder in path: 1446 | java = os.path.join(folder, "java") 1447 | if os.path.isfile( java ): 1448 | break 1449 | else: 1450 | print("Java is not installed on this system. Please install " + \ 1451 | "the default-jre or openjdk-7-jre or sun-java7-bin package or equivalent.") 1452 | okay = False 1453 | 1454 | # check if we have node.js available to run the coffeescript much faster 1455 | global PATH_TO_NODEJS 1456 | if not IsWindows: 1457 | path = os.environ["PATH"].split(":") 1458 | for folder in path: 1459 | node = os.path.join(folder, "node") 1460 | if os.path.isfile( node ): 1461 | PATH_TO_NODEJS = node 1462 | break 1463 | 1464 | # We need rhino. 1465 | haveRhino = False 1466 | global RHINO_CMD 1467 | for folder in os.environ["PATH"].split(":"): 1468 | rhino = os.path.join(folder, "rhino") 1469 | if os.path.isfile( rhino ): 1470 | haveRhino = True 1471 | RHINO_CMD = [rhino] 1472 | break 1473 | 1474 | if not haveRhino: 1475 | rhino = os.path.join(GetStorageFolder(), "rhino.jar") 1476 | 1477 | if not haveRhino: 1478 | InstallRhino(rhino) 1479 | RHINO_CMD = [JAVA_PATH, "-jar", rhino] 1480 | 1481 | return okay 1482 | 1483 | def CreateProjects(options): 1484 | """No Makefile.jz exists. Automatically create one based on the files in the 1485 | current working folder and the given options.""" 1486 | 1487 | input = options.input 1488 | if len(input) == 0: 1489 | input = ["*.js"] 1490 | 1491 | files = [] 1492 | for infile in input: 1493 | list = glob.glob(infile) 1494 | if len(list) == 0: 1495 | print("Error: Could not find '%s'" % infile) 1496 | for file in list: 1497 | if file in NEVER_CHECK_THESE_FILES: 1498 | print("Ignoring library file '%s'" % file) 1499 | elif options.output != file: 1500 | files.append( file ) 1501 | 1502 | projects = { 1503 | "release": { 1504 | "input": files, 1505 | "include": options.include 1506 | } 1507 | } 1508 | 1509 | if options.output: 1510 | projects["release"]["output"] = options.output 1511 | projects["release"]["compiler"] = options.compiler 1512 | 1513 | if options.compiler != "cat": 1514 | if options.release and \ 1515 | "releaseOptions" in COMPILERS[options.compiler]: 1516 | 1517 | projects["release"]["compilerOptions"] = \ 1518 | COMPILERS[options.compiler]["releaseOptions"] 1519 | 1520 | else: 1521 | projects["release"]["compilerOptions"] = \ 1522 | COMPILERS[options.compiler]["defaultOptions"] 1523 | 1524 | 1525 | return projects 1526 | 1527 | class Options: 1528 | """ Parse arguments to the script file """ 1529 | 1530 | def __init__(self): 1531 | self.names = [] 1532 | self.input = [] 1533 | self.include = [] 1534 | self.clean = False 1535 | self.help = False 1536 | self.output = None 1537 | self.prepend = []; 1538 | self.makefile = MAKEFILE_NAME 1539 | self.compiler = 'cat' 1540 | self.release = False 1541 | self.watch = False 1542 | self.cloud = False 1543 | 1544 | i = 1 1545 | args = sys.argv; 1546 | while i < len(args): 1547 | if args[i] == 'clean': 1548 | self.clean = True 1549 | elif args[i] == '-?' or args[i] == '--help' or args[i] == "/?": 1550 | self.help = True 1551 | elif args[i] == '--out': 1552 | if i == len(args)-1: 1553 | print("Error: --out requires an argument.") 1554 | sys.exit(-1) 1555 | else: 1556 | self.output = args[i + 1]; 1557 | i += 1 1558 | 1559 | elif args[i] == '-f': 1560 | if i == len(args)-1: 1561 | print("Error: --f requires an argument.") 1562 | sys.exit(-1) 1563 | else: 1564 | self.makefile = args[i + 1]; 1565 | i += 1 1566 | 1567 | elif args[i] == '--prepend': 1568 | if i == len(args)-1: 1569 | print("Error: --prepend requires an argument.") 1570 | sys.exit(-1) 1571 | else: 1572 | self.prepend.append( args[i + 1] ); 1573 | i += 1 1574 | 1575 | elif args[i] == '--compiler': 1576 | if i == len(args)-1: 1577 | print("Error: --compiler requires an argument.") 1578 | sys.exit(-1) 1579 | elif args[i+1] not in VALID_COMPILERS: 1580 | print("Error: --compiler must be one of %s" % ( 1581 | ",".join(VALID_COMPILERS) )) 1582 | sys.exit(-1) 1583 | else: 1584 | self.compiler = args[ i + 1] 1585 | i += 1 1586 | 1587 | elif args[i] == '--release': 1588 | self.release = True 1589 | 1590 | elif args[i] == '--cloud': 1591 | self.cloud = True 1592 | 1593 | elif args[i] == '--watch': 1594 | self.watch = True 1595 | 1596 | elif args[i].startswith('-I'): 1597 | # Set the include path 1598 | self.include.append( args[i][2:] ) 1599 | 1600 | elif args[i].startswith('--'): 1601 | # Allow the user to specify a compiler without writing 1602 | # "--compiler" first. 1603 | for compiler in VALID_COMPILERS: 1604 | if "--" + compiler == args[i]: 1605 | self.compiler = args[i][2:] 1606 | break 1607 | else: 1608 | print("Error: Unknown option %s" % (args[i])) 1609 | sys.exit(-1) 1610 | 1611 | else: 1612 | self.names.append( args[i] ) 1613 | 1614 | i += 1 1615 | 1616 | if self.output != None or not os.path.exists( MAKEFILE_NAME ): 1617 | # No makefile mode. All the project names were actually filenames. 1618 | self.input = self.names 1619 | self.names = [] 1620 | 1621 | 1622 | def watchFiles(fileList, timestamp): 1623 | """ 1624 | Monitor the given files for changes, and return when any are removed or 1625 | have a modification time after the given timestamp. 1626 | """ 1627 | print("Watching files for changes...") 1628 | while True: 1629 | time.sleep(1.0) 1630 | for name in fileList: 1631 | if not os.path.exists(name) or os.path.getmtime(name) > timestamp: 1632 | print("Detected change in {0}".format(name)) 1633 | return 1634 | 1635 | def compileProjects(options, lastCheckTime): 1636 | """ 1637 | Compile all projects, using the given options. 1638 | Returns the complete list of input files, suitable for watching 1639 | changes. Also returns whether any files were missing 1640 | 1641 | Requires the time that the input files were last checked for changes (0 1642 | for never) 1643 | """ 1644 | watchedFiles = [] 1645 | 1646 | # Parse the json 1647 | if not os.path.exists( options.makefile ) or options.output != None: 1648 | if not os.path.exists( options.makefile ): 1649 | print("Could not find %s. Running jslint on input files." % 1650 | options.makefile) 1651 | projects = CreateProjects(options) 1652 | else: 1653 | projects = ParseLazyJson(open(options.makefile, "r").read()) 1654 | 1655 | if len(options.names) == 0: 1656 | if len(projects) == 1: 1657 | options.names = projects.keys() 1658 | else: 1659 | print("Please specify a project to load. Valid projects are:") 1660 | print(" ".join(projects.keys())) 1661 | 1662 | for name in options.names: 1663 | if name not in projects: 1664 | print("Error: Cannot find project '%s'" % ( 1665 | name )) 1666 | sys.exit(-1) 1667 | 1668 | if not CheckEnvironment(projects, options.names): 1669 | sys.exit(-1) 1670 | 1671 | wereFilesMissing = False 1672 | 1673 | # Look for Makefile.json in current folder. For each process, 1674 | for name in options.names: 1675 | if name in projects: 1676 | project = name 1677 | 1678 | if options.clean: 1679 | print("Cleaning %s..." % ( name )) 1680 | else: 1681 | print("Building %s..." % ( name )) 1682 | 1683 | output = GetKey( projects, name, "output" ) 1684 | if output == None: 1685 | print("Warning: project %s missing output file. We will only run jslint." % ( 1686 | name )) 1687 | 1688 | compiler = GetKey( projects, name, "compiler" ) 1689 | if compiler not in VALID_COMPILERS: 1690 | if output != None: 1691 | print("Warning: Project missing 'compiler' option. Using 'cat'") 1692 | compiler = 'cat' 1693 | 1694 | input = GetKey( projects, name, "input", True ) 1695 | if input == None: 1696 | print("Warning: project %s missing input file. skipping." % ( 1697 | name )) 1698 | continue 1699 | 1700 | compilerOptions = GetKey( projects, name, "compilerOptions" ) 1701 | if compilerOptions == None: 1702 | compilerOptions = [] 1703 | 1704 | include = GetKey( projects, name, "include", True ) 1705 | include.append("") 1706 | 1707 | prepend = GetKey( projects, name, "prepend", True ) 1708 | 1709 | # Check for dangerous mistake. Is the output file part of the input? 1710 | if output in input: 1711 | print("Error: Output file %s same as input! Skipping project." % ( 1712 | output )) 1713 | continue 1714 | 1715 | # Normalize the slashes in the path names. 1716 | input = ReplaceSlashes(input) 1717 | include = ReplaceSlashes(include) 1718 | 1719 | # Process included files to obtain a complete list of files. 1720 | analysis = Analysis(input, include) 1721 | 1722 | # if we are asked to clean, then simply delete the output file 1723 | if options.clean: 1724 | filesToDelete = [] 1725 | if output != None: 1726 | filesToDelete.append( output ) 1727 | 1728 | # also delete the .js files generated from coffeescript 1729 | for coffeeFile in analysis.getInputFilesEndingWith(".coffee"): 1730 | filesToDelete.append( coffeeFile + ".js" ) 1731 | 1732 | for textFile in analysis.getInputFilesEndingWith(".txt"): 1733 | filesToDelete.append( textFile + ".js" ) 1734 | 1735 | for filename in filesToDelete: 1736 | try: 1737 | os.unlink( filename ) 1738 | print("Deleted %s" % filename) 1739 | except: 1740 | pass 1741 | 1742 | continue 1743 | 1744 | # Also process prepended files 1745 | prependedFiles = Analysis( prepend, include ).getFileList() 1746 | 1747 | exports = analysis.getExports() 1748 | 1749 | # Get the file time of the output file, if it exists. 1750 | targetTime = lastCheckTime 1751 | try: 1752 | if lastCheckTime == 0: 1753 | targetTime = os.path.getmtime(output) 1754 | else: 1755 | targetTime = min(lastCheckTime, os.path.getmtime(output)) 1756 | except: 1757 | pass 1758 | 1759 | ConvertTextFiles(analysis, targetTime, options) 1760 | RunJsLint( analysis.getFileList(), targetTime, options ) 1761 | CompileCoffeeScript( analysis, options, compiler, output != None, 1762 | lastCheckTime) 1763 | 1764 | if len(analysis.errors): 1765 | for error in analysis.errors: 1766 | print(error) 1767 | 1768 | elif output != None: 1769 | if compiler != "cat": 1770 | useExterns = GetKey(projects, name, "noexterns", False) != "true" 1771 | RunCompiler( compiler, analysis.getFileList(), output, 1772 | compilerOptions, prepend, exports, True, options, 1773 | useExterns) 1774 | else: 1775 | print("Creating %s" % output) 1776 | JoinFiles( prepend, analysis.getFileList(), output, True, 1777 | exports) 1778 | 1779 | wereFilesMissing = wereFilesMissing or analysis.isMissingFiles() 1780 | watchedFiles.extend(analysis.getInputFiles()) 1781 | 1782 | return watchedFiles, wereFilesMissing 1783 | 1784 | def main(): 1785 | options = Options() 1786 | 1787 | if options.help: 1788 | print(MAN_PAGE) 1789 | sys.exit(0) 1790 | 1791 | compiledAt = time.time() 1792 | watchList, wereFilesMissing = compileProjects(options, 0) 1793 | 1794 | # Loop while watching changes. Carefully handle the case where an input 1795 | # file is changed while we are compiling, in which case the input file will 1796 | # be older than the output file even though it has changed. 1797 | while options.watch: 1798 | watchFiles(watchList, compiledAt) 1799 | nextCompiledAt = time.time() 1800 | newWatchList, wereFilesMissing = compileProjects(options, compiledAt) 1801 | compiledAt = nextCompiledAt 1802 | if not wereFilesMissing: 1803 | # if any files in the include list could not be found, then don't 1804 | # update the watch list because then it wouldn't be complete. 1805 | watchList = newWatchList 1806 | else: 1807 | print("Some files were missing. Not updating watch list.") 1808 | 1809 | # Here is jslint in case they don't have it. 1810 | JSLINT_RHINO = """ 1811 | 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 2428 | uhuX2co9uO9D7/wFiFQhh 2429 | """ 2430 | 2431 | COFFEESCRIPT_UTILITIES = """ 2432 | var __hasProp = Object.prototype.hasOwnProperty; 2433 | var __extends = function (child, parent) { 2434 | for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } 2435 | /** @constructor */ 2436 | function ctor() { this.constructor = child; } 2437 | ctor.prototype = parent.prototype; 2438 | child.prototype = new ctor; 2439 | child.__super__ = parent.prototype; 2440 | return child; 2441 | }; 2442 | 2443 | var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; } 2444 | 2445 | var __indexOf = Array.prototype.indexOf || function(item) { 2446 | for (var i = 0, l = this.length; i < l; i++) { 2447 | if (this[i] === item) return i; 2448 | } 2449 | return -1; 2450 | }; 2451 | 2452 | var __slice = Array.prototype.slice; 2453 | """ 2454 | 2455 | if __name__ == '__main__': 2456 | main(); 2457 | 2458 | --------------------------------------------------------------------------------