use super::{IndexError, PackageIndex, PackageMeta, VersionMeta};
pub struct Go;
impl Go {
const GO_PROXY: &'static str = "https://proxy.golang.org";
const PKG_GO_DEV: &'static str = "https://pkg.go.dev";
}
impl PackageIndex for Go {
fn ecosystem(&self) -> &'static str {
"go"
}
fn display_name(&self) -> &'static str {
"Go Modules"
}
fn fetch(&self, name: &str) -> Result<PackageMeta, IndexError> {
let versions = self.fetch_versions(name)?;
let latest = versions
.first()
.ok_or_else(|| IndexError::NotFound(name.to_string()))?;
let repository = if name.starts_with("github.com/") {
Some(format!("https://{}", name))
} else if name.starts_with("golang.org/x/") {
let pkg_name = name.strip_prefix("golang.org/x/").unwrap_or(name);
Some(format!("https://github.com/golang/{}", pkg_name))
} else {
None
};
let info_url = format!("{}/{}/@v/{}.info", Self::GO_PROXY, name, latest.version);
let published = ureq::get(&info_url)
.call()
.ok()
.and_then(|r| r.into_json::<serde_json::Value>().ok())
.and_then(|v| v["Time"].as_str().map(String::from));
Ok(PackageMeta {
name: name.to_string(),
version: latest.version.clone(),
description: None, homepage: Some(format!("{}/{}", Self::PKG_GO_DEV, name)),
repository,
license: None, binaries: Vec::new(),
keywords: Vec::new(),
maintainers: Vec::new(),
published,
downloads: None, archive_url: Some(format!(
"{}/{}/@v/{}.zip",
Self::GO_PROXY,
name,
latest.version
)),
checksum: None, extra: Default::default(),
})
}
fn fetch_versions(&self, name: &str) -> Result<Vec<VersionMeta>, IndexError> {
let url = format!("{}/{}/@v/list", Self::GO_PROXY, name);
let response = ureq::get(&url).call()?.into_string()?;
let mut versions: Vec<VersionMeta> = response
.lines()
.filter(|line| !line.is_empty())
.map(|version| VersionMeta {
version: version.to_string(),
released: None,
yanked: false,
})
.collect();
versions.sort_by(|a, b| b.version.cmp(&a.version));
if versions.is_empty() {
return Err(IndexError::NotFound(name.to_string()));
}
Ok(versions)
}
fn search(&self, query: &str) -> Result<Vec<PackageMeta>, IndexError> {
Err(IndexError::Network(format!(
"Go module search not available via API. Visit: {}/search?q={}",
Self::PKG_GO_DEV,
query
)))
}
}