Skip to content

Commit 80c3a09

Browse files
committed
fix: broken CI build
separate build and update scripts, so that the grammer files are always downloaded on fresh checkout
1 parent a9135a2 commit 80c3a09

File tree

3 files changed

+110
-88
lines changed

3 files changed

+110
-88
lines changed

Diff for: build.ts

+59-87
Original file line numberDiff line numberDiff line change
@@ -9,88 +9,58 @@ import { once } from 'events';
99
import { EOL } from 'os';
1010
import { promisify } from 'util';
1111

12-
const grammerFiles = [
13-
'JavaParser.g4',
14-
'JavaLexer.g4'
15-
];
16-
17-
const main = async () => {
18-
const isStale = await withLog(
19-
'Checking if head is stale... ',
20-
getIsStale(),
21-
isStaleValue => isStaleValue ? 'Stale' : 'Up-to date'
22-
)
23-
if (!isStale && !process.argv.includes('--force')) {
24-
console.log('Exiting, use --force to build anyway');
25-
return;
26-
}
27-
const files = await withLog('Fetching files from upstream... ', getFiles());
12+
export const grammerFiles = ['JavaParser.g4', 'JavaLexer.g4'];
13+
export const grammerRoot = 'src/parser';
14+
15+
export const main = async () => {
16+
const heads = await withLog('Reading head.json ', getHead());
17+
const files = await withLog('Fetching files from upstream... ', getFiles(heads));
2818
await withLog('Writing files... ', writeFiles(files));
29-
await withLog('Updating head.json... ', updateHead());
3019
await withLog('Generating parser...\n', writeParser());
3120
await withLog('Generating contexts... ', writeParserContexts());
3221
await withLog('Compiling typescript files... ', writeJavascript());
3322
console.log('Build successful!');
34-
}
35-
36-
const getIsStale = async () => {
37-
const [head, upstreamHead] = await Promise.all([getHead(), getUpstreamHead()]);
38-
return grammerFiles.some(file => head[file] !== upstreamHead[file]);
39-
}
23+
};
4024

41-
const getHead = async () =>
42-
JSON.parse(
43-
await fs.readFile(path.join(__dirname, 'src/head.json'), 'utf-8')
44-
) as { [file: string]: string };
25+
export const getHead = async () =>
26+
JSON.parse(await fs.readFile(path.join(__dirname, 'src/head.json'), 'utf-8')) as {
27+
[file: string]: string;
28+
};
4529

46-
let upstreamHeadCache: { [file: string]: string } | undefined;
47-
const getUpstreamHead = async () => {
48-
if (upstreamHeadCache) return upstreamHeadCache;
49-
50-
const upstreamHead = mergeAll(
30+
const getFiles = async (heads: { [key: string]: string }) =>
31+
mergeAll(
5132
await Promise.all(
52-
grammerFiles.map(async file => {
53-
const res = await fetch(`https://api.github.com/repos/antlr/grammars-v4/commits?path=java/java/${file}`);
54-
const commits = await res.json();
55-
return { [file]: commits[0].sha as string };
56-
})
57-
)
58-
)
59-
upstreamHeadCache = upstreamHead;
60-
return upstreamHead;
61-
}
62-
63-
const getFiles = async () =>
64-
mergeAll(await Promise.all(
65-
grammerFiles.map(async file => {
66-
const res = await fetch(`https://raw.githubusercontent.com/antlr/grammars-v4/master/java/java/${file}`)
67-
const data = await res.text();
68-
return { [file]: data };
69-
})
70-
))
33+
grammerFiles.map(async (file) => {
34+
const res = await fetch(
35+
`https://raw.githubusercontent.com/antlr/grammars-v4/${heads[file]}/java/java/${file}`,
36+
);
37+
const data = await res.text();
38+
return { [file]: data };
39+
}),
40+
),
41+
);
7142

7243
const writeFiles = (files: { [file: string]: string }) =>
7344
Promise.all(
74-
Object.entries(files)
75-
.map(([file, data]) =>
76-
fs.writeFile(path.join(__dirname, 'src/parser/', file), data)
77-
)
78-
)
79-
80-
const updateHead = async () =>
81-
fs.writeFile(
82-
path.join(__dirname, 'src/head.json'),
83-
JSON.stringify(await getUpstreamHead(), null, ' ')
84-
)
45+
Object.entries(files).map(([file, data]) =>
46+
fs.writeFile(path.join(__dirname, grammerRoot, file), data),
47+
),
48+
);
8549

86-
const writeParser = () =>
87-
execCommand(`${prependBinDir('antlr4ts')} -visitor -o src/parser -Xexact-output-dir src/parser/JavaLexer.g4 src/parser/JavaParser.g4`)
50+
const writeParser = () => {
51+
const binary = prependBinDir('antlr4ts');
52+
return execCommand(
53+
`${binary} -visitor -o ${grammerRoot} -Xexact-output-dir ${grammerRoot}/JavaLexer.g4 ${grammerRoot}/JavaParser.g4`,
54+
);
55+
};
8856

8957
const writeParserContexts = async () => {
90-
const listenerSource = await fs.readFile(path.join(__dirname, '/src/parser/JavaParserListener.ts'), 'utf-8');
58+
const listenerSource = await fs.readFile(
59+
path.join(__dirname, grammerRoot, 'JavaParserListener.ts'),
60+
'utf-8',
61+
);
9162

92-
const exportList =
93-
listenerSource
63+
const exportList = listenerSource
9464
.split(EOL)
9565
.map((l) => {
9666
const matches = l.match(/import\s*\{\s*(.*Context)\s*\}.*/);
@@ -101,48 +71,50 @@ const writeParserContexts = async () => {
10171
.reduce((list, context) => list + ` ${context},${EOL}`, '');
10272

10373
await fs.writeFile(
104-
path.join(__dirname, '/src/parser/JavaContexts.ts'),
105-
`export {${EOL}${exportList}} from './JavaParser';`
74+
path.join(__dirname, grammerRoot, 'JavaContexts.ts'),
75+
`export {${EOL}${exportList}} from './JavaParser';`,
10676
);
107-
}
77+
};
10878

10979
const writeJavascript = async () => {
110-
await promisify(rimraf)(path.join(__dirname, '/dist'))
111-
await execCommand(prependBinDir('tsc'))
112-
}
80+
await promisify(rimraf)(path.join(__dirname, '/dist'));
81+
await execCommand(prependBinDir('tsc'));
82+
};
11383

114-
const withLog = async <T>(
84+
export const withLog = async <T>(
11585
label: string,
11686
promise: Promise<T>,
117-
fulfilMessage: ((value: T) => string) = () => 'Done'
87+
fulfilMessage: (value: T) => string = () => 'Done',
11888
) => {
11989
process.stdout.write(label);
12090
try {
12191
const value = await promise;
122-
process.stdout.write(fulfilMessage(value) + '\n')
92+
process.stdout.write(fulfilMessage(value) + '\n');
12393
return value;
12494
} catch (error) {
12595
process.stdout.write('Something went wrong\n');
12696
throw error;
12797
}
128-
}
98+
};
12999

130100
const execCommand = async (command: string) => {
131-
const childProcess = exec(command, { cwd: __dirname })
101+
const childProcess = exec(command, { cwd: __dirname });
132102
childProcess.stdout.pipe(process.stdout);
133103
childProcess.stderr.pipe(process.stderr);
134104

135-
const [code] = await once(childProcess, 'exit') as [number];
105+
const [code] = (await once(childProcess, 'exit')) as [number];
136106
if (code !== 0) throw undefined;
137-
}
107+
};
138108

139-
const prependBinDir = (p: string) =>
140-
path.join(__dirname, '/node_modules/.bin/', p);
109+
const prependBinDir = (p: string) => path.join(__dirname, '/node_modules/.bin/', p);
141110

142-
type MergeAll = <T extends object[]>(xs: T) => UnionToIntersection<T[number]>;
143-
const mergeAll: MergeAll = xs => xs.reduce((m, x) => ({ ...m, ...x }), {}) as any;
111+
export type MergeAll = <T extends object[]>(xs: T) => UnionToIntersection<T[number]>;
112+
export const mergeAll: MergeAll = (xs) => xs.reduce((m, x) => ({ ...m, ...x }), {}) as any;
144113

145-
type UnionToIntersection<U> =
146-
(U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never
114+
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void
115+
? I
116+
: never;
147117

148-
main();
118+
if (require.main === module) {
119+
main();
120+
}

Diff for: package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
],
2323
"scripts": {
2424
"build": "ts-node build.ts",
25-
"format": "prettier --write build.ts src/**.ts **/*.json",
25+
"update": "ts-node update.ts",
26+
"format": "prettier --write build.ts update.ts src/**.ts **/*.json",
2627
"prepublish": "yarn build",
2728
"precommit": "lint-staged",
2829
"postcommit": "git update-index --again",

Diff for: update.ts

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// tslint:disable:no-console
2+
import { promises as fs } from 'fs';
3+
import fetch from 'node-fetch';
4+
import path from 'path';
5+
import { getHead, grammerFiles, main as buildMain, mergeAll, withLog } from './build';
6+
7+
const main = async () => {
8+
const isStale = await withLog('Checking if head is stale... ', getIsStale(), (isStaleValue) =>
9+
isStaleValue ? 'Stale' : 'Up-to date',
10+
);
11+
if (!isStale && !process.argv.includes('--force')) {
12+
console.log('Exiting, use --force to build anyway');
13+
return;
14+
}
15+
await withLog('Updating head.json... ', updateHead());
16+
await buildMain();
17+
};
18+
19+
const getIsStale = async () => {
20+
const [head, upstreamHead] = await Promise.all([getHead(), getUpstreamHead()]);
21+
return grammerFiles.some((file) => head[file] !== upstreamHead[file]);
22+
};
23+
24+
let upstreamHeadCache: { [file: string]: string } | undefined;
25+
const getUpstreamHead = async () => {
26+
if (upstreamHeadCache) return upstreamHeadCache;
27+
28+
const upstreamHead = mergeAll(
29+
await Promise.all(
30+
grammerFiles.map(async (file) => {
31+
const res = await fetch(
32+
`https://api.github.com/repos/antlr/grammars-v4/commits?path=java/java/${file}`,
33+
);
34+
const commits = await res.json();
35+
return { [file]: commits[0].sha as string };
36+
}),
37+
),
38+
);
39+
upstreamHeadCache = upstreamHead;
40+
return upstreamHead;
41+
};
42+
43+
const updateHead = async () =>
44+
fs.writeFile(
45+
path.join(__dirname, 'src/head.json'),
46+
JSON.stringify(await getUpstreamHead(), null, ' '),
47+
);
48+
49+
main();

0 commit comments

Comments
 (0)