mirror of
https://github.com/meilisearch/meilisearch.git
synced 2025-12-10 22:55:43 +00:00
195 lines
5.9 KiB
Rust
195 lines
5.9 KiB
Rust
use std::collections::BTreeMap;
|
|
use std::fmt::Display;
|
|
use std::path::PathBuf;
|
|
|
|
use anyhow::Context;
|
|
use cargo_metadata::semver::Version;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use super::Edition;
|
|
use crate::common::assets::{Asset, AssetFormat};
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
|
pub struct Release {
|
|
#[serde(default)]
|
|
pub edition: Edition,
|
|
pub version: Version,
|
|
}
|
|
|
|
impl Display for Release {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "v{}", self.version)?;
|
|
match self.edition {
|
|
Edition::Community => f.write_str(" Community Edition"),
|
|
Edition::Enterprise => f.write_str(" Enterprise Edition"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Release {
|
|
pub fn binary_path(&self, asset_folder: &str) -> anyhow::Result<PathBuf> {
|
|
let mut asset_folder: PathBuf = asset_folder
|
|
.parse()
|
|
.with_context(|| format!("parsing asset folder `{asset_folder}` as a path"))?;
|
|
asset_folder.push(self.local_filename()?);
|
|
Ok(asset_folder)
|
|
}
|
|
|
|
fn local_filename(&self) -> anyhow::Result<String> {
|
|
let version = &self.version;
|
|
let arch = get_arch()?;
|
|
let base = self.edition.binary_base();
|
|
|
|
Ok(format!("{base}-{version}-{arch}"))
|
|
}
|
|
|
|
fn remote_filename(&self) -> anyhow::Result<String> {
|
|
let arch = get_arch()?;
|
|
let base = self.edition.binary_base();
|
|
|
|
Ok(format!("{base}-{arch}"))
|
|
}
|
|
|
|
async fn fetch_sha256(&self) -> anyhow::Result<String> {
|
|
let version = &self.version;
|
|
let asset_name = self.remote_filename()?;
|
|
|
|
// If version is lower than 1.15 there is no point in trying to get the sha256, GitHub didn't support it
|
|
if *version < Version::parse("1.15.0")? {
|
|
anyhow::bail!("version is lower than 1.15, sha256 not available");
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
struct GithubReleaseAsset {
|
|
name: String,
|
|
digest: Option<String>,
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
struct GithubRelease {
|
|
assets: Vec<GithubReleaseAsset>,
|
|
}
|
|
|
|
let url = format!(
|
|
"https://api.github.com/repos/meilisearch/meilisearch/releases/tags/v{version}"
|
|
);
|
|
|
|
let client = reqwest::Client::builder()
|
|
.user_agent("Meilisearch bench xtask")
|
|
.build()
|
|
.context("failed to build reqwest client")?;
|
|
let body = client.get(url).send().await?.text().await?;
|
|
let data: GithubRelease = serde_json::from_str(&body)?;
|
|
|
|
let digest = data
|
|
.assets
|
|
.into_iter()
|
|
.find(|asset| asset.name.as_str() == asset_name.as_str())
|
|
.with_context(|| format!("asset {asset_name} not found in release {self}"))?
|
|
.digest
|
|
.with_context(|| format!("asset {asset_name} has no digest"))?;
|
|
|
|
let sha256 = digest
|
|
.strip_prefix("sha256:")
|
|
.map(|s| s.to_string())
|
|
.context("invalid sha256 format")?;
|
|
|
|
Ok(sha256)
|
|
}
|
|
|
|
async fn add_asset(&self, assets: &mut BTreeMap<String, Asset>) -> anyhow::Result<()> {
|
|
let local_filename = self.local_filename()?;
|
|
let version = &self.version;
|
|
if assets.contains_key(&local_filename) {
|
|
return Ok(());
|
|
}
|
|
|
|
let remote_filename = self.remote_filename()?;
|
|
|
|
// Try to get the sha256 but it may fail if Github is rate limiting us
|
|
// We hardcode some values to speed up tests and avoid hitting Github
|
|
// Also, versions prior to 1.15 don't have sha256 available anyway
|
|
let sha256 = match local_filename.as_str() {
|
|
"meilisearch-1.12.0-macos-apple-silicon" => {
|
|
Some("3b384707a5df9edf66f9157f0ddb70dcd3ac84d4887149169cf93067d06717b7".into())
|
|
}
|
|
"meilisearch-1.12.0-linux-amd64" => {
|
|
Some("865a3fc222e3b3bd1f4b64346cb114b9669af691aae28d71fa68dbf39427abcf".into())
|
|
}
|
|
_ => match self.fetch_sha256().await {
|
|
Ok(sha256) => Some(sha256),
|
|
Err(err) => {
|
|
tracing::warn!("failed to get sha256 for release {self}: {err}");
|
|
None
|
|
}
|
|
},
|
|
};
|
|
|
|
let url = format!(
|
|
"https://github.com/meilisearch/meilisearch/releases/download/v{version}/{remote_filename}"
|
|
);
|
|
|
|
let asset = Asset {
|
|
local_location: Some(local_filename.clone()),
|
|
remote_location: Some(url),
|
|
format: AssetFormat::Raw,
|
|
sha256,
|
|
};
|
|
|
|
assets.insert(local_filename, asset);
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
pub fn get_arch() -> anyhow::Result<&'static str> {
|
|
// linux-aarch64
|
|
#[cfg(all(target_os = "linux", target_arch = "aarch64"))]
|
|
{
|
|
Ok("linux-aarch64")
|
|
}
|
|
|
|
// linux-amd64
|
|
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
|
|
{
|
|
Ok("linux-amd64")
|
|
}
|
|
|
|
// macos-amd64
|
|
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
|
|
{
|
|
Ok("macos-amd64")
|
|
}
|
|
|
|
// macos-apple-silicon
|
|
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
|
|
{
|
|
Ok("macos-apple-silicon")
|
|
}
|
|
|
|
// windows-amd64
|
|
#[cfg(all(target_os = "windows", target_arch = "x86_64"))]
|
|
{
|
|
Ok("windows-amd64")
|
|
}
|
|
|
|
#[cfg(not(all(target_os = "windows", target_arch = "x86_64")))]
|
|
#[cfg(not(all(target_os = "linux", target_arch = "aarch64")))]
|
|
#[cfg(not(all(target_os = "linux", target_arch = "x86_64")))]
|
|
#[cfg(not(all(target_os = "macos", target_arch = "aarch64")))]
|
|
#[cfg(not(all(target_os = "macos", target_arch = "x86_64")))]
|
|
anyhow::bail!("unsupported platform")
|
|
}
|
|
|
|
pub async fn add_releases_to_assets(
|
|
assets: &mut BTreeMap<String, Asset>,
|
|
releases: impl IntoIterator<Item = &Release>,
|
|
) -> anyhow::Result<()> {
|
|
for release in releases {
|
|
release.add_asset(assets).await?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|