|
| 1 | +use distribution_types::Index; |
1 | 2 | use itertools::Itertools; |
2 | 3 | use pep440_rs::{Version, VersionSpecifier, VersionSpecifiers}; |
3 | 4 | use pep508_rs::{ExtraName, MarkerTree, PackageName, Requirement, VersionOrUrl}; |
4 | 5 | use std::path::Path; |
5 | 6 | use std::str::FromStr; |
6 | 7 | use std::{fmt, mem}; |
7 | 8 | use thiserror::Error; |
8 | | -use toml_edit::{Array, DocumentMut, Item, RawString, Table, TomlError, Value}; |
| 9 | +use toml_edit::{Array, ArrayOfTables, DocumentMut, Item, RawString, Table, TomlError, Value}; |
9 | 10 | use uv_fs::PortablePath; |
10 | 11 |
|
11 | 12 | use crate::pyproject::{DependencyType, Source}; |
@@ -190,6 +191,77 @@ impl PyProjectTomlMut { |
190 | 191 | Ok(edit) |
191 | 192 | } |
192 | 193 |
|
| 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 | + |
193 | 265 | /// Adds a dependency to `project.optional-dependencies`. |
194 | 266 | /// |
195 | 267 | /// Returns `true` if the dependency was added, `false` if it was updated. |
|
0 commit comments