mirror of
https://github.com/ivabus/pantry
synced 2025-06-08 08:20:32 +03:00
fixes not incl runtime deps of build deps
Refactor build a bit. This was causing build failure for GHC on linux as the system perl didn't have something autoconf needed. TODO: infuser shouldn't have perl installed!
This commit is contained in:
parent
d680562710
commit
54781e96e1
6 changed files with 254 additions and 52 deletions
|
@ -3,3 +3,12 @@
|
|||
```sh
|
||||
scripts/ls.ts | xargs scripts/sort.ts | xargs scripts/build.ts
|
||||
```
|
||||
|
||||
# test all
|
||||
|
||||
`each.ts` reduces output for each input to a concise ✅ or ❌ based on exit
|
||||
status.
|
||||
|
||||
```sh
|
||||
scripts/ls.ts | xargs scripts/each.ts scripts/test.ts
|
||||
```
|
||||
|
|
|
@ -12,31 +12,30 @@ args:
|
|||
- --import-map={{ srcroot }}/import-map.json
|
||||
---*/
|
||||
|
||||
import useSourceUnarchiver from "hooks/useSourceUnarchiver.ts"
|
||||
import useCellar from "hooks/useCellar.ts"
|
||||
import usePantry from "hooks/usePantry.ts"
|
||||
import useCache from "hooks/useCache.ts"
|
||||
import { lvl1 as link } from "prefab/link.ts"
|
||||
import build from "./build.prefab.ts"
|
||||
import build from "./build/build.ts"
|
||||
import { Package, parsePackageRequirement, semver } from "types"
|
||||
import useFlags from "hooks/useFlags.ts"
|
||||
import usePlatform from "hooks/usePlatform.ts"
|
||||
import hydrate from "prefab/hydrate.ts"
|
||||
import useCellar from "hooks/useCellar.ts"
|
||||
|
||||
useFlags()
|
||||
|
||||
const pantry = usePantry()
|
||||
const cellar = useCellar()
|
||||
|
||||
const dry = Deno.args.map(parsePackageRequirement)
|
||||
const gha = !!Deno.env.get("GITHUB_ACTIONS")
|
||||
const group_it = gha && dry.length > 1
|
||||
|
||||
const rv: Package[] = []
|
||||
|
||||
if (cellar.prefix.string != "/opt") {
|
||||
console.error({ TEA_PREFIX: cellar.prefix.string })
|
||||
throw new Error("builds must be performed in /opt (try TEA_PREFIX=/opt)")
|
||||
}
|
||||
|
||||
for (const pkgrq of dry) {
|
||||
const versions = await pantry.getVersions(pkgrq)
|
||||
const version = semver.maxSatisfying(versions, pkgrq.constraint)
|
||||
if (!version) throw "no-version-found"
|
||||
if (!version) throw new Error(`no-version-found: ${pkgrq.project}`)
|
||||
const pkg = { project: pkgrq.project, version }
|
||||
|
||||
if (group_it) {
|
||||
|
@ -45,48 +44,7 @@ for (const pkgrq of dry) {
|
|||
console.log({ building: pkgrq.project })
|
||||
}
|
||||
|
||||
// Get the source
|
||||
const prebuild = async () => {
|
||||
const dstdir = cellar.mkpath(pkg).join("src")
|
||||
const { url, stripComponents } = await pantry.getDistributable(pkg)
|
||||
const { download } = useCache()
|
||||
const zip = await download({ pkg, url, type: 'src' })
|
||||
await useSourceUnarchiver().unarchive({
|
||||
dstdir,
|
||||
zipfile: zip,
|
||||
stripComponents
|
||||
})
|
||||
}
|
||||
|
||||
//TODO this was already calculated in `sort` and should not be recalculated
|
||||
const deps = await pantry.getDeps(pkg)
|
||||
const wet = await hydrate(deps.runtime, pkg => pantry.getDeps(pkg).then(x => x.runtime))
|
||||
deps.runtime.push(...wet.pkgs)
|
||||
|
||||
// only required as we aren't passing everything into hydrate
|
||||
const depends_on_self = () => deps.build.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()) {
|
||||
const installation = await cellar.isInstalled(pkg)
|
||||
if (installation) {
|
||||
console.log({ cleaning: installation.path })
|
||||
for await (const [path, {name}] of installation.path.ls()) {
|
||||
if (name == 'src') continue
|
||||
path.rm({ recursive: true })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const env = usePlatform().platform == 'darwin'
|
||||
? {MACOSX_DEPLOYMENT_TARGET: ['11.0']}
|
||||
: undefined
|
||||
|
||||
// Build and link
|
||||
const path = await build({ pkg, deps, prebuild, env })
|
||||
await link({ path, pkg })
|
||||
|
||||
await build(pkg)
|
||||
rv.push(pkg)
|
||||
|
||||
if (group_it) {
|
||||
|
|
135
scripts/build/build.ts
Normal file
135
scripts/build/build.ts
Normal file
|
@ -0,0 +1,135 @@
|
|||
import useSourceUnarchiver from "hooks/useSourceUnarchiver.ts"
|
||||
import useCellar from "hooks/useCellar.ts"
|
||||
import usePantry from "hooks/usePantry.ts"
|
||||
import useCache from "hooks/useCache.ts"
|
||||
import { lvl1 as link } from "prefab/link.ts"
|
||||
import { Installation, Package, Path, semver } from "types"
|
||||
import usePlatform from "hooks/usePlatform.ts"
|
||||
import hydrate from "prefab/hydrate.ts"
|
||||
import useShellEnv, { expand } from "hooks/useShellEnv.ts"
|
||||
import { run, undent } from "utils"
|
||||
import fix_pkg_config_files from "./fix-pkg-config-files.ts"
|
||||
import fix_linux_rpaths from "./fix-linux-rpaths.ts"
|
||||
|
||||
const cellar = useCellar()
|
||||
const pantry = usePantry()
|
||||
const { platform } = usePlatform()
|
||||
|
||||
export default async function _build(pkg: Package) {
|
||||
const [deps, wet] = await calc_deps()
|
||||
await clean()
|
||||
const env = await mkenv()
|
||||
const dst = cellar.mkpath(pkg)
|
||||
const src = await fetch_src(pkg)
|
||||
const installation = await build()
|
||||
await link(installation)
|
||||
await fix_binaries(installation)
|
||||
await fix_pkg_config_files(installation)
|
||||
|
||||
return installation
|
||||
|
||||
//////// 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)
|
||||
function tuplize<T extends any[]>(...elements: T) { return elements }
|
||||
return tuplize(deps, wet)
|
||||
}
|
||||
|
||||
async function clean() {
|
||||
const installation = await should_clean()
|
||||
if (!installation) return
|
||||
console.log({ cleaning: installation.path })
|
||||
for await (const [path, {name}] of installation.path.ls()) {
|
||||
if (name == 'src') continue
|
||||
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)
|
||||
|
||||
// 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()) {
|
||||
return await cellar.isInstalled(pkg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function mkenv() {
|
||||
const env = await useShellEnv([...deps.runtime, ...deps.build])
|
||||
|
||||
if (env.pending.length) {
|
||||
console.error({uninstalled: env.pending})
|
||||
throw new Error("uninstalled")
|
||||
}
|
||||
|
||||
if (platform == 'darwin') {
|
||||
env.vars['MACOSX_DEPLOYMENT_TARGET'] = ['11.0']
|
||||
}
|
||||
|
||||
return env
|
||||
}
|
||||
|
||||
async function build() {
|
||||
const sh = await pantry.getScript(pkg, 'build')
|
||||
|
||||
const cmd = dst.join("build.sh").write({ force: true, text: undent`
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
set -x
|
||||
cd "${src}"
|
||||
|
||||
${expand(env.vars)}
|
||||
|
||||
${/*FIXME hardcoded paths*/ ''}
|
||||
export PATH=/opt/tea.xyz/var/pantry/scripts/brewkit:"$PATH"
|
||||
|
||||
${sh}
|
||||
`
|
||||
}).chmod(0o500)
|
||||
|
||||
await run({ cmd }) // THE BUILD
|
||||
|
||||
return { path: dst, pkg }
|
||||
}
|
||||
|
||||
async function fix_binaries(installation: Installation) {
|
||||
switch (usePlatform().platform) {
|
||||
case 'darwin':
|
||||
await fix_macho(installation)
|
||||
break
|
||||
case 'linux': {
|
||||
const self = {project: pkg.project, constraint: new semver.Range(`=${pkg.version}`)}
|
||||
await fix_linux_rpaths(installation, [...deps.runtime, self])
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
async function fetch_src(pkg: Package): Promise<Path> {
|
||||
const dstdir = cellar.mkpath(pkg).join("src")
|
||||
const { url, stripComponents } = await pantry.getDistributable(pkg)
|
||||
const { download } = useCache()
|
||||
const zip = await download({ pkg, url, type: 'src' })
|
||||
await useSourceUnarchiver().unarchive({
|
||||
dstdir,
|
||||
zipfile: zip,
|
||||
stripComponents
|
||||
})
|
||||
return dstdir
|
||||
}
|
||||
|
||||
async function fix_macho(installation: Installation) {
|
||||
const d = new Path(new URL(import.meta.url).pathname).parent()
|
||||
const walk = ['bin', 'lib', 'libexec'].map(x => installation.path.join(x)).filter(x => x.isDirectory())
|
||||
await run({
|
||||
cmd: [d.join('fix-machos.rb'), installation.path, ...walk],
|
||||
env: {
|
||||
TEA_PREFIX: cellar.prefix.string,
|
||||
}
|
||||
})
|
||||
}
|
28
scripts/build/fix-pkg-config-files.ts
Normal file
28
scripts/build/fix-pkg-config-files.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { Installation } from "types"
|
||||
import { Path } from "types"
|
||||
|
||||
|
||||
export default async function fix_pkg_config_files(installation: Installation) {
|
||||
for await (const pcfile of find_pkg_config_files(installation)) {
|
||||
const orig = await pcfile.read()
|
||||
const relative_path = installation.path.relative({ to: pcfile.parent() })
|
||||
const text = orig.replace(installation.path.string, `\${pcfiledir}/${relative_path}`)
|
||||
if (orig !== text) {
|
||||
console.verbose({ fixed: pcfile })
|
||||
pcfile.write({text, force: true})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//NOTE currently we only support pc files in lib/pkgconfig
|
||||
// we aim to standardize on this but will relent if a package is found
|
||||
// that uses share and other tools that build against it only accept that
|
||||
async function *find_pkg_config_files(installation: Installation): AsyncIterable<Path> {
|
||||
const pcdir = installation.path.join("lib/pkgconfig")
|
||||
if (!pcdir.isDirectory()) return
|
||||
for await (const [path, { isFile }] of pcdir.ls()) {
|
||||
if (isFile && path.extname() == ".pc") {
|
||||
yield path
|
||||
}
|
||||
}
|
||||
}
|
27
scripts/each.ts
Executable file
27
scripts/each.ts
Executable file
|
@ -0,0 +1,27 @@
|
|||
#!/usr/bin/env -S tea -E
|
||||
|
||||
/*---
|
||||
args:
|
||||
- deno
|
||||
- run
|
||||
- --allow-run
|
||||
- --allow-read
|
||||
- --allow-env
|
||||
- --import-map={{ srcroot }}/import-map.json
|
||||
---*/
|
||||
|
||||
const args = [...Deno.args]
|
||||
const via = args.shift()
|
||||
|
||||
for (const arg of args) {
|
||||
const proc = Deno.run({
|
||||
stdout: "null", stderr: "null",
|
||||
cmd: [via!, arg]
|
||||
})
|
||||
const status = await proc.status()
|
||||
if (status.code !== 0) {
|
||||
console.error(`${arg} ❌`)
|
||||
} else {
|
||||
console.info(`${arg} ✅`)
|
||||
}
|
||||
}
|
45
scripts/fetch.ts
Executable file
45
scripts/fetch.ts
Executable file
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/env -S tea -E
|
||||
|
||||
/*---
|
||||
args:
|
||||
- deno
|
||||
- run
|
||||
- --allow-net
|
||||
- --allow-run
|
||||
- --allow-read
|
||||
- --allow-write={{ tea.prefix }}
|
||||
- --allow-env
|
||||
- --import-map={{ srcroot }}/import-map.json
|
||||
---*/
|
||||
|
||||
import usePantry from "hooks/usePantry.ts"
|
||||
import useCache from "hooks/useCache.ts"
|
||||
import useCellar from "hooks/useCellar.ts"
|
||||
import useSourceUnarchiver from "hooks/useSourceUnarchiver.ts"
|
||||
import { parsePackageRequirement, semver } from "types"
|
||||
import { Command } from "cliffy/command/mod.ts"
|
||||
import { print } from "utils"
|
||||
|
||||
const { args } = await new Command()
|
||||
.name("tea-fetch-src")
|
||||
.arguments("<pkgspec:string>")
|
||||
.parse(Deno.args)
|
||||
|
||||
const pantry = usePantry()
|
||||
const req = parsePackageRequirement(args[0])
|
||||
const versions = await pantry.getVersions(req)
|
||||
const version = semver.maxSatisfying(versions, req.constraint)
|
||||
if (!version) throw "no-version-found"
|
||||
const pkg = { project: req.project, version }; console.debug(pkg)
|
||||
|
||||
const dstdir = useCellar().mkpath(pkg).join("src")
|
||||
const { url, stripComponents } = await pantry.getDistributable(pkg)
|
||||
const { download } = useCache()
|
||||
const zip = await download({ pkg, url, type: 'src' })
|
||||
await useSourceUnarchiver().unarchive({
|
||||
dstdir,
|
||||
zipfile: zip,
|
||||
stripComponents
|
||||
})
|
||||
|
||||
await print(`${dstdir}\n`)
|
Loading…
Reference in a new issue