Skip to main content

uv_install_wheel/
lib.rs

1//! Takes a wheel and installs it into a venv.
2
3use std::io;
4use std::path::PathBuf;
5
6use owo_colors::OwoColorize;
7use thiserror::Error;
8
9use uv_fs::Simplified;
10use uv_normalize::PackageName;
11use uv_pep440::Version;
12use uv_pypi_types::Scheme;
13
14pub use install::{install_wheel, installed_dist_info_path};
15pub use linker::{InstallState, LinkMode};
16pub use record::RecordEntry;
17pub use uninstall::{Uninstall, uninstall_egg, uninstall_legacy_editable, uninstall_wheel};
18pub use wheel::{WheelFile, read_record, read_record_into_iter, validate_and_heal_record};
19
20mod install;
21mod linker;
22mod record;
23mod script;
24mod uninstall;
25mod wheel;
26
27/// The layout of the target environment into which a wheel can be installed.
28#[derive(Debug, Clone)]
29pub struct Layout {
30    /// The Python interpreter, as returned by `sys.executable`.
31    pub sys_executable: PathBuf,
32    /// The Python version, as returned by `sys.version_info`.
33    pub python_version: (u8, u8),
34    /// The `os.name` value for the current platform.
35    pub os_name: String,
36    /// The [`Scheme`] paths for the interpreter.
37    pub scheme: Scheme,
38}
39
40/// Note: The caller is responsible for adding the path of the wheel we're installing.
41#[derive(Error, Debug)]
42pub enum Error {
43    #[error(transparent)]
44    Io(#[from] io::Error),
45    /// The wheel is broken
46    #[error("The wheel is invalid: {0}")]
47    InvalidWheel(String),
48    /// Doesn't follow file name schema
49    #[error("Failed to move data files")]
50    WalkDir(#[from] walkdir::Error),
51    // This shouldn't be possible anymore, we keep it for better error reporting.
52    #[error(
53        "RECORD file doesn't match wheel contents, could not find entry for: {} ({})",
54        relative.simplified_display(),
55        absolute.simplified_display()
56    )]
57    RecordFile {
58        relative: PathBuf,
59        absolute: PathBuf,
60    },
61    #[error("RECORD file is invalid")]
62    RecordCsv(#[from] csv::Error),
63    #[error("Non-UTF8 path in {0}: {1:?}")]
64    NonUtf8WheelPath(String, PathBuf),
65    #[error("Broken virtual environment: {0}")]
66    BrokenVenv(String),
67    #[error(
68        "Unable to create Windows launcher for: {0} (only x86_64, x86, and arm64 are supported)"
69    )]
70    UnsupportedWindowsArch(&'static str),
71    #[error("Unable to create Windows launcher on non-Windows platform")]
72    NotWindows,
73    #[error("Invalid `direct_url.json`")]
74    DirectUrlJson(#[from] serde_json::Error),
75    #[error("Cannot uninstall package; `RECORD` file not found at: {}", _0.user_display())]
76    MissingRecord(PathBuf),
77    #[error("Cannot uninstall package; `top_level.txt` file not found at: {}", _0.user_display())]
78    MissingTopLevel(PathBuf),
79    #[error("Invalid package version")]
80    InvalidVersion(#[from] uv_pep440::VersionParseError),
81    #[error("Wheel package name does not match filename ({0} != {1}), which indicates a malformed wheel. If this is intentional, set `{env_var}`.", env_var = "UV_SKIP_WHEEL_FILENAME_CHECK=1".green())]
82    MismatchedName(PackageName, PackageName),
83    #[error("Wheel version does not match filename ({0} != {1}), which indicates a malformed wheel. If this is intentional, set `{env_var}`.", env_var = "UV_SKIP_WHEEL_FILENAME_CHECK=1".green())]
84    MismatchedVersion(Version, Version),
85    #[error("Invalid egg-link")]
86    InvalidEggLink(PathBuf),
87    #[error(transparent)]
88    LauncherError(#[from] uv_trampoline_builder::Error),
89    #[error("Scripts must not use the reserved name `{reserved}`, got: `{declared}`")]
90    ReservedScriptName { reserved: String, declared: String },
91    #[error(transparent)]
92    Copy(#[from] uv_fs::link::LinkError),
93}