fix some linter warnings
outsource api types to files
This commit is contained in:
parent
70f1d76554
commit
f319facda1
25
backend/src/api/aur.rs
Normal file
25
backend/src/api/aur.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
use crate::aur::aur::query_aur;
|
||||||
|
use rocket::serde::json::Json;
|
||||||
|
|
||||||
|
use rocket::get;
|
||||||
|
|
||||||
|
use crate::api::types::input::ApiPackage;
|
||||||
|
use rocket_okapi::openapi;
|
||||||
|
|
||||||
|
#[openapi(tag = "aur")]
|
||||||
|
#[get("/search?<query>")]
|
||||||
|
pub async fn search(query: &str) -> Result<Json<Vec<ApiPackage>>, String> {
|
||||||
|
return match query_aur(query).await {
|
||||||
|
Ok(v) => {
|
||||||
|
let mapped = v
|
||||||
|
.iter()
|
||||||
|
.map(|x| ApiPackage {
|
||||||
|
name: x.name.clone(),
|
||||||
|
version: x.version.clone(),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
Ok(Json(mapped))
|
||||||
|
}
|
||||||
|
Err(e) => Err(format!("{}", e)),
|
||||||
|
};
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
|
use crate::api::aur::*;
|
||||||
use crate::api::build::*;
|
use crate::api::build::*;
|
||||||
use crate::api::list::*;
|
|
||||||
use crate::api::package::*;
|
use crate::api::package::*;
|
||||||
|
use crate::api::stats::*;
|
||||||
use crate::api::version::*;
|
use crate::api::version::*;
|
||||||
use rocket::Route;
|
use rocket::Route;
|
||||||
use rocket_okapi::openapi_get_routes;
|
use rocket_okapi::openapi_get_routes;
|
||||||
|
@ -3,29 +3,16 @@ use crate::db::prelude::Builds;
|
|||||||
use crate::db::{builds, packages, versions};
|
use crate::db::{builds, packages, versions};
|
||||||
use rocket::response::status::NotFound;
|
use rocket::response::status::NotFound;
|
||||||
use rocket::serde::json::Json;
|
use rocket::serde::json::Json;
|
||||||
use rocket::serde::{Deserialize, Serialize};
|
|
||||||
use rocket::{delete, get, State};
|
use rocket::{delete, get, State};
|
||||||
use rocket_okapi::okapi::schemars;
|
|
||||||
use rocket_okapi::{openapi, JsonSchema};
|
use crate::api::types::input::ListBuildsModel;
|
||||||
|
use rocket_okapi::openapi;
|
||||||
use sea_orm::ColumnTrait;
|
use sea_orm::ColumnTrait;
|
||||||
use sea_orm::QueryFilter;
|
use sea_orm::QueryFilter;
|
||||||
use sea_orm::{
|
use sea_orm::{
|
||||||
DatabaseConnection, EntityTrait, FromQueryResult, ModelTrait, QueryOrder, QuerySelect,
|
DatabaseConnection, EntityTrait, ModelTrait, QueryOrder, QuerySelect, RelationTrait,
|
||||||
RelationTrait,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(FromQueryResult, Deserialize, JsonSchema, Serialize)]
|
|
||||||
#[serde(crate = "rocket::serde")]
|
|
||||||
pub struct ListPackageModel {
|
|
||||||
id: i32,
|
|
||||||
name: String,
|
|
||||||
status: i32,
|
|
||||||
outofdate: bool,
|
|
||||||
latest_version: Option<String>,
|
|
||||||
latest_version_id: Option<i32>,
|
|
||||||
latest_aur_version: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[openapi(tag = "build")]
|
#[openapi(tag = "build")]
|
||||||
#[get("/build/<buildid>/output?<startline>")]
|
#[get("/build/<buildid>/output?<startline>")]
|
||||||
pub async fn build_output(
|
pub async fn build_output(
|
||||||
@ -46,7 +33,7 @@ pub async fn build_output(
|
|||||||
Some(v) => match startline {
|
Some(v) => match startline {
|
||||||
None => Ok(v),
|
None => Ok(v),
|
||||||
Some(startline) => {
|
Some(startline) => {
|
||||||
let output: Vec<String> = v.split("\n").map(|x| x.to_string()).collect();
|
let output: Vec<String> = v.split('\n').map(|x| x.to_string()).collect();
|
||||||
let len = output.len();
|
let len = output.len();
|
||||||
let len_missing = len as i32 - startline;
|
let len_missing = len as i32 - startline;
|
||||||
|
|
||||||
@ -59,7 +46,7 @@ pub async fn build_output(
|
|||||||
0
|
0
|
||||||
})
|
})
|
||||||
.rev()
|
.rev()
|
||||||
.map(|x1| x1.clone())
|
.cloned()
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let output = output.join("\n");
|
let output = output.join("\n");
|
||||||
@ -69,18 +56,6 @@ pub async fn build_output(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromQueryResult, Deserialize, JsonSchema, Serialize)]
|
|
||||||
#[serde(crate = "rocket::serde")]
|
|
||||||
pub struct ListBuildsModel {
|
|
||||||
id: i32,
|
|
||||||
pkg_id: i32,
|
|
||||||
pkg_name: String,
|
|
||||||
version: String,
|
|
||||||
status: i32,
|
|
||||||
start_time: Option<u32>,
|
|
||||||
end_time: Option<u32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[openapi(tag = "build")]
|
#[openapi(tag = "build")]
|
||||||
#[get("/builds?<pkgid>&<limit>")]
|
#[get("/builds?<pkgid>&<limit>")]
|
||||||
pub async fn list_builds(
|
pub async fn list_builds(
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
|
mod aur;
|
||||||
pub mod backend;
|
pub mod backend;
|
||||||
mod build;
|
mod build;
|
||||||
#[cfg(feature = "static")]
|
#[cfg(feature = "static")]
|
||||||
pub mod embed;
|
pub mod embed;
|
||||||
mod list;
|
|
||||||
mod package;
|
mod package;
|
||||||
|
mod stats;
|
||||||
|
mod types;
|
||||||
mod version;
|
mod version;
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use crate::api::build::ListPackageModel;
|
|
||||||
use crate::builder::types::Action;
|
use crate::builder::types::Action;
|
||||||
use crate::db::migration::{JoinType, Order};
|
use crate::db::migration::{JoinType, Order};
|
||||||
use crate::db::prelude::Packages;
|
use crate::db::prelude::Packages;
|
||||||
@ -8,20 +7,16 @@ use crate::package::delete::package_delete;
|
|||||||
use crate::package::update::package_update;
|
use crate::package::update::package_update;
|
||||||
use rocket::response::status::{BadRequest, NotFound};
|
use rocket::response::status::{BadRequest, NotFound};
|
||||||
use rocket::serde::json::Json;
|
use rocket::serde::json::Json;
|
||||||
use rocket::serde::Deserialize;
|
|
||||||
use rocket::{delete, get, post, State};
|
use rocket::{delete, get, post, State};
|
||||||
use rocket_okapi::okapi::schemars;
|
|
||||||
use rocket_okapi::{openapi, JsonSchema};
|
use crate::api::types::input::ListPackageModel;
|
||||||
|
use crate::api::types::output::{AddBody, UpdateBody};
|
||||||
|
use rocket_okapi::openapi;
|
||||||
use sea_orm::DatabaseConnection;
|
use sea_orm::DatabaseConnection;
|
||||||
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter, QueryOrder, QuerySelect, RelationTrait};
|
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter, QueryOrder, QuerySelect, RelationTrait};
|
||||||
use tokio::sync::broadcast::Sender;
|
use tokio::sync::broadcast::Sender;
|
||||||
|
|
||||||
#[derive(Deserialize, JsonSchema)]
|
|
||||||
#[serde(crate = "rocket::serde")]
|
|
||||||
pub struct AddBody {
|
|
||||||
name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[openapi(tag = "Packages")]
|
#[openapi(tag = "Packages")]
|
||||||
#[post("/package", data = "<input>")]
|
#[post("/package", data = "<input>")]
|
||||||
pub async fn package_add_endpoint(
|
pub async fn package_add_endpoint(
|
||||||
@ -34,12 +29,6 @@ pub async fn package_add_endpoint(
|
|||||||
.map_err(|e| BadRequest(Some(e.to_string())))
|
.map_err(|e| BadRequest(Some(e.to_string())))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, JsonSchema)]
|
|
||||||
#[serde(crate = "rocket::serde")]
|
|
||||||
pub struct UpdateBody {
|
|
||||||
force: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[openapi(tag = "Packages")]
|
#[openapi(tag = "Packages")]
|
||||||
#[post("/package/<id>/update", data = "<input>")]
|
#[post("/package/<id>/update", data = "<input>")]
|
||||||
pub async fn package_update_endpoint(
|
pub async fn package_update_endpoint(
|
||||||
@ -50,7 +39,7 @@ pub async fn package_update_endpoint(
|
|||||||
) -> Result<Json<i32>, BadRequest<String>> {
|
) -> Result<Json<i32>, BadRequest<String>> {
|
||||||
package_update(db, id, input.force, tx)
|
package_update(db, id, input.force, tx)
|
||||||
.await
|
.await
|
||||||
.map(|e| Json(e))
|
.map(Json)
|
||||||
.map_err(|e| BadRequest(Some(e.to_string())))
|
.map_err(|e| BadRequest(Some(e.to_string())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,53 +1,17 @@
|
|||||||
use crate::aur::aur::query_aur;
|
use crate::db::builds;
|
||||||
use crate::db::prelude::{Builds, Packages};
|
use crate::db::prelude::{Builds, Packages};
|
||||||
use crate::db::{builds};
|
|
||||||
use crate::utils::dir_size::dir_size;
|
use crate::utils::dir_size::dir_size;
|
||||||
|
|
||||||
use rocket::response::status::NotFound;
|
use rocket::response::status::NotFound;
|
||||||
use rocket::serde::json::Json;
|
use rocket::serde::json::Json;
|
||||||
use rocket::serde::{Deserialize, Serialize};
|
|
||||||
use rocket::{get, State};
|
use rocket::{get, State};
|
||||||
use rocket_okapi::okapi::schemars;
|
|
||||||
use rocket_okapi::{openapi, JsonSchema};
|
use crate::api::types::input::ListStats;
|
||||||
|
use rocket_okapi::openapi;
|
||||||
|
use sea_orm::PaginatorTrait;
|
||||||
use sea_orm::{ColumnTrait, QueryFilter};
|
use sea_orm::{ColumnTrait, QueryFilter};
|
||||||
use sea_orm::{DatabaseConnection, EntityTrait, FromQueryResult};
|
use sea_orm::{DatabaseConnection, EntityTrait};
|
||||||
use sea_orm::{PaginatorTrait};
|
|
||||||
|
|
||||||
#[derive(Serialize, JsonSchema)]
|
|
||||||
#[serde(crate = "rocket::serde")]
|
|
||||||
pub struct ApiPackage {
|
|
||||||
name: String,
|
|
||||||
version: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[openapi(tag = "aur")]
|
|
||||||
#[get("/search?<query>")]
|
|
||||||
pub async fn search(query: &str) -> Result<Json<Vec<ApiPackage>>, String> {
|
|
||||||
return match query_aur(query).await {
|
|
||||||
Ok(v) => {
|
|
||||||
let mapped = v
|
|
||||||
.iter()
|
|
||||||
.map(|x| ApiPackage {
|
|
||||||
name: x.name.clone(),
|
|
||||||
version: x.version.clone(),
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
Ok(Json(mapped))
|
|
||||||
}
|
|
||||||
Err(e) => Err(format!("{}", e)),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(FromQueryResult, Deserialize, JsonSchema, Serialize)]
|
|
||||||
#[serde(crate = "rocket::serde")]
|
|
||||||
pub struct ListStats {
|
|
||||||
total_builds: u32,
|
|
||||||
failed_builds: u32,
|
|
||||||
avg_queue_wait_time: u32,
|
|
||||||
avg_build_time: u32,
|
|
||||||
repo_storage_size: u64,
|
|
||||||
active_builds: u32,
|
|
||||||
total_packages: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[openapi(tag = "stats")]
|
#[openapi(tag = "stats")]
|
||||||
#[get("/stats")]
|
#[get("/stats")]
|
47
backend/src/api/types/input.rs
Normal file
47
backend/src/api/types/input.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
use rocket::serde::{Deserialize, Serialize};
|
||||||
|
use rocket_okapi::okapi::schemars;
|
||||||
|
use rocket_okapi::JsonSchema;
|
||||||
|
use sea_orm::FromQueryResult;
|
||||||
|
|
||||||
|
#[derive(Serialize, JsonSchema)]
|
||||||
|
#[serde(crate = "rocket::serde")]
|
||||||
|
pub struct ApiPackage {
|
||||||
|
pub name: String,
|
||||||
|
pub version: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromQueryResult, Deserialize, JsonSchema, Serialize)]
|
||||||
|
#[serde(crate = "rocket::serde")]
|
||||||
|
pub struct ListPackageModel {
|
||||||
|
pub id: i32,
|
||||||
|
pub name: String,
|
||||||
|
pub status: i32,
|
||||||
|
pub outofdate: bool,
|
||||||
|
pub latest_version: Option<String>,
|
||||||
|
pub latest_version_id: Option<i32>,
|
||||||
|
pub latest_aur_version: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromQueryResult, Deserialize, JsonSchema, Serialize)]
|
||||||
|
#[serde(crate = "rocket::serde")]
|
||||||
|
pub struct ListBuildsModel {
|
||||||
|
id: i32,
|
||||||
|
pkg_id: i32,
|
||||||
|
pkg_name: String,
|
||||||
|
version: String,
|
||||||
|
status: i32,
|
||||||
|
start_time: Option<u32>,
|
||||||
|
end_time: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromQueryResult, Deserialize, JsonSchema, Serialize)]
|
||||||
|
#[serde(crate = "rocket::serde")]
|
||||||
|
pub struct ListStats {
|
||||||
|
pub total_builds: u32,
|
||||||
|
pub failed_builds: u32,
|
||||||
|
pub avg_queue_wait_time: u32,
|
||||||
|
pub avg_build_time: u32,
|
||||||
|
pub repo_storage_size: u64,
|
||||||
|
pub active_builds: u32,
|
||||||
|
pub total_packages: u32,
|
||||||
|
}
|
2
backend/src/api/types/mod.rs
Normal file
2
backend/src/api/types/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod input;
|
||||||
|
pub mod output;
|
15
backend/src/api/types/output.rs
Normal file
15
backend/src/api/types/output.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
use rocket::serde::Deserialize;
|
||||||
|
use rocket_okapi::okapi::schemars;
|
||||||
|
use rocket_okapi::JsonSchema;
|
||||||
|
|
||||||
|
#[derive(Deserialize, JsonSchema)]
|
||||||
|
#[serde(crate = "rocket::serde")]
|
||||||
|
pub struct AddBody {
|
||||||
|
pub(crate) name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, JsonSchema)]
|
||||||
|
#[serde(crate = "rocket::serde")]
|
||||||
|
pub struct UpdateBody {
|
||||||
|
pub(crate) force: bool,
|
||||||
|
}
|
@ -52,7 +52,7 @@ pub async fn download_pkgbuild(url: &str, dest_dir: &str) -> anyhow::Result<Stri
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Check if the directory exists
|
// Check if the directory exists
|
||||||
if !fs::metadata(dest_dir).is_ok() {
|
if fs::metadata(dest_dir).is_err() {
|
||||||
// Create the directory if it does not exist
|
// Create the directory if it does not exist
|
||||||
fs::create_dir(dest_dir)?;
|
fs::create_dir(dest_dir)?;
|
||||||
}
|
}
|
||||||
@ -71,7 +71,7 @@ async fn download_file(url: &str) -> anyhow::Result<(Vec<u8>, String)> {
|
|||||||
.path_segments()
|
.path_segments()
|
||||||
.and_then(|segments| segments.last())
|
.and_then(|segments| segments.last())
|
||||||
.ok_or(anyhow!("no segments"))?
|
.ok_or(anyhow!("no segments"))?
|
||||||
.split(".")
|
.split('.')
|
||||||
.collect::<Vec<&str>>()
|
.collect::<Vec<&str>>()
|
||||||
.first()
|
.first()
|
||||||
.ok_or(anyhow!(""))?
|
.ok_or(anyhow!(""))?
|
||||||
|
@ -34,7 +34,7 @@ fn main() {
|
|||||||
|
|
||||||
t.block_on(async move {
|
t.block_on(async move {
|
||||||
// create folder for db stuff
|
// create folder for db stuff
|
||||||
if !fs::metadata("./db").is_ok() {
|
if fs::metadata("./db").is_err() {
|
||||||
fs::create_dir("./db").unwrap();
|
fs::create_dir("./db").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ fn main() {
|
|||||||
Migrator::up(&db, None).await.unwrap();
|
Migrator::up(&db, None).await.unwrap();
|
||||||
|
|
||||||
// create repo folder
|
// create repo folder
|
||||||
if !fs::metadata("./repo").is_ok() {
|
if fs::metadata("./repo").is_err() {
|
||||||
fs::create_dir("./repo").unwrap();
|
fs::create_dir("./repo").unwrap();
|
||||||
|
|
||||||
let tar_gz = File::create("./repo/repo.db.tar.gz").unwrap();
|
let tar_gz = File::create("./repo/repo.db.tar.gz").unwrap();
|
||||||
@ -74,9 +74,11 @@ fn main() {
|
|||||||
start_aur_version_checking(db.clone());
|
start_aur_version_checking(db.clone());
|
||||||
|
|
||||||
let backend_handle = tokio::spawn(async {
|
let backend_handle = tokio::spawn(async {
|
||||||
let mut config = Config::default();
|
let config = Config {
|
||||||
config.address = "0.0.0.0".parse().unwrap();
|
address: "0.0.0.0".parse().unwrap(),
|
||||||
config.port = 8081;
|
port: 8081,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
let rock = rocket::custom(config)
|
let rock = rocket::custom(config)
|
||||||
.manage(db)
|
.manage(db)
|
||||||
@ -100,9 +102,11 @@ fn main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let repo_handle = tokio::spawn(async {
|
let repo_handle = tokio::spawn(async {
|
||||||
let mut config = Config::default();
|
let config = Config {
|
||||||
config.address = "0.0.0.0".parse().unwrap();
|
address: "0.0.0.0".parse().unwrap(),
|
||||||
config.port = 8080;
|
port: 8080,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
let launch_result = rocket::custom(config)
|
let launch_result = rocket::custom(config)
|
||||||
.mount("/", FileServer::from("./repo"))
|
.mount("/", FileServer::from("./repo"))
|
||||||
@ -116,6 +120,4 @@ fn main() {
|
|||||||
|
|
||||||
join_all([repo_handle, backend_handle]).await;
|
join_all([repo_handle, backend_handle]).await;
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,11 @@ pub async fn package_add(
|
|||||||
// remove leading and trailing whitespaces
|
// remove leading and trailing whitespaces
|
||||||
let pkg_name = pkg_name.trim();
|
let pkg_name = pkg_name.trim();
|
||||||
|
|
||||||
if let Some(..) = Packages::find()
|
if Packages::find()
|
||||||
.filter(packages::Column::Name.eq(pkg_name))
|
.filter(packages::Column::Name.eq(pkg_name))
|
||||||
.one(&txn)
|
.one(&txn)
|
||||||
.await?
|
.await?
|
||||||
|
.is_some()
|
||||||
{
|
{
|
||||||
return Err(anyhow!("Package already exists"));
|
return Err(anyhow!("Package already exists"));
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ pub async fn package_update(
|
|||||||
|
|
||||||
let version_model = match Versions::find()
|
let version_model = match Versions::find()
|
||||||
.filter(versions::Column::Version.eq(pkg.version.clone()))
|
.filter(versions::Column::Version.eq(pkg.version.clone()))
|
||||||
.filter(versions::Column::PackageId.eq(pkg.id.clone()))
|
.filter(versions::Column::PackageId.eq(pkg.id))
|
||||||
.one(&txn)
|
.one(&txn)
|
||||||
.await?
|
.await?
|
||||||
{
|
{
|
||||||
|
@ -7,7 +7,7 @@ use tokio::sync::broadcast::Sender;
|
|||||||
// todo consider removing pkg_vers from attribute list
|
// todo consider removing pkg_vers from attribute list
|
||||||
pub async fn build_pkgbuild(
|
pub async fn build_pkgbuild(
|
||||||
folder_path: String,
|
folder_path: String,
|
||||||
pkg_vers: &str,
|
_pkg_vers: &str,
|
||||||
pkg_name: &str,
|
pkg_name: &str,
|
||||||
tx: Sender<String>,
|
tx: Sender<String>,
|
||||||
) -> anyhow::Result<Vec<String>> {
|
) -> anyhow::Result<Vec<String>> {
|
||||||
@ -26,7 +26,7 @@ pub async fn build_pkgbuild(
|
|||||||
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 mut child = tokio::process::Command::new("bash")
|
let mut child = tokio::process::Command::new("bash")
|
||||||
.args(&[
|
.args([
|
||||||
script_file.as_os_str().to_str().unwrap(),
|
script_file.as_os_str().to_str().unwrap(),
|
||||||
"-f",
|
"-f",
|
||||||
"--noconfirm",
|
"--noconfirm",
|
||||||
@ -106,7 +106,7 @@ fn locate_built_packages(pkg_name: String, folder_path: String) -> anyhow::Resul
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return if pkg_names.is_empty() {
|
if pkg_names.is_empty() {
|
||||||
Err(anyhow!("Built package not found"))
|
Err(anyhow!("Built package not found"))
|
||||||
} else {
|
} else {
|
||||||
// expect at least one of the packages to start with the package name
|
// expect at least one of the packages to start with the package name
|
||||||
@ -116,5 +116,5 @@ fn locate_built_packages(pkg_name: String, folder_path: String) -> anyhow::Resul
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
Ok(pkg_names)
|
Ok(pkg_names)
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user