Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
167 lines
4.4 KiB
Rust
167 lines
4.4 KiB
Rust
#[derive(Clone, Default)]
|
|
pub struct Archive {}
|
|
|
|
use std::{
|
|
io::{Bytes, Cursor},
|
|
path::Path,
|
|
};
|
|
|
|
use anyhow::Context;
|
|
|
|
use super::file_reader::Files;
|
|
|
|
impl Archive {
|
|
pub fn new() -> Self {
|
|
Self {}
|
|
}
|
|
|
|
pub async fn create_archive(&self, prefix: &Path, files: Files) -> anyhow::Result<ArchiveFile> {
|
|
tracing::trace!("archiving files: {}", files.len());
|
|
|
|
let buffer = Vec::new();
|
|
let cursor = Cursor::new(buffer);
|
|
|
|
let mut tar_builder = tar::Builder::new(cursor);
|
|
|
|
for file in files {
|
|
let abs_file_path = file.path;
|
|
|
|
let mut fd = std::fs::File::open(&abs_file_path)?;
|
|
if let Some(rel) = file.relative {
|
|
tracing::trace!("archiving rel file: {}", rel.display());
|
|
tar_builder.append_file(&rel, &mut fd)?;
|
|
} else {
|
|
tracing::trace!("archiving file: {}", abs_file_path.display());
|
|
tar_builder.append_file(
|
|
abs_file_path
|
|
.strip_prefix(prefix)
|
|
.context("failed to strip prefix from path")?,
|
|
&mut fd,
|
|
)?;
|
|
}
|
|
}
|
|
|
|
tar_builder.finish()?;
|
|
|
|
let cursor = tar_builder.into_inner()?;
|
|
let buffer = cursor.into_inner();
|
|
|
|
Ok(buffer.into())
|
|
}
|
|
|
|
pub async fn unpack_archive(&self, archive: &ArchiveFile, dest: &Path) -> anyhow::Result<()> {
|
|
tracing::trace!("unpacking archive: {}", dest.display());
|
|
|
|
let cursor = Cursor::new(archive.content.clone());
|
|
let mut arc = tar::Archive::new(cursor);
|
|
|
|
arc.unpack(dest)?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
pub struct ArchiveFile {
|
|
pub content: Vec<u8>,
|
|
}
|
|
|
|
impl From<Vec<u8>> for ArchiveFile {
|
|
fn from(value: Vec<u8>) -> Self {
|
|
Self { content: value }
|
|
}
|
|
}
|
|
|
|
pub mod extensions {
|
|
|
|
use std::{env::temp_dir, path::PathBuf};
|
|
|
|
use async_trait::async_trait;
|
|
use tokio::io::AsyncWriteExt;
|
|
use uuid::Uuid;
|
|
|
|
use crate::app::SharedLocalApp;
|
|
use crate::{app::SharedApp, services::release_manager::models::ArtifactID};
|
|
|
|
use crate::services::file_store::FileStore;
|
|
|
|
use super::Archive;
|
|
use super::ArchiveFile;
|
|
|
|
pub trait ArchiveExt {
|
|
fn archive(&self) -> Archive;
|
|
}
|
|
|
|
impl ArchiveExt for SharedApp {
|
|
fn archive(&self) -> Archive {
|
|
Archive::new()
|
|
}
|
|
}
|
|
|
|
impl ArchiveExt for SharedLocalApp {
|
|
fn archive(&self) -> Archive {
|
|
Archive::new()
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
pub trait ArchiveUploadExt {
|
|
async fn upload_archive(
|
|
&self,
|
|
artifact_id: ArtifactID,
|
|
archive: ArchiveFile,
|
|
) -> anyhow::Result<()>;
|
|
}
|
|
|
|
#[async_trait]
|
|
impl ArchiveUploadExt for FileStore {
|
|
async fn upload_archive(
|
|
&self,
|
|
artifact_id: ArtifactID,
|
|
archive: ArchiveFile,
|
|
) -> anyhow::Result<()> {
|
|
tracing::trace!("uploading archive: {}", artifact_id.to_string());
|
|
let suffix = Uuid::new_v4();
|
|
let temp_root = temp_dir();
|
|
|
|
let archive_path = temp_root
|
|
.join("flux-releaser")
|
|
.join("archives")
|
|
.join(format!("{}-{}.tar", &artifact_id.to_string(), suffix));
|
|
|
|
let archive_file_guard = ArchiveFilePath(archive_path.clone());
|
|
|
|
tokio::fs::create_dir_all(archive_path.parent().unwrap()).await?;
|
|
|
|
{
|
|
let mut archive_file = tokio::fs::File::create(&archive_path).await?;
|
|
|
|
archive_file.write_all(&archive.content).await?;
|
|
archive_file.flush().await?;
|
|
}
|
|
|
|
self.upload_file(artifact_id, archive_path).await?;
|
|
|
|
drop(archive_file_guard);
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
pub struct ArchiveFilePath(PathBuf);
|
|
|
|
// make sure we delete the archive file when we're done with it, we don't want it sticking around longer than it needs to
|
|
impl Drop for ArchiveFilePath {
|
|
fn drop(&mut self) {
|
|
let file_path = self.0.clone();
|
|
tokio::spawn(async move {
|
|
if file_path.exists() {
|
|
tracing::trace!("deleting archive: {}", file_path.display());
|
|
if let Err(e) = tokio::fs::remove_file(&file_path).await {
|
|
tracing::error!("failed to delete archive: {}", e);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|