@@ -3,7 +3,8 @@ use std::path::Path;
33use std:: str:: FromStr ;
44use std:: { fmt, mem} ;
55use thiserror:: Error ;
6- use toml_edit:: { Array , DocumentMut , Item , RawString , Table , TomlError , Value } ;
6+ use toml_edit:: { Array , ArrayOfTables , DocumentMut , Item , RawString , Table , TomlError , Value } ;
7+ use uv_distribution_types:: Index ;
78use uv_fs:: PortablePath ;
89use uv_pep440:: { Version , VersionSpecifier , VersionSpecifiers } ;
910use uv_pep508:: { ExtraName , MarkerTree , PackageName , Requirement , VersionOrUrl } ;
@@ -190,6 +191,77 @@ impl PyProjectTomlMut {
190191 Ok ( edit)
191192 }
192193
194+ /// Add an [`Index`] to `tool.uv.index`.
195+ pub fn add_index ( & mut self , index : & Index ) -> Result < ( ) , Error > {
196+ let existing = self
197+ . doc
198+ . entry ( "tool" )
199+ . or_insert ( implicit ( ) )
200+ . as_table_mut ( )
201+ . ok_or ( Error :: MalformedSources ) ?
202+ . entry ( "uv" )
203+ . or_insert ( implicit ( ) )
204+ . as_table_mut ( )
205+ . ok_or ( Error :: MalformedSources ) ?
206+ . entry ( "index" )
207+ . or_insert ( Item :: ArrayOfTables ( ArrayOfTables :: new ( ) ) )
208+ . as_array_of_tables ( )
209+ . ok_or ( Error :: MalformedSources ) ?;
210+
211+ let mut table = Table :: new ( ) ;
212+ if let Some ( name) = index. name . as_ref ( ) {
213+ table. insert ( "name" , toml_edit:: value ( name. to_string ( ) ) ) ;
214+ }
215+ table. insert ( "url" , toml_edit:: value ( index. url . to_string ( ) ) ) ;
216+ if index. default {
217+ table. insert ( "default" , toml_edit:: value ( true ) ) ;
218+ }
219+
220+ // Push the item to the table.
221+ let mut updated = ArrayOfTables :: new ( ) ;
222+ updated. push ( table) ;
223+ for table in existing {
224+ // If there's another index with the same name, replace it.
225+ if table
226+ . get ( "name" )
227+ . is_some_and ( |name| name. as_str ( ) == index. name . as_deref ( ) )
228+ {
229+ continue ;
230+ }
231+
232+ // If there's another default index, remove it.
233+ if index. default
234+ && table
235+ . get ( "default" )
236+ . is_some_and ( |default| default. as_bool ( ) == Some ( true ) )
237+ {
238+ continue ;
239+ }
240+
241+ // If there's another index with the same URL, replace it.
242+ if table
243+ . get ( "url" )
244+ . is_some_and ( |url| url. as_str ( ) == Some ( index. url . url ( ) . as_str ( ) ) )
245+ {
246+ continue ;
247+ }
248+
249+ updated. push ( table. clone ( ) ) ;
250+ }
251+ self . doc
252+ . entry ( "tool" )
253+ . or_insert ( implicit ( ) )
254+ . as_table_mut ( )
255+ . ok_or ( Error :: MalformedSources ) ?
256+ . entry ( "uv" )
257+ . or_insert ( implicit ( ) )
258+ . as_table_mut ( )
259+ . ok_or ( Error :: MalformedSources ) ?
260+ . insert ( "index" , Item :: ArrayOfTables ( updated) ) ;
261+
262+ Ok ( ( ) )
263+ }
264+
193265 /// Adds a dependency to `project.optional-dependencies`.
194266 ///
195267 /// Returns `true` if the dependency was added, `false` if it was updated.
0 commit comments