Skip to content
This repository
Browse code

new jetpack xpi

  • Loading branch information...
commit 95baedd332e98499bc6797bbae0f3e13e00d5475 1 parent 745db9b
Christoph Dorn cadorn authored
BIN  demos/JetpackExtension/extension/extension.xpi
Binary file not shown
1,632 demos/JetpackExtension/extension/lib/pinf-loader.js
@@ -2142,66 +2142,68 @@ Assembler.prototype.assembleProgram = function(sandbox, uri, programCallback, ca
2142 2142 // if (uri.charAt(0) == "/")
2143 2143 path = uri;
2144 2144
2145   - var programDescriptor = new DESCRIPTORS.Program(path, {
  2145 + new DESCRIPTORS.Program(path, {
2146 2146 extendsProgramDescriptorPath: options.extendsProgramDescriptorPath || false
2147   - });
2148   - var program = new PROGRAM.Program(programDescriptor);
2149   -
2150   - if (typeof programCallback != "undefined")
2151   - {
2152   - if (programCallback(program) === false)
2153   - return;
2154   - }
2155   -
2156   - sandbox.setProgram(program);
2157   - sandbox.sourceDescriptors = options.sourceDescriptors || void 0;
2158   -
2159   - program.assembler = self;
2160   -
2161   - // This will download all packages and make them available on disk
2162   - program.discoverPackages(function assembler_assembleProgram_lambda_discoverPackages_packageForLocator(locator, callback)
  2147 + }, function(programDescriptor)
2163 2148 {
2164   - program.resolveLocator(self, locator, function(resolvedLocator)
  2149 + var program = new PROGRAM.Program(programDescriptor);
  2150 +
  2151 + if (typeof programCallback != "undefined")
2165 2152 {
2166   - if (resolvedLocator.available === false)
2167   - {
2168   - callback(null);
2169   - }
2170   - else
2171   - if (typeof resolvedLocator.available != "undefined" && resolvedLocator.available === false)
2172   - {
2173   - callback(null);
2174   - }
2175   - else
2176   - if (typeof resolvedLocator.id != "undefined")
2177   - {
2178   - callback(sandbox.ensurePackageForLocator(resolvedLocator, options), resolvedLocator);
2179   - }
2180   - else
2181   - if (typeof resolvedLocator.location == "undefined")
2182   - {
2183   - throw new Error("No location property found in locator: " + UTIL.locatorToString(resolvedLocator));
2184   - }
2185   - else
2186   - if (!FILE.exists(resolvedLocator.location))
2187   - {
2188   - throw new Error("Directory for location property not found in locator: " + UTIL.locatorToString(resolvedLocator));
2189   - }
2190   -// else
2191   - // We do not need to follow locators (in order to discover requires()) that map to providers.
2192   -// if (typeof locator.provider != "undefined")
2193   -// callback(null);
2194   - else
  2153 + if (programCallback(program) === false)
  2154 + return;
  2155 + }
  2156 +
  2157 + sandbox.setProgram(program);
  2158 + sandbox.sourceDescriptors = options.sourceDescriptors || void 0;
  2159 +
  2160 + program.assembler = self;
  2161 +
  2162 + // This will download all packages and make them available on disk
  2163 + program.discoverPackages(function assembler_assembleProgram_lambda_discoverPackages_packageForLocator(locator, callback)
  2164 + {
  2165 + program.resolveLocator(self, locator, function(resolvedLocator)
2195 2166 {
2196   - callback(sandbox.ensurePackageForLocator(resolvedLocator, options), resolvedLocator);
2197   - }
2198   - }, options);
2199   - }, function assembler_assembleProgram_lambda_discoverPackages_done()
2200   - {
2201   - DEBUG.indent(di);
2202   - self.finalizeProgram(sandbox, program);
2203   - callback(program);
2204   - }, options);
  2167 + if (resolvedLocator.available === false)
  2168 + {
  2169 + callback(null);
  2170 + }
  2171 + else
  2172 + if (typeof resolvedLocator.available != "undefined" && resolvedLocator.available === false)
  2173 + {
  2174 + callback(null);
  2175 + }
  2176 + else
  2177 + if (typeof resolvedLocator.id != "undefined")
  2178 + {
  2179 + callback(sandbox.ensurePackageForLocator(resolvedLocator, options), resolvedLocator);
  2180 + }
  2181 + else
  2182 + if (!resolvedLocator.location)
  2183 + {
  2184 + throw new Error("No location property found in locator: " + UTIL.locatorToString(resolvedLocator));
  2185 + }
  2186 + else
  2187 + if (!FILE.exists(resolvedLocator.location))
  2188 + {
  2189 + throw new Error("Directory for location property not found in locator: " + UTIL.locatorToString(resolvedLocator));
  2190 + }
  2191 + // else
  2192 + // We do not need to follow locators (in order to discover requires()) that map to providers.
  2193 + // if (typeof locator.provider != "undefined")
  2194 + // callback(null);
  2195 + else
  2196 + {
  2197 + callback(sandbox.ensurePackageForLocator(resolvedLocator, options), resolvedLocator);
  2198 + }
  2199 + }, options);
  2200 + }, function assembler_assembleProgram_lambda_discoverPackages_done()
  2201 + {
  2202 + DEBUG.indent(di);
  2203 + self.finalizeProgram(sandbox, program);
  2204 + callback(program);
  2205 + }, options);
  2206 + });
2205 2207 }
2206 2208
2207 2209 if (ENV.mustClean && !this.cleaned[this.downloader.basePath + "/downloads"])
@@ -5001,6 +5003,63 @@ return function calcMD5(str)
5001 5003 })();
5002 5004
5003 5005 });
  5006 +__loader__.memoize('console', function(__require__, module, exports) {
  5007 +// ######################################################################
  5008 +// # /console.js
  5009 +// ######################################################################
  5010 +
  5011 +var API = __require__('api');
  5012 +
  5013 +var consoleAPI = {
  5014 + instance: console || void 0
  5015 +};
  5016 +var errorLogPath = false;
  5017 +
  5018 +[
  5019 + "log",
  5020 + "info",
  5021 + "warn",
  5022 + "error",
  5023 + "to"
  5024 +].forEach(function(priority)
  5025 +{
  5026 + consoleAPI[priority] = function()
  5027 + {
  5028 + if (errorLogPath) {
  5029 + var line = [
  5030 + "[" + new Date() + "]",
  5031 + priority.toUpperCase()
  5032 + ];
  5033 + for (var i=0,ic=arguments.length ; i<ic ; i++) {
  5034 + line.push(arguments[i]);
  5035 + }
  5036 + API.FILE.asyncAppend(errorLogPath, line.join("\t") + "\n");
  5037 + }
  5038 +
  5039 + if (typeof consoleAPI.instance != "undefined" && consoleAPI.instance[priority])
  5040 + return consoleAPI.instance[priority].apply(consoleAPI.instance, arguments);
  5041 + else
  5042 + API.DEBUG.print("[console]" + arguments);
  5043 + }
  5044 +});
  5045 +
  5046 +exports.setErrorLogPath = function(path)
  5047 +{
  5048 + errorLogPath = path;
  5049 +}
  5050 +
  5051 +exports.setConsole = function(console)
  5052 +{
  5053 + API.ENV.console = console;
  5054 + consoleAPI.instance = console;
  5055 +}
  5056 +
  5057 +exports.getAPI = function()
  5058 +{
  5059 + return consoleAPI;
  5060 +}
  5061 +
  5062 +});
5004 5063 __loader__.memoize('contexts', function(__require__, module, exports) {
5005 5064 // ######################################################################
5006 5065 // # /contexts.js
@@ -5298,7 +5357,7 @@ Descriptor.prototype.clone = function()
5298 5357 return descriptor;
5299 5358 }
5300 5359
5301   -Descriptor.prototype.load = function(path, create, options)
  5360 +Descriptor.prototype.load = function(path, create, options, callback)
5302 5361 {
5303 5362 options = options || {};
5304 5363
@@ -5344,22 +5403,29 @@ Descriptor.prototype.load = function(path, create, options)
5344 5403 }
5345 5404 }
5346 5405
5347   - try
5348   - {
  5406 + try {
5349 5407 this.json = JSON.parse(FILE.read(this.path));
5350   - canonicalizePaths(this.json, API.FILE.dirname(this.path));
5351   - }
5352   - catch(e)
5353   - {
  5408 + } catch(e) {
5354 5409 throw new Error("Error parsing JSON file '" + this.path + "': " + e);
5355 5410 }
5356 5411
  5412 + var localPath = this.path.replace(/\.json$/, ".local.json");
  5413 + if (FILE.exists(localPath)) {
  5414 + try {
  5415 + this.json = API.UTIL.deepMerge(this.json, JSON.parse(FILE.read(localPath)));
  5416 + } catch(e) {
  5417 + throw new Error("Error parsing JSON file '" + this.path + "': " + e);
  5418 + }
  5419 + }
  5420 +
  5421 + canonicalizePaths(this.json, API.FILE.dirname(this.path));
  5422 +
5357 5423 var self = this;
5358 5424
5359   - function mergeExtended(extendsLocator)
  5425 + function mergeExtended(extendsLocator, doneMergingCallback)
5360 5426 {
5361 5427 // TODO: More generic locator resolving
5362   - if (typeof extendsLocator.location == "undefined")
  5428 + if (!extendsLocator.location)
5363 5429 throw new Error("Extends locator must contain 'location' property in: " + self.path);
5364 5430
5365 5431 var path = extendsLocator.location;
@@ -5391,7 +5457,9 @@ Descriptor.prototype.load = function(path, create, options)
5391 5457
5392 5458 if (typeof self.json["extends"] != "undefined")
5393 5459 {
5394   - mergeExtended(self.json["extends"]);
  5460 + mergeExtended(self.json["extends"], doneMergingCallback);
  5461 + } else {
  5462 + doneMergingCallback();
5395 5463 }
5396 5464 }
5397 5465
@@ -5405,22 +5473,42 @@ Descriptor.prototype.load = function(path, create, options)
5405 5473 }
5406 5474 }
5407 5475
5408   - if (typeof options.extendsProgramDescriptorPath !== "undefined" && options.extendsProgramDescriptorPath)
  5476 + function mergeFinal()
  5477 + {
  5478 + if (typeof self.json["extends"] != "undefined")
  5479 + {
  5480 + mergeExtended(self.json["extends"], function()
  5481 + {
  5482 + if (typeof callback === "function")
  5483 + callback();
  5484 + });
  5485 + } else {
  5486 + if (typeof callback === "function")
  5487 + callback();
  5488 + }
  5489 + }
  5490 +
  5491 + if (typeof options.extendsDescriptorJSON === "object") {
  5492 + this.json = API.UTIL.deepMerge(this.json, options.extendsDescriptorJSON);
  5493 + }
  5494 +
  5495 + // TODO: Rename options.extendsProgramDescriptorPath to options.extendsDescriptorPath
  5496 + if (options.extendsProgramDescriptorPath)
5409 5497 {
5410 5498 var previousExtends = this.json["extends"];
5411 5499 // NOTE: options.extendsProgramDescriptorPath may NOT be a URL (must be absolute local path)
5412 5500 // If it is a URL the mergeExtended for the original "extends" may fails due to a race condition
5413 5501 mergeExtended({
5414 5502 location: options.extendsProgramDescriptorPath
  5503 + }, function()
  5504 + {
  5505 + if (typeof previousExtends !== "undefined") {
  5506 + self.json["extends"] = previousExtends;
  5507 + }
  5508 + mergeFinal();
5415 5509 });
5416   - if (typeof previousExtends !== "undefined") {
5417   - this.json["extends"] = previousExtends;
5418   - }
5419   - }
5420   -
5421   - if (typeof this.json["extends"] != "undefined")
5422   - {
5423   - mergeExtended(this.json["extends"]);
  5510 + } else {
  5511 + mergeFinal();
5424 5512 }
5425 5513 }
5426 5514
@@ -5470,7 +5558,7 @@ Descriptor.prototype._normalizeLocator = function(locator)
5470 5558 }
5471 5559 }
5472 5560
5473   - if (typeof locator.location != "undefined")
  5561 + if (locator.location)
5474 5562 {
5475 5563 if (locator.location.charAt(0) == ".")
5476 5564 locator.location = FILE.realpath(FILE.dirname(this.path) + "/" + locator.location) + "/";
@@ -5489,18 +5577,23 @@ Descriptor.prototype.toJSONObject = function()
5489 5577 // # Program Descriptor
5490 5578 // ######################################################################
5491 5579
5492   -var Program = exports.Program = function(path, options)
  5580 +var Program = exports.Program = function(path, options, callback)
5493 5581 {
5494 5582 if (typeof path == "undefined")
5495 5583 return;
5496 5584 this.cloneConstructor = exports.Program;
5497 5585 this.filename = "program.json";
5498   - this.load(path, false, options);
5499   - if (typeof this.json.uid != "undefined")
  5586 + var self = this;
  5587 + this.load(path, false, options, function()
5500 5588 {
5501   - if (!this.json.uid.match(/^https?:\/\/(.*)\/$/))
5502   - throw this.validationError("Value (" + this.json.uid + ") for property 'uid' is not a valid HTTP(s) URL");
5503   - }
  5589 + if (typeof self.json.uid != "undefined")
  5590 + {
  5591 + if (!self.json.uid.match(/^https?:\/\/(.*)\/$/))
  5592 + throw this.validationError("Value (" + self.json.uid + ") for property 'uid' is not a valid HTTP(s) URL");
  5593 + }
  5594 + if (typeof callback === "function")
  5595 + callback(self);
  5596 + });
5504 5597 }
5505 5598 Program.prototype = new Descriptor();
5506 5599
@@ -5671,18 +5764,21 @@ Program.prototype.augmentLocator = function(locator, options)
5671 5764 // # Package Descriptor
5672 5765 // ######################################################################
5673 5766
5674   -var Package = exports.Package = function(path)
  5767 +var Package = exports.Package = function(path, options)
5675 5768 {
5676 5769 if (typeof path == "undefined")
5677 5770 return;
5678 5771 this.cloneConstructor = exports.Package;
5679 5772 this.filename = "package.json";
5680   - this.load(path);
5681   - if (typeof this.json.uid != "undefined")
  5773 + var self = this;
  5774 + this.load(path, false, options, function()
5682 5775 {
5683   - if (!this.json.uid.match(/^\w*:\/\/(.*)\/$/))
5684   - throw this.validationError("Value (" + this.json.uid + ") for property 'uid' is not a valid URI!");
5685   - }
  5776 + if (typeof self.json.uid != "undefined")
  5777 + {
  5778 + if (!self.json.uid.match(/^\w*:\/\/(.*)\/$/))
  5779 + throw self.validationError("Value (" + self.json.uid + ") for property 'uid' is not a valid URI!");
  5780 + }
  5781 + });
5686 5782 }
5687 5783 Package.prototype = new Descriptor();
5688 5784
@@ -5740,13 +5836,16 @@ Package.prototype.moduleIdToLibPath = function(moduleId)
5740 5836 // # Dummy Descriptor - used for resource packages that are not CommonJS packages
5741 5837 // ######################################################################
5742 5838
5743   -var Dummy = exports.Dummy = function(path)
  5839 +var Dummy = exports.Dummy = function(path, options)
5744 5840 {
5745 5841 if (typeof path == "undefined")
5746 5842 return;
5747 5843 this.cloneConstructor = exports.Dummy;
5748 5844 this.path = path;
5749 5845 this.json = {};
  5846 + if (typeof options.extendsDescriptorJSON === "object") {
  5847 + this.json = API.UTIL.deepMerge(this.json, options.extendsDescriptorJSON);
  5848 + }
5750 5849 }
5751 5850 Dummy.prototype = new Package();
5752 5851
@@ -5831,7 +5930,7 @@ Sources.prototype.augmentLocator = function(locator)
5831 5930 typeof this.json.packages[locator.id] == "undefined" ||
5832 5931 typeof this.json.packages[locator.id].source == "undefined")
5833 5932 return false;
5834   - if (typeof this.json.packages[locator.id].source.location == "undefined")
  5933 + if (!this.json.packages[locator.id].source.location)
5835 5934 throw new Error("Source locator for package '" + locator.id + "' must specify 'location' property in: " + this.path);
5836 5935
5837 5936 if (this.json.packages[locator.id].source.location.charAt(0) != "/" &&
@@ -5887,39 +5986,60 @@ var API = __require__('api'),
5887 5986 DEBUG = API.DEBUG;
5888 5987
5889 5988 var MAX_PARALLEL_DOWNLOADS = 2,
5890   - USE_CACHE = false;
  5989 + USE_CACHE = false,
  5990 + ENABLED = true;
5891 5991
5892 5992 var Downloader = exports.Downloader = function(options)
5893 5993 {
5894 5994 this.basePath = options.basePath;
  5995 +
  5996 + // this is the case when used in jetpack or other embedded environment with no PWD
  5997 + if (/^__PWD__/.test(this.basePath)) {
  5998 + ENABLED = false;
  5999 + return;
  6000 + }
  6001 +
  6002 + FILE.mkdirs(this.basePath + "/downloads/files", 0775);
  6003 + FILE.mkdirs(this.basePath + "/downloads/packages", 0775);
  6004 + FILE.mkdirs(this.basePath + "/downloads/archives", 0775);
  6005 + FILE.mkdirs(this.basePath + "/cache", 0775);
5895 6006 }
5896 6007
5897 6008 Downloader.prototype.pathForURL = function(url, type)
5898 6009 {
5899 6010 type = type || "source";
5900 6011
5901   - var m = url.match(/^https?:\/(.*)$/);
  6012 + var m = url.match(/^https?:\/(.*?)(\?(.*))?$/);
5902 6013 if (!m)
5903 6014 throw new Error("Invalid archive URL for mapping: " + archive);
5904 6015
5905 6016 var path = m[1];
5906 6017
  6018 + if (m[3]) {
  6019 + path += "." + encodeURIComponent("?" + m[3]);
  6020 + }
  6021 +
5907 6022 if (path.charAt(path.length-1) == "/")
5908 6023 path = path.substring(0, path.length-1);
5909 6024
5910 6025 if (type=="file")
5911 6026 {
5912   - return this.basePath + "/downloads" + path;
  6027 + return this.basePath + "/downloads/files" + path;
5913 6028 }
5914 6029 else
5915 6030 if (type=="source")
5916 6031 {
5917   - return this.basePath + "/downloads" + path + "~sources";
  6032 + return this.basePath + "/downloads/packages" + path + "~pkg";
  6033 + }
  6034 + else
  6035 + if (type=="install")
  6036 + {
  6037 + return this.basePath + "/downloads/packages" + path + "~install";
5918 6038 }
5919 6039 else
5920 6040 if (type=="archive")
5921 6041 {
5922   - return this.basePath + "/downloads" + path;
  6042 + return this.basePath + "/downloads/archives" + path;
5923 6043 }
5924 6044 else
5925 6045 if (type=="cache")
@@ -5935,6 +6055,9 @@ var unzipping = false,
5935 6055
5936 6056 Downloader.prototype.getForArchive = function(archive, callback, options)
5937 6057 {
  6058 + if (!ENABLED)
  6059 + throw new Error("Downloader is not enabled!");
  6060 +
5938 6061 options = options || {};
5939 6062 var self = this;
5940 6063 var sourcePath = self.pathForURL(archive, "source");
@@ -6011,110 +6134,127 @@ Downloader.prototype.getForArchive = function(archive, callback, options)
6011 6134 callback(sourcePath);
6012 6135 return;
6013 6136 }
6014   - // First check if we have a TGZ archive
6015   - SYSTEM.exec("gunzip -t " + archivePath, function(stdout, stderr)
6016   - {
6017   - if (/gunzip: command not found/.test(stderr))
6018   - {
6019   - return throwError("UNIX Command not found: gunzip");
6020   - }
6021   - else
6022   - if (stderr)
6023   - {
6024   - // ZIP File
6025   - SYSTEM.exec("unzip -qq -o " + archivePath + " -d " + sourcePath, function(stdout, stderr)
6026   - {
6027   - if (/unzip: command not found/.test(stderr))
6028   - {
6029   - cleanup();
6030   - return throwError("UNIX Command not found: unzip");
6031   - }
6032   - else
6033   - if (stderr)
6034   - {
6035   - cleanup();
6036   - return throwError("Error extracting file '" + archivePath + "': " + stderr);
6037   - }
6038   - else
6039   - if (!FILE.exists(sourcePath))
6040   - {
6041   - cleanup();
6042   - return throwError("Error extracting file '" + archivePath) + "' to '" + sourcePath + "'.";
6043   - }
6044   -
6045   - // See if archive has a directory containing our package
6046   - var list = FILE.readdir(sourcePath);
6047   - if (list.length == 1)
6048   - {
6049   - SYSTEM.exec("mv " + sourcePath + "/*/* " + sourcePath + "/", function(stdout, stderr)
6050   - {
6051   - if (!FILE.exists(sourcePath + packageTestFilepath))
6052   - {
6053   - cleanup();
6054   - return throwError("Cannot find " + packageTestFilepath + " in extracted archive: " + sourcePath + packageTestFilepath);
6055   - }
6056   -
6057   - SYSTEM.exec("mv " + sourcePath + "/*/.* " + sourcePath + "/", function(stdout, stderr)
6058   - {
6059   - callback(sourcePath);
6060   - });
6061   - });
6062   - }
6063   - else
6064   - {
6065   - callback(sourcePath);
6066   - }
6067   - });
6068   - }
6069   - else
6070   - {
6071   - // TGZ file
6072   - API.FILE.mkdirs(sourcePath, 0775);
6073   - SYSTEM.exec("tar -zxf " + archivePath + " -C " + sourcePath, function(stdout, stderr)
6074   - {
6075   - if (/tar: command not found/.test(stderr))
6076   - {
6077   - cleanup();
6078   - return throwError("UNIX Command not found: tar");
6079   - }
6080   - else
6081   - if (stderr)
6082   - {
6083   - cleanup();
6084   - return throwError("Error extracting file '" + archivePath + "': " + stderr);
6085   - }
6086   - else
6087   - if (!FILE.exists(sourcePath))
6088   - {
6089   - cleanup();
6090   - return throwError("Error extracting file '" + archivePath) + "' to '" + sourcePath + "'.";
6091   - }
6092   -
6093   - // See if archive has a directory containing our package
6094   - var list = FILE.readdir(sourcePath);
6095   - if (list.length == 1)
6096   - {
6097   - SYSTEM.exec("mv " + sourcePath + "/*/* " + sourcePath + "/", function(stdout, stderr)
6098   - {
6099   - if (!FILE.exists(sourcePath + packageTestFilepath))
6100   - {
6101   - cleanup();
6102   - return throwError("Cannot find " + packageTestFilepath + " in extracted archive: " + sourcePath + packageTestFilepath);
6103   - }
6104 6137
6105   - SYSTEM.exec("mv " + sourcePath + "/*/.* " + sourcePath + "/", function(stdout, stderr)
6106   - {
6107   - callback(sourcePath);
6108   - });
6109   - });
6110   - }
6111   - else
6112   - {
6113   - callback(sourcePath);
6114   - }
6115   - });
6116   - }
6117   - });
  6138 + if (typeof options.extract === "function")
  6139 + {
  6140 + try {
  6141 + options.extract(archivePath, sourcePath, function()
  6142 + {
  6143 + callback(sourcePath);
  6144 + });
  6145 + } catch(e) {
  6146 + cleanup();
  6147 + return throwError("Error calling custom extract while extracting file '" + archivePath + "': " + e);
  6148 + }
  6149 + }
  6150 + else
  6151 + {
  6152 + // First check if we have a TGZ archive
  6153 + SYSTEM.exec("gunzip -t " + archivePath, function(stdout, stderr)
  6154 + {
  6155 + if (/gunzip: command not found/.test(stderr))
  6156 + {
  6157 + return throwError("UNIX Command not found: gunzip");
  6158 + }
  6159 + else
  6160 + if (stderr)
  6161 + {
  6162 + FILE.mkdirs(sourcePath, 0775);
  6163 + // ZIP File
  6164 + SYSTEM.exec("unzip -qq -o " + archivePath + " -d " + sourcePath, function(stdout, stderr)
  6165 + {
  6166 + if (/unzip: command not found/.test(stderr))
  6167 + {
  6168 + cleanup();
  6169 + return throwError("UNIX Command not found: unzip");
  6170 + }
  6171 + else
  6172 + if (stderr)
  6173 + {
  6174 + cleanup();
  6175 + return throwError("Error extracting file '" + archivePath + "': " + stderr);
  6176 + }
  6177 + else
  6178 + if (!FILE.exists(sourcePath))
  6179 + {
  6180 + cleanup();
  6181 + return throwError("Error extracting file '" + archivePath) + "' to '" + sourcePath + "'.";
  6182 + }
  6183 +
  6184 + // See if archive has a directory containing our package
  6185 + var list = FILE.readdir(sourcePath);
  6186 + if (list.length == 1)
  6187 + {
  6188 + SYSTEM.exec("mv " + sourcePath + "/*/* " + sourcePath + "/", function(stdout, stderr)
  6189 + {
  6190 + if (!FILE.exists(sourcePath + packageTestFilepath))
  6191 + {
  6192 + cleanup();
  6193 + return throwError("Cannot find " + packageTestFilepath + " in extracted archive: " + sourcePath + packageTestFilepath);
  6194 + }
  6195 +
  6196 + SYSTEM.exec("mv " + sourcePath + "/*/.* " + sourcePath + "/", function(stdout, stderr)
  6197 + {
  6198 + callback(sourcePath);
  6199 + });
  6200 + });
  6201 + }
  6202 + else
  6203 + {
  6204 + callback(sourcePath);
  6205 + }
  6206 + });
  6207 + }
  6208 + else
  6209 + {
  6210 + // TGZ file
  6211 + FILE.mkdirs(sourcePath, 0775);
  6212 + SYSTEM.exec("tar -zxf " + archivePath + " -C " + sourcePath, function(stdout, stderr)
  6213 + {
  6214 + if (/tar: command not found/.test(stderr))
  6215 + {
  6216 + cleanup();
  6217 + return throwError("UNIX Command not found: tar");
  6218 + }
  6219 + else
  6220 + if (stderr)
  6221 + {
  6222 + cleanup();
  6223 + return throwError("Error extracting file '" + archivePath + "': " + stderr);
  6224 + }
  6225 + else
  6226 + if (!FILE.exists(sourcePath))
  6227 + {
  6228 + cleanup();
  6229 + return throwError("Error extracting file '" + archivePath) + "' to '" + sourcePath + "'.";
  6230 + }
  6231 +
  6232 + // See if archive has a directory containing our package
  6233 + var list = FILE.readdir(sourcePath);
  6234 + if (list.length == 1)
  6235 + {
  6236 + SYSTEM.exec("mv " + sourcePath + "/*/* " + sourcePath + "/", function(stdout, stderr)
  6237 + {
  6238 + if (!FILE.exists(sourcePath + packageTestFilepath))
  6239 + {
  6240 + cleanup();
  6241 + return throwError("Cannot find " + packageTestFilepath + " in extracted archive: " + sourcePath + packageTestFilepath);
  6242 + }
  6243 +
  6244 + SYSTEM.exec("mv " + sourcePath + "/*/.* " + sourcePath + "/", function(stdout, stderr)
  6245 + {
  6246 + callback(sourcePath);
  6247 + });
  6248 + });
  6249 + }
  6250 + else
  6251 + {
  6252 + callback(sourcePath);
  6253 + }
  6254 + });
  6255 + }
  6256 + });
  6257 + }
6118 6258 }
6119 6259
6120 6260 var archivePath = self.pathForURL(archive, "archive");
@@ -6141,6 +6281,9 @@ Downloader.prototype.getCatalogForURL = function(url, callback)
6141 6281
6142 6282 Downloader.prototype.getFileForURL = function(url, callback)
6143 6283 {
  6284 + if (!ENABLED)
  6285 + throw new Error("Downloader is not enabled!");
  6286 +
6144 6287 var path = this.pathForURL(url, "file");
6145 6288
6146 6289 if (FILE.exists(path))
@@ -6206,7 +6349,7 @@ Downloader.prototype.enqueueDownload = function(url, path, callback)
6206 6349
6207 6350 Downloader.prototype.doDownload = function(url, path, callback)
6208 6351 {
6209   - currentlyDownloading[url + "::" + path] = true;
  6352 + currentlyDownloading[url + "::" + path] = true;
6210 6353 var cachePath = this.pathForURL(url, "cache");
6211 6354 if (USE_CACHE)
6212 6355 {
@@ -6224,6 +6367,7 @@ Downloader.prototype.doDownload = function(url, path, callback)
6224 6367
6225 6368 NET.download(url, path + ".tmp", function()
6226 6369 {
  6370 + FILE.rename(path + ".tmp", path);
6227 6371 if (USE_CACHE)
6228 6372 {
6229 6373 API.FILE.mkdirs(API.FILE.dirname(cachePath), 0775);
@@ -6234,7 +6378,6 @@ Downloader.prototype.doDownload = function(url, path, callback)
6234 6378 });
6235 6379 return;
6236 6380 }
6237   - FILE.rename(path + ".tmp", path);
6238 6381 delete currentlyDownloading[url + "::" + path];
6239 6382 callback();
6240 6383 });
@@ -6317,6 +6460,7 @@ var boot = exports.boot = function(options)
6317 6460
6318 6461 var API = __require__('api');
6319 6462 API.SANDBOX = __require__('sandbox');
  6463 + API.CONSOLE = __require__('console');
6320 6464
6321 6465 API.ENV.timers = timers;
6322 6466 API.DEBUG.enabled = options.debug || void 0;
@@ -6346,6 +6490,8 @@ var boot = exports.boot = function(options)
6346 6490 optParser.arg(".../[program.json]").optional();
6347 6491 optParser.help("Runs the PINF JavaScript Loader.");
6348 6492 optParser.option("-v", "--verbose").bool().help("Enables progress messages");
  6493 + optParser.option("--pidfile").set().help("Write the process ID to the specified file. Remove file on exit. Ensures only one instance at a time.");
  6494 + optParser.option("--daemonize").bool().help("Daemonize the process. Requires: npm install daemon");
6349 6495 optParser.option("--platform").set().help("The platform to use");
6350 6496 optParser.option("--sources").set().help("The path to a sources.json file to overlay source repositories");
6351 6497 optParser.option("--script").set().help("Call a script defined in the program boot package");
@@ -6426,325 +6572,372 @@ var boot = exports.boot = function(options)
6426 6572 spawnForPlatform(cliOptions.platform);
6427 6573 return;
6428 6574 }
6429   -
6430   - API.DEBUG.print("\0magenta(----------------------------------------------------------------------------");
6431   - API.DEBUG.print("\0bold(| PINF Loader v" + VERSION + " ~ https://github.com/pinf/loader-js/\0)");
6432   - API.DEBUG.print("----------------------------------------------------------------------------\0)");
6433   -
6434   - API.DEBUG.print("Loaded adapter: " + API.ENV.platform);
6435   -
6436   - var downloader = new (__require__('downloader').Downloader)({
6437   - // TODO: Look for a better place first
6438   - basePath: API.SYSTEM.pwd + "/.pinf-packages"
6439   - });
6440   -
6441   - var assembler = API.ENV.assembler = new (__require__('assembler').Assembler)(downloader);
6442   -
6443   - API.ENV.loadSourceDescriptorsForProgram = function(path, existingSourceDescriptors)
6444   - {
6445   - var DESCRIPTORS = __require__('descriptors');
6446   - var sourceDescriptors = [],
6447   - files = [];
6448   - if (typeof existingSourceDescriptors !== "undefined") {
6449   - existingSourceDescriptors.forEach(function(descriptor)
6450   - {
6451   - sourceDescriptors[descriptor.path] = descriptor;
6452   - });
6453   - }
6454   - if (cliOptions.sources)
6455   - {
6456   - if (!API.FILE.exists(cliOptions.sources))
6457   - throw new Error("Source repository overlay file specified via --sources not found at: " + cliOptions.sources);
6458   - files.push(cliOptions.sources);
6459   - }
6460   - if (options.sources)
6461   - {
6462   - if (!API.FILE.exists(options.sources))
6463   - throw new Error("Source repository overlay file specified via options.sources not found at: " + options.sources);
6464   - files.push(options.sources);
6465   - }
6466   - files.push(API.FILE.dirname(path) + "/sources.local.json");
6467   - if (typeof API.SYSTEM.env.HOME != "undefined" && API.SYSTEM.env.HOME)
6468   - files.push(API.SYSTEM.env.HOME + "/.pinf/config/sources.json");
6469   - files.push(API.FILE.dirname(path) + "/sources.json");
6470   - files.forEach(function(sourcesPath)
6471   - {
6472   - if (!sourceDescriptors[sourcesPath] && API.FILE.exists(sourcesPath))
6473   - sourceDescriptors[sourcesPath] = new DESCRIPTORS.Sources(sourcesPath);
6474   - });
6475   - var descriptors = [];
6476   - for (var key in sourceDescriptors)
6477   - descriptors.push(sourceDescriptors[key]);
6478   - sourceDescriptors = descriptors;
6479   - if (API.DEBUG.enabled)
6480   - {
6481   - if (sourceDescriptors.length > 0)
6482   - {
6483   - API.DEBUG.print("Using source overlay files:");
6484   - sourceDescriptors.forEach(function(sourceDescriptor)
6485   - {
6486   - API.DEBUG.print(" \0cyan(" + sourceDescriptor.path + "\0)");
6487   - });
  6575 +
  6576 + function run()
  6577 + {
  6578 + API.DEBUG.print("\0magenta(----------------------------------------------------------------------------");
  6579 + API.DEBUG.print("\0bold(| PINF Loader v" + VERSION + " ~ https://github.com/pinf/loader-js/\0)");
  6580 + API.DEBUG.print("----------------------------------------------------------------------------\0)");
  6581 +
  6582 + API.DEBUG.print("Loaded adapter: " + API.ENV.platform);
  6583 +
  6584 + var downloader = new ((API.DOWNLOADER = __require__('downloader')).Downloader)({
  6585 + // TODO: Look for a better place first
  6586 + basePath: API.SYSTEM.pwd + "/.pinf-packages"
  6587 + });
  6588 +
  6589 + var assembler = API.ENV.assembler = new (__require__('assembler').Assembler)(downloader);
  6590 +
  6591 + API.ENV.loadSourceDescriptorsForProgram = function(path, existingSourceDescriptors)
  6592 + {
  6593 + var DESCRIPTORS = __require__('descriptors');
  6594 + var sourceDescriptors = [],
  6595 + files = [];
  6596 + if (typeof existingSourceDescriptors !== "undefined") {
  6597 + existingSourceDescriptors.forEach(function(descriptor)
  6598 + {
  6599 + sourceDescriptors[descriptor.path] = descriptor;
  6600 + });
  6601 + }
  6602 + if (cliOptions.sources)
  6603 + {
  6604 + if (!API.FILE.exists(cliOptions.sources))
  6605 + throw new Error("Source repository overlay file specified via --sources not found at: " + cliOptions.sources);
  6606 + files.push(cliOptions.sources);
  6607 + }
  6608 + if (options.sources)
  6609 + {
  6610 + if (!API.FILE.exists(options.sources))
  6611 + throw new Error("Source repository overlay file specified via options.sources not found at: " + options.sources);
  6612 + files.push(options.sources);
  6613 + }
  6614 +
  6615 + if (API.SYSTEM.pwd !== "__PWD__")
  6616 + {
  6617 + files.push(API.SYSTEM.pwd + "/sources.local.json");
  6618 + }
  6619 + files.push(API.FILE.dirname(path) + "/sources.local.json");
  6620 + if (typeof API.SYSTEM.env.HOME != "undefined" && API.SYSTEM.env.HOME)
  6621 + files.push(API.SYSTEM.env.HOME + "/.pinf/config/sources.json");
  6622 + files.push(API.FILE.dirname(path) + "/sources.json");
  6623 + files.forEach(function(sourcesPath)
  6624 + {
  6625 + if (!sourceDescriptors[sourcesPath] && API.FILE.exists(sourcesPath))
  6626 + sourceDescriptors[sourcesPath] = new DESCRIPTORS.Sources(sourcesPath);
  6627 + });
  6628 + var descriptors = [];
  6629 + for (var key in sourceDescriptors)
  6630 + descriptors.push(sourceDescriptors[key]);
  6631 + sourceDescriptors = descriptors;
  6632 + if (API.DEBUG.enabled)
  6633 + {
  6634 + if (sourceDescriptors.length > 0)
  6635 + {
  6636 + API.DEBUG.print("Using source overlay files:");
  6637 + sourceDescriptors.forEach(function(sourceDescriptor)
  6638 + {
  6639 + API.DEBUG.print(" \0cyan(" + sourceDescriptor.path + "\0)");
  6640 + });
  6641 + }
  6642 + else
  6643 + API.DEBUG.print("Not using any source overlay files.");
  6644 + }
  6645 + return sourceDescriptors;
  6646 + }
  6647 +
  6648 + var init = function(path)
  6649 + {
  6650 + path = path || "";
  6651 + if (path.charAt(0) != "/")
  6652 + path = API.SYSTEM.pwd + "/" + path;
  6653 + path = path.split("/");
  6654 +
  6655 + if (/\.zip$/.test(path[path.length-1]))
  6656 + {
  6657 + path[path.length-1] += "!/";
  6658 + }
  6659 + if (!path[path.length-1] || path[path.length-1] != "program.json")
  6660 + {
  6661 + API.DEBUG.print("No descriptor URI argument. Assuming: '[./]program.json'");
  6662 + path.push("program.json");
  6663 + }
  6664 + path = API.FILE.realpath(path.join("/"));
  6665 +
  6666 + API.DEBUG.print("Loading program descriptor from: " + path);
  6667 +
  6668 + downloader.basePath = path.substring(0, path.length-13) + "/.pinf-packages";
  6669 +
  6670 + API.DEBUG.print("Using program cache directory: " + downloader.basePath);
  6671 +
  6672 + // ######################################################################
  6673 + // # Sandbox
  6674 + // ######################################################################
  6675 +
  6676 + var sandbox = new API.SANDBOX.Sandbox({
  6677 + mainModuleDir: API.FILE.dirname(path) + "/"
  6678 + });
  6679 +
  6680 + // ######################################################################
  6681 + // # Simple script
  6682 + // ######################################################################
  6683 +
  6684 + if (!API.FILE.isFile(path))
  6685 + {
  6686 + var scriptPath = cliOptions.args[0];
  6687 +
  6688 + if (scriptPath.charAt(0) != "/")
  6689 + {
  6690 + scriptPath = API.FILE.realpath(API.SYSTEM.pwd + "/" + scriptPath);
  6691 + if (!/\.js$/.test(scriptPath))
  6692 + scriptPath += ".js";
  6693 + }
  6694 +
  6695 + if (!API.FILE.exists(scriptPath))
  6696 + {
  6697 + if (/\.js$/.test(scriptPath))
  6698 + scriptPath = scriptPath.substring(0, scriptPath.length-3);
  6699 +
  6700 + if (!API.FILE.exists(scriptPath))
  6701 + throw new Error("Script not found at: " + scriptPath);
  6702 + }
  6703 +
  6704 + sandbox.init();
  6705 + sandbox.declare([ scriptPath ], function(require, exports, module)
  6706 + {
  6707 + var scriptModule = require(scriptPath);
  6708 + if (typeof scriptModule.main == "undefined")
  6709 + throw new Error("Script at '" + scriptPath + "' does not export 'main()'");
  6710 +
  6711 + API.DEBUG.print("Running script: " + scriptPath);
  6712 +
  6713 + API.DEBUG.print("\0magenta(\0:blue(----- | Script stdout & stderr follows ====>\0:)\0)");
  6714 +
  6715 + scriptModule.main({
  6716 + bootProgram: function(options)
  6717 + {
  6718 + if (typeof options.platformRequire == "undefined")
  6719 + options.platformRequire = API.ENV.platformRequire;
  6720 + return boot(options);
  6721 + },
  6722 + args: cliOptions.args.slice(1, cliOptions.args.length)
  6723 + });
  6724 + });
  6725 + return;
  6726 + }
  6727 +
  6728 + // ######################################################################
  6729 + // # Program assembly
  6730 + // ######################################################################
  6731 +
  6732 + if (!API.FILE.exists(path))
  6733 + {
  6734 + API.SYSTEM.print("\0red(No program descriptor found at: " + path + "\0)\n");
  6735 + return;
  6736 + }
  6737 +
  6738 + // Assemble the program (making all code available on disk) by downloading all it's dependencies
  6739 +
  6740 + assembler.assembleProgram(sandbox, path, function(program)
  6741 + {
  6742 + var engines = program.getEngines();
  6743 + if (engines)
  6744 + {
  6745 + if (engines.indexOf(API.ENV.platform) === -1)
  6746 + {
  6747 + API.DEBUG.print("\0yellow(Spawning platform: " + engines[0] + "\0)");
  6748 + spawnForPlatform(engines[0]);
  6749 + return false;
  6750 + }
  6751 + }
  6752 + return true;
  6753 + },
  6754 + function(program)
  6755 + {
  6756 + API.ENV.booting = false;
  6757 +
  6758 + // TODO: Keep these references elsewhere so we can have nested sandboxes
  6759 + API.ENV.program = program;
  6760 + API.ENV.sandbox = sandbox;
  6761 +
  6762 + var dependencies = program.getBootPackages();
  6763 + if (dependencies.length > 1)
  6764 + {
  6765 + throw new Error("Only one program boot package allowed in: " + path);
  6766 + }
  6767 +
  6768 + // ######################################################################
  6769 + // # Program Booting
  6770 + // ######################################################################
  6771 +
  6772 + API.ENV.booting = true;
  6773 +
  6774 + if (API.DEBUG.enabled) {
  6775 + API.DEBUG.print("Loading program's main packages:");
  6776 + for (var i=0, ic=dependencies.length ; i<ic ; i++ )
  6777 + {
  6778 + if (typeof dependencies[i]["_package-" + i] != "undefined")
  6779 + API.DEBUG.print(" " + dependencies[i]["_package-" + i].location);
  6780 + }
  6781 + }
  6782 +
  6783 + timers.load = new Date().getTime()
  6784 +
  6785 + var env = options.env || {};
  6786 + env.args = env.args || options.args || cliOptions.args.slice(1, cliOptions.args.length) || [];
  6787 +
  6788 + sandbox.declare(dependencies, function(require, exports, module)
  6789 + {
  6790 + timers.run = new Date().getTime()
  6791 +
  6792 + // ######################################################################
  6793 + // # Program Script
  6794 + // ######################################################################
  6795 +
  6796 + if (cliOptions.script)
  6797 + {
  6798 + var pkg = sandbox.packageForId(dependencies[0]['_package-0'].location);
  6799 + if (typeof pkg.normalizedDescriptor.json.scripts == "undefined")
  6800 + throw new Error("No 'scripts' defined in package descriptor: " + pkg.normalizedDescriptor.path);
  6801 + if (typeof pkg.normalizedDescriptor.json.scripts[cliOptions.script] == "undefined")
  6802 + throw new Error("Script '" + cliOptions.script + "' not found in 'scripts' defined in package descriptor: " + pkg.normalizedDescriptor.path);
  6803 + if (typeof pkg.normalizedDescriptor.json.scripts[cliOptions.script] == "object")
  6804 + {
  6805 + assembler.addPackageToProgram(sandbox, sandbox.program, pkg.normalizedDescriptor.json.scripts[cliOptions.script], function(pkg)
  6806 + {
  6807 + module.load(pkg.getMainId(pkg.normalizedDescriptor.json.scripts[cliOptions.script]), function(id)
  6808 + {
  6809 + var script = require(id);
  6810 +
  6811 + if (typeof script.main == "undefined")
  6812 + throw new Error("Script does not export main() in " + id);
  6813 +
  6814 + API.ENV.booting = false;
  6815 +
  6816 + API.DEBUG.print("\0magenta(\0:blue(----- | Program script stdout & stderr follows ====>\0:)\0)");
  6817 +
  6818 + script.main(env);
  6819 + });
  6820 + }, {
  6821 + "discover-packages": cliOptions["discover-packages"] || false,
  6822 + sourceDescriptors: API.ENV.loadSourceDescriptorsForProgram(path)
  6823 + });
  6824 + }
  6825 + else
  6826 + throw new Error("NYI - Non-locator based script pointers");
  6827 + }
  6828 + else
  6829 +
  6830 + // ######################################################################
  6831 + // # Program Boot Packages
  6832 + // ######################################################################
  6833 +
  6834 + {
  6835 + API.DEBUG.print("Booting program. Output for boot package follows in green between ==> ... <==");
  6836 +
  6837 + // Run the program by calling main() on each packages' main module
  6838 + var pkg,
  6839 + hl;
  6840 + // TODO: Refactor as there is only ever one boot package
  6841 +