1use 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#[derive(Debug, Clone)]
29pub struct Layout {
30 pub sys_executable: PathBuf,
32 pub python_version: (u8, u8),
34 pub os_name: String,
36 pub scheme: Scheme,
38}
39
40#[derive(Error, Debug)]
42pub enum Error {
43 #[error(transparent)]
44 Io(#[from] io::Error),
45 #[error("The wheel is invalid: {0}")]
47 InvalidWheel(String),
48 #[error("Failed to move data files")]
50 WalkDir(#[from] walkdir::Error),
51 #[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}