1 | #!/usr/bin/env node
|
2 |
|
3 | var util = require('util');
|
4 | var path = require('path');
|
5 | var events = require('events');
|
6 | var fs = require('fs');
|
7 | var colors = require('./lib/colors')
|
8 | var quote = require('shell-quote').quote;
|
9 |
|
10 | var program = require('commander');
|
11 | var display = require('./lib/console').Console
|
12 |
|
13 | var nf = require('./package.json');
|
14 |
|
15 | program.version(nf.version);
|
16 | program.option('-j, --procfile <FILE>' ,'load procfile FILE','Procfile');
|
17 | program.option('-e, --env <FILE>' ,'use FILE to load environment','.env');
|
18 | program.option('-p, --port <PORT>' ,'start indexing ports at number PORT',0);
|
19 |
|
20 | var command;
|
21 |
|
22 |
|
23 |
|
24 | var emitter = new events.EventEmitter();
|
25 | emitter.once('killall',function(signal){
|
26 | display.Done("Killing all processes with signal ", signal);
|
27 | })
|
28 | emitter.setMaxListeners(50);
|
29 |
|
30 | var _proc = require('./lib/proc')
|
31 | var start = _proc.start
|
32 | var once = _proc.once
|
33 |
|
34 | var _procfile = require('./lib/procfile')
|
35 | var procs = _procfile.procs
|
36 | var loadProc = _procfile.loadProc
|
37 |
|
38 | var _envs = require('./lib/envs')
|
39 | var loadEnvs = _envs.loadEnvs
|
40 |
|
41 | var _requirements = require('./lib/requirements')
|
42 | var getreqs = _requirements.getreqs
|
43 | var calculatePadding = _requirements.calculatePadding
|
44 |
|
45 | var startProxies = require('./lib/proxy').startProxies
|
46 | var startForward = require('./lib/forward').startForward
|
47 |
|
48 |
|
49 | process.once('SIGINT',function userkill(){
|
50 | console.log();
|
51 | display.Warn('Interrupted by User');
|
52 | emitter.emit('killall', 'SIGINT');
|
53 | });
|
54 |
|
55 | program
|
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 |
|
105 | program
|
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 |
|
137 | var exporters = require('./lib/exporters')
|
138 |
|
139 | program
|
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 |
|
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 |
|
184 |
|
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 |
|
201 |
|
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 |
|
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 |
|
265 | writeout.foreman_app(c,command.out);
|
266 |
|
267 | baseport_i=0;
|
268 | baseport_j++;
|
269 | }
|
270 |
|
271 |
|
272 | writeout.foreman(config,command.out);
|
273 |
|
274 | });
|
275 |
|
276 | program.parse(process.argv);
|
277 |
|
278 | if(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 | }
|