@@ -45,68 +45,111 @@ def set_version(self, version: str) -> None:
4545 self .set_lock_version (version )
4646
4747 def set_lock_version (self , version : str ) -> None :
48- cargo_toml = parse (self .file .read_text ())
49- cargo_lock = parse (self .lock_file .read_text ())
50- packages = cargo_lock ["package" ]
48+ cargo_toml_content = parse (self .file .read_text ())
49+ cargo_lock_content = parse (self .lock_file .read_text ())
50+ packages = cargo_lock_content ["package" ]
51+
5152 if TYPE_CHECKING :
5253 assert isinstance (packages , AoT )
5354
54- root_pkg = _table_get (cargo_toml , "package" )
55+ root_pkg = _table_get (cargo_toml_content , "package" )
5556 if root_pkg is not None :
5657 name = root_pkg .get ("name" )
5758 if isinstance (name , str ):
5859 _lock_set_versions (packages , {name }, version )
59- self .lock_file .write_text (dumps (cargo_lock ))
60+ self .lock_file .write_text (dumps (cargo_lock_content ))
6061 return
6162
62- ws = _table_get (cargo_toml , "workspace" ) or {}
63- members = cast ("list[str]" , ws .get ("members" , []) or [])
64- excludes = cast ("list[str]" , ws .get ("exclude" , []) or [])
65- inheriting = _workspace_inheriting_member_names (members , excludes )
63+ ws = _table_get (cargo_toml_content , "workspace" ) or {}
64+ member_globs = cast ("list[str]" , ws .get ("members" , []) or [])
65+ exclude_globs = cast ("list[str]" , ws .get ("exclude" , []) or [])
66+ inheriting = _workspace_inheriting_member_names (member_globs , exclude_globs )
6667 _lock_set_versions (packages , inheriting , version )
67- self .lock_file .write_text (dumps (cargo_lock ))
68+ self .lock_file .write_text (dumps (cargo_lock_content ))
6869
6970
7071def _table_get (doc : TOMLDocument , key : str ) -> DictLike | None :
71- """Return a dict-like table for `key` if present, else None (type-safe for Pylance)."""
72+ """Get a TOML table by key as a dict-like object.
73+
74+ Returns:
75+ The value at `doc[key]` cast to a dict-like table (supports `.get`) if it
76+ exists and is table/container-like; otherwise returns None.
77+
78+ Rationale:
79+ tomlkit returns loosely-typed Container/Table objects; using a small
80+ helper keeps call sites readable and makes type-checkers happier.
81+ """
7282 try :
73- v = doc [key ] # tomlkit returns Container/Table-like; typing is loose
83+ value = doc [key ]
7484 except NonExistentKey :
7585 return None
76- return cast ("DictLike" , v ) if hasattr (v , "get" ) else None
86+ return cast ("DictLike" , value ) if hasattr (value , "get" ) else None
7787
7888
7989def _root_version_table (doc : TOMLDocument ) -> DictLike :
80- """Prefer [workspace.package]; fallback to [package]."""
81- ws = _table_get (doc , "workspace" )
82- if ws is not None :
83- pkg = ws .get ("package" )
84- if hasattr (pkg , "get" ):
85- return cast ("DictLike" , pkg )
86- pkg = _table_get (doc , "package" )
87- if pkg is None :
90+ """Return the table that owns the "root" version field.
91+
92+ This provider supports two layouts:
93+
94+ 1) Workspace virtual manifests:
95+ [workspace.package]
96+ version = "x.y.z"
97+
98+ 2) Regular crate(non-workspace root manifest):
99+ [package]
100+ version = "x.y.z"
101+
102+ The selected table is where `get()` reads from and `set()` writes to.
103+ """
104+ workspace_table = _table_get (doc , "workspace" )
105+ if workspace_table is not None :
106+ workspace_package_table = workspace_table .get ("package" )
107+ if hasattr (workspace_package_table , "get" ):
108+ return cast ("DictLike" , workspace_package_table )
109+
110+ package_table = _table_get (doc , "package" )
111+ if package_table is None :
88112 raise NonExistentKey ("expected either [workspace.package] or [package]" )
89- return pkg
113+ return package_table
90114
91115
92116def _is_workspace_inherited_version (v : Any ) -> bool :
93117 return hasattr (v , "get" ) and cast ("DictLike" , v ).get ("workspace" ) is True
94118
95119
96120def _iter_member_dirs (
97- members : Iterable [str ], excludes : Iterable [str ]
121+ member_globs : Iterable [str ], exclude_globs : Iterable [str ]
98122) -> Iterable [Path ]:
99- for pat in members :
100- for p in glob .glob (pat , recursive = True ):
101- if any (fnmatch .fnmatch (p , ex ) for ex in excludes ):
123+ """Yield workspace member directories matched by `member_globs`, excluding `exclude_globs`.
124+
125+ Cargo workspaces define members/exclude as glob patterns (e.g. "crates/*").
126+ This helper expands those patterns and yields the corresponding directories
127+ as `Path` objects, skipping any matches that satisfy an exclude glob.
128+
129+ Kept as a helper to make call sites read as domain logic ("iterate member dirs")
130+ rather than glob/filter plumbing.
131+ """
132+ for member_glob in member_globs :
133+ for match in glob .glob (member_glob , recursive = True ):
134+ if any (fnmatch .fnmatch (match , ex ) for ex in exclude_globs ):
102135 continue
103- yield Path (p )
136+ yield Path (match )
104137
105138
106139def _workspace_inheriting_member_names (
107140 members : Iterable [str ], excludes : Iterable [str ]
108141) -> set [str ]:
109- out : set [str ] = set ()
142+ """Return workspace member crate names that inherit the workspace version.
143+
144+ A member is considered "inheriting" when its Cargo.toml has:
145+ [package]
146+ version.workspace = true
147+
148+ This scans `members` globs (respecting `excludes`) and returns the set of
149+ `[package].name` values for matching crates. Missing/invalid Cargo.toml files
150+ are ignored.
151+ """
152+ inheriting_member_names : set [str ] = set ()
110153 for d in _iter_member_dirs (members , excludes ):
111154 cargo_file = d / "Cargo.toml"
112155 if not cargo_file .exists ():
@@ -118,13 +161,25 @@ def _workspace_inheriting_member_names(
118161 if _is_workspace_inherited_version (pkgd .get ("version" )):
119162 name = pkgd .get ("name" )
120163 if isinstance (name , str ):
121- out .add (name )
122- return out
164+ inheriting_member_names .add (name )
165+ return inheriting_member_names
166+
167+
168+ def _lock_set_versions (packages : Any , package_names : set [str ], version : str ) -> None :
169+ """Update Cargo.lock package entries in-place.
123170
171+ Args:
172+ packages: `Cargo.lock` parsed TOML "package" array (AoT-like). Mutated in-place.
173+ package_names: Set of package names whose `version` field should be updated.
174+ version: New version string to write.
124175
125- def _lock_set_versions (packages : Any , names : set [str ], version : str ) -> None :
126- if not names :
176+ Notes:
177+ We use `enumerate` + index assignment because tomlkit AoT entries may be
178+ Container-like and direct mutation patterns vary; indexed assignment is
179+ reliable for updating the underlying document.
180+ """
181+ if not package_names :
127182 return
128- for i , p in enumerate (packages ):
129- if getattr (p , "get" , None ) and p .get ("name" ) in names :
183+ for i , pkg_entry in enumerate (packages ):
184+ if getattr (pkg_entry , "get" , None ) and pkg_entry .get ("name" ) in package_names :
130185 packages [i ]["version" ] = version
0 commit comments