From 0ddf756536fdcfcc15eba72755e9480bddf46aba Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Tue, 1 Aug 2023 13:29:20 +0200 Subject: [PATCH 1/3] feat(server): start of package database schema --- server/Cargo.toml | 11 ++- server/src/api/mod.rs | 15 +++ server/src/cli.rs | 5 +- server/src/db/entities/mod.rs | 2 + server/src/db/entities/package.rs | 53 ++++++++++ server/src/db/entities/package_license.rs | 33 +++++++ server/src/db/entities/prelude.rs | 2 + server/src/db/entities/repo.rs | 16 ++- .../m20230730_000001_create_repo_tables.rs | 98 ++++++++++++++++++- 9 files changed, 229 insertions(+), 6 deletions(-) create mode 100644 server/src/db/entities/package.rs create mode 100644 server/src/db/entities/package_license.rs diff --git a/server/Cargo.toml b/server/Cargo.toml index aeb0f48..400b621 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -11,7 +11,6 @@ axum = { version = "0.6.18", features = ["http2"] } clap = { version = "4.3.12", features = ["env", "derive"] } futures = "0.3.28" libarchive = { path = "../libarchive" } -sea-orm = { version = "0.12.1", features = ["sqlx-sqlite", "runtime-tokio-rustls", "macros"] } sea-orm-migration = "0.12.1" serde = { version = "1.0.178", features = ["derive"] } sha256 = "1.1.4" @@ -22,3 +21,13 @@ tower-http = { version = "0.4.1", features = ["fs", "trace"] } tracing = "0.1.37" tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } uuid = { version = "1.4.0", features = ["v4"] } + +[dependencies.sea-orm] +version = "0.12.1" +features = [ + "sqlx-sqlite", + "sqlx-postgres", + "runtime-tokio-rustls", + "macros", + "with-chrono" +] diff --git a/server/src/api/mod.rs b/server/src/api/mod.rs index 91a1023..011f008 100644 --- a/server/src/api/mod.rs +++ b/server/src/api/mod.rs @@ -10,12 +10,14 @@ use sea_orm::PaginatorTrait; use pagination::PaginatedResponse; +use crate::db::entities::package; use crate::db::entities::repo; pub fn router() -> Router { Router::new() .route("/repos", get(get_repos)) .route("/repos/:id", get(get_single_repo)) + .route("/packages", get(get_packages)) } async fn get_repos( @@ -42,3 +44,16 @@ async fn get_single_repo( Ok(Json(repo)) } + +async fn get_packages( + State(global): State, + Query(pagination): Query, +) -> crate::Result>> { + let pkgs = package::Entity::find() + .order_by_asc(package::Column::Id) + .paginate(&global.db, pagination.per_page.unwrap_or(25)) + .fetch_page(pagination.page.unwrap_or(1) - 1) + .await?; + + Ok(Json(pagination.res(pkgs))) +} diff --git a/server/src/cli.rs b/server/src/cli.rs index 3ec7cd8..015dd1b 100644 --- a/server/src/cli.rs +++ b/server/src/cli.rs @@ -47,7 +47,10 @@ impl Cli { pub async fn run(&self) { self.init_tracing(); - let db = crate::db::init("sqlite://test.db").await.unwrap(); + // let db = crate::db::init("sqlite://test.db").await.unwrap(); + let db = crate::db::init("postgres://rieter:rieter@localhost:5432/rieter") + .await + .unwrap(); let config = Config { repo_dir: self.repo_dir.clone(), diff --git a/server/src/db/entities/mod.rs b/server/src/db/entities/mod.rs index f1e964a..e5ad810 100644 --- a/server/src/db/entities/mod.rs +++ b/server/src/db/entities/mod.rs @@ -2,4 +2,6 @@ pub mod prelude; +pub mod package; +pub mod package_license; pub mod repo; diff --git a/server/src/db/entities/package.rs b/server/src/db/entities/package.rs new file mode 100644 index 0000000..7920aac --- /dev/null +++ b/server/src/db/entities/package.rs @@ -0,0 +1,53 @@ +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 + +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)] +#[sea_orm(table_name = "package")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub repo_id: i32, + pub base: String, + pub name: String, + pub version: String, + pub arch: String, + pub size: i64, + pub c_size: i64, + pub description: Option, + pub url: Option, + pub build_date: Option, + pub packager: Option, + pub pgp_sig: Option, + pub pgp_sig_size: Option, + pub sha256_sum: String, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm(has_many = "super::package_license::Entity")] + PackageLicense, + #[sea_orm( + belongs_to = "super::repo::Entity", + from = "Column::RepoId", + to = "super::repo::Column::Id", + on_update = "NoAction", + on_delete = "Cascade" + )] + Repo, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::PackageLicense.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Repo.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/server/src/db/entities/package_license.rs b/server/src/db/entities/package_license.rs new file mode 100644 index 0000000..2920d3f --- /dev/null +++ b/server/src/db/entities/package_license.rs @@ -0,0 +1,33 @@ +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 + +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)] +#[sea_orm(table_name = "package_license")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub package_id: i32, + #[sea_orm(primary_key, auto_increment = false)] + pub value: String, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::package::Entity", + from = "Column::PackageId", + to = "super::package::Column::Id", + on_update = "NoAction", + on_delete = "Cascade" + )] + Package, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Package.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/server/src/db/entities/prelude.rs b/server/src/db/entities/prelude.rs index 8b651f8..1f8176c 100644 --- a/server/src/db/entities/prelude.rs +++ b/server/src/db/entities/prelude.rs @@ -1,3 +1,5 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 +pub use super::package::Entity as Package; +pub use super::package_license::Entity as PackageLicense; pub use super::repo::Entity as Repo; diff --git a/server/src/db/entities/repo.rs b/server/src/db/entities/repo.rs index 0676a76..b7a1af1 100644 --- a/server/src/db/entities/repo.rs +++ b/server/src/db/entities/repo.rs @@ -1,18 +1,28 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 use sea_orm::entity::prelude::*; -use serde::Serialize; +use serde::{Deserialize, Serialize}; -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize)] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)] #[sea_orm(table_name = "repo")] pub struct Model { #[sea_orm(primary_key)] pub id: i32, + #[sea_orm(unique)] pub name: String, pub description: Option, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation {} +pub enum Relation { + #[sea_orm(has_many = "super::package::Entity")] + Package, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Package.def() + } +} impl ActiveModelBehavior for ActiveModel {} diff --git a/server/src/db/migrator/m20230730_000001_create_repo_tables.rs b/server/src/db/migrator/m20230730_000001_create_repo_tables.rs index 4c36ade..5e6420a 100644 --- a/server/src/db/migrator/m20230730_000001_create_repo_tables.rs +++ b/server/src/db/migrator/m20230730_000001_create_repo_tables.rs @@ -10,7 +10,6 @@ impl MigrationName for Migration { #[async_trait::async_trait] impl MigrationTrait for Migration { - // Define how to apply this migration: Create the Bakery table. async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { manager .create_table( @@ -27,11 +26,81 @@ impl MigrationTrait for Migration { .col(ColumnDef::new(Repo::Description).string()) .to_owned(), ) + .await?; + manager + .create_table( + Table::create() + .table(Package::Table) + .col( + ColumnDef::new(Package::Id) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col(ColumnDef::new(Package::RepoId).integer().not_null()) + .col(ColumnDef::new(Package::Base).string_len(255).not_null()) + .col(ColumnDef::new(Package::Name).string_len(255).not_null()) + .col(ColumnDef::new(Package::Version).string_len(255).not_null()) + .col(ColumnDef::new(Package::Arch).string_len(255).not_null()) + .col(ColumnDef::new(Package::Size).big_integer().not_null()) + .col(ColumnDef::new(Package::CSize).big_integer().not_null()) + .col(ColumnDef::new(Package::Description).string()) + .col(ColumnDef::new(Package::Url).string_len(255)) + .col(ColumnDef::new(Package::BuildDate).date_time()) + .col(ColumnDef::new(Package::Packager).string_len(255)) + .col(ColumnDef::new(Package::PgpSig).string_len(255)) + .col(ColumnDef::new(Package::PgpSigSize).big_integer()) + .col(ColumnDef::new(Package::Sha256Sum).char_len(64).not_null()) + .foreign_key( + ForeignKey::create() + .name("fk-package-repo_id") + .from(Package::Table, Package::RepoId) + .to(Repo::Table, Repo::Id) + .on_delete(ForeignKeyAction::Cascade), + ) + .to_owned(), + ) + .await?; + manager + .create_table( + Table::create() + .table(PackageLicense::Table) + .col( + ColumnDef::new(PackageLicense::PackageId) + .integer() + .not_null(), + ) + .col( + ColumnDef::new(PackageLicense::Value) + .string_len(255) + .not_null(), + ) + .primary_key( + Index::create() + .col(PackageLicense::PackageId) + .col(PackageLicense::Value), + ) + .foreign_key( + ForeignKey::create() + .name("fk-package_license-package_id") + .from(PackageLicense::Table, PackageLicense::PackageId) + .to(Package::Table, Package::Id) + .on_delete(ForeignKeyAction::Cascade), + ) + .to_owned(), + ) .await } // Define how to rollback this migration: Drop the Bakery table. async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop().table(PackageLicense::Table).to_owned()) + .await?; + manager + .drop_table(Table::drop().table(Package::Table).to_owned()) + .await?; manager .drop_table(Table::drop().table(Repo::Table).to_owned()) .await @@ -45,3 +114,30 @@ pub enum Repo { Name, Description, } + +#[derive(Iden)] +pub enum Package { + Table, + Id, + RepoId, + Name, + Base, + Version, + Description, + Size, + CSize, + Url, + Arch, + BuildDate, + Packager, + PgpSig, + PgpSigSize, + Sha256Sum, +} + +#[derive(Iden)] +pub enum PackageLicense { + Table, + PackageId, + Value, +} From f8da62d7da6de74fb08010d193b29c2ea993c36d Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Tue, 1 Aug 2023 13:54:26 +0200 Subject: [PATCH 2/3] feat(server): improve package parse semantics --- Cargo.lock | 39 +++++++++--- server/Cargo.toml | 1 + .../m20230730_000001_create_repo_tables.rs | 2 +- server/src/repo/package.rs | 59 ++++++++++++------- 4 files changed, 69 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7e82ecd..d9c6efe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -407,8 +407,11 @@ checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" dependencies = [ "android-tzdata", "iana-time-zone", + "js-sys", "num-traits", "serde", + "time 0.1.45", + "wasm-bindgen", "winapi", ] @@ -774,7 +777,7 @@ checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] @@ -1194,7 +1197,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys", ] @@ -1624,6 +1627,7 @@ name = "rieterd" version = "0.1.0" dependencies = [ "axum", + "chrono", "clap", "futures", "libarchive", @@ -1834,7 +1838,7 @@ dependencies = [ "sqlx", "strum", "thiserror", - "time", + "time 0.3.23", "tracing", "url", "uuid", @@ -1902,7 +1906,7 @@ dependencies = [ "rust_decimal", "sea-query-derive", "serde_json", - "time", + "time 0.3.23", "uuid", ] @@ -1918,7 +1922,7 @@ dependencies = [ "sea-query", "serde_json", "sqlx", - "time", + "time 0.3.23", "uuid", ] @@ -2196,7 +2200,7 @@ dependencies = [ "smallvec", "sqlformat", "thiserror", - "time", + "time 0.3.23", "tokio", "tokio-stream", "tracing", @@ -2285,7 +2289,7 @@ dependencies = [ "sqlx-core", "stringprep", "thiserror", - "time", + "time 0.3.23", "tracing", "uuid", "whoami", @@ -2330,7 +2334,7 @@ dependencies = [ "sqlx-core", "stringprep", "thiserror", - "time", + "time 0.3.23", "tracing", "uuid", "whoami", @@ -2355,7 +2359,7 @@ dependencies = [ "percent-encoding", "serde", "sqlx-core", - "time", + "time 0.3.23", "tracing", "url", "uuid", @@ -2472,6 +2476,17 @@ dependencies = [ "once_cell", ] +[[package]] +name = "time" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + [[package]] name = "time" version = "0.3.23" @@ -2809,6 +2824,12 @@ dependencies = [ "try-lock", ] +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/server/Cargo.toml b/server/Cargo.toml index 400b621..c147eae 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -8,6 +8,7 @@ authors = ["Jef Roosens"] [dependencies] axum = { version = "0.6.18", features = ["http2"] } +chrono = { version = "0.4.26", features = ["serde"] } clap = { version = "4.3.12", features = ["env", "derive"] } futures = "0.3.28" libarchive = { path = "../libarchive" } diff --git a/server/src/db/migrator/m20230730_000001_create_repo_tables.rs b/server/src/db/migrator/m20230730_000001_create_repo_tables.rs index 5e6420a..df56657 100644 --- a/server/src/db/migrator/m20230730_000001_create_repo_tables.rs +++ b/server/src/db/migrator/m20230730_000001_create_repo_tables.rs @@ -47,7 +47,7 @@ impl MigrationTrait for Migration { .col(ColumnDef::new(Package::CSize).big_integer().not_null()) .col(ColumnDef::new(Package::Description).string()) .col(ColumnDef::new(Package::Url).string_len(255)) - .col(ColumnDef::new(Package::BuildDate).date_time()) + .col(ColumnDef::new(Package::BuildDate).date_time().not_null()) .col(ColumnDef::new(Package::Packager).string_len(255)) .col(ColumnDef::new(Package::PgpSig).string_len(255)) .col(ColumnDef::new(Package::PgpSigSize).big_integer()) diff --git a/server/src/repo/package.rs b/server/src/repo/package.rs index 4ff9433..6d8070b 100644 --- a/server/src/repo/package.rs +++ b/server/src/repo/package.rs @@ -1,3 +1,4 @@ +use chrono::NaiveDateTime; use libarchive::read::{Archive, Builder}; use libarchive::{Entry, ReadFilter}; use std::fmt; @@ -17,18 +18,18 @@ pub struct Package { #[derive(Debug, Default)] pub struct PkgInfo { - pub name: String, pub base: String, + pub name: String, pub version: String, - pub description: String, - pub size: u64, - pub csize: u64, - pub url: String, pub arch: String, - pub build_date: i64, - pub packager: String, - pub pgpsig: String, - pub pgpsigsize: i64, + pub description: Option, + pub size: i64, + pub csize: i64, + pub url: Option, + pub build_date: NaiveDateTime, + pub packager: Option, + pub pgpsig: Option, + pub pgpsigsize: Option, pub groups: Vec, pub licenses: Vec, pub replaces: Vec, @@ -70,23 +71,27 @@ impl PkgInfo { "pkgname" => self.name = value.to_string(), "pkgbase" => self.base = value.to_string(), "pkgver" => self.version = value.to_string(), - "pkgdesc" => self.description = value.to_string(), + "pkgdesc" => self.description = Some(value.to_string()), "size" => { self.size = value.parse().map_err(|_| ParsePkgInfoError::InvalidSize)? } - "url" => self.url = value.to_string(), + "url" => self.url = Some(value.to_string()), "arch" => self.arch = value.to_string(), "builddate" => { - self.build_date = value + let seconds: i64 = value .parse() - .map_err(|_| ParsePkgInfoError::InvalidBuildDate)? + .map_err(|_| ParsePkgInfoError::InvalidBuildDate)?; + self.build_date = NaiveDateTime::from_timestamp_millis(seconds * 1000) + .ok_or(ParsePkgInfoError::InvalidBuildDate)? } - "packager" => self.packager = value.to_string(), - "pgpsig" => self.pgpsig = value.to_string(), + "packager" => self.packager = Some(value.to_string()), + "pgpsig" => self.pgpsig = Some(value.to_string()), "pgpsigsize" => { - self.pgpsigsize = value - .parse() - .map_err(|_| ParsePkgInfoError::InvalidPgpSigSize)? + self.pgpsigsize = Some( + value + .parse() + .map_err(|_| ParsePkgInfoError::InvalidPgpSigSize)?, + ) } "group" => self.groups.push(value.to_string()), "license" => self.licenses.push(value.to_string()), @@ -156,7 +161,8 @@ impl Package { } if let Some(mut info) = info { - info.csize = fs::metadata(path.as_ref())?.len(); + // I'll take my chances on a file size fitting in an i64 + info.csize = fs::metadata(path.as_ref())?.len().try_into().unwrap(); Ok(Package { path: path.as_ref().to_path_buf(), @@ -216,7 +222,10 @@ impl Package { write("NAME", &info.name)?; write("BASE", &info.base)?; write("VERSION", &info.version)?; - write("DESC", &info.description)?; + + if let Some(ref description) = info.description { + write("DESC", description)?; + } write("GROUPS", &info.groups.join("\n"))?; write("CSIZE", &info.csize.to_string())?; write("ISIZE", &info.size.to_string())?; @@ -225,11 +234,17 @@ impl Package { write("SHA256SUM", checksum)?; } - write("URL", &info.url)?; + if let Some(ref url) = info.url { + write("URL", url)?; + } + write("LICENSE", &info.licenses.join("\n"))?; write("ARCH", &info.arch)?; write("BUILDDATE", &info.build_date.to_string())?; - write("PACKAGER", &info.packager)?; + + if let Some(ref packager) = info.packager { + write("PACKAGER", packager)?; + } write("REPLACES", &info.replaces.join("\n"))?; write("CONFLICTS", &info.conflicts.join("\n"))?; From b097a5ea877bb470244c388d627073e8302f9701 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Tue, 1 Aug 2023 14:38:50 +0200 Subject: [PATCH 3/3] feat(server): update database when publishing packages --- server/src/cli.rs | 8 +++--- server/src/db/entities/package.rs | 2 +- server/src/main.rs | 2 +- server/src/repo/manager.rs | 13 +++++++--- server/src/repo/mod.rs | 36 +++++++++++++++++++++++++-- server/src/repo/package.rs | 41 ++++++++++++++++++++++--------- 6 files changed, 79 insertions(+), 23 deletions(-) diff --git a/server/src/cli.rs b/server/src/cli.rs index 015dd1b..7fa1566 100644 --- a/server/src/cli.rs +++ b/server/src/cli.rs @@ -47,10 +47,10 @@ impl Cli { pub async fn run(&self) { self.init_tracing(); - // let db = crate::db::init("sqlite://test.db").await.unwrap(); - let db = crate::db::init("postgres://rieter:rieter@localhost:5432/rieter") - .await - .unwrap(); + let db = crate::db::init("sqlite://test.db").await.unwrap(); + // let db = crate::db::init("postgres://rieter:rieter@localhost:5432/rieter") + // .await + // .unwrap(); let config = Config { repo_dir: self.repo_dir.clone(), diff --git a/server/src/db/entities/package.rs b/server/src/db/entities/package.rs index 7920aac..86606bf 100644 --- a/server/src/db/entities/package.rs +++ b/server/src/db/entities/package.rs @@ -17,7 +17,7 @@ pub struct Model { pub c_size: i64, pub description: Option, pub url: Option, - pub build_date: Option, + pub build_date: DateTime, pub packager: Option, pub pgp_sig: Option, pub pgp_sig_size: Option, diff --git a/server/src/main.rs b/server/src/main.rs index a6d41b5..8217909 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,6 +1,6 @@ mod api; mod cli; -mod db; +pub mod db; mod error; mod repo; diff --git a/server/src/repo/manager.rs b/server/src/repo/manager.rs index df6ee17..d036aab 100644 --- a/server/src/repo/manager.rs +++ b/server/src/repo/manager.rs @@ -71,9 +71,12 @@ impl RepoGroupManager { ar_db.close().and(ar_files.close()).map_err(Into::into) } - pub fn add_pkg_from_path>(&mut self, repo: &str, path: P) -> io::Result<()> { - let mut pkg = Package::open(&path)?; - pkg.calculate_checksum()?; + pub fn add_pkg_from_path>( + &mut self, + repo: &str, + path: P, + ) -> io::Result { + let pkg = Package::open(&path)?; let archs = self.add_pkg_in_repo(repo, &pkg)?; @@ -87,7 +90,9 @@ impl RepoGroupManager { fs::hard_link(&path, dest_pkg_path)?; } - fs::remove_file(path) + fs::remove_file(path)?; + + Ok(pkg) } /// Add a package to the given repo, returning to what architectures the package was added. diff --git a/server/src/repo/mod.rs b/server/src/repo/mod.rs index 57ddd11..e4be526 100644 --- a/server/src/repo/mod.rs +++ b/server/src/repo/mod.rs @@ -3,11 +3,13 @@ mod package; pub use manager::RepoGroupManager; +use crate::db::entities::{package as db_package, repo as db_repo}; use axum::extract::{BodyStream, Path, State}; use axum::http::StatusCode; use axum::routing::{delete, get_service, post}; use axum::Router; use futures::StreamExt; +use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter}; use std::sync::Arc; use tokio::{fs, io::AsyncWriteExt}; use tower_http::services::ServeDir; @@ -43,8 +45,38 @@ async fn post_package_archive( } let clone = Arc::clone(&global.repo_manager); - tokio::task::spawn_blocking(move || clone.write().unwrap().add_pkg_from_path(&repo, &path)) - .await??; + + let repo_clone = repo.clone(); + let pkg = tokio::task::spawn_blocking(move || { + clone.write().unwrap().add_pkg_from_path(&repo_clone, &path) + }) + .await??; + + // Query the repo for its ID, or create it if it does not already exist + let repo_entity = db_repo::Entity::find() + .filter(db_repo::Column::Name.eq(&repo)) + .one(&global.db) + .await?; + + let repo_id = if let Some(repo_entity) = repo_entity { + repo_entity.id + } else { + let model = db_repo::ActiveModel { + name: sea_orm::Set(repo.clone()), + ..Default::default() + }; + + db_repo::Entity::insert(model) + .exec(&global.db) + .await? + .last_insert_id + }; + + // Insert the package's data into the database + let mut model: db_package::ActiveModel = pkg.into(); + model.repo_id = sea_orm::Set(repo_id); + + model.insert(&global.db).await?; Ok(()) } diff --git a/server/src/repo/package.rs b/server/src/repo/package.rs index 6d8070b..ddafbd9 100644 --- a/server/src/repo/package.rs +++ b/server/src/repo/package.rs @@ -1,11 +1,14 @@ use chrono::NaiveDateTime; use libarchive::read::{Archive, Builder}; use libarchive::{Entry, ReadFilter}; +use sea_orm::ActiveValue::Set; use std::fmt; use std::fs; use std::io::{self, BufRead, BufReader, BufWriter, Read, Write}; use std::path::{Path, PathBuf}; +use crate::db::entities::package; + const IGNORED_FILES: [&str; 5] = [".BUILDINFO", ".INSTALL", ".MTREE", ".PKGINFO", ".CHANGELOG"]; #[derive(Debug)] @@ -39,7 +42,7 @@ pub struct PkgInfo { pub optdepends: Vec, pub makedepends: Vec, pub checkdepends: Vec, - pub sha256sum: Option, + pub sha256sum: String, } #[derive(Debug, PartialEq, Eq)] @@ -163,6 +166,7 @@ impl Package { if let Some(mut info) = info { // I'll take my chances on a file size fitting in an i64 info.csize = fs::metadata(path.as_ref())?.len().try_into().unwrap(); + info.sha256sum = sha256::try_digest(path.as_ref())?; Ok(Package { path: path.as_ref().to_path_buf(), @@ -178,12 +182,6 @@ impl Package { } } - pub fn calculate_checksum(&mut self) -> io::Result<()> { - self.info.sha256sum = Some(sha256::try_digest(self.path.as_ref())?); - - Ok(()) - } - pub fn full_name(&self) -> String { format!( "{}-{}-{}", @@ -230,9 +228,7 @@ impl Package { write("CSIZE", &info.csize.to_string())?; write("ISIZE", &info.size.to_string())?; - if let Some(checksum) = &info.sha256sum { - write("SHA256SUM", checksum)?; - } + write("SHA256SUM", &info.sha256sum)?; if let Some(ref url) = info.url { write("URL", url)?; @@ -240,7 +236,7 @@ impl Package { write("LICENSE", &info.licenses.join("\n"))?; write("ARCH", &info.arch)?; - write("BUILDDATE", &info.build_date.to_string())?; + write("BUILDDATE", &info.build_date.timestamp().to_string())?; if let Some(ref packager) = info.packager { write("PACKAGER", packager)?; @@ -271,3 +267,26 @@ impl Package { Ok(()) } } + +impl From for package::ActiveModel { + fn from(pkg: Package) -> Self { + let info = pkg.info; + + package::ActiveModel { + base: Set(info.base), + name: Set(info.name), + version: Set(info.version), + arch: Set(info.arch), + size: Set(info.size), + c_size: Set(info.csize), + description: Set(info.description), + url: Set(info.url), + build_date: Set(info.build_date), + packager: Set(info.packager), + pgp_sig: Set(info.pgpsig), + pgp_sig_size: Set(info.pgpsigsize), + sha256_sum: Set(info.sha256sum), + ..Default::default() + } + } +}