Skip to content

Commit 73c63c3

Browse files
authored
Merge pull request #126 from adaptlearning/develop
Expose commands as an API
2 parents c59563b + 38ac6cf commit 73c63c3

9 files changed

Lines changed: 495 additions & 36 deletions

File tree

lib/Constants.js

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
var bower = require('bower'),
2-
fs = require('fs');
2+
fs = require('fs'),
3+
path = require('path');
34

45
module.exports = {
5-
DefaultProjectManifestPath : './adapt.json',
6-
DefaultProjectFrameworkPath: './package.json',
6+
ManifestFilename: 'adapt.json',
7+
FrameworkFilename: 'package.json',
8+
DefaultProjectManifestPath : './'+this.ManifestFilename,
9+
DefaultProjectFrameworkPath: './'+this.FrameworkFilename,
710
DefaultCreateType : 'course',
811
DefaultTypeNames : {
912
'course':'my-adapt-course',
@@ -15,7 +18,9 @@ module.exports = {
1518
ComponentRepositoryName : 'adapt-component',
1619
DefaultBranch : process.env.ADAPT_BRANCH || 'master',
1720
HomeDirectory : searchForHome(),
18-
getRegistry:getRegistry
21+
getRegistry:getRegistry,
22+
setCwd: setCwd,
23+
cwd: '.'
1924
};
2025

2126
var registry = null;
@@ -40,7 +45,7 @@ function getRegistry() {
4045
if (process.env.ADAPT_REGISTRY) {
4146
registry = process.env.ADAPT_REGISTRY;
4247

43-
} else if (fs.existsSync('./.bowerrc')) {
48+
} else if (fs.existsSync(path.join(this.cwd, './.bowerrc'))) {
4449
// a manifest exists; let bower determine the registry
4550
registry = undefined;
4651

@@ -51,3 +56,12 @@ function getRegistry() {
5156

5257
return registry;
5358
}
59+
60+
function setCwd(cwd) {
61+
if (!cwd) return;
62+
63+
this.cwd = cwd;
64+
65+
this.DefaultProjectManifestPath = path.join(this.cwd, this.ManifestFilename);
66+
this.DefaultProjectFrameworkPath = path.join(this.cwd, this.FrameworkFilename);
67+
}

lib/cli.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,26 @@ function execute() {
2727
});
2828
}
2929

30+
function getApi() {
31+
var commands = require('./commands');
32+
var apiCommands = {};
33+
34+
_.each(commands, function(command, commandName) {
35+
var prefix = 'api';
36+
if (commandName.startsWith(prefix)) {
37+
apiCommands[commandName.split(prefix)[1]] = command;
38+
}
39+
});
40+
41+
return {
42+
commands:apiCommands
43+
}
44+
}
45+
3046
module.exports = {
3147
command: null,
3248
withOptions: withOptions,
3349
withPackage: withPackage,
34-
execute: execute
50+
execute: execute,
51+
api: getApi()
3552
};

lib/commands/install.js

Lines changed: 147 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ var path = require('path');
99
var prompt = require('prompt')
1010
var Q = require('q');
1111
var semver = require('semver');
12+
var Errors = require('../errors');
1213
var Constants = require('../Constants');
1314
var JsonLoader = require('../JsonLoader');
14-
var JsonWriter = require('../JsonWriter');
1515
var PackageMeta = require('../PackageMeta');
1616
var Plugin = require('../Plugin');
1717
var Project = require('../Project');
@@ -38,8 +38,33 @@ module.exports = function (dependencies) {
3838
var isCompatibleEnabled = false;
3939
// whether adapt.json is being used to compile the list of plugins to install
4040
var isUsingManifest = false;
41+
// whether this command is being performed on the command line
42+
var isInteractive = true;
4143

4244
return {
45+
apiinstall: function(pluginName, cwd) {
46+
isInteractive = false;
47+
48+
Constants.setCwd(cwd);
49+
50+
project = new Project(Constants.DefaultProjectManifestPath, Constants.DefaultProjectFrameworkPath);
51+
52+
if(!project.isProjectContainsManifestFile()) {
53+
return Q.reject({error:Errors.ERROR_COURSE_DIR});
54+
}
55+
56+
itinerary = {};
57+
plugins = [];
58+
59+
return init(pluginName ? [pluginName] : [])
60+
.then(createPlugins)
61+
.then(getInitialInfo)
62+
.then(findCompatibleVersions)
63+
.then(checkConstraints)
64+
.then(createInstallationManifest)
65+
.then(performInstallation)
66+
.then(summariseInstallation);
67+
},
4368
install: function(renderer) {
4469
var args = [].slice.call(arguments, 1);
4570
var done = args.pop() || function() {};
@@ -145,7 +170,11 @@ module.exports = function (dependencies) {
145170
promises.push(plugins[i].getInitialInfo());
146171
}
147172

148-
return Q.all(promises).progress(progressUpdate).then(conclude);
173+
if (isInteractive) {
174+
return Q.all(promises).progress(progressUpdate).then(conclude);
175+
}
176+
177+
return Q.all(promises);
149178

150179
function progressUpdate() {
151180
var settled = plugins.filter(function(plugin) {return plugin._rawInfo || plugin._isMissingAtRepo;}).length;
@@ -169,7 +198,11 @@ module.exports = function (dependencies) {
169198
promises.push(present[i].findCompatibleVersion(project.getFrameworkVersion()));
170199
}
171200

172-
return Q.all(promises).progress(progressUpdate).then(conclude);
201+
if (isInteractive) {
202+
return Q.all(promises).progress(progressUpdate).then(conclude);
203+
}
204+
205+
return Q.all(promises);
173206

174207
function progressUpdate() {
175208
var settled = present.filter(function(plugin) {return plugin._latestCompatibleVersion != undefined;}).length;
@@ -193,7 +226,11 @@ module.exports = function (dependencies) {
193226
promises.push(present[i].checkConstraint(project.getFrameworkVersion()));
194227
}
195228

196-
return Q.all(promises).progress(progressUpdate).then(conclude);
229+
if (isInteractive) {
230+
return Q.all(promises).progress(progressUpdate).then(conclude);
231+
}
232+
233+
return Q.all(promises);
197234

198235
function progressUpdate() {
199236
var settled = present.filter(function(plugin) {return plugin._constraintChecked != undefined;}).length;
@@ -234,6 +271,37 @@ module.exports = function (dependencies) {
234271
// a compatible version exists but user has requested a valid version that is later than the latest compatible version (prompt for (r)equested, (l)atest compatible or (s)kip)
235272
var compatibleWithUnmetConstraint = present.filter(isCompatibleWithUnmetConstraint);
236273

274+
if (!isInteractive) {
275+
276+
incompatibleWithOldConstraint.forEach(function(p) {
277+
p._error = Errors.ERROR_INCOMPATIBLE_VALID_REQUEST;
278+
});
279+
incompatibleWithLatestConstraint.forEach(function(p) {
280+
p._error = Errors.ERROR_INCOMPATIBLE_VALID_REQUEST;
281+
});
282+
incompatibleWithBadConstraint.forEach(function(p) {
283+
p._error = Errors.ERROR_INCOMPATIBLE_BAD_REQUEST;
284+
});
285+
incompatibleWithNoConstraint.forEach(function(p) {
286+
p._error = Errors.ERROR_INCOMPATIBLE;
287+
});
288+
compatibleWithOldIncompatibleConstraint.forEach(function(p) {
289+
p._error = Errors.ERROR_COMPATIBLE_INC_REQUEST;
290+
});
291+
compatibleWithBadConstraint.forEach(function(p) {
292+
p._error = Errors.ERROR_COMPATIBLE_BAD_REQUEST;
293+
});
294+
compatibleWithUnmetConstraint.forEach(function(p) {
295+
p._error = Errors.ERROR_COMPATIBLE_INC_REQUEST;
296+
});
297+
298+
compatibleWithOldCompatibleConstraint.forEach(function(p) {
299+
p.markRequestedForInstallation();
300+
});
301+
302+
return Q.resolve();
303+
}
304+
237305
var allPromises = [];
238306

239307
add(incompatibleWithOldConstraint, 'There is no compatible version of the following plugins:', getPrompt_incompatibleGeneric);
@@ -270,6 +338,10 @@ module.exports = function (dependencies) {
270338
console.log(obj.header);
271339
return promise.serialise(obj.list, obj.prompt);
272340
}
341+
342+
function getPackageName(p) {
343+
return p.packageName;
344+
}
273345
}
274346

275347
function updateManifest() {
@@ -477,6 +549,69 @@ module.exports = function (dependencies) {
477549
var noSuccess = 'None of the requested plugins could be installed';
478550
var successMsg;
479551

552+
if (!isInteractive) {
553+
var report = [];
554+
555+
if (plugins.length == 1) {
556+
var p = plugins[0];
557+
558+
if (installSucceeded.length == 1) {
559+
var bowerPath = path.join(Constants.cwd, 'src', p._belongsTo, p.packageName, 'bower.json');
560+
return Q.resolve(JsonLoader.readJSONSync(bowerPath));
561+
}
562+
if (installSkipped.length == 1) {
563+
return Q.reject(p._error);
564+
}
565+
if (installErrored.length == 1) {
566+
var error = _.clone(Errors.ERROR_INSTALL_ERROR);
567+
568+
if (p._installError) error.message = p._installError;
569+
570+
return Q.reject(error);
571+
}
572+
return Q.reject(Errors.ERROR_NOT_FOUND);
573+
}
574+
575+
installSucceeded.forEach(function(p) {
576+
var bowerPath = path.join(Constants.cwd, 'src', p._belongsTo, p.packageName, 'bower.json');
577+
report.push({
578+
name:p.packageName,
579+
status:'fulfilled',
580+
pluginData:JsonLoader.readJSONSync(bowerPath)
581+
});
582+
});
583+
584+
installSkipped.forEach(function(p) {
585+
report.push({
586+
name:p.packageName,
587+
status:'rejected',
588+
reason:p._error
589+
});
590+
});
591+
592+
installErrored.forEach(function(p) {
593+
var error = _.clone(Errors.ERROR_INSTALL_ERROR);
594+
595+
if (p._installError) error.message = p._installError;
596+
597+
report.push({
598+
name:p.packageName,
599+
status:'rejected',
600+
reason:error
601+
});
602+
});
603+
604+
missing.forEach(function(p) {
605+
report.push({
606+
name:p.packageName,
607+
status:'rejected',
608+
reason:Errors.ERROR_NOT_FOUND
609+
});
610+
});
611+
612+
return Q.resolve(report);
613+
}
614+
480615
if (installErrored.length == 0 && missing.length == 0) successMsg = allSuccess;
481616
else if (installSucceeded.length == 0) successMsg = noSuccess;
482617
else successMsg = someSuccess;
@@ -676,7 +811,11 @@ module.exports = function (dependencies) {
676811
}
677812

678813
function performInstallation() {
679-
return Q.all(plugins.filter(isToBeInstalled).map(createInstallationTask)).progress(progressUpdate).then(conclude);
814+
if (isInteractive) {
815+
return Q.all(plugins.filter(isToBeInstalled).map(createInstallationTask)).progress(progressUpdate).then(conclude);
816+
}
817+
818+
return Q.all(plugins.filter(isToBeInstalled).map(createInstallationTask));
680819

681820
function progressUpdate() {
682821
var list = plugins.filter(isPresent).filter(isToBeInstalled);
@@ -692,7 +831,7 @@ module.exports = function (dependencies) {
692831
}
693832

694833
function createInstallationTask(plugin) {
695-
return PackageMeta.getKeywords(plugin, { registry: Constants.getRegistry() }).then(doInstall).then(conclude);
834+
return PackageMeta.getKeywords(plugin, { registry: Constants.getRegistry(), cwd: Constants.cwd }).then(doInstall).then(conclude);
696835

697836
function doInstall(keywords) {
698837
var resolver = new PluginTypeResolver(),
@@ -703,7 +842,8 @@ module.exports = function (dependencies) {
703842

704843
return install(plugin, {
705844
directory: path.join('src', pluginType.belongsTo),
706-
registry: Constants.getRegistry()
845+
registry: Constants.getRegistry(),
846+
cwd: Constants.cwd
707847
});
708848
}
709849

lib/commands/install/InstallTarget.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ var InstallTarget = extend(Plugin, {
8787
try {
8888
var versionString = this._versions ? '#'+this._versions[this._versionIndex] : '';
8989
this._bowerCmdCount++;
90-
bower.commands.info(this.packageName+versionString, null, {registry:Constants.getRegistry()}).on('end', _.bind(onSuccess, this)).on('error', _.bind(onFail, this));
90+
bower.commands.info(this.packageName+versionString, null, {registry:Constants.getRegistry(), cwd: Constants.cwd}).on('end', _.bind(onSuccess, this)).on('error', _.bind(onFail, this));
9191
} catch(err) {
9292
onFail.call(this, err);
9393
}

0 commit comments

Comments
 (0)