Skip to content

Commit

Permalink
Foo
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Aug 13, 2024
1 parent 8dbf43c commit 6746f61
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 29 deletions.
7 changes: 7 additions & 0 deletions crates/distribution-types/src/file.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::borrow::Cow;
use std::fmt::{self, Display, Formatter};
use std::path::PathBuf;
use std::str::FromStr;
Expand Down Expand Up @@ -197,6 +198,12 @@ impl From<&Url> for UrlString {
}
}

impl From<Cow<'_, Url>> for UrlString {
fn from(value: Cow<'_, Url>) -> Self {
UrlString(value.to_string())
}
}

impl From<VerbatimUrl> for UrlString {
fn from(value: VerbatimUrl) -> Self {
UrlString(value.raw().to_string())
Expand Down
9 changes: 9 additions & 0 deletions crates/distribution-types/src/index_url.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,15 @@ impl IndexLocations {
no_index: self.no_index || no_index,
}
}

/// Returns `true` if no index configuration is set, i.e., the [`IndexLocations`] matches the
/// default configuration.
pub fn is_none(&self) -> bool {
self.index.is_none()
&& self.extra_index.is_empty()
&& self.flat_index.is_empty()
&& !self.no_index
}
}

impl<'a> IndexLocations {
Expand Down
9 changes: 9 additions & 0 deletions crates/uv-resolver/src/lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1210,10 +1210,19 @@ impl Package {
&self.id.version
}

/// Return the fork markers for this package, if any.
pub fn fork_markers(&self) -> Option<&BTreeSet<MarkerTree>> {
self.fork_markers.as_ref()
}

/// Return the index URL for this package, if it is a registry source.
pub fn index(&self) -> Option<&UrlString> {
match &self.id.source {
Source::Registry(url) => Some(url),
_ => None,
}
}

/// Returns a [`VersionId`] for this package that can be used for resolution.
fn version_id(&self, workspace_root: &Path) -> Result<VersionId, LockError> {
match &self.id.source {
Expand Down
52 changes: 50 additions & 2 deletions crates/uv/src/commands/project/lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ use owo_colors::OwoColorize;
use rustc_hash::{FxBuildHasher, FxHashMap};
use tracing::debug;

use distribution_types::{Diagnostic, UnresolvedRequirementSpecification};
use distribution_types::{
Diagnostic, FlatIndexLocation, IndexUrl, UnresolvedRequirementSpecification, UrlString,
};
use pep440_rs::Version;
use uv_auth::store_credentials_from_url;
use uv_cache::Cache;
Expand Down Expand Up @@ -427,7 +429,53 @@ async fn do_lock(
existing_lock.and_then(|lock| lock.fork_markers().clone())
});

let resolution = match existing_lock.filter(|_| upgrade.is_none()) {
// If any upgrades are specified, don't use the existing lockfile.
let existing_lock = existing_lock.filter(|_| upgrade.is_none());

// If the user provided at least one index URL (from the command line, or from a configuration
// file), don't use the existing lockfile if it references any registries that are no longer
// included in the current configuration.
let existing_lock = existing_lock.filter(|lock| {
// If _no_ indexes were provided, we assume that the user wants to reuse the existing
// distributions, even though a failure to reuse the lockfile will result in re-resolving
// against PyPI by default.
if settings.index_locations.is_none() {
return true;
}

// Collect the set of available indexes (both `--index-url` and `--find-links` entries).
let indexes = settings
.index_locations
.indexes()
.map(IndexUrl::redacted)
.chain(
settings
.index_locations
.flat_index()
.map(FlatIndexLocation::redacted),
)
.map(UrlString::from)
.collect::<BTreeSet<_>>();

// Find any packages in the lockfile that reference a registry that is no longer included in
// the current configuration.
for package in lock.packages() {
let Some(index) = package.index() else {
continue;
};
if !indexes.contains(index) {
let _ = writeln!(
printer.stderr(),
"Ignoring existing lockfile due to removal of referenced registry: {index}"
);
return false;
}
}

true
});

let resolution = match existing_lock {
None => None,

// Try to resolve using metadata in the lockfile.
Expand Down
109 changes: 109 additions & 0 deletions crates/uv/tests/lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7613,3 +7613,112 @@ fn lock_mismatched_versions() -> Result<()> {

Ok(())
}

/// Change indexes between locking operations.
#[test]
fn lock_change_index() -> Result<()> {
let context = TestContext::new("3.12");

let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["iniconfig"]
"#,
)?;

uv_snapshot!(context.filters(), context.lock().arg("--index-url").arg("https://public:heron@pypi-proxy.fly.dev/basic-auth/simple"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `uv lock` is experimental and may change without warning
Resolved 2 packages in [TIME]
"###);

let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();

insta::with_settings!({
filters => context.filters(),
}, {
assert_snapshot!(
lock, @r###"
version = 1
requires-python = ">=3.12"
[options]
exclude-newer = "2024-03-25 00:00:00 UTC"
[[package]]
name = "iniconfig"
version = "2.0.0"
source = { registry = "https://pypi-proxy.fly.dev/basic-auth/simple" }
sdist = { url = "https://pypi-proxy.fly.dev/basic-auth/files/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 }
wheels = [
{ url = "https://pypi-proxy.fly.dev/basic-auth/files/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 },
]
[[package]]
name = "project"
version = "0.1.0"
source = { editable = "." }
dependencies = [
{ name = "iniconfig" },
]
"###
);
});

// Re-run against PyPI.
uv_snapshot!(context.filters(), context.lock().arg("--index-url").arg("https://pypi.org/simple"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `uv lock` is experimental and may change without warning
Ignoring existing lockfile due to removal of referenced registry: https://pypi-proxy.fly.dev/basic-auth/simple
Resolved 2 packages in [TIME]
"###);

let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();

insta::with_settings!({
filters => context.filters(),
}, {
assert_snapshot!(
lock, @r###"
version = 1
requires-python = ">=3.12"
[options]
exclude-newer = "2024-03-25 00:00:00 UTC"
[[package]]
name = "iniconfig"
version = "2.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 },
]
[[package]]
name = "project"
version = "0.1.0"
source = { editable = "." }
dependencies = [
{ name = "iniconfig" },
]
"###
);
});

// Re-run with `--locked`.
uv_snapshot!(context.filters(), context.lock().arg("--locked"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `uv lock` is experimental and may change without warning
Resolved 2 packages in [TIME]
"###);

Ok(())
}
Loading

0 comments on commit 6746f61

Please sign in to comment.