mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-03 07:14:35 +00:00
cli: conventionally treat -
as "read from stdin" (#1314)
Basically, when a path to a requirements file is `-`, then we should read its contents from `stdin` instead of the file path named `-`. Fixes #1313
This commit is contained in:
parent
c5e413c4b8
commit
b6fba00153
5 changed files with 69 additions and 6 deletions
|
@ -12,6 +12,38 @@ pub use crate::path::*;
|
|||
|
||||
mod path;
|
||||
|
||||
/// Reads the contents of the file path given into memory.
|
||||
///
|
||||
/// If the file path is `-`, then contents are read from stdin instead.
|
||||
pub fn read(path: impl AsRef<Path>) -> std::io::Result<Vec<u8>> {
|
||||
use std::io::Read;
|
||||
|
||||
let path = path.as_ref();
|
||||
if path == Path::new("-") {
|
||||
let mut buf = Vec::with_capacity(1024);
|
||||
std::io::stdin().read_to_end(&mut buf)?;
|
||||
Ok(buf)
|
||||
} else {
|
||||
fs::read(path)
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads the contents of the file path given into memory as a `String`.
|
||||
///
|
||||
/// If the file path is `-`, then contents are read from stdin instead.
|
||||
pub fn read_to_string(path: impl AsRef<Path>) -> std::io::Result<String> {
|
||||
use std::io::Read;
|
||||
|
||||
let path = path.as_ref();
|
||||
if path == Path::new("-") {
|
||||
let mut buf = String::with_capacity(1024);
|
||||
std::io::stdin().read_to_string(&mut buf)?;
|
||||
Ok(buf)
|
||||
} else {
|
||||
fs::read_to_string(path)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a symlink from `src` to `dst`, replacing any existing symlink.
|
||||
///
|
||||
/// On Windows, this uses the `junction` crate to create a junction point.
|
||||
|
|
|
@ -158,6 +158,8 @@ fn date_or_datetime(input: &str) -> Result<DateTime<Utc>, String> {
|
|||
#[allow(clippy::struct_excessive_bools)]
|
||||
struct PipCompileArgs {
|
||||
/// Include all packages listed in the given `requirements.in` files.
|
||||
///
|
||||
/// When the path is `-`, then requirements are read from stdin.
|
||||
#[clap(required(true))]
|
||||
src_file: Vec<PathBuf>,
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ use std::path::{Path, PathBuf};
|
|||
|
||||
use anyhow::{Context, Result};
|
||||
use console::Term;
|
||||
use fs_err as fs;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use distribution_types::{FlatIndexLocation, IndexUrl};
|
||||
|
@ -193,7 +192,7 @@ impl RequirementsSpecification {
|
|||
}
|
||||
}
|
||||
RequirementsSource::PyprojectToml(path) => {
|
||||
let contents = fs::read_to_string(path)?;
|
||||
let contents = puffin_fs::read_to_string(path)?;
|
||||
let pyproject_toml = toml::from_str::<pyproject_toml::PyProjectToml>(&contents)
|
||||
.with_context(|| format!("Failed to parse `{}`", path.normalized_display()))?;
|
||||
let mut used_extras = FxHashSet::default();
|
||||
|
|
|
@ -47,6 +47,36 @@ fn compile_requirements_in() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Resolve a specific version of Django from a `requirements.in` file on stdin
|
||||
/// when passed a path of `-`.
|
||||
#[test]
|
||||
fn compile_requirements_in_stdin() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
let requirements_in = context.temp_dir.child("requirements.in");
|
||||
requirements_in.write_str("django==5.0b1")?;
|
||||
|
||||
puffin_snapshot!(context
|
||||
.compile()
|
||||
.stdin(fs::File::open(requirements_in)?)
|
||||
.arg("-"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
# This file was autogenerated by Puffin v[VERSION] via the following command:
|
||||
# puffin pip compile --cache-dir [CACHE_DIR] --exclude-newer 2023-11-18T12:00:00Z -
|
||||
asgiref==3.7.2
|
||||
# via django
|
||||
django==5.0b1
|
||||
sqlparse==0.4.4
|
||||
# via django
|
||||
|
||||
----- stderr -----
|
||||
Resolved 3 packages in [TIME]
|
||||
"###);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_requirements_in() {
|
||||
let context = TestContext::new("3.12");
|
||||
|
|
|
@ -39,7 +39,6 @@ use std::fmt::{Display, Formatter};
|
|||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use fs_err as fs;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::warn;
|
||||
use unscanny::{Pattern, Scanner};
|
||||
|
@ -299,10 +298,11 @@ impl RequirementsTxt {
|
|||
requirements_txt: impl AsRef<Path>,
|
||||
working_dir: impl AsRef<Path>,
|
||||
) -> Result<Self, RequirementsTxtFileError> {
|
||||
let content =
|
||||
fs::read_to_string(&requirements_txt).map_err(|err| RequirementsTxtFileError {
|
||||
let content = puffin_fs::read_to_string(&requirements_txt).map_err(|err| {
|
||||
RequirementsTxtFileError {
|
||||
file: requirements_txt.as_ref().to_path_buf(),
|
||||
error: RequirementsTxtParserError::IO(err),
|
||||
}
|
||||
})?;
|
||||
let data = Self::parse_inner(&content, working_dir.as_ref()).map_err(|err| {
|
||||
RequirementsTxtFileError {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue