Skip to content

Commit

Permalink
Automatically add to PATH on UNIX shells (astral-sh#580)
Browse files Browse the repository at this point in the history
  • Loading branch information
mitsuhiko authored Feb 3, 2024
1 parent 475c6d5 commit 8dae30e
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 10 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ _Unreleased_

- The internal Python version was bumped to 3.12. #576

- The installer now can automatically add Rye to `PATH` on most UNIX environments. #580

<!-- released start -->

## 0.20.0
Expand Down
31 changes: 28 additions & 3 deletions docs/guide/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,23 @@ This folder is a folder that contains "shims" which are executables that
Rye manages for you as well as the `rye` executable itself. For instance any
Python installation managed by Rye will be available via a shim placed there.

On macOS or Linux you can accomplish this by adding it to your `.bashrc`, `.zshrc`
On macOS or Linux you can accomplish this by adding it to your `.profile` file
or similar. This step is technically optional but required if you want to be able to
just type `python` or `rye` into the shell to pick up the current virtualenv's Python
interpreter.
interpreter. The installer will offer to do this for you automatically. If you
opt-out, or you run a custom shell you will need to do this manually.

=== "Bash"

Rye ships an `env` file which should be sourced to update `PATH` automatically.

```bash
echo 'source "$HOME/.rye/env"' >> ~/.profile
```

In some setups `.profile` is not sourced, in which case you can add it to your
`.bashrc` instead:

```bash
echo 'source "$HOME/.rye/env"' >> ~/.bashrc
```
Expand All @@ -69,7 +77,14 @@ interpreter.
Rye ships an `env` file which should be sourced to update `PATH` automatically.

```bash
echo 'source "$HOME/.rye/env"' >> ~/.zshrc
echo 'source "$HOME/.rye/env"' >> ~/.profile
```

In some setups `.profile` is not sourced, in which case you can add it to your
`.zprofile` instead:

```bash
echo 'source "$HOME/.rye/env"' >> ~/.zprofile
```

=== "Fish"
Expand All @@ -82,6 +97,16 @@ interpreter.
set -Ua fish_user_paths "$HOME/.rye/shims"
```

=== "Nushell"

Since nushell does not support `env` files, you instead need to add
the shims directly. This can be accomplished by adding this to your
`env.nu` file:

```shell
$env.PATH = ($env.PATH | split row (char esep) | append "~/.rye/shims")
```

=== "Unix Shells"

Rye ships an `env` file which should be sourced to update `PATH` automatically.
Expand Down
4 changes: 2 additions & 2 deletions rye/src/bootstrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,9 +308,9 @@ pub fn get_pip_module(venv: &Path) -> Result<PathBuf, Error> {
Ok(rv)
}

/// we only support cpython 3.9 to 3.11
/// we only support cpython 3.9 to 3.12
pub fn is_self_compatible_toolchain(version: &PythonVersion) -> bool {
version.name == "cpython" && version.major == 3 && version.minor >= 9 && version.minor < 12
version.name == "cpython" && version.major == 3 && version.minor >= 9 && version.minor <= 12
}

fn ensure_self_toolchain(output: CommandOutput) -> Result<PythonVersion, Error> {
Expand Down
33 changes: 28 additions & 5 deletions rye/src/cli/rye.rs
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,7 @@ fn perform_install(mode: InstallMode, toolchain_path: Option<&Path>) -> Result<(
prompt_for_default_toolchain(registered_toolchain.unwrap(), config_doc)?;
}

let rye_home = Path::new(&*rye_home);
#[cfg(unix)]
{
if !env::split_paths(&env::var_os("PATH").unwrap())
Expand All @@ -496,23 +497,45 @@ fn perform_install(mode: InstallMode, toolchain_path: Option<&Path>) -> Result<(
style("PATH").cyan()
);
echo!("It is highly recommended that you add it.");
echo!("Add this at the end of your .profile, .zprofile or similar:");

if matches!(mode, InstallMode::NoPrompts)
|| dialoguer::Confirm::with_theme(tui_theme())
.with_prompt(format!(
"Should the installer add Rye to {} via .profile?",
style("PATH").cyan()
))
.interact()?
{
crate::utils::unix::add_to_path(rye_home)?;
echo!("Added to {}.", style("PATH").cyan());
echo!(
"{}: for this to take effect you will need to restart your shell or run this manually:",
style("note").cyan()
);
} else {
echo!(
"{}: did not manipulate the path. To make it work, add this to your .profile manually:",
style("note").cyan()
);
}

echo!();
echo!(" source \"{}/env\"", rye_home);
echo!(" source \"{}/env\"", rye_home.display());
echo!();
if is_fish() {
echo!("To make it work with fish, run this once instead:");
echo!();
echo!(" set -Ua fish_user_paths \"{}/shims\"", rye_home);
echo!(
" set -Ua fish_user_paths \"{}/shims\"",
rye_home.display()
);
echo!();
}
echo!("Note: after adding rye to your path, restart your shell for it to take effect.");
echo!("For more information read https://mitsuhiko.github.io/rye/guide/installation");
}
}
#[cfg(windows)]
{
let rye_home = Path::new(&*rye_home);
crate::utils::windows::add_to_programs(rye_home)?;
crate::utils::windows::add_to_path(rye_home)?;
}
Expand Down
3 changes: 3 additions & 0 deletions rye/src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ pub fn tui_theme() -> &'static dyn Theme {
#[cfg(windows)]
pub(crate) mod windows;

#[cfg(unix)]
pub(crate) mod unix;

#[cfg(windows)]
pub fn symlink_dir<P, Q>(original: P, link: Q) -> Result<(), std::io::Error>
where
Expand Down
43 changes: 43 additions & 0 deletions rye/src/utils/unix.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use std::path::{Path, PathBuf};
use std::{env, fs};

use anyhow::{Context, Error};

pub(crate) fn add_to_path(rye_home: &Path) -> Result<(), Error> {
// for regular shells just add the path to `.profile`
add_source_line_to_profile(
&home::home_dir()
.context("could not find home dir")?
.join(".profile"),
&(format!(
". \"{}\"",
reverse_resolve_env_home(rye_home.join("env")).display()
)),
)?;
Ok(())
}

fn add_source_line_to_profile(profile_path: &Path, source_line: &str) -> Result<(), Error> {
let mut profile = if profile_path.is_file() {
fs::read_to_string(profile_path)?
} else {
String::new()
};

if !profile.lines().any(|x| x.trim() == source_line) {
profile.push_str(source_line);
profile.push('\n');
fs::write(profile_path, profile).context("failed to write updated .profile")?;
}

Ok(())
}

fn reverse_resolve_env_home(path: PathBuf) -> PathBuf {
if let Some(env_home) = env::var_os("HOME").map(PathBuf::from) {
if let Ok(rest) = path.strip_prefix(&env_home) {
return Path::new("$HOME").join(rest);
}
}
path
}

0 comments on commit 8dae30e

Please sign in to comment.