Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

READY : (willbe): Add "publish_diff" command and related functions #1230

Merged
merged 6 commits into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions module/core/process_tools/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 )
Expand Down
2 changes: 2 additions & 0 deletions module/move/willbe/src/action/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
38 changes: 38 additions & 0 deletions module/move/willbe/src/action/publish_diff.rs
Original file line number Diff line number Diff line change
@@ -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;
}
13 changes: 13 additions & 0 deletions module/move/willbe/src/command/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ pub( crate ) mod private
.routine( command::publish )
.end()

.command( "publish.diff" )
.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( "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()
.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." )
Expand Down Expand Up @@ -237,6 +248,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
Expand Down
39 changes: 39 additions & 0 deletions module/move/willbe/src/command/publish_diff.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
mod private
{
use crate::*;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

!


use std::path::PathBuf;
use wca::Args;

use wtools::error::Result;

/// 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()? );

println!( "{}", action::publish_diff( path )? );

Ok( () )
}
}

//

crate::mod_interface!
{
/// Publishes the difference between the local and published versions of a package.
orphan use publish_diff;
}
113 changes: 113 additions & 0 deletions module/move/willbe/src/entity/diff.rs
Original file line number Diff line number Diff line change
@@ -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;
}
4 changes: 4 additions & 0 deletions module/move/willbe/src/entity/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
17 changes: 16 additions & 1 deletion module/move/willbe/src/entity/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,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
Expand Down Expand Up @@ -744,7 +760,6 @@ mod private

Ok( !is_same )
}

}

//
Expand Down