Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
1#!/usr/bin/env nix-shell 2/* 3#!nix-shell -i node -p nodejs 4*/ 5 6import { promises as fs } from 'node:fs'; 7 8const constants = { 9 githubUrl: "https://api.github.com/repos/pulsar-edit/pulsar/releases", 10 sha256FileURL: (newVersion) => `https://github.com/pulsar-edit/pulsar/releases/download/v${newVersion}/SHA256SUMS.txt`, 11 x86_64FileName: (newVersion) => `Linux.pulsar-${newVersion}.tar.gz`, 12 aarch64FileName: (newVersion) => `ARM.Linux.pulsar-${newVersion}-arm64.tar.gz`, 13 targetFile: new URL("package.nix", import.meta.url).pathname, 14}; 15 16async function utf16ToUtf8(blob) { 17 // Sometime, upstream saves the SHA256SUMS.txt file in UTF-16, which absolutely breaks node's string handling 18 // So we need to convert this blob to UTF-8 19 20 // We need to skip the first 2 bytes, which are the BOM 21 const arrayBuffer = await blob.slice(2).arrayBuffer(); 22 const buffer = Buffer.from(arrayBuffer); 23 const utf8String = buffer.toString('utf16le'); 24 return utf8String; 25} 26 27async function getLatestVersion() { 28 const requestResult = await fetch(constants.githubUrl); 29 if (!requestResult.ok) { 30 console.error("Failed to fetch releases"); 31 console.error(requestResult); 32 process.exit(1); 33 }; 34 let jsonResult = await requestResult.json(); 35 36 jsonResult = jsonResult.filter((release) => !release.prerelease && !release.draft); 37 if (jsonResult.length == 0) { 38 console.error("No releases found"); 39 process.exit(1); 40 } 41 42 return jsonResult[0].tag_name.replace(/^v/, ''); 43} 44 45async function getSha256Sum(hashFileContent, targetFile) { 46 // The upstream file has a fomat like this: 47 // 0000000000000000000000000000000000000000000000000000000000000000 targetFile 48 49 let sha256 = hashFileContent. 50 split('\n'). 51 map(line => line.replace("\r", "")). // Side-effect of the UTF-16 conversion, if the file was created from Windows 52 filter((line) => line.endsWith(targetFile))[0]. 53 split(' ')[0]; 54 55 return "sha256-" + Buffer.from(sha256, 'hex').toString('base64'); 56} 57 58async function getSha256Sums(newVersion) { 59 // Upstream provides a file with the hashes of the files, but it's not in the SRI format, and it refers to the compressed tarball 60 // So let's just use nix-prefetch-url to get the hashes of the decompressed tarball, and `nix hash to-sri` to convert them to SRI format 61 const hashFileUrl = constants.sha256FileURL(newVersion); 62 const hashFileContent = await fetch(hashFileUrl).then((response) => response.blob()); 63 const headerbuffer = await hashFileContent.slice(0, 2).arrayBuffer() 64 const header = Buffer.from(headerbuffer).toString('hex'); 65 66 // We must detect if it's UTF-16 or UTF-8. If it's UTF-16, we must convert it to UTF-8, otherwise just use it as-is 67 const hashFileContentString = header == 'fffe' ? 68 await utf16ToUtf8(hashFileContent) : 69 await hashFileContent.text(); 70 71 let x86_64; 72 let aarch64; 73 console.log("Getting new hashes"); 74 let promises = [ 75 getSha256Sum(hashFileContentString, constants.x86_64FileName(newVersion)).then((hash) => { x86_64 = hash; }), 76 getSha256Sum(hashFileContentString, constants.aarch64FileName(newVersion)).then((hash) => { aarch64 = hash; }), 77 ]; 78 await Promise.all(promises); 79 return { x86_64, aarch64 }; 80} 81 82async function updateFile(newVersion, sha256Sums, currentFile) { 83 // There is some assumptions in how the file is formatted, but nothing egregious 84 85 let newFile = currentFile.replace(/version = "(.*)";/, `version = "${newVersion}";`); 86 newFile = newFile.replace(/x86_64-linux\.hash = "(.*)";/, `x86_64-linux.hash = "${sha256Sums.x86_64}";`); 87 newFile = newFile.replace(/aarch64-linux\.hash = "(.*)";/, `aarch64-linux.hash = "${sha256Sums.aarch64}";`); 88 89 await fs.writeFile(constants.targetFile, newFile); 90}; 91 92let currentFile = await fs.readFile(constants.targetFile, 'utf8'); 93let currentVersion = currentFile.match(/version = "(.*)";/)[1]; 94const newVersion = await getLatestVersion(); 95if (currentVersion === newVersion) { 96 console.error("Already up to date"); 97 process.exit(0); 98} 99console.log("New version: " + newVersion); 100const sha256Sums = await getSha256Sums(newVersion); 101console.log(sha256Sums) 102if (!sha256Sums.x86_64 || !sha256Sums.aarch64) { 103 console.error("Failed to find sha256 sums for the 2 files"); 104 process.exit(1); 105} 106updateFile(newVersion, sha256Sums, currentFile);