Compare commits
No commits in common. "513a760040513765225ff83f2b008555d61eafa6" and "ce7b5159e815ba6928c34583bf5aafe087e884c4" have entirely different histories.
513a760040
...
ce7b5159e8
|
|
@ -1660,7 +1660,6 @@ dependencies = [
|
|||
"futures",
|
||||
"http-body-util",
|
||||
"libarchive",
|
||||
"regex",
|
||||
"sea-orm",
|
||||
"sea-orm-migration",
|
||||
"serde",
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ clap = { version = "4.3.12", features = ["env", "derive"] }
|
|||
futures = "0.3.28"
|
||||
http-body-util = "0.1.1"
|
||||
libarchive = { path = "../libarchive" }
|
||||
regex = "1.10.4"
|
||||
sea-orm-migration = "0.12.1"
|
||||
serde = { version = "1.0.178", features = ["derive"] }
|
||||
sha256 = "1.1.4"
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@ use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
|||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
pub struct Cli {
|
||||
/// Directory where package archives will be stored
|
||||
#[arg(env = "RIETER_PKG_DIR")]
|
||||
pub pkg_dir: PathBuf,
|
||||
/// Directory where repository metadata & SQLite database is stored
|
||||
#[arg(env = "RIETER_DATA_DIR")]
|
||||
pub data_dir: PathBuf,
|
||||
|
|
@ -82,17 +85,16 @@ impl Cli {
|
|||
|
||||
let config = Config {
|
||||
data_dir: self.data_dir.clone(),
|
||||
repo_dir: self.data_dir.join("repos"),
|
||||
pkg_dir: self.pkg_dir.clone(),
|
||||
api_key: self.api_key.clone(),
|
||||
};
|
||||
let repo_manager = MetaRepoMgr::new(&self.data_dir.join("repos"));
|
||||
|
||||
let pkg_filename_re = regex::Regex::new(r"^([a-z0-9@_+][a-z0-9@_+-.]*)-((?:[0-9]+:)?[a-z0-9._]+-[0-9.]+)-([a-z0-9_]+)\.pkg\.tar\.([a-z0-9]+)$").unwrap();
|
||||
let repo_manager = MetaRepoMgr::new(&config.repo_dir, &self.pkg_dir);
|
||||
|
||||
let global = Global {
|
||||
config,
|
||||
repo_manager: Arc::new(RwLock::new(repo_manager)),
|
||||
db,
|
||||
pkg_filename_re,
|
||||
};
|
||||
|
||||
// build our application with a single route
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1
|
||||
|
||||
use chrono::NaiveDateTime;
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -18,7 +17,7 @@ pub struct Model {
|
|||
pub c_size: i64,
|
||||
pub description: Option<String>,
|
||||
pub url: Option<String>,
|
||||
pub build_date: NaiveDateTime,
|
||||
pub build_date: String,
|
||||
pub packager: Option<String>,
|
||||
pub pgp_sig: Option<String>,
|
||||
pub pgp_sig_size: Option<i64>,
|
||||
|
|
|
|||
|
|
@ -47,23 +47,13 @@ pub async fn by_fields(
|
|||
repo_id: i32,
|
||||
arch: &str,
|
||||
name: &str,
|
||||
version: Option<&str>,
|
||||
compression: Option<&str>,
|
||||
) -> Result<Option<package::Model>> {
|
||||
let mut query = Package::find()
|
||||
Package::find()
|
||||
.filter(package::Column::RepoId.eq(repo_id))
|
||||
.filter(package::Column::Name.eq(name))
|
||||
.filter(package::Column::Arch.eq(arch));
|
||||
|
||||
if let Some(version) = version {
|
||||
query = query.filter(package::Column::Version.eq(version));
|
||||
}
|
||||
|
||||
if let Some(compression) = compression {
|
||||
query = query.filter(package::Column::Compression.eq(compression));
|
||||
}
|
||||
|
||||
query.one(conn).await
|
||||
.filter(package::Column::Arch.eq(arch))
|
||||
.one(conn)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn delete_with_arch(conn: &DbConn, repo_id: i32, arch: &str) -> Result<DeleteResult> {
|
||||
|
|
@ -88,7 +78,7 @@ pub async fn insert(conn: &DbConn, repo_id: i32, pkg: crate::repo::package::Pack
|
|||
c_size: Set(info.csize),
|
||||
description: Set(info.description),
|
||||
url: Set(info.url),
|
||||
build_date: Set(info.build_date),
|
||||
build_date: Set(info.build_date.to_string()),
|
||||
packager: Set(info.packager),
|
||||
pgp_sig: Set(info.pgpsig),
|
||||
pgp_sig_size: Set(info.pgpsigsize),
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ use tokio::sync::RwLock;
|
|||
#[derive(Clone)]
|
||||
pub struct Config {
|
||||
data_dir: PathBuf,
|
||||
repo_dir: PathBuf,
|
||||
pkg_dir: PathBuf,
|
||||
api_key: String,
|
||||
}
|
||||
|
||||
|
|
@ -23,7 +25,6 @@ pub struct Global {
|
|||
config: Config,
|
||||
repo_manager: Arc<RwLock<MetaRepoMgr>>,
|
||||
db: sea_orm::DbConn,
|
||||
pkg_filename_re: regex::Regex,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use uuid::Uuid;
|
|||
|
||||
use futures::StreamExt;
|
||||
use tokio::io::AsyncRead;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
use super::archive;
|
||||
use super::package;
|
||||
|
|
@ -15,12 +16,14 @@ pub const ANY_ARCH: &'static str = "any";
|
|||
|
||||
pub struct MetaRepoMgr {
|
||||
repo_dir: PathBuf,
|
||||
pkg_dir: PathBuf,
|
||||
}
|
||||
|
||||
impl MetaRepoMgr {
|
||||
pub fn new<P: AsRef<Path>>(repo_dir: P) -> Self {
|
||||
pub fn new<P1: AsRef<Path>, P2: AsRef<Path>>(repo_dir: P1, pkg_dir: P2) -> Self {
|
||||
MetaRepoMgr {
|
||||
repo_dir: repo_dir.as_ref().to_path_buf(),
|
||||
pkg_dir: pkg_dir.as_ref().to_path_buf(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -61,14 +64,11 @@ impl MetaRepoMgr {
|
|||
|
||||
let repo = repo.unwrap();
|
||||
|
||||
let parent_dir = self.repo_dir.join(&repo.name);
|
||||
let parent_dir = self.repo_dir.join(&repo.name).join(arch);
|
||||
tokio::fs::create_dir_all(&parent_dir).await?;
|
||||
|
||||
let ar_db =
|
||||
archive::RepoArchiveWriter::open(parent_dir.join(format!("{}.db.tar.gz", arch)))
|
||||
.await?;
|
||||
let ar_files =
|
||||
archive::RepoArchiveWriter::open(parent_dir.join(format!("{}.files.tar.gz", arch)))
|
||||
archive::RepoArchiveWriter::open(parent_dir.join(format!("{}.db.tar.gz", repo.name)))
|
||||
.await?;
|
||||
|
||||
// Query all packages in the repo that have the given architecture or the "any"
|
||||
|
|
@ -79,12 +79,11 @@ impl MetaRepoMgr {
|
|||
.stream(conn)
|
||||
.await?;
|
||||
|
||||
// Create two temp file paths to write our entries to
|
||||
let uuid: uuid::fmt::Simple = Uuid::new_v4().into();
|
||||
let files_tmp_file_path = self.repo_dir.join(uuid.to_string());
|
||||
let files_tmp_file_path = self.pkg_dir.join(uuid.to_string());
|
||||
|
||||
let uuid: uuid::fmt::Simple = Uuid::new_v4().into();
|
||||
let desc_tmp_file_path = self.repo_dir.join(uuid.to_string());
|
||||
let desc_tmp_file_path = self.pkg_dir.join(uuid.to_string());
|
||||
|
||||
while let Some(pkg) = pkgs.next().await.transpose()? {
|
||||
let mut files_tmp_file = tokio::fs::File::create(&files_tmp_file_path).await?;
|
||||
|
|
@ -94,10 +93,6 @@ impl MetaRepoMgr {
|
|||
package::write_desc(conn, &mut desc_tmp_file, &pkg).await?;
|
||||
|
||||
let full_name = format!("{}-{}", pkg.name, pkg.version);
|
||||
|
||||
ar_db
|
||||
.add_entry(&full_name, &desc_tmp_file_path, true)
|
||||
.await?;
|
||||
ar_files
|
||||
.add_entry(&full_name, &desc_tmp_file_path, true)
|
||||
.await?;
|
||||
|
|
@ -106,11 +101,7 @@ impl MetaRepoMgr {
|
|||
.await?;
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
ar_db.close().await?;
|
||||
ar_files.close().await?;
|
||||
|
||||
tokio::fs::remove_file(desc_tmp_file_path).await?;
|
||||
tokio::fs::remove_file(files_tmp_file_path).await?;
|
||||
|
||||
Ok(())
|
||||
|
|
@ -126,6 +117,7 @@ impl MetaRepoMgr {
|
|||
|
||||
// Remove files from file system
|
||||
tokio::fs::remove_dir_all(self.repo_dir.join(repo)).await?;
|
||||
tokio::fs::remove_dir_all(self.pkg_dir.join(repo)).await?;
|
||||
|
||||
Ok(true)
|
||||
} else {
|
||||
|
|
@ -143,7 +135,7 @@ impl MetaRepoMgr {
|
|||
let repo = db::query::repo::by_name(conn, repo).await?;
|
||||
|
||||
if let Some(repo) = repo {
|
||||
let pkg = db::query::package::by_fields(conn, repo.id, arch, name, None, None).await?;
|
||||
let pkg = db::query::package::by_fields(conn, repo.id, arch, name).await?;
|
||||
|
||||
if let Some(pkg) = pkg {
|
||||
// Remove package from database
|
||||
|
|
@ -165,7 +157,7 @@ impl MetaRepoMgr {
|
|||
) -> crate::Result<()> {
|
||||
// Copy file contents to temporary path so libarchive can work with it
|
||||
let uuid: uuid::fmt::Simple = Uuid::new_v4().into();
|
||||
let path = self.repo_dir.join(uuid.to_string());
|
||||
let path = self.pkg_dir.join(uuid.to_string());
|
||||
let mut temp_file = tokio::fs::File::create(&path).await?;
|
||||
|
||||
tokio::io::copy(reader, &mut temp_file).await?;
|
||||
|
|
@ -188,21 +180,18 @@ impl MetaRepoMgr {
|
|||
};
|
||||
|
||||
// If the package already exists in the database, we remove it first
|
||||
let res = db::query::package::by_fields(
|
||||
conn,
|
||||
repo_id,
|
||||
&pkg.info.arch,
|
||||
&pkg.info.name,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
let res =
|
||||
db::query::package::by_fields(conn, repo_id, &pkg.info.arch, &pkg.info.name).await?;
|
||||
|
||||
if let Some(entry) = res {
|
||||
entry.delete(conn).await?;
|
||||
}
|
||||
|
||||
let dest_pkg_path = self.repo_dir.join(repo).join(pkg.file_name());
|
||||
let dest_pkg_path = self
|
||||
.pkg_dir
|
||||
.join(repo)
|
||||
.join(&pkg.info.arch)
|
||||
.join(pkg.file_name());
|
||||
|
||||
// Insert new package into database
|
||||
let arch = pkg.info.arch.clone();
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ use axum::routing::{delete, post};
|
|||
use axum::Router;
|
||||
use futures::TryStreamExt;
|
||||
use futures::{Stream, StreamExt};
|
||||
use regex::Regex;
|
||||
use sea_orm::ModelTrait;
|
||||
use std::sync::Arc;
|
||||
use tokio::{fs, io::AsyncWriteExt};
|
||||
|
|
@ -57,25 +56,52 @@ pub fn router(api_key: &str) -> Router<crate::Global> {
|
|||
/// is returned.
|
||||
async fn get_file(
|
||||
State(global): State<crate::Global>,
|
||||
Path((repo, arch, file_name)): Path<(String, String, String)>,
|
||||
Path((repo, arch, mut file_name)): Path<(String, String, String)>,
|
||||
req: Request<Body>,
|
||||
) -> crate::Result<impl IntoResponse> {
|
||||
let repo_dir = global.config.data_dir.join("repos").join(&repo);
|
||||
let repo_dir = global.config.repo_dir.join(&repo).join(&arch);
|
||||
let repo_exists = tokio::fs::try_exists(&repo_dir).await?;
|
||||
|
||||
let file_name =
|
||||
if file_name == format!("{}.db", repo) || file_name == format!("{}.db.tar.gz", repo) {
|
||||
format!("{}.db.tar.gz", arch)
|
||||
} else if file_name == format!("{}.files", repo)
|
||||
|| file_name == format!("{}.files.tar.gz", repo)
|
||||
{
|
||||
format!("{}.files.tar.gz", arch)
|
||||
} else {
|
||||
file_name
|
||||
let res = if DB_FILE_EXTS.iter().any(|ext| file_name.ends_with(ext)) {
|
||||
// Append tar extension to ensure we find the file
|
||||
if !file_name.ends_with(".tar.gz") {
|
||||
file_name.push_str(".tar.gz");
|
||||
};
|
||||
|
||||
Ok(ServeFile::new(repo_dir.join(file_name)).oneshot(req).await)
|
||||
if repo_exists {
|
||||
ServeFile::new(repo_dir.join(file_name)).oneshot(req).await
|
||||
} else {
|
||||
let path = global
|
||||
.config
|
||||
.repo_dir
|
||||
.join(repo)
|
||||
.join(manager::ANY_ARCH)
|
||||
.join(file_name);
|
||||
|
||||
ServeFile::new(path).oneshot(req).await
|
||||
}
|
||||
} else {
|
||||
let any_file = global
|
||||
.config
|
||||
.pkg_dir
|
||||
.join(repo)
|
||||
.join(manager::ANY_ARCH)
|
||||
.join(file_name);
|
||||
|
||||
if repo_exists {
|
||||
ServeDir::new(global.config.pkg_dir)
|
||||
.fallback(ServeFile::new(any_file))
|
||||
.oneshot(req)
|
||||
.await
|
||||
} else {
|
||||
ServeFile::new(any_file).oneshot(req).await
|
||||
}
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
#[axum::debug_handler]
|
||||
async fn post_package_archive(
|
||||
State(global): State<crate::Global>,
|
||||
Path(repo): Path<String>,
|
||||
|
|
@ -96,6 +122,7 @@ async fn post_package_archive(
|
|||
//tracing::info!("Added '{}' to repository '{}'", pkg.file_name(), repo);
|
||||
}
|
||||
|
||||
#[axum::debug_handler]
|
||||
async fn delete_repo(
|
||||
State(global): State<crate::Global>,
|
||||
Path(repo): Path<String>,
|
||||
|
|
@ -180,3 +207,11 @@ async fn delete_package(
|
|||
// Ok(StatusCode::NOT_FOUND)
|
||||
//}
|
||||
}
|
||||
|
||||
fn help_me_figure_this_out(_: impl Send) {}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn assert_my_handler_is_ok() {
|
||||
// This is the fun part: we need to call our handler, and *not* await it's Future.
|
||||
help_me_figure_this_out(delete_repo)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ impl From<Package> for package::ActiveModel {
|
|||
c_size: Set(info.csize),
|
||||
description: Set(info.description),
|
||||
url: Set(info.url),
|
||||
build_date: Set(info.build_date),
|
||||
build_date: Set(info.build_date.to_string()),
|
||||
packager: Set(info.packager),
|
||||
pgp_sig: Set(info.pgpsig),
|
||||
pgp_sig_size: Set(info.pgpsigsize),
|
||||
|
|
@ -359,12 +359,7 @@ pub async fn write_desc<W: AsyncWrite + std::marker::Unpin>(
|
|||
write_attribute(writer, "ARCH", &pkg.arch).await?;
|
||||
|
||||
// TODO build date
|
||||
write_attribute(
|
||||
writer,
|
||||
"BUILDDATE",
|
||||
&pkg.build_date.and_utc().timestamp().to_string(),
|
||||
)
|
||||
.await?;
|
||||
//write_attribute(writer, "BUILDDATE", &pkg.build_)
|
||||
|
||||
if let Some(ref packager) = pkg.packager {
|
||||
write_attribute(writer, "PACKAGER", packager).await?;
|
||||
|
|
|
|||
Loading…
Reference in New Issue