Files
yarn-plugin-nixify-patched/src/nixUtils.ts
T
2021-04-30 15:10:47 +02:00

74 lines
2.0 KiB
TypeScript

import { createHash } from "crypto";
import { Filename, PortablePath, ppath } from "@yarnpkg/fslib";
const charset = "0123456789abcdfghijklmnpqrsvwxyz";
/**
* Short-hand for simple hash computation.
*/
export const computeHash = (algorithm: string, data: string | Buffer) =>
createHash(algorithm).update(data).digest();
/**
* Nix-compatible hash compression.
*/
export const compressHash = (hash: Buffer, size: number) => {
const result = Buffer.alloc(size);
for (let idx = 0; idx < hash.length; idx++) {
result[idx % size] ^= hash[idx];
}
return result;
};
/**
* Nix-compatible base32 encoding.
*
* This is probably a super inefficient implementation, but we only process
* small inputs. (20 bytes)
*/
export const encodeBase32 = (buf: Buffer) => {
let result = ``;
let bits = [...buf]
.reverse()
.map((n) => n.toString(2).padStart(8, `0`))
.join(``);
while (bits) {
result += charset[parseInt(bits.slice(0, 5), 2)];
bits = bits.slice(5);
}
return result;
};
/**
* Compute the Nix store path for a fixed-output derivation.
*/
export const computeFixedOutputStorePath = (
name: string,
hashAlgorithm: string,
hash: Buffer,
storePath = `/nix/store` as PortablePath
) => {
const hashHex = hash.toString("hex");
const innerStr = `fixed:out:${hashAlgorithm}:${hashHex}:`;
const innerHash = computeHash(`sha256`, innerStr);
const innerHashHex = innerHash.toString("hex");
const outerStr = `output:out:sha256:${innerHashHex}:${storePath}:${name}`;
const outerHash = computeHash(`sha256`, outerStr);
const outerHash32 = encodeBase32(compressHash(outerHash, 20));
return ppath.join(storePath, `${outerHash32}-${name}` as Filename);
};
/**
* Creates a valid derivation name from a potentially invalid one.
*
* Matches lib.strings.sanitizeDerivationName in Nixpkgs.
*/
export const sanitizeDerivationName = (name: string) =>
name
.replace(/^\.+/, "")
.replace(/[^a-zA-Z0-9+._?=-]+/g, "-")
.slice(0, 207) || "unknown";