1+ #!/usr/bin/env tea
2+
3+ /* ---
4+ dependencies:
5+ gnu.org/tar: ^1.34
6+ tukaani.org/xz: ^5
7+ zlib.net: 1
8+ gnupg.org: ^2
9+ args:
10+ - deno
11+ - run
12+ - --allow-net
13+ - --allow-run
14+ - --allow-env
15+ - --allow-read
16+ - --allow-write
17+ --- */
18+
19+ import { Installation } from "types"
20+ import { useCellar , usePrefix , useFlags , useCache } from "hooks"
21+ import { backticks , panic , run } from "utils"
22+ import { crypto } from "deno/crypto/mod.ts"
23+ import { encode } from "deno/encoding/hex.ts"
24+ import { encode as base64Encode } from "deno/encoding/base64.ts"
25+ import { set_output } from "../../libexec/utils/gha.ts"
26+ import * as ARGV from "../../libexec/utils/args.ts"
27+ import Path from "path"
28+
29+ const cellar = useCellar ( )
30+
31+
32+ //-------------------------------------------------------------------------- main
33+
34+ if ( import . meta. main ) {
35+ useFlags ( )
36+
37+ const compression = Deno . env . get ( "COMPRESSION" ) == 'xz' ? 'xz' : 'gz'
38+ const gpgKey = Deno . env . get ( "GPG_KEY_ID" ) ?? panic ( "missing GPG_KEY_ID" )
39+ const gpgPassphrase = Deno . env . get ( "GPG_PASSPHRASE" ) ?? panic ( "missing GPG_PASSPHRASE" )
40+ const checksums : string [ ] = [ ]
41+ const signatures : string [ ] = [ ]
42+ const bottles : Path [ ] = [ ]
43+
44+ for await ( const pkg of ARGV . pkgs ( ) ) {
45+ console . log ( { bottling : pkg } )
46+
47+ const installation = await cellar . resolve ( pkg )
48+ const path = await bottle ( installation , compression )
49+ const checksum = await sha256 ( path )
50+ const signature = await gpg ( path , { gpgKey, gpgPassphrase } )
51+
52+ console . log ( { bottled : path } )
53+
54+ bottles . push ( path )
55+ checksums . push ( checksum )
56+ signatures . push ( signature )
57+ }
58+
59+ await set_output ( "bottles" , bottles . map ( b => b . relative ( { to : usePrefix ( ) } ) ) )
60+ await set_output ( "checksums" , checksums )
61+ await set_output ( "signatures" , signatures )
62+ }
63+
64+
65+ //------------------------------------------------------------------------- funcs
66+ export async function bottle ( { path : kegdir , pkg } : Installation , compression : 'gz' | 'xz' ) : Promise < Path > {
67+ const tarball = useCache ( ) . path ( { pkg, type : 'bottle' , compression } )
68+ const z = compression == 'gz' ? 'z' : 'J'
69+ const cwd = usePrefix ( )
70+ const cmd = [ "tar" , `c${ z } f` , tarball , kegdir . relative ( { to : cwd } ) ]
71+ await run ( { cmd, cwd } )
72+ return tarball
73+ }
74+
75+ export async function sha256 ( file : Path ) : Promise < string > {
76+ return await Deno . open ( file . string , { read : true } )
77+ . then ( file => crypto . subtle . digest ( "SHA-256" , file . readable ) )
78+ . then ( buf => new TextDecoder ( ) . decode ( encode ( new Uint8Array ( buf ) ) ) )
79+ }
80+
81+ interface GPGCredentials {
82+ gpgKey : string
83+ gpgPassphrase : string
84+ }
85+
86+ async function gpg ( file : Path , { gpgKey, gpgPassphrase } : GPGCredentials ) : Promise < string > {
87+ const rv = await backticks ( {
88+ cmd : [
89+ "gpg" ,
90+ "--detach-sign" ,
91+ "--armor" ,
92+ "--output" ,
93+ "-" ,
94+ "--local-user" ,
95+ gpgKey ,
96+ "--passphrase" ,
97+ gpgPassphrase ,
98+ file . string
99+ ]
100+ } )
101+ return base64Encode ( rv )
102+ }
0 commit comments