1 |
|
2 | (function() {
|
3 | var Cron, PREFIX, Service, spawn,
|
4 | __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
5 |
|
6 | spawn = require('child_process').spawn;
|
7 |
|
8 | Cron = require("./Cron");
|
9 |
|
10 | PREFIX = "ggg";
|
11 |
|
12 | Service = (function() {
|
13 |
|
14 | Service.prototype.log = function(msg) {
|
15 | return this.parent.log(this.host, msg);
|
16 | };
|
17 |
|
18 | Service.prototype.runCommand = function(commands, cb) {
|
19 | if (this.isLocal) {
|
20 | return this.localCommand("bash", ["-c", commands], cb);
|
21 | } else {
|
22 | return this.sshCommand(commands, cb);
|
23 | }
|
24 | };
|
25 |
|
26 | Service.prototype.sshCommand = function(commands, cb) {
|
27 | return this.localCommand('ssh', ["-o StrictHostKeyChecking=no", this.host, commands], function(err) {
|
28 | if (err != null) {
|
29 | return cb(new Error("SSH Command Failed"));
|
30 | }
|
31 | return cb();
|
32 | });
|
33 | };
|
34 |
|
35 | Service.prototype.localCommand = function(command, args, cb) {
|
36 | var proc,
|
37 | _this = this;
|
38 | proc = spawn(command, args, {
|
39 | env: process.env
|
40 | });
|
41 | proc.stdout.on('data', function(data) {
|
42 | return _this.log(data.toString().replace(/\n$/, ""));
|
43 | });
|
44 | proc.stderr.on('data', function(data) {
|
45 | return _this.log(data.toString().replace(/\n$/, ""));
|
46 | });
|
47 | proc.on('exit', function(code) {
|
48 | if (code) {
|
49 | return cb(new Error("Command Failed"));
|
50 | }
|
51 | return cb();
|
52 | });
|
53 | return proc;
|
54 | };
|
55 |
|
56 | function Service(name, repoName, config, parent, isLocal) {
|
57 | this.name = name;
|
58 | this.repoName = repoName;
|
59 | this.config = config;
|
60 | this.parent = parent;
|
61 | this.isLocal = isLocal != null ? isLocal : false;
|
62 | this.sshCommand = __bind(this.sshCommand, this);
|
63 |
|
64 | this.runCommand = __bind(this.runCommand, this);
|
65 |
|
66 | this.id = this.repoName + "_" + this.name;
|
67 | this.repoDir = "$HOME/" + PREFIX + "/" + this.id;
|
68 | this.historyFile = "$HOME/" + PREFIX + "/" + this.id + "-history.txt";
|
69 | this.serverUser = this.config.getUser();
|
70 | this.hookFile = "" + this.repoDir + "/.git/hooks/post-receive";
|
71 | this.logFile = "" + this.repoDir + "/ggg.log";
|
72 | this.upstartFile = "/etc/init/" + this.id + ".conf";
|
73 | if (!this.config.getStart()) {
|
74 | this.noUpstart = true;
|
75 | }
|
76 | if (this.isLocal) {
|
77 | this.host = "localhost";
|
78 | this.repoDir = "" + process.env.HOME + "/" + PREFIX + "/" + this.id;
|
79 | this.repoUrl = this.repoDir;
|
80 | } else {
|
81 | this.host = this.config.getHost();
|
82 | this.repoUrl = "ssh://" + this.host + "/~/" + PREFIX + "/" + this.id;
|
83 | }
|
84 | }
|
85 |
|
86 | Service.prototype.create = function(cb) {
|
87 | var createRemoteScript, cron, cronConfig, cronScript, hookScript, upstartScript;
|
88 | this.log(" - id: " + this.id);
|
89 | this.log(" - repo: " + this.repoDir);
|
90 | this.log(" - remote: " + this.repoUrl);
|
91 | this.log(" - start: " + (this.config.getStart()));
|
92 | this.log(" - install: " + (this.config.getInstall()));
|
93 | upstartScript = "";
|
94 | if (!this.noUpstart) {
|
95 | upstartScript = this.makeUpstartScript();
|
96 | }
|
97 | hookScript = this.makeHookScript();
|
98 | cronConfig = this.config.getCron();
|
99 | cronScript = '';
|
100 | if (cronConfig) {
|
101 | cron = new Cron(cronConfig, this.id, this.repoDir, this.serverUser);
|
102 | cronScript = cron.buildCron();
|
103 | }
|
104 | createRemoteScript = this.makeCreateScript(upstartScript, hookScript, cronScript);
|
105 | return this.runCommand(createRemoteScript, function(err) {
|
106 | if (err != null) {
|
107 | return cb(err);
|
108 | }
|
109 | return cb();
|
110 | });
|
111 | };
|
112 |
|
113 | Service.prototype.makeUpstartScript = function() {
|
114 | return "description '" + this.id + "'\nstart on [2345]\nstop on [!2345]\nlimit nofile 10000 15000\nrespawn\nrespawn limit 5 5 \nexec su " + this.serverUser + " -c 'cd " + this.repoDir + " && " + (this.config.getStart()) + "' >> " + this.logFile + " 2>&1";
|
115 | };
|
116 |
|
117 | Service.prototype.makeHookScript = function() {
|
118 | return "read oldrev newrev refname\necho 'GOGOGO checking out:'\necho \\$newrev\necho \\`date\\` - \\$newrev >> " + this.historyFile + "\ncd " + this.repoDir + "/.git\nGIT_WORK_TREE=" + this.repoDir + " git reset --hard \\$newrev || exit 1;";
|
119 | };
|
120 |
|
121 | Service.prototype.makeCreateScript = function(upstart, hook, cronInstallScript) {
|
122 | var upstartInstall;
|
123 | upstartInstall = "";
|
124 | if (upstart) {
|
125 | upstartInstall = "echo \"" + upstart + "\" | sudo tee " + this.upstartFile;
|
126 | }
|
127 | return "echo '\nCREATING...'\nmkdir -p " + this.repoDir + "\ncd " + this.repoDir + "\necho \"Locating git\"\nwhich git \nif (( $? )); then\n echo \"Could not locate git\"\n exit 1\nfi\ngit init\ngit config receive.denyCurrentBranch ignore\n\n" + upstartInstall + "\n\necho \"" + hook + "\" > " + this.hookFile + "\nchmod +x " + this.hookFile + "\necho \"[√] created\"\n" + cronInstallScript;
|
128 | };
|
129 |
|
130 | Service.prototype.deploy = function(branch, cb) {
|
131 | var _this = this;
|
132 | this.log(" - name: " + this.name);
|
133 | this.log(" - server: " + this.host);
|
134 | this.log(" - branch: " + branch);
|
135 | return this.create(function(err) {
|
136 | if (err != null) {
|
137 | return cb(err);
|
138 | }
|
139 | _this.log("\nPUSHING");
|
140 | return _this.localCommand("git", ["push", _this.repoUrl, branch, "-f"], function(err) {
|
141 | var installCommand;
|
142 | if (err != null) {
|
143 | return cb(err);
|
144 | }
|
145 | _this.log("[√] pushed");
|
146 | installCommand = _this.makeInstallCommand() + "\n" + _this.makeRestartCommand();
|
147 | return _this.runCommand(installCommand, function(err) {
|
148 | var command, kill;
|
149 | if (err != null) {
|
150 | return cb(err);
|
151 | }
|
152 | command = _this.serverLogs(10, function() {});
|
153 | kill = function() {
|
154 | command.kill();
|
155 | return cb();
|
156 | };
|
157 | return setTimeout(kill, 2000);
|
158 | });
|
159 | });
|
160 | });
|
161 | };
|
162 |
|
163 | Service.prototype.makeInstallCommand = function() {
|
164 | return "echo '\nINSTALLING'\ncd " + this.repoDir + "\n" + (this.config.getInstall()) + " || exit 1;\necho '[√] installed'";
|
165 | };
|
166 |
|
167 | Service.prototype.makeRestartCommand = function() {
|
168 | if (this.noUpstart) {
|
169 | return "";
|
170 | }
|
171 | return "echo '\nRESTARTING'\nsudo stop " + this.id + "\nsudo start " + this.id + "\necho '[√] restarted'";
|
172 | };
|
173 |
|
174 | Service.prototype.restart = function(cb) {
|
175 | if (this.noUpstart) {
|
176 | return this.log("nothing to restart");
|
177 | }
|
178 | this.log("RESTARTING");
|
179 | return this.runCommand(this.makeRestartCommand(), cb);
|
180 | };
|
181 |
|
182 | Service.prototype.stop = function(cb) {
|
183 | if (this.noUpstart) {
|
184 | return this.log("nothing to stop");
|
185 | }
|
186 | this.log("STOPPING");
|
187 | return this.runCommand("sudo stop " + this.id + ";", cb);
|
188 | };
|
189 |
|
190 | Service.prototype.start = function(cb) {
|
191 | if (this.noUpstart) {
|
192 | return this.log("nothing to start");
|
193 | }
|
194 | this.log("STARTING");
|
195 | return this.runCommand("sudo start " + this.id + ";", cb);
|
196 | };
|
197 |
|
198 | Service.prototype.serverLogs = function(lines, cb) {
|
199 | this.log("Tailing " + this.logFile + "... Control-C to exit");
|
200 | this.log("-------------------------------------------------------------");
|
201 | return this.runCommand("tail -n " + lines + " -f " + this.logFile, cb);
|
202 | };
|
203 |
|
204 | Service.prototype.getHistory = function(revisions, cb) {
|
205 | this.log("Retrieving last " + revisions + " deploys, most recent first!");
|
206 | this.log("-------------------------------------------------------------");
|
207 | return this.runCommand("tail -n " + revisions + " " + this.historyFile + " | tac", cb);
|
208 | };
|
209 |
|
210 | return Service;
|
211 |
|
212 | })();
|
213 |
|
214 | module.exports = Service;
|
215 |
|
216 | }).call(this);
|