Support locking relative paths (#4205)

By splitting `path` into a lockable, relative (or absolute) and an
absolute installable path and by splitting between urls and paths by
dist type, we can store relative paths in the lockfile.
This commit is contained in:
konsti 2024-06-11 13:58:03 +02:00 committed by GitHub
parent 33cf47182f
commit 44833801b3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 533 additions and 364 deletions

View file

@ -158,7 +158,7 @@ impl<'a> From<&'a PathSourceDist> for PathSourceUrl<'a> {
fn from(dist: &'a PathSourceDist) -> Self {
Self {
url: &dist.url,
path: Cow::Borrowed(&dist.path),
path: Cow::Borrowed(&dist.install_path),
}
}
}
@ -180,7 +180,7 @@ impl<'a> From<&'a DirectorySourceDist> for DirectorySourceUrl<'a> {
fn from(dist: &'a DirectorySourceDist) -> Self {
Self {
url: &dist.url,
path: Cow::Borrowed(&dist.path),
path: Cow::Borrowed(&dist.install_path),
editable: dist.editable,
}
}

View file

@ -116,12 +116,14 @@ impl CachedDist {
Self::Url(dist) => {
if dist.editable {
assert_eq!(dist.url.scheme(), "file", "{}", dist.url);
let path = dist
.url
.to_file_path()
.map_err(|()| anyhow!("Invalid path in file URL"))?;
Ok(Some(ParsedUrl::Path(ParsedPathUrl {
url: dist.url.raw().clone(),
path: dist
.url
.to_file_path()
.map_err(|()| anyhow!("Invalid path in file URL"))?,
install_path: path.clone(),
lock_path: path,
editable: dist.editable,
})))
} else {

View file

@ -259,8 +259,12 @@ pub struct GitSourceDist {
#[derive(Debug, Clone)]
pub struct PathSourceDist {
pub name: PackageName,
/// The path to the archive.
pub path: PathBuf,
/// The resolved, absolute path to the distribution which we use for installing.
pub install_path: PathBuf,
/// The absolute path or path relative to the workspace root pointing to the distribution
/// which we use for locking. Unlike `given` on the verbatim URL all environment variables
/// are resolved, and unlike the install path, we did not yet join it on the base directory.
pub lock_path: PathBuf,
/// The URL as it was provided by the user.
pub url: VerbatimUrl,
}
@ -269,8 +273,12 @@ pub struct PathSourceDist {
#[derive(Debug, Clone)]
pub struct DirectorySourceDist {
pub name: PackageName,
/// The path to the directory.
pub path: PathBuf,
/// The resolved, absolute path to the distribution which we use for installing.
pub install_path: PathBuf,
/// The absolute path or path relative to the workspace root pointing to the distribution
/// which we use for locking. Unlike `given` on the verbatim URL all environment variables
/// are resolved, and unlike the install path, we did not yet join it on the base directory.
pub lock_path: PathBuf,
/// Whether the package should be installed in editable mode.
pub editable: bool,
/// The URL as it was provided by the user.
@ -319,11 +327,12 @@ impl Dist {
pub fn from_file_url(
name: PackageName,
url: VerbatimUrl,
path: &Path,
install_path: &Path,
lock_path: &Path,
editable: bool,
) -> Result<Dist, Error> {
// Store the canonicalized path, which also serves to validate that it exists.
let path = match path.canonicalize() {
let canonicalized_path = match install_path.canonicalize() {
Ok(path) => path,
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
return Err(Error::NotFound(url.to_url()));
@ -332,14 +341,15 @@ impl Dist {
};
// Determine whether the path represents an archive or a directory.
if path.is_dir() {
if canonicalized_path.is_dir() {
Ok(Self::Source(SourceDist::Directory(DirectorySourceDist {
name,
path,
install_path: canonicalized_path.clone(),
lock_path: lock_path.to_path_buf(),
editable,
url,
})))
} else if path
} else if canonicalized_path
.extension()
.is_some_and(|ext| ext.eq_ignore_ascii_case("whl"))
{
@ -359,7 +369,7 @@ impl Dist {
Ok(Self::Built(BuiltDist::Path(PathBuiltDist {
filename,
path,
path: canonicalized_path,
url,
})))
} else {
@ -369,7 +379,8 @@ impl Dist {
Ok(Self::Source(SourceDist::Path(PathSourceDist {
name,
path,
install_path: canonicalized_path.clone(),
lock_path: canonicalized_path,
url,
})))
}
@ -396,9 +407,13 @@ impl Dist {
ParsedUrl::Archive(archive) => {
Self::from_http_url(name, url.verbatim, archive.url, archive.subdirectory)
}
ParsedUrl::Path(file) => {
Self::from_file_url(name, url.verbatim, &file.path, file.editable)
}
ParsedUrl::Path(file) => Self::from_file_url(
name,
url.verbatim,
&file.install_path,
&file.lock_path,
file.editable,
),
ParsedUrl::Git(git) => {
Self::from_git_url(name, url.verbatim, git.url, git.subdirectory)
}
@ -517,8 +532,8 @@ impl SourceDist {
/// Returns the path to the source distribution, if it's a local distribution.
pub fn as_path(&self) -> Option<&Path> {
match self {
Self::Path(dist) => Some(&dist.path),
Self::Directory(dist) => Some(&dist.path),
Self::Path(dist) => Some(&dist.install_path),
Self::Directory(dist) => Some(&dist.install_path),
_ => None,
}
}

View file

@ -141,7 +141,8 @@ impl From<&ResolvedDist> for Requirement {
}
}
Dist::Built(BuiltDist::Path(wheel)) => RequirementSource::Path {
path: wheel.path.clone(),
install_path: wheel.path.clone(),
lock_path: wheel.path.clone(),
url: wheel.url.clone(),
editable: false,
},
@ -168,12 +169,14 @@ impl From<&ResolvedDist> for Requirement {
subdirectory: sdist.subdirectory.clone(),
},
Dist::Source(SourceDist::Path(sdist)) => RequirementSource::Path {
path: sdist.path.clone(),
install_path: sdist.install_path.clone(),
lock_path: sdist.lock_path.clone(),
url: sdist.url.clone(),
editable: false,
},
Dist::Source(SourceDist::Directory(sdist)) => RequirementSource::Path {
path: sdist.path.clone(),
install_path: sdist.install_path.clone(),
lock_path: sdist.lock_path.clone(),
url: sdist.url.clone(),
editable: sdist.editable,
},