From 72c89a0664a880b9d995c117252a5d46766ccda9 Mon Sep 17 00:00:00 2001 From: Barsik Date: Wed, 30 Oct 2024 16:45:36 +0200 Subject: [PATCH 1/4] feat: `exclude_dev_dependencies` flag for `.publish` and `.publish.diff`. Default value is `true` --- module/move/willbe/src/action/publish.rs | 3 + module/move/willbe/src/action/publish_diff.rs | 22 +++--- module/move/willbe/src/command/mod.rs | 10 +++ module/move/willbe/src/command/publish.rs | 7 +- .../move/willbe/src/command/publish_diff.rs | 13 +++- module/move/willbe/src/entity/publish.rs | 11 +++ module/move/willbe/src/tool/cargo.rs | 75 +++++++++++++++++++ 7 files changed, 128 insertions(+), 13 deletions(-) diff --git a/module/move/willbe/src/action/publish.rs b/module/move/willbe/src/action/publish.rs index 58412a2d7a..d19b34c3c7 100644 --- a/module/move/willbe/src/action/publish.rs +++ b/module/move/willbe/src/action/publish.rs @@ -109,6 +109,7 @@ mod private /// /// # Arguments /// * `patterns` - A vector of patterns specifying the folders to search for packages. + /// * `exclude_dev_dependencies` - A boolean value indicating whether to exclude dev dependencies from manifest before publish. /// * `dry` - A boolean value indicating whether to perform a dry run. /// * `temp` - A boolean value indicating whether to use a temporary directory. /// @@ -119,6 +120,7 @@ mod private ( patterns : Vec< String >, channel : channel::Channel, + exclude_dev_dependencies : bool, dry : bool, temp : bool ) @@ -233,6 +235,7 @@ mod private .channel( channel ) .workspace_dir( CrateDir::try_from( workspace_root_dir ).unwrap() ) .option_base_temp_dir( dir.clone() ) + .exclude_dev_dependencies( exclude_dev_dependencies ) .dry( dry ) .roots( roots ) .packages( queue ) diff --git a/module/move/willbe/src/action/publish_diff.rs b/module/move/willbe/src/action/publish_diff.rs index d27920c7bc..bbb04c1bf1 100644 --- a/module/move/willbe/src/action/publish_diff.rs +++ b/module/move/willbe/src/action/publish_diff.rs @@ -22,6 +22,7 @@ mod private pub struct PublishDiffOptions { path : PathBuf, + exclude_dev_dependencies : bool, keep_archive : Option< PathBuf >, } @@ -141,16 +142,17 @@ mod private let name = &package.name()?; let version = &package.version()?; - _ = cargo::pack - ( - cargo::PackOptions::former() - .path( dir.as_ref() ) - .allow_dirty( true ) - .checking_consistency( false ) - .dry( false ).form() - )?; - let l = CrateArchive::read( packed_crate::local_path( name, version, dir )? )?; - let r = CrateArchive::download_crates_io( name, version ).unwrap(); + _ = cargo::pack + ( + cargo::PackOptions::former() + .path( dir.as_ref() ) + .allow_dirty( true ) + .checking_consistency( false ) + .exclude_dev_dependencies( o.exclude_dev_dependencies) + .dry( false ).form() + )?; + let l = CrateArchive::read( packed_crate::local_path( name, version, dir )? )?; + let r = CrateArchive::download_crates_io( name, version ).unwrap(); if let Some( out_path ) = &o.keep_archive diff --git a/module/move/willbe/src/command/mod.rs b/module/move/willbe/src/command/mod.rs index bae53834e1..66057093cd 100644 --- a/module/move/willbe/src/command/mod.rs +++ b/module/move/willbe/src/command/mod.rs @@ -25,6 +25,11 @@ mod private .kind( Type::String ) .optional( true ) .end() + .property( "exclude_dev_dependencies" ) + .hint( "Setting this option to true will temporarily remove development dependencies before executing the command, then restore them afterward. Default is `true`." ) + .kind( Type::Bool ) + .optional( true ) + .end() .property( "dry" ) .hint( "Enables 'dry run'. Does not publish, only simulates. Default is `true`." ) .kind( Type::Bool ) @@ -47,6 +52,11 @@ mod private .kind( Type::Path ) .optional( true ) .end() + .property( "exclude_dev_dependencies" ) + .hint( "Setting this option to true will temporarily remove development dependencies before executing the command, then restore them afterward. Default is `true`." ) + .kind( Type::Bool ) + .optional( true ) + .end() .property( "keep_archive" ) .hint( "Save remote package version to the specified path" ) .kind( Type::Path ) diff --git a/module/move/willbe/src/command/publish.rs b/module/move/willbe/src/command/publish.rs index a70af4265d..ba09a55288 100644 --- a/module/move/willbe/src/command/publish.rs +++ b/module/move/willbe/src/command/publish.rs @@ -16,6 +16,8 @@ mod private #[ former( default = Channel::Stable ) ] channel : Channel, #[ former( default = true ) ] + exclude_dev_dependencies : bool, + #[ former( default = true ) ] dry : bool, #[ former( default = true ) ] temp : bool, @@ -52,10 +54,11 @@ mod private let PublishProperties { channel, + exclude_dev_dependencies, dry, temp } = o.props.try_into()?; - let plan = action::publish_plan( patterns, channel, dry, temp ) + let plan = action::publish_plan( patterns, channel, exclude_dev_dependencies, dry, temp ) .context( "Failed to plan the publication process" )?; let mut formatted_plan = String::new(); @@ -110,6 +113,8 @@ mod private else { this }; + this = if let Some( v ) = value + .get_owned( "exclude_dev_dependencies" ) { this.exclude_dev_dependencies::< bool >( v ) } else { this }; this = if let Some( v ) = value .get_owned( "dry" ) { this.dry::< bool >( v ) } else { this }; this = if let Some( v ) = value diff --git a/module/move/willbe/src/command/publish_diff.rs b/module/move/willbe/src/command/publish_diff.rs index 4691331866..5e4bc27889 100644 --- a/module/move/willbe/src/command/publish_diff.rs +++ b/module/move/willbe/src/command/publish_diff.rs @@ -13,6 +13,8 @@ mod private #[ derive( former::Former ) ] struct PublishDiffProperties { + #[ former( default = true ) ] + exclude_dev_dependencies : bool, keep_archive : Option< PathBuf >, } @@ -33,10 +35,11 @@ mod private pub fn publish_diff( o : VerifiedCommand ) -> error::untyped::Result< () > // qqq : use typed error { let path : PathBuf = o.args.get_owned( 0 ).unwrap_or( std::env::current_dir()? ); - let PublishDiffProperties { keep_archive } = o.props.try_into()?; + let PublishDiffProperties { keep_archive, exclude_dev_dependencies } = o.props.try_into()?; let mut o = action::PublishDiffOptions::former() - .path( path ); + .path( path ) + .exclude_dev_dependencies( exclude_dev_dependencies ); if let Some( k ) = keep_archive.clone() { o = o.keep_archive( k ); } let o = o.form(); @@ -57,6 +60,12 @@ mod private { let mut this = Self::former(); + this = if let Some( v ) = value + .get_owned( "exclude_dev_dependencies" ) + { this.exclude_dev_dependencies::< bool >( v ) } + else + { this }; + this = if let Some( v ) = value .get_owned( "keep_archive" ) { this.keep_archive::< PathBuf >( v ) } diff --git a/module/move/willbe/src/entity/publish.rs b/module/move/willbe/src/entity/publish.rs index ed1e336129..5ff07ec17a 100644 --- a/module/move/willbe/src/entity/publish.rs +++ b/module/move/willbe/src/entity/publish.rs @@ -42,6 +42,7 @@ mod private package : package::Package< 'a >, channel : channel::Channel, base_temp_dir : Option< path::PathBuf >, + exclude_dev_dependencies : bool, #[ former( default = true ) ] dry : bool, } @@ -58,6 +59,7 @@ mod private channel : self.channel, allow_dirty : self.dry, checking_consistency : !self.dry, + exclude_dev_dependencies : self.exclude_dev_dependencies, temp_path : self.base_temp_dir.clone(), dry : self.dry, }; @@ -84,6 +86,7 @@ mod private { path : crate_dir.clone().absolute_path().inner(), temp_path : self.base_temp_dir.clone(), + exclude_dev_dependencies : self.exclude_dev_dependencies, retry_count : 2, dry : self.dry, }; @@ -121,6 +124,10 @@ mod private /// Release channels for rust. pub channel : channel::Channel, + /// Setting this option to true will temporarily remove development dependencies before executing the command, then restore them afterward. + #[ allow( dead_code ) ] // former related + pub( crate ) exclude_dev_dependencies : bool, + /// `dry` - A boolean value indicating whether to do a dry run. If set to `true`, the application performs /// a simulated run without making any actual changes. If set to `false`, the operations are actually executed. /// This property is optional and defaults to `true`. @@ -246,6 +253,10 @@ mod private { plan = plan.dry( dry ); } + if let Some( exclude_dev_dependencies ) = &self.storage.exclude_dev_dependencies + { + plan = plan.exclude_dev_dependencies( *exclude_dev_dependencies ) + } let plan = plan .channel( channel ) .package( package ) diff --git a/module/move/willbe/src/tool/cargo.rs b/module/move/willbe/src/tool/cargo.rs index 71590ecd45..c380bcc4b1 100644 --- a/module/move/willbe/src/tool/cargo.rs +++ b/module/move/willbe/src/tool/cargo.rs @@ -1,6 +1,8 @@ /// Internal namespace. mod private { + use crate::*; + #[ allow( unused_imports ) ] use crate::tool::*; @@ -47,6 +49,9 @@ mod private // aaa : don't abuse negative form, rename to checking_consistency // renamed and changed logic pub( crate ) checking_consistency : bool, + /// Setting this option to true will temporarily remove development dependencies before executing the command, then restore them afterward. + #[ former( default = true ) ] + pub( crate ) exclude_dev_dependencies : bool, /// An optional temporary path to be used during packaging. /// /// This field may contain a path to a temporary directory that will be used during the packaging process. @@ -79,6 +84,53 @@ mod private } } + #[ derive( Debug ) ] + struct TemporaryManifestFile + { + original : PathBuf, + temporary : PathBuf, + } + + impl TemporaryManifestFile + { + /// Creates a backup copy of the original file, allowing the original file location to serve as a temporary workspace. + /// When the object is dropped, the temporary file at the original location is replaced by the backup, restoring the original file. + fn new( path : impl Into< PathBuf > ) -> error::untyped::Result< Self > + { + let path = path.into(); + if !path.ends_with( "Cargo.toml" ) + { + error::untyped::bail!( "Wrong path to temporary manifest" ); + } + + let mut index = 0; + let original = loop + { + let temp_path = PathBuf::from( format!( "{}.temp_{index}", path.display() ) ); + if !temp_path.exists() + { + _ = std::fs::copy( &path, &temp_path )?; + break temp_path; + } + index += 1; + }; + + Ok( Self + { + original, + temporary : path, + }) + } + } + + impl Drop for TemporaryManifestFile + { + fn drop( &mut self ) + { + _ = std::fs::rename( &self.original, &self.temporary ).ok(); + } + } + /// /// Assemble the local package into a distributable tarball. /// @@ -96,6 +148,17 @@ mod private // qqq : use typed error pub fn pack( args : PackOptions ) -> error::untyped::Result< process::Report > { + let _temp = if args.exclude_dev_dependencies + { + let manifest = TemporaryManifestFile::new( args.path.join( "Cargo.toml" ) )?; + let mut file = Manifest::try_from( ManifestFile::try_from( &manifest.temporary )? )?; + let data = file.data(); + + _ = data.remove( "dev-dependencies" ); + file.store()?; + + Some( manifest ) + } else { None }; let ( program, options ) = ( "rustup", args.to_pack_args() ); if args.dry @@ -129,6 +192,7 @@ mod private { pub( crate ) path : PathBuf, pub( crate ) temp_path : Option< PathBuf >, + pub( crate ) exclude_dev_dependencies : bool, #[ former( default = 0usize ) ] pub( crate ) retry_count : usize, pub( crate ) dry : bool, @@ -162,6 +226,17 @@ mod private pub fn publish( args : PublishOptions ) -> error::untyped::Result< process::Report > // qqq : use typed error { + let _temp = if args.exclude_dev_dependencies + { + let manifest = TemporaryManifestFile::new( args.path.join( "Cargo.toml" ) )?; + let mut file = Manifest::try_from( ManifestFile::try_from( &manifest.temporary )? )?; + let data = file.data(); + + _ = data.remove( "dev-dependencies" ); + file.store()?; + + Some( manifest ) + } else { None }; let ( program, arguments) = ( "cargo", args.as_publish_args() ); if args.dry From 23bbba403ba9f9e2e9a53b57d20069bbcc170bc2 Mon Sep 17 00:00:00 2001 From: Barsik Date: Wed, 30 Oct 2024 17:14:43 +0200 Subject: [PATCH 2/4] feat: `commit_changes` flag for `.publish`. Default value is `true` --- module/move/willbe/src/action/publish.rs | 2 + module/move/willbe/src/command/mod.rs | 5 ++ module/move/willbe/src/command/publish.rs | 7 +- module/move/willbe/src/entity/publish.rs | 83 +++++++++++++++-------- 4 files changed, 66 insertions(+), 31 deletions(-) diff --git a/module/move/willbe/src/action/publish.rs b/module/move/willbe/src/action/publish.rs index d19b34c3c7..048220bc20 100644 --- a/module/move/willbe/src/action/publish.rs +++ b/module/move/willbe/src/action/publish.rs @@ -121,6 +121,7 @@ mod private patterns : Vec< String >, channel : channel::Channel, exclude_dev_dependencies : bool, + commit_changes : bool, dry : bool, temp : bool ) @@ -236,6 +237,7 @@ mod private .workspace_dir( CrateDir::try_from( workspace_root_dir ).unwrap() ) .option_base_temp_dir( dir.clone() ) .exclude_dev_dependencies( exclude_dev_dependencies ) + .commit_changes( commit_changes ) .dry( dry ) .roots( roots ) .packages( queue ) diff --git a/module/move/willbe/src/command/mod.rs b/module/move/willbe/src/command/mod.rs index 66057093cd..dc4f4eb8f9 100644 --- a/module/move/willbe/src/command/mod.rs +++ b/module/move/willbe/src/command/mod.rs @@ -30,6 +30,11 @@ mod private .kind( Type::Bool ) .optional( true ) .end() + .property( "commit_changes" ) + .hint( "Indicates whether changes should be committed. Default is `true`." ) + .kind( Type::Bool ) + .optional( true ) + .end() .property( "dry" ) .hint( "Enables 'dry run'. Does not publish, only simulates. Default is `true`." ) .kind( Type::Bool ) diff --git a/module/move/willbe/src/command/publish.rs b/module/move/willbe/src/command/publish.rs index ba09a55288..233ecb9a6b 100644 --- a/module/move/willbe/src/command/publish.rs +++ b/module/move/willbe/src/command/publish.rs @@ -18,6 +18,8 @@ mod private #[ former( default = true ) ] exclude_dev_dependencies : bool, #[ former( default = true ) ] + commit_changes : bool, + #[ former( default = true ) ] dry : bool, #[ former( default = true ) ] temp : bool, @@ -55,10 +57,11 @@ mod private { channel, exclude_dev_dependencies, + commit_changes, dry, temp } = o.props.try_into()?; - let plan = action::publish_plan( patterns, channel, exclude_dev_dependencies, dry, temp ) + let plan = action::publish_plan( patterns, channel, exclude_dev_dependencies, commit_changes, dry, temp ) .context( "Failed to plan the publication process" )?; let mut formatted_plan = String::new(); @@ -116,6 +119,8 @@ mod private this = if let Some( v ) = value .get_owned( "exclude_dev_dependencies" ) { this.exclude_dev_dependencies::< bool >( v ) } else { this }; this = if let Some( v ) = value + .get_owned( "commit_changes" ) { this.commit_changes::< bool >( v ) } else { this }; + this = if let Some( v ) = value .get_owned( "dry" ) { this.dry::< bool >( v ) } else { this }; this = if let Some( v ) = value .get_owned( "temp" ) { this.temp::< bool >( v ) } else { this }; diff --git a/module/move/willbe/src/entity/publish.rs b/module/move/willbe/src/entity/publish.rs index 5ff07ec17a..c30a8d13ce 100644 --- a/module/move/willbe/src/entity/publish.rs +++ b/module/move/willbe/src/entity/publish.rs @@ -26,7 +26,7 @@ mod private /// Options for bumping the package version. pub bump : version::BumpOptions, /// Git options related to the package. - pub git_options : entity::git::GitOptions, + pub git_options : Option< entity::git::GitOptions >, /// Options for publishing the package using Cargo. pub publish : cargo::PublishOptions, /// Indicates whether the process should be dry-run (no actual publishing). @@ -44,6 +44,8 @@ mod private base_temp_dir : Option< path::PathBuf >, exclude_dev_dependencies : bool, #[ former( default = true ) ] + commit_changes : bool, + #[ former( default = true ) ] dry : bool, } @@ -75,13 +77,16 @@ mod private dependencies : dependencies.clone(), dry : self.dry, }; - let git_options = entity::git::GitOptions + let git_options = if self.commit_changes { - git_root : workspace_root, - items : dependencies.iter().chain([ &crate_dir ]).map( | d | d.clone().absolute_path().join( "Cargo.toml" ) ).collect(), - message : format!( "{}-v{}", self.package.name().unwrap(), new_version ), - dry : self.dry, - }; + Some( entity::git::GitOptions + { + git_root : workspace_root, + items : dependencies.iter().chain([ &crate_dir ]).map( | d | d.clone().absolute_path().join( "Cargo.toml" ) ).collect(), + message : format!( "{}-v{}", self.package.name().unwrap(), new_version ), + dry : self.dry, + }) + } else { None }; let publish = cargo::PublishOptions { path : crate_dir.clone().absolute_path().inner(), @@ -126,7 +131,11 @@ mod private /// Setting this option to true will temporarily remove development dependencies before executing the command, then restore them afterward. #[ allow( dead_code ) ] // former related - pub( crate ) exclude_dev_dependencies : bool, + pub exclude_dev_dependencies : bool, + + /// Indicates whether changes should be committed. + #[ former( default = true ) ] + pub commit_changes : bool, /// `dry` - A boolean value indicating whether to do a dry run. If set to `true`, the application performs /// a simulated run without making any actual changes. If set to `false`, the operations are actually executed. @@ -257,6 +266,10 @@ mod private { plan = plan.exclude_dev_dependencies( *exclude_dev_dependencies ) } + if let Some( commit_changes ) = &self.storage.commit_changes + { + plan = plan.commit_changes( *commit_changes ) + } let plan = plan .channel( channel ) .package( package ) @@ -373,45 +386,55 @@ mod private } = instruction; pack.dry = dry; bump.dry = dry; - git_options.dry = dry; + git_options.as_mut().map( | d | d.dry = dry ); publish.dry = dry; report.get_info = Some( cargo::pack( pack ).err_with_report( &report )? ); // aaa : redundant field? // aaa : removed let bump_report = version::bump( bump ).err_with_report( &report )?; report.bump = Some( bump_report.clone() ); - let git_root = git_options.git_root.clone(); - let git = match entity::git::perform_git_commit( git_options ) + + let git_root = git_options.as_ref().map( | g | g.git_root.clone() ); + if let Some( git_options ) = git_options { - Ok( git ) => git, - Err( e ) => + let git = match entity::git::perform_git_commit( git_options ) { - version::revert( &bump_report ) - .map_err( | le | format_err!( "Base error:\n{}\nRevert error:\n{}", e.to_string().replace( '\n', "\n\t" ), le.to_string().replace( '\n', "\n\t" ) ) ) - .err_with_report( &report )?; - return Err(( report, e )); - } - }; - report.add = git.add; - report.commit = git.commit; + Ok( git ) => git, + Err( e ) => + { + version::revert( &bump_report ) + .map_err( | le | format_err!( "Base error:\n{}\nRevert error:\n{}", e.to_string().replace( '\n', "\n\t" ), le.to_string().replace( '\n', "\n\t" ) ) ) + .err_with_report( &report )?; + return Err(( report, e )); + } + }; + report.add = git.add; + report.commit = git.commit; + } report.publish = match cargo::publish( publish ) { Ok( publish ) => Some( publish ), Err( e ) => { - tool::git::reset( git_root.as_ref(), true, 1, false ) - .map_err - ( - | le | - format_err!( "Base error:\n{}\nRevert error:\n{}", e.to_string().replace( '\n', "\n\t" ), le.to_string().replace( '\n', "\n\t" ) ) - ) - .err_with_report( &report )?; + if let Some( git_root ) = git_root.as_ref() + { + tool::git::reset( git_root.as_ref(), true, 1, false ) + .map_err + ( + | le | + format_err!( "Base error:\n{}\nRevert error:\n{}", e.to_string().replace( '\n', "\n\t" ), le.to_string().replace( '\n', "\n\t" ) ) + ) + .err_with_report( &report )?; + } return Err(( report, e )); } }; - let res = tool::git::push( &git_root, dry ).err_with_report( &report )?; - report.push = Some( res ); + if let Some( git_root ) = git_root.as_ref() + { + let res = tool::git::push( &git_root, dry ).err_with_report( &report )?; + report.push = Some( res ); + } Ok( report ) } From d1bd9d59f30a5157227c9a0a2bad6fd2102e36da Mon Sep 17 00:00:00 2001 From: Barsik Date: Thu, 31 Oct 2024 00:18:00 +0200 Subject: [PATCH 3/4] chore: `commit_changes` flag for `.publish`. Default value is `false` --- module/move/willbe/src/command/mod.rs | 2 +- module/move/willbe/src/command/publish.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/module/move/willbe/src/command/mod.rs b/module/move/willbe/src/command/mod.rs index dc4f4eb8f9..5c81dcf47b 100644 --- a/module/move/willbe/src/command/mod.rs +++ b/module/move/willbe/src/command/mod.rs @@ -31,7 +31,7 @@ mod private .optional( true ) .end() .property( "commit_changes" ) - .hint( "Indicates whether changes should be committed. Default is `true`." ) + .hint( "Indicates whether changes should be committed. Default is `false`." ) .kind( Type::Bool ) .optional( true ) .end() diff --git a/module/move/willbe/src/command/publish.rs b/module/move/willbe/src/command/publish.rs index 233ecb9a6b..91ebaab975 100644 --- a/module/move/willbe/src/command/publish.rs +++ b/module/move/willbe/src/command/publish.rs @@ -17,7 +17,7 @@ mod private channel : Channel, #[ former( default = true ) ] exclude_dev_dependencies : bool, - #[ former( default = true ) ] + #[ former( default = false ) ] commit_changes : bool, #[ former( default = true ) ] dry : bool, From f772d9a39f48154a9b8556bd59ce41b9381c7c57 Mon Sep 17 00:00:00 2001 From: Barsik Date: Fri, 1 Nov 2024 09:56:54 +0200 Subject: [PATCH 4/4] chore: `exclude_dev_dependencies` Default value is `false` --- module/move/willbe/src/command/publish.rs | 2 +- module/move/willbe/src/command/publish_diff.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/module/move/willbe/src/command/publish.rs b/module/move/willbe/src/command/publish.rs index 91ebaab975..b9ca441ef5 100644 --- a/module/move/willbe/src/command/publish.rs +++ b/module/move/willbe/src/command/publish.rs @@ -15,7 +15,7 @@ mod private { #[ former( default = Channel::Stable ) ] channel : Channel, - #[ former( default = true ) ] + #[ former( default = false ) ] exclude_dev_dependencies : bool, #[ former( default = false ) ] commit_changes : bool, diff --git a/module/move/willbe/src/command/publish_diff.rs b/module/move/willbe/src/command/publish_diff.rs index 5e4bc27889..74cdbcbc48 100644 --- a/module/move/willbe/src/command/publish_diff.rs +++ b/module/move/willbe/src/command/publish_diff.rs @@ -13,7 +13,7 @@ mod private #[ derive( former::Former ) ] struct PublishDiffProperties { - #[ former( default = true ) ] + #[ former( default = false ) ] exclude_dev_dependencies : bool, keep_archive : Option< PathBuf >, }