Move shell manipulation into its own crate (#5028)

## Summary

This is going to get a little more complex as we support Windows, so
carving it out.
This commit is contained in:
Charlie Marsh 2024-07-12 21:12:58 -04:00 committed by GitHub
parent ba217f1059
commit a61464e802
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 42 additions and 17 deletions

12
Cargo.lock generated
View file

@ -4456,7 +4456,6 @@ dependencies = [
"flate2",
"fs-err",
"futures",
"home",
"ignore",
"indexmap",
"indicatif",
@ -4476,7 +4475,6 @@ dependencies = [
"regex",
"reqwest",
"rustc-hash 2.0.0",
"same-file",
"serde",
"serde_json",
"textwrap",
@ -4506,6 +4504,7 @@ dependencies = [
"uv-resolver",
"uv-scripts",
"uv-settings",
"uv-shell",
"uv-tool",
"uv-types",
"uv-virtualenv",
@ -5086,6 +5085,15 @@ dependencies = [
"uv-warnings",
]
[[package]]
name = "uv-shell"
version = "0.0.1"
dependencies = [
"home",
"same-file",
"uv-fs",
]
[[package]]
name = "uv-state"
version = "0.0.1"

View file

@ -41,13 +41,14 @@ uv-git = { path = "crates/uv-git" }
uv-installer = { path = "crates/uv-installer" }
uv-macros = { path = "crates/uv-macros" }
uv-normalize = { path = "crates/uv-normalize" }
uv-python = { path = "crates/uv-python" }
uv-requirements = { path = "crates/uv-requirements" }
uv-resolver = { path = "crates/uv-resolver" }
uv-scripts = { path = "crates/uv-scripts" }
uv-settings = { path = "crates/uv-settings" }
uv-shell = { path = "crates/uv-shell" }
uv-state = { path = "crates/uv-state" }
uv-tool = { path = "crates/uv-tool" }
uv-python = { path = "crates/uv-python" }
uv-types = { path = "crates/uv-types" }
uv-version = { path = "crates/uv-version" }
uv-virtualenv = { path = "crates/uv-virtualenv" }

View file

@ -109,6 +109,10 @@ Utilities for reading package requirements from `pyproject.toml` and `requiremen
Functionality for resolving Python packages and their dependencies.
## [uv-shell](./uv-shell)
Utilities for detecting and manipulating shell environments.
## [uv-types](./uv-types)
Shared traits for uv, to avoid circular dependencies.

View file

@ -2,7 +2,7 @@
name = "uv-normalize"
version = "0.0.1"
edition = "2021"
description = "Normalization for distribution, package and extra anmes"
description = "Normalization for distribution, package and extra names."
[lints]
workspace = true

View file

@ -0,0 +1,14 @@
[package]
name = "uv-shell"
version = "0.0.1"
edition = "2021"
description = "Utilities for detecting and manipulating shell environments"
[lints]
workspace = true
[dependencies]
uv-fs = { workspace = true }
home = { workspace = true }
same-file = { workspace = true }

View file

@ -4,7 +4,7 @@ use uv_fs::Simplified;
/// Shells for which virtualenv activation scripts are available.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[allow(clippy::doc_markdown)]
pub(crate) enum Shell {
pub enum Shell {
/// Bourne Again SHell (bash)
Bash,
/// Friendly Interactive SHell (fish)
@ -32,7 +32,7 @@ impl Shell {
///
/// If `SHELL` is set, but contains a value that doesn't correspond to one of the supported
/// shell types, then return `None`.
pub(crate) fn from_env() -> Option<Shell> {
pub fn from_env() -> Option<Shell> {
if std::env::var_os("NU_VERSION").is_some() {
Some(Shell::Nushell)
} else if std::env::var_os("FISH_VERSION").is_some() {
@ -68,7 +68,7 @@ impl Shell {
/// assert_eq!(Shell::from_shell_path("/usr/bin/zsh"), Some(Shell::Zsh));
/// assert_eq!(Shell::from_shell_path("/opt/my_custom_shell"), None);
/// ```
pub(crate) fn from_shell_path(path: impl AsRef<Path>) -> Option<Shell> {
pub fn from_shell_path(path: impl AsRef<Path>) -> Option<Shell> {
parse_shell_from_path(path.as_ref())
}
@ -77,7 +77,7 @@ impl Shell {
/// Some of the logic here is based on rustup's rc file detection.
///
/// See: <https://github.com/rust-lang/rustup/blob/fede22fea7b160868cece632bd213e6d72f8912f/src/cli/self_update/shell.rs#L197>
pub(crate) fn configuration_files(self) -> Vec<PathBuf> {
pub fn configuration_files(self) -> Vec<PathBuf> {
let Some(home_dir) = home::home_dir() else {
return vec![];
};
@ -158,7 +158,7 @@ impl Shell {
}
/// Returns `true` if the given path is on the `PATH` in this shell.
pub(crate) fn contains_path(path: &Path) -> bool {
pub fn contains_path(path: &Path) -> bool {
std::env::var_os("PATH")
.as_ref()
.iter()
@ -167,7 +167,7 @@ impl Shell {
}
/// Returns the command necessary to prepend a directory to the `PATH` in this shell.
pub(crate) fn prepend_path(self, path: &Path) -> Option<String> {
pub fn prepend_path(self, path: &Path) -> Option<String> {
match self {
Shell::Nushell => None,
Shell::Bash | Shell::Zsh => Some(format!(

View file

@ -32,12 +32,13 @@ uv-fs = { workspace = true }
uv-git = { workspace = true }
uv-installer = { workspace = true }
uv-normalize = { workspace = true }
uv-python = { workspace = true, features = ["schemars"]}
uv-requirements = { workspace = true }
uv-resolver = { workspace = true }
uv-scripts = { workspace = true }
uv-settings = { workspace = true, features = ["schemars"] }
uv-shell = { workspace = true }
uv-tool = { workspace = true }
uv-python = { workspace = true, features = ["schemars"]}
uv-types = { workspace = true }
uv-virtualenv = { workspace = true }
uv-warnings = { workspace = true }
@ -50,7 +51,6 @@ clap = { workspace = true, features = ["derive", "string", "wrap_help"] }
flate2 = { workspace = true, default-features = false }
fs-err = { workspace = true, features = ["tokio"] }
futures = { workspace = true }
home = { workspace = true }
indexmap = { workspace = true }
indicatif = { workspace = true }
itertools = { workspace = true }
@ -59,7 +59,6 @@ owo-colors = { workspace = true }
rayon = { workspace = true }
regex = { workspace = true }
rustc-hash = { workspace = true }
same-file = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
textwrap = { workspace = true }

View file

@ -22,6 +22,7 @@ use uv_python::{
EnvironmentPreference, PythonFetch, PythonInstallation, PythonPreference, PythonRequest,
};
use uv_requirements::RequirementsSpecification;
use uv_shell::Shell;
use uv_tool::{entrypoint_paths, find_executable_directory, InstalledTools, Tool, ToolEntrypoint};
use uv_warnings::{warn_user, warn_user_once};
@ -31,7 +32,6 @@ use crate::commands::tool::common::resolve_requirements;
use crate::commands::{ExitStatus, SharedState};
use crate::printer::Printer;
use crate::settings::ResolverInstallerSettings;
use crate::shell::Shell;
/// Install a tool.
pub(crate) async fn install(

View file

@ -7,12 +7,12 @@ use tracing::debug;
use uv_configuration::PreviewMode;
use uv_fs::Simplified;
use uv_shell::Shell;
use uv_tool::find_executable_directory;
use uv_warnings::warn_user_once;
use crate::commands::ExitStatus;
use crate::printer::Printer;
use crate::shell::Shell;
/// Ensure that the executable directory is in PATH.
pub(crate) async fn update_shell(preview: PreviewMode, printer: Printer) -> Result<ExitStatus> {

View file

@ -26,12 +26,12 @@ use uv_python::{
PythonPreference, PythonRequest,
};
use uv_resolver::{ExcludeNewer, FlatIndex};
use uv_shell::Shell;
use uv_types::{BuildContext, BuildIsolation, HashStrategy};
use crate::commands::reporters::PythonDownloadReporter;
use crate::commands::{pip, ExitStatus, SharedState};
use crate::printer::Printer;
use crate::shell::Shell;
/// Create a virtual environment.
#[allow(clippy::unnecessary_wraps, clippy::fn_params_excessive_bools)]

View file

@ -53,7 +53,6 @@ pub(crate) mod commands;
pub(crate) mod logging;
pub(crate) mod printer;
pub(crate) mod settings;
pub(crate) mod shell;
pub(crate) mod version;
#[instrument(skip_all)]