simics_python_utils/
environment.rs1use crate::version::PythonVersion;
5use anyhow::{anyhow, Result};
6use std::path::PathBuf;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
10pub enum PackageSource {
11 Traditional,
13 SeparatePackage,
15}
16
17#[derive(Debug, Clone)]
19pub struct PythonEnvironment {
20 pub mini_python: PathBuf,
22 pub include_dir: PathBuf,
24 pub include_flag: String,
26 pub lib_dir: PathBuf,
28 pub lib_path: PathBuf,
30 pub version: PythonVersion,
32 pub package_source: PackageSource,
34}
35
36impl PythonEnvironment {
37 pub fn new(
39 mini_python: PathBuf,
40 include_dir: PathBuf,
41 lib_dir: PathBuf,
42 lib_path: PathBuf,
43 version: PythonVersion,
44 package_source: PackageSource,
45 ) -> Self {
46 let include_flag = format!("-I{}", include_dir.display());
47
48 Self {
49 mini_python,
50 include_dir,
51 include_flag,
52 lib_dir,
53 lib_path,
54 version,
55 package_source,
56 }
57 }
58
59 pub fn with_source(mut self, source: PackageSource) -> Self {
61 self.package_source = source;
62 self
63 }
64
65 pub fn validate(&self) -> Result<()> {
67 if !self.mini_python.exists() {
68 return Err(anyhow!(
69 "Mini-python executable not found: {}",
70 self.mini_python.display()
71 ));
72 }
73
74 if !self.mini_python.is_file() {
75 return Err(anyhow!(
76 "Mini-python path is not a file: {}",
77 self.mini_python.display()
78 ));
79 }
80
81 if !self.include_dir.exists() {
82 return Err(anyhow!(
83 "Python include directory not found: {}",
84 self.include_dir.display()
85 ));
86 }
87
88 if !self.include_dir.is_dir() {
89 return Err(anyhow!(
90 "Python include path is not a directory: {}",
91 self.include_dir.display()
92 ));
93 }
94
95 if !self.lib_dir.exists() {
96 return Err(anyhow!(
97 "Python library directory not found: {}",
98 self.lib_dir.display()
99 ));
100 }
101
102 if !self.lib_dir.is_dir() {
103 return Err(anyhow!(
104 "Python library path is not a directory: {}",
105 self.lib_dir.display()
106 ));
107 }
108
109 if !self.lib_path.exists() {
110 return Err(anyhow!(
111 "Python library file not found: {}",
112 self.lib_path.display()
113 ));
114 }
115
116 if !self.lib_path.is_file() {
117 return Err(anyhow!(
118 "Python library path is not a file: {}",
119 self.lib_path.display()
120 ));
121 }
122
123 Ok(())
124 }
125
126 pub fn major_version_str(&self) -> String {
128 self.version.major.to_string()
129 }
130
131 pub fn minor_version_str(&self) -> String {
133 self.version.minor.to_string()
134 }
135
136 pub fn py_limited_api_define(&self) -> String {
138 format!("-DPy_LIMITED_API={}", self.version.py_limited_api_hex())
139 }
140
141 pub fn lib_filename(&self) -> Result<String> {
143 self.lib_path
144 .file_name()
145 .and_then(|name| name.to_str())
146 .map(|s| s.to_string())
147 .ok_or_else(|| {
148 anyhow!(
149 "Failed to get library filename from {}",
150 self.lib_path.display()
151 )
152 })
153 }
154}
155
156impl std::fmt::Display for PythonEnvironment {
157 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158 write!(
159 f,
160 "PythonEnvironment {{ version: {}, source: {:?}, mini_python: {}, include: {}, lib: {} }}",
161 self.version,
162 self.package_source,
163 self.mini_python.display(),
164 self.include_dir.display(),
165 self.lib_path.display()
166 )
167 }
168}