Add a --project argument to run a command from a project (#7603)

## Summary

`uv run --project ./path/to/project` now uses the provided directory as
the starting point for any file discovery. However, relative paths are
still resolved relative to the current working directory.

Closes https://github.com/astral-sh/uv/issues/5613.
This commit is contained in:
Charlie Marsh 2024-09-21 16:19:49 -04:00 committed by GitHub
parent d9a5f5ca1c
commit 35d6274c31
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 591 additions and 88 deletions

View file

@ -63,8 +63,8 @@ impl FilesystemOptions {
///
/// The search starts at the given path and goes up the directory tree until a `uv.toml` file or
/// `pyproject.toml` file is found.
pub fn find(path: impl AsRef<Path>) -> Result<Option<Self>, Error> {
for ancestor in path.as_ref().ancestors() {
pub fn find(path: &Path) -> Result<Option<Self>, Error> {
for ancestor in path.ancestors() {
match Self::from_directory(ancestor) {
Ok(Some(options)) => {
return Ok(Some(options));
@ -91,9 +91,9 @@ impl FilesystemOptions {
/// Load a [`FilesystemOptions`] from a directory, preferring a `uv.toml` file over a
/// `pyproject.toml` file.
pub fn from_directory(dir: impl AsRef<Path>) -> Result<Option<Self>, Error> {
pub fn from_directory(dir: &Path) -> Result<Option<Self>, Error> {
// Read a `uv.toml` file in the current directory.
let path = dir.as_ref().join("uv.toml");
let path = dir.join("uv.toml");
match fs_err::read_to_string(&path) {
Ok(content) => {
let options: Options = toml::from_str(&content)
@ -101,7 +101,7 @@ impl FilesystemOptions {
// If the directory also contains a `[tool.uv]` table in a `pyproject.toml` file,
// warn.
let pyproject = dir.as_ref().join("pyproject.toml");
let pyproject = dir.join("pyproject.toml");
if let Some(pyproject) = fs_err::read_to_string(pyproject)
.ok()
.and_then(|content| toml::from_str::<PyProjectToml>(&content).ok())
@ -121,7 +121,7 @@ impl FilesystemOptions {
}
// Read a `pyproject.toml` file in the current directory.
let path = dir.as_ref().join("pyproject.toml");
let path = dir.join("pyproject.toml");
match fs_err::read_to_string(&path) {
Ok(content) => {
// Parse, but skip any `pyproject.toml` that doesn't have a `[tool.uv]` section.
@ -130,14 +130,14 @@ impl FilesystemOptions {
let Some(tool) = pyproject.tool else {
debug!(
"Skipping `pyproject.toml` in `{}` (no `[tool]` section)",
dir.as_ref().display()
dir.display()
);
return Ok(None);
};
let Some(options) = tool.uv else {
debug!(
"Skipping `pyproject.toml` in `{}` (no `[tool.uv]` section)",
dir.as_ref().display()
dir.display()
);
return Ok(None);
};