123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- /*
- * Jake JavaScript build tool
- * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
- if (!global.jake) {
- let EventEmitter = require('events').EventEmitter;
- // And so it begins
- global.jake = new EventEmitter();
- let fs = require('fs');
- let chalk = require('chalk');
- let taskNs = require('./task');
- let Task = taskNs.Task;
- let FileTask = taskNs.FileTask;
- let DirectoryTask = taskNs.DirectoryTask;
- let Rule = require('./rule').Rule;
- let Namespace = require('./namespace').Namespace;
- let RootNamespace = require('./namespace').RootNamespace;
- let api = require('./api');
- let utils = require('./utils');
- let Program = require('./program').Program;
- let loader = require('./loader')();
- let pkg = JSON.parse(fs.readFileSync(__dirname + '/../package.json').toString());
- const MAX_RULE_RECURSION_LEVEL = 16;
- // Globalize jake and top-level API methods (e.g., `task`, `desc`)
- Object.assign(global, api);
- // Copy utils onto base jake
- jake.logger = utils.logger;
- jake.exec = utils.exec;
- // File utils should be aliased directly on base jake as well
- Object.assign(jake, utils.file);
- // Also add top-level API methods to exported object for those who don't want to
- // use the globals (`file` here will overwrite the 'file' utils namespace)
- Object.assign(jake, api);
- Object.assign(jake, new (function () {
- this._invocationChain = [];
- this._taskTimeout = 30000;
- // Public properties
- // =================
- this.version = pkg.version;
- // Used when Jake exits with a specific error-code
- this.errorCode = null;
- // Loads Jakefiles/jakelibdirs
- this.loader = loader;
- // The root of all ... namespaces
- this.rootNamespace = new RootNamespace();
- // Non-namespaced tasks are placed into the default
- this.defaultNamespace = this.rootNamespace;
- // Start in the default
- this.currentNamespace = this.defaultNamespace;
- // Saves the description created by a 'desc' call that prefaces a
- // 'task' call that defines a task.
- this.currentTaskDescription = null;
- this.program = new Program();
- this.FileList = require('filelist').FileList;
- this.PackageTask = require('./package_task').PackageTask;
- this.PublishTask = require('./publish_task').PublishTask;
- this.TestTask = require('./test_task').TestTask;
- this.Task = Task;
- this.FileTask = FileTask;
- this.DirectoryTask = DirectoryTask;
- this.Namespace = Namespace;
- this.Rule = Rule;
- this.parseAllTasks = function () {
- let _parseNs = function (ns) {
- let nsTasks = ns.tasks;
- let nsNamespaces = ns.childNamespaces;
- for (let q in nsTasks) {
- let nsTask = nsTasks[q];
- jake.Task[nsTask.fullName] = nsTask;
- }
- for (let p in nsNamespaces) {
- let nsNamespace = nsNamespaces[p];
- _parseNs(nsNamespace);
- }
- };
- _parseNs(jake.defaultNamespace);
- };
- /**
- * Displays the list of descriptions available for tasks defined in
- * a Jakefile
- */
- this.showAllTaskDescriptions = function (f) {
- let p;
- let maxTaskNameLength = 0;
- let task;
- let padding;
- let name;
- let descr;
- let filter = typeof f == 'string' ? f : null;
- let taskParams;
- let len;
- for (p in jake.Task) {
- if (!Object.prototype.hasOwnProperty.call(jake.Task, p)) {
- continue;
- }
- if (filter && p.indexOf(filter) == -1) {
- continue;
- }
- task = jake.Task[p];
- taskParams = task.params;
- // Record the length of the longest task name -- used for
- // pretty alignment of the task descriptions
- if (task.description) {
- len = p.length + taskParams.length;
- maxTaskNameLength = len > maxTaskNameLength ?
- len : maxTaskNameLength;
- }
- }
- // Print out each entry with descriptions neatly aligned
- for (p in jake.Task) {
- if (!Object.prototype.hasOwnProperty.call(jake.Task, p)) {
- continue;
- }
- if (filter && p.indexOf(filter) == -1) {
- continue;
- }
- task = jake.Task[p];
- taskParams = "";
- if (task.params != "") {
- taskParams = "[" + task.params + "]";
- }
- //name = '\033[32m' + p + '\033[39m ';
- name = chalk.green(p);
- descr = task.description;
- if (descr) {
- descr = chalk.gray('# ' + descr);
- // Create padding-string with calculated length
- padding = (new Array(maxTaskNameLength - p.length - taskParams.length + 4)).join(' ');
- console.log('jake ' + name + taskParams + padding + descr);
- }
- }
- };
- this.createTask = function () {
- let args = Array.prototype.slice.call(arguments);
- let arg;
- let obj;
- let task;
- let type;
- let name;
- let action;
- let opts = {};
- let prereqs = [];
- type = args.shift();
- // name, [deps], [action]
- // Name (string) + deps (array) format
- if (typeof args[0] == 'string') {
- name = args.shift();
- if (Array.isArray(args[0])) {
- prereqs = args.shift();
- }
- }
- // name:deps, [action]
- // Legacy object-literal syntax, e.g.: {'name': ['depA', 'depB']}
- else {
- obj = args.shift();
- for (let p in obj) {
- prereqs = prereqs.concat(obj[p]);
- name = p;
- }
- }
- // Optional opts/callback or callback/opts
- while ((arg = args.shift())) {
- if (typeof arg == 'function') {
- action = arg;
- }
- else {
- opts = Object.assign(Object.create(null), arg);
- }
- }
- task = jake.currentNamespace.resolveTask(name);
- if (task && !action) {
- // Task already exists and no action, just update prereqs, and return it.
- task.prereqs = task.prereqs.concat(prereqs);
- return task;
- }
- switch (type) {
- case 'directory':
- action = function action() {
- jake.mkdirP(name);
- };
- task = new DirectoryTask(name, prereqs, action, opts);
- break;
- case 'file':
- task = new FileTask(name, prereqs, action, opts);
- break;
- default:
- task = new Task(name, prereqs, action, opts);
- }
- jake.currentNamespace.addTask(task);
- if (jake.currentTaskDescription) {
- task.description = jake.currentTaskDescription;
- jake.currentTaskDescription = null;
- }
- // FIXME: Should only need to add a new entry for the current
- // task-definition, not reparse the entire structure
- jake.parseAllTasks();
- return task;
- };
- this.attemptRule = function (name, ns, level) {
- let prereqRule;
- let prereq;
- if (level > MAX_RULE_RECURSION_LEVEL) {
- return null;
- }
- // Check Rule
- prereqRule = ns.matchRule(name);
- if (prereqRule) {
- prereq = prereqRule.createTask(name, level);
- }
- return prereq || null;
- };
- this.createPlaceholderFileTask = function (name, namespace) {
- let parsed = name.split(':');
- let filePath = parsed.pop(); // Strip any namespace
- let task;
- task = namespace.resolveTask(name);
- // If there's not already an existing dummy FileTask for it,
- // create one
- if (!task) {
- // Create a dummy FileTask only if file actually exists
- if (fs.existsSync(filePath)) {
- task = new jake.FileTask(filePath);
- task.dummy = true;
- let ns;
- if (parsed.length) {
- ns = namespace.resolveNamespace(parsed.join(':'));
- }
- else {
- ns = namespace;
- }
- if (!namespace) {
- throw new Error('Invalid namespace, cannot add FileTask');
- }
- ns.addTask(task);
- // Put this dummy Task in the global Tasks list so
- // modTime will be eval'd correctly
- jake.Task[`${ns.path}:${filePath}`] = task;
- }
- }
- return task || null;
- };
- this.run = function () {
- let args = Array.prototype.slice.call(arguments);
- let program = this.program;
- let loader = this.loader;
- let preempt;
- let opts;
- program.parseArgs(args);
- program.init();
- preempt = program.firstPreemptiveOption();
- if (preempt) {
- preempt();
- }
- else {
- opts = program.opts;
- // jakefile flag set but no jakefile yet
- if (opts.autocomplete && opts.jakefile === true) {
- process.stdout.write('no-complete');
- return;
- }
- // Load Jakefile and jakelibdir files
- let jakefileLoaded = loader.loadFile(opts.jakefile);
- let jakelibdirLoaded = loader.loadDirectory(opts.jakelibdir);
- if(!jakefileLoaded && !jakelibdirLoaded && !opts.autocomplete) {
- fail('No Jakefile. Specify a valid path with -f/--jakefile, ' +
- 'or place one in the current directory.');
- }
- program.run();
- }
- };
- })());
- }
- module.exports = jake;
|