When fetching extensions from blob store, don't halt on invalid extensions. (#9241)

This fixes an error where we were failing to sync extensions from the
blob store because of the presence of one invalid extensions
(`gentle-dark`), which was missing the `authors` field in its manifest.

Release Notes:

- N/A

Co-authored-by: Marshall <marshall@zed.dev>
This commit is contained in:
Max Brunsfeld 2024-03-12 13:36:40 -07:00 committed by GitHub
parent 05dfe96f0c
commit 64219ba49f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -140,6 +140,8 @@ async fn fetch_extensions_from_blob_store(
blob_store_bucket: &String, blob_store_bucket: &String,
app_state: &Arc<AppState>, app_state: &Arc<AppState>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
log::info!("fetching extensions from blob store");
let list = blob_store_client let list = blob_store_client
.list_objects() .list_objects()
.bucket(blob_store_bucket) .bucket(blob_store_bucket)
@ -164,10 +166,12 @@ async fn fetch_extensions_from_blob_store(
let Some(version) = parts.next() else { let Some(version) = parts.next() else {
continue; continue;
}; };
published_versions if parts.next() == Some("manifest.json") {
.entry(extension_id) published_versions
.or_default() .entry(extension_id)
.push(version); .or_default()
.push(version);
}
} }
let known_versions = app_state.db.get_known_extension_versions().await?; let known_versions = app_state.db.get_known_extension_versions().await?;
@ -182,46 +186,20 @@ async fn fetch_extensions_from_blob_store(
.binary_search_by_key(&published_version, String::as_str) .binary_search_by_key(&published_version, String::as_str)
.is_err() .is_err()
{ {
let object = blob_store_client if let Some(extension) = fetch_extension_manifest(
.get_object() blob_store_client,
.bucket(blob_store_bucket) blob_store_bucket,
.key(format!( extension_id,
"extensions/{extension_id}/{published_version}/manifest.json" published_version,
)) )
.send() .await
.await?; .log_err()
let manifest_bytes = object {
.body new_versions
.collect() .entry(extension_id)
.await .or_default()
.map(|data| data.into_bytes()) .push(extension);
.with_context(|| format!("failed to download manifest for extension {extension_id} version {published_version}"))? }
.to_vec();
let manifest = serde_json::from_slice::<ExtensionManifest>(&manifest_bytes)
.with_context(|| format!("invalid manifest for extension {extension_id} version {published_version}: {}", String::from_utf8_lossy(&manifest_bytes)))?;
let published_at = object.last_modified.ok_or_else(|| anyhow!("missing last modified timestamp for extension {extension_id} version {published_version}"))?;
let published_at =
time::OffsetDateTime::from_unix_timestamp_nanos(published_at.as_nanos())?;
let published_at = PrimitiveDateTime::new(published_at.date(), published_at.time());
let version = semver::Version::parse(&manifest.version).with_context(|| {
format!(
"invalid version for extension {extension_id} version {published_version}"
)
})?;
new_versions
.entry(extension_id)
.or_default()
.push(NewExtensionVersion {
name: manifest.name,
version,
description: manifest.description.unwrap_or_default(),
authors: manifest.authors,
repository: manifest.repository,
published_at,
});
} }
} }
} }
@ -231,5 +209,56 @@ async fn fetch_extensions_from_blob_store(
.insert_extension_versions(&new_versions) .insert_extension_versions(&new_versions)
.await?; .await?;
log::info!(
"fetched {} new extensions from blob store",
new_versions.values().map(|v| v.len()).sum::<usize>()
);
Ok(()) Ok(())
} }
async fn fetch_extension_manifest(
blob_store_client: &aws_sdk_s3::Client,
blob_store_bucket: &String,
extension_id: &str,
version: &str,
) -> Result<NewExtensionVersion, anyhow::Error> {
let object = blob_store_client
.get_object()
.bucket(blob_store_bucket)
.key(format!("extensions/{extension_id}/{version}/manifest.json"))
.send()
.await?;
let manifest_bytes = object
.body
.collect()
.await
.map(|data| data.into_bytes())
.with_context(|| {
format!("failed to download manifest for extension {extension_id} version {version}")
})?
.to_vec();
let manifest =
serde_json::from_slice::<ExtensionManifest>(&manifest_bytes).with_context(|| {
format!(
"invalid manifest for extension {extension_id} version {version}: {}",
String::from_utf8_lossy(&manifest_bytes)
)
})?;
let published_at = object.last_modified.ok_or_else(|| {
anyhow!("missing last modified timestamp for extension {extension_id} version {version}")
})?;
let published_at = time::OffsetDateTime::from_unix_timestamp_nanos(published_at.as_nanos())?;
let published_at = PrimitiveDateTime::new(published_at.date(), published_at.time());
let version = semver::Version::parse(&manifest.version).with_context(|| {
format!("invalid version for extension {extension_id} version {version}")
})?;
Ok(NewExtensionVersion {
name: manifest.name,
version,
description: manifest.description.unwrap_or_default(),
authors: manifest.authors,
repository: manifest.repository,
published_at,
})
}