UNPKG

8.14 kBJavaScriptView Raw
1#!/usr/bin/env node
2
3var util = require('util');
4var path = require('path');
5var events = require('events');
6var fs = require('fs');
7var colors = require('./lib/colors')
8var quote = require('shell-quote').quote;
9
10var program = require('commander');
11var display = require('./lib/console').Console
12
13var nf = require('./package.json');
14
15program.version(nf.version);
16program.option('-j, --procfile <FILE>' ,'load procfile FILE','Procfile');
17program.option('-e, --env <FILE>' ,'use FILE to load environment','.env');
18program.option('-p, --port <PORT>' ,'start indexing ports at number PORT',0);
19
20var command;
21
22// Foreman Event Bus/Emitter //
23
24var emitter = new events.EventEmitter();
25emitter.once('killall',function(signal){
26 display.Done("Killing all processes with signal ", signal);
27})
28emitter.setMaxListeners(50);
29
30var _proc = require('./lib/proc')
31var start = _proc.start
32var once = _proc.once
33
34var _procfile = require('./lib/procfile')
35var procs = _procfile.procs
36var loadProc = _procfile.loadProc
37
38var _envs = require('./lib/envs')
39var loadEnvs = _envs.loadEnvs
40
41var _requirements = require('./lib/requirements')
42var getreqs = _requirements.getreqs
43var calculatePadding = _requirements.calculatePadding
44
45var startProxies = require('./lib/proxy').startProxies
46var startForward = require('./lib/forward').startForward
47
48// Kill All Child Processes on SIGINT
49process.once('SIGINT',function userkill(){
50 console.log();
51 display.Warn('Interrupted by User');
52 emitter.emit('killall', 'SIGINT');
53});
54
55program
56.command('start')
57.usage('[Options] [Processes] e.g. web=1,log=2,api')
58.option('-s, --showenvs' ,'show ENV variables on start',false)
59.option('-x, --proxy <PORT>' ,'start a load balancing proxy on PORT')
60.option('-f, --forward <PORT>' ,'start a forward proxy on PORT')
61.option('-i, --intercept <HOSTNAME>' ,'set forward proxy to intercept HOSTNAME',null)
62.option('-t, --trim <N>' ,'trim logs to N characters',0)
63.option('-w, --wrap' ,'wrap logs (negates trim)')
64.description('Start the jobs in the Procfile')
65.action(function(command_left,command_right){
66
67 command = command_right || command_left;
68
69 var envs = loadEnvs(program.env);
70
71 var proc = loadProc(program.procfile);
72
73 if(!proc) return;
74
75 if(command.showenvs){
76 for(key in envs){
77 display.Alert("env %s=%s",key,envs[key]);
78 }
79 }
80
81 var reqs = getreqs(program.args[0],proc);
82
83 display.padding = calculatePadding(reqs);
84
85 if(command.wrap){
86 display.wrapline = process.stdout.columns - display.padding - 7
87 display.trimline = 0
88 display.Alert('Wrapping display Output to %d Columns',display.wrapline)
89 }else{
90 display.trimline = command.trim || process.stdout.columns - display.padding - 5
91 if(display.trimline>0){
92 display.Alert('Trimming display Output to %d Columns',display.trimline)
93 }
94 }
95
96 if(command.forward) startForward(command.forward,command.intercept,emitter)
97
98 startProxies(reqs,proc,command,emitter,program.port || envs.PORT || process.env.PORT || 5000);
99
100 if(process.getuid && process.getuid()==0) process.setuid(process.env.SUDO_USER);
101
102 start(proc,reqs,envs,program.port || envs.PORT || process.env.PORT || 5000,emitter);
103});
104
105program
106.command('run')
107.usage('[Options]')
108.option('-s, --showenvs' ,'show ENV variables on start',false)
109.description('Run a one off process using the ENV variables')
110.action(function(command_left,command_right){
111
112 command = command_right || command_left;
113
114 var envs = loadEnvs(program.env);
115 var arguments = Array.prototype.slice.apply(this.args);
116 arguments.pop();
117
118 var callback = function(code) {
119 process.exit(code);
120 }
121
122 if(!command) return;
123
124 var input = quote(arguments);
125
126 if(command.showenvs){
127 for(key in envs){
128 display.Alert("env %s=%s",key,envs[key]);
129 }
130 }
131
132 display.trimline = process.stdout.columns - 5;
133
134 once(input,envs,callback);
135});
136
137var exporters = require('./lib/exporters')
138
139program
140.command('export')
141.option('-a, --app <NAME>' ,'export upstart application as NAME','foreman')
142.option('-u, --user <NAME>' ,'export upstart user as NAME','root')
143.option('-o, --out <DIR>' ,'export upstart files to DIR','.')
144.option('-c, --cwd <DIR>' ,'change current working directory to DIR')
145.option('-g, --gid <GID>' ,'set gid of upstart config to GID')
146.option('-l, --log <DIR>' ,'specify upstart log directory','/var/log')
147.option('-t, --type <TYPE>' ,'export file to TYPE (default upstart)','upstart')
148.option('-m, --template <DIR>' ,'use template folder')
149.description('Export to an upstart job independent of foreman')
150.action(function(command_left,command_right){
151
152 command = command_right || command_left;
153
154 var envs = loadEnvs(program.env);
155
156 var procs = loadProc(program.procfile);
157
158 if(!procs) return;
159
160 var req = getreqs(program.args[0],procs);
161
162 // Variables for Upstart Template
163 var config = {
164 application : command.app,
165 cwd : path.resolve(process.cwd(), command.cwd || ''),
166 user : command.user,
167 logs : command.log,
168 envs : envs,
169 group : command.gid || command.user,
170 template : command.template
171 };
172
173 config.envfile = path.resolve(program.env)
174
175 var writeout
176 if(exporters[command.type]){
177 writeout = exporters[command.type]
178 }else{
179 display.Error("Unknown Export Format",command.type)
180 process.exit(1);
181 }
182
183 // Check for Upstart User
184 // friendly warning - does not stop export
185 var user_exists = false;
186 fs.readFileSync('/etc/passwd')
187 .toString().split(/\n/).forEach(function(line){
188 if(line.match(/^[^:]*/)[0] == config.user){
189 user_exists = true;
190 }
191 })
192 if(!user_exists) display.Warn(display.fmt("User %s Does Not Exist on System",config.user));
193
194 var baseport = parseInt(program.port || envs.PORT || process.env.PORT || 5000);
195 var baseport_i = 0;
196 var baseport_j = 0;
197
198 config.processes=[]
199
200 // This is ugly because of shitty support for array copying
201 // Cleanup is definitely required
202 for(key in req){
203
204 var c = {};
205 var cmd = procs[key];
206
207 if (!cmd){
208 display.Warn("Required Key '%s' Does Not Exist in Procfile Definition",key);
209 continue;
210 }
211
212 var n = req[key];
213
214 config.processes.push({process:key, n: n})
215 c.process=key;
216 c.command=cmd;
217
218 for(_ in config){
219 c[_] = config[_];
220 }
221
222 c.numbers = [];
223 for(var i=1;i<=n;i++){
224
225 var conf = {};
226 conf.number = i;
227
228 for(_ in c){
229 conf[_] = c[_];
230 }
231
232 conf.port = baseport + baseport_i + baseport_j*100;
233
234
235 var envl = [];
236 for(key in envs){
237 envl.push({
238 key: key,
239 value: envs[key]
240 })
241 }
242 envl.push({ key: 'PORT', value: conf.port });
243 envl.push({ key: 'FOREMAN_WORKER_NAME', value: conf.process+'.'+conf.number });
244
245 conf.envs = envl;
246
247 // Write the APP-PROCESS-N.conf File
248 writeout.foreman_app_n(conf,command.out);
249
250 baseport_i++;
251 c.numbers.push({number:i})
252 }
253
254 var envl = [];
255 for(key in envs){
256 envl.push({
257 key: key,
258 value: envs[key]
259 })
260 }
261
262 c.envs = envl;
263
264 // Write the APP-Process.conf File
265 writeout.foreman_app(c,command.out);
266
267 baseport_i=0;
268 baseport_j++;
269 }
270
271 // Write the APP.conf File
272 writeout.foreman(config,command.out);
273
274});
275
276program.parse(process.argv);
277
278if(program.args.length==0) {
279 console.log(colors.cyan(' _____ '))
280 console.log(colors.cyan(' | __|___ ___ ___ _____ ___ ___ '))
281 console.log(colors.yellow(' | __| . | _| -_| | | |'))
282 console.log(colors.magenta(' |__| |___|_| |___|_|_|_|_^_|_|_|'))
283 program.outputHelp();
284 process.exit(1);
285}