Browse Source

amberc.js: async collecting and resolving of files

resolve_js(): now takes a callback which gets called upon success
collect_files(): async search for .st and .js files
resolve_libraries(): split into 3 sub-functions
always_resolve(): takes a callback and calls it immediately
Manfred Kroehnert 12 years ago
parent
commit
e7f60df0f0
1 changed files with 158 additions and 38 deletions
  1. 158 38
      bin/amberc.js

+ 158 - 38
bin/amberc.js

@@ -59,12 +59,12 @@ var defaults = function() {
 	return {
 		'amber_dir': amber_dir,
 		'smalltalk': {}, // the evaluated compiler will be stored in this variable (see create_compiler)
+		'base': kernel_libraries,
 		'compiler_libraries': kernel_libraries.concat(compiler_libs),
+		'load': [],
 		'init': path.join(amber_dir, 'js', 'init.js'),
 		'main': undefined,
 		'mainfile': undefined,
-		'base': kernel_libraries,
-		'load': [],
 		'closure': false,
 		'closure_parts': false,
 		'closure_full': false,
@@ -149,7 +149,9 @@ function handle_options(optionsArray) {
 }
 
 
-// print options and exit
+/**
+ * print usage options and exit
+ */
 function usage() {
 	console.log('Usage: $0 [-l lib1,lib2...] [-i init_file] [-m main_class] [-M main_file]');
 	console.log('          [-o] [-O|-A] [-d] [-s suffix] [-S suffix] [file1 [file2 ...]] [Program]');
@@ -229,6 +231,13 @@ function usage() {
 }
 
 
+/**
+ * Checks if the java executable exists and afterwards,
+ * if compiler.jar exists at the path stored in defaults.closure_jar.
+ * All closure related entries are set to false upon failure.
+ *
+ * callback gets called in any case.
+ */
 function check_for_closure_compiler(callback) {
 	if (defaults.closure) {
 		exec('which java', function(error, stdout, stderr) {
@@ -258,17 +267,40 @@ function check_for_closure_compiler(callback) {
 }
 
 
-function resolve_js(filename) {
+/**
+ * Check if the file given as parameter exists in the local directory or in $AMBER/js/.
+ * '.js' is appended first.
+ *
+ * @param filename name of a file without '.js' prefix
+ * @param callback gets called on success with path to .js file as parameter
+ */
+function resolve_js(filename, callback) {
 	var jsFile = filename + defaults.loadsuffix + '.js';
 	var amberJsFile = path.join(defaults.amber_dir, 'js', jsFile);
 	console.log('Resolving: ' + jsFile);
-	if (path.existsSync(jsFile)) {
-		return jsFile;
-	} else if (path.existsSync(amberJsFile)) {
-		return amberJsFile;
-	} else {
-		throw(new Error('JavaScript file not found: ' + jsFile));
-	}
+	path.exists(jsFile, function(exists) {
+		if (exists) {
+			callback(jsFile);
+		} else {
+			path.exists(amberJsFile, function(exists) {
+				if (exists) {
+					callback(amberJsFile);
+				} else {
+					throw(new Error('JavaScript file not found: ' + jsFile));
+				}
+			});
+		}
+	});
+}
+
+
+/**
+ * Always evaluates the callback parameter.
+ * Used by Combo blocks to always call the next function,
+ * even if all of the other functions did not run.
+ */
+function always_resolve(callback) {
+	callback();
 }
 
 
@@ -277,56 +309,144 @@ function resolve_js(filename) {
 // both locally and in $AMBER/js and $AMBER/st 
 // --------------------------------------------------
 function collect_files(filesArray) {
+	var stFiles = [];
+	var jsFiles = [];
+	var programName = [];
 	filesArray.forEach(function(currentFile) {
 		var fileSuffix = path.extname(currentFile);
-		var category = path.basename(currentFile, '.st');
-		var amberFile = path.join(defaults.amber_dir, 'st', currentFile);
 		switch (fileSuffix) {
 			case '.st':
-				if (path.existsSync(currentFile)) {
-					defaults.compile.push(currentFile);
-					defaults.compiled_categories.push(category);
-					defaults.compiled.push(category + defaults.suffix_used + '.js');
-				} else if (path.existsSync(amberFile)) {
-					defaults.compile.push(amberFile);
-					defaults.compiled_categories.push(category);
-					defaults.compiled.push(category + defaults.suffix_used + '.js');
-				} else {
-					throw(new Error('File not found: ' + currentFile));
-				}
+				stFiles.push(currentFile);
 				break;
 			case '.js':
-				defaults.libraries.push(resolve_js(currentFile));
+				jsFiles.push(currentFile);
 				break;
 			default:
 				// Will end up being the last non js/st argument
-				defaults.program = currentFile
+				programName.push(currentFile);
 				break;
 		};
 	});
-	resolve_libraries();
+
+	if(1 < programName.length) {
+		throw new Error('More than one name for ProgramName given: ' + programName);
+	} else {
+		defaults.program = programName[0];
+	}
+
+	// collecting files starts here!!
+	var collected_files = new Combo(function() {
+		resolve_libraries();
+	});
+	collect_st_files(stFiles, collected_files.add());
+	collect_js_files(jsFiles, collected_files.add());
+}
+
+
+function collect_st_files(stFiles, callback) {
+	var collected_st_files = new Combo(function() {
+		Array.prototype.slice.call(arguments).forEach(function(data) {
+			if (undefined !== data[0]) {
+				var stFile = data[0];
+				var stCategory = data[1];
+				defaults.compile.push(stFile);
+				defaults.compiled_categories.push(stCategory);
+				defaults.compiled.push(stCategory + defaults.suffix_used + '.js');
+			}
+		});
+		callback();
+	});
+
+	stFiles.forEach(function(stFile) {
+		var _callback = collected_st_files.add();
+		console.log('Checking: ' + stFile);
+		var category = path.basename(stFile, '.st');
+		var amberStFile = path.join(defaults.amber_dir, 'st', stFile);
+		path.exists(stFile, function(exists) {
+			if (exists) {
+				_callback(stFile, category);
+			} else {
+				path.exists(amberJsFile, function(exists) {
+					if (exists) {
+						_callback(amberStFile, category);
+					} else {
+						throw(new Error('JavaScript file not found: ' + jsFile));
+					}
+				});
+			}
+		});
+	});
+
+	always_resolve(collected_st_files.add());
+}
+
+
+function collect_js_files(jsFiles, callback) {
+	var collected_js_files = new Combo(function() {
+		Array.prototype.slice.call(arguments).forEach(function(file) {
+			if (undefined !== file[0]) {
+				defaults.libraries.push(file[0]);
+			}
+		});
+		callback();
+	});
+
+	jsFiles.forEach(function(jsFile) {
+		resolve_js(currentFile, collected_js_files.add());
+	});
+
+	always_resolve(collected_js_files.add());
 }
 
 
 function resolve_libraries() {
 	// Resolve libraries listed in defaults.base
-	defaults.base.forEach(function(file) {
-		defaults.libraries.push(resolve_js(file));
+	var all_resolved = new Combo(function(resolved_library_files, resolved_compiler_files) {
+		resolve_init(resolved_compiler_files[0]);
+	});
+	resolve_kernel(all_resolved.add());
+	resolve_compiler(all_resolved.add());
+}
+
+
+function resolve_kernel(callback) {
+	var kernel_files = defaults.base.concat(defaults.load);
+	var kernel_resolved = new Combo(function() {
+		Array.prototype.slice.call(arguments).forEach(function(file) {
+			if (undefined !== file[0]) {
+				defaults.libraries.push(file[0]);
+			}
+		});
+		callback(null);
 	});
 
-	// Resolve libraries listed in defaults.compiler
-	var compilerFiles = [];
-	defaults.compiler_libraries.forEach(function(file) {
-		compilerFiles.push(resolve_js(file));
+	kernel_files.forEach(function(file) {
+		resolve_js(file, kernel_resolved.add());
 	});
 
-	// Resolve libraries listed in defaults.load
-	defaults.load.forEach(function(file) {
-		var resolvedFile = resolve_js(file);
-		compilerFiles.push(resolvedFile);
-		defaults.libraries.push(resolvedFile);
+	always_resolve(kernel_resolved.add());
+}
+
+function resolve_compiler(callback) {
+	// Resolve compiler libraries
+	var compiler_files = defaults.compiler_libraries.concat(defaults.load);
+	var compiler_resolved = new Combo(function() {
+		var compilerFiles = [];
+		Array.prototype.slice.call(arguments).forEach(function(file) {
+			if (undefined !== file[0]) {
+				compilerFiles.push(file[0]);
+			}
+		});
+		callback(compilerFiles);
 	});
+	compiler_files.forEach(function(file) {
+		resolve_js(file, compiler_resolved.add());
+	});
+
+	always_resolve(compiler_resolved.add());
+}
 
+function resolve_init(compilerFiles) {
 	// check and add init.js
 	var initFile = defaults.init;
 	if ('.js' !== path.extname(initFile)) {