@ -72,11 +72,143 @@ mod test {
}
}
fn parse_args ( ) -> Result < config ::Config , error ::Error >
#[ inline ]
fn absolute ( path : impl AsRef < std ::path ::Path > ) -> std ::path ::PathBuf
{
std ::fs ::canonicalize ( path ) . expect ( "Invalid path internal" )
}
#[ cfg(feature= " threads " ) ]
async fn rebase_one_async ( path : impl AsRef < std ::path ::Path > , hash : hash ::Sha256Hash ) -> Result < Option < ( std ::path ::PathBuf , hash ::Sha256Hash ) > , error ::Error >
{
use std ::{
convert ::TryInto ,
} ;
use tokio ::{
fs ::{
OpenOptions ,
} ,
} ;
let path = path . as_ref ( ) ;
let mut file = OpenOptions ::new ( )
. read ( true )
. open ( path ) . await ? ;
let sz : usize = file . metadata ( ) . await ? . len ( ) . try_into ( ) . or ( Err ( error ::Error ::Arch ( Some ( "Filesize is too large to be known. you have likely compiled the binary for 32-bit architecture or less. This shouldn't happen on 64-bit systems." ) ) ) ) ? ;
let mut result = hash ::Sha256Hash ::default ( ) ;
error ::check_size ( sz , hash ::compute_async ( & mut file , & mut result ) . await ? ) ? ;
println! ( "Computed {:?}" , path ) ;
if hash ! = result {
Ok ( Some ( ( path . to_owned ( ) , result ) ) )
} else {
Ok ( None )
}
}
#[ cfg(feature= " threads " ) ]
async fn rebase ( config : config ::Rebase ) -> Result < ( ) , Box < dyn std ::error ::Error > >
{
use std ::{
path ::{
Path ,
} ,
} ;
use tokio ::{
fs ::{
OpenOptions ,
} ,
} ;
let mut hashes = container ::DupeMap ::new ( ) ;
for ( transient , load ) in config . load . iter ( ) . map ( | x | ( false , x ) ) . chain ( config . save . iter ( ) . map ( | x | ( true , x ) ) )
{
let load = Path ::new ( load ) ;
if load . exists ( ) {
if load . is_file ( ) {
if let Ok ( mut file ) = OpenOptions ::new ( )
. read ( true )
. open ( load ) . await
{
match hashes . load_async ( & mut file , transient ) . await {
Err ( e ) if ! transient = > return Err ( format! ( "Failed to load required {:?}: {}" , file , e ) ) ? ,
_ = > ( ) ,
} ;
}
}
}
}
let mut remove = Vec ::new ( ) ;
let mut children = Vec ::with_capacity ( hashes . cache_len ( ) ) ;
for ( path , ( hash , trans ) ) in hashes . cache_iter ( )
{
if ! trans { //Don't rebuild transient ones, this is desired I think? Maybe not... Dunno.
if path . exists ( ) & & path . is_file ( ) {
//Getting hash
let path = path . clone ( ) ;
let hash = * hash ;
children . push ( tokio ::task ::spawn ( async move {
rebase_one_async ( path , hash ) . await
} ) ) ;
} else {
remove . push ( path . clone ( ) ) ;
}
}
}
let ( mut changed , mut removed ) = ( 0 usize , 0 usize ) ;
for child in children . into_iter ( )
{
if let Some ( ( path , hash ) ) = child . await . expect ( "Child panic" ) ?
{
println! ( "Updating {:?} -> {}" , path , hash ) ;
hashes . cache_force ( path , hash , false ) ;
changed + = 1 ;
}
}
for remove in remove . into_iter ( )
{
println! ( "Removing {:?}" , remove ) ;
hashes . uncache ( remove ) ;
removed + = 1 ;
}
println! ( "Updated. {} changed, {} removed." , changed , removed ) ;
for save in config . save . iter ( )
{
let save = Path ::new ( save ) ;
let mut file = match OpenOptions ::new ( )
. create ( true )
. truncate ( true )
. write ( true )
. open ( & save ) . await {
Ok ( v ) = > v ,
Err ( e ) = > { println! ( "Warning: Failed to open output {:?}, ignoring: {}" , save , e ) ; continue ; } ,
} ;
match hashes . save_async ( & mut file ) . await {
Err ( e ) = > println! ( "Warning: Failed to write to output {:?}: ignoring: {}" , file , e ) ,
_ = > ( ) ,
} ;
}
Ok ( ( ) )
}
#[ cfg(not(feature= " threads " )) ]
fn rebase ( config : config ::Rebase ) -> Result < ( ) , Box < dyn std ::error ::Error > >
{
todo! ( )
}
fn parse_args ( ) -> Result < arg ::Output , error ::Error >
{
match arg ::parse_args ( ) ? {
arg ::Output ::Normal ( conf ) = > Ok ( conf ) ,
_ = > arg ::usage ( ) ,
arg ::Output ::Help = > arg ::usage ( ) ,
conf = > Ok ( conf ) ,
}
}
@ -96,7 +228,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>>
path ::Path ,
sync ::Arc ,
} ;
let args = parse_args ( ) . into_string ( ) ? ;
match parse_args ( ) . into_string ( ) ? {
arg ::Output ::Rebase ( r ) = > {
return rebase ( r ) . await ;
} ,
arg ::Output ::Normal ( args ) = > {
let lmode = & args . mode . logging_mode ;
log ! ( Debug , lmode = > "Args parsed: {:?}" , args ) ;
@ -135,7 +272,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>>
if path . is_dir ( ) {
log ! ( Debug , lmode = > "Spawning for {:?}" , path ) ;
let mode = args . mode . clone ( ) ;
let path = path. to_owned ( ) ;
let path = absolute( & path ) ;
let hashes = Arc ::clone ( & hashes ) ;
children . push ( tokio ::task ::spawn ( async move {
log ! ( Debug , mode . logging_mode = > " + {:?}" , path ) ;
@ -170,6 +307,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>>
args . mode . error_mode . handle ( hashes . save_async ( & mut file ) . await ) . log_and_forget ( lmode , log ::Level ::Warning ) ? ;
}
}
} ,
_ = > unreachable! ( ) ,
} ;
Ok ( ( ) )
}