UNPKG

4.81 kBJavaScriptView Raw
1var path = require('path');
2var _ = require('underscore');
3var Source = require('./sources/source');
4var Command = require('./command');
5var fs = require('fs');
6var fstream = require('fstream');
7var wrench = require('wrench');
8var spawn = require('child_process').spawn;
9var exec = require('child_process').exec;
10
11
12// A 'Meteor' refers to a single commit (branch, tag) of a version of the core meteor
13//
14// They are located on disk in ~/.meteorite/meteors.
15// When you install a meteor into a project, it copies everything into
16// ./.meteor/meteorite to create a 'custom' version of meteor for you to install packages into.
17Meteor = function(config) {
18 // Config defaults
19 config = config || {};
20 this.defaultMeteor = (! _.include(_.keys(config), 'git'));
21
22 if (this.defaultMeteor) {
23 this.prepared = true
24 } else {
25 config.git = config.git || 'https://github.com/meteor/meteor.git';
26 config.keepGitDir = true;
27
28 // Prepare source
29 var root = Meteor.installRoot();
30
31 this.source = Source.prepare(root, config);
32
33 // TODO -- this is a bit coarse. but it avoids multiple installs for now
34 this.prepared = fs.existsSync(this.source.path);
35 }
36};
37
38// download the repo + install dev_bundle
39Meteor.prototype.prepare = function(buildDevBundle, fn) {
40 var self = this;
41
42 if (_.isFunction(buildDevBundle))
43 fn = buildDevBundle;
44
45 // no need to do anything
46 if (self.defaultMeteor)
47 return fn();
48
49 self.source.fetch(function() {
50 self.install(buildDevBundle, fn);
51 }, 'Meteor');
52};
53
54Meteor.prototype.install = function(buildDevBundle, fn) {
55 var self = this;
56
57 if (_.isFunction(buildDevBundle))
58 fn = buildDevBundle;
59
60 self.prepared = true;
61
62 // ensure the dev_bundle is installed.
63 var dev_bundle = path.join(self.source.path, 'dev_bundle');
64
65 if (!fs.existsSync(dev_bundle)) {
66
67 if (buildDevBundle) {
68 console.log('Building Meteor development bundle');
69 var generate = spawn('./scripts/generate-dev-bundle.sh', [], {cwd: self.source.path});
70
71 generate.stdout.pipe(process.stdout);
72 generate.stderr.pipe(process.stderr);
73 generate.on('exit', fn);
74
75 } else {
76 // meteor --help installs the dev bundle before doing anything else
77 console.log('Downloading Meteor development bundle');
78 var meteor = spawn('./meteor', ['--help'], {cwd: self.source.path});
79
80 // just output the status bar
81 meteor.stderr.pipe(process.stderr);
82 meteor.on('exit', fn);
83 }
84 } else {
85 fn();
86 }
87};
88
89// check that the above has happened
90Meteor.prototype.ensurePrepared = function(fn) {
91 if (this.prepared) {
92 fn();
93 } else {
94 this.prepare(fn);
95 }
96};
97
98Meteor.prototype._executable = function() {
99 var self = this;
100
101 if (self.defaultMeteor) {
102 return 'meteor';
103 } else {
104 return path.join(self.source.packagePath(), 'meteor');
105 }
106}
107
108// run a command using just this checked-out version of meteor
109Meteor.prototype.execute = function(args, package_dir, fn) {
110 var self = this;
111
112 if (_.isFunction(package_dir)) {
113 fn = package_dir;
114 package_dir = null;
115 }
116
117 self.ensurePrepared(function() {
118 Command.spawn(self._executable(), args, package_dir, fn);
119 });
120};
121
122Meteor.prototype.isUsing = function(packageName, fn) {
123 var self = this;
124
125 Command.exec(self._executable(), ['list', '--using'], function(error, packages) {
126 var packageNames = packages.split('\n');
127
128 var regExp = new RegExp('^\w*' + packageName + '\w*$');
129 fn(_.any(packageNames, function(pn) { return regExp.exec(pn); }));
130 });
131}
132
133Meteor.prototype.hasPackage = function(pkgName, fn) {
134 var self = this;
135
136 if (self.defaultMeteor) {
137 var checker = function(names) {
138 fn(_.any(names, function(n) { return n === pkgName}))
139 }
140
141 if (!self.packageNames) {
142 // we have to call meteor list because there's no obvious place to look
143 exec('meteor list', function(error, list) {
144 var lines = list.split('\n');
145
146 self.packageNames = _.map(lines, function(l) {
147 return l.split(' ')[0]
148 }).filter(function(n) { return n !== ''; });
149
150 checker(self.packageNames);
151 });
152 } else {
153 checker(self.packageNames);
154 }
155 } else {
156 self.prepare(function() {
157 fn(fs.existsSync(path.join(self.source.path, 'packages', pkgName)));
158 });
159 }
160}
161
162Meteor.prototype.toJson = function(lock) {
163 if (this.defaultMeteor) {
164 return {};
165 } else {
166 return this.source.toJson(lock);
167 }
168};
169
170Meteor.prototype.equals = function(otherMeteor) {
171 if (this.defaultMeteor)
172 return otherMeteor.defaultMeteor;
173
174 return !otherMeteor.defaultMeteor && this.source.equals(otherMeteor.source);
175};
176
177Meteor.installRoot = function() {
178 return path.join(Meteorite.root(), 'meteors');
179};
180
181module.exports = Meteor;