-
Notifications
You must be signed in to change notification settings - Fork 723
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Track tool entry points in receipts (#4634)
We need this to power uninstallations! The latter two commits were reviewed in: - #4637 - #4638 Note this is a breaking change for existing tool installations, but it's in preview and very new. In the future, we'll need a clear upgrade path for tool receipt changes.
- Loading branch information
Showing
7 changed files
with
203 additions
and
47 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,127 @@ | ||
use std::path::PathBuf; | ||
|
||
use path_slash::PathBufExt; | ||
use pypi_types::VerbatimParsedUrl; | ||
use serde::{Deserialize, Serialize}; | ||
use serde::Deserialize; | ||
use toml_edit::value; | ||
use toml_edit::Array; | ||
use toml_edit::Table; | ||
use toml_edit::Value; | ||
|
||
/// A tool entry. | ||
#[allow(dead_code)] | ||
#[derive(Debug, Clone, Serialize, PartialEq, Eq, Deserialize)] | ||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)] | ||
#[serde(rename_all = "kebab-case")] | ||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] | ||
pub struct Tool { | ||
// The requirements requested by the user during installation. | ||
requirements: Vec<pep508_rs::Requirement<VerbatimParsedUrl>>, | ||
/// The Python requested by the user during installation. | ||
python: Option<String>, | ||
// A mapping of entry point names to their metadata. | ||
entrypoints: Vec<ToolEntrypoint>, | ||
} | ||
|
||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Deserialize)] | ||
#[serde(rename_all = "kebab-case")] | ||
pub struct ToolEntrypoint { | ||
name: String, | ||
install_path: PathBuf, | ||
} | ||
|
||
/// Format an array so that each element is on its own line and has a trailing comma. | ||
/// | ||
/// Example: | ||
/// | ||
/// ```toml | ||
/// requirements = [ | ||
/// "foo", | ||
/// "bar", | ||
/// ] | ||
/// ``` | ||
fn each_element_on_its_line_array(elements: impl Iterator<Item = impl Into<Value>>) -> Array { | ||
let mut array = elements | ||
.map(Into::into) | ||
.map(|mut value| { | ||
// Each dependency is on its own line and indented. | ||
value.decor_mut().set_prefix("\n "); | ||
value | ||
}) | ||
.collect::<Array>(); | ||
// With a trailing comma, inserting another entry doesn't change the preceding line, | ||
// reducing the diff noise. | ||
array.set_trailing_comma(true); | ||
// The line break between the last element's comma and the closing square bracket. | ||
array.set_trailing("\n"); | ||
array | ||
} | ||
|
||
impl Tool { | ||
/// Create a new `Tool`. | ||
pub fn new( | ||
requirements: Vec<pep508_rs::Requirement<VerbatimParsedUrl>>, | ||
python: Option<String>, | ||
entrypoints: impl Iterator<Item = ToolEntrypoint>, | ||
) -> Self { | ||
let mut entrypoints: Vec<_> = entrypoints.collect(); | ||
entrypoints.sort(); | ||
Self { | ||
requirements, | ||
python, | ||
entrypoints, | ||
} | ||
} | ||
|
||
/// Returns the TOML table for this tool. | ||
pub(crate) fn to_toml(&self) -> Table { | ||
let mut table = Table::new(); | ||
|
||
table.insert("requirements", { | ||
let requirements = match self.requirements.as_slice() { | ||
[] => Array::new(), | ||
[requirement] => Array::from_iter([Value::from(requirement.to_string())]), | ||
requirements => each_element_on_its_line_array( | ||
requirements | ||
.iter() | ||
.map(|requirement| Value::from(requirement.to_string())), | ||
), | ||
}; | ||
value(requirements) | ||
}); | ||
|
||
if let Some(ref python) = self.python { | ||
table.insert("python", value(python)); | ||
} | ||
|
||
table.insert("entrypoints", { | ||
let entrypoints = each_element_on_its_line_array( | ||
self.entrypoints | ||
.iter() | ||
.map(ToolEntrypoint::to_toml) | ||
.map(toml_edit::Table::into_inline_table), | ||
); | ||
value(entrypoints) | ||
}); | ||
|
||
table | ||
} | ||
} | ||
|
||
impl ToolEntrypoint { | ||
/// Create a new [`ToolEntrypoint`]. | ||
pub fn new(name: String, install_path: PathBuf) -> Self { | ||
Self { name, install_path } | ||
} | ||
|
||
/// Returns the TOML table for this entrypoint. | ||
pub(crate) fn to_toml(&self) -> Table { | ||
let mut table = Table::new(); | ||
table.insert("name", value(&self.name)); | ||
table.insert( | ||
"install-path", | ||
// Use cross-platform slashes so the toml string type does not change | ||
value(self.install_path.to_slash_lossy().to_string()), | ||
); | ||
table | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.