@@ -6,106 +6,139 @@ description = "In all Cargo.toml files in the repo, for all dependencies that ha
66
77[ dependencies]
88regex = "1.5"
9- semver = "1.0"
109toml_edit = "0.22"
1110---
1211
1312use regex:: Regex ;
14- use semver:: Version ;
15- use std:: collections:: HashMap ;
1613use std:: io:: Write ;
14+ use std:: sync:: atomic:: { AtomicBool , Ordering } ;
1715use std:: { env, error:: Error , fs, path:: PathBuf } ;
1816use toml_edit:: { value, DocumentMut , Item , Table } ;
1917
18+ static VERBOSE : AtomicBool = AtomicBool :: new ( false ) ;
19+
20+ macro_rules! verbose {
21+ ( $( $arg: tt) * ) => {
22+ if VERBOSE . load( Ordering :: Relaxed ) {
23+ eprintln!( "[VERBOSE] {}" , format!( $( $arg) * ) ) ;
24+ }
25+ } ;
26+ }
27+
2028fn main ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
21- let add_mode = env:: args ( )
22- . nth ( 1 )
29+ let args: Vec < String > = env:: args ( ) . collect ( ) ;
30+
31+ // Check for --verbose flag
32+ let verbose_mode = args. iter ( ) . any ( |arg| arg == "--verbose" || arg == "-v" ) ;
33+ VERBOSE . store ( verbose_mode, Ordering :: Relaxed ) ;
34+
35+ // Filter out verbose flag to get mode argument
36+ let mode_args: Vec < & String > = args. iter ( )
37+ . skip ( 1 )
38+ . filter ( |arg| * arg != "--verbose" && * arg != "-v" )
39+ . collect ( ) ;
40+
41+ let add_mode = mode_args. first ( )
2342 . map ( |arg| match arg. as_str ( ) {
2443 "add" => true ,
2544 "update" => false ,
26- _ => panic ! ( "Invalid mode. Use 'add' or 'update'." ) ,
45+ _ => panic ! ( "Invalid mode. Use 'add' or 'update'. Optional: --verbose or -v" )
2746 } )
28- . expect ( "requires 'add' or 'update' mode argument" ) ;
47+ . expect ( "requires 'add' or 'update' mode argument. Optional: --verbose or -v" ) ;
48+
49+ verbose ! ( "Mode: {}" , if add_mode { "add" } else { "update" } ) ;
2950
3051 let script_root = PathBuf :: from ( env:: var ( "CARGO_MANIFEST_DIR" ) ?) ;
31- let repo_root = script_root. join ( "../../.." ) . canonicalize ( ) ?;
52+ let repo_root = script_root. join ( "../.." ) . canonicalize ( ) ?;
53+ verbose ! ( "Repository root: {}" , repo_root. display( ) ) ;
3254
3355 // find all Cargo.toml files in the repo_root directory
34- let exclude_dirs = vec ! [ repo_root. join( "eng" ) , repo_root. join( "target" ) ] ;
56+ let exclude_dirs = vec ! [
57+ repo_root. join( "eng" ) ,
58+ repo_root. join( "target" )
59+ ] ;
60+ verbose ! ( "Excluded directories: {:?}" , exclude_dirs) ;
3561
3662 let toml_files = load_cargo_toml_files ( & repo_root, & exclude_dirs) ?;
63+ verbose ! ( "Found {} Cargo.toml files" , toml_files. len( ) ) ;
3764
3865 let package_versions = get_package_versions ( & toml_files) ;
66+ verbose ! ( "Found {} packages with versions" , package_versions. len( ) ) ;
67+ for ( name, version, is_publish_disabled) in & package_versions {
68+ verbose ! ( " Package: {} @ {} (publish_disabled: {})" , name, version, is_publish_disabled) ;
69+ }
3970
71+ verbose ! ( "Starting to process toml files..." ) ;
4072 for mut toml_file in toml_files {
73+ verbose ! ( "Processing: {}" , toml_file. path. display( ) ) ;
4174 let should_add = add_mode && !toml_file. is_publish_disabled ;
75+ verbose ! ( " should_add: {} (add_mode: {}, is_publish_disabled: {})" ,
76+ should_add, add_mode, toml_file. is_publish_disabled) ;
4277
43- update_package_versions (
44- toml_file. document . as_table_mut ( ) ,
45- & package_versions,
46- should_add,
47- ) ;
78+ update_package_versions ( toml_file. document . as_table_mut ( ) , & package_versions, should_add, & toml_file. path ) ;
4879
4980 // if the toml file has a workspace table, update the workspace table
5081 if let Some ( workspace) = toml_file. document . get_mut ( "workspace" ) {
5182 if let Some ( table) = workspace. as_table_mut ( ) {
52- update_package_versions ( table, & package_versions, should_add) ;
83+ verbose ! ( " Processing workspace table" ) ;
84+ update_package_versions ( table, & package_versions, should_add, & toml_file. path ) ;
5385 }
5486 }
5587
5688 // write the updated document back to the file
57- let mut file = fs:: File :: create ( toml_file. path ) ?;
89+ verbose ! ( " Writing changes to file" ) ;
90+ let mut file = fs:: File :: create ( & toml_file. path ) ?;
5891 fs:: File :: write_all ( & mut file, toml_file. document . to_string ( ) . as_bytes ( ) ) ?;
5992 }
6093
94+ verbose ! ( "Done!" ) ;
6195 Ok ( ( ) )
6296}
6397
64- fn load_cargo_toml_files (
65- repo_root : & PathBuf ,
66- exclude_dirs : & Vec < PathBuf > ,
67- ) -> Result < Vec < TomlInfo > , Box < dyn Error > > {
98+ fn load_cargo_toml_files ( repo_root : & PathBuf , exclude_dirs : & Vec < PathBuf > ) -> Result < Vec < TomlInfo > , Box < dyn Error > > {
6899 let mut toml_paths = Vec :: new ( ) ;
100+ verbose ! ( "Searching for Cargo.toml files in: {}" , repo_root. display( ) ) ;
69101 find_cargo_toml_files ( repo_root, exclude_dirs, & mut toml_paths) ?;
102+ verbose ! ( "Found {} Cargo.toml paths" , toml_paths. len( ) ) ;
70103
71104 let mut toml_files = Vec :: new ( ) ;
72105 for path in toml_paths {
106+ verbose ! ( " Loading: {}" , path. display( ) ) ;
73107 let content = fs:: read_to_string ( & path) ?;
74108 let doc = content. parse :: < DocumentMut > ( ) ?;
75109 let package_table = doc. get ( "package" ) . and_then ( Item :: as_table) ;
76- let publish_property = package_table
77- . and_then ( |table| table. get ( "publish" ) )
78- . and_then ( Item :: as_bool) ;
79- let package_name = package_table
80- . and_then ( |table| table. get ( "name" ) )
81- . and_then ( Item :: as_str) ;
82- let package_version = package_table
83- . and_then ( |table| table. get ( "version" ) )
84- . and_then ( Item :: as_str) ;
110+ let publish_property = package_table. and_then ( |table| table. get ( "publish" ) ) . and_then ( Item :: as_bool) ;
111+ let package_name = package_table. and_then ( |table| table. get ( "name" ) ) . and_then ( Item :: as_str) ;
112+ let package_version = package_table. and_then ( |table| table. get ( "version" ) ) . and_then ( Item :: as_str) ;
113+
114+ verbose ! ( " name: {:?}, version: {:?}, publish: {:?}" ,
115+ package_name, package_version, publish_property) ;
85116
86117 toml_files. push ( TomlInfo {
87118 path,
88119 package_name : package_name. map ( |s| s. to_string ( ) ) ,
89120 package_version : package_version. map ( |s| s. to_string ( ) ) ,
90121 is_publish_disabled : publish_property == Some ( false ) ,
91- document : doc,
122+ document : doc
92123 } ) ;
93124 }
94125
95126 Ok ( toml_files)
96127}
97128
98- fn find_cargo_toml_files (
99- dir : & PathBuf ,
100- exclude_dirs : & Vec < PathBuf > ,
101- toml_paths : & mut Vec < PathBuf > ,
102- ) -> Result < ( ) , Box < dyn Error > > {
129+ fn find_cargo_toml_files ( dir : & PathBuf , exclude_dirs : & Vec < PathBuf > , toml_paths : & mut Vec < PathBuf > ) -> Result < ( ) , Box < dyn Error > > {
130+ verbose ! ( " Scanning directory: {}" , dir. display( ) ) ;
103131 for entry in fs:: read_dir ( dir) ? {
104132 let entry = entry?;
105133 let path = entry. path ( ) ;
106- if path. is_dir ( ) && !exclude_dirs. contains ( & path) {
107- find_cargo_toml_files ( & path, exclude_dirs, toml_paths) ?;
134+ if path. is_dir ( ) {
135+ if exclude_dirs. contains ( & path) {
136+ verbose ! ( " Skipping excluded dir: {}" , path. display( ) ) ;
137+ } else {
138+ find_cargo_toml_files ( & path, exclude_dirs, toml_paths) ?;
139+ }
108140 } else if path. is_file ( ) && path. file_name ( ) == Some ( "Cargo.toml" . as_ref ( ) ) {
141+ verbose ! ( " Found Cargo.toml: {}" , path. display( ) ) ;
109142 toml_paths. push ( path) ;
110143 }
111144 }
@@ -114,56 +147,20 @@ fn find_cargo_toml_files(
114147}
115148
116149fn get_package_versions ( toml_files : & Vec < TomlInfo > ) -> Vec < ( String , String , bool ) > {
117- // Use a HashMap to deduplicate package versions.
118- // When there are multiple Cargo.toml files with the same package name but different versions
119- // (e.g., test fixtures, examples, or stale files), we need to pick the correct version.
120- let mut package_map: HashMap < String , ( String , bool ) > = HashMap :: new ( ) ;
150+ let mut package_versions = Vec :: new ( ) ;
121151
122152 for toml_file in toml_files {
123153 if toml_file. package_name . is_none ( ) || toml_file. package_version . is_none ( ) {
124154 continue ;
125155 }
126156
127- let name = toml_file. package_name . clone ( ) . unwrap ( ) ;
128- let version = toml_file. package_version . clone ( ) . unwrap ( ) ;
129- let is_publish_disabled = toml_file. is_publish_disabled ;
130-
131- // Determine if we should use this version
132- let should_use = match package_map. get ( & name) {
133- None => true , // First occurrence, always use it
134- Some ( ( existing_version, existing_publish_disabled) ) => {
135- // Prefer publishable packages over non-publishable ones
136- if * existing_publish_disabled && !is_publish_disabled {
137- true
138- } else if !* existing_publish_disabled && is_publish_disabled {
139- false
140- } else {
141- // Both have the same publish status, prefer the higher version
142- match ( Version :: parse ( & version) , Version :: parse ( existing_version) ) {
143- ( Ok ( new_ver) , Ok ( existing_ver) ) => new_ver > existing_ver,
144- _ => false , // If parsing fails, keep existing
145- }
146- }
147- }
148- } ;
149-
150- if should_use {
151- package_map. insert ( name, ( version, is_publish_disabled) ) ;
152- }
157+ package_versions. push ( ( toml_file. package_name . clone ( ) . unwrap ( ) , toml_file. package_version . clone ( ) . unwrap ( ) , toml_file. is_publish_disabled ) ) ;
153158 }
154159
155- // Convert HashMap back to Vec for compatibility with existing code
156- package_map
157- . into_iter ( )
158- . map ( |( name, ( version, is_publish_disabled) ) | ( name, version, is_publish_disabled) )
159- . collect ( )
160+ package_versions
160161}
161162
162- fn update_package_versions (
163- toml : & mut Table ,
164- package_versions : & Vec < ( String , String , bool ) > ,
165- add : bool ,
166- ) {
163+ fn update_package_versions ( toml : & mut Table , package_versions : & Vec < ( String , String , bool ) > , add : bool , file_path : & PathBuf ) {
167164 // for each dependency table, for each package in package_versions
168165 // if the package is in the dependency table
169166 // if the dependency has both path and version properties, update the version property
@@ -173,20 +170,23 @@ fn update_package_versions(
173170 // 3. the add flag is true
174171
175172 let dependency_tables = get_dependency_tables ( toml) ;
173+ verbose ! ( " Found {} dependency tables" , dependency_tables. len( ) ) ;
176174
177175 for ( table_name, table) in dependency_tables {
176+ verbose ! ( " Processing table: {}" , table_name) ;
178177 for ( package, version, is_publish_disabled) in package_versions {
179178 if let Some ( dependency) = table. get_mut ( package) {
180- // azure_idenentity will only be a transitive dev-dependency
181- let should_add = add
182- && table_name != "dev-dependencies"
183- && !is_publish_disabled
184- && package != "azure_identity" ;
179+ // azure_identity will only be a transitive dev-dependency
180+ let should_add = add && table_name != "dev-dependencies" && !is_publish_disabled && package != "azure_identity" ;
185181
186182 let has_path_property = dependency. get ( "path" ) . is_some ( ) ;
187183 let has_version_property = dependency. get ( "version" ) . is_some ( ) ;
188184
185+ verbose ! ( " Checking package '{}': has_path={}, has_version={}, should_add={}" ,
186+ package, has_path_property, has_version_property, should_add) ;
187+
189188 if has_path_property && ( has_version_property || should_add) {
189+ verbose ! ( " Updating '{}' version to '{}' in {}" , package, version, file_path. display( ) ) ;
190190 dependency[ "version" ] = value ( version) ;
191191 }
192192 }
@@ -201,6 +201,7 @@ fn get_dependency_tables(toml: &mut Table) -> Vec<(String, &mut Table)> {
201201 for ( key, value) in toml. iter_mut ( ) {
202202 if let Some ( table) = value. as_table_mut ( ) {
203203 if re. is_match ( & key) {
204+ verbose ! ( " Found dependency table: {}" , key) ;
204205 tables. push ( ( key. to_string ( ) , table) ) ;
205206 }
206207 }
0 commit comments