UNPKG

4.43 kBJavaScriptView Raw
1/**
2 * Module dependencies.
3 */
4
5var component = require('component')
6 , fs = require('fs')
7 , exists = fs.existsSync
8 , utils = component.utils
9 , log = utils.log
10 , error = utils.error
11 , url = require('url')
12 , path = require('path')
13 , resolve = path.resolve
14 , async = require('async');
15
16// parse argv
17
18module.exports = function (config, opts, callback){
19
20 // pkgs
21
22 var pkgs = opts.args;
23
24 // install from ./component.json
25
26 var local = 0 == pkgs.length;
27
28 // component.json required
29
30 if (local && !config) utils.fatal('missing config');
31
32 // read json
33
34 var conf = config;
35
36 // install from ./component.json
37
38 if (local) {
39 if (conf.dependencies) {
40 pkgs = normalize(conf.dependencies);
41 }
42
43 if (conf.development && opts.dev) {
44 pkgs = pkgs.concat(normalize(conf.development));
45 }
46
47 if (conf.local) {
48 conf.local.forEach(function(pkg){
49 try {
50 var deps = component.dependenciesOf(pkg, conf.paths);
51 deps.map(normalize).forEach(function(deps){
52 pkgs = pkgs.concat(deps);
53 });
54 } catch (err) {
55 utils.fatal(err.message);
56 }
57 });
58 }
59 }
60
61 // save to ./component.json
62 var deps = null;
63
64 if (!local) {
65 deps = conf.dependencies;
66 var key = opts.dev ? 'development' : 'dependencies';
67
68 conf[key] = conf[key] || {};
69 pkgs.forEach(function(pkg){
70 pkg = parsePackage(pkg);
71 conf[key][pkg.name] = pkg.version || '*';
72 deps[pkg.name] = pkg.version || '*';
73 });
74
75 if (exists('component.json')) saveConfig();
76 }
77
78 // implicit remotes
79
80 conf.remotes = conf.remotes || [];
81
82 // explicit remotes
83
84 if (opts.remotes) {
85 conf.remotes = opts.remotes.split(',').concat(conf.remotes);
86 }
87
88 // default to github
89
90 conf.remotes.push('https://raw.github.com');
91
92 // install
93
94 async.each(pkgs, function(pkg, callback){
95 pkg = parsePackage(pkg);
96 install(pkg.name, pkg.version || 'master', callback);
97 }, installDone);
98
99 function installDone(err){
100 if(err) return console.log(err);
101 log('install',"DONE");
102 callback(null, deps);
103 }
104
105 // parse package identifier
106
107 function parsePackage(pkg) {
108 var parts = pkg.split('@');
109 return {
110 name: parts.shift(),
111 version: parts.shift()
112 };
113 }
114
115 // map deps to args
116
117 function normalize(deps) {
118 return Object.keys(deps).map(function(name){
119 return name + '@' + deps[name];
120 });
121 }
122
123 // reporter
124
125 function report(pkg, options) {
126 options = options || {};
127 if (pkg.inFlight) return;
128 log('install', pkg.name + '@' + pkg.version);
129
130 pkg.on('error', function(err){
131 if (err.fatal) {
132 error(err.message);
133 process.exit(1);
134 }
135
136 error(err.message);
137 });
138
139 if (opts.verbose) {
140 pkg.on('dep', function(dep){
141 log('dep', dep.name + '@' + dep.version);
142 report(dep, options);
143 });
144
145 pkg.on('exists', function(dep){
146 log('exists', dep.name + '@' + dep.version);
147 });
148
149 pkg.on('file', function(file){
150 log('fetch', pkg.name + ':' + file);
151 });
152 }
153
154 pkg.on('end', function(){
155 log('complete', pkg.name);
156 });
157 }
158
159 // padding
160
161 process.on('exit', function(){
162 //console.log("EXIT");
163 });
164
165 /**
166 * Install package `name` at the given `version`
167 * from all specified remotes.
168 *
169 * @param {String} name
170 * @param {String} version
171 * @api private
172 */
173
174 function install(name, version, callback) {
175 touch(opts.out);
176
177 // kick off installation
178 var pkg = component.install(name, version, {
179 dest: opts.out,
180 force: opts.force,
181 dev: opts.dev,
182 remotes: conf.remotes
183 });
184 pkg.force = opts.force;
185 report(pkg);
186 //comment it for a while https://github.com/component/component/pull/414
187 pkg.on('end', function(){
188 setTimeout(callback, 200);
189 });
190
191 pkg.on('exists', function(){
192 setTimeout(callback, 200);
193 })
194
195 // TODO: add callback
196 pkg.install();
197 }
198
199 /**
200 * Touch `path` when present.
201 *
202 * @param {String} path
203 * @api private
204 */
205
206 function touch(path) {
207 try {
208 fs.utimesSync(path, new Date, new Date);
209 } catch (err) {
210 // ignore
211 }
212 }
213
214 /**
215 * Save configuration.
216 *
217 * @api private
218 */
219
220 function saveConfig() {
221 var path = resolve('component.json');
222 fs.writeFileSync(path, JSON.stringify(conf, null, 2));
223 }
224
225}