pantry/scripts/upload.ts

96 lines
2.7 KiB
TypeScript
Raw Normal View History

2022-08-01 22:43:40 +03:00
#!/usr/bin/env -S tea -E
/*---
args:
- deno
- run
- --allow-net
2022-09-08 23:40:35 +03:00
- --allow-read
2022-08-17 15:22:22 +03:00
- --allow-env
2022-08-01 22:43:40 +03:00
- --import-map={{ srcroot }}/import-map.json
---*/
import { S3 } from "s3"
2022-09-20 14:53:40 +03:00
import { parse_pkg } from "utils"
import { useCache, useFlags } from "hooks"
import { Package } from "types"
import SemVer, * as semver from "semver"
import { dirname, basename } from "deno/path/mod.ts"
2022-08-17 15:22:22 +03:00
useFlags()
2022-08-01 22:43:40 +03:00
if (Deno.args.length === 0) throw new Error("no args supplied")
const s3 = new S3({
accessKeyID: Deno.env.get("AWS_ACCESS_KEY_ID")!,
secretKey: Deno.env.get("AWS_SECRET_ACCESS_KEY")!,
region: "us-east-1",
})
2022-09-13 16:18:47 +03:00
const bucket = s3.getBucket(Deno.env.get("AWS_S3_BUCKET")!)
2022-08-01 22:43:40 +03:00
const encode = (() => { const e = new TextEncoder(); return e.encode.bind(e) })()
2022-09-20 14:53:40 +03:00
const pkgs = args_get("pkgs").map(parse_pkg)
const bottles = args_get("bottles")
const checksums = args_get("checksums")
function args_get(key: string): string[] {
const it = Deno.args[Symbol.iterator]()
while (true) {
const { value, done } = it.next()
if (done) throw new Error()
if (value === `--${key}`) break
}
const rv: string[] = []
while (true) {
const { value, done } = it.next()
if (done) return rv
if (value.startsWith('--')) return rv
rv.push(value)
2022-09-08 23:40:35 +03:00
}
}
for (const [index, pkg] of pkgs.entries()) {
const bottle = bottles[index]
const checksum = checksums[index]
2022-08-01 22:43:40 +03:00
const key = useCache().s3Key(pkg)
//FIXME stream it to S3
const bottle_contents = await Deno.readFile(bottle)
const checksum_contents = fixup_checksum(await Deno.readFile(checksum), basename(bottle))
2022-08-01 22:43:40 +03:00
const versions = await get_versions(pkg)
console.log({ uploading: key })
2022-08-01 22:43:40 +03:00
await bucket.putObject(key, bottle_contents)
await bucket.putObject(`${key}.sha256sum`, checksum_contents)
await bucket.putObject(`${dirname(key)}/versions.txt`, encode(versions.join("\n")))
2022-08-01 22:43:40 +03:00
console.log({ uploaded: key })
}
//end
2022-08-01 22:43:40 +03:00
async function get_versions(pkg: Package): Promise<SemVer[]> {
2022-08-04 18:28:23 +03:00
const prefix = dirname(useCache().s3Key(pkg))
2022-08-01 22:43:40 +03:00
const rsp = await bucket.listObjects({ prefix })
//FIXME? API isnt clear if these nulls indicate failure or not
//NOTE if this is a new package then some empty results is expected
2022-08-02 05:50:33 +03:00
const got = rsp
2022-08-01 22:43:40 +03:00
?.contents
2022-09-20 14:53:40 +03:00
?.compact_map(x => x.key)
2022-08-04 18:28:23 +03:00
.map(x => basename(x))
2022-09-20 14:53:40 +03:00
.compact_map(semver.coerce) //FIXME coerce is too loose
2022-08-02 05:50:33 +03:00
?? []
// have to add pkg.version as put and get are not atomic
return [...new Set([...got, pkg.version])].sort()
2022-08-01 22:43:40 +03:00
}
// Somewhat hacky. We call the bottle on thing locally, and another on the server.
function fixup_checksum(data: Uint8Array, new_file_name: string) {
const checksum = new TextDecoder().decode(data).split(" ")[0]
return new TextEncoder().encode(`${checksum} ${new_file_name}`)
}