1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 | var readJSON = require('./common').readJSON;
|
17 | var PackageName = require('./package-name');
|
18 | var asp = require('bluebird').Promise.promisify;
|
19 | var path = require('path');
|
20 | var ui = require('./ui');
|
21 | var rimraf = require('rimraf');
|
22 | var mkdirp = require('mkdirp');
|
23 | var fs = require('graceful-fs');
|
24 | var install = require('./install');
|
25 | var config = require('./config');
|
26 | var Promise = require('bluebird');
|
27 | var registry = require('./registry');
|
28 |
|
29 | exports.link = function(dir, name, options) {
|
30 | var alias;
|
31 | if (dir.indexOf('=') != -1) {
|
32 | alias = dir.split('=')[0];
|
33 | dir = dir.split('=').splice(1).join('=');
|
34 | }
|
35 |
|
36 | var pkg = new PackageName(name || '');
|
37 | var pjson;
|
38 |
|
39 | dir = path.resolve(dir);
|
40 |
|
41 |
|
42 | return Promise.resolve()
|
43 | .then(function() {
|
44 | return new Promise(function(resolve) {
|
45 | fs.exists(dir, resolve);
|
46 | });
|
47 | })
|
48 | .then(function(exists) {
|
49 | if (!exists)
|
50 | throw 'Link target directory %' + dir + '% doesn\'t exist.';
|
51 |
|
52 | return config.load();
|
53 | })
|
54 | .then(function() {
|
55 | return readJSON(path.resolve(dir, 'package.json'))
|
56 | .then(function(_pjson) {
|
57 | pjson = _pjson;
|
58 |
|
59 |
|
60 | if (pjson.jspm) {
|
61 | if ('dependencies' in pjson.jspm || 'devDependencies' in pjson.jspm || 'peerDependencies' in pjson.jspm) {
|
62 | delete pjson.dependencies;
|
63 | delete pjson.devDependencies;
|
64 | delete pjson.peerDependencies;
|
65 | }
|
66 | for (var p in pjson.jspm)
|
67 | pjson[p] = pjson.jspm[p];
|
68 | }
|
69 | });
|
70 | })
|
71 |
|
72 |
|
73 | .then(function() {
|
74 | if (!pkg.registry)
|
75 | pkg.setRegistry(pjson.registry != 'jspm' && pjson.registry || 'local');
|
76 |
|
77 |
|
78 | if (!pkg.package)
|
79 | pkg.setPackage(pjson.name || dir.split(path.sep).pop());
|
80 |
|
81 |
|
82 | var pkgNameFormats = registry.load(pkg.registry).constructor.packageNameFormats || ['*'];
|
83 | if (!pkgNameFormats.some(function(format) {
|
84 | var formatRegEx = new RegExp('^' + format.replace(/\*/g, '[^\/]+') + '$');
|
85 | return pkg.package.match(formatRegEx);
|
86 | }))
|
87 | throw 'Error linking `' + pkg.name + '`. The %' + pkg.registry + '% registry doesn\'t support package names of this form. Make sure to enter a valid package name as the second argument to %jspm link% or set the package.json %name% field of the package being linked.';
|
88 |
|
89 | if (pkg.version)
|
90 | return;
|
91 |
|
92 | if (pjson.version) {
|
93 | pkg.setVersion(pjson.version);
|
94 | return;
|
95 | }
|
96 |
|
97 |
|
98 | return asp(fs.readFile)(path.resolve(dir, '.git', 'HEAD'))
|
99 | .then(function(headSource) {
|
100 | headSource = headSource.toString();
|
101 | if (headSource.substr(0, 16) == 'ref: refs/heads/')
|
102 | pkg.setVersion(headSource.substr(16).replace(/\s*$/, ''));
|
103 | else
|
104 | pkg.setVersion('master');
|
105 | }, function() {
|
106 | pkg.setVersion('master');
|
107 | });
|
108 | })
|
109 |
|
110 | .then(function() {
|
111 | var libDir = pjson.directories && (pjson.directories.dist || pjson.directories.lib);
|
112 | if (libDir)
|
113 | libDir = path.resolve(dir, libDir);
|
114 |
|
115 | if (!libDir || libDir == dir)
|
116 | return;
|
117 |
|
118 |
|
119 |
|
120 |
|
121 | return new Promise(function(resolve) {
|
122 | fs.exists(path.resolve(libDir, 'package.json'), resolve);
|
123 | })
|
124 | .then(function(hasPackageJson) {
|
125 | if (hasPackageJson)
|
126 | return;
|
127 |
|
128 | return ui.confirm('Create a package.json symlink in the ' + path.relative(dir, libDir) + ' folder?', true, {
|
129 | info: 'In order to link the folder %' + path.relative(dir, libDir) + '%, ' +
|
130 | 'a symlink of the package.json needs to be created in this folder of the package so jspm can read the package configuration.'
|
131 | })
|
132 | .then(function(confirm) {
|
133 | if (!confirm)
|
134 | throw 'Linking process aborted.';
|
135 |
|
136 | return asp(fs.symlink)(path.join(dir, 'package.json'), path.resolve(libDir, 'package.json'), 'file');
|
137 | });
|
138 | })
|
139 | .then(function() {
|
140 | dir = libDir;
|
141 | });
|
142 | })
|
143 | .then(function() {
|
144 |
|
145 | var linkPath = pkg.getPath();
|
146 |
|
147 | return asp(fs.readlink)(pkg.getPath())
|
148 | .then(function(linkString) {
|
149 | if (path.resolve(path.dirname(linkPath), linkString) === dir)
|
150 | return asp(fs.unlink)(linkPath);
|
151 |
|
152 | return Promise.resolve(ui.confirm('Relink?', true, {
|
153 | info: '`' + pkg.exactName + '` is already linked, are you sure you want to link over it?'
|
154 | }))
|
155 | .then(function(remove) {
|
156 | if (!remove)
|
157 | throw 'Aborted.';
|
158 | return asp(fs.unlink)(linkPath);
|
159 | });
|
160 | }, function(err) {
|
161 | if (err.code === 'ENOENT')
|
162 | return;
|
163 | if (err.code !== 'EINVAL' && err.code !== 'UNKNOWN')
|
164 | throw err;
|
165 |
|
166 | return Promise.resolve(ui.confirm('Replace installed version?', true, {
|
167 | info: '`' + pkg.exactName + '` is already installed, are you sure you want to link over it?'
|
168 | }))
|
169 | .then(function(remove) {
|
170 | if (!remove)
|
171 | throw 'Aborted.';
|
172 | return asp(rimraf)(linkPath);
|
173 | });
|
174 | })
|
175 | .then(function() {
|
176 | return asp(mkdirp)(path.dirname(linkPath));
|
177 | })
|
178 | .then(function() {
|
179 | return asp(fs.symlink)(path.relative(path.dirname(linkPath), dir), linkPath, 'junction');
|
180 | });
|
181 | })
|
182 |
|
183 |
|
184 | .then(function() {
|
185 |
|
186 | if (!alias)
|
187 | Object.keys(config.loader.baseMap).forEach(function(dep) {
|
188 | if (config.loader.baseMap[dep].exactName == pkg.exactName)
|
189 | alias = dep;
|
190 | });
|
191 |
|
192 | var installName = alias || pkg.package.split('/').pop();
|
193 | config.loader.baseMap[installName] = pkg;
|
194 |
|
195 | return install.install(installName, pkg.exactName, { quick: options.quick, force: options.force, dev: options.dev, peer: options.peer });
|
196 | })
|
197 | .then(function(aborted) {
|
198 | if (!aborted)
|
199 | ui.log('info',
|
200 | '\nRun this link command again or %jspm install ' + pkg.exactName + '% to relink changes in the package.json file.\n' +
|
201 | 'Run %jspm install --unlink% to unlink and install all original packages. Linked packages can also be uninstalled normally.');
|
202 | else
|
203 | ui.log('info', 'Link operation aborted.');
|
204 | }, function(err) {
|
205 | ui.log('err', err.stack || err);
|
206 | });
|
207 | };
|
208 |
|