mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-16 17:55:01 +00:00
Implement uv run --directory
(#5566)
## Summary uv run --directory <path> means that one doesn't have to change to a project's directory to run programs from it. It makes it possible to use projects as if they are tool installations. To support this, first the code reading .python-version was updated so that it can read such markers outside the current directory. Note the minor change this causes (if I'm right), described in the commit. ## Test Plan One test has been added. ## --directory Not sure what the name of the argument should be, but it's following uv sync's directory for now. Other alternatives could be "--project". Uv run and uv tool run should probably find common agreement on this (relevant for project-locked tools). I've implemented this same change in Rye, some time ago, and then we went with --pyproject `<`path to pyproject.toml file`>`. I think using pyproject.toml file path and not directory was probably a mistake, an overgeneralization one doesn't need.
This commit is contained in:
parent
cf94a10054
commit
e46c24d3cf
10 changed files with 119 additions and 22 deletions
|
@ -1,3 +1,5 @@
|
|||
use std::path::Path;
|
||||
|
||||
use fs_err as fs;
|
||||
use tracing::debug;
|
||||
|
||||
|
@ -13,15 +15,17 @@ pub static PYTHON_VERSIONS_FILENAME: &str = ".python-versions";
|
|||
///
|
||||
/// Prefers `.python-versions` then `.python-version`.
|
||||
/// If only one Python version is desired, use [`request_from_version_files`] which prefers the `.python-version` file.
|
||||
pub async fn requests_from_version_file() -> Result<Option<Vec<PythonRequest>>, std::io::Error> {
|
||||
if let Some(versions) = read_versions_file().await? {
|
||||
pub async fn requests_from_version_file(
|
||||
directory: Option<&Path>,
|
||||
) -> Result<Option<Vec<PythonRequest>>, std::io::Error> {
|
||||
if let Some(versions) = read_versions_file(directory).await? {
|
||||
Ok(Some(
|
||||
versions
|
||||
.into_iter()
|
||||
.map(|version| PythonRequest::parse(&version))
|
||||
.collect(),
|
||||
))
|
||||
} else if let Some(version) = read_version_file().await? {
|
||||
} else if let Some(version) = read_version_file(directory).await? {
|
||||
Ok(Some(vec![PythonRequest::parse(&version)]))
|
||||
} else {
|
||||
Ok(None)
|
||||
|
@ -30,12 +34,17 @@ pub async fn requests_from_version_file() -> Result<Option<Vec<PythonRequest>>,
|
|||
|
||||
/// Read a [`PythonRequest`] from a version file, if present.
|
||||
///
|
||||
/// Find the version file inside directory, or the current directory
|
||||
/// if None.
|
||||
///
|
||||
/// Prefers `.python-version` then the first entry of `.python-versions`.
|
||||
/// If multiple Python versions are desired, use [`requests_from_version_files`] instead.
|
||||
pub async fn request_from_version_file() -> Result<Option<PythonRequest>, std::io::Error> {
|
||||
if let Some(version) = read_version_file().await? {
|
||||
pub async fn request_from_version_file(
|
||||
directory: Option<&Path>,
|
||||
) -> Result<Option<PythonRequest>, std::io::Error> {
|
||||
if let Some(version) = read_version_file(directory).await? {
|
||||
Ok(Some(PythonRequest::parse(&version)))
|
||||
} else if let Some(versions) = read_versions_file().await? {
|
||||
} else if let Some(versions) = read_versions_file(directory).await? {
|
||||
Ok(versions
|
||||
.into_iter()
|
||||
.next()
|
||||
|
@ -52,10 +61,17 @@ pub async fn write_version_file(version: &str) -> Result<(), std::io::Error> {
|
|||
fs::tokio::write(PYTHON_VERSION_FILENAME, format!("{version}\n")).await
|
||||
}
|
||||
|
||||
async fn read_versions_file() -> Result<Option<Vec<String>>, std::io::Error> {
|
||||
match fs::tokio::read_to_string(PYTHON_VERSIONS_FILENAME).await {
|
||||
async fn read_versions_file(
|
||||
directory: Option<&Path>,
|
||||
) -> Result<Option<Vec<String>>, std::io::Error> {
|
||||
let file_path = directory.map(|pth| pth.join(PYTHON_VERSIONS_FILENAME));
|
||||
let path = file_path
|
||||
.as_deref()
|
||||
.unwrap_or(Path::new(PYTHON_VERSIONS_FILENAME));
|
||||
|
||||
match fs::tokio::read_to_string(path).await {
|
||||
Ok(content) => {
|
||||
debug!("Reading requests from `{PYTHON_VERSIONS_FILENAME}`");
|
||||
debug!("Reading requests from `{}`", path.display());
|
||||
Ok(Some(
|
||||
content
|
||||
.lines()
|
||||
|
@ -73,10 +89,15 @@ async fn read_versions_file() -> Result<Option<Vec<String>>, std::io::Error> {
|
|||
}
|
||||
}
|
||||
|
||||
async fn read_version_file() -> Result<Option<String>, std::io::Error> {
|
||||
match fs::tokio::read_to_string(PYTHON_VERSION_FILENAME).await {
|
||||
async fn read_version_file(directory: Option<&Path>) -> Result<Option<String>, std::io::Error> {
|
||||
let file_path = directory.map(|pth| pth.join(PYTHON_VERSION_FILENAME));
|
||||
let path = file_path
|
||||
.as_deref()
|
||||
.unwrap_or(Path::new(PYTHON_VERSION_FILENAME));
|
||||
|
||||
match fs::tokio::read_to_string(path).await {
|
||||
Ok(content) => {
|
||||
debug!("Reading requests from `{PYTHON_VERSION_FILENAME}`");
|
||||
debug!("Reading requests from `{}`", path.display());
|
||||
Ok(content
|
||||
.lines()
|
||||
.find(|line| {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue