|
| 1 | +#!/usr/bin/env node |
| 2 | + |
| 3 | +const main = async (...args) => { |
| 4 | + const cpus = { |
| 5 | + '64-bit': { label: 'x64 (64-bit)', rank: 3 }, |
| 6 | + 'arm64': { label: 'ARM64', rank: 2 }, |
| 7 | + '32-bit': { label: 'x86 (32-bit)', rank: 1 }, |
| 8 | + } |
| 9 | + const urls = { |
| 10 | + installers: [], |
| 11 | + portableGits: [], |
| 12 | + minGits: [], |
| 13 | + busyBoxMinGits: [] |
| 14 | + } |
| 15 | + const cpuRE = `(${Object.keys(cpus).join('|')})` |
| 16 | + const fileNameRegex = new RegExp(`^(?:${[ |
| 17 | + ['Git', 'exe'], |
| 18 | + ['PortableGit', '7z\\.exe'], |
| 19 | + ['MinGit', 'zip', '-BusyBox'], |
| 20 | + ['MinGit', 'zip'], |
| 21 | + ].map(a => `(${a[0]}-.*?${a[2] || ''}-${cpuRE}\\.${a[1]})`) |
| 22 | + .join('|')})$`, 'i') |
| 23 | + const addURL = url => { |
| 24 | + const fileName = url.replace(/.*\//, '') |
| 25 | + const match = fileName.match(fileNameRegex) |
| 26 | + if (!match) throw new Error(`Cannot parse URL: ${url}`) |
| 27 | + else if (match[1]) urls.installers.push({ url, cpu: cpus[match[2]] }) |
| 28 | + else if (match[3]) urls.portableGits.push({ url, cpu: cpus[match[4]] }) |
| 29 | + else if (match[5]) urls.busyBoxMinGits.push({ url, cpu: cpus[match[6]] }) |
| 30 | + else if (match[7]) urls.minGits.push({ url, cpu: cpus[match[8]] }) |
| 31 | + else throw new Error(`Cannot parse URL: ${url}`) |
| 32 | + } |
| 33 | + |
| 34 | + let date |
| 35 | + let commit |
| 36 | + while (args.length > 0) { |
| 37 | + const arg = args.shift() |
| 38 | + if (arg.startsWith('--date=')) date = arg.replace(/.*?=/, '') |
| 39 | + else if (arg.startsWith('--commit=')) commit = arg.replace(/.*?=/, '') |
| 40 | + else if (arg.startsWith('https://')) addURL(arg) |
| 41 | + else { |
| 42 | + throw new Error(`Unhandled argument '${arg}`) |
| 43 | + } |
| 44 | + } |
| 45 | + |
| 46 | + if (!date) throw new Error('Need a date!') |
| 47 | + if (!commit) throw new Error('Need a commit!') |
| 48 | + if (Object.values(urls).reduce((a, e) => e.length + a, 0) === 0) throw new Error('Need at least one URL!') |
| 49 | + |
| 50 | + const listURLs = array => array |
| 51 | + .sort((a, b) => b.cpu.rank - a.cpu.rank) |
| 52 | + .map((e, i) => `${i < 1 ? '' : array[i + 1] ? ', ' : ' and '}<a href="${e.url}">${e.cpu.label}</a>`) |
| 53 | + .join('') |
| 54 | + |
| 55 | + const insert = [ |
| 56 | + `<h2 id="${new Date(date).toISOString()}">`, |
| 57 | + date, |
| 58 | + '<br />', |
| 59 | + `(commit <a href="https://github.com/git-for-windows/git/commit/${commit}">${commit}</a>)</h2>\n`, |
| 60 | + '\n', |
| 61 | + '<ul>\n', ...[ |
| 62 | + { label: 'Git for Windows installer', urls: urls.installers }, |
| 63 | + { label: 'Portable Git (self-extracting <tt>.7z</tt> archive)', urls: urls.portableGits }, |
| 64 | + { label: 'MinGit', urls: urls.minGits }, |
| 65 | + { label: 'MinGit (BusyBox)', urls: urls.busyBoxMinGits }, |
| 66 | + ].filter(e => e.urls.length > 0).map(e => `<li>${e.label}: ${listURLs(e.urls)}.</li>\n`), |
| 67 | + '</ul>' |
| 68 | + ].join('') |
| 69 | + |
| 70 | + const fs = require('fs') |
| 71 | + const sections = fs |
| 72 | + .readFileSync('index.html', 'utf-8') |
| 73 | + .split(/(<h2 .+<\/h2>)/) |
| 74 | + if (sections.length < 3) throw new Error(`'index.html' is not in the expected format`) |
| 75 | + |
| 76 | + sections[1] = `${insert}\n\n${sections[1]}` |
| 77 | + fs.writeFileSync('index.html', sections.join('')) |
| 78 | +} |
| 79 | + |
| 80 | +module.exports = main |
| 81 | + |
| 82 | +if (require.main === module) main(process.argv.slice(2)).catch(e => { |
| 83 | + console.error(e) |
| 84 | + process.exit(1) |
| 85 | +}) |
0 commit comments