291 lines
10 KiB
JavaScript
Executable File
291 lines
10 KiB
JavaScript
Executable File
#! /usr/bin/env nix-shell
|
|
/*
|
|
#! nix-shell -i zx -p zx
|
|
*/
|
|
|
|
console.log(process.cwd())
|
|
|
|
const custompkgs = (await $`git rev-parse --show-toplevel`).stdout.trim()
|
|
const $custompkgs = $({
|
|
cwd:custompkgs
|
|
})
|
|
const nixpkgs = "<nixpkgs>"
|
|
|
|
const dummy_hash = 'sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA='
|
|
|
|
const lockfile_file = './info.json'
|
|
const lockfile_initial = fs.readJsonSync(lockfile_file)
|
|
function flush_to_file() {
|
|
fs.writeJsonSync(lockfile_file, lockfile, { spaces: 2 })
|
|
}
|
|
const flush_to_file_proxy = {
|
|
get(obj, prop) {
|
|
const value = obj[prop]
|
|
return typeof value == 'object' ? new Proxy(value, flush_to_file_proxy) : value
|
|
},
|
|
|
|
set(obj, prop, value) {
|
|
obj[prop] = value
|
|
flush_to_file()
|
|
return true
|
|
},
|
|
}
|
|
const lockfile = new Proxy(structuredClone(lockfile_initial), flush_to_file_proxy)
|
|
const ungoogled_rev = argv['ungoogled-chromium-rev']
|
|
|
|
for (const attr_path of Object.keys(lockfile)) {
|
|
const ungoogled = attr_path === 'ungoogled-chromium'
|
|
|
|
if (!argv[attr_path] && !(ungoogled && ungoogled_rev)) {
|
|
console.log(`[${attr_path}] Skipping ${attr_path}. Pass --${attr_path} as argument to update.`)
|
|
continue
|
|
}
|
|
|
|
const version_nixpkgs = !ungoogled ? lockfile[attr_path].version : lockfile[attr_path].deps['ungoogled-patches'].rev
|
|
const version_upstream = !ungoogled ? await get_latest_chromium_release('linux') :
|
|
ungoogled_rev ?? await get_latest_ungoogled_release()
|
|
|
|
console.log(`[${attr_path}] ${chalk.red(version_nixpkgs)} (nixpkgs)`)
|
|
console.log(`[${attr_path}] ${chalk.green(version_upstream)} (upstream)`)
|
|
|
|
if (ungoogled_rev || version_greater_than(version_upstream, version_nixpkgs)) {
|
|
console.log(`[${attr_path}] ${chalk.green(version_upstream)} from upstream is newer than our ${chalk.red(version_nixpkgs)}...`)
|
|
|
|
let ungoogled_patches = ungoogled ? await fetch_ungoogled(version_upstream) : undefined
|
|
|
|
// For ungoogled-chromium we need to remove the patch revision (e.g. 130.0.6723.116-1 -> 130.0.6723.116)
|
|
// by just using the chromium_version.txt content from the patches checkout (to also work with commit revs).
|
|
const version_chromium = ungoogled_patches?.chromium_version ?? version_upstream
|
|
|
|
const chromium_rev = await chromium_resolve_tag_to_rev(version_chromium)
|
|
|
|
lockfile[attr_path] = {
|
|
version: version_chromium,
|
|
chromedriver: !ungoogled ? await fetch_chromedriver_binaries(await get_latest_chromium_release('mac')) : undefined,
|
|
deps: {
|
|
depot_tools: {},
|
|
gn: await fetch_gn(chromium_rev, lockfile_initial[attr_path].deps.gn),
|
|
'ungoogled-patches': !ungoogled ? undefined : {
|
|
rev: ungoogled_patches.rev,
|
|
hash: ungoogled_patches.hash,
|
|
},
|
|
npmHash: dummy_hash,
|
|
},
|
|
DEPS: {},
|
|
}
|
|
|
|
const depot_tools = await fetch_depot_tools(chromium_rev, lockfile_initial[attr_path].deps.depot_tools)
|
|
lockfile[attr_path].deps.depot_tools = {
|
|
rev: depot_tools.rev,
|
|
hash: depot_tools.hash,
|
|
}
|
|
|
|
// DEPS update loop
|
|
lockfile[attr_path].DEPS = await resolve_DEPS(depot_tools.out, chromium_rev)
|
|
for (const [path, value] of Object.entries(lockfile[attr_path].DEPS)) {
|
|
delete value.fetcher
|
|
delete value.postFetch
|
|
|
|
if (value.url === 'https://chromium.googlesource.com/chromium/src.git') {
|
|
value.recompress = true
|
|
}
|
|
|
|
const cache_hit = (() => {
|
|
for (const attr_path in lockfile_initial) {
|
|
const cache = lockfile_initial[attr_path].DEPS[path]
|
|
const hits_cache =
|
|
cache !== undefined &&
|
|
value.url === cache.url &&
|
|
value.rev === cache.rev &&
|
|
value.recompress === cache.recompress &&
|
|
cache.hash !== undefined &&
|
|
cache.hash !== '' &&
|
|
cache.hash !== dummy_hash
|
|
|
|
if (hits_cache) {
|
|
cache.attr_path = attr_path
|
|
return cache;
|
|
}
|
|
}
|
|
})();
|
|
|
|
if (cache_hit) {
|
|
console.log(`[${chalk.green(path)}] Reusing hash from previous info.json for ${cache_hit.url}@${cache_hit.rev} from ${cache_hit.attr_path}`)
|
|
value.hash = cache_hit.hash
|
|
continue
|
|
}
|
|
|
|
console.log(`[${chalk.red(path)}] FOD prefetching ${value.url}@${value.rev}...`)
|
|
// value.hash = await prefetch_FOD('./package.nix', '-A', `${attr_path}.browser.passthru.chromiumDeps."${path}"`)
|
|
value.hash = await prefetch_flake_FOD(`.#helium-browser.browser.passthru.chromiumDeps."${path}"`)
|
|
// console.log(`[${chalk.green(path)}] FOD prefetching successful`)
|
|
}
|
|
|
|
// lockfile[attr_path].deps.npmHash = await prefetch_FOD('./package.nix', '-A', `${attr_path}.browser.passthru.npmDeps`)
|
|
lockfile[attr_path].deps.npmHash = await prefetch_flake_FOD(`.#helium-browser.browser.passthru.npmDeps`)
|
|
|
|
console.log(chalk.green(`[${attr_path}] Done updating ${attr_path} from ${version_nixpkgs} to ${version_upstream}!`))
|
|
}
|
|
}
|
|
|
|
|
|
async function fetch_gn(chromium_rev, gn_previous) {
|
|
const DEPS_file = await get_gitiles_file('https://chromium.googlesource.com/chromium/src', chromium_rev, 'DEPS')
|
|
const { rev } = /^\s+'gn_version': 'git_revision:(?<rev>.+)',$/m.exec(DEPS_file).groups
|
|
|
|
const cache_hit = rev === gn_previous.rev;
|
|
if (cache_hit) {
|
|
return gn_previous
|
|
}
|
|
|
|
const commit_date = await get_gitiles_commit_date('https://gn.googlesource.com/gn', rev)
|
|
const version = `0-unstable-${commit_date}`
|
|
|
|
const expr = [`(import ${nixpkgs} {}).gn.override { version = "${version}"; rev = "${rev}"; hash = ""; }`]
|
|
const derivation = await $`nix-instantiate --expr ${expr}`
|
|
|
|
return {
|
|
version,
|
|
rev,
|
|
hash: await prefetch_FOD(derivation),
|
|
}
|
|
}
|
|
|
|
|
|
async function get_gitiles_commit_date(base_url, rev) {
|
|
const url = `${base_url}/+/${rev}?format=json`
|
|
const response = await (await fetch(url)).text()
|
|
const json = JSON.parse(response.replace(`)]}'\n`, ''))
|
|
|
|
const date = new Date(json.committer.time)
|
|
return date.toISOString().split("T")[0]
|
|
}
|
|
|
|
|
|
async function fetch_chromedriver_binaries(version) {
|
|
// https://developer.chrome.com/docs/chromedriver/downloads/version-selection
|
|
const prefetch = async (url) => {
|
|
const expr = [`(import ${nixpkgs} {}).fetchzip { url = "${url}"; hash = ""; }`]
|
|
const derivation = await $`nix-instantiate --expr ${expr}`
|
|
return await prefetch_FOD(derivation)
|
|
}
|
|
|
|
// if the URL ever changes, the URLs in the chromedriver derivations need updating as well!
|
|
const url = (platform) => `https://storage.googleapis.com/chrome-for-testing-public/${version}/${platform}/chromedriver-${platform}.zip`
|
|
return {
|
|
version,
|
|
hash_darwin: await prefetch(url('mac-x64')),
|
|
hash_darwin_aarch64: await prefetch(url('mac-arm64')),
|
|
}
|
|
}
|
|
|
|
|
|
async function chromium_resolve_tag_to_rev(tag) {
|
|
const url = `https://chromium.googlesource.com/chromium/src/+/refs/tags/${tag}?format=json`
|
|
const response = await (await fetch(url)).text()
|
|
const json = JSON.parse(response.replace(`)]}'\n`, ''))
|
|
return json.commit
|
|
}
|
|
|
|
|
|
async function resolve_DEPS(depot_tools_checkout, chromium_rev) {
|
|
const { stdout } = await $`./depot_tools.py ${depot_tools_checkout} ${chromium_rev}`
|
|
const deps = JSON.parse(stdout)
|
|
return Object.fromEntries(Object.entries(deps).map(([k, { url, rev, hash }]) => [k, { url, rev, hash }]))
|
|
}
|
|
|
|
|
|
async function get_latest_chromium_release(platform) {
|
|
const url = `https://versionhistory.googleapis.com/v1/chrome/platforms/${platform}/channels/stable/versions/all/releases?` + new URLSearchParams({
|
|
order_by: 'version desc',
|
|
filter: 'endtime=none,fraction>=0.5'
|
|
})
|
|
|
|
const response = await (await fetch(url)).json()
|
|
return response.releases[0].version
|
|
}
|
|
|
|
|
|
async function get_latest_ungoogled_release() {
|
|
const ungoogled_tags = await (await fetch('https://api.github.com/repos/imputnet/helium/tags')).json()
|
|
// console.log(ungoogled_tags)
|
|
// const chromium_releases = await (await fetch('https://versionhistory.googleapis.com/v1/chrome/platforms/linux/channels/stable/versions/all/releases')).json()
|
|
// const chromium_release_map = chromium_releases.releases.map((x) => x.version)
|
|
// return "0.5.2" // TODO: figure out how to actually properly do this stuff
|
|
return ungoogled_tags[0].name
|
|
}
|
|
|
|
|
|
async function fetch_ungoogled(rev) {
|
|
const expr = (hash) => [`(import ${nixpkgs} {}).fetchFromGitHub { owner = "imputnet"; repo = "helium"; rev = "${rev}"; hash = "${hash}"; }`]
|
|
const hash = await prefetch_FOD('--expr', expr(''))
|
|
|
|
const checkout = await $`nix-build --expr ${expr(hash)}`
|
|
const checkout_path = checkout.stdout.trim()
|
|
|
|
await fs.copy(path.join(checkout_path, 'flags.gn'), './ungoogled-flags.toml')
|
|
|
|
const chromium_version = (await fs.readFile(path.join(checkout_path, 'chromium_version.txt'))).toString().trim()
|
|
|
|
console.log(`[ungoogled-chromium] ${chalk.green(rev)} patch revision resolves to chromium version ${chalk.green(chromium_version)}`)
|
|
|
|
return {
|
|
rev,
|
|
hash,
|
|
chromium_version,
|
|
}
|
|
}
|
|
|
|
|
|
function version_greater_than(greater, than) {
|
|
return greater.localeCompare(than, undefined, { numeric: true, sensitivity: 'base' }) === 1
|
|
}
|
|
|
|
|
|
async function get_gitiles_file(repo, rev, path) {
|
|
const base64 = await (await fetch(`${repo}/+/${rev}/${path}?format=TEXT`)).text()
|
|
return Buffer.from(base64, 'base64').toString('utf-8')
|
|
}
|
|
|
|
|
|
async function fetch_depot_tools(chromium_rev, depot_tools_previous) {
|
|
const depot_tools_rev = await get_gitiles_file('https://chromium.googlesource.com/chromium/src', chromium_rev, 'third_party/depot_tools')
|
|
const hash = depot_tools_rev === depot_tools_previous.rev ? depot_tools_previous.hash : ''
|
|
return await prefetch_gitiles('https://chromium.googlesource.com/chromium/tools/depot_tools', depot_tools_rev, hash)
|
|
}
|
|
|
|
|
|
async function prefetch_gitiles(url, rev, hash = '') {
|
|
const expr = () => [`(import ${nixpkgs} {}).fetchFromGitiles { url = "${url}"; rev = "${rev}"; hash = "${hash}"; }`]
|
|
|
|
if (hash === '') {
|
|
hash = await prefetch_FOD('--expr', expr())
|
|
}
|
|
|
|
const { stdout } = await $`nix-build --expr ${expr()}`
|
|
return {
|
|
url,
|
|
rev,
|
|
hash,
|
|
out: stdout.trim(),
|
|
}
|
|
}
|
|
|
|
|
|
async function prefetch_FOD(...args) {
|
|
const { stderr } = await $`nix-build ${args}`.nothrow()
|
|
const hash = /\s+got:\s+(?<hash>.+)$/m.exec(stderr)?.groups?.hash
|
|
if (hash == undefined) {
|
|
throw new Error(chalk.red('Expected to find hash in nix-build stderr output:') + stderr)
|
|
}
|
|
return hash
|
|
}
|
|
async function prefetch_flake_FOD(...args) {
|
|
const { stderr } = await $custompkgs`nix build ${args}`.nothrow()
|
|
const hash = /\s+got:\s+(?<hash>.+)$/m.exec(stderr)?.groups?.hash
|
|
if (hash == undefined) {
|
|
throw new Error(chalk.red('Expected to find hash in nix build stderr output:') + stderr)
|
|
}
|
|
return hash
|
|
}
|