mirror of
https://github.com/astral-sh/uv.git
synced 2025-11-18 11:20:40 +00:00
Only use relative paths in lockfile (#6490)
For users who were using absolute paths in the `pyproject.toml` previously, this is a behavior change: We now convert all absolute paths in `path` entries to relative paths. Since i assume that no-one relies on absolute path in their lockfiles - they are intended to be portable - I'm tagging this as a bugfix. Closes https://github.com/astral-sh/uv/pull/6438 Fixes https://github.com/astral-sh/uv/issues/6371
This commit is contained in:
parent
611a9003c9
commit
f7835243c5
30 changed files with 329 additions and 383 deletions
|
|
@ -332,13 +332,13 @@ impl Source {
|
|||
|
||||
let source = match source {
|
||||
RequirementSource::Registry { .. } => return Ok(None),
|
||||
RequirementSource::Path { lock_path, .. } => Source::Path {
|
||||
RequirementSource::Path { install_path, .. } => Source::Path {
|
||||
editable,
|
||||
path: lock_path.to_string_lossy().into_owned(),
|
||||
path: install_path.to_string_lossy().into_owned(),
|
||||
},
|
||||
RequirementSource::Directory { lock_path, .. } => Source::Path {
|
||||
RequirementSource::Directory { install_path, .. } => Source::Path {
|
||||
editable,
|
||||
path: lock_path.to_string_lossy().into_owned(),
|
||||
path: install_path.to_string_lossy().into_owned(),
|
||||
},
|
||||
RequirementSource::Url {
|
||||
subdirectory, url, ..
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use tracing::{debug, trace, warn};
|
|||
|
||||
use pep508_rs::{MarkerTree, RequirementOrigin, VerbatimUrl};
|
||||
use pypi_types::{Requirement, RequirementSource};
|
||||
use uv_fs::{absolutize_path, normalize_path, relative_to, Simplified};
|
||||
use uv_fs::{absolutize_path, Simplified};
|
||||
use uv_normalize::{GroupName, PackageName, DEV_DEPENDENCIES};
|
||||
use uv_warnings::warn_user;
|
||||
|
||||
|
|
@ -62,11 +62,6 @@ pub struct Workspace {
|
|||
/// The workspace root is the directory containing the top level `pyproject.toml` with
|
||||
/// the `uv.tool.workspace`, or the `pyproject.toml` in an implicit single workspace project.
|
||||
install_path: PathBuf,
|
||||
/// The same path as `install_path`, but relative to the main workspace.
|
||||
///
|
||||
/// We use this value to compute relative paths for workspace-to-workspace dependencies. It's an
|
||||
/// empty path for the main workspace.
|
||||
lock_path: PathBuf,
|
||||
/// The members of the workspace.
|
||||
packages: BTreeMap<PackageName, WorkspaceMember>,
|
||||
/// The sources table from the workspace `pyproject.toml`.
|
||||
|
|
@ -176,8 +171,6 @@ impl Workspace {
|
|||
|
||||
Self::collect_members(
|
||||
workspace_root.clone(),
|
||||
// This method supports only absolute paths.
|
||||
workspace_root,
|
||||
workspace_definition,
|
||||
workspace_pyproject_toml,
|
||||
current_project,
|
||||
|
|
@ -286,11 +279,6 @@ impl Workspace {
|
|||
marker: MarkerTree::TRUE,
|
||||
source: RequirementSource::Directory {
|
||||
install_path: member.root.clone(),
|
||||
lock_path: member
|
||||
.root
|
||||
.strip_prefix(&self.install_path)
|
||||
.expect("Project must be below workspace root")
|
||||
.to_path_buf(),
|
||||
editable: true,
|
||||
url,
|
||||
},
|
||||
|
|
@ -421,12 +409,6 @@ impl Workspace {
|
|||
&self.install_path
|
||||
}
|
||||
|
||||
/// The same path as `install_path()`, but relative to the main workspace. We use this value
|
||||
/// to compute relative paths for workspace-to-workspace dependencies.
|
||||
pub fn lock_path(&self) -> &PathBuf {
|
||||
&self.lock_path
|
||||
}
|
||||
|
||||
/// The path to the workspace virtual environment.
|
||||
pub fn venv(&self) -> PathBuf {
|
||||
self.install_path.join(".venv")
|
||||
|
|
@ -480,7 +462,6 @@ impl Workspace {
|
|||
/// Collect the workspace member projects from the `members` and `excludes` entries.
|
||||
async fn collect_members(
|
||||
workspace_root: PathBuf,
|
||||
lock_path: PathBuf,
|
||||
workspace_definition: ToolUvWorkspace,
|
||||
workspace_pyproject_toml: PyProjectToml,
|
||||
current_project: Option<WorkspaceMember>,
|
||||
|
|
@ -644,7 +625,6 @@ impl Workspace {
|
|||
|
||||
Ok(Workspace {
|
||||
install_path: workspace_root,
|
||||
lock_path,
|
||||
packages: workspace_members,
|
||||
sources: workspace_sources,
|
||||
pyproject_toml: workspace_pyproject_toml,
|
||||
|
|
@ -817,21 +797,13 @@ impl ProjectWorkspace {
|
|||
.clone()
|
||||
.ok_or_else(|| WorkspaceError::MissingProject(pyproject_path.clone()))?;
|
||||
|
||||
Self::from_project(
|
||||
project_root,
|
||||
Path::new(""),
|
||||
&project,
|
||||
&pyproject_toml,
|
||||
options,
|
||||
)
|
||||
.await
|
||||
Self::from_project(project_root, &project, &pyproject_toml, options).await
|
||||
}
|
||||
|
||||
/// If the current directory contains a `pyproject.toml` with a `project` table, discover the
|
||||
/// workspace and return it, otherwise it is a dynamic path dependency and we return `Ok(None)`.
|
||||
pub async fn from_maybe_project_root(
|
||||
install_path: &Path,
|
||||
lock_path: &Path,
|
||||
options: &DiscoveryOptions<'_>,
|
||||
) -> Result<Option<Self>, WorkspaceError> {
|
||||
// Read the `pyproject.toml`.
|
||||
|
|
@ -849,8 +821,7 @@ impl ProjectWorkspace {
|
|||
return Ok(None);
|
||||
};
|
||||
|
||||
match Self::from_project(install_path, lock_path, &project, &pyproject_toml, options).await
|
||||
{
|
||||
match Self::from_project(install_path, &project, &pyproject_toml, options).await {
|
||||
Ok(workspace) => Ok(Some(workspace)),
|
||||
Err(WorkspaceError::NonWorkspace(_)) => Ok(None),
|
||||
Err(err) => Err(err),
|
||||
|
|
@ -894,7 +865,6 @@ impl ProjectWorkspace {
|
|||
/// Find the workspace for a project.
|
||||
pub async fn from_project(
|
||||
install_path: &Path,
|
||||
lock_path: &Path,
|
||||
project: &Project,
|
||||
project_pyproject_toml: &PyProjectToml,
|
||||
options: &DiscoveryOptions<'_>,
|
||||
|
|
@ -954,8 +924,6 @@ impl ProjectWorkspace {
|
|||
project_name: project.name.clone(),
|
||||
workspace: Workspace {
|
||||
install_path: project_path.clone(),
|
||||
// The workspace and the project are the same, so the relative path is, too.
|
||||
lock_path: lock_path.to_path_buf(),
|
||||
packages: current_project_as_members,
|
||||
// There may be package sources, but we don't need to duplicate them into the
|
||||
// workspace sources.
|
||||
|
|
@ -970,28 +938,8 @@ impl ProjectWorkspace {
|
|||
workspace_root.simplified_display()
|
||||
);
|
||||
|
||||
// Say we have:
|
||||
// ```
|
||||
// root
|
||||
// ├── main_workspace <- The reference point
|
||||
// │ ├── pyproject.toml
|
||||
// │ └── uv.lock
|
||||
// └──current_workspace <- We want this relative to the main workspace
|
||||
// └── packages
|
||||
// └── current_package <- We have this relative to the main workspace
|
||||
// └── pyproject.toml
|
||||
// ```
|
||||
// The lock path we need: `../current_workspace`
|
||||
// workspace root: `/root/current_workspace`
|
||||
// project path: `/root/current_workspace/packages/current_project`
|
||||
// relative to workspace: `../..`
|
||||
// lock path: `../current_workspace`
|
||||
let up_to_root = relative_to(&workspace_root, &project_path)?;
|
||||
let lock_path = normalize_path(&lock_path.join(up_to_root));
|
||||
|
||||
let workspace = Workspace::collect_members(
|
||||
workspace_root,
|
||||
lock_path,
|
||||
workspace_definition,
|
||||
workspace_pyproject_toml,
|
||||
Some(current_project),
|
||||
|
|
@ -1270,14 +1218,9 @@ impl VirtualProject {
|
|||
|
||||
if let Some(project) = pyproject_toml.project.as_ref() {
|
||||
// If the `pyproject.toml` contains a `[project]` table, it's a project.
|
||||
let project = ProjectWorkspace::from_project(
|
||||
project_root,
|
||||
Path::new(""),
|
||||
project,
|
||||
&pyproject_toml,
|
||||
options,
|
||||
)
|
||||
.await?;
|
||||
let project =
|
||||
ProjectWorkspace::from_project(project_root, project, &pyproject_toml, options)
|
||||
.await?;
|
||||
Ok(Self::Project(project))
|
||||
} else if let Some(workspace) = pyproject_toml
|
||||
.tool
|
||||
|
|
@ -1294,7 +1237,6 @@ impl VirtualProject {
|
|||
|
||||
let workspace = Workspace::collect_members(
|
||||
project_path,
|
||||
PathBuf::new(),
|
||||
workspace.clone(),
|
||||
pyproject_toml,
|
||||
None,
|
||||
|
|
@ -1452,7 +1394,6 @@ mod tests {
|
|||
"project_name": "bird-feeder",
|
||||
"workspace": {
|
||||
"install_path": "[ROOT]/albatross-in-example/examples/bird-feeder",
|
||||
"lock_path": "",
|
||||
"packages": {
|
||||
"bird-feeder": {
|
||||
"root": "[ROOT]/albatross-in-example/examples/bird-feeder",
|
||||
|
|
@ -1496,7 +1437,6 @@ mod tests {
|
|||
"project_name": "bird-feeder",
|
||||
"workspace": {
|
||||
"install_path": "[ROOT]/albatross-project-in-excluded/excluded/bird-feeder",
|
||||
"lock_path": "",
|
||||
"packages": {
|
||||
"bird-feeder": {
|
||||
"root": "[ROOT]/albatross-project-in-excluded/excluded/bird-feeder",
|
||||
|
|
@ -1539,7 +1479,6 @@ mod tests {
|
|||
"project_name": "albatross",
|
||||
"workspace": {
|
||||
"install_path": "[ROOT]/albatross-root-workspace",
|
||||
"lock_path": "",
|
||||
"packages": {
|
||||
"albatross": {
|
||||
"root": "[ROOT]/albatross-root-workspace",
|
||||
|
|
@ -1624,7 +1563,6 @@ mod tests {
|
|||
"project_name": "albatross",
|
||||
"workspace": {
|
||||
"install_path": "[ROOT]/albatross-virtual-workspace",
|
||||
"lock_path": "../..",
|
||||
"packages": {
|
||||
"albatross": {
|
||||
"root": "[ROOT]/albatross-virtual-workspace/packages/albatross",
|
||||
|
|
@ -1696,7 +1634,6 @@ mod tests {
|
|||
"project_name": "albatross",
|
||||
"workspace": {
|
||||
"install_path": "[ROOT]/albatross-just-project",
|
||||
"lock_path": "",
|
||||
"packages": {
|
||||
"albatross": {
|
||||
"root": "[ROOT]/albatross-just-project",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue