@@ -2,7 +2,12 @@ use anyhow::{bail, Result};
22use dialoguer:: theme:: Theme ;
33use goldboot_image:: ImageArch ;
44use serde:: { Deserialize , Serialize } ;
5- use std:: io:: { BufRead , BufReader } ;
5+ use serde_json:: { Map , Value } ;
6+ use std:: {
7+ collections:: HashMap ,
8+ io:: { BufRead , BufReader } ,
9+ } ;
10+ use tracing:: debug;
611use validator:: Validate ;
712
813use crate :: {
@@ -54,6 +59,10 @@ impl CastImage for Goldboot {
5459 let mut qemu = QemuBuilder :: new ( & worker, OsCategory :: Linux )
5560 . vga ( "cirrus" )
5661 . source ( & worker. element . source ) ?
62+ . drive_files ( HashMap :: from ( [ (
63+ "goldboot" . to_string ( ) ,
64+ get_latest_release ( OsCategory :: Linux , worker. arch ) ?,
65+ ) ] ) ) ?
5766 . start ( ) ?;
5867
5968 // Start HTTP
@@ -77,7 +86,8 @@ impl CastImage for Goldboot {
7786 enter!( "root" ) ,
7887 enter!( "r00tme" ) ,
7988 // Install goldboot
80- enter!( format!( "curl -o /usr/bin/goldboot https://github.com/fossable/goldboot/releases/download/goldboot-v0.0.7/goldboot_{}-unknown-linux-gnu" , worker. arch) ) ,
89+ enter!( "mount /dev/vdb /mnt" ) ,
90+ enter!( "cp /mnt/goldboot /usr/bin/goldboot" ) ,
8191 enter!( "chmod +x /usr/bin/goldboot" ) ,
8292 // Skip getty login
8393 enter!
( "sed -i 's|ExecStart=.*$|ExecStart=/usr/bin/goldboot|' /usr/lib/systemd/system/[email protected] " ) , @@ -89,3 +99,80 @@ impl CastImage for Goldboot {
8999 Ok ( ( ) )
90100 }
91101}
102+
103+ /// Download the latest goldboot release.
104+ fn get_latest_release ( os : OsCategory , arch : ImageArch ) -> Result < Vec < u8 > > {
105+ // List releases
106+ let releases: Vec < Value > = reqwest:: blocking:: Client :: new ( )
107+ . get ( "https://api.github.com/repos/fossable/goldboot/releases" )
108+ . header ( "Accept" , "application/vnd.github+json" )
109+ . header ( "X-GitHub-Api-Version" , "2022-11-28" )
110+ . header ( "User-Agent" , "goldboot" )
111+ . send ( ) ?
112+ . json ( ) ?;
113+ debug ! ( count = releases. len( ) , "Total releases" ) ;
114+
115+ // Match the major and minor versions against what we're currently running
116+ let mut releases: Vec < Map < String , Value > > = releases
117+ . into_iter ( )
118+ . filter_map ( |r| match r {
119+ Value :: Object ( release) => match release. get ( "tag_name" ) {
120+ Some ( Value :: String ( name) ) => {
121+ if name. starts_with ( & format ! (
122+ "goldboot-v{}.{}." ,
123+ crate :: built_info:: PKG_VERSION_MAJOR ,
124+ crate :: built_info:: PKG_VERSION_MINOR
125+ ) ) {
126+ Some ( release)
127+ } else {
128+ None
129+ }
130+ }
131+ _ => None ,
132+ } ,
133+ _ => None ,
134+ } )
135+ . collect ( ) ;
136+
137+ debug ! ( count = releases. len( ) , "Matched releases" ) ;
138+
139+ // Sort by patch version
140+ releases. sort_by_key ( |release| match release. get ( "tag_name" ) {
141+ Some ( Value :: String ( name) ) => name. split ( "." ) . last ( ) . unwrap ( ) . parse :: < i64 > ( ) . unwrap ( ) ,
142+ _ => todo ! ( ) ,
143+ } ) ;
144+
145+ // Find asset for the given arch
146+ let asset = match releases. last ( ) . unwrap ( ) . get ( "assets" ) {
147+ Some ( Value :: Array ( assets) ) => assets
148+ . iter ( )
149+ . filter_map ( |a| match a {
150+ Value :: Object ( asset) => match asset. get ( "name" ) {
151+ Some ( Value :: String ( name) ) => {
152+ if name. contains ( & arch. as_github_string ( ) )
153+ && name. contains ( & os. as_github_string ( ) )
154+ {
155+ Some ( asset)
156+ } else {
157+ None
158+ }
159+ }
160+ _ => None ,
161+ } ,
162+ _ => None ,
163+ } )
164+ . last ( ) ,
165+ _ => None ,
166+ } ;
167+
168+ // Download the asset
169+ if let Some ( asset) = asset {
170+ debug ! ( asset = ?asset, "Found asset for download" ) ;
171+ match asset. get ( "browser_download_url" ) {
172+ Some ( Value :: String ( url) ) => Ok ( reqwest:: blocking:: get ( url) ?. bytes ( ) ?. into ( ) ) ,
173+ _ => todo ! ( ) ,
174+ }
175+ } else {
176+ bail ! ( "No release asset found for OS/Arch combination" ) ;
177+ }
178+ }
0 commit comments