-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
201 lines (167 loc) · 5.17 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
var fs = require('fs');
var optimist = require('optimist');
var DEFAULT_DESCRIPTOR_PATH = 'deployment.json';
function validate(argv) {
// correct port
var port = argv.port;
if (typeof port !== 'number' || port < 1 || port > 65535 || Math.round(port) != port) {
throw 'port must be an integer value from 1 to 65535. Provided value: ' + port;
}
}
function dotNotation(key, object, parentObject) {
if (typeof object !== 'object') {
return;
}
for (var i in object) {
var newKey = key + '.' + i;
if (typeof object[i] !== 'object') {
parentObject[newKey] = object[i];
continue;
}
if (object[i] instanceof Array) {
var arrayVal = [];
for (var j in object[i]) {
arrayVal.push(typeof object[i][j] === 'object' ? null : object[i][j]);
}
parentObject[newKey] = arrayVal;
continue;
}
dotNotation(key + '.' + i, object[i], parentObject);
}
}
// *****************************************************************************
// Process arguments
// *****************************************************************************
// collect keys
var keys = [];
for (var i = 2; i < process.argv.length; i++) {
if (process.argv[i].match(/^--?\D/)) {
keys.push(process.argv[i].replace(/^--?/, ""));
}
}
// all the arguments should be trated as strings in the initial parsing
var argv = optimist
.string(keys)
.argv;
// an empty descriptor
var descriptor = {};
// the computed descriptor file path
var descriptorPath = process.cwd() + '/' + (argv['_'][0] || DEFAULT_DESCRIPTOR_PATH);
// load the descriptor file
if (fs.existsSync(descriptorPath)) {
try {
descriptor = require(descriptorPath);
} catch (err) {
console.error('Invalid deployment descriptor file: ' + descriptorPath);
process.exit(1);
}
} else {
if (argv['_'][0]) {
console.error('No such deployment descriptor file: ' + descriptorPath);
process.exit(2);
}
}
for (var i in descriptor) {
var object = descriptor[i];
if (typeof object === 'object') {
var dotn = dotNotation(i, object, descriptor);
delete descriptor[i];
}
}
delete argv['_'];
delete argv['$0'];
var aliases = {
'h': 'host',
'p': 'port',
'u': 'user',
'f': 'force',
'd': 'path',
'r': 'repo'
}
var descriptions = {
'host': 'the host name of the server to which the deployment is made',
'port': 'the port on which the server should listen',
'user': 'the user name form which the deployment is made on the host',
'path': 'the path on the server where the deployment will be made',
'force': 'the deployment should overwrite (remove) path if this already exists',
'repo': 'the URL of the repository from where to fetch the code'
}
// overwriting the descriptor options
for (var i in argv) {
var longi = aliases[i] || i;
descriptor[longi] = argv[i];
}
// gather all the options
argv = process.argv.slice(0, 2);
for (var i in descriptor) {
var key = '--' + i;
var val;
switch (typeof descriptor[i]) {
case 'object':
var newObj = {};
dotNotation(i, descriptor[i], newObj);
for (var j in newObj) {
argv.push('--' + j);
argv.push(newObj[j].toString());
}
continue;
default:
val = descriptor[i].toString();
}
argv.push(key);
argv.push(val);
}
// overwrite the process arguments
process.argv = argv;
// parse again the arguments now with restrictions
argv = optimist(argv)
// usage and desctiptions
.usage('Usage:\n' +
' gotowork [options] [descriptor.json]\n\n' +
' If no deployment descriptor is provided, a file named deployment.json will be\n' +
' searched for in the current directory. If deployment.json is not found, all\n' +
' the mandatory deployment properties must be provided as options.'
)
.alias(aliases)
.describe(descriptions)
.demand(['host', 'user', 'repo'])
// types
.string(['host', 'user', 'path', 'repo'])
.boolean('force')
// defaults
.default('port', 80)
.default('path', '~')
.default('force', false)
.check(validate)
.argv;
delete argv['_'];
delete argv['$0'];
// remove the short aliases
for (var i in aliases) {
delete argv[i];
}
// *****************************************************************************
// Deploy
// *****************************************************************************
var spawn = require('child_process').spawn;
var userHost = argv.user + '@' + argv.host;
console.log('Connecting to ' + userHost + ' ...');
var env = '';
for (var i in argv.env) {
env += i + '="' + argv.env[i] + '" ';
}
if (env) {
delete argv.env;
}
for (var i in argv) {
env += 'DEPLOY_' + i.toUpperCase() + '="' + argv[i] + '" ';
}
var ssh = spawn('ssh', ['-A', userHost, env + ' bash -s' ], { stdio: 'inherit' });
ssh.on('exit', function (code) {
if (!code) {
console.log('Deployment done');
} else {
console.log('Deployment finished with error code: ' + code);
}
process.exit(code);
});