forked from fabricjs/fabric.js
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuildLock.mjs
115 lines (108 loc) · 2.66 KB
/
buildLock.mjs
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
import chalk from 'chalk';
import fs from 'fs-extra';
import _ from 'lodash';
import moment from 'moment';
import path from 'node:path';
import process from 'node:process';
import psList from 'ps-list';
import { dumpsPath } from './dirname.mjs';
export const lockFile = path.resolve(dumpsPath, 'build-lock.json');
/**
*
* @returns {{start:{pid:number,timestamp:string},error?:{pid:number,timestamp:string}} | null}
*/
function readLockFile() {
return fs.existsSync(lockFile) ? JSON.parse(fs.readFileSync(lockFile)) : null;
}
/**
* For concurrency reasons, the last process to lock is granted permission to unlock.
* If the process died the next process to try to unlock will be granted permission.
*/
export async function unlock() {
const lock = readLockFile();
if (!lock) return;
const lockPID = lock.start.pid;
const hasPermissionToUnlock =
process.pid === lockPID ||
!(await psList()).find(({ pid }) => pid === lockPID);
try {
hasPermissionToUnlock && fs.unlinkSync(lockFile);
} catch (error) {}
}
export function isLocked() {
return fs.existsSync(lockFile);
}
export function awaitBuild() {
return new Promise((resolve) => {
if (isLocked()) {
console.log(chalk.cyanBright('> waiting for build to finish...'));
const watcher = subscribe((locked) => {
if (!locked) {
watcher.close();
resolve();
}
}, 500);
} else {
resolve();
}
});
}
/**
* Subscribe to build start/error/completion.
*
* @param {(locked: boolean, error: boolean) => any} cb
* @param {number} [debounce]
* @returns
*/
export function subscribe(cb, debounce) {
return fs.watch(
path.dirname(lockFile),
_.debounce((type, file) => {
if (file !== path.basename(lockFile)) return;
cb(isLocked(), !!(readLockFile() ?? {}).error);
}, debounce)
);
}
/**
*
* @param {'start'|'error'|'end'} type
* @param {*} [data]
*/
export function report(type, data) {
switch (type) {
case 'start':
fs.writeFileSync(
lockFile,
JSON.stringify(
{
start: {
timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
pid: process.pid,
},
},
null,
'\t'
)
);
break;
case 'error':
fs.writeFileSync(
lockFile,
JSON.stringify(
{
...readLockFile(),
error: {
timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
pid: process.pid,
data,
},
},
null,
'\t'
)
);
break;
case 'end':
isLocked() && !readLockFile().error && unlock();
}
}