outsource backend stuff
prepare makepkg command execution to store output in db and stdout
This commit is contained in:
		| @@ -1,4 +1,5 @@ | |||||||
| [package] | [package] | ||||||
|  | # todo rename to AURCentral | ||||||
| name = "untitled" | name = "untitled" | ||||||
| version = "0.1.0" | version = "0.1.0" | ||||||
| edition = "2021" | edition = "2021" | ||||||
|   | |||||||
							
								
								
									
										56
									
								
								src/api/add.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/api/add.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | |||||||
|  | use crate::aur::aur::get_info_by_name; | ||||||
|  | use crate::builder::types::Action; | ||||||
|  | use crate::db::{packages, versions}; | ||||||
|  | use rocket::serde::json::Json; | ||||||
|  | use rocket::serde::Deserialize; | ||||||
|  | use rocket::{post, State}; | ||||||
|  | use rocket_okapi::okapi::schemars; | ||||||
|  | use rocket_okapi::{openapi, JsonSchema}; | ||||||
|  | use sea_orm::ActiveModelTrait; | ||||||
|  | use sea_orm::{DatabaseConnection, Set}; | ||||||
|  | use tokio::sync::broadcast::Sender; | ||||||
|  |  | ||||||
|  | #[derive(Deserialize, JsonSchema)] | ||||||
|  | #[serde(crate = "rocket::serde")] | ||||||
|  | pub struct AddBody { | ||||||
|  |     name: String, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[openapi(tag = "test")] | ||||||
|  | #[post("/packages/add", data = "<input>")] | ||||||
|  | pub async fn package_add( | ||||||
|  |     db: &State<DatabaseConnection>, | ||||||
|  |     input: Json<AddBody>, | ||||||
|  |     tx: &State<Sender<Action>>, | ||||||
|  | ) -> Result<(), String> { | ||||||
|  |     let db = db as &DatabaseConnection; | ||||||
|  |     let pkg_name = &input.name; | ||||||
|  |  | ||||||
|  |     let pkg = get_info_by_name(pkg_name) | ||||||
|  |         .await | ||||||
|  |         .map_err(|_| "couldn't download package metadata".to_string())?; | ||||||
|  |  | ||||||
|  |     let new_package = packages::ActiveModel { | ||||||
|  |         name: Set(pkg_name.clone()), | ||||||
|  |         ..Default::default() | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     let pkt_model = new_package.save(db).await.expect("TODO: panic message"); | ||||||
|  |  | ||||||
|  |     let new_version = versions::ActiveModel { | ||||||
|  |         version: Set(pkg.version.clone()), | ||||||
|  |         package_id: Set(pkt_model.id.clone().unwrap()), | ||||||
|  |         ..Default::default() | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     let version_model = new_version.save(db).await.expect("TODO: panic message"); | ||||||
|  |  | ||||||
|  |     let _ = tx.send(Action::Build( | ||||||
|  |         pkg.name, | ||||||
|  |         pkg.version, | ||||||
|  |         pkg.url_path.unwrap(), | ||||||
|  |         version_model, | ||||||
|  |     )); | ||||||
|  |  | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
| @@ -1,147 +1,13 @@ | |||||||
| use crate::aur::aur::get_info_by_name; | use crate::api::add::okapi_add_operation_for_package_add_; | ||||||
| use crate::builder::types::Action; | use crate::api::add::package_add; | ||||||
| use crate::db::{packages, versions}; | use crate::api::list::okapi_add_operation_for_package_list_; | ||||||
| use crate::query_aur; | use crate::api::list::okapi_add_operation_for_search_; | ||||||
| use rocket::serde::json::Json; | use crate::api::list::{package_list, search}; | ||||||
| use rocket::serde::{Deserialize, Serialize}; | use crate::api::remove::okapi_add_operation_for_package_del_; | ||||||
| use rocket::State; | use crate::api::remove::okapi_add_operation_for_version_del_; | ||||||
| use rocket::{get, post, Route}; | use crate::api::remove::{package_del, version_del}; | ||||||
| use rocket_okapi::okapi::schemars; | use rocket::Route; | ||||||
| use rocket_okapi::{openapi, openapi_get_routes, JsonSchema}; | use rocket_okapi::openapi_get_routes; | ||||||
| use sea_orm::EntityTrait; |  | ||||||
| use sea_orm::{ActiveModelTrait, DatabaseConnection, FromQueryResult, JoinType, QuerySelect, Set}; |  | ||||||
| use sea_orm::{ColumnTrait, RelationTrait}; |  | ||||||
| use tokio::sync::broadcast::Sender; |  | ||||||
|  |  | ||||||
| use crate::db::prelude::Packages; |  | ||||||
| use crate::repo::repo::{remove_pkg, remove_version}; |  | ||||||
|  |  | ||||||
| #[derive(Serialize, JsonSchema)] |  | ||||||
| #[serde(crate = "rocket::serde")] |  | ||||||
| struct ApiPackage { |  | ||||||
|     name: String, |  | ||||||
|     version: String, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[openapi(tag = "test")] |  | ||||||
| #[get("/search?<query>")] |  | ||||||
| async fn search(query: &str) -> Result<Json<Vec<ApiPackage>>, String> { |  | ||||||
|     match query_aur(query).await { |  | ||||||
|         Ok(v) => { |  | ||||||
|             let mapped = v |  | ||||||
|                 .iter() |  | ||||||
|                 .map(|x| ApiPackage { |  | ||||||
|                     name: x.name.clone(), |  | ||||||
|                     version: x.version.clone(), |  | ||||||
|                 }) |  | ||||||
|                 .collect(); |  | ||||||
|             return Ok(Json(mapped)); |  | ||||||
|         } |  | ||||||
|         Err(e) => { |  | ||||||
|             return Err(format!("{}", e)); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[derive(FromQueryResult, Deserialize, JsonSchema, Serialize)] |  | ||||||
| #[serde(crate = "rocket::serde")] |  | ||||||
| struct ListPackageModel { |  | ||||||
|     name: String, |  | ||||||
|     count: i32, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[openapi(tag = "test")] |  | ||||||
| #[get("/packages/list")] |  | ||||||
| async fn package_list( |  | ||||||
|     db: &State<DatabaseConnection>, |  | ||||||
| ) -> Result<Json<Vec<ListPackageModel>>, String> { |  | ||||||
|     let db = db as &DatabaseConnection; |  | ||||||
|  |  | ||||||
|     let all: Vec<ListPackageModel> = Packages::find() |  | ||||||
|         .join_rev(JoinType::InnerJoin, versions::Relation::Packages.def()) |  | ||||||
|         .select_only() |  | ||||||
|         .column_as(versions::Column::Id.count(), "count") |  | ||||||
|         .column(packages::Column::Name) |  | ||||||
|         .group_by(packages::Column::Name) |  | ||||||
|         .into_model::<ListPackageModel>() |  | ||||||
|         .all(db) |  | ||||||
|         .await |  | ||||||
|         .unwrap(); |  | ||||||
|  |  | ||||||
|     Ok(Json(all)) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[derive(Deserialize, JsonSchema)] |  | ||||||
| #[serde(crate = "rocket::serde")] |  | ||||||
| struct AddBody { |  | ||||||
|     name: String, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[openapi(tag = "test")] |  | ||||||
| #[post("/packages/add", data = "<input>")] |  | ||||||
| async fn package_add( |  | ||||||
|     db: &State<DatabaseConnection>, |  | ||||||
|     input: Json<AddBody>, |  | ||||||
|     tx: &State<Sender<Action>>, |  | ||||||
| ) -> Result<(), String> { |  | ||||||
|     let db = db as &DatabaseConnection; |  | ||||||
|     let pkg_name = &input.name; |  | ||||||
|  |  | ||||||
|     let pkg = get_info_by_name(pkg_name) |  | ||||||
|         .await |  | ||||||
|         .map_err(|_| "couldn't download package metadata".to_string())?; |  | ||||||
|  |  | ||||||
|     let new_package = packages::ActiveModel { |  | ||||||
|         name: Set(pkg_name.clone()), |  | ||||||
|         ..Default::default() |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     let pkt_model = new_package.save(db).await.expect("TODO: panic message"); |  | ||||||
|  |  | ||||||
|     let new_version = versions::ActiveModel { |  | ||||||
|         version: Set(pkg.version.clone()), |  | ||||||
|         package_id: Set(pkt_model.id.clone().unwrap()), |  | ||||||
|         ..Default::default() |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     let version_model = new_version.save(db).await.expect("TODO: panic message"); |  | ||||||
|  |  | ||||||
|     let _ = tx.send(Action::Build( |  | ||||||
|         pkg.name, |  | ||||||
|         pkg.version, |  | ||||||
|         pkg.url_path.unwrap(), |  | ||||||
|         version_model, |  | ||||||
|     )); |  | ||||||
|  |  | ||||||
|     Ok(()) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[derive(Deserialize, JsonSchema)] |  | ||||||
| #[serde(crate = "rocket::serde")] |  | ||||||
| struct DelBody { |  | ||||||
|     id: i32, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[openapi(tag = "test")] |  | ||||||
| #[post("/packages/delete", data = "<input>")] |  | ||||||
| async fn package_del(db: &State<DatabaseConnection>, input: Json<DelBody>) -> Result<(), String> { |  | ||||||
|     let db = db as &DatabaseConnection; |  | ||||||
|     let pkg_id = input.id.clone(); |  | ||||||
|  |  | ||||||
|     remove_pkg(db, pkg_id).await.map_err(|e| e.to_string())?; |  | ||||||
|  |  | ||||||
|     Ok(()) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[openapi(tag = "test")] |  | ||||||
| #[post("/versions/delete/<id>")] |  | ||||||
| async fn version_del(db: &State<DatabaseConnection>, id: i32) -> Result<(), String> { |  | ||||||
|     let db = db as &DatabaseConnection; |  | ||||||
|  |  | ||||||
|     remove_version(db, id).await.map_err(|e| e.to_string())?; |  | ||||||
|  |  | ||||||
|     Ok(()) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| pub fn build_api() -> Vec<Route> { | pub fn build_api() -> Vec<Route> { | ||||||
|     openapi_get_routes![search, package_list, package_add, package_del, version_del] |     openapi_get_routes![search, package_list, package_add, package_del, version_del] | ||||||
|   | |||||||
							
								
								
									
										66
									
								
								src/api/list.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/api/list.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | |||||||
|  | use crate::aur::aur::query_aur; | ||||||
|  | use crate::db::migration::JoinType; | ||||||
|  | use crate::db::prelude::Packages; | ||||||
|  | use crate::db::{packages, versions}; | ||||||
|  | use rocket::serde::json::Json; | ||||||
|  | use rocket::serde::{Deserialize, Serialize}; | ||||||
|  | use rocket::{get, State}; | ||||||
|  | use rocket_okapi::okapi::schemars; | ||||||
|  | use rocket_okapi::{openapi, JsonSchema}; | ||||||
|  | use sea_orm::ColumnTrait; | ||||||
|  | use sea_orm::{DatabaseConnection, EntityTrait, FromQueryResult, QuerySelect, RelationTrait}; | ||||||
|  |  | ||||||
|  | #[derive(Serialize, JsonSchema)] | ||||||
|  | #[serde(crate = "rocket::serde")] | ||||||
|  | pub struct ApiPackage { | ||||||
|  |     name: String, | ||||||
|  |     version: String, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[openapi(tag = "test")] | ||||||
|  | #[get("/search?<query>")] | ||||||
|  | pub async fn search(query: &str) -> Result<Json<Vec<ApiPackage>>, String> { | ||||||
|  |     match query_aur(query).await { | ||||||
|  |         Ok(v) => { | ||||||
|  |             let mapped = v | ||||||
|  |                 .iter() | ||||||
|  |                 .map(|x| ApiPackage { | ||||||
|  |                     name: x.name.clone(), | ||||||
|  |                     version: x.version.clone(), | ||||||
|  |                 }) | ||||||
|  |                 .collect(); | ||||||
|  |             return Ok(Json(mapped)); | ||||||
|  |         } | ||||||
|  |         Err(e) => { | ||||||
|  |             return Err(format!("{}", e)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(FromQueryResult, Deserialize, JsonSchema, Serialize)] | ||||||
|  | #[serde(crate = "rocket::serde")] | ||||||
|  | pub struct ListPackageModel { | ||||||
|  |     name: String, | ||||||
|  |     count: i32, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[openapi(tag = "test")] | ||||||
|  | #[get("/packages/list")] | ||||||
|  | pub async fn package_list( | ||||||
|  |     db: &State<DatabaseConnection>, | ||||||
|  | ) -> Result<Json<Vec<ListPackageModel>>, String> { | ||||||
|  |     let db = db as &DatabaseConnection; | ||||||
|  |  | ||||||
|  |     let all: Vec<ListPackageModel> = Packages::find() | ||||||
|  |         .join_rev(JoinType::InnerJoin, versions::Relation::Packages.def()) | ||||||
|  |         .select_only() | ||||||
|  |         .column_as(versions::Column::Id.count(), "count") | ||||||
|  |         .column(packages::Column::Name) | ||||||
|  |         .group_by(packages::Column::Name) | ||||||
|  |         .into_model::<ListPackageModel>() | ||||||
|  |         .all(db) | ||||||
|  |         .await | ||||||
|  |         .unwrap(); | ||||||
|  |  | ||||||
|  |     Ok(Json(all)) | ||||||
|  | } | ||||||
| @@ -1 +1,4 @@ | |||||||
|  | mod add; | ||||||
| pub mod backend; | pub mod backend; | ||||||
|  | mod list; | ||||||
|  | mod remove; | ||||||
|   | |||||||
							
								
								
									
										37
									
								
								src/api/remove.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/api/remove.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | use crate::repo::repo::{remove_pkg, remove_version}; | ||||||
|  | use rocket::serde::json::Json; | ||||||
|  | use rocket::serde::Deserialize; | ||||||
|  | use rocket::{post, State}; | ||||||
|  | use rocket_okapi::okapi::schemars; | ||||||
|  | use rocket_okapi::{openapi, JsonSchema}; | ||||||
|  | use sea_orm::DatabaseConnection; | ||||||
|  |  | ||||||
|  | #[derive(Deserialize, JsonSchema)] | ||||||
|  | #[serde(crate = "rocket::serde")] | ||||||
|  | pub struct DelBody { | ||||||
|  |     id: i32, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[openapi(tag = "test")] | ||||||
|  | #[post("/packages/delete", data = "<input>")] | ||||||
|  | pub async fn package_del( | ||||||
|  |     db: &State<DatabaseConnection>, | ||||||
|  |     input: Json<DelBody>, | ||||||
|  | ) -> Result<(), String> { | ||||||
|  |     let db = db as &DatabaseConnection; | ||||||
|  |     let pkg_id = input.id.clone(); | ||||||
|  |  | ||||||
|  |     remove_pkg(db, pkg_id).await.map_err(|e| e.to_string())?; | ||||||
|  |  | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[openapi(tag = "test")] | ||||||
|  | #[post("/versions/delete/<id>")] | ||||||
|  | pub async fn version_del(db: &State<DatabaseConnection>, id: i32) -> Result<(), String> { | ||||||
|  |     let db = db as &DatabaseConnection; | ||||||
|  |  | ||||||
|  |     remove_version(db, id).await.map_err(|e| e.to_string())?; | ||||||
|  |  | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
| @@ -6,7 +6,6 @@ mod pkgbuild; | |||||||
| mod repo; | mod repo; | ||||||
|  |  | ||||||
| use crate::api::backend; | use crate::api::backend; | ||||||
| use crate::aur::aur::query_aur; |  | ||||||
| use crate::builder::types::Action; | use crate::builder::types::Action; | ||||||
| use crate::db::migration::Migrator; | use crate::db::migration::Migrator; | ||||||
| use rocket::config::Config; | use rocket::config::Config; | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| use anyhow::anyhow; | use anyhow::anyhow; | ||||||
| use std::fs; | use std::fs; | ||||||
| use std::process::{Command, Stdio}; | use std::io::{BufRead, BufReader}; | ||||||
|  | use std::process::Command; | ||||||
| use std::time::SystemTime; | use std::time::SystemTime; | ||||||
|  |  | ||||||
| pub fn build_pkgbuild( | pub fn build_pkgbuild( | ||||||
| @@ -14,7 +15,7 @@ pub fn build_pkgbuild( | |||||||
|     let script_file = std::env::temp_dir().join("makepkg_custom.sh"); |     let script_file = std::env::temp_dir().join("makepkg_custom.sh"); | ||||||
|     fs::write(&script_file, makepkg).expect("Unable to write script to file"); |     fs::write(&script_file, makepkg).expect("Unable to write script to file"); | ||||||
|  |  | ||||||
|     let output = Command::new("bash") |     let mut output = Command::new("bash") | ||||||
|         .args(&[ |         .args(&[ | ||||||
|             script_file.as_os_str().to_str().unwrap(), |             script_file.as_os_str().to_str().unwrap(), | ||||||
|             "-f", |             "-f", | ||||||
| @@ -23,20 +24,29 @@ pub fn build_pkgbuild( | |||||||
|             "-c", |             "-c", | ||||||
|         ]) |         ]) | ||||||
|         .current_dir(folder_path.clone()) |         .current_dir(folder_path.clone()) | ||||||
|         .stdout(Stdio::inherit()) |  | ||||||
|         .spawn() |         .spawn() | ||||||
|         .unwrap(); |         .unwrap(); | ||||||
|     let output = output.wait_with_output(); |  | ||||||
|  |  | ||||||
|     match output { |     if let Some(stdout) = output.stdout.take() { | ||||||
|         Ok(output) => { |         let reader = BufReader::new(stdout); | ||||||
|             if output.status.success() { |  | ||||||
|                 let stdout = String::from_utf8_lossy(&output.stdout); |  | ||||||
|                 println!("makepkg output: {}", stdout); |  | ||||||
|             } else { |  | ||||||
|                 let stderr = String::from_utf8_lossy(&output.stderr); |  | ||||||
|                 eprintln!("makepkg error: {}", stderr); |  | ||||||
|  |  | ||||||
|  |         // Iterate through each line of output | ||||||
|  |         for line in reader.lines() { | ||||||
|  |             if let Ok(line_content) = line { | ||||||
|  |                 // Print the line to the terminal | ||||||
|  |                 println!("{}", line_content); | ||||||
|  |  | ||||||
|  |                 // todo store line to database for being fetchable from api | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Ensure the command completes | ||||||
|  |     let result = output.wait(); | ||||||
|  |  | ||||||
|  |     match result { | ||||||
|  |         Ok(result) => { | ||||||
|  |             if !result.success() { | ||||||
|                 return Err(anyhow!("failed to build package")); |                 return Err(anyhow!("failed to build package")); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -46,6 +56,14 @@ pub fn build_pkgbuild( | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     locate_built_package(pkg_name.to_string(), pkg_vers.to_string(), folder_path) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn locate_built_package( | ||||||
|  |     pkg_name: String, | ||||||
|  |     pkg_vers: String, | ||||||
|  |     folder_path: String, | ||||||
|  | ) -> anyhow::Result<String> { | ||||||
|     // check if expected built dir exists |     // check if expected built dir exists | ||||||
|     let built_name = build_expected_repo_packagename(pkg_name.to_string(), pkg_vers.to_string()); |     let built_name = build_expected_repo_packagename(pkg_name.to_string(), pkg_vers.to_string()); | ||||||
|     if fs::metadata(format!("{folder_path}/{built_name}")).is_ok() { |     if fs::metadata(format!("{folder_path}/{built_name}")).is_ok() { | ||||||
| @@ -65,7 +83,8 @@ pub fn build_pkgbuild( | |||||||
|                 if let Some(file_name) = path.file_name() { |                 if let Some(file_name) = path.file_name() { | ||||||
|                     let file_name = file_name.to_str().unwrap(); |                     let file_name = file_name.to_str().unwrap(); | ||||||
|  |  | ||||||
|                     if file_name.ends_with("-x86_64.pkg.tar.zst") && file_name.starts_with(pkg_name) |                     if file_name.ends_with("-x86_64.pkg.tar.zst") | ||||||
|  |                         && file_name.starts_with(pkg_name.as_str()) | ||||||
|                     { |                     { | ||||||
|                         if let Ok(metadata) = path.metadata() { |                         if let Ok(metadata) = path.metadata() { | ||||||
|                             if let Ok(modified_time) = metadata.modified() { |                             if let Ok(modified_time) = metadata.modified() { | ||||||
| @@ -87,7 +106,7 @@ pub fn build_pkgbuild( | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     Err(anyhow!("No package built")) |     Err(anyhow!("Built package not found")) | ||||||
| } | } | ||||||
|  |  | ||||||
| /// don't trust this pkg name from existing | /// don't trust this pkg name from existing | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| use crate::aur::aur::download_pkgbuild; | use crate::aur::aur::download_pkgbuild; | ||||||
| use crate::db::prelude::Packages; | use crate::db::prelude::Packages; | ||||||
| use crate::db::prelude::Versions; | use crate::db::prelude::Versions; | ||||||
| use crate::db::{versions}; | use crate::db::versions; | ||||||
| use crate::pkgbuild::build::build_pkgbuild; | use crate::pkgbuild::build::build_pkgbuild; | ||||||
| use anyhow::anyhow; | use anyhow::anyhow; | ||||||
| use sea_orm::{ColumnTrait, DatabaseConnection, EntityTrait, ModelTrait, QueryFilter}; | use sea_orm::{ColumnTrait, DatabaseConnection, EntityTrait, ModelTrait, QueryFilter}; | ||||||
| @@ -69,7 +69,10 @@ fn repo_remove(pkg_file_name: String) -> anyhow::Result<()> { | |||||||
| } | } | ||||||
|  |  | ||||||
| pub async fn remove_pkg(db: &DatabaseConnection, pkg_id: i32) -> anyhow::Result<()> { | pub async fn remove_pkg(db: &DatabaseConnection, pkg_id: i32) -> anyhow::Result<()> { | ||||||
|     let pkg = Packages::find_by_id(pkg_id).one(db).await?.ok_or(anyhow!("id not found"))?; |     let pkg = Packages::find_by_id(pkg_id) | ||||||
|  |         .one(db) | ||||||
|  |         .await? | ||||||
|  |         .ok_or(anyhow!("id not found"))?; | ||||||
|  |  | ||||||
|     fs::remove_dir_all(format!("./builds/{}", pkg.name))?; |     fs::remove_dir_all(format!("./builds/{}", pkg.name))?; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user