diff --git a/libarchive/src/archive.rs b/libarchive/src/archive.rs index d8f7086..97c9d0a 100644 --- a/libarchive/src/archive.rs +++ b/libarchive/src/archive.rs @@ -39,7 +39,7 @@ pub enum ReadFormat { Zip, } -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, Clone)] pub enum ReadFilter { All, Bzip2, diff --git a/libarchive/src/write/file.rs b/libarchive/src/write/file.rs index 9c7abe2..5d932f1 100644 --- a/libarchive/src/write/file.rs +++ b/libarchive/src/write/file.rs @@ -54,7 +54,7 @@ impl FileWriter { self.handle_mut(), &buf[written] as *const u8 as *const _, buf_len - written, - ) + ) } as isize; // Negative values signal errors diff --git a/server/src/api/mod.rs b/server/src/api/mod.rs index 011f008..abb67c3 100644 --- a/server/src/api/mod.rs +++ b/server/src/api/mod.rs @@ -6,11 +6,13 @@ use axum::Json; use axum::Router; use sea_orm::entity::EntityTrait; use sea_orm::query::QueryOrder; +use sea_orm::ModelTrait; use sea_orm::PaginatorTrait; use pagination::PaginatedResponse; use crate::db::entities::package; +use crate::db::entities::package_license; use crate::db::entities::repo; pub fn router() -> Router { @@ -18,6 +20,7 @@ pub fn router() -> Router { .route("/repos", get(get_repos)) .route("/repos/:id", get(get_single_repo)) .route("/packages", get(get_packages)) + .route("/packages/:id", get(get_single_package)) } async fn get_repos( @@ -57,3 +60,31 @@ async fn get_packages( Ok(Json(pagination.res(pkgs))) } + +#[derive(serde::Serialize)] +pub struct PackageRes { + #[serde(flatten)] + entry: package::Model, + licenses: Vec, +} + +async fn get_single_package( + State(global): State, + Path(id): Path, +) -> crate::Result> { + let entry = package::Entity::find_by_id(id) + .one(&global.db) + .await? + .ok_or(axum::http::StatusCode::NOT_FOUND)?; + let licenses = entry + .find_related(package_license::Entity) + .all(&global.db) + .await? + .iter() + .map(|e| e.value.clone()) + .collect(); + + let res = PackageRes { entry, licenses }; + + Ok(Json(res)) +} diff --git a/server/src/db/entities/mod.rs b/server/src/db/entities/mod.rs index e5ad810..828fec2 100644 --- a/server/src/db/entities/mod.rs +++ b/server/src/db/entities/mod.rs @@ -3,5 +3,10 @@ pub mod prelude; pub mod package; +pub mod package_conflicts; +pub mod package_depends; +pub mod package_group; pub mod package_license; +pub mod package_provides; +pub mod package_replaces; pub mod repo; diff --git a/server/src/db/entities/package.rs b/server/src/db/entities/package.rs index 86606bf..c34abb1 100644 --- a/server/src/db/entities/package.rs +++ b/server/src/db/entities/package.rs @@ -26,8 +26,18 @@ pub struct Model { #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { + #[sea_orm(has_many = "super::package_conflicts::Entity")] + PackageConflicts, + #[sea_orm(has_many = "super::package_depends::Entity")] + PackageDepends, + #[sea_orm(has_many = "super::package_group::Entity")] + PackageGroup, #[sea_orm(has_many = "super::package_license::Entity")] PackageLicense, + #[sea_orm(has_many = "super::package_provides::Entity")] + PackageProvides, + #[sea_orm(has_many = "super::package_replaces::Entity")] + PackageReplaces, #[sea_orm( belongs_to = "super::repo::Entity", from = "Column::RepoId", @@ -38,12 +48,42 @@ pub enum Relation { Repo, } +impl Related for Entity { + fn to() -> RelationDef { + Relation::PackageConflicts.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::PackageDepends.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::PackageGroup.def() + } +} + impl Related for Entity { fn to() -> RelationDef { Relation::PackageLicense.def() } } +impl Related for Entity { + fn to() -> RelationDef { + Relation::PackageProvides.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::PackageReplaces.def() + } +} + impl Related for Entity { fn to() -> RelationDef { Relation::Repo.def() diff --git a/server/src/db/entities/package_conflicts.rs b/server/src/db/entities/package_conflicts.rs new file mode 100644 index 0000000..e9e8ba8 --- /dev/null +++ b/server/src/db/entities/package_conflicts.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_conflicts")] +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/package_depends.rs b/server/src/db/entities/package_depends.rs new file mode 100644 index 0000000..b22f717 --- /dev/null +++ b/server/src/db/entities/package_depends.rs @@ -0,0 +1,35 @@ +//! `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_depends")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub package_id: i32, + #[sea_orm(primary_key, auto_increment = false)] + pub r#type: 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/package_group.rs b/server/src/db/entities/package_group.rs new file mode 100644 index 0000000..61e69f2 --- /dev/null +++ b/server/src/db/entities/package_group.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_group")] +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/package_provides.rs b/server/src/db/entities/package_provides.rs new file mode 100644 index 0000000..7fca6ee --- /dev/null +++ b/server/src/db/entities/package_provides.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_provides")] +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/package_replaces.rs b/server/src/db/entities/package_replaces.rs new file mode 100644 index 0000000..0946b2d --- /dev/null +++ b/server/src/db/entities/package_replaces.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_replaces")] +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 1f8176c..9eae171 100644 --- a/server/src/db/entities/prelude.rs +++ b/server/src/db/entities/prelude.rs @@ -1,5 +1,10 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 pub use super::package::Entity as Package; +pub use super::package_conflicts::Entity as PackageConflicts; +pub use super::package_depends::Entity as PackageDepends; +pub use super::package_group::Entity as PackageGroup; pub use super::package_license::Entity as PackageLicense; +pub use super::package_provides::Entity as PackageProvides; +pub use super::package_replaces::Entity as PackageReplaces; pub use super::repo::Entity as Repo; 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 df56657..aceae78 100644 --- a/server/src/db/migrator/m20230730_000001_create_repo_tables.rs +++ b/server/src/db/migrator/m20230730_000001_create_repo_tables.rs @@ -90,7 +90,152 @@ impl MigrationTrait for Migration { ) .to_owned(), ) - .await + .await?; + manager + .create_table( + Table::create() + .table(PackageGroup::Table) + .col(ColumnDef::new(PackageGroup::PackageId).integer().not_null()) + .col( + ColumnDef::new(PackageGroup::Value) + .string_len(255) + .not_null(), + ) + .primary_key( + Index::create() + .col(PackageGroup::PackageId) + .col(PackageGroup::Value), + ) + .foreign_key( + ForeignKey::create() + .name("fk-package_group-package_id") + .from(PackageGroup::Table, PackageGroup::PackageId) + .to(Package::Table, Package::Id) + .on_delete(ForeignKeyAction::Cascade), + ) + .to_owned(), + ) + .await?; + manager + .create_table( + Table::create() + .table(PackageReplaces::Table) + .col( + ColumnDef::new(PackageReplaces::PackageId) + .integer() + .not_null(), + ) + .col( + ColumnDef::new(PackageReplaces::Value) + .string_len(255) + .not_null(), + ) + .primary_key( + Index::create() + .col(PackageReplaces::PackageId) + .col(PackageReplaces::Value), + ) + .foreign_key( + ForeignKey::create() + .name("fk-package_replaces-package_id") + .from(PackageReplaces::Table, PackageReplaces::PackageId) + .to(Package::Table, Package::Id) + .on_delete(ForeignKeyAction::Cascade), + ) + .to_owned(), + ) + .await?; + manager + .create_table( + Table::create() + .table(PackageConflicts::Table) + .col( + ColumnDef::new(PackageConflicts::PackageId) + .integer() + .not_null(), + ) + .col( + ColumnDef::new(PackageConflicts::Value) + .string_len(255) + .not_null(), + ) + .primary_key( + Index::create() + .col(PackageConflicts::PackageId) + .col(PackageConflicts::Value), + ) + .foreign_key( + ForeignKey::create() + .name("fk-package_conflicts-package_id") + .from(PackageConflicts::Table, PackageConflicts::PackageId) + .to(Package::Table, Package::Id) + .on_delete(ForeignKeyAction::Cascade), + ) + .to_owned(), + ) + .await?; + manager + .create_table( + Table::create() + .table(PackageProvides::Table) + .col( + ColumnDef::new(PackageProvides::PackageId) + .integer() + .not_null(), + ) + .col( + ColumnDef::new(PackageProvides::Value) + .string_len(255) + .not_null(), + ) + .primary_key( + Index::create() + .col(PackageProvides::PackageId) + .col(PackageProvides::Value), + ) + .foreign_key( + ForeignKey::create() + .name("fk-package_provides-package_id") + .from(PackageProvides::Table, PackageProvides::PackageId) + .to(Package::Table, Package::Id) + .on_delete(ForeignKeyAction::Cascade), + ) + .to_owned(), + ) + .await?; + manager + .create_table( + Table::create() + .table(PackageDepends::Table) + .col( + ColumnDef::new(PackageDepends::PackageId) + .integer() + .not_null(), + ) + .col(ColumnDef::new(PackageDepends::Type).integer().not_null()) + .col( + ColumnDef::new(PackageDepends::Value) + .string_len(255) + .not_null(), + ) + .primary_key( + Index::create() + .col(PackageDepends::PackageId) + .col(PackageDepends::Type) + .col(PackageDepends::Value), + ) + .foreign_key( + ForeignKey::create() + .name("fk-package_depends-package_id") + .from(PackageDepends::Table, PackageDepends::PackageId) + .to(Package::Table, Package::Id) + .on_delete(ForeignKeyAction::Cascade), + ) + .to_owned(), + ) + .await?; + + Ok(()) } // Define how to rollback this migration: Drop the Bakery table. @@ -98,6 +243,21 @@ impl MigrationTrait for Migration { manager .drop_table(Table::drop().table(PackageLicense::Table).to_owned()) .await?; + manager + .drop_table(Table::drop().table(PackageGroup::Table).to_owned()) + .await?; + manager + .drop_table(Table::drop().table(PackageReplaces::Table).to_owned()) + .await?; + manager + .drop_table(Table::drop().table(PackageConflicts::Table).to_owned()) + .await?; + manager + .drop_table(Table::drop().table(PackageProvides::Table).to_owned()) + .await?; + manager + .drop_table(Table::drop().table(PackageDepends::Table).to_owned()) + .await?; manager .drop_table(Table::drop().table(Package::Table).to_owned()) .await?; @@ -141,3 +301,39 @@ pub enum PackageLicense { PackageId, Value, } + +#[derive(Iden)] +pub enum PackageGroup { + Table, + PackageId, + Value, +} + +#[derive(Iden)] +pub enum PackageReplaces { + Table, + PackageId, + Value, +} + +#[derive(Iden)] +pub enum PackageConflicts { + Table, + PackageId, + Value, +} + +#[derive(Iden)] +pub enum PackageProvides { + Table, + PackageId, + Value, +} + +#[derive(Iden)] +pub enum PackageDepends { + Table, + PackageId, + Type, + Value, +} diff --git a/server/src/repo/manager.rs b/server/src/repo/manager.rs index 5846b5d..c288f30 100644 --- a/server/src/repo/manager.rs +++ b/server/src/repo/manager.rs @@ -136,6 +136,10 @@ impl RepoGroupManager { /// Add a package to the given repo, returning to what architectures the package was added. pub fn add_pkg(&mut self, repo: &str, pkg: &Package) -> io::Result<()> { + // TODO + // * if arch is "any", check if package doesn't already exist for other architecture + // * if arch isn't "any", check if package doesn't already exist for "any" architecture + // We first remove any existing version of the package self.remove_pkg(repo, &pkg.info.arch, &pkg.info.name, false)?; diff --git a/server/src/repo/mod.rs b/server/src/repo/mod.rs index d300ffe..b2c2fec 100644 --- a/server/src/repo/mod.rs +++ b/server/src/repo/mod.rs @@ -5,7 +5,9 @@ pub use manager::RepoGroupManager; use std::path::PathBuf; -use crate::db::entities::{package as db_package, repo as db_repo}; +use crate::db::entities::{ + package as db_package, package_license as db_package_license, repo as db_repo, +}; use axum::body::Body; use axum::extract::{BodyStream, Path, State}; use axum::http::Request; @@ -159,10 +161,18 @@ async fn post_package_archive( } // Insert the package's data into the database - let mut model: db_package::ActiveModel = pkg.into(); + let mut model: db_package::ActiveModel = pkg.clone().into(); model.repo_id = sea_orm::Set(repo_id); - model.insert(&global.db).await?; + let pkg_entry = model.insert(&global.db).await?; + db_package_license::Entity::insert_many(pkg.info.licenses.iter().map(|s| { + db_package_license::ActiveModel { + package_id: sea_orm::Set(pkg_entry.id), + value: sea_orm::Set(s.to_string()), + } + })) + .exec(&global.db) + .await?; Ok(()) } diff --git a/server/src/repo/package.rs b/server/src/repo/package.rs index ddafbd9..18c69c3 100644 --- a/server/src/repo/package.rs +++ b/server/src/repo/package.rs @@ -11,7 +11,7 @@ use crate::db::entities::package; const IGNORED_FILES: [&str; 5] = [".BUILDINFO", ".INSTALL", ".MTREE", ".PKGINFO", ".CHANGELOG"]; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Package { pub path: PathBuf, pub info: PkgInfo, @@ -19,7 +19,7 @@ pub struct Package { pub compression: ReadFilter, } -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] pub struct PkgInfo { pub base: String, pub name: String,