2024-01-20 20:52:23 -06:00
use sha2 ::{ Digest , Sha256 } ;
use std ::fs ::OpenOptions ;
use std ::io ::BufRead ;
use std ::io ::Write ;
2023-10-08 11:40:17 -05:00
use std ::{
2024-04-13 04:34:47 -05:00
io ,
2023-11-07 18:27:08 -06:00
path ::Path ,
2023-10-08 11:40:17 -05:00
process ::{ Command , Stdio } ,
} ;
2023-09-15 10:45:12 -05:00
2024-05-14 07:46:44 -05:00
const CAPNP_VERSION : & str = " 1.0.2 " ;
2023-09-16 11:23:56 -05:00
2023-09-15 10:45:12 -05:00
fn get_desired_capnp_version_string ( ) -> String {
2023-09-19 18:12:51 -05:00
CAPNP_VERSION . to_string ( )
}
2023-09-15 10:45:12 -05:00
fn get_capnp_version_string ( ) -> String {
2023-09-16 12:07:12 -05:00
let output = Command ::new ( " capnp " )
2023-09-15 10:45:12 -05:00
. arg ( " --version " )
. stdout ( Stdio ::piped ( ) )
. output ( )
2023-11-07 19:38:36 -06:00
. expect ( " capnp was not in the PATH, and is required for the build when you have changed any .capnp files " ) ;
2023-09-15 10:45:12 -05:00
let s = String ::from_utf8 ( output . stdout )
2023-09-16 12:07:12 -05:00
. expect ( " 'capnp --version' output was not a valid string " )
2023-09-15 10:45:12 -05:00
. trim ( )
. to_owned ( ) ;
if ! s . starts_with ( " Cap'n Proto version " ) {
2023-09-16 12:07:12 -05:00
panic! ( " invalid capnp version string: {} " , s ) ;
2023-09-15 10:45:12 -05:00
}
s [ 20 .. ] . to_owned ( )
}
2024-01-20 20:52:23 -06:00
fn is_input_file_outdated < P , Q > ( input : P , output : Q ) -> io ::Result < bool >
2023-11-07 18:27:08 -06:00
where
2024-01-20 20:52:23 -06:00
P : AsRef < Path > ,
Q : AsRef < Path > ,
2023-11-07 18:27:08 -06:00
{
2024-01-20 20:52:23 -06:00
let Some ( out_bh ) = get_build_hash ( output ) else {
// output file not found or no build hash, we are outdated
return Ok ( true ) ;
} ;
let in_bh = make_build_hash ( input ) ;
Ok ( out_bh ! = in_bh )
}
fn calculate_hash ( lines : std ::io ::Lines < std ::io ::BufReader < std ::fs ::File > > ) -> Vec < u8 > {
let mut hasher = Sha256 ::new ( ) ;
// Build hash of lines, ignoring EOL conventions
for l in lines {
let l = l . unwrap ( ) ;
hasher . update ( l . as_bytes ( ) ) ;
hasher . update ( b " \n " ) ;
2023-10-17 21:13:00 -05:00
}
2024-01-20 20:52:23 -06:00
let out = hasher . finalize ( ) ;
out . to_vec ( )
}
fn get_build_hash < Q : AsRef < Path > > ( output_path : Q ) -> Option < Vec < u8 > > {
let lines = std ::io ::BufReader ::new ( std ::fs ::File ::open ( output_path ) . ok ( ) ? ) . lines ( ) ;
for l in lines {
let l = l . unwrap ( ) ;
2024-01-21 14:50:48 -06:00
if let Some ( rest ) = l . strip_prefix ( " //BUILDHASH: " ) {
return Some ( hex ::decode ( rest ) . unwrap ( ) ) ;
2024-01-20 20:52:23 -06:00
}
}
None
}
fn make_build_hash < P : AsRef < Path > > ( input_path : P ) -> Vec < u8 > {
let input_path = input_path . as_ref ( ) ;
let lines = std ::io ::BufReader ::new ( std ::fs ::File ::open ( input_path ) . unwrap ( ) ) . lines ( ) ;
calculate_hash ( lines )
}
fn append_hash < P : AsRef < Path > , Q : AsRef < Path > > ( input_path : P , output_path : Q ) {
let input_path = input_path . as_ref ( ) ;
let output_path = output_path . as_ref ( ) ;
let lines = std ::io ::BufReader ::new ( std ::fs ::File ::open ( input_path ) . unwrap ( ) ) . lines ( ) ;
let h = calculate_hash ( lines ) ;
2024-03-02 23:42:22 -06:00
let mut out_file = OpenOptions ::new ( ) . append ( true ) . open ( output_path ) . unwrap ( ) ;
2024-01-20 20:52:23 -06:00
writeln! ( out_file , " \n //BUILDHASH:{} " , hex ::encode ( h ) ) . unwrap ( ) ;
2023-11-07 18:27:08 -06:00
}
2023-09-15 10:45:12 -05:00
2023-11-07 18:27:08 -06:00
fn do_capnp_build ( ) {
2023-10-17 21:13:00 -05:00
let desired_capnp_version_string = get_desired_capnp_version_string ( ) ;
let capnp_version_string = get_capnp_version_string ( ) ;
2023-09-15 10:45:12 -05:00
2023-10-17 21:13:00 -05:00
// Check capnp version
let desired_capnp_major_version = desired_capnp_version_string
. split_once ( '.' )
. unwrap ( )
. 0
. parse ::< usize > ( )
. expect ( " should be valid int " ) ;
2023-09-19 18:12:51 -05:00
2023-10-17 21:13:00 -05:00
if capnp_version_string
. split_once ( '.' )
. unwrap ( )
. 0
. parse ::< usize > ( )
. expect ( " should be valid int " )
! = desired_capnp_major_version
{
panic! (
" capnproto version should be major version 1, preferably {} but is {} " ,
desired_capnp_version_string , capnp_version_string
) ;
} else if capnp_version_string ! = desired_capnp_version_string {
println! (
" cargo:warning=capnproto version may be untested: {} " ,
capnp_version_string
) ;
}
2023-09-19 18:12:51 -05:00
2023-10-17 21:13:00 -05:00
::capnpc ::CompilerCommand ::new ( )
. file ( " proto/veilid.capnp " )
2023-11-07 13:19:28 -06:00
. output_path ( " . " )
2023-10-17 21:13:00 -05:00
. run ( )
. expect ( " compiling schema " ) ;
2023-11-07 20:06:29 -06:00
2024-01-20 20:52:23 -06:00
// If successful, append a hash of the input to the output file
append_hash ( " proto/veilid.capnp " , " proto/veilid_capnp.rs " ) ;
2023-11-07 18:27:08 -06:00
}
2023-10-17 21:13:00 -05:00
2023-11-07 18:27:08 -06:00
fn main ( ) {
if std ::env ::var ( " DOCS_RS " ) . is_ok ( )
| | std ::env ::var ( " CARGO_CFG_DOC " ) . is_ok ( )
| | std ::env ::var ( " BUILD_DOCS " ) . is_ok ( )
{
return ;
}
2024-05-14 21:26:58 -05:00
// Check if installed capnp version is different from the desired version - force rebuild then
if get_capnp_version_string ( ) ! = get_desired_capnp_version_string ( ) {
println! ( " cargo:warning=rebuilding proto/veilid_capnp.rs because desired capnp version is different from the installed version " ) ;
do_capnp_build ( ) ;
}
// Check if the hash in the generated file is different from the hash of the input file - force rebuild then (This signifies there's been a change in the input)
else if is_input_file_outdated ( " ./proto/veilid.capnp " , " ./proto/veilid_capnp.rs " ) . unwrap ( ) {
2024-01-20 20:52:23 -06:00
println! ( " cargo:warning=rebuilding proto/veilid_capnp.rs because it has changed from the last generation of proto/veilid.capnp " ) ;
2023-11-07 18:27:08 -06:00
do_capnp_build ( ) ;
}
}