Skip to content

Commit

Permalink
fix oci cache name splitting
Browse files Browse the repository at this point in the history
  • Loading branch information
wolfv committed Mar 6, 2024
1 parent 46aa8c0 commit 8db3a23
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 32 deletions.
1 change: 1 addition & 0 deletions crates/rattler_networking/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ async-trait = { workspace = true }
base64 = { workspace = true }
dirs = { workspace = true }
fslock = { workspace = true }
http = "1.1.0"
itertools = { workspace = true }
keyring = { workspace = true }
lazy_static = { workspace = true }
Expand Down
109 changes: 77 additions & 32 deletions crates/rattler_networking/src/mirror_middleware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,22 +171,68 @@ fn oci_url_with_hash(url: &Url, hash: &str) -> Url {
.unwrap()
}

#[derive(Debug)]
struct OciTagMediaType {
url: Url,
tag: String,
media_type: String,
}

#[allow(dead_code)]
fn reverse_version_build_tag(tag: &str) -> String {
tag.replace("__p__", "+")
.replace("__e__", "!")
.replace("__eq__", "=")
}

fn version_build_tag(tag: &str) -> String {
tag.replace("+", "__p__")
.replace("!", "__e__")
.replace("=", "__eq__")
}

/// We reimplement some logic from rattler here because we don't want to introduce cyclic dependencies
fn package_to_tag(url: &Url) -> (Url, String) {
fn package_to_tag(url: &Url) -> OciTagMediaType {
// get filename (last segment of path)
let filename = url.path_segments().unwrap().last().unwrap();
if let Some(archive_name) = filename
.strip_suffix(".conda")
.or(filename.strip_suffix(".tar.bz2"))
{
let parts = archive_name.splitn(3, '-').collect::<Vec<&str>>();
let name = parts[0];
let tag = format!("{}-{}", parts[1], parts[2]);
// TODO we need to adjust the tag for OCI compatibility
(url.join(name).unwrap(), tag)
} else {
(url.clone(), "latest".to_string())

let mut res = OciTagMediaType {
url: url.clone(),
tag: "latest".to_string(),
media_type: "".to_string(),
};

let mut computed_filename = filename.to_string();

if let Some(archive_name) = filename.strip_suffix(".conda") {
let parts = archive_name.rsplitn(3, '-').collect::<Vec<&str>>();
computed_filename = parts[2].to_string();
res.tag = version_build_tag(&format!("{}-{}", parts[1], parts[0]));
res.media_type = "application/vnd.conda.package.v2".to_string();
} else if let Some(archive_name) = filename.strip_suffix(".tar.bz2") {
let parts = archive_name.rsplitn(3, '-').collect::<Vec<&str>>();
computed_filename = parts[2].to_string();
res.tag = version_build_tag(&format!("{}-{}", parts[1], parts[0]));
res.media_type = "application/vnd.conda.package.v1".to_string();
} else if filename.starts_with("repodata.json") {
computed_filename = "repodata.json".to_string();
if filename == "repodata.json" {
res.media_type = "application/vnd.conda.repodata.v1+json".to_string();
} else if filename.ends_with(".gz") {
res.media_type = "application/vnd.conda.repodata.v1+json+gzip".to_string();
} else if filename.ends_with(".bz2") {
res.media_type = "application/vnd.conda.repodata.v1+json+bz2".to_string();
} else if filename.ends_with(".zst") {
res.media_type = "application/vnd.conda.repodata.v1+json+zst".to_string();
}
}

if computed_filename.starts_with("_") {
computed_filename = format!("zzz{computed_filename}");
}

res.url = url.join(&computed_filename).unwrap();
res
}

#[allow(dead_code)]
Expand Down Expand Up @@ -223,8 +269,9 @@ impl Middleware for OciMiddleware {
return next.run(req, extensions).await;
}

let (url, tag) = package_to_tag(req.url());
let token = self.token_cache.lock().unwrap().get(&url).cloned();
let oci_info = package_to_tag(req.url());
let url = &oci_info.url;
let token = self.token_cache.lock().unwrap().get(url).cloned();

let token = if let Some(token) = token {
token
Expand Down Expand Up @@ -257,7 +304,7 @@ impl Middleware for OciMiddleware {
"https://{}/v2{}/manifests/{}",
url.host_str().unwrap(),
url.path(),
tag
&oci_info.tag
);

let manifest = reqwest::Client::new()
Expand All @@ -268,25 +315,23 @@ impl Middleware for OciMiddleware {
.await
.map_err(reqwest_middleware::Error::Reqwest)?;

let manifest_string = manifest.text().await.unwrap();

let manifest_string = manifest.text().await?;
tracing::info!("{}", manifest_string);
let manifest: Manifest = serde_json::from_str(&manifest_string).unwrap();
let layer = if url.as_str().ends_with(".json") {
manifest
.layers
.iter()
.find(|l| {
l.media_type
.starts_with("application/vnd.conda.repodata.v1+json")
})
.unwrap()

tracing::info!("{:?}", oci_info);

let layer = if let Some(layer) = manifest
.layers
.iter()
.find(|l| l.media_type == oci_info.media_type)
{
layer
} else {
// find the layer with the correct media type
manifest
.layers
.iter()
.find(|l| l.media_type.starts_with("application/vnd.conda.package"))
.unwrap()
// TODO it would be much better to return a 404 here
return Err(reqwest_middleware::Error::Middleware(anyhow::anyhow!(
"No layer found with the expected media type".to_string()
)));
};

let layer_url = format!(
Expand Down

0 comments on commit 8db3a23

Please sign in to comment.