2022-10-17 20:45:32 +03:00
|
|
|
|
import { useCellar, usePantry, usePrefix } from "hooks"
|
2022-09-20 14:53:40 +03:00
|
|
|
|
import { link, hydrate } from "prefab"
|
|
|
|
|
import { Installation, Package } from "types"
|
2022-09-19 16:32:27 +03:00
|
|
|
|
import useShellEnv, { expand } from "hooks/useShellEnv.ts"
|
2022-10-27 17:59:31 +03:00
|
|
|
|
import { run, undent, host, tuplize } from "utils"
|
2022-10-03 18:30:12 +03:00
|
|
|
|
import { str as pkgstr } from "utils/pkg.ts"
|
2022-09-19 16:32:27 +03:00
|
|
|
|
import fix_pkg_config_files from "./fix-pkg-config-files.ts"
|
2022-09-20 14:53:40 +03:00
|
|
|
|
import Path from "path"
|
2022-09-19 16:32:27 +03:00
|
|
|
|
|
|
|
|
|
const cellar = useCellar()
|
|
|
|
|
const pantry = usePantry()
|
2022-09-20 14:53:40 +03:00
|
|
|
|
const { platform } = host()
|
2022-09-19 16:32:27 +03:00
|
|
|
|
|
2022-10-17 20:45:32 +03:00
|
|
|
|
export interface BuildResult {
|
|
|
|
|
installation: Installation
|
|
|
|
|
src?: Path
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default async function _build(pkg: Package): Promise<BuildResult> {
|
2022-09-23 16:54:00 +03:00
|
|
|
|
try {
|
2022-09-28 18:14:46 +03:00
|
|
|
|
return await __build(pkg)
|
2022-09-23 16:54:00 +03:00
|
|
|
|
} catch (e) {
|
2022-09-25 15:41:58 +03:00
|
|
|
|
cellar.keg(pkg).isDirectory()?.isEmpty()?.rm() // don’t leave empty kegs around
|
2022-09-23 16:54:00 +03:00
|
|
|
|
throw e
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-17 20:45:32 +03:00
|
|
|
|
async function __build(pkg: Package): Promise<BuildResult> {
|
2022-09-25 15:41:58 +03:00
|
|
|
|
const [deps, wet, resolved] = await calc_deps()
|
2022-09-19 16:32:27 +03:00
|
|
|
|
await clean()
|
2022-11-28 18:52:20 +03:00
|
|
|
|
const env = await mkenv()
|
2022-09-23 16:54:00 +03:00
|
|
|
|
const dst = cellar.keg(pkg).mkpath()
|
2022-10-17 20:45:32 +03:00
|
|
|
|
const [src, src_tarball] = await fetch_src(pkg) ?? []
|
2022-09-19 16:32:27 +03:00
|
|
|
|
const installation = await build()
|
|
|
|
|
await link(installation)
|
|
|
|
|
await fix_binaries(installation)
|
|
|
|
|
await fix_pkg_config_files(installation)
|
2022-10-17 20:45:32 +03:00
|
|
|
|
return { installation, src: src_tarball }
|
2022-09-19 16:32:27 +03:00
|
|
|
|
|
|
|
|
|
//////// utils
|
|
|
|
|
async function calc_deps() {
|
|
|
|
|
const deps = await pantry.getDeps(pkg)
|
2022-10-26 04:55:49 +03:00
|
|
|
|
const wet = await hydrate([...deps.runtime, ...deps.build])
|
2022-09-19 16:32:27 +03:00
|
|
|
|
deps.runtime.push(...wet.pkgs)
|
2022-09-25 15:41:58 +03:00
|
|
|
|
const resolved = await Promise.all(wet.pkgs.map(pkg => cellar.resolve(pkg)))
|
|
|
|
|
return tuplize(deps, wet, resolved)
|
2022-09-19 16:32:27 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function clean() {
|
|
|
|
|
const installation = await should_clean()
|
2022-11-01 19:14:07 +03:00
|
|
|
|
// If we clean deno.land, it breaks the rest of the process.
|
|
|
|
|
if (installation && installation.pkg.project !== "deno.land") {
|
2022-09-21 09:35:03 +03:00
|
|
|
|
console.log({ cleaning: installation.path })
|
2022-09-23 16:54:00 +03:00
|
|
|
|
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 })
|
|
|
|
|
}
|
2022-09-19 16:32:27 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
2022-09-20 14:53:40 +03:00
|
|
|
|
const wet_dep = () => wet.pkgs.some(x => x.project === pkg.project)
|
2022-09-19 16:32:27 +03:00
|
|
|
|
|
|
|
|
|
// provided this package doesn't transitively depend on itself (yes this happens)
|
|
|
|
|
// clean out the destination prefix first
|
2022-09-20 14:53:40 +03:00
|
|
|
|
if (!wet.bootstrap_required.has(pkg.project) && !depends_on_self() && !wet_dep()) {
|
2022-09-21 10:46:24 +03:00
|
|
|
|
return await cellar.has(pkg)
|
2022-09-19 16:32:27 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-28 18:52:20 +03:00
|
|
|
|
async function mkenv() {
|
|
|
|
|
const env = await useShellEnv({ installations: resolved})
|
2022-09-19 16:32:27 +03:00
|
|
|
|
|
|
|
|
|
if (platform == 'darwin') {
|
2022-10-07 17:51:40 +03:00
|
|
|
|
env['MACOSX_DEPLOYMENT_TARGET'] = ['11.0']
|
2022-09-19 16:32:27 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return env
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function build() {
|
2022-10-17 20:45:32 +03:00
|
|
|
|
const bld = src ?? Path.mktmp({ prefix: pkg.project }).join("wd").mkdir()
|
2022-09-25 15:41:58 +03:00
|
|
|
|
const sh = await pantry.getScript(pkg, 'build', resolved)
|
2022-09-19 16:32:27 +03:00
|
|
|
|
|
2022-12-01 16:42:25 +03:00
|
|
|
|
const brewkit = new URL(import.meta.url).path().parent().parent().join("brewkit")
|
|
|
|
|
|
2022-10-17 20:45:32 +03:00
|
|
|
|
const cmd = bld.parent().join("build.sh").write({ force: true, text: undent`
|
2022-09-19 16:32:27 +03:00
|
|
|
|
#!/bin/bash
|
|
|
|
|
|
|
|
|
|
set -e
|
|
|
|
|
set -o pipefail
|
|
|
|
|
set -x
|
2022-10-17 20:45:32 +03:00
|
|
|
|
cd "${bld}"
|
2022-09-19 16:32:27 +03:00
|
|
|
|
|
2022-10-17 20:45:32 +03:00
|
|
|
|
export SRCROOT="${bld}"
|
2022-10-07 17:51:40 +03:00
|
|
|
|
${expand(env)}
|
2022-09-19 16:32:27 +03:00
|
|
|
|
|
2022-12-01 16:42:25 +03:00
|
|
|
|
export PATH=${brewkit}:"$PATH"
|
2022-09-19 16:32:27 +03:00
|
|
|
|
|
|
|
|
|
${sh}
|
|
|
|
|
`
|
2022-11-09 19:20:28 +03:00
|
|
|
|
}).chmod(0o700)
|
2022-09-19 16:32:27 +03:00
|
|
|
|
|
2022-09-25 15:41:58 +03:00
|
|
|
|
// copy in auxillary files from pantry directory
|
2022-09-25 17:41:14 +03:00
|
|
|
|
for await (const [path, {isFile}] of pantry.getYAML(pkg).path.parent().ls()) {
|
2022-09-25 15:41:58 +03:00
|
|
|
|
if (isFile) {
|
2022-10-17 20:45:32 +03:00
|
|
|
|
path.cp({ into: bld.join("props").mkdir() })
|
2022-09-25 15:41:58 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-17 22:29:15 +03:00
|
|
|
|
await run({ cmd }) // WELCOME TO THE BUILD
|
2022-09-19 16:32:27 +03:00
|
|
|
|
|
|
|
|
|
return { path: dst, pkg }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function fix_binaries(installation: Installation) {
|
2022-10-03 18:30:12 +03:00
|
|
|
|
const prefix = usePrefix().join("tea.xyz/var/pantry/scripts/brewkit")
|
|
|
|
|
const env = {
|
|
|
|
|
TEA_PREFIX: usePrefix().string,
|
|
|
|
|
}
|
2022-09-20 14:53:40 +03:00
|
|
|
|
switch (host().platform) {
|
2022-09-19 16:32:27 +03:00
|
|
|
|
case 'darwin':
|
2022-10-03 18:30:12 +03:00
|
|
|
|
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
|
|
|
|
|
})
|
|
|
|
|
}
|
2022-09-19 16:32:27 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-30 23:18:05 +03:00
|
|
|
|
|
2022-12-07 18:33:12 +03:00
|
|
|
|
async function fetch_src(pkg: Package): Promise<[Path, Path] | undefined> {
|
2022-11-30 23:18:05 +03:00
|
|
|
|
console.log('fetching', pkgstr(pkg))
|
|
|
|
|
|
|
|
|
|
// we run this as a script because we don’t want these deps imported into *this* env
|
|
|
|
|
// since that leads to situations where we depend on things we didn’t expect to
|
|
|
|
|
const script = new URL(import.meta.url).path().parent().parent().join('fetch.ts')
|
|
|
|
|
const proc = Deno.run({
|
|
|
|
|
cmd: [script.string, pkgstr(pkg)],
|
|
|
|
|
stdout: 'piped'
|
|
|
|
|
})
|
|
|
|
|
const out = await proc.output()
|
|
|
|
|
const [dstdir, tarball] = new TextDecoder().decode(out).split("\n")
|
2022-12-07 18:33:12 +03:00
|
|
|
|
if (!tarball) {
|
|
|
|
|
// no tarball, e.g. tea.xyz/gx/cc
|
|
|
|
|
return undefined
|
|
|
|
|
}
|
2022-11-30 23:18:05 +03:00
|
|
|
|
return [new Path(dstdir), new Path(tarball)]
|
|
|
|
|
}
|