Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions crates/uv-cache/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -764,16 +764,18 @@ pub enum CacheBucket {
impl CacheBucket {
fn to_str(self) -> &'static str {
match self {
Self::SourceDistributions => "sdists-v5",
Self::FlatIndex => "flat-index-v1",
// Note that when bumping this, you'll also need to bump it
// in crates/uv/tests/cache_prune.rs.
Self::SourceDistributions => "sdists-v6",
Self::FlatIndex => "flat-index-v2",
Self::Git => "git-v0",
Self::Interpreter => "interpreter-v2",
Self::Interpreter => "interpreter-v3",
// Note that when bumping this, you'll also need to bump it
// in crates/uv/tests/cache_clean.rs.
Self::Simple => "simple-v13",
Self::Simple => "simple-v14",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice okay, this is what I was looking for. 👍

// Note that when bumping this, you'll also need to bump it
// in crates/uv/tests/cache_prune.rs.
Self::Wheels => "wheels-v2",
Self::Wheels => "wheels-v3",
Self::Archive => "archive-v0",
Self::Builds => "builds-v0",
Self::Environments => "environments-v1",
Expand Down
136 changes: 89 additions & 47 deletions crates/uv-pep440/src/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ impl Version {
#[inline]
pub fn local(&self) -> LocalVersionSlice {
match *self.inner {
VersionInner::Small { ref small } => small.local(),
VersionInner::Small { ref small } => small.local_slice(),
VersionInner::Full { ref full } => full.local.as_slice(),
}
}
Expand Down Expand Up @@ -546,6 +546,11 @@ impl Version {
match value {
LocalVersion::Segments(segments) => self.with_local_segments(segments),
LocalVersion::Max => {
if let VersionInner::Small { ref mut small } = Arc::make_mut(&mut self.inner) {
if small.set_local(LocalVersion::Max) {
return self;
}
}
self.make_full().local = value;
self
}
Expand All @@ -559,12 +564,12 @@ impl Version {
#[inline]
#[must_use]
pub fn without_local(mut self) -> Self {
// A "small" version is already guaranteed not to have a local
// component, so we only need to do anything if we have a "full"
// version.
if let VersionInner::Full { ref mut full } = Arc::make_mut(&mut self.inner) {
full.local.clear();
if let VersionInner::Small { ref mut small } = Arc::make_mut(&mut self.inner) {
if small.set_local(LocalVersion::empty()) {
return self;
}
}
self.make_full().local = LocalVersion::empty();
self
}

Expand Down Expand Up @@ -628,7 +633,7 @@ impl Version {
pre: small.pre(),
post: small.post(),
dev: small.dev(),
local: LocalVersion::Segments(vec![]),
local: small.local(),
};
*self = Self {
inner: Arc::new(VersionInner::Full { full }),
Expand Down Expand Up @@ -846,16 +851,16 @@ impl FromStr for Version {
/// * Bytes 5, 4 and 3 correspond to the second, third and fourth release
/// segments, respectively.
/// * Bytes 2, 1 and 0 represent *one* of the following:
/// `min, .devN, aN, bN, rcN, <no suffix>, .postN, max`.
/// `min, .devN, aN, bN, rcN, <no suffix>, local, .postN, max`.
/// Its representation is thus:
/// * The most significant 3 bits of Byte 2 corresponds to a value in
/// the range 0-7 inclusive, corresponding to min, dev, pre-a, pre-b,
/// * The most significant 4 bits of Byte 2 corresponds to a value in
/// the range 0-8 inclusive, corresponding to min, dev, pre-a, pre-b,
/// pre-rc, no-suffix, post or max releases, respectively. `min` is a
/// special version that does not exist in PEP 440, but is used here to
/// represent the smallest possible version, preceding any `dev`, `pre`,
/// `post` or releases. `max` is an analogous concept for the largest
/// possible version, following any `post` or local releases.
/// * The low 5 bits combined with the bits in bytes 1 and 0 correspond
/// * The low 4 bits combined with the bits in bytes 1 and 0 correspond
/// to the release number of the suffix, if one exists. If there is no
/// suffix, then these bits are always 0.
///
Expand Down Expand Up @@ -933,8 +938,9 @@ impl VersionSmall {
const SUFFIX_PRE_BETA: u64 = 3;
const SUFFIX_PRE_RC: u64 = 4;
const SUFFIX_NONE: u64 = 5;
const SUFFIX_POST: u64 = 6;
const SUFFIX_MAX: u64 = 7;
const SUFFIX_LOCAL: u64 = 6;
const SUFFIX_POST: u64 = 7;
const SUFFIX_MAX: u64 = 8;

// The mask to get only the release segment bits.
//
Expand All @@ -943,16 +949,16 @@ impl VersionSmall {
// `Parser::parse_fast`.
const SUFFIX_RELEASE_MASK: u64 = 0xFFFF_FFFF_FF00_0000;
// The mask to get the version suffix.
const SUFFIX_VERSION_MASK: u64 = 0x001F_FFFF;
const SUFFIX_VERSION_MASK: u64 = 0x000F_FFFF;
// The number of bits used by the version suffix. Shifting the `repr`
// right by this number of bits should put the suffix kind in the least
// significant bits.
const SUFFIX_VERSION_BIT_LEN: u64 = 21;
const SUFFIX_VERSION_BIT_LEN: u64 = 20;
// The mask to get only the suffix kind, after shifting right by the
// version bits. If you need to add a bit here, then you'll probably need
// to take a bit from the suffix version. (Which requires a change to both
// the mask and the bit length above.)
const SUFFIX_KIND_MASK: u64 = 0b111;
const SUFFIX_KIND_MASK: u64 = 0b1111;

#[inline]
fn new() -> Self {
Expand Down Expand Up @@ -1026,11 +1032,8 @@ impl VersionSmall {

#[inline]
fn set_post(&mut self, value: Option<u64>) -> bool {
if self.min().is_some()
|| self.pre().is_some()
|| self.dev().is_some()
|| self.max().is_some()
{
let suffix_kind = self.suffix_kind();
if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_POST) {
return value.is_none();
}
match value {
Expand Down Expand Up @@ -1073,10 +1076,11 @@ impl VersionSmall {

#[inline]
fn set_pre(&mut self, value: Option<Prerelease>) -> bool {
if self.min().is_some()
|| self.dev().is_some()
|| self.post().is_some()
|| self.max().is_some()
let suffix_kind = self.suffix_kind();
if !(suffix_kind == Self::SUFFIX_NONE
|| suffix_kind == Self::SUFFIX_PRE_ALPHA
|| suffix_kind == Self::SUFFIX_PRE_BETA
|| suffix_kind == Self::SUFFIX_PRE_RC)
{
return value.is_none();
}
Expand Down Expand Up @@ -1116,11 +1120,8 @@ impl VersionSmall {

#[inline]
fn set_dev(&mut self, value: Option<u64>) -> bool {
if self.min().is_some()
|| self.pre().is_some()
|| self.post().is_some()
|| self.max().is_some()
{
let suffix_kind = self.suffix_kind();
if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_DEV) {
return value.is_none();
}
match value {
Expand Down Expand Up @@ -1149,11 +1150,8 @@ impl VersionSmall {

#[inline]
fn set_min(&mut self, value: Option<u64>) -> bool {
if self.dev().is_some()
|| self.pre().is_some()
|| self.post().is_some()
|| self.max().is_some()
{
let suffix_kind = self.suffix_kind();
if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_MIN) {
return value.is_none();
}
match value {
Expand Down Expand Up @@ -1182,11 +1180,8 @@ impl VersionSmall {

#[inline]
fn set_max(&mut self, value: Option<u64>) -> bool {
if self.dev().is_some()
|| self.pre().is_some()
|| self.post().is_some()
|| self.min().is_some()
{
let suffix_kind = self.suffix_kind();
if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_MAX) {
return value.is_none();
}
match value {
Expand All @@ -1205,11 +1200,40 @@ impl VersionSmall {
}

#[inline]
#[allow(clippy::unused_self)]
fn local(&self) -> LocalVersionSlice {
// A "small" version is never used if the version has a non-zero number
// of local segments.
LocalVersionSlice::Segments(&[])
fn local(&self) -> LocalVersion {
if self.suffix_kind() == Self::SUFFIX_LOCAL {
LocalVersion::Max
} else {
LocalVersion::empty()
}
}

#[inline]
fn local_slice(&self) -> LocalVersionSlice {
if self.suffix_kind() == Self::SUFFIX_LOCAL {
LocalVersionSlice::Max
} else {
LocalVersionSlice::empty()
}
}

#[inline]
fn set_local(&mut self, value: LocalVersion) -> bool {
let suffix_kind = self.suffix_kind();
if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_LOCAL) {
return value.is_empty();
}
match value {
LocalVersion::Max => {
self.set_suffix_kind(Self::SUFFIX_LOCAL);
true
}
LocalVersion::Segments(segments) if segments.is_empty() => {
self.set_suffix_kind(Self::SUFFIX_NONE);
true
}
LocalVersion::Segments(_) => false,
}
}

#[inline]
Expand All @@ -1224,7 +1248,7 @@ impl VersionSmall {
debug_assert!(kind <= Self::SUFFIX_MAX);
self.repr &= !(Self::SUFFIX_KIND_MASK << Self::SUFFIX_VERSION_BIT_LEN);
self.repr |= kind << Self::SUFFIX_VERSION_BIT_LEN;
if kind == Self::SUFFIX_NONE {
if kind == Self::SUFFIX_NONE || kind == Self::SUFFIX_LOCAL {
self.set_suffix_version(0);
}
}
Expand Down Expand Up @@ -1450,6 +1474,19 @@ pub enum LocalVersionSlice<'a> {
}

impl LocalVersion {
/// Return an empty local version.
pub fn empty() -> Self {
Self::Segments(Vec::new())
}

/// Returns `true` if the local version is empty.
pub fn is_empty(&self) -> bool {
match self {
Self::Segments(segments) => segments.is_empty(),
Self::Max => false,
}
}

/// Convert the local version segments into a slice.
pub fn as_slice(&self) -> LocalVersionSlice<'_> {
match self {
Expand Down Expand Up @@ -1506,7 +1543,12 @@ impl Ord for LocalVersionSlice<'_> {
}

impl LocalVersionSlice<'_> {
/// Whether the local version is absent
/// Return an empty local version.
pub const fn empty() -> Self {
Self::Segments(&[])
}

/// Returns `true` if the local version is empty.
pub fn is_empty(&self) -> bool {
matches!(self, Self::Segments(&[]))
}
Expand Down
4 changes: 2 additions & 2 deletions crates/uv/tests/it/cache_clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ fn clean_package_pypi() -> Result<()> {
// Assert that the `.rkyv` file is created for `iniconfig`.
let rkyv = context
.cache_dir
.child("simple-v13")
.child("simple-v14")
.child("pypi")
.child("iniconfig.rkyv");
assert!(
Expand Down Expand Up @@ -123,7 +123,7 @@ fn clean_package_index() -> Result<()> {
// Assert that the `.rkyv` file is created for `iniconfig`.
let rkyv = context
.cache_dir
.child("simple-v13")
.child("simple-v14")
.child("index")
.child("e8208120cae3ba69")
.child("iniconfig.rkyv");
Expand Down
4 changes: 2 additions & 2 deletions crates/uv/tests/it/cache_prune.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ fn prune_stale_symlink() -> Result<()> {
.success();

// Remove the wheels directory, causing the symlink to become stale.
let wheels = context.cache_dir.child("wheels-v2");
let wheels = context.cache_dir.child("wheels-v3");
fs_err::remove_dir_all(wheels)?;

let filters: Vec<_> = context
Expand Down Expand Up @@ -328,7 +328,7 @@ fn prune_stale_revision() -> Result<()> {
----- stderr -----
DEBUG uv [VERSION] ([COMMIT] DATE)
Pruning cache at: [CACHE_DIR]/
DEBUG Removing dangling source revision: [CACHE_DIR]/sdists-v5/[ENTRY]
DEBUG Removing dangling source revision: [CACHE_DIR]/sdists-v6/[ENTRY]
DEBUG Removing dangling cache archive: [CACHE_DIR]/archive-v0/[ENTRY]
Removed 8 files ([SIZE])
"###);
Expand Down
Loading