#!/usr/bin/env node var VERSION = require("../package.json").version; var program = require("commander"); var console = require("../lib/utils").console; var run = require("../lib/run"); var test = require("../lib/test"); var xpi = require("../lib/xpi"); var init = require("../lib/init"); var cmd = require("../lib/cmd"); var open = require("open"); var postXPI = require("../lib/post"); var watch = require("node-watch"); var cp = require("child_process"); var signCmd = require("../lib/sign").signCmd; var path = require("path"); var AMO_API_PREFIX = require("../lib/settings").AMO_API_PREFIX; // TODO: use .jpmignore file here instead var IGNORE_FILES_REGEX = /(?:bootstrap\.js|install\.rdf|\.xpi)$/i; program .version(VERSION) .option("-b, --binary ", "Path of Firefox binary to use.") .option("-p, --profile ", "Path or name of Firefox profile to use.") .option("--no-copy", "Do not copy the profile. Use with caution!") .option("-v, --verbose", "More verbose logging to stdout.") .option( "-o, --overload [path]", "Overloads the built-in Firefox SDK modules with a local copy " + "located at environment variable `JETPACK_ROOT` or `path` if " + "supplied. Used for development on the SDK itself.") .option( "-f, --filter ", "--filter=FILENAME[:TESTNAME] only run tests " + "whose filenames match FILENAME and " + "optionally match TESTNAME, both regexps") .option("--addon-dir ", "Path of Firefox addon to build.", // turn into an absolute path function(dir) { return path.resolve(dir); }, process.cwd()) .option("--binary-args ", "Pass additional arguments into Firefox.") .option("--prefs ", "Custom set user preferences (path to a json file)") .option("--post-url ", "A url to post a xpi of your extension") .option("--stop-on-error", "Stop running tests after the first failure") .option("--do-not-quit", "Do not close Firefox on a test failure") .option("--tbpl", "Print test output in TBPL format") .option("--times ", "Number of times to run tests") .option("--debug", "Enable the add-on debugger when running the add-on") .option("--check-memory", "Enable leaked tracker that attempts to report compartments leaked") .option("--profile-memory", "Enable profiling of memory usage") .option( "--retro", "In development flag for transitioning to new style addons; forces the " + "lack of install.rdf/bootstrap.js creation regardless of what engine " + "versions are running"); program .command("docs") .description("Open the JPM documentation") .action(function() { open("https://developer.mozilla.org/Add-ons/SDK/Tutorials/" + "Getting_Started_%28jpm%29"); }); program .command("xpi") .description("Bundle the addon into an .xpi file") .action(cmd.prepare("xpi", program, function(manifest) { var start = Date.now(); xpi(manifest, program).then(function(xpiPath) { var diff = Date.now() - start; console.log("Successfully created XPI at " + xpiPath + " (" + diff + "ms)"); }, function(reason) { console.error("XPI creation failed: " + reason); }); })); program .command("post") .description( "*EXPERIMENTAL* Bundle the addon into an .xpi file and post it to a url") .action(cmd.prepare("post", program, function(manifest) { postXPI(manifest, program); })); program .command("sign") .description("Retrieve a Mozilla-signed .xpi file for your current add-on") .option("--api-key ", "addons.mozilla.org API key string") .option("--api-secret ", "addons.mozilla.org API secret string") .option("--api-url-prefix ", "addons.mozilla.org API URL prefix [" + AMO_API_PREFIX + "]", AMO_API_PREFIX) .option("--xpi ", "optional XPI to be signed. By default, an XPI will be built " + "from your working directory") .option("--timeout ", "time to wait for a signing result") .action(function(options) { signCmd(program, options); }); program .command("watchpost") .description( "*EXPERIMENTAL* Bundle the addon into an .xpi file and post it to a " + "url, whenever your add-on changes") .action(cmd.prepare("watchpost", program, function(manifest) { postXPI(manifest, program); var lastSubProcess = null; watch(process.cwd(), function(filename) { // ignore install.rdf, boostrap.js, xpi files to avoid infinite loops if (IGNORE_FILES_REGEX.test(filename)) { return null; } if (lastSubProcess) { return null; } var subProcess = cp.spawn("node", [ __filename, "post", "--post-url", program.postUrl ]); lastSubProcess = subProcess; subProcess.stdout.pipe(process.stdout); subProcess.stderr.pipe(process.stderr); subProcess.on("exit", function() { lastSubProcess = null; }); return null; }); return null; })); program .command("test") .description("Run tests for current addon") .action(cmd.prepare("test", program, function(manifest) { test(manifest, program).then(function(results) { process.exit(results.code); }, console.error); })); program .command("init") .description("Series of prompts to create a package.json for a new addon") .action(function() { init().then(process.exit); }); program .command("run") .description("Install and run in Firefox the current addon") .action(cmd.prepare("run", program, function(manifest) { run(manifest, program).then(null, console.error); })); program.parse(process.argv); // If no command (run, xpi, init, etc.) specified, display basic help if (cmd.isEmptyCommand(program)) { program.help(); }