pantry/scripts/build/build.ts
Max Howell f836b167a1 “superenv” (#185)
* fixes for dylib ids on darwin (sadly elaborate)

* wip
2022-10-17 13:45:32 -04:00

144 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useCellar, usePantry, usePrefix } from "hooks"
import { link, hydrate } from "prefab"
import { Installation, Package } from "types"
import useShellEnv, { expand } from "hooks/useShellEnv.ts"
import { run, undent, host, tuplize, panic } from "utils"
import { str as pkgstr } from "utils/pkg.ts"
import fix_pkg_config_files from "./fix-pkg-config-files.ts"
import Path from "path"
import { fetch_src } from "../fetch.ts";
const cellar = useCellar()
const pantry = usePantry()
const { platform } = host()
export interface BuildResult {
installation: Installation
src?: Path
}
export default async function _build(pkg: Package): Promise<BuildResult> {
try {
return await __build(pkg)
} catch (e) {
cellar.keg(pkg).isDirectory()?.isEmpty()?.rm() // dont leave empty kegs around
throw e
}
}
async function __build(pkg: Package): Promise<BuildResult> {
const [deps, wet, resolved] = await calc_deps()
await clean()
const env = mkenv()
const dst = cellar.keg(pkg).mkpath()
const [src, src_tarball] = await fetch_src(pkg) ?? []
const installation = await build()
await link(installation)
await fix_binaries(installation)
await fix_pkg_config_files(installation)
return { installation, src: src_tarball }
//////// utils
async function calc_deps() {
const deps = await pantry.getDeps(pkg)
const wet = await hydrate([...deps.runtime, ...deps.build], pkg => pantry.getDeps(pkg).then(x => x.runtime))
deps.runtime.push(...wet.pkgs)
const resolved = await Promise.all(wet.pkgs.map(pkg => cellar.resolve(pkg)))
return tuplize(deps, wet, resolved)
}
async function clean() {
const installation = await should_clean()
if (installation) {
console.log({ cleaning: installation.path })
for await (const [path] of installation.path.ls()) {
// we delete contents rather than the directory itself to prevent broken vx.y symlinks
path.rm({ recursive: true })
}
}
async function should_clean() {
// only required as we aren't passing everything into hydrate
const depends_on_self = () => deps.build.some(x => x.project === pkg.project)
const wet_dep = () => wet.pkgs.some(x => x.project === pkg.project)
// provided this package doesn't transitively depend on itself (yes this happens)
// clean out the destination prefix first
if (!wet.bootstrap_required.has(pkg.project) && !depends_on_self() && !wet_dep()) {
return await cellar.has(pkg)
}
}
}
function mkenv() {
const env = useShellEnv({ installations: resolved})
if (platform == 'darwin') {
env['MACOSX_DEPLOYMENT_TARGET'] = ['11.0']
}
return env
}
async function build() {
const bld = src ?? Path.mktmp({ prefix: pkg.project }).join("wd").mkdir()
const sh = await pantry.getScript(pkg, 'build', resolved)
const cmd = bld.parent().join("build.sh").write({ force: true, text: undent`
#!/bin/bash
set -e
set -o pipefail
set -x
cd "${bld}"
export SRCROOT="${bld}"
${expand(env)}
${/*FIXME hardcoded paths*/ ''}
export PATH=/opt/tea.xyz/var/pantry/scripts/brewkit:"$PATH"
${sh}
`
}).chmod(0o500)
// copy in auxillary files from pantry directory
for await (const [path, {isFile}] of pantry.getYAML(pkg).path.parent().ls()) {
if (isFile) {
path.cp({ into: bld.join("props").mkdir() })
}
}
await run({ cmd }) // THE BUILD
return { path: dst, pkg }
}
async function fix_binaries(installation: Installation) {
const prefix = usePrefix().join("tea.xyz/var/pantry/scripts/brewkit")
const env = {
TEA_PREFIX: usePrefix().string,
}
switch (host().platform) {
case 'darwin':
return await run({
cmd: [
prefix.join('fix-machos.rb'),
installation.path,
...['bin', 'lib', 'libexec'].map(x => installation.path.join(x)).filter(x => x.isDirectory())
],
env
})
case 'linux':
return await run({
cmd: [
prefix.join('fix-elf.ts'),
installation.path,
...[...deps.runtime, pkg].map(pkgstr)
],
env
})
}
}
}