From 95ba033e007f431126aef5aa41a862b72184d6da Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sun, 21 Jan 2024 00:30:29 +0100 Subject: [PATCH] Add simplified rye fetch (#545) --- CHANGELOG.md | 7 +++++++ docs/guide/toolchains/index.md | 8 ++++++++ rye/src/cli/fetch.rs | 25 ++++++++++++++++++++++--- rye/src/cli/init.rs | 8 ++++++-- rye/src/cli/shim.rs | 30 +++++++++++++++++++++--------- 5 files changed, 64 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e255eca27..b7e9e7b4ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ that were not yet released. _Unreleased_ +- Improved the behavior of `rye fetch`. When invoked without arguments it will now try to + fetch the version of the requested Python interpreter. Specifically this combining + `pin` and `fetch` work in a much simplified manner. #545 + +- Fixed an issue where `rye init` would pin a much too specific version in the `.python-version` + file that is generated. #545 + ## 0.18.0 diff --git a/docs/guide/toolchains/index.md b/docs/guide/toolchains/index.md index 96a1cbb0b9..9281cd0cf9 100644 --- a/docs/guide/toolchains/index.md +++ b/docs/guide/toolchains/index.md @@ -82,6 +82,14 @@ with `rye toolchain fetch` (also aliased to `rye fetch`): rye toolchain fetch cpython@3.8.5 ``` +Starting with Rye 0.19.0 the argument to `fetch` is inferred from the current pin. This means +you can also fetch as follows: + +``` +rye pin 3.10 +rye fetch +``` + Toolchains are fetched from two sources: * [Indygreg's Portable Python Builds](https://github.com/indygreg/python-build-standalone) for CPython diff --git a/rye/src/cli/fetch.rs b/rye/src/cli/fetch.rs index 3a406d6ef9..7c468106bb 100644 --- a/rye/src/cli/fetch.rs +++ b/rye/src/cli/fetch.rs @@ -1,14 +1,19 @@ -use anyhow::{Context, Error}; +use anyhow::{anyhow, Context, Error}; use clap::Parser; use crate::bootstrap::fetch; +use crate::platform::get_python_version_request_from_pyenv_pin; +use crate::pyproject::PyProject; +use crate::sources::PythonVersionRequest; use crate::utils::CommandOutput; /// Fetches a Python interpreter for the local machine. #[derive(Parser, Debug)] pub struct Args { /// The version of Python to fetch. - version: String, + /// + /// If no version is provided, the requested version will be fetched. + version: Option, /// Overrides the architecture to fetch. /// /// When a non native architecture is fetched, the toolchain is @@ -24,6 +29,20 @@ pub struct Args { pub fn execute(cmd: Args) -> Result<(), Error> { let output = CommandOutput::from_quiet_and_verbose(cmd.quiet, cmd.verbose); - fetch(&cmd.version.parse()?, output).context("error while fetching python installation")?; + + let version: PythonVersionRequest = match cmd.version { + Some(version) => version.parse()?, + None => { + if let Ok(pyproject) = PyProject::discover() { + pyproject.venv_python_version()?.into() + } else { + get_python_version_request_from_pyenv_pin(&std::env::current_dir()?).ok_or_else( + || anyhow!("not sure what to fetch, please provide an explicit version"), + )? + } + } + }; + + fetch(&version, output).context("error while fetching python installation")?; Ok(()) } diff --git a/rye/src/cli/init.rs b/rye/src/cli/init.rs index d162d18e77..9a4cee92ab 100644 --- a/rye/src/cli/init.rs +++ b/rye/src/cli/init.rs @@ -19,7 +19,7 @@ use tempfile::tempdir; use crate::bootstrap::ensure_self_venv; use crate::config::Config; use crate::platform::{ - get_default_author_with_fallback, get_latest_cpython_version, + get_default_author_with_fallback, get_latest_cpython_version, get_pinnable_version, get_python_version_request_from_pyenv_pin, }; use crate::pyproject::BuildSystem; @@ -370,7 +370,11 @@ pub fn execute(cmd: Args) -> Result<(), Error> { // write .python-version if !cmd.no_pin && !python_version_file.is_file() { - fs::write(python_version_file, format!("{}\n", py)) + // get_pinnable_version ideally doesn't fail, but if it does we fall back to + // the full version request. This has the disadvantage that we might end up + // pinning to an architecture specific version. + let to_write = get_pinnable_version(&py, false).unwrap_or_else(|| py.to_string()); + fs::write(python_version_file, format!("{}\n", to_write)) .context("could not write .python-version file")?; } diff --git a/rye/src/cli/shim.rs b/rye/src/cli/shim.rs index 112fedba94..cc35942cdb 100644 --- a/rye/src/cli/shim.rs +++ b/rye/src/cli/shim.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::convert::Infallible; use std::env; use std::ffi::{OsStr, OsString}; @@ -227,19 +228,25 @@ fn get_shim_target( let config = Config::current(); let mut remove1 = false; - let version_request = if let Some(rest) = args + let (version_request, implicit_request) = if let Some(rest) = args .get(1) .and_then(|x| x.as_os_str().to_str()) .and_then(|x| x.strip_prefix('+')) { remove1 = true; - PythonVersionRequest::from_str(rest) - .context("invalid python version requested from command line")? + ( + PythonVersionRequest::from_str(rest) + .context("invalid python version requested from command line")?, + false, + ) } else if config.global_python() { - match get_python_version_request_from_pyenv_pin(&std::env::current_dir()?) { - Some(version_request) => version_request, - None => config.default_toolchain()?, - } + ( + match get_python_version_request_from_pyenv_pin(&std::env::current_dir()?) { + Some(version_request) => version_request, + None => config.default_toolchain()?, + }, + true, + ) } else { // if neither requested explicitly, nor global-python is enabled, we fall // back to the next shadowed target @@ -253,10 +260,15 @@ fn get_shim_target( }; let py = get_toolchain_python_bin(&py_ver)?; if !py.is_file() { + let hint = if implicit_request { + Cow::Borrowed("rye fetch") + } else { + Cow::Owned(format!("rye fetch {}", py_ver)) + }; bail!( - "Requested Python version ({}) is not installed. Install with `rye fetch {}`", + "Requested Python version ({}) is not installed. Install with `{}`", py_ver, - py_ver + hint ); }