-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathauto-install-npm.js
134 lines (121 loc) · 4.01 KB
/
auto-install-npm.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import path from 'path';
import fs from 'fs';
import semver from 'semver';
import {_} from 'meteor/underscore';
import {exec} from 'child_process';
const execSync = Meteor.wrapAsync((...params) => {
const cb = params.pop();
exec(...params, (error, stdout, stderr) => {
stdout && console.log(stdout.toString());
stderr && console.error(stderr.toString());
cb(error);
});
});
const projectRoot = (cwd => {
if (process.env.NODE_ENV !== 'development') {
return;
}
const indexMeteor = cwd.indexOf('/.meteor/');
if (indexMeteor === -1) {
return;
}
const p = cwd.substring(0, indexMeteor);
if (!p) {
return;
}
return path.join(p, 'package.json');
})(process.cwd());
// Returns:
// - true if a version of the package in the range is installed
// - false if no version is installed
// - version# if incompatible version is installed
function compatibleVersionIsInstalled (name, range) {
try {
const installedVersion = require(`${name}/package.json`).version;
if (semver.satisfies(installedVersion, range)) {
return true;
} else {
return installedVersion;
}
} catch (e) {
// XXX add something to the tool to make this more reliable
const message = e.toString();
// One message comes out of the install npm package the other from npm directly
if (message.match('Cannot find module') || message.match('Can\'t find npm module')) {
return false;
} else {
throw e;
}
}
}
export default function autoInstallNpm (packages, packageName) {
const failures = {};
_.forEach(packages, (range, name) => {
const failure = compatibleVersionIsInstalled(name, range);
if (failure !== true) {
failures[name] = failure;
}
});
if (_.keys(failures).length === 0) {
return true;
}
const errors = [];
const npmPackages = {};
_.forEach(failures, (installed, name) => {
const requirement = `${name}@${packages[name]}`;
if (installed) {
errors.push(` - ${name}@${installed} installed, ${requirement} needed`);
} else {
npmPackages[name] = packages[name];
}
});
if (Object.keys(npmPackages).length) {
if (!addDependencyToPackageJson(npmPackages)) {
var arr = Object.keys(npmPackages);
if (arr && arr.length > 1) {
errors.push(` - some of ${arr.join()} are not installed or with problems.`);
} else {
errors.push(` - ${arr.join(', ')} is not installed correctly or at all.`);
}
}
}
if (errors && errors.length) {
const qualifier = packageName ? `(for ${packageName}) ` : '';
console.warn(`WARNING: npm peer requirements ${qualifier}not installed:\n${errors.join('\n')}`);
}
}
function getPackageJson () {
if (!projectRoot) {
return;
}
let packageJson;
try {
packageJson = Npm.require(projectRoot);
} catch (e) {
console.warn(e.message);
}
return packageJson;
}
function addDependencyToPackageJson (deps) {
if (!projectRoot || typeof deps !== 'object') {
return;
}
const packageDef = getPackageJson();
if (packageDef && packageDef.name) {
if (!packageDef.dependencies) {
packageDef.dependencies = {};
}
Object.keys(deps).forEach(name => packageDef.dependencies[name] = deps[name]);
try {
console.log('Refreshing dependencies in ' + projectRoot);
fs.writeFileSync(projectRoot, JSON.stringify(packageDef, undefined, 4));
console.log('New dependencies: ' +
Object.keys(deps).map(k=> k + '@' + deps[k]).join(', '));
console.log('running: meteor npm install');
execSync('meteor npm install', {cwd: path.dirname(projectRoot)});
return packageDef;
} catch (e) {
console.error(e);
}
}
}