|
1 | 1 | /*!
|
2 | 2 | # Handling of `PEP-440`
|
3 |
| -This library implements Pythons Package versioning system. |
| 3 | +This library implements Python's Package versioning system. |
4 | 4 |
|
5 | 5 | Read more at <https://peps.python.org/pep-0440/>
|
6 | 6 |
|
@@ -32,273 +32,18 @@ assert!(
|
32 | 32 | );
|
33 | 33 | ```
|
34 | 34 | */
|
35 |
| -use anyhow::Result; |
36 |
| -use serde::{Deserialize, Serialize}; |
37 |
| -use std::fmt; |
38 | 35 |
|
39 | 36 | #[macro_use]
|
40 | 37 | extern crate derivative;
|
41 | 38 |
|
42 | 39 | mod validator;
|
| 40 | +// Expose validate_440_version function |
43 | 41 | pub use validator::validate_440_version;
|
44 | 42 |
|
45 | 43 | /// Identifiers (i.e. the components of a version string)
|
| 44 | +// Expose Ids Module |
46 | 45 | pub mod ids;
|
47 |
| -use ids::{DevHead, PostHead, PostHeader, PreHeader, ReleaseHeader}; |
48 | 46 |
|
49 |
| -/// `PEP-440` Compliant versioning system |
50 |
| -/// |
51 |
| -//# This struct is sorted so that PartialOrd |
52 |
| -//# correctly interprets priority |
53 |
| -//# Lower == More important |
54 |
| -/// |
55 |
| -/// # Example Usage |
56 |
| -/// ``` |
57 |
| -///# use pyver::PackageVersion; |
58 |
| -/// let _ = PackageVersion::new("v1.0"); |
59 |
| -/// ``` |
60 |
| -#[derive(Derivative, Debug, Serialize, Deserialize)] |
61 |
| -#[derivative(PartialOrd, PartialEq)] |
62 |
| -pub struct PackageVersion { |
63 |
| - /// ## Original String |
64 |
| - /// Just holds the original string passed in when creating |
65 |
| - /// the `PackageVersion` as some formating data is lost |
66 |
| - /// when parsing the string |
67 |
| - #[derivative(PartialOrd = "ignore", PartialEq = "ignore")] |
68 |
| - pub original: String, |
69 |
| - |
70 |
| - /// ## `PEP-440` Local version identifier |
71 |
| - /// Local version sorting will have to be it's own issue |
72 |
| - /// since there are no limits to what a local version can be |
73 |
| - /// |
74 |
| - /// For those who can read regex here it is for the local version: |
75 |
| - /// `[a-z0-9]+(?:(?:[\-_.][a-z0-9]+)+)?` |
76 |
| - /// |
77 |
| - /// Here in Rulex: |
78 |
| - /// ```toml |
79 |
| - /// ['a'-'z' '0'-'9']+ |
80 |
| - /// ((["-" "_" "."] ['a'-'z' '0'-'9']+)+)? |
81 |
| - /// ``` |
82 |
| - #[derivative(PartialOrd = "ignore", PartialEq = "ignore")] |
83 |
| - pub local: Option<String>, |
84 |
| - |
85 |
| - /// ## `PEP-440` Developmental release identifier |
86 |
| - pub dev: Option<DevHead>, |
87 |
| - |
88 |
| - /// ## `PEP-440` Post-Release identifier |
89 |
| - pub post: Option<PostHeader>, |
90 |
| - |
91 |
| - /// ## `PEP-440` Pre-Release identifier |
92 |
| - pub pre: Option<PreHeader>, |
93 |
| - |
94 |
| - /// ## `PEP-440` Release number |
95 |
| - pub release: ReleaseHeader, |
96 |
| - |
97 |
| - /// ## `PEP-440` Version-Epoch |
98 |
| - pub epoch: Option<u32>, |
99 |
| -} |
100 |
| - |
101 |
| -impl PackageVersion { |
102 |
| - pub fn new(version: &str) -> Result<Self> { |
103 |
| - let version_match = validate_440_version(version)?; |
104 |
| - |
105 |
| - let epoch: Option<u32> = match version_match.name("epoch") { |
106 |
| - // Convert Epoch String to Epoch Number |
107 |
| - Some(v) => Some(v.as_str().parse::<u32>()?), |
108 |
| - None => None, |
109 |
| - }; |
110 |
| - |
111 |
| - let release: ReleaseHeader = match version_match.name("release") { |
112 |
| - Some(v) => { |
113 |
| - // Does Release String contain minor version |
114 |
| - if v.as_str().contains('.') { |
115 |
| - let split: Vec<&str> = v.as_str().split('.').into_iter().collect(); |
116 |
| - ReleaseHeader { |
117 |
| - major: split[0].parse::<u32>()?, |
118 |
| - minor: split[1].parse::<u32>()?, |
119 |
| - } |
120 |
| - } else { |
121 |
| - ReleaseHeader { |
122 |
| - major: v.as_str().parse::<u32>()?, |
123 |
| - minor: 0, |
124 |
| - } |
125 |
| - } |
126 |
| - } |
127 |
| - // There always has to be at least a major version |
128 |
| - None => anyhow::bail!("Failed to decode version {}", version), |
129 |
| - }; |
130 |
| - |
131 |
| - let pre: Option<PreHeader> = match version_match.name("pre") { |
132 |
| - Some(_) => { |
133 |
| - let pre_n = match version_match.name("pre_n") { |
134 |
| - Some(v) => Some(v.as_str().parse::<u32>()?), |
135 |
| - None => None, |
136 |
| - }; |
137 |
| - |
138 |
| - // Should be safe to unwrap since we already checked if pre has a value |
139 |
| - // since pre_n has to exist |
140 |
| - match version_match.name("pre_l").unwrap().as_str() { |
141 |
| - "alpha" => Some(PreHeader::Alpha(pre_n)), |
142 |
| - "a" => Some(PreHeader::Alpha(pre_n)), |
143 |
| - "beta" => Some(PreHeader::Beta(pre_n)), |
144 |
| - "b" => Some(PreHeader::Beta(pre_n)), |
145 |
| - "rc" => Some(PreHeader::ReleaseCandidate(pre_n)), |
146 |
| - "c" => Some(PreHeader::ReleaseCandidate(pre_n)), |
147 |
| - "preview" => Some(PreHeader::Preview(pre_n)), |
148 |
| - "pre" => Some(PreHeader::Preview(pre_n)), |
149 |
| - _ => None, |
150 |
| - } |
151 |
| - } |
152 |
| - None => None, |
153 |
| - }; |
154 |
| - |
155 |
| - let post: Option<PostHeader> = match version_match.name("post") { |
156 |
| - Some(_) => { |
157 |
| - let post_num: Option<u32> = match version_match.name("post_n1") { |
158 |
| - Some(v) => Some(v.as_str().parse::<u32>()?), |
159 |
| - None => match version_match.name("post_n2") { |
160 |
| - Some(v) => Some(v.as_str().parse::<u32>()?), |
161 |
| - _ => None, |
162 |
| - }, |
163 |
| - }; |
164 |
| - |
165 |
| - let post_head: Option<PostHead> = match version_match.name("post_l") { |
166 |
| - Some(v) => { |
167 |
| - match v.as_str() { |
168 |
| - "post" => Some(PostHead::Post), |
169 |
| - "rev" => Some(PostHead::Rev), |
170 |
| - "r" => Some(PostHead::Rev), |
171 |
| - // This branch Should be impossible (see regex-group post_l) |
172 |
| - _ => None, |
173 |
| - } |
174 |
| - } |
175 |
| - None => None, |
176 |
| - }; |
177 |
| - |
178 |
| - Some(PostHeader { |
179 |
| - post_head, |
180 |
| - post_num, |
181 |
| - }) |
182 |
| - } |
183 |
| - None => None, |
184 |
| - }; |
185 |
| - |
186 |
| - let dev: Option<DevHead> = match version_match.name("dev") { |
187 |
| - Some(_) => { |
188 |
| - let dev_num = match version_match.name("dev_n") { |
189 |
| - Some(v) => Some(v.as_str().parse::<u32>()?), |
190 |
| - None => None, |
191 |
| - }; |
192 |
| - Some(DevHead { dev_num }) |
193 |
| - } |
194 |
| - None => None, |
195 |
| - }; |
196 |
| - |
197 |
| - let local: Option<String> = |
198 |
| - version_match.name("local").map(|v| v.as_str().to_string()); |
199 |
| - |
200 |
| - Ok(Self { |
201 |
| - original: version.to_string(), |
202 |
| - epoch, |
203 |
| - release, |
204 |
| - pre, |
205 |
| - post, |
206 |
| - dev, |
207 |
| - local, |
208 |
| - }) |
209 |
| - } |
210 |
| -} |
211 |
| - |
212 |
| -impl fmt::Display for PackageVersion { |
213 |
| - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
214 |
| - write!(f, "{}", self.original) |
215 |
| - } |
216 |
| -} |
217 |
| - |
218 |
| -#[cfg(test)] |
219 |
| -mod tests { |
220 |
| - use crate::PackageVersion; |
221 |
| - use anyhow::Result; |
222 |
| - |
223 |
| - #[test] |
224 |
| - fn test_pep440_ordering() -> Result<()> { |
225 |
| - assert!( |
226 |
| - PackageVersion::new( |
227 |
| - "v1!1.0-preview-921.post-516.dev-241+yeah.this.is.the.problem.with.local.versions", |
228 |
| - )? |
229 |
| - > |
230 |
| - PackageVersion::new("1.0")? |
231 |
| - ); |
232 |
| - Ok(()) |
233 |
| - } |
234 |
| - |
235 |
| - #[test] |
236 |
| - fn test_pep440_equality() -> Result<()> { |
237 |
| - assert_eq!( |
238 |
| - PackageVersion::new("1.0a1")?, |
239 |
| - PackageVersion::new("1.0alpha1")? |
240 |
| - ); |
241 |
| - assert_eq!( |
242 |
| - PackageVersion::new("1.0b")?, |
243 |
| - PackageVersion::new("1.0beta")? |
244 |
| - ); |
245 |
| - assert_eq!(PackageVersion::new("1.0r")?, PackageVersion::new("1.0rev")?); |
246 |
| - assert_eq!(PackageVersion::new("1.0c")?, PackageVersion::new("1.0rc")?); |
247 |
| - assert_eq!(PackageVersion::new("v1.0")?, PackageVersion::new("1.0")?); |
248 |
| - Ok(()) |
249 |
| - } |
250 |
| - |
251 |
| - #[test] |
252 |
| - fn test_pep440() { |
253 |
| - // list of every example mentioned in pep-440 |
254 |
| - let versions = vec![ |
255 |
| - "1.0", |
256 |
| - "v1.1", |
257 |
| - "2.0", |
258 |
| - "2013.10", |
259 |
| - "2014.04", |
260 |
| - "1!1.0", |
261 |
| - "1!1.1", |
262 |
| - "1!2.0", |
263 |
| - "2!1.0.pre0", |
264 |
| - "1.0.dev456", |
265 |
| - "1.0a1", |
266 |
| - "1.0a2.dev456", |
267 |
| - "1.0a12.dev456", |
268 |
| - "1.0a12", |
269 |
| - "1.0b1.dev456", |
270 |
| - "1.0b2", |
271 |
| - "1.0b2.post345.dev456", |
272 |
| - "1.0b2.post345", |
273 |
| - "1.0rc1.dev456", |
274 |
| - "1.0rc1", |
275 |
| - "1.0", |
276 |
| - "1.0+abc.5", |
277 |
| - "1.0+abc.7", |
278 |
| - "1.0+5", |
279 |
| - "1.0.post456.dev34", |
280 |
| - "1.0.post456", |
281 |
| - "1.0.15", |
282 |
| - "1.1.dev1", |
283 |
| - ]; |
284 |
| - |
285 |
| - for version in versions { |
286 |
| - match PackageVersion::new(version) { |
287 |
| - Ok(_v) => continue, |
288 |
| - Err(e) => panic!("Oh no {}", e), |
289 |
| - } |
290 |
| - } |
291 |
| - } |
292 |
| - |
293 |
| - #[test] |
294 |
| - fn test_pep440_negative() { |
295 |
| - let versions = vec!["not a version"]; |
296 |
| - |
297 |
| - for version in versions { |
298 |
| - match PackageVersion::new(version) { |
299 |
| - Ok(v) => panic!("Oh no {}", v), |
300 |
| - Err(_e) => continue, |
301 |
| - } |
302 |
| - } |
303 |
| - } |
304 |
| -} |
| 47 | +mod version; |
| 48 | +// Expose PackageVersion Struct |
| 49 | +pub use version::PackageVersion; |
0 commit comments