Commit | Line | Data |
---|---|---|
3f4a49f8 AE |
1 | import * as fs from 'fs'; |
2 | import * as md5File from 'md5-file'; | |
3 | import * as path from 'path'; | |
4 | import { promisify } from 'util'; | |
5 | ||
6 | const copyFile = promisify(fs.copyFile); | |
7 | const exists = promisify(fs.exists); | |
8 | const stat = promisify(fs.stat); | |
9 | ||
10 | if (process.argv.length !== 3) { | |
11 | throw new Error('Expected the path to the repository root as the only argument.'); | |
12 | } | |
13 | ||
14 | const repository = process.argv[2]; | |
15 | if (!fs.existsSync(repository)) { | |
16 | throw new Error(`The path '${repository}' does not exist.`); | |
17 | } | |
18 | process.chdir(repository); | |
19 | ||
20 | const getFileStatus = async (filename: string, directory: string): Promise<FileStatus> => { | |
21 | const file = path.join(directory, filename); | |
22 | if (await exists(file)) { | |
23 | const stats = await stat(file); | |
24 | ||
25 | return { | |
26 | checksum: md5File.sync(file), | |
27 | lastModified: stats.mtime, | |
28 | }; | |
29 | } | |
30 | ||
31 | return null; | |
32 | }; | |
33 | ||
34 | (async (): Promise<void> => { | |
35 | fs.readFile('syncTemplates.json', 'utf8', async (err: NodeJS.ErrnoException, content: string): Promise<void> => { | |
36 | if (!err) { | |
37 | const data: SyncTemplateConfiguration = JSON.parse(content); | |
38 | ||
39 | if ((<any>data).__proto__ === Object.prototype) { | |
40 | let filesCopied = 0; | |
41 | ||
42 | await Promise.all(data.templates.map(async (template: string): Promise<void> => { | |
43 | template = `${template}.tpl`; | |
44 | const status = await Promise.all([ | |
45 | getFileStatus(template, data.directories[0]), | |
46 | getFileStatus(template, data.directories[1]), | |
47 | ]); | |
48 | ||
49 | if (status[0] === null && status[1] === null) { | |
50 | throw new Error(`Unknown file ${template}.`); | |
51 | } | |
52 | ||
53 | let copyTo = -1; | |
54 | if (status[0] === null) { | |
55 | copyTo = 0; | |
56 | } else if (status[1] === null) { | |
57 | copyTo = 1; | |
58 | } else if (status[0].checksum !== status[1].checksum) { | |
59 | copyTo = (status[0].lastModified > status[1].lastModified) ? 1 : 0; | |
60 | } | |
61 | ||
62 | if (copyTo !== -1) { | |
63 | const source = (copyTo === 0) ? 1 : 0; | |
64 | await copyFile( | |
65 | path.join(data.directories[source], template), | |
66 | path.join(data.directories[copyTo], template), | |
67 | ); | |
68 | ||
69 | filesCopied++; | |
70 | } | |
71 | })); | |
72 | ||
73 | if (filesCopied === 0) { | |
74 | console.log("All files are in sync."); | |
75 | } else { | |
76 | console.log(`Copied ${filesCopied} of ${data.templates.length} files.`); | |
77 | } | |
78 | } else { | |
79 | throw new Error("Expected an object at the JSON root."); | |
80 | } | |
81 | } | |
82 | }); | |
83 | })(); | |
84 | ||
85 | interface SyncTemplateConfiguration { | |
86 | directories: string[]; | |
87 | templates: string[]; | |
88 | } | |
89 | ||
90 | interface FileStatus { | |
91 | checksum: string; | |
92 | lastModified: Date; | |
93 | } |