c892dd0
use proto::kenshell::v1 as pb;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::rpcgit::archive::types::ArchiveFormat;
use crate::service::GitService;
use crate::service::rpc::{rpc_error, wait_job};
use crate::share::errors::GitError;
use crate::share::validate;
#[derive(Debug, Clone, Serialize, utoipa::ToSchema)]
pub struct ArchiveResultDto {
pub format: String,
pub size: i64,
pub cache_key: String,
pub download_url: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ArchiveOptionsDto {
pub format: ArchiveFormat,
#[serde(default)]
pub path_filter: Option<String>,
}
fn ext(format: ArchiveFormat) -> &'static str {
match format {
ArchiveFormat::Tar => "tar",
ArchiveFormat::TarGz => "tar.gz",
ArchiveFormat::TarBz2 => "tar.bz2",
ArchiveFormat::Zip => "zip",
}
}
fn archive_proto(format: ArchiveFormat) -> pb::ArchiveFormat {
match format {
ArchiveFormat::Tar => pb::ArchiveFormat::Tar,
ArchiveFormat::TarGz => pb::ArchiveFormat::TarGz,
ArchiveFormat::TarBz2 => pb::ArchiveFormat::TarBz2,
ArchiveFormat::Zip => pb::ArchiveFormat::Zip,
}
}
impl GitService {
pub async fn archive_create(
&self,
space_name: String,
repo_name: String,
revision: String,
opts: ArchiveOptionsDto,
) -> Result<ArchiveResultDto, GitError> {
validate::validate_revision(&revision)?;
let ctx = self.context(space_name, repo_name).await?;
let mut client = ctx.ks.archive();
let job = client
.start_archive(pb::StartArchiveRequest {
repository: Some(ctx.repository_ref()),
revision,
format: archive_proto(opts.format) as i32,
path_filters: opts.path_filter.into_iter().collect(),
actor: Some(ctx.actor()),
idempotency_key: Uuid::now_v7().to_string(),
})
.await
.map_err(rpc_error)?
.into_inner()
.job
.ok_or_else(|| GitError::Internal("archive job missing".into()))?;
let job = wait_job(&ctx.ks, &job.id, self.job_timeout()).await?;
let artifact = match job.result {
Some(pb::job::Result::Archive(archive)) => archive,
_ => {
return Err(GitError::Internal(
"archive job returned no artifact".into(),
));
}
};
Ok(ArchiveResultDto {
format: ext(opts.format).to_string(),
size: artifact.size_bytes as i64,
cache_key: artifact.storage_key,
download_url: Some(artifact.download_url),
})
}
pub async fn archive_download(
&self,
space_name: String,
repo_name: String,
revision: String,
opts: ArchiveOptionsDto,
) -> Result<ArchiveResultDto, GitError> {
validate::validate_revision(&revision)?;
let ctx = self.context(space_name, repo_name).await?;
let mut client = ctx.ks.archive();
let artifact = client
.get_archive_artifact(pb::GetArchiveArtifactRequest {
repository: Some(ctx.repository_ref()),
revision,
format: archive_proto(opts.format) as i32,
path_filters: opts.path_filter.into_iter().collect(),
})
.await
.map_err(rpc_error)?
.into_inner()
.artifact
.ok_or(GitError::NotFound)?;
Ok(ArchiveResultDto {
format: ext(opts.format).to_string(),
size: artifact.size_bytes as i64,
cache_key: artifact.storage_key,
download_url: Some(artifact.download_url),
})
}
pub async fn archive_create_bundle(
&self,
space_name: String,
repo_name: String,
) -> Result<ArchiveResultDto, GitError> {
let ctx = self.context(space_name, repo_name).await?;
let mut client = ctx.ks.archive();
let job = client
.start_archive_bundle(pb::StartArchiveBundleRequest {
repository: Some(ctx.repository_ref()),
actor: Some(ctx.actor()),
idempotency_key: Uuid::now_v7().to_string(),
})
.await
.map_err(rpc_error)?
.into_inner()
.job
.ok_or_else(|| GitError::Internal("bundle job missing".into()))?;
let job = wait_job(&ctx.ks, &job.id, self.job_timeout()).await?;
let artifact = match job.result {
Some(pb::job::Result::Archive(archive)) => archive,
_ => {
return Err(GitError::Internal(
"archive job returned no artifact".into(),
));
}
};
Ok(ArchiveResultDto {
format: "bundle".to_string(),
size: artifact.size_bytes as i64,
cache_key: artifact.storage_key,
download_url: Some(artifact.download_url),
})
}
}