Commit

Author:

Hash:

Timestamp:

+38 -17 +/-2 browse

Kevin Schoon [me@kevinschoon.com]

60416b6080f72eb2e8083b154566cb76bb1e7ac3

Wed, 16 Apr 2025 14:47:48 +0000 (1 month ago)

add repository address
1diff --git a/src/address.rs b/src/address.rs
2index 88347a5..49fbe28 100644
3--- a/src/address.rs
4+++ b/src/address.rs
5 @@ -49,6 +49,9 @@ pub enum Address {
6 namespace: Namespace,
7 digest: Digest,
8 },
9+ Repository {
10+ namespace: Namespace,
11+ },
12 }
13
14 impl Display for Address {
15 @@ -131,6 +134,11 @@ impl Address {
16 .split("/")
17 .map(|part| part.to_string()),
18 ),
19+ Address::Repository { namespace } => Vec::from_iter(
20+ format!("repositories/{}", namespace)
21+ .split("/")
22+ .map(|part| part.to_string()),
23+ ),
24 }
25 }
26 }
27 @@ -140,10 +148,6 @@ impl FromStr for Address {
28
29 fn from_str(s: &str) -> Result<Self, Self::Err> {
30 let mut split: VecDeque<String> = s.split(SEPARATOR).map(|part| part.to_string()).collect();
31- let n_components = split.len();
32- if n_components < 3 {
33- return Err(crate::error::Error::UnparsableAddress(s.to_string()));
34- }
35 let first = split.pop_front().unwrap();
36 match first.as_str() {
37 "blobs" => {
38 @@ -170,7 +174,9 @@ impl FromStr for Address {
39 split.iter().cloned().collect::<Vec<String>>().as_slice(),
40 )?;
41 Ok(Address::Tag { namespace, name })
42- } else if split.get(split.len() - 2).is_some_and(|item| item == "tmp") {
43+ } else if split.len() > 2
44+ && split.get(split.len() - 2).is_some_and(|item| item == "tmp")
45+ {
46 // example: /hello/world/tmp/614f0a00-169e-4586-a6ed-cc52894130ae
47 let uuid = Uuid::from_str(&split.pop_back().unwrap())?;
48 split.pop_back();
49 @@ -178,9 +184,10 @@ impl FromStr for Address {
50 split.iter().cloned().collect::<Vec<String>>().as_slice(),
51 )?;
52 Ok(Address::TempBlob { uuid, namespace })
53- } else if split
54- .get(split.len() - 4)
55- .is_some_and(|item| item == "revisions")
56+ } else if split.len() > 4
57+ && split
58+ .get(split.len() - 4)
59+ .is_some_and(|item| item == "revisions")
60 {
61 // example: /hello/world/manifests/revisions/sha256/57f2ae062b76cff6f5a511fe6f907decfdefd6495e6afa31c44e0a6a1eca146f/link
62 let alogrithm = split.get(split.len() - 3).unwrap();
63 @@ -192,7 +199,10 @@ impl FromStr for Address {
64 )?;
65 Ok(Address::ManifestRevision { namespace, digest })
66 } else {
67- Err(crate::error::Error::UnparsableAddress(s.to_string()))
68+ let namespace = Namespace::try_from(
69+ split.iter().cloned().collect::<Vec<String>>().as_slice(),
70+ )?;
71+ Ok(Address::Repository { namespace })
72 }
73 }
74 _ => Err(crate::error::Error::UnparsableAddress(s.to_string())),
75 @@ -265,14 +275,24 @@ mod test {
76 },
77 "repositories/hello/world/manifests/revisions/sha256/57f2ae062b76cff6f5a511fe6f907decfdefd6495e6afa31c44e0a6a1eca146f/link",
78 );
79-
80- ["repositories/hello/world/fuu/bar/tags", "repositories/hello/world///fuu/bar/tags"]
81- .iter()
82- .for_each(|item| {
83- if let Err(err) = Address::from_str(item) {
84- panic!("Cannot parse {}, got: {}", item, err)
85- }
86- });
87+ check_address(
88+ &Address::Repository {
89+ namespace: namespace.clone(),
90+ },
91+ "repositories/hello/world",
92+ );
93+ [
94+ "repositories/hello/world/fuu/bar/tags",
95+ "repositories/hello/world///fuu/bar/tags",
96+ "repositories/fuu/bar",
97+ "repositories/fuu",
98+ ]
99+ .iter()
100+ .for_each(|item| {
101+ if let Err(err) = Address::from_str(item) {
102+ panic!("Cannot parse {}, got: {}", item, err)
103+ }
104+ });
105
106 [
107 "repositories/tags",
108 diff --git a/src/axum/mod.rs b/src/axum/mod.rs
109index ab18274..b44f1c8 100644
110--- a/src/axum/mod.rs
111+++ b/src/axum/mod.rs
112 @@ -20,6 +20,7 @@ mod handlers_blob;
113 mod handlers_manifest;
114 mod handlers_tag;
115 mod paths;
116+
117 #[cfg(all(feature = "web", feature = "axum"))]
118 pub mod web;
119