-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgulpfile.babel.js
311 lines (272 loc) · 11 KB
/
gulpfile.babel.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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
import gulp from 'gulp';
import git from 'gulp-git';
import { spawn } from 'child_process';
import { readFileSync, writeFileSync } from 'fs';
const applicationPath = process.cwd();
/**
* Reads files from the application directory
* @param fileName - The name of the file that we want to read
* @returns {object} the object resulting from parsing the application configuration
*/
const readFile = (fileName) => {
const filePath = applicationPath + `/${fileName}`;
let file;
try {
file = readFileSync(filePath);
} catch (e) {
throw new Error('Error loading application configuration: ' + e.message);
}
try {
file = JSON.parse(file);
} catch (e) {
throw new Error('Error parsing application configuration: ' + e.message);
}
return file;
};
const config = readFile('config.json');
const appState = readFile('app-state.json');
/**
* Updates the state of the module object loaded from the configuration with the newState
*
* @param {object} module - The configuration of a module that needs to be processed
* @param {object} newState - A set of properties on the module status object that need to have their values updated, along with the new values
*/
const updateModuleStatus = (module, newState) => {
if (typeof module === 'object' && typeof newState === 'object') {
module.status = Object.assign(module.status || {}, newState);
}
};
/**
* Asynchronously clones a module as defined in the module configuration
*
* @param {object} module
* @returns {Promise} A Promise that will resolve if the clone operation has succeeded and will reject otherwise
*/
const clone = (module) => {
const options = {
args: module.name
};
return new Promise((resolve, reject) => {
git.clone(module.url, options, (err) => {
if (err) {
console.warn(err.message);
return reject(err);
}
updateModuleStatus(module, { cloneSucceeded: true });
return resolve();
});
});
};
/**
* Asynchronously executes a command by spawning a child process
*
* @param {string} command - the command to be executed, without arguments or parameters
* @param {Array<string>} [args=[]] - the list of parameters and arguments to be passed to the command
* @param {object} wd - the working directory that the command should be executed in
* @returns {Promise} - A promise that resolves if the child process exits with exit code 0, and rejects otherwise
*/
const runCommand = (command, args = [], wd, dataCallback) => {
const cwd = process.cwd();
if (wd) {
process.chdir(wd);
}
return new Promise((resolve, reject) => {
const fullCommand = `${command} ${args.join(' ')}`;
console.log(`Running command: ${fullCommand}`);
const child = spawn(command, args);
child.on('exit', (code, signal) => {
const exit = { code, signal };
if (wd) {
process.chdir(cwd);
}
if (!exit.code) {
return resolve();
} else {
return reject(new Error(`Command '${fullCommand}' exited with code ${exit.code}, signal ${exit.signal}`));
}
});
child.on('error', (err) => {
if (wd) {
process.chdir(cwd);
}
reject(err);
});
child.stdout.on('data', (data) => {
if (dataCallback) {
dataCallback(data);
} else {
console.log(data.toString());
}
});
child.stderr.on('data', (data) => {
console.error(data.toString());
});
});
};
/**
* Creates a Promise to execute the npm install command in a module's folder
*
* @param {object} module - the module configuration for the module that needs npm install
* @returns {Promise} A Promise that resolves if npm install succeeds, and rejects otherwise
*/
const npmInstall = (module) => {
if (!module.status || !module.status.cloneSucceeded) {
return;
}
return runCommand('npm', ['install'], module.name);
};
/**
* Creates a Promise to execute the schematics insert-module command for a module
*
* @param {object} module - the module configuration for the module that needs npm install
* @returns {Promise} A Promise that resolves if npm install succeeds, and rejects otherwise
*/
const schematicsInsert = (module) => {
if (!module.status || !module.status.cloneSucceeded) {
return;
}
return runCommand('ng', ['g', '.:insert-module', `--name=${module.name}`,
`--parentExitPointComponentPath=${module.config.parentExitPointComponent.path}`,
`--parentExitPointComponentElementId=${module.config.parentExitPointComponent.elementId}`,
`--parentExitPointComponentSelector=${module.config.parentExitPointComponent.componentSelector}`,
module.config.parentExitPointComponent.options.label ? `--parentExitPointComponentLabel=${module.config.parentExitPointComponent.options.label}` : '',
module.config.parentExitPointComponent.options.icon ? `--parentExitPointComponentIcon=${module.config.parentExitPointComponent.options.icon}` : '',
module.config.parentExitPointComponent.options.route ? `--parentExitPointComponentRoute=${module.config.parentExitPointComponent.options.route}` : '',
module.config.parentExitPointComponent.options.routerOutlet ? `--parentExitPointComponentRouterOutlet=${module.config.parentExitPointComponent.options.routerOutlet}` : '',
`--routingModuleOptionsPath=${module.config.routingModuleOptions.path}`,
`--routingModuleOptionsChildrenArrayIndex=${module.config.routingModuleOptions.childrenArrayIndex}`,
`--routingModuleOptionsParentComponent=${module.config.routingModuleOptions.parentComponent}`,
`--styles=${module.config.styles}`,
`--scripts=${module.config.scripts}`,
`--assets=${module.config.assets}`,
],
'../../node_modules/midgard-schematics/');
};
/**
* Creates a Promise to execute the schematics remove-module command for a module
*
* @param {object} module - the module configuration for the module that needs npm install
* @returns {Promise} A Promise that resolves if npm install succeeds, and rejects otherwise
*/
const schematicsRemove = (module) => {
return runCommand('ng', ['g', '.:remove-module', `--name=${module.name}`,
`--parentExitPointComponentPath=${module.config.parentExitPointComponent.path}`,
`--parentExitPointComponentElementId=${module.config.parentExitPointComponent.elementId}`,
`--parentExitPointComponentSelector=${module.config.parentExitPointComponent.componentSelector}`,
module.config.parentExitPointComponent.options.label ? `--parentExitPointComponentLabel=${module.config.parentExitPointComponent.options.label}` : '',
module.config.parentExitPointComponent.options.icon ? `--parentExitPointComponentIcon=${module.config.parentExitPointComponent.options.icon}` : '',
module.config.parentExitPointComponent.options.route ? `--parentExitPointComponentRoute=${module.config.parentExitPointComponent.options.route}` : '',
module.config.parentExitPointComponent.options.routerOutlet ? `--parentExitPointComponentRouterOutlet=${module.config.parentExitPointComponent.options.routerOutlet}` : '',
`--routingModuleOptionsPath=${module.config.routingModuleOptions.path}`,
`--routingModuleOptionsChildrenArrayIndex=${module.config.routingModuleOptions.childrenArrayIndex}`,
`--routingModuleOptionsParentComponent=${module.config.routingModuleOptions.parentComponent}`,
`--styles=${module.config.styles}`,
`--scripts=${module.config.scripts}`,
`--assets=${module.config.assets}`,
],
'../../node_modules/midgard-schematics/');
};
/**
* An error handler function that handles exceptions but writes their messages to the console as warnings
*
* @param {Error} err - the error generated by the exception
*/
const genericErrorHandler = (err) => { console.warn(err.message); };
/**
* Gulp task which initializes an entire walhall application based on the configuration found in its config.json
*
* Clone, npm install, run schematics#import-module on every module defined in the application's config.json
*
* Tasks will be executed in sequence. If a clone operation fails, no further operations will be performed on that module.
*
*/
gulp.task('init', (done) => {
if (!config) {
throw new Error('Application configuration not found');
}
if (!config.modules) {
throw new Error('No application modules found');
}
const tasksToRun = [];
process.chdir('src/clients');
for (let i = 0; i < config.modules.length; i++) {
const module = config.modules[i];
const taskName = `init:${module.name}`;
gulp.task(taskName, (subTaskDone) => {
return clone(module)
.catch(genericErrorHandler)
.then(() => { return npmInstall(module); })
.catch(genericErrorHandler)
.then(() => {
if (module.config) {
return schematicsInsert(module);
}
})
.catch(genericErrorHandler)
.then(subTaskDone);
});
tasksToRun.push(taskName);
}
gulp.task('add:app', () => {
process.chdir('../');
return gulp.src('.').pipe(git.add());
});
gulp.task('commit:app', () => {
return gulp.src('.').pipe(git.commit('modules has been added to the application by midgard-schematics'));
});
gulp.task('getCommitId:app', () => {
return runCommand('../node_modules/midgard-schematics/lib/git-log.sh', [], undefined, (data) => {
appState.app.initCommitId = data.toString().split(' ')[1].trim();
console.warn(data.toString());
});
});
tasksToRun.push('add:app', 'commit:app', 'getCommitId:app');
return gulp.series(tasksToRun)(() => {
process.chdir('../');
writeFileSync(`${applicationPath}/app-state.json`, JSON.stringify(appState))
done();
});
});
/**
* Gulp task that cleans up the code generated by schematics
*
* run schematics#remove-module on every module defined in the application's config.json
**
*/
gulp.task('cleanup', (done) => {
if (!config) {
throw new Error('Application configuration not found');
}
if (!config.modules) {
throw new Error('No application modules found');
}
const tasksToRun = [];
process.chdir('src/clients');
for (let i = config.modules.length - 1; i >= 0; i--) {
const module = config.modules[i];
const taskName = `cleanup:${module.name}`;
gulp.task(taskName, (subTaskDone) => {
return schematicsRemove(module).catch(genericErrorHandler).then(subTaskDone);
});
tasksToRun.push(taskName);
}
gulp.task('add:app', () => {
process.chdir('../');
return gulp.src('.').pipe(git.add());
});
gulp.task('commit:app', () => {
return gulp.src('.').pipe(git.commit('modules has been removed from the application by midgard-schematics'));
});
gulp.task('getCommitId:app', () => {
return runCommand('../node_modules/midgard-schematics/lib/git-log.sh', [], undefined, (data) => {
appState.app.initCommitId = data.toString().split(' ')[1].trim();
console.warn(data.toString());
});
});
tasksToRun.push('add:app', 'commit:app', 'getCommitId:app');
return gulp.series(tasksToRun)(() => {
process.chdir('../');
writeFileSync(`${applicationPath}/app-state.json`, JSON.stringify(appState))
done();
});
});