0
# Utility Functions
1
2
Built-in utilities for shell command execution and file operations, providing cross-platform build automation capabilities and common operations needed in build scripts.
3
4
## Capabilities
5
6
### Command Execution
7
8
Execute shell commands asynchronously with comprehensive options for output handling and error control.
9
10
```javascript { .api }
11
/**
12
* Executes shell-commands asynchronously with optional callback
13
* Arguments after cmds can be provided in any order and are parsed by type
14
* @param {string|string[]} cmds - The shell command(s) to execute
15
* @param {Object} [opts] - Execution options (optional, any order)
16
* @param {boolean} [opts.printStdout=false] - Print stdout from each command
17
* @param {boolean} [opts.printStderr=false] - Print stderr from each command
18
* @param {boolean} [opts.breakOnError=true] - Stop execution on first error
19
* @param {boolean} [opts.windowsVerbatimArguments=false] - Don't translate arguments on Windows
20
* @param {boolean} [opts.interactive=false] - Run command interactively
21
* @param {Function} [callback] - Callback to run after executing commands (optional, any order)
22
* @returns {Exec} Exec instance for monitoring execution
23
*/
24
function exec(cmds, ...args);
25
```
26
27
**Usage Examples:**
28
29
```javascript
30
// Simple command execution
31
jake.exec(['echo "Hello World"'], { printStdout: true });
32
33
// Multiple commands with options
34
const cmds = [
35
'echo "Showing directories"',
36
'ls -al | grep ^d',
37
'echo "Moving up a directory"',
38
'cd ../'
39
];
40
41
jake.exec(cmds, {
42
printStdout: true,
43
printStderr: true
44
}, function () {
45
console.log('Finished running commands.');
46
});
47
48
// Flexible argument order - these are all equivalent:
49
jake.exec(['npm test'], { printStdout: true }, callback);
50
jake.exec(['npm test'], callback, { printStdout: true });
51
jake.exec(['npm test'], callback); // options omitted
52
jake.exec(['npm test'], { printStdout: true }); // callback omitted
53
54
// Error handling
55
jake.exec(['invalid-command'], {
56
breakOnError: false,
57
printStderr: true
58
}, function () {
59
console.log('Commands completed (some may have failed)');
60
});
61
62
// Interactive command
63
jake.exec(['npm init'], {
64
interactive: true
65
}, function () {
66
console.log('Interactive npm init completed');
67
});
68
69
// Platform-specific commands
70
const isWindows = process.platform === 'win32';
71
const cmd = isWindows ? 'dir' : 'ls -la';
72
jake.exec([cmd], { printStdout: true });
73
```
74
75
### Exec Class
76
77
Direct access to the Exec class for advanced command execution control.
78
79
```javascript { .api }
80
/**
81
* Command execution handler with EventEmitter capabilities
82
*/
83
class Exec extends EventEmitter {
84
constructor(cmds, opts, callback);
85
86
append(cmd: string): void; // Add command to execution queue
87
run(): void; // Start command execution
88
}
89
```
90
91
**Exec Events:**
92
93
```javascript { .api }
94
interface ExecEvents {
95
'cmdStart': (cmd: string) => void; // Command started executing
96
'cmdEnd': (cmd: string) => void; // Command finished successfully
97
'stdout': (data: Buffer) => void; // Stdout data received
98
'stderr': (data: Buffer) => void; // Stderr data received
99
'error': (msg: string, code: number) => void; // Command failed
100
'end': () => void; // All commands completed
101
}
102
```
103
104
**Usage Examples:**
105
106
```javascript
107
// Create exec instance for monitoring
108
const ex = new jake.Exec(['npm test', 'npm run build']);
109
110
ex.on('cmdStart', function (cmd) {
111
console.log('Starting:', cmd);
112
});
113
114
ex.on('stdout', function (data) {
115
process.stdout.write(data.toString());
116
});
117
118
ex.on('stderr', function (data) {
119
process.stderr.write(data.toString());
120
});
121
122
ex.on('error', function (msg, code) {
123
console.error('Command failed:', msg, 'Exit code:', code);
124
});
125
126
ex.on('end', function () {
127
console.log('All commands completed');
128
});
129
130
// Add more commands dynamically
131
ex.append('npm run lint');
132
ex.run();
133
```
134
135
### File Operations
136
137
Cross-platform file and directory operations for common build tasks.
138
139
#### Recursive Copy
140
141
```javascript { .api }
142
/**
143
* Copies files and directories recursively
144
* @param {string} fromPath - The source path to copy from
145
* @param {string} toPath - The destination path to copy to
146
* @param {Object} [opts] - Copy options
147
* @param {boolean} [opts.preserveMode=false] - Preserve file modes when overwriting
148
* @returns {void}
149
*/
150
function cpR(fromPath, toPath, opts);
151
```
152
153
**Usage Examples:**
154
155
```javascript
156
// Copy directory recursively
157
jake.cpR('src/assets', 'dist/assets');
158
159
// Copy file to directory
160
jake.cpR('config.json', 'dist/');
161
162
// Copy with options
163
jake.cpR('build/', 'backup/', { preserveMode: true });
164
165
// Copy and rename
166
jake.cpR('src/app.js', 'dist/bundle.js');
167
168
// Copy multiple items in a task
169
task('copyAssets', function () {
170
jake.cpR('src/images', 'dist/images');
171
jake.cpR('src/fonts', 'dist/fonts');
172
jake.cpR('src/data', 'dist/data');
173
});
174
```
175
176
#### Create Directories
177
178
```javascript { .api }
179
/**
180
* Create directories recursively (like mkdir -p)
181
* @param {string} dir - The directory path to create
182
* @param {number} [mode=0755] - The mode/permissions for created directories
183
* @returns {void}
184
*/
185
function mkdirP(dir, mode);
186
```
187
188
**Usage Examples:**
189
190
```javascript
191
// Create single directory
192
jake.mkdirP('dist');
193
194
// Create nested directories
195
jake.mkdirP('dist/assets/images');
196
197
// Create with specific permissions
198
jake.mkdirP('tmp/cache', parseInt('755', 8));
199
200
// Create multiple directories
201
task('setupDirs', function () {
202
jake.mkdirP('dist/css');
203
jake.mkdirP('dist/js');
204
jake.mkdirP('dist/images');
205
jake.mkdirP('tmp/build');
206
});
207
208
// Ensure directory exists before file operations
209
file('dist/bundle.js', ['src/**/*.js'], function () {
210
jake.mkdirP('dist'); // Ensure target directory exists
211
jake.exec(['webpack src/app.js dist/bundle.js']);
212
});
213
```
214
215
#### Remove Files and Directories
216
217
```javascript { .api }
218
/**
219
* Remove files and directories recursively (like rm -rf)
220
* @param {string} path - The path to remove (file or directory)
221
* @param {Object} [options] - Removal options
222
* @returns {void}
223
*/
224
function rmRf(path, options);
225
```
226
227
**Usage Examples:**
228
229
```javascript
230
// Remove directory and all contents
231
jake.rmRf('dist');
232
233
// Remove specific file
234
jake.rmRf('temp.log');
235
236
// Clean task
237
desc('Clean build artifacts');
238
task('clean', function () {
239
jake.rmRf('dist');
240
jake.rmRf('tmp');
241
jake.rmRf('coverage');
242
jake.rmRf('*.log');
243
});
244
245
// Conditional removal
246
task('cleanOld', function () {
247
const fs = require('fs');
248
249
if (fs.existsSync('old-dist')) {
250
jake.rmRf('old-dist');
251
}
252
});
253
```
254
255
### Path Utilities
256
257
Utilities for working with file paths and determining absolute vs relative paths.
258
259
#### Check Absolute Path
260
261
```javascript { .api }
262
/**
263
* Checks if a path is absolute or relative
264
* @param {string} path - Path to check
265
* @returns {boolean|string} If absolute, returns first character; otherwise false
266
*/
267
function isAbsolute(path);
268
```
269
270
#### Convert to Absolute Path
271
272
```javascript { .api }
273
/**
274
* Returns the absolute path for the given path
275
* @param {string} path - The path to make absolute
276
* @returns {string} The absolute path
277
*/
278
function absolutize(path);
279
```
280
281
**Usage Examples:**
282
283
```javascript
284
// Check if path is absolute
285
const path1 = '/home/user/project';
286
const path2 = 'src/app.js';
287
288
console.log(jake.isAbsolute(path1)); // '/'
289
console.log(jake.isAbsolute(path2)); // false
290
291
// Convert to absolute path
292
const absolutePath = jake.absolutize('src/app.js');
293
console.log(absolutePath); // '/current/working/directory/src/app.js'
294
295
// Use in file operations
296
task('copyConfig', function () {
297
const configPath = jake.absolutize('config/app.json');
298
const distPath = jake.absolutize('dist/config.json');
299
300
jake.cpR(configPath, distPath);
301
});
302
303
// Resolve paths in rules
304
rule('dist/%.js', 'src/%.js', function () {
305
const srcPath = jake.absolutize(this.source);
306
const distPath = jake.absolutize(this.name);
307
308
console.log('Compiling:', srcPath, '->', distPath);
309
jake.exec(['babel ' + srcPath + ' -o ' + distPath]);
310
});
311
```
312
313
## Advanced Utility Patterns
314
315
### Command Execution Patterns
316
317
```javascript
318
// Conditional command execution
319
task('deploy', function () {
320
const env = process.env.NODE_ENV || 'development';
321
322
if (env === 'production') {
323
jake.exec([
324
'npm run build:prod',
325
'docker build -t myapp:latest .',
326
'docker push myapp:latest'
327
], { printStdout: true });
328
} else {
329
jake.exec([
330
'npm run build:dev',
331
'rsync -av dist/ staging-server:/var/www/'
332
], { printStdout: true });
333
}
334
});
335
336
// Command chaining with error handling
337
task('testAndDeploy', { async: true }, function () {
338
jake.exec(['npm test'], {
339
printStdout: true,
340
printStderr: true
341
}, function () {
342
console.log('Tests passed, deploying...');
343
344
jake.exec(['npm run deploy'], {
345
printStdout: true
346
}, function () {
347
console.log('Deployment complete');
348
complete();
349
});
350
});
351
});
352
353
// Parallel command execution
354
task('buildAll', { async: true }, function () {
355
let completed = 0;
356
357
const commands = [
358
['npm run build:css'],
359
['npm run build:js'],
360
['npm run build:images']
361
];
362
363
commands.forEach(function (cmd) {
364
jake.exec(cmd, { printStdout: true }, function () {
365
completed++;
366
if (completed === commands.length) {
367
console.log('All builds completed');
368
complete();
369
}
370
});
371
});
372
});
373
```
374
375
### File Operation Patterns
376
377
```javascript
378
// Backup and restore operations
379
task('backup', function () {
380
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
381
const backupDir = `backup-${timestamp}`;
382
383
jake.mkdirP(backupDir);
384
jake.cpR('dist', `${backupDir}/dist`);
385
jake.cpR('config', `${backupDir}/config`);
386
387
console.log('Backup created:', backupDir);
388
});
389
390
task('restore', function (backupName) {
391
if (!backupName) {
392
fail('Please specify backup name: jake restore[backup-2023-...]');
393
}
394
395
jake.rmRf('dist');
396
jake.rmRf('config');
397
jake.cpR(`${backupName}/dist`, 'dist');
398
jake.cpR(`${backupName}/config`, 'config');
399
400
console.log('Backup restored:', backupName);
401
});
402
403
// Cleanup with pattern matching
404
task('cleanLogs', function () {
405
const fs = require('fs');
406
const path = require('path');
407
408
const files = fs.readdirSync('.');
409
files.forEach(function (file) {
410
if (file.match(/\.log$/)) {
411
jake.rmRf(file);
412
console.log('Removed log file:', file);
413
}
414
});
415
});
416
417
// Archive old builds
418
task('archiveBuilds', function () {
419
const fs = require('fs');
420
const path = require('path');
421
422
if (fs.existsSync('dist')) {
423
const timestamp = Date.now();
424
const archiveDir = `archive/build-${timestamp}`;
425
426
jake.mkdirP('archive');
427
jake.cpR('dist', archiveDir);
428
console.log('Archived build to:', archiveDir);
429
}
430
});
431
```
432
433
### Cross-Platform Utilities
434
435
```javascript
436
// Platform-specific operations
437
const isWindows = process.platform === 'win32';
438
const isMac = process.platform === 'darwin';
439
const isLinux = process.platform === 'linux';
440
441
task('install-deps', function () {
442
const commands = [];
443
444
if (isWindows) {
445
commands.push('powershell -Command "& {Install-Module -Name SomeModule}"');
446
} else if (isMac) {
447
commands.push('brew install some-package');
448
} else if (isLinux) {
449
commands.push('sudo apt-get install some-package');
450
}
451
452
jake.exec(commands, { printStdout: true });
453
});
454
455
// Path handling across platforms
456
task('setupPaths', function () {
457
const sep = path.sep;
458
const buildPath = ['dist', 'assets', 'js'].join(sep);
459
460
jake.mkdirP(buildPath);
461
462
const sourcePath = jake.absolutize('src' + sep + 'app.js');
463
const targetPath = jake.absolutize(buildPath + sep + 'app.js');
464
465
jake.cpR(sourcePath, targetPath);
466
});
467
```
468
469
## Advanced Execution Control
470
471
### Exec Class
472
473
The Exec class provides direct control over command execution with event-based monitoring and lifecycle management.
474
475
```javascript { .api }
476
/**
477
* Creates an Exec instance for advanced command control
478
* @param {string|string[]} cmds - Commands to execute
479
* @param {Object} [opts] - Execution options
480
* @param {Function} [callback] - Completion callback
481
* @returns {Exec} Exec instance
482
*/
483
function createExec(cmds, opts, callback);
484
485
/**
486
* Exec class for command execution control
487
*/
488
class Exec extends EventEmitter {
489
constructor(cmds, opts, callback);
490
491
// Methods
492
run(): void; // Start command execution
493
append(cmd: string): void; // Add command to execution queue
494
495
// Events (inherited from EventEmitter)
496
// 'cmdStart' - Emitted when a command starts
497
// 'cmdEnd' - Emitted when a command completes successfully
498
// 'stdout' - Emitted when command outputs to stdout
499
// 'stderr' - Emitted when command outputs to stderr
500
// 'error' - Emitted when a command fails
501
// 'end' - Emitted when all commands complete
502
}
503
```
504
505
**Usage Examples:**
506
507
```javascript
508
// Create exec instance for monitoring
509
const exec = createExec([
510
'npm install',
511
'npm run build',
512
'npm test'
513
], {
514
printStdout: true,
515
breakOnError: false
516
});
517
518
// Monitor execution progress
519
exec.on('cmdStart', function(cmd) {
520
console.log('Starting:', cmd);
521
});
522
523
exec.on('cmdEnd', function(cmd) {
524
console.log('Completed:', cmd);
525
});
526
527
exec.on('stdout', function(data) {
528
console.log('Output:', data.toString());
529
});
530
531
exec.on('error', function(err, code) {
532
console.log('Command failed:', err, 'Exit code:', code);
533
});
534
535
exec.on('end', function() {
536
console.log('All commands completed');
537
});
538
539
// Start execution
540
exec.run();
541
542
// Add more commands dynamically
543
exec.append('npm run deploy');
544
```
545
546
### UUID Generation
547
548
Generate unique identifiers for tasks, temporary files, or other build artifacts.
549
550
```javascript { .api }
551
/**
552
* Generates a UUID string
553
* @param {number} [length] - Specific length for compact form
554
* @param {number} [radix] - Number base for character set (default: 62)
555
* @returns {string} Generated UUID
556
*/
557
function uuid(length, radix);
558
```
559
560
**Usage Examples:**
561
562
```javascript
563
// Generate standard RFC4122 UUID
564
const id = jake.uuid();
565
console.log(id); // "f47ac10b-58cc-4372-a567-0e02b2c3d479"
566
567
// Generate compact UUID
568
const shortId = jake.uuid(8);
569
console.log(shortId); // "3B7nZq4k"
570
571
// Generate with specific radix
572
const hexId = jake.uuid(12, 16);
573
console.log(hexId); // "a3b5c7d9e1f3"
574
575
// Use in build tasks
576
task('generateTempFiles', function() {
577
const tempDir = `temp-${jake.uuid(8)}`;
578
jake.mkdirP(tempDir);
579
580
// Process files in temp directory
581
jake.exec([`process-files ${tempDir}`], { printStdout: true });
582
});
583
584
// Create unique artifact names
585
task('package', function() {
586
const buildId = jake.uuid(6);
587
const packageName = `myapp-${jake.version}-${buildId}.tar.gz`;
588
589
jake.exec([`tar -czf ${packageName} dist/`], { printStdout: true });
590
});
591
```
592
593
### Logger Utilities
594
595
Access Jake's built-in logging system for consistent output formatting and log levels.
596
597
```javascript { .api }
598
/**
599
* Jake's logger instance with formatted output methods
600
*/
601
interface Logger {
602
log(message: string): void; // Standard log output
603
error(message: string): void; // Error output to stderr
604
warn(message: string): void; // Warning output
605
info(message: string): void; // Informational output
606
}
607
608
// Access via jake.logger
609
const logger = jake.logger;
610
```
611
612
**Usage Examples:**
613
614
```javascript
615
// Use logger in tasks
616
task('deploy', function() {
617
jake.logger.info('Starting deployment process...');
618
619
try {
620
jake.exec(['npm run build'], { printStdout: true });
621
jake.logger.log('Build completed successfully');
622
623
jake.exec(['rsync -av dist/ server:/var/www/'], { printStdout: true });
624
jake.logger.log('Deployment completed successfully');
625
626
} catch (err) {
627
jake.logger.error('Deployment failed: ' + err.message);
628
fail(err);
629
}
630
});
631
632
// Custom logging in functions
633
function logBuildStep(step, message) {
634
jake.logger.log(`[${step}] ${message}`);
635
}
636
637
task('build', function() {
638
logBuildStep('CLEAN', 'Removing old build files');
639
jake.rmRf('dist');
640
641
logBuildStep('COMPILE', 'Compiling TypeScript');
642
jake.exec(['tsc'], { printStdout: true });
643
644
logBuildStep('BUNDLE', 'Creating bundle');
645
jake.exec(['webpack'], { printStdout: true });
646
647
jake.logger.log('Build process completed');
648
});
649
```