@@ -15,22 +15,30 @@ use std::{env, error::Error, fs, path::PathBuf};
1515use toml_edit:: { value, DocumentMut , Item , Table } ;
1616
1717fn main ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
18- let add_mode = env:: args ( ) . nth ( 1 )
18+ let add_mode = env:: args ( )
19+ . nth ( 1 )
1920 . map ( |arg| match arg. as_str ( ) {
2021 "add" => true ,
2122 "update" => false ,
22- _ => panic ! ( "Invalid mode. Use 'add' or 'update'." )
23+ _ => panic ! ( "Invalid mode. Use 'add' or 'update'." ) ,
2324 } )
2425 . expect ( "requires 'add' or 'update' mode argument" ) ;
2526
27+ println ! (
28+ "Running update-pathversions in {} mode" ,
29+ if add_mode { "add" } else { "update" }
30+ ) ;
31+
2632 let script_root = PathBuf :: from ( env:: var ( "CARGO_MANIFEST_DIR" ) ?) ;
27- let repo_root = script_root. join ( "../../.." ) . canonicalize ( ) ?;
33+ let repo_root = script_root. join ( "../.." ) . canonicalize ( ) ?;
34+
35+ println ! (
36+ "Scanning for Cargo.toml files under {}" ,
37+ repo_root. display( )
38+ ) ;
2839
2940 // find all Cargo.toml files in the repo_root directory
30- let exclude_dirs = vec ! [
31- repo_root. join( "eng" ) ,
32- repo_root. join( "target" )
33- ] ;
41+ let exclude_dirs = vec ! [ repo_root. join( "eng" ) , repo_root. join( "target" ) ] ;
3442
3543 let toml_files = load_cargo_toml_files ( & repo_root, & exclude_dirs) ?;
3644
@@ -39,15 +47,26 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
3947 for mut toml_file in toml_files {
4048 let should_add = add_mode && !toml_file. is_publish_disabled ;
4149
42- update_package_versions ( toml_file. document . as_table_mut ( ) , & package_versions, should_add) ;
50+ let mut updated = update_package_versions (
51+ toml_file. document . as_table_mut ( ) ,
52+ & package_versions,
53+ should_add,
54+ ) ;
4355
4456 // if the toml file has a workspace table, update the workspace table
4557 if let Some ( workspace) = toml_file. document . get_mut ( "workspace" ) {
58+ // print out that we're working on a workspace
4659 if let Some ( table) = workspace. as_table_mut ( ) {
47- update_package_versions ( table, & package_versions, should_add) ;
60+ updated = update_package_versions ( table, & package_versions, should_add) || updated ;
4861 }
4962 }
5063
64+ if !updated {
65+ continue ;
66+ }
67+
68+ println ! ( "Updating {}" , toml_file. path. display( ) ) ;
69+
5170 // write the updated document back to the file
5271 let mut file = fs:: File :: create ( toml_file. path ) ?;
5372 fs:: File :: write_all ( & mut file, toml_file. document . to_string ( ) . as_bytes ( ) ) ?;
@@ -56,32 +75,49 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
5675 Ok ( ( ) )
5776}
5877
59- fn load_cargo_toml_files ( repo_root : & PathBuf , exclude_dirs : & Vec < PathBuf > ) -> Result < Vec < TomlInfo > , Box < dyn Error > > {
78+ fn load_cargo_toml_files (
79+ repo_root : & PathBuf ,
80+ exclude_dirs : & Vec < PathBuf > ,
81+ ) -> Result < Vec < TomlInfo > , Box < dyn Error > > {
6082 let mut toml_paths = Vec :: new ( ) ;
6183 find_cargo_toml_files ( repo_root, exclude_dirs, & mut toml_paths) ?;
6284
6385 let mut toml_files = Vec :: new ( ) ;
86+
6487 for path in toml_paths {
6588 let content = fs:: read_to_string ( & path) ?;
6689 let doc = content. parse :: < DocumentMut > ( ) ?;
6790 let package_table = doc. get ( "package" ) . and_then ( Item :: as_table) ;
68- let publish_property = package_table. and_then ( |table| table. get ( "publish" ) ) . and_then ( Item :: as_bool) ;
69- let package_name = package_table. and_then ( |table| table. get ( "name" ) ) . and_then ( Item :: as_str) ;
70- let package_version = package_table. and_then ( |table| table. get ( "version" ) ) . and_then ( Item :: as_str) ;
91+
92+ let publish_property = package_table
93+ . and_then ( |table| table. get ( "publish" ) )
94+ . and_then ( Item :: as_bool) ;
95+
96+ let package_name = package_table
97+ . and_then ( |table| table. get ( "name" ) )
98+ . and_then ( Item :: as_str) ;
99+
100+ let package_version = package_table
101+ . and_then ( |table| table. get ( "version" ) )
102+ . and_then ( Item :: as_str) ;
71103
72104 toml_files. push ( TomlInfo {
73105 path,
74106 package_name : package_name. map ( |s| s. to_string ( ) ) ,
75107 package_version : package_version. map ( |s| s. to_string ( ) ) ,
76108 is_publish_disabled : publish_property == Some ( false ) ,
77- document : doc
109+ document : doc,
78110 } ) ;
79111 }
80112
81113 Ok ( toml_files)
82114}
83115
84- fn find_cargo_toml_files ( dir : & PathBuf , exclude_dirs : & Vec < PathBuf > , toml_paths : & mut Vec < PathBuf > ) -> Result < ( ) , Box < dyn Error > > {
116+ fn find_cargo_toml_files (
117+ dir : & PathBuf ,
118+ exclude_dirs : & Vec < PathBuf > ,
119+ toml_paths : & mut Vec < PathBuf > ,
120+ ) -> Result < ( ) , Box < dyn Error > > {
85121 for entry in fs:: read_dir ( dir) ? {
86122 let entry = entry?;
87123 let path = entry. path ( ) ;
@@ -103,38 +139,98 @@ fn get_package_versions(toml_files: &Vec<TomlInfo>) -> Vec<(String, String, bool
103139 continue ;
104140 }
105141
106- package_versions. push ( ( toml_file. package_name . clone ( ) . unwrap ( ) , toml_file. package_version . clone ( ) . unwrap ( ) , toml_file. is_publish_disabled ) ) ;
142+ package_versions. push ( (
143+ toml_file. package_name . clone ( ) . unwrap ( ) ,
144+ toml_file. package_version . clone ( ) . unwrap ( ) ,
145+ toml_file. is_publish_disabled ,
146+ ) ) ;
107147 }
108148
109149 package_versions
110150}
111151
112- fn update_package_versions ( toml : & mut Table , package_versions : & Vec < ( String , String , bool ) > , add : bool ) {
152+ fn update_package_versions (
153+ toml : & mut Table ,
154+ package_versions : & Vec < ( String , String , bool ) > ,
155+ add : bool ,
156+ ) -> bool {
157+ /// Updates package versions in dependency tables within a TOML configuration.
158+ ///
159+ /// This function scans through all dependency tables in the provided TOML table and updates
160+ /// version properties for packages that have both path and version dependencies. It can also
161+ /// add version properties to path-only dependencies based on the `add` parameter.
162+ ///
163+ /// # Arguments
164+ ///
165+ /// * `toml` - A mutable reference to the TOML table to update
166+ /// * `package_versions` - A vector of tuples containing package name, version, and publish status
167+ /// * `add` - Whether to add version properties to path-only dependencies (when applicable)
168+ ///
169+ /// # Returns
170+ ///
171+ /// Returns `true` if any modifications were made to the TOML table, `false` otherwise.
172+ /// This indicates whether the file needs to be written back to disk.
173+ //
113174 // for each dependency table, for each package in package_versions
114175 // if the package is in the dependency table
115176 // if the dependency has both path and version properties, update the version property
116177 // if the dependency has has path, but not version, add the version property only if
117178 // 1. the table name is not "dev-dependencies"
118179 // 2. the package is not publish disabled
119180 // 3. the add flag is true
181+ //
182+ let crate_name = toml
183+ . get ( "package" )
184+ . and_then ( Item :: as_table)
185+ . and_then ( |table| table. get ( "name" ) )
186+ . and_then ( Item :: as_str)
187+ . unwrap_or ( "<unknown>" )
188+ . trim_matches ( '"' )
189+ . trim ( )
190+ . to_string ( ) ;
120191
121192 let dependency_tables = get_dependency_tables ( toml) ;
122-
193+ let mut updated = false ;
123194 for ( table_name, table) in dependency_tables {
124195 for ( package, version, is_publish_disabled) in package_versions {
125196 if let Some ( dependency) = table. get_mut ( package) {
126197 // azure_idenentity will only be a transitive dev-dependency
127- let should_add = add && table_name != "dev-dependencies" && !is_publish_disabled && package != "azure_identity" ;
198+ let should_add = add
199+ && table_name != "dev-dependencies"
200+ && !is_publish_disabled
201+ && package != "azure_identity" ;
128202
129203 let has_path_property = dependency. get ( "path" ) . is_some ( ) ;
130204 let has_version_property = dependency. get ( "version" ) . is_some ( ) ;
131205
132- if has_path_property && ( has_version_property || should_add) {
133- dependency[ "version" ] = value ( version) ;
206+ if has_path_property {
207+ if has_version_property {
208+ let current_version = dependency
209+ . get ( "version" )
210+ . and_then ( Item :: as_str)
211+ . unwrap_or ( "" ) ;
212+ if current_version != version {
213+ dependency[ "version" ] = value ( version) ;
214+ println ! (
215+ "set {} to version {} in {} {}" ,
216+ package, version, crate_name, table_name
217+ ) ;
218+ updated = true ;
219+ }
220+ } else if should_add {
221+ dependency[ "version" ] = value ( version) ;
222+ println ! (
223+ "added version {} to {} in {} {}" ,
224+ version, package, crate_name, table_name
225+ ) ;
226+ updated = true ;
227+ }
134228 }
135229 }
136230 }
137231 }
232+
233+ updated
138234}
139235
140236fn get_dependency_tables ( toml : & mut Table ) -> Vec < ( String , & mut Table ) > {
0 commit comments