diff --git a/backend/src/api/backend.rs b/backend/src/api/backend.rs index cedb98d..1606b81 100644 --- a/backend/src/api/backend.rs +++ b/backend/src/api/backend.rs @@ -5,14 +5,13 @@ use crate::api::list::search; use crate::api::list::{get_build, okapi_add_operation_for_list_builds_}; use crate::api::list::{list_builds, okapi_add_operation_for_search_}; use crate::api::list::{okapi_add_operation_for_build_output_, stats}; -use crate::api::package::okapi_add_operation_for_get_package_; +use crate::api::package::okapi_add_operation_for_package_add_endpoint_; use crate::api::package::okapi_add_operation_for_package_del_; use crate::api::package::okapi_add_operation_for_package_list_; -use crate::api::package::okapi_add_operation_for_package_update_; -use crate::api::package::package_add; -use crate::api::package::{ - get_package, okapi_add_operation_for_package_add_, package_del, package_list, package_update, -}; +use crate::api::package::okapi_add_operation_for_package_update_endpoint_; +use crate::api::package::package_add_endpoint; +use crate::api::package::{get_package, package_del, package_list}; +use crate::api::package::{okapi_add_operation_for_get_package_, package_update_endpoint}; use crate::api::remove::okapi_add_operation_for_version_del_; use crate::api::remove::version_del; use rocket::Route; @@ -22,7 +21,7 @@ pub fn build_api() -> Vec { openapi_get_routes![ search, package_list, - package_add, + package_add_endpoint, package_del, version_del, build_output, @@ -30,6 +29,6 @@ pub fn build_api() -> Vec { stats, get_build, get_package, - package_update + package_update_endpoint ] } diff --git a/backend/src/api/package.rs b/backend/src/api/package.rs index 8afe672..78a609e 100644 --- a/backend/src/api/package.rs +++ b/backend/src/api/package.rs @@ -1,21 +1,19 @@ use crate::api::list::ListPackageModel; -use crate::aur::aur::get_info_by_name; use crate::builder::types::Action; use crate::db::migration::{JoinType, Order}; -use crate::db::prelude::{Packages, Versions}; +use crate::db::prelude::Packages; use crate::db::{packages, versions}; -use crate::repo::repo::remove_pkg; +use crate::package::add::package_add; +use crate::package::delete::package_delete; +use crate::package::update::package_update; use rocket::response::status::{BadRequest, NotFound}; use rocket::serde::json::Json; use rocket::serde::Deserialize; use rocket::{get, post, State}; use rocket_okapi::okapi::schemars; use rocket_okapi::{openapi, JsonSchema}; -use sea_orm::{ - ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, QueryOrder, QuerySelect, - RelationTrait, TransactionTrait, -}; -use sea_orm::{DatabaseConnection, Set}; +use sea_orm::DatabaseConnection; +use sea_orm::{ColumnTrait, EntityTrait, QueryFilter, QueryOrder, QuerySelect, RelationTrait}; use tokio::sync::broadcast::Sender; #[derive(Deserialize, JsonSchema)] @@ -26,75 +24,14 @@ pub struct AddBody { #[openapi(tag = "Packages")] #[post("/packages/add", data = "")] -pub async fn package_add( +pub async fn package_add_endpoint( db: &State, input: Json, tx: &State>, ) -> Result<(), BadRequest> { - let txn = db - .begin() + package_add(db, input.name.clone(), tx) .await - .map_err(|e| BadRequest(Some(e.to_string())))?; - - // remove leading and trailing whitespaces - let pkg_name = input.name.trim(); - - if let Some(..) = Packages::find() - .filter(packages::Column::Name.eq(pkg_name)) - .one(&txn) - .await - .map_err(|e| BadRequest(Some(e.to_string())))? - { - return Err(BadRequest(Some("Package already exists".to_string()))); - } - - let pkg = get_info_by_name(pkg_name) - .await - .map_err(|_| BadRequest(Some("couldn't download package metadata".to_string())))?; - - let mut new_package = packages::ActiveModel { - name: Set(pkg_name.to_string()), - status: Set(3), - latest_aur_version: Set(pkg.version.clone()), - ..Default::default() - }; - - let mut new_package = new_package - .clone() - .save(&txn) - .await - .map_err(|e| BadRequest(Some(e.to_string())))?; - - let new_version = versions::ActiveModel { - version: Set(pkg.version.clone()), - package_id: new_package.id.clone(), - ..Default::default() - }; - - let new_version = new_version - .clone() - .save(&txn) - .await - .map_err(|e| BadRequest(Some(e.to_string())))?; - - new_package.status = Set(3); - new_package.latest_version_id = Set(Some(new_version.id.clone().unwrap())); - new_package - .save(&txn) - .await - .map_err(|e| BadRequest(Some(e.to_string())))?; - - let _ = tx.send(Action::Build( - pkg.name, - pkg.version, - pkg.url_path.unwrap(), - new_version, - )); - - txn.commit() - .await - .map_err(|e| BadRequest(Some(e.to_string())))?; - Ok(()) + .map_err(|e| BadRequest(Some(e.to_string()))) } #[derive(Deserialize, JsonSchema)] @@ -105,64 +42,15 @@ pub struct UpdateBody { #[openapi(tag = "Packages")] #[post("/packages//update", data = "")] -pub async fn package_update( +pub async fn package_update_endpoint( db: &State, id: i32, input: Json, tx: &State>, ) -> Result<(), BadRequest> { - let db = db as &DatabaseConnection; - - let mut pkg_model: packages::ActiveModel = Packages::find_by_id(id) - .one(db) + package_update(db, id, input.force, tx) .await - .map_err(|e| BadRequest(Some(e.to_string())))? - .ok_or(BadRequest(Some("id not found".to_string())))? - .into(); - - let pkg = get_info_by_name(pkg_model.name.clone().unwrap().as_str()) - .await - .map_err(|_| BadRequest(Some("couldn't download package metadata".to_string())))?; - - let version_model = match Versions::find() - .filter(versions::Column::Version.eq(pkg.version.clone())) - .filter(versions::Column::PackageId.eq(pkg.id.clone())) - .one(db) - .await - .map_err(|e| BadRequest(Some(e.to_string())))? - { - None => { - let new_version = versions::ActiveModel { - version: Set(pkg.version.clone()), - package_id: Set(pkg_model.id.clone().unwrap()), - ..Default::default() - }; - - new_version.save(db).await.expect("TODO: panic message") - } - Some(p) => { - // todo add check if this version was successfully built - // if not allow build - if input.force { - p.into() - } else { - return Err(BadRequest(Some("Version already existing".to_string()))); - } - } - }; - - pkg_model.status = Set(3); - pkg_model.latest_version_id = Set(Some(version_model.id.clone().unwrap())); - pkg_model.save(db).await.expect("todo error message"); - - let _ = tx.send(Action::Build( - pkg.name, - pkg.version, - pkg.url_path.unwrap(), - version_model, - )); - - Ok(()) + .map_err(|e| BadRequest(Some(e.to_string()))) } #[openapi(tag = "Packages")] @@ -170,7 +58,7 @@ pub async fn package_update( pub async fn package_del(db: &State, id: i32) -> Result<(), String> { let db = db as &DatabaseConnection; - remove_pkg(db, id).await.map_err(|e| e.to_string())?; + package_delete(db, id).await.map_err(|e| e.to_string())?; Ok(()) } diff --git a/backend/src/main.rs b/backend/src/main.rs index 3d9c655..ecbf2c6 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -2,6 +2,7 @@ mod api; mod aur; mod builder; mod db; +mod package; mod pkgbuild; mod repo; mod scheduler; diff --git a/backend/src/package/add.rs b/backend/src/package/add.rs new file mode 100644 index 0000000..b3eaf74 --- /dev/null +++ b/backend/src/package/add.rs @@ -0,0 +1,63 @@ +use crate::aur::aur::get_info_by_name; +use crate::builder::types::Action; +use crate::db::prelude::Packages; +use crate::db::{packages, versions}; +use anyhow::anyhow; +use rocket::State; +use sea_orm::ColumnTrait; +use sea_orm::QueryFilter; +use sea_orm::{ActiveModelTrait, DatabaseConnection, EntityTrait, Set, TransactionTrait}; +use tokio::sync::broadcast::Sender; + +pub async fn package_add( + db: &DatabaseConnection, + pkg_name: String, + tx: &State>, +) -> anyhow::Result<()> { + let txn = db.begin().await?; + + // remove leading and trailing whitespaces + let pkg_name = pkg_name.trim(); + + if let Some(..) = Packages::find() + .filter(packages::Column::Name.eq(pkg_name)) + .one(&txn) + .await? + { + return Err(anyhow!("Package already exists")); + } + + let pkg = get_info_by_name(pkg_name).await?; + + let new_package = packages::ActiveModel { + name: Set(pkg_name.to_string()), + status: Set(3), + latest_aur_version: Set(pkg.version.clone()), + ..Default::default() + }; + + let mut new_package = new_package.clone().save(&txn).await?; + + let new_version = versions::ActiveModel { + version: Set(pkg.version.clone()), + package_id: new_package.id.clone(), + ..Default::default() + }; + + let new_version = new_version.clone().save(&txn).await?; + + new_package.status = Set(3); + new_package.latest_version_id = Set(Some(new_version.id.clone().unwrap())); + new_package.save(&txn).await?; + + let _ = tx.send(Action::Build( + pkg.name, + pkg.version, + pkg.url_path.unwrap(), + new_version, + )); + + txn.commit().await?; + + Ok(()) +} diff --git a/backend/src/package/delete.rs b/backend/src/package/delete.rs new file mode 100644 index 0000000..507a5cb --- /dev/null +++ b/backend/src/package/delete.rs @@ -0,0 +1,45 @@ +use crate::db::prelude::{Builds, Packages, Versions}; +use crate::db::{builds, versions}; +use crate::repo::repo::rem_ver; +use anyhow::anyhow; +use sea_orm::ColumnTrait; +use sea_orm::QueryFilter; +use sea_orm::{DatabaseConnection, EntityTrait, ModelTrait, TransactionTrait}; +use std::fs; + +pub async fn package_delete(db: &DatabaseConnection, pkg_id: i32) -> anyhow::Result<()> { + let txn = db.begin().await?; + + let pkg = Packages::find_by_id(pkg_id) + .one(&txn) + .await? + .ok_or(anyhow!("id not found"))?; + + // remove build dir if available + let _ = fs::remove_dir_all(format!("./builds/{}", pkg.name)); + + // remove package db entry + pkg.clone().delete(&txn).await?; + + let versions = Versions::find() + .filter(versions::Column::PackageId.eq(pkg.id)) + .all(&txn) + .await?; + + for v in versions { + rem_ver(&txn, v).await?; + } + + // remove corresponding builds + let builds = Builds::find() + .filter(builds::Column::PkgId.eq(pkg.id)) + .all(&txn) + .await?; + for b in builds { + b.delete(&txn).await?; + } + + txn.commit().await?; + + Ok(()) +} diff --git a/backend/src/package/mod.rs b/backend/src/package/mod.rs new file mode 100644 index 0000000..097212a --- /dev/null +++ b/backend/src/package/mod.rs @@ -0,0 +1,3 @@ +pub mod add; +pub mod delete; +pub mod update; diff --git a/backend/src/package/update.rs b/backend/src/package/update.rs new file mode 100644 index 0000000..1fa6eec --- /dev/null +++ b/backend/src/package/update.rs @@ -0,0 +1,70 @@ +use crate::aur::aur::get_info_by_name; +use crate::builder::types::Action; +use crate::db::prelude::{Packages, Versions}; +use crate::db::{packages, versions}; +use anyhow::anyhow; +use rocket::State; +use sea_orm::ColumnTrait; +use sea_orm::QueryFilter; +use sea_orm::{ActiveModelTrait, DatabaseConnection, EntityTrait, Set, TransactionTrait}; +use tokio::sync::broadcast::Sender; + +pub async fn package_update( + db: &DatabaseConnection, + pkg_id: i32, + force: bool, + tx: &State>, +) -> anyhow::Result<()> { + let txn = db.begin().await?; + + let mut pkg_model: packages::ActiveModel = Packages::find_by_id(pkg_id) + .one(&txn) + .await? + .ok_or(anyhow!("id not found"))? + .into(); + + let pkg = get_info_by_name(pkg_model.name.clone().unwrap().as_str()) + .await + .map_err(|_| anyhow!("couldn't download package metadata".to_string()))?; + + let version_model = match Versions::find() + .filter(versions::Column::Version.eq(pkg.version.clone())) + .filter(versions::Column::PackageId.eq(pkg.id.clone())) + .one(&txn) + .await? + { + None => { + let new_version = versions::ActiveModel { + version: Set(pkg.version.clone()), + package_id: Set(pkg_model.id.clone().unwrap()), + ..Default::default() + }; + + new_version.save(&txn).await.expect("TODO: panic message") + } + Some(p) => { + // todo add check if this version was successfully built + // if not allow build + if force { + p.into() + } else { + return Err(anyhow!("Version already existing")); + } + } + }; + + pkg_model.status = Set(3); + pkg_model.latest_version_id = Set(Some(version_model.id.clone().unwrap())); + pkg_model.save(&txn).await.expect("todo error message"); + + let _ = tx.send(Action::Build( + pkg.name, + pkg.version, + pkg.url_path.unwrap(), + version_model, + )); + + txn.commit().await?; + + Ok(()) +} diff --git a/backend/src/repo/repo.rs b/backend/src/repo/repo.rs index 8805857..f822966 100644 --- a/backend/src/repo/repo.rs +++ b/backend/src/repo/repo.rs @@ -1,7 +1,7 @@ use crate::aur::aur::download_pkgbuild; +use crate::db::prelude::Packages; use crate::db::prelude::Versions; -use crate::db::prelude::{Builds, Packages}; -use crate::db::{builds, versions}; +use crate::db::versions; use crate::pkgbuild::build::build_pkgbuild; use anyhow::anyhow; use sea_orm::{ @@ -48,43 +48,6 @@ pub async fn add_pkg( Ok(firstpkgname) } -pub async fn remove_pkg(db: &DatabaseConnection, pkg_id: i32) -> anyhow::Result<()> { - let txn = db.begin().await?; - - let pkg = Packages::find_by_id(pkg_id) - .one(&txn) - .await? - .ok_or(anyhow!("id not found"))?; - - // remove build dir if available - let _ = fs::remove_dir_all(format!("./builds/{}", pkg.name)); - - // remove package db entry - pkg.clone().delete(&txn).await?; - - let versions = Versions::find() - .filter(versions::Column::PackageId.eq(pkg.id)) - .all(&txn) - .await?; - - for v in versions { - rem_ver(&txn, v).await?; - } - - // remove corresponding builds - let builds = Builds::find() - .filter(builds::Column::PkgId.eq(pkg.id)) - .all(&txn) - .await?; - for b in builds { - b.delete(&txn).await?; - } - - txn.commit().await?; - - Ok(()) -} - pub async fn remove_version(db: &DatabaseConnection, version_id: i32) -> anyhow::Result<()> { let txn = db.begin().await?; @@ -141,7 +104,10 @@ fn repo_remove(pkg_file_name: String) -> anyhow::Result<()> { Ok(()) } -async fn rem_ver(db: &DatabaseTransaction, version: versions::Model) -> anyhow::Result<()> { +pub(crate) async fn rem_ver( + db: &DatabaseTransaction, + version: versions::Model, +) -> anyhow::Result<()> { if let Some(filename) = version.file_name.clone() { // so repo-remove only supports passing a package name and removing the whole package // it seems that repo-add removes an older version when called