Skip to content

Commit 0823621

Browse files
committed
Ignore origin when comparing installed tools
1 parent 1d76c5a commit 0823621

3 files changed

Lines changed: 197 additions & 2 deletions

File tree

crates/uv-distribution-types/src/index.rs

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl IndexCacheControl {
4848
}
4949
}
5050

51-
#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
51+
#[derive(Debug, Clone, Serialize, Deserialize)]
5252
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5353
#[serde(rename_all = "kebab-case")]
5454
pub struct Index {
@@ -156,6 +156,92 @@ pub struct Index {
156156
pub cache_control: Option<IndexCacheControl>,
157157
}
158158

159+
impl PartialEq for Index {
160+
fn eq(&self, other: &Self) -> bool {
161+
let Self {
162+
name,
163+
url,
164+
explicit,
165+
default,
166+
origin: _,
167+
format,
168+
publish_url,
169+
authenticate,
170+
ignore_error_codes,
171+
cache_control,
172+
} = self;
173+
*url == other.url
174+
&& *name == other.name
175+
&& *explicit == other.explicit
176+
&& *default == other.default
177+
&& *format == other.format
178+
&& *publish_url == other.publish_url
179+
&& *authenticate == other.authenticate
180+
&& *ignore_error_codes == other.ignore_error_codes
181+
&& *cache_control == other.cache_control
182+
}
183+
}
184+
185+
impl Eq for Index {}
186+
187+
impl PartialOrd for Index {
188+
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
189+
Some(self.cmp(other))
190+
}
191+
}
192+
193+
impl Ord for Index {
194+
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
195+
let Self {
196+
name,
197+
url,
198+
explicit,
199+
default,
200+
origin: _,
201+
format,
202+
publish_url,
203+
authenticate,
204+
ignore_error_codes,
205+
cache_control,
206+
} = self;
207+
url.cmp(&other.url)
208+
.then_with(|| name.cmp(&other.name))
209+
.then_with(|| explicit.cmp(&other.explicit))
210+
.then_with(|| default.cmp(&other.default))
211+
.then_with(|| format.cmp(&other.format))
212+
.then_with(|| publish_url.cmp(&other.publish_url))
213+
.then_with(|| authenticate.cmp(&other.authenticate))
214+
.then_with(|| ignore_error_codes.cmp(&other.ignore_error_codes))
215+
.then_with(|| cache_control.cmp(&other.cache_control))
216+
}
217+
}
218+
219+
impl std::hash::Hash for Index {
220+
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
221+
let Self {
222+
name,
223+
url,
224+
explicit,
225+
default,
226+
origin: _,
227+
format,
228+
publish_url,
229+
authenticate,
230+
ignore_error_codes,
231+
cache_control,
232+
} = self;
233+
url.hash(state);
234+
name.hash(state);
235+
explicit.hash(state);
236+
default.hash(state);
237+
format.hash(state);
238+
publish_url.hash(state);
239+
authenticate.hash(state);
240+
ignore_error_codes.hash(state);
241+
cache_control.hash(state);
242+
}
243+
}
244+
159245
#[derive(
160246
Default,
161247
Debug,

crates/uv/tests/it/tool_install.rs

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3906,7 +3906,6 @@ fn tool_install_default_credentials() -> Result<()> {
39063906
sys.argv[0] = sys.argv[0][:-4]
39073907
sys.exit(main())
39083908
"###);
3909-
39103909
});
39113910

39123911
insta::with_settings!({
@@ -4094,6 +4093,116 @@ fn tool_install_with_executables_from_no_entrypoints() {
40944093
"###);
40954094
}
40964095

4096+
#[test]
4097+
fn tool_install_find_links() {
4098+
let context = TestContext::new("3.13").with_filtered_exe_suffix();
4099+
let tool_dir = context.temp_dir.child("tools");
4100+
let bin_dir = context.temp_dir.child("bin");
4101+
4102+
// Run with `--find-links`.
4103+
uv_snapshot!(context.filters(), context.tool_run()
4104+
.arg("--find-links")
4105+
.arg(context.workspace_root.join("scripts/links/"))
4106+
.arg("basic-app")
4107+
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
4108+
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str()), @r"
4109+
success: true
4110+
exit_code: 0
4111+
----- stdout -----
4112+
Hello from basic-app!
4113+
4114+
----- stderr -----
4115+
Resolved 1 package in [TIME]
4116+
Prepared 1 package in [TIME]
4117+
Installed 1 package in [TIME]
4118+
+ basic-app==0.1.0
4119+
");
4120+
4121+
// Install with `--find-links`.
4122+
uv_snapshot!(context.filters(), context.tool_install()
4123+
.arg("--find-links")
4124+
.arg(context.workspace_root.join("scripts/links/"))
4125+
.arg("basic-app")
4126+
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
4127+
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str())
4128+
.env(EnvVars::PATH, bin_dir.as_os_str()), @r"
4129+
success: true
4130+
exit_code: 0
4131+
----- stdout -----
4132+
4133+
----- stderr -----
4134+
Resolved 1 package in [TIME]
4135+
Installed 1 package in [TIME]
4136+
+ basic-app==0.1.0
4137+
Installed 1 executable: basic-app
4138+
");
4139+
4140+
tool_dir
4141+
.child("basic-app")
4142+
.assert(predicate::path::is_dir());
4143+
tool_dir
4144+
.child("basic-app")
4145+
.child("uv-receipt.toml")
4146+
.assert(predicate::path::exists());
4147+
4148+
let executable = bin_dir.child(format!("basic-app{}", std::env::consts::EXE_SUFFIX));
4149+
assert!(executable.exists());
4150+
4151+
// On Windows, we can't snapshot an executable file.
4152+
#[cfg(not(windows))]
4153+
insta::with_settings!({
4154+
filters => context.filters(),
4155+
}, {
4156+
// Should run black in the virtual environment
4157+
assert_snapshot!(fs_err::read_to_string(executable).unwrap(), @r#"
4158+
#![TEMP_DIR]/tools/basic-app/bin/python
4159+
# -*- coding: utf-8 -*-
4160+
import sys
4161+
from basic_app import main
4162+
if __name__ == "__main__":
4163+
if sys.argv[0].endswith("-script.pyw"):
4164+
sys.argv[0] = sys.argv[0][:-11]
4165+
elif sys.argv[0].endswith(".exe"):
4166+
sys.argv[0] = sys.argv[0][:-4]
4167+
sys.exit(main())
4168+
"#);
4169+
});
4170+
4171+
// Run the installed version with `--find-links` on the CLI again.
4172+
uv_snapshot!(context.filters(), context.tool_run()
4173+
.arg("--offline")
4174+
.arg("--find-links")
4175+
.arg(context.workspace_root.join("scripts/links/"))
4176+
.arg("basic-app")
4177+
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
4178+
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str()), @r"
4179+
success: true
4180+
exit_code: 0
4181+
----- stdout -----
4182+
Hello from basic-app!
4183+
4184+
----- stderr -----
4185+
");
4186+
4187+
// Run the installed version without `--find-links`.
4188+
uv_snapshot!(context.filters(), context.tool_run()
4189+
.arg("--offline")
4190+
.arg("basic-app")
4191+
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
4192+
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str()), @r"
4193+
success: false
4194+
exit_code: 1
4195+
----- stdout -----
4196+
4197+
----- stderr -----
4198+
× No solution found when resolving tool dependencies:
4199+
╰─▶ Because only basic-app==0.1 is available and basic-app==0.1 needs to be downloaded from a registry, we can conclude that all versions of basic-app cannot be used.
4200+
And because you require basic-app, we can conclude that your requirements are unsatisfiable.
4201+
4202+
hint: Packages were unavailable because the network was disabled. When the network is disabled, registry packages may only be read from the cache.
4203+
");
4204+
}
4205+
40974206
#[test]
40984207
fn tool_install_python_platform() {
40994208
let context = TestContext::new("3.12")
1.53 KB
Binary file not shown.

0 commit comments

Comments
 (0)