From 26ed31c165a522e9681e36c68e1d56721d6b3d0f Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Wed, 10 Jul 2013 07:59:58 -0700 Subject: Subcommand 'eos-application-manifest init' This implements the 'init' subcommand of the application manifest tool, which creates a new manifest in the current directory. [endlessm/eos-sdk#154] [endlessm/eos-sdk#154] --- tools/eos-application-manifest/commands/init.js | 197 ++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 tools/eos-application-manifest/commands/init.js (limited to 'tools/eos-application-manifest') diff --git a/tools/eos-application-manifest/commands/init.js b/tools/eos-application-manifest/commands/init.js new file mode 100644 index 0000000..8fdc165 --- /dev/null +++ b/tools/eos-application-manifest/commands/init.js @@ -0,0 +1,197 @@ +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const System = imports.system; + +const DEFAULT_LOCALE = 'en'; +const CURRENT_MANIFEST_VERSION = 1; + +function execute(args) { + let [id, argdict] = parseArgs(args); + let manifest = createManifest(id, argdict); + let json_manifest = JSON.stringify(manifest, null, " "); + + let filename = createFilenameForManifest(manifest); + let cwd = Gio.File.new_for_path(GLib.get_current_dir()); + let file = cwd.get_child(filename); + + file.replace_contents(json_manifest, null /* etag */, + false /* make backup */, Gio.FileCreateFlags.REPLACE_DESTINATION, + null /* cancellable */); +} + +// Takes a manifest with a valid application ID and creates the appropriate +// filename to put it in. +function createFilenameForManifest(manifest) { + return manifest.applicationId + '.json'; +} + +// Takes a valid application ID and validated list of command-line arguments +// and creates a valid application manifest. +function createManifest(id, argdict) { + let locale = argdict.locale || DEFAULT_LOCALE; + let manifestVersion = CURRENT_MANIFEST_VERSION; + if ('manifest-version' in argdict) + manifestVersion = parseInt(argdict['manifest-version'], 10); + + let launcherKey, launcherValue; + if (typeof argdict.appclass != 'undefined') { + launcherKey = 'applicationClass'; + launcherValue = argdict.appclass; + } else { + launcherKey = 'exec'; + launcherValue = argdict.exec; + } + + let manifest = {}; + manifest.manifestVersion = manifestVersion; + manifest.applicationId = id; + manifest.applicationName = createLocaleDict(locale, argdict.appname); + manifest.authorName = argdict.author; + manifest.authorWebsite = argdict.website || ''; + manifest.description = createLocaleDict(locale, argdict.description || ''); + manifest.version = argdict.appversion; + manifest.changes = createLocaleDict(locale, []); + manifest.license = argdict.license || ''; + manifest.resources = []; + manifest[launcherKey] = launcherValue; + manifest.icons = {}; + manifest.categories = []; + manifest.permissions = []; + manifest.metadata = {}; + + return manifest; +} + +// Takes a locale and a JS object and creates a dictionary such that for +// locale == 'pt_BR', return value is { 'pt_BR': value }. +function createLocaleDict(locale, value) { + let retval = {}; + retval[locale] = value; + return retval; +} + +// Parse command line arguments and return a valid application ID and a +// dictionary of other parameters passed. Validates the parameters. +function parseArgs(args) { + if (typeof args == 'undefined' || args.length === 0) { + help(); + throw new Error(); + } + + // App ID is the mandatory first argument + let id = args.shift(); + if (!Gio.Application.id_is_valid(id)) + throw new Error('"%s" is not a valid application ID. Rules:\n\ +- must contain only the ASCII characters "[A-Z][a-z][0-9]_-." and must not\n\ + begin with a digit.\n\ +- must contain at least one "."" (period) character (and thus at least three\n\ + characters).\n\ +- must not begin or end with a "." (period) character.\n\ +- must not contain consecutive "."" (period) characters.\n\ +- must not exceed 255 characters.'.format(id)); + + let argdict = parseRemainingArgs(args); + if (!validateRemainingArgs(argdict)) { + help(); + throw new Error(); + } + + return [id, argdict]; +} + +// Parse all arguments after the application ID has been removed +function parseRemainingArgs(args) { + let retval = {}; + for (let count = 0; count < args.length; count++) { + if (args[count].startsWith('--')) { + if (args[count].indexOf('=') != -1) { + // One parameter of the form --parameter=value + let expr = args[count].slice(2); + let [parameter, value] = expr.split('='); + retval[parameter] = value; + continue; + } + // Otherwise, the --parameter consumes the next argument if it's + // there and not also a --parameter + if (typeof args[count + 1] == 'undefined' || + args[count + 1].startsWith('--')) { + let parameter = args[count].slice(2); + retval[parameter] = null; + continue; + } + let parameter = args[count].slice(2); + retval[parameter] = args[count + 1]; + count++; + } + } + return retval; +} + +// Validate all arguments besides the application ID +function validateRemainingArgs(args) { + let requiredArgs = ['appname', 'author', 'appversion']; + let knownArgs = ['appclass', 'exec', 'manifest-version', 'website', + 'description', 'locale', 'license']; + + for (let arg of requiredArgs) { + if (!(arg in args)) + return false; + } + + // Only one of --appclass or --exec + if ('appclass' in args && 'exec' in args) + return false; + if (!('appclass' in args) && !('exec' in args)) + return false; + + for (let arg in args) { + if (requiredArgs.indexOf(arg) == -1 && knownArgs.indexOf(arg) == -1) + return false; + if (args[arg] === null) + return false; + } + + // Validate any content requirements for certain parameters here + + if ('manifest-version' in args) { + let versionNumber = parseInt(args['manifest-version'], 10); + if (Number.isNaN(versionNumber) || versionNumber < 0 || + versionNumber > CURRENT_MANIFEST_VERSION) + return false; + } + + return true; +} + +function summary() { + return 'Generate a minimal valid manifest'; +} + +function help() { + print('Generates a minimal valid manifest in the current directory.\n\n\ +Usage: %s init \n\ + --appname= --appversion=\n\ + --author= {--appclass=|--exec=}\n\ + [--manifest-version=] [--website=]\n\ + [--description=] [--locale=]\n\ + [--license=]\n\n\ +Required options for a minimal valid manifest:\n\ + - A unique application ID, e.g. "com.example.weather"\n\ + --appname - Human-readable application name, e.g. "Weather Reader"\n\ + --author - Author name, e.g. "Joe Coder "\n\ + --appversion - Application version number\n\ + --appclass - Name of a class derived from Endless.Application with\n\ + its module to import, e.g. WeatherReader.App\n\ + --exec - Path to an executable within the package, that\n\ + launches the application, e.g. "bin/weather-reader"\n\ +(Use only one of either --appclass or --exec.)\n\n\ +Other options:\n\ + --manifest-version - Version of the manifest file specification to use\n\ + [default: the current one]\n\ + --website - URI with more information about the application\n\ + --description - Long description of the application\n\ + --locale - Locale information for --appname and --description\n\ + [default "en"]\n\ + --license - Software license under which the application is\n\ + provided to users'.format(System.programInvocationName)); +} -- cgit v1.2.3