diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index b4b0a176a..56a4f0a88 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -779,6 +779,18 @@ fn parse_index_url(input: &str) -> Result, String> { } } +/// Parse a string into an [`FlatIndexLocation`], mapping the empty string to `None`. +fn parse_flat_index(input: &str) -> Result, String> { + if input.is_empty() { + Ok(Maybe::None) + } else { + match FlatIndexLocation::from_str(input) { + Ok(url) => Ok(Maybe::Some(url)), + Err(err) => Err(err.to_string()), + } + } +} + /// Parse a string into an [`Url`], mapping the empty string to `None`. fn parse_insecure_host(input: &str) -> Result, String> { if input.is_empty() { @@ -3730,8 +3742,15 @@ pub struct IndexArgs { /// /// If a URL, the page must contain a flat list of links to package files adhering to the /// formats described above. - #[arg(long, short, help_heading = "Index options")] - pub find_links: Option>, + #[arg( + long, + short, + env = "UV_FIND_LINKS", + value_delimiter = ' ', + value_parser = parse_flat_index, + help_heading = "Index options" + )] + pub find_links: Option>>, /// Ignore the registry index (e.g., PyPI), instead relying on direct URL dependencies and those /// provided via `--find-links`. diff --git a/crates/uv-cli/src/options.rs b/crates/uv-cli/src/options.rs index fb7cd5235..3fe5d0e77 100644 --- a/crates/uv-cli/src/options.rs +++ b/crates/uv-cli/src/options.rs @@ -194,14 +194,19 @@ impl From for PipOptions { Self { index_url: index_url.and_then(Maybe::into_option), - extra_index_url: extra_index_url.map(|extra_index_urls| { - extra_index_urls + extra_index_url: extra_index_url.map(|extra_index_url| { + extra_index_url .into_iter() .filter_map(Maybe::into_option) .collect() }), no_index: if no_index { Some(true) } else { None }, - find_links, + find_links: find_links.map(|find_links| { + find_links + .into_iter() + .filter_map(Maybe::into_option) + .collect() + }), ..PipOptions::default() } } @@ -243,8 +248,8 @@ pub fn resolver_options( ResolverOptions { index_url: index_args.index_url.and_then(Maybe::into_option), - extra_index_url: index_args.extra_index_url.map(|extra_index_urls| { - extra_index_urls + extra_index_url: index_args.extra_index_url.map(|extra_index_url| { + extra_index_url .into_iter() .filter_map(Maybe::into_option) .collect() @@ -254,7 +259,12 @@ pub fn resolver_options( } else { None }, - find_links: index_args.find_links, + find_links: index_args.find_links.map(|find_links| { + find_links + .into_iter() + .filter_map(Maybe::into_option) + .collect() + }), upgrade: flag(upgrade, no_upgrade), upgrade_package: Some(upgrade_package), index_strategy, @@ -327,8 +337,8 @@ pub fn resolver_installer_options( ResolverInstallerOptions { index_url: index_args.index_url.and_then(Maybe::into_option), - extra_index_url: index_args.extra_index_url.map(|extra_index_urls| { - extra_index_urls + extra_index_url: index_args.extra_index_url.map(|extra_index_url| { + extra_index_url .into_iter() .filter_map(Maybe::into_option) .collect() @@ -338,7 +348,12 @@ pub fn resolver_installer_options( } else { None }, - find_links: index_args.find_links, + find_links: index_args.find_links.map(|find_links| { + find_links + .into_iter() + .filter_map(Maybe::into_option) + .collect() + }), upgrade: flag(upgrade, no_upgrade), upgrade_package: if upgrade_package.is_empty() { None diff --git a/crates/uv/tests/pip_compile.rs b/crates/uv/tests/pip_compile.rs index 2638aa3dd..c8bc765b8 100644 --- a/crates/uv/tests/pip_compile.rs +++ b/crates/uv/tests/pip_compile.rs @@ -4593,6 +4593,33 @@ fn find_links_requirements_txt() -> Result<()> { Ok(()) } +/// Compile using the `UV_FIND_LINKS` environment variable +#[test] +fn find_links_uv_env_var() -> Result<()> { + let context = TestContext::new("3.12"); + let requirements_in = context.temp_dir.child("requirements.in"); + requirements_in.write_str("tqdm")?; + + uv_snapshot!(context.filters(), context.pip_compile() + .arg("requirements.in") + .arg("--no-index") + .env("UV_FIND_LINKS", "https://download.pytorch.org/whl/torch_stable.html"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + # This file was autogenerated by uv via the following command: + # uv pip compile --cache-dir [CACHE_DIR] requirements.in --no-index + tqdm==4.64.1 + # via -r requirements.in + + ----- stderr ----- + Resolved 1 package in [TIME] + "### + ); + + Ok(()) +} + /// `extras==0.0.2` fails to build (i.e., it always throws). Since `extras==0.0.1` is pinned, we /// should never even attempt to build `extras==0.0.2`, despite an unpinned `extras[dev]` /// requirement. diff --git a/docs/configuration/environment.md b/docs/configuration/environment.md index 917ebd164..cf29ad291 100644 --- a/docs/configuration/environment.md +++ b/docs/configuration/environment.md @@ -6,6 +6,8 @@ uv accepts the following command-line arguments as environment variables: URL as the base index for searching for packages. - `UV_EXTRA_INDEX_URL`: Equivalent to the `--extra-index-url` command-line argument. If set, uv will use this space-separated list of URLs as additional indexes when searching for packages. +- `UV_FIND_LINKS`: Equivalent to the `--find-links` command-line argument. If set, uv will use this + space-separated list of additional locations to search for packages. - `UV_CACHE_DIR`: Equivalent to the `--cache-dir` command-line argument. If set, uv will use this directory for caching instead of the default cache directory. - `UV_NO_CACHE`: Equivalent to the `--no-cache` command-line argument. If set, uv will not use the diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 83292120a..34a03105b 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -148,6 +148,7 @@ uv run [OPTIONS]

If a URL, the page must contain a flat list of links to package files adhering to the formats described above.

+

May also be set with the UV_FIND_LINKS environment variable.

--frozen

Run without updating the uv.lock file.

Instead of checking if the lockfile is up-to-date, uses the versions in the lockfile as the source of truth. If the lockfile is missing, uv will exit with an error. If the pyproject.toml includes changes to dependencies that have not been included in the lockfile yet, they will not be present in the environment.

@@ -692,6 +693,7 @@ uv add [OPTIONS] >

If a URL, the page must contain a flat list of links to package files adhering to the formats described above.

+

May also be set with the UV_FIND_LINKS environment variable.

--frozen

Add dependencies without re-locking the project.

The project environment will not be synced.

@@ -1009,6 +1011,7 @@ uv remove [OPTIONS] ...

If a URL, the page must contain a flat list of links to package files adhering to the formats described above.

+

May also be set with the UV_FIND_LINKS environment variable.

--frozen

Remove dependencies without re-locking the project.

The project environment will not be synced.

@@ -1314,6 +1317,7 @@ uv sync [OPTIONS]

If a URL, the page must contain a flat list of links to package files adhering to the formats described above.

+

May also be set with the UV_FIND_LINKS environment variable.

--frozen

Sync without updating the uv.lock file.

Instead of checking if the lockfile is up-to-date, uses the versions in the lockfile as the source of truth. If the lockfile is missing, uv will exit with an error. If the pyproject.toml includes changes to dependencies that have not been included in the lockfile yet, they will not be present in the environment.

@@ -1617,6 +1621,7 @@ uv lock [OPTIONS]

If a URL, the page must contain a flat list of links to package files adhering to the formats described above.

+

May also be set with the UV_FIND_LINKS environment variable.

--frozen

Assert that a uv.lock exists, without updating it

--help, -h

Display the concise help for this command

@@ -1896,6 +1901,7 @@ uv export [OPTIONS]

If a URL, the page must contain a flat list of links to package files adhering to the formats described above.

+

May also be set with the UV_FIND_LINKS environment variable.

--format format

The format to which uv.lock should be exported.

At present, only requirements-txt is supported.

@@ -2204,6 +2210,7 @@ uv tree [OPTIONS]

If a URL, the page must contain a flat list of links to package files adhering to the formats described above.

+

May also be set with the UV_FIND_LINKS environment variable.

--frozen

Display the requirements without locking the project.

If the lockfile is missing, uv will exit with an error.

@@ -2575,6 +2582,7 @@ uv tool run [OPTIONS] [COMMAND]

If a URL, the page must contain a flat list of links to package files adhering to the formats described above.

+

May also be set with the UV_FIND_LINKS environment variable.

--from from

Use the given package to provide the command.

By default, the package name is assumed to match the command name.

@@ -2863,6 +2871,7 @@ uv tool install [OPTIONS]

If a URL, the page must contain a flat list of links to package files adhering to the formats described above.

+

May also be set with the UV_FIND_LINKS environment variable.

--force

Force installation of the tool.

Will replace any existing entry points with the same name in the executable directory.

@@ -3147,6 +3156,7 @@ uv tool upgrade [OPTIONS] ...

If a URL, the page must contain a flat list of links to package files adhering to the formats described above.

+

May also be set with the UV_FIND_LINKS environment variable.

--help, -h

Display the concise help for this command

--index-strategy index-strategy

The strategy to use when resolving against multiple index URLs.

@@ -4711,6 +4721,7 @@ uv pip compile [OPTIONS] ...

If a URL, the page must contain a flat list of links to package files adhering to the formats described above.

+

May also be set with the UV_FIND_LINKS environment variable.

--generate-hashes

Include distribution hashes in the output file

--help, -h

Display the concise help for this command

@@ -5099,6 +5110,7 @@ uv pip sync [OPTIONS] ...

If a URL, the page must contain a flat list of links to package files adhering to the formats described above.

+

May also be set with the UV_FIND_LINKS environment variable.

--help, -h

Display the concise help for this command

--index-strategy index-strategy

The strategy to use when resolving against multiple index URLs.

@@ -5441,6 +5453,7 @@ uv pip install [OPTIONS] |--editable If a URL, the page must contain a flat list of links to package files adhering to the formats described above.

+

May also be set with the UV_FIND_LINKS environment variable.

--help, -h

Display the concise help for this command

--index-strategy index-strategy

The strategy to use when resolving against multiple index URLs.

@@ -6610,6 +6623,7 @@ uv venv [OPTIONS] [PATH]

If a URL, the page must contain a flat list of links to package files adhering to the formats described above.

+

May also be set with the UV_FIND_LINKS environment variable.

--help, -h

Display the concise help for this command

--index-strategy index-strategy

The strategy to use when resolving against multiple index URLs.

@@ -6857,6 +6871,7 @@ uv build [OPTIONS] [SRC]

If a URL, the page must contain a flat list of links to package files adhering to the formats described above.

+

May also be set with the UV_FIND_LINKS environment variable.

--help, -h

Display the concise help for this command

--index-strategy index-strategy

The strategy to use when resolving against multiple index URLs.