From 2edeb1fa45595ab2ab3e7f561314ebc3dd6baa98 Mon Sep 17 00:00:00 2001 From: Barsik Date: Thu, 21 Mar 2024 16:01:11 +0200 Subject: [PATCH 1/5] Add "publish_diff" command and related functions Created a new function called "publish_diff" in publish_diff.rs, registered it as a new command in mod.rs, and added related functions in package.rs. This "publish_diff" feature compares local and published versions of a specific package. --- module/move/willbe/src/command/mod.rs | 14 +++ .../move/willbe/src/command/publish_diff.rs | 28 +++++ module/move/willbe/src/entity/package.rs | 112 ++++++++++++++++++ 3 files changed, 154 insertions(+) create mode 100644 module/move/willbe/src/command/publish_diff.rs diff --git a/module/move/willbe/src/command/mod.rs b/module/move/willbe/src/command/mod.rs index 08cf29ba2a..0c2c2e4b8a 100644 --- a/module/move/willbe/src/command/mod.rs +++ b/module/move/willbe/src/command/mod.rs @@ -34,6 +34,18 @@ pub( crate ) mod private .routine( command::publish ) .end() + // qqq : for Barsik : provide hints + .command( "publish.diff" ) + .hint( "---" ) + .long_hint( "---" ) + .subject() + .hint( "---" ) + .kind( Type::Path ) + .optional( true ) + .end() + .routine( command::publish_diff ) + .end() + .command( "list" ) .hint( "list packages from a directory" ) .long_hint( "generates a list of packages based on the provided directory path. The directory must contain a `Cargo.toml` file." ) @@ -237,6 +249,8 @@ crate::mod_interface! layer list; /// Publish packages. layer publish; + /// Used to compare local and published versions of a specific package. + layer publish_diff; /// Generates health table in main Readme.md file of workspace. // aaa : for Petro : what a table?? // aaa : add more details to documentation diff --git a/module/move/willbe/src/command/publish_diff.rs b/module/move/willbe/src/command/publish_diff.rs new file mode 100644 index 0000000000..4abaf487c3 --- /dev/null +++ b/module/move/willbe/src/command/publish_diff.rs @@ -0,0 +1,28 @@ +mod private +{ + use std::path::PathBuf; + use crate::*; + + use { action, wtools }; + + use wca::{ Args, Props }; + use wtools::error::{ for_app::Context, Result }; + + /// + /// + /// + + pub fn publish_diff( args : Args ) -> Result< () > + { + let package : PathBuf = args.get_owned( 0 ).unwrap_or( std::env::current_dir()? ); + + Ok( () ) + } +} + +// + +crate::mod_interface! +{ + orphan use publish_diff; +} diff --git a/module/move/willbe/src/entity/package.rs b/module/move/willbe/src/entity/package.rs index 188e19da10..0bfc5fc9fe 100644 --- a/module/move/willbe/src/entity/package.rs +++ b/module/move/willbe/src/entity/package.rs @@ -11,6 +11,7 @@ mod private use std::hash::Hash; use std::path::PathBuf; use cargo_metadata::{ Dependency, DependencyKind, Package as PackageMetadata }; + use colored::Colorize; use toml_edit::value; use process_tools::process; @@ -34,6 +35,7 @@ mod private }; use action::readme_health_table_renew::Stability; use former::Former; + use wtools::iter::EitherOrBoth; /// #[ derive( Debug ) ] @@ -745,6 +747,116 @@ mod private Ok( !is_same ) } + #[ derive( Debug ) ] + enum Diff< T > + { + Same( T ), + Add( T ), + Rem( T ), + } + + #[ derive( Debug, Default ) ] + struct DiffReport( HashMap< PathBuf, Vec< Diff< Vec< u8 > > > > ); + + impl std::fmt::Display for DiffReport + { + fn fmt( &self, f : &mut Formatter< '_ > ) -> std::fmt::Result + { + for ( path, diffs ) in &self.0 + { + writeln!( f, "-- begin [{}]", path.display() )?; + for diff in diffs + { + let str = match diff + { + Diff::Same( t ) => String::from_utf8_lossy( t ).into(), + Diff::Add( t ) => format!( "[{}]", String::from_utf8_lossy( t ).green() ), + Diff::Rem( t ) => format!( "{{{}}}", String::from_utf8_lossy( t ).red() ), + }; + write!( f, "{str}" )?; + } + writeln!( f, "-- end [{}]", path.display() )?; + } + Ok( () ) + } + } + + fn crate_diff( left : &CrateArchive, right : &CrateArchive ) -> DiffReport + { + let mut report = DiffReport::default(); + + let local_package_files : HashSet< _ > = left.list().into_iter().collect(); + let remote_package_files : HashSet< _ > = right.list().into_iter().collect(); + + let local_only = local_package_files.difference( &remote_package_files ); + let remote_only = remote_package_files.difference( &local_package_files ); + let both = local_package_files.intersection( &remote_package_files ); + + for &path in local_only + { + report.0.entry( path.to_path_buf() ).or_default().push( Diff::Add( left.content_bytes( path ).unwrap().to_vec() ) ); + } + + for &path in remote_only + { + report.0.entry( path.to_path_buf() ).or_default().push( Diff::Rem( right.content_bytes( path ).unwrap().to_vec() ) ); + } + + for &path in both + { + // unwraps are safe because the paths to the files was compared previously + let local = left.content_bytes( path ).unwrap(); + let remote = right.content_bytes( path ).unwrap(); + let mut diffs = Vec::with_capacity( std::cmp::min( local.len(), remote.len() ) ); + + for pair in local.iter().zip_longest(remote) + { + match pair + { + EitherOrBoth::Both( l, r ) => + if l == r + { + diffs.push( Diff::Same( *l ) ); + } + else + { + diffs.push( Diff::Rem( *r ) ); + diffs.push( Diff::Add( *l ) ); + } + EitherOrBoth::Left( l ) => diffs.push( Diff::Add( *l ) ), + EitherOrBoth::Right( r ) => diffs.push( Diff::Rem( *r ) ), + } + } + let mut diffs_iter = diffs.iter().peekable(); + while let Some( first ) = diffs_iter.next() + { + let mut group = vec![ first ]; + while diffs_iter.peek().map_or( false, | &next | std::mem::discriminant( next ) == std::mem::discriminant( &group[ 0 ] ) ) + { + group.push( diffs_iter.next().unwrap() ); + } + let group = match first + { + Diff::Same( _ ) => Diff::Same( group.into_iter().map( | d | { let Diff::Same( v ) = d else { unreachable!() }; *v } ).collect() ), + Diff::Add( _ ) => Diff::Add( group.into_iter().map( | d | { let Diff::Add( v ) = d else { unreachable!() }; *v } ).collect() ), + Diff::Rem( _ ) => Diff::Rem( group.into_iter().map( | d | { let Diff::Rem( v ) = d else { unreachable!() }; *v } ).collect() ), + }; + report.0.entry( path.to_path_buf() ).or_default().push( group ); + } + } + + report + } + + #[ test ] + fn temporary() { + let path = AbsolutePath::try_from(PathBuf::from("../../test/a")).unwrap(); + let dir = CrateDir::try_from(path).unwrap(); + let l = CrateArchive::read( packed_crate::local_path( "test_experimental_a", "0.3.0", dir ).unwrap() ).unwrap(); + let r = CrateArchive::download_crates_io( "test_experimental_a", "0.3.0" ).unwrap(); + println!("{}", crate_diff( &l, &r )); + panic!() + } } // From 7cacbb6f4a8f0ef8809c37fe9e36e18ab3f7d544 Mon Sep 17 00:00:00 2001 From: Barsik Date: Thu, 21 Mar 2024 18:00:02 +0200 Subject: [PATCH 2/5] Update publish_diff function and improve crate comparison logic The publish_diff function in publish_diff.rs module has been updated to enhance the package publication capability. The underlying crate comparison logic in package.rs module has also been optimized for better performance. Now, instead of listing the differences byte by byte, files are being compared which makes the DiffReport response more readable and concise. --- .../move/willbe/src/command/publish_diff.rs | 23 +++- module/move/willbe/src/entity/package.rs | 104 ++++++++---------- 2 files changed, 64 insertions(+), 63 deletions(-) diff --git a/module/move/willbe/src/command/publish_diff.rs b/module/move/willbe/src/command/publish_diff.rs index 4abaf487c3..0e0f893343 100644 --- a/module/move/willbe/src/command/publish_diff.rs +++ b/module/move/willbe/src/command/publish_diff.rs @@ -3,10 +3,12 @@ mod private use std::path::PathBuf; use crate::*; - use { action, wtools }; + use { wtools }; + use crates_tools::CrateArchive; - use wca::{ Args, Props }; - use wtools::error::{ for_app::Context, Result }; + use wca::Args; + use wtools::error::Result; + use crate::_path::AbsolutePath; /// /// @@ -14,7 +16,20 @@ mod private pub fn publish_diff( args : Args ) -> Result< () > { - let package : PathBuf = args.get_owned( 0 ).unwrap_or( std::env::current_dir()? ); + let path : PathBuf = args.get_owned( 0 ).unwrap_or( std::env::current_dir()? ); + + let path = AbsolutePath::try_from( path )?; + let dir = CrateDir::try_from( path )?; + + let package = package::Package::try_from( dir.clone() )?; + let name = &package.name()?; + let version = &package.version()?; + + _ = cargo::pack( cargo::PackOptions::former().path( dir.as_ref() ).dry( false ).form() )?; + let l = CrateArchive::read( packed_crate::local_path( name, version, dir )? )?; + let r = CrateArchive::download_crates_io( name, version ).unwrap(); + + println!( "{}", package::crate_diff( &l, &r ) ); Ok( () ) } diff --git a/module/move/willbe/src/entity/package.rs b/module/move/willbe/src/entity/package.rs index 0bfc5fc9fe..9003660245 100644 --- a/module/move/willbe/src/entity/package.rs +++ b/module/move/willbe/src/entity/package.rs @@ -35,7 +35,6 @@ mod private }; use action::readme_health_table_renew::Stability; use former::Former; - use wtools::iter::EitherOrBoth; /// #[ derive( Debug ) ] @@ -89,6 +88,22 @@ mod private } } + impl TryFrom< CrateDir > for Package + { + type Error = PackageError; + + fn try_from( value : CrateDir ) -> Result< Self, Self::Error > + { + let manifest = manifest::open( value.absolute_path().join( "Cargo.toml" ) )?; + if !manifest.package_is()? + { + return Err( PackageError::NotAPackage ); + } + + Ok( Self::Manifest( manifest ) ) + } + } + impl TryFrom< Manifest > for Package { // qqq : make better errors @@ -748,40 +763,47 @@ mod private } #[ derive( Debug ) ] - enum Diff< T > + pub enum Diff< T > { Same( T ), + Modified( T ), Add( T ), Rem( T ), } #[ derive( Debug, Default ) ] - struct DiffReport( HashMap< PathBuf, Vec< Diff< Vec< u8 > > > > ); + pub struct DiffReport( Vec< Diff< PathBuf > > ); impl std::fmt::Display for DiffReport { fn fmt( &self, f : &mut Formatter< '_ > ) -> std::fmt::Result { - for ( path, diffs ) in &self.0 + for diff in &self.0 { - writeln!( f, "-- begin [{}]", path.display() )?; - for diff in diffs + match diff { - let str = match diff - { - Diff::Same( t ) => String::from_utf8_lossy( t ).into(), - Diff::Add( t ) => format!( "[{}]", String::from_utf8_lossy( t ).green() ), - Diff::Rem( t ) => format!( "{{{}}}", String::from_utf8_lossy( t ).red() ), - }; - write!( f, "{str}" )?; - } - writeln!( f, "-- end [{}]", path.display() )?; + Diff::Same( t ) => writeln!( f, "{}", t.display() )?, + Diff::Modified( t ) => writeln!( f, "~ {}", t.to_string_lossy().yellow() )?, + Diff::Add( t ) => writeln!( f, "+ {}", t.to_string_lossy().green() )?, + Diff::Rem( t ) => writeln!( f, "- {}", t.to_string_lossy().red() )?, + }; } + Ok( () ) } } - fn crate_diff( left : &CrateArchive, right : &CrateArchive ) -> DiffReport + /// Compare two crate archives and create a difference report. + /// + /// # Arguments + /// + /// * `left` - A reference to the left crate archive. + /// * `right` - A reference to the right crate archive. + /// + /// # Returns + /// + /// A `DiffReport` struct representing the difference between the two crate archives. + pub fn crate_diff( left : &CrateArchive, right : &CrateArchive ) -> DiffReport { let mut report = DiffReport::default(); @@ -794,12 +816,12 @@ mod private for &path in local_only { - report.0.entry( path.to_path_buf() ).or_default().push( Diff::Add( left.content_bytes( path ).unwrap().to_vec() ) ); + report.0.push( Diff::Add( path.to_path_buf() ) ); } for &path in remote_only { - report.0.entry( path.to_path_buf() ).or_default().push( Diff::Rem( right.content_bytes( path ).unwrap().to_vec() ) ); + report.0.push( Diff::Rem( path.to_path_buf() ) ); } for &path in both @@ -807,56 +829,19 @@ mod private // unwraps are safe because the paths to the files was compared previously let local = left.content_bytes( path ).unwrap(); let remote = right.content_bytes( path ).unwrap(); - let mut diffs = Vec::with_capacity( std::cmp::min( local.len(), remote.len() ) ); - for pair in local.iter().zip_longest(remote) + if local == remote { - match pair - { - EitherOrBoth::Both( l, r ) => - if l == r - { - diffs.push( Diff::Same( *l ) ); - } - else - { - diffs.push( Diff::Rem( *r ) ); - diffs.push( Diff::Add( *l ) ); - } - EitherOrBoth::Left( l ) => diffs.push( Diff::Add( *l ) ), - EitherOrBoth::Right( r ) => diffs.push( Diff::Rem( *r ) ), - } + report.0.push( Diff::Same( path.to_path_buf() ) ); } - let mut diffs_iter = diffs.iter().peekable(); - while let Some( first ) = diffs_iter.next() + else { - let mut group = vec![ first ]; - while diffs_iter.peek().map_or( false, | &next | std::mem::discriminant( next ) == std::mem::discriminant( &group[ 0 ] ) ) - { - group.push( diffs_iter.next().unwrap() ); - } - let group = match first - { - Diff::Same( _ ) => Diff::Same( group.into_iter().map( | d | { let Diff::Same( v ) = d else { unreachable!() }; *v } ).collect() ), - Diff::Add( _ ) => Diff::Add( group.into_iter().map( | d | { let Diff::Add( v ) = d else { unreachable!() }; *v } ).collect() ), - Diff::Rem( _ ) => Diff::Rem( group.into_iter().map( | d | { let Diff::Rem( v ) = d else { unreachable!() }; *v } ).collect() ), - }; - report.0.entry( path.to_path_buf() ).or_default().push( group ); + report.0.push( Diff::Modified( path.to_path_buf() ) ); } } report } - - #[ test ] - fn temporary() { - let path = AbsolutePath::try_from(PathBuf::from("../../test/a")).unwrap(); - let dir = CrateDir::try_from(path).unwrap(); - let l = CrateArchive::read( packed_crate::local_path( "test_experimental_a", "0.3.0", dir ).unwrap() ).unwrap(); - let r = CrateArchive::download_crates_io( "test_experimental_a", "0.3.0" ).unwrap(); - println!("{}", crate_diff( &l, &r )); - panic!() - } } // @@ -871,6 +856,7 @@ crate::mod_interface! protected use PackageError; protected use publish_need; + protected use crate_diff; protected use CrateId; protected use DependenciesSort; From 20e72beca7a05c3d1b46a4be676ee53e0a7d2b29 Mon Sep 17 00:00:00 2001 From: Barsik Date: Thu, 21 Mar 2024 18:04:37 +0200 Subject: [PATCH 3/5] Sort diffs in package.rs In the entity package, a sort function has been incorporated into the for loop to sort the diffs. This sort function is sorted by key, assisted by a match pattern which covers all types of diffs including Modified, Same, Rem, and Add. --- module/move/willbe/src/entity/package.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/module/move/willbe/src/entity/package.rs b/module/move/willbe/src/entity/package.rs index 9003660245..b6ce1668b2 100644 --- a/module/move/willbe/src/entity/package.rs +++ b/module/move/willbe/src/entity/package.rs @@ -778,7 +778,8 @@ mod private { fn fmt( &self, f : &mut Formatter< '_ > ) -> std::fmt::Result { - for diff in &self.0 + for diff in self.0.iter() + .sorted_by_key( | d | match d { Diff::Modified( df ) | Diff::Same( df ) | Diff::Rem( df ) | Diff::Add( df ) => df } ) { match diff { From 53c5f9f6c31d3e3060e675f9850693af8edf9545 Mon Sep 17 00:00:00 2001 From: Barsik Date: Thu, 21 Mar 2024 18:16:15 +0200 Subject: [PATCH 4/5] Capture and handle stderr output in process tools The commit adds the capturing of the stderr output from a process in the process tools module. It includes error handling for cases when the output contains invalid UTF-8. If such an error is encountered, the function will now return an error report. --- module/core/process_tools/src/process.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/module/core/process_tools/src/process.rs b/module/core/process_tools/src/process.rs index 98027c9f7a..f41e3bf120 100644 --- a/module/core/process_tools/src/process.rs +++ b/module/core/process_tools/src/process.rs @@ -176,6 +176,22 @@ pub( crate ) mod private report.out = out; + let err = String::from_utf8( output.stderr ) + .context( "Found invalid UTF-8" ) + .map_err( | e | + { + report.error = Err( e.into() ); + Err::< (), () >( () ) + }); + + if err.is_err() + { + return Err( report ); + } + let err = err.unwrap(); + + report.err = err; + if output.status.success() { Ok( report ) From d243fe1a531bd73e4f4b793c25b5535c4de37869 Mon Sep 17 00:00:00 2001 From: Barsik Date: Thu, 21 Mar 2024 20:05:49 +0200 Subject: [PATCH 5/5] Add feature to compare local and remote package versions The commit introduces a new functionality to compare local and remote package versions and generate a detailed report of changes. The comparison looks at each file, stating whether it's been added, removed, or modified. Now, users can see how their local package version is different from the remote one. Command line hints were updated to guide users through this feature. --- module/move/willbe/src/action/mod.rs | 2 + module/move/willbe/src/action/publish_diff.rs | 38 ++++++ module/move/willbe/src/command/mod.rs | 7 +- .../move/willbe/src/command/publish_diff.rs | 32 +++-- module/move/willbe/src/entity/diff.rs | 113 ++++++++++++++++++ module/move/willbe/src/entity/mod.rs | 4 + module/move/willbe/src/entity/package.rs | 84 ------------- 7 files changed, 174 insertions(+), 106 deletions(-) create mode 100644 module/move/willbe/src/action/publish_diff.rs create mode 100644 module/move/willbe/src/entity/diff.rs diff --git a/module/move/willbe/src/action/mod.rs b/module/move/willbe/src/action/mod.rs index 08c634878f..03d817fc44 100644 --- a/module/move/willbe/src/action/mod.rs +++ b/module/move/willbe/src/action/mod.rs @@ -8,6 +8,8 @@ crate::mod_interface! layer main_header; /// Publish packages. layer publish; + /// Return the differences between a local and remote package versions. + layer publish_diff; /// Generates health table in main Readme.md file of workspace. // aaa : for Petro : give high quality explanations // aaa : add more details to description diff --git a/module/move/willbe/src/action/publish_diff.rs b/module/move/willbe/src/action/publish_diff.rs new file mode 100644 index 0000000000..d8f648aba7 --- /dev/null +++ b/module/move/willbe/src/action/publish_diff.rs @@ -0,0 +1,38 @@ +/// Internal namespace. +mod private +{ + use crate::*; + + use std::path::PathBuf; + use crates_tools::CrateArchive; + + use _path::AbsolutePath; + use wtools::error::for_app::Result; + use diff::{ DiffReport, crate_diff }; + + /// Return the differences between a local and remote package versions. + #[ cfg_attr( feature = "tracing", tracing::instrument ) ] + pub fn publish_diff( path : PathBuf ) -> Result< DiffReport > + { + let path = AbsolutePath::try_from( path )?; + let dir = CrateDir::try_from( path )?; + + let package = package::Package::try_from( dir.clone() )?; + let name = &package.name()?; + let version = &package.version()?; + + _ = cargo::pack( cargo::PackOptions::former().path( dir.as_ref() ).dry( false ).form() )?; + let l = CrateArchive::read( packed_crate::local_path( name, version, dir )? )?; + let r = CrateArchive::download_crates_io( name, version ).unwrap(); + + Ok( crate_diff( &l, &r ) ) + } +} + +// + +crate::mod_interface! +{ + /// Publishes the difference between the local and published versions of a package. + orphan use publish_diff; +} diff --git a/module/move/willbe/src/command/mod.rs b/module/move/willbe/src/command/mod.rs index 0c2c2e4b8a..384d1540f4 100644 --- a/module/move/willbe/src/command/mod.rs +++ b/module/move/willbe/src/command/mod.rs @@ -34,12 +34,11 @@ pub( crate ) mod private .routine( command::publish ) .end() - // qqq : for Barsik : provide hints .command( "publish.diff" ) - .hint( "---" ) - .long_hint( "---" ) + .hint( "Display the differences between a local and remote package versions." ) + .long_hint( "Following this command, you will immediately get a comparison between the local and remote packages. It looks at each file, identifying those added, removed, or modified. A full report will then be generated where you can quickly and easily see the differences." ) .subject() - .hint( "---" ) + .hint( "Provide path to the package that you want to check.\n\t The path should point to a directory that contains a `Cargo.toml` file." ) .kind( Type::Path ) .optional( true ) .end() diff --git a/module/move/willbe/src/command/publish_diff.rs b/module/move/willbe/src/command/publish_diff.rs index 0e0f893343..baedd83605 100644 --- a/module/move/willbe/src/command/publish_diff.rs +++ b/module/move/willbe/src/command/publish_diff.rs @@ -1,35 +1,30 @@ mod private { - use std::path::PathBuf; use crate::*; - use { wtools }; - use crates_tools::CrateArchive; - + use std::path::PathBuf; use wca::Args; + use wtools::error::Result; - use crate::_path::AbsolutePath; + /// Command to display the differences between a local and remote package versions. /// + /// # Arguments /// + /// * `args` - Command line arguments. /// - + /// # Returns + /// + /// Returns a `Result` indicating success or failure. + /// + /// # Errors + /// + /// Returns an error if there is an issue with the command. pub fn publish_diff( args : Args ) -> Result< () > { let path : PathBuf = args.get_owned( 0 ).unwrap_or( std::env::current_dir()? ); - let path = AbsolutePath::try_from( path )?; - let dir = CrateDir::try_from( path )?; - - let package = package::Package::try_from( dir.clone() )?; - let name = &package.name()?; - let version = &package.version()?; - - _ = cargo::pack( cargo::PackOptions::former().path( dir.as_ref() ).dry( false ).form() )?; - let l = CrateArchive::read( packed_crate::local_path( name, version, dir )? )?; - let r = CrateArchive::download_crates_io( name, version ).unwrap(); - - println!( "{}", package::crate_diff( &l, &r ) ); + println!( "{}", action::publish_diff( path )? ); Ok( () ) } @@ -39,5 +34,6 @@ mod private crate::mod_interface! { + /// Publishes the difference between the local and published versions of a package. orphan use publish_diff; } diff --git a/module/move/willbe/src/entity/diff.rs b/module/move/willbe/src/entity/diff.rs new file mode 100644 index 0000000000..27c39543ff --- /dev/null +++ b/module/move/willbe/src/entity/diff.rs @@ -0,0 +1,113 @@ +mod private +{ + use crate::*; + + use std:: + { + collections::HashSet, + fmt::Formatter, + path::PathBuf, + }; + use colored::Colorize; + use crates_tools::CrateArchive; + + use wtools::iter::Itertools; + + /// The `Diff` enum is designed to represent differences between two versions + /// of some kind of item identified. + #[ derive( Debug ) ] + pub enum Diff< T > + { + /// This variant represents items that are identical or same in both versions. + Same( T ), + /// This variant represents items that exists in both versions but have been modified. + Modified( T ), + /// This variant represents items that were added. + Add( T ), + /// This variant represents items that were removed. + Rem( T ), + } + + /// The `DiffReport` struct represents a diff report containing a list of `Diff` objects. + #[ derive( Debug, Default ) ] + pub struct DiffReport( Vec< Diff< PathBuf > > ); + + impl std::fmt::Display for DiffReport + { + fn fmt( &self, f : &mut Formatter< '_ > ) -> std::fmt::Result + { + for diff in self.0.iter() + .sorted_by_key( | d | match d { Diff::Modified( df ) | Diff::Same( df ) | Diff::Rem( df ) | Diff::Add( df ) => df } ) + { + match diff + { + Diff::Same( t ) => writeln!( f, "{}", t.display() )?, + Diff::Modified( t ) => writeln!( f, "~ {}", t.to_string_lossy().yellow() )?, + Diff::Add( t ) => writeln!( f, "+ {}", t.to_string_lossy().green() )?, + Diff::Rem( t ) => writeln!( f, "- {}", t.to_string_lossy().red() )?, + }; + } + + Ok( () ) + } + } + + /// Compare two crate archives and create a difference report. + /// + /// # Arguments + /// + /// * `left` - A reference to the left crate archive. + /// * `right` - A reference to the right crate archive. + /// + /// # Returns + /// + /// A `DiffReport` struct representing the difference between the two crate archives. + pub fn crate_diff( left : &CrateArchive, right : &CrateArchive ) -> DiffReport + { + let mut report = DiffReport::default(); + + let local_package_files : HashSet< _ > = left.list().into_iter().collect(); + let remote_package_files : HashSet< _ > = right.list().into_iter().collect(); + + let local_only = local_package_files.difference( &remote_package_files ); + let remote_only = remote_package_files.difference( &local_package_files ); + let both = local_package_files.intersection( &remote_package_files ); + + for &path in local_only + { + report.0.push( Diff::Add( path.to_path_buf() ) ); + } + + for &path in remote_only + { + report.0.push( Diff::Rem( path.to_path_buf() ) ); + } + + for &path in both + { + // unwraps are safe because the paths to the files was compared previously + let local = left.content_bytes( path ).unwrap(); + let remote = right.content_bytes( path ).unwrap(); + + if local == remote + { + report.0.push( Diff::Same( path.to_path_buf() ) ); + } + else + { + report.0.push( Diff::Modified( path.to_path_buf() ) ); + } + } + + report + } +} + +// + +crate::mod_interface! +{ + protected use Diff; + protected use DiffReport; + protected use crate_diff; +} \ No newline at end of file diff --git a/module/move/willbe/src/entity/mod.rs b/module/move/willbe/src/entity/mod.rs index 6073c0fa94..5a0be78e1f 100644 --- a/module/move/willbe/src/entity/mod.rs +++ b/module/move/willbe/src/entity/mod.rs @@ -1,6 +1,10 @@ crate::mod_interface! { + /// Compare two crate archives and create a difference report. + layer diff; + orphan use super::diff; + /// Operation with features layer features; orphan use super::features; diff --git a/module/move/willbe/src/entity/package.rs b/module/move/willbe/src/entity/package.rs index c0a36c0afc..b9794b4d82 100644 --- a/module/move/willbe/src/entity/package.rs +++ b/module/move/willbe/src/entity/package.rs @@ -11,7 +11,6 @@ mod private use std::hash::Hash; use std::path::PathBuf; use cargo_metadata::{ Dependency, DependencyKind }; - use colored::Colorize; use toml_edit::value; use process_tools::process; @@ -761,88 +760,6 @@ mod private Ok( !is_same ) } - - #[ derive( Debug ) ] - pub enum Diff< T > - { - Same( T ), - Modified( T ), - Add( T ), - Rem( T ), - } - - #[ derive( Debug, Default ) ] - pub struct DiffReport( Vec< Diff< PathBuf > > ); - - impl std::fmt::Display for DiffReport - { - fn fmt( &self, f : &mut Formatter< '_ > ) -> std::fmt::Result - { - for diff in self.0.iter() - .sorted_by_key( | d | match d { Diff::Modified( df ) | Diff::Same( df ) | Diff::Rem( df ) | Diff::Add( df ) => df } ) - { - match diff - { - Diff::Same( t ) => writeln!( f, "{}", t.display() )?, - Diff::Modified( t ) => writeln!( f, "~ {}", t.to_string_lossy().yellow() )?, - Diff::Add( t ) => writeln!( f, "+ {}", t.to_string_lossy().green() )?, - Diff::Rem( t ) => writeln!( f, "- {}", t.to_string_lossy().red() )?, - }; - } - - Ok( () ) - } - } - - /// Compare two crate archives and create a difference report. - /// - /// # Arguments - /// - /// * `left` - A reference to the left crate archive. - /// * `right` - A reference to the right crate archive. - /// - /// # Returns - /// - /// A `DiffReport` struct representing the difference between the two crate archives. - pub fn crate_diff( left : &CrateArchive, right : &CrateArchive ) -> DiffReport - { - let mut report = DiffReport::default(); - - let local_package_files : HashSet< _ > = left.list().into_iter().collect(); - let remote_package_files : HashSet< _ > = right.list().into_iter().collect(); - - let local_only = local_package_files.difference( &remote_package_files ); - let remote_only = remote_package_files.difference( &local_package_files ); - let both = local_package_files.intersection( &remote_package_files ); - - for &path in local_only - { - report.0.push( Diff::Add( path.to_path_buf() ) ); - } - - for &path in remote_only - { - report.0.push( Diff::Rem( path.to_path_buf() ) ); - } - - for &path in both - { - // unwraps are safe because the paths to the files was compared previously - let local = left.content_bytes( path ).unwrap(); - let remote = right.content_bytes( path ).unwrap(); - - if local == remote - { - report.0.push( Diff::Same( path.to_path_buf() ) ); - } - else - { - report.0.push( Diff::Modified( path.to_path_buf() ) ); - } - } - - report - } } // @@ -857,7 +774,6 @@ crate::mod_interface! protected use PackageError; protected use publish_need; - protected use crate_diff; protected use CrateId; protected use DependenciesSort;