mirror of
https://github.com/Drop-OSS/drop.git
synced 2026-07-27 10:14:40 +10:00
refactor: Remove ConfigItem
This commit is contained in:
+3
-2
@@ -1,6 +1,7 @@
|
|||||||
use crate::config::config::ConfigOptionCli;
|
|
||||||
use clap::{Args, Parser, Subcommand, ValueEnum};
|
use clap::{Args, Parser, Subcommand, ValueEnum};
|
||||||
|
|
||||||
|
use crate::commands::config::config_option::ConfigOptionCli;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(version, about, long_about = None)]
|
#[command(version, about, long_about = None)]
|
||||||
pub struct Cli {
|
pub struct Cli {
|
||||||
@@ -19,7 +20,7 @@ pub enum Commands {
|
|||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
name: String,
|
name: String,
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
option: ConfigOptionCli
|
option: ConfigOptionCli,
|
||||||
},
|
},
|
||||||
/// Uploads new game version to depot
|
/// Uploads new game version to depot
|
||||||
Upload(UploadInfo),
|
Upload(UploadInfo),
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
use crate::config::{
|
use crate::commands::config::{config_option::ConfigOption, s3::S3Config};
|
||||||
s3::{S3Config, S3ConfigCli},
|
|
||||||
server::ServerConfig,
|
|
||||||
};
|
|
||||||
use clap::Subcommand;
|
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{collections::HashMap, fs};
|
use std::{collections::HashMap, fs};
|
||||||
@@ -15,6 +11,12 @@ pub struct Config {
|
|||||||
active_s3: Option<String>,
|
active_s3: Option<String>,
|
||||||
}
|
}
|
||||||
impl Config {
|
impl Config {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
items: HashMap::new(),
|
||||||
|
active_s3: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn save(&self) -> anyhow::Result<()> {
|
pub fn save(&self) -> anyhow::Result<()> {
|
||||||
let json = serde_json::to_string(self)?;
|
let json = serde_json::to_string(self)?;
|
||||||
let save_path = dirs::config_dir()
|
let save_path = dirs::config_dir()
|
||||||
@@ -41,26 +43,7 @@ impl Config {
|
|||||||
self.items.insert(name, object);
|
self.items.insert(name, object);
|
||||||
self.save().expect("Failed to save config");
|
self.save().expect("Failed to save config");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Subcommand, Clone)]
|
|
||||||
pub enum ConfigOptionCli {
|
|
||||||
Server(ServerConfig),
|
|
||||||
S3(S3ConfigCli),
|
|
||||||
}
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
|
||||||
pub enum ConfigOption {
|
|
||||||
Server(ServerConfig),
|
|
||||||
S3(S3Config),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Config {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
items: HashMap::new(),
|
|
||||||
active_s3: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn get_active_s3(&self) -> Option<S3Config> {
|
pub fn get_active_s3(&self) -> Option<S3Config> {
|
||||||
if let Some(active_s3) = &self.active_s3 {
|
if let Some(active_s3) = &self.active_s3 {
|
||||||
self.items
|
self.items
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
use clap::Subcommand;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::commands::config::{
|
||||||
|
s3::{S3Config, S3ConfigCli},
|
||||||
|
server::{ServerConfig, ServerConfigCli},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Subcommand, Clone)]
|
||||||
|
pub enum ConfigOptionCli {
|
||||||
|
Server(ServerConfigCli),
|
||||||
|
S3(S3ConfigCli),
|
||||||
|
}
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
pub enum ConfigOption {
|
||||||
|
Server(ServerConfig),
|
||||||
|
S3(S3Config),
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
use crate::commands::config::config_option::ConfigOption;
|
||||||
|
|
||||||
|
pub trait Configurable {
|
||||||
|
async fn configure(self) -> anyhow::Result<ConfigOption>;
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ macro_rules! interactive_variable {
|
|||||||
let $var = if let Some($var) = $value.$var {
|
let $var = if let Some($var) = $value.$var {
|
||||||
$var
|
$var
|
||||||
} else {
|
} else {
|
||||||
crate::config::interactive::query_variable($prompt).unwrap()
|
crate::commands::config::interactive::query_variable($prompt).unwrap()
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,7 @@ macro_rules! interactive_optional_variable {
|
|||||||
let $var = if let Some($var) = $value.$var {
|
let $var = if let Some($var) = $value.$var {
|
||||||
Some($var)
|
Some($var)
|
||||||
} else {
|
} else {
|
||||||
crate::config::interactive::query_optional_variable($prompt).unwrap()
|
crate::commands::config::interactive::query_optional_variable($prompt).unwrap()
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -44,4 +44,4 @@ where
|
|||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
Ok(Some(input))
|
Ok(Some(input))
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
pub mod config;
|
pub mod config;
|
||||||
|
pub mod configure;
|
||||||
pub mod s3;
|
pub mod s3;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
pub mod configure;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod interactive;
|
pub mod interactive;
|
||||||
|
pub mod config_option;
|
||||||
@@ -4,10 +4,12 @@ use clap::Args;
|
|||||||
use s3::{Bucket, Region, creds::Credentials};
|
use s3::{Bucket, Region, creds::Credentials};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{config::configure::Configurable, interactive_optional_variable, interactive_variable};
|
use crate::{
|
||||||
|
commands::config::{config_option::ConfigOption, configure::Configurable},
|
||||||
|
interactive_optional_variable, interactive_variable,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Args, Clone)]
|
||||||
#[derive(Serialize, Deserialize, Args, Clone)]
|
|
||||||
pub struct S3ConfigCli {
|
pub struct S3ConfigCli {
|
||||||
secret_key: Option<String>,
|
secret_key: Option<String>,
|
||||||
key_id: Option<String>,
|
key_id: Option<String>,
|
||||||
@@ -16,25 +18,6 @@ pub struct S3ConfigCli {
|
|||||||
endpoint: Option<String>,
|
endpoint: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Configurable for S3ConfigCli {
|
|
||||||
type Out = S3Config;
|
|
||||||
|
|
||||||
fn configure(self) -> Self::Out {
|
|
||||||
interactive_variable!(self, secret_key, "S3 Secret Key");
|
|
||||||
interactive_variable!(self, key_id, "S3 Key ID");
|
|
||||||
interactive_variable!(self, region, "S3 Region");
|
|
||||||
interactive_variable!(self, bucket_name, "S3 Bucket Name");
|
|
||||||
interactive_optional_variable!(self, endpoint, "S3 Endpoint (leave blank for none");
|
|
||||||
Self::Out {
|
|
||||||
secret_key,
|
|
||||||
key_id,
|
|
||||||
region,
|
|
||||||
bucket_name,
|
|
||||||
endpoint,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct S3Config {
|
pub struct S3Config {
|
||||||
secret_key: String,
|
secret_key: String,
|
||||||
@@ -44,6 +27,23 @@ pub struct S3Config {
|
|||||||
endpoint: Option<String>,
|
endpoint: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Configurable for S3ConfigCli {
|
||||||
|
async fn configure(self) -> anyhow::Result<ConfigOption> {
|
||||||
|
interactive_variable!(self, secret_key, "S3 Secret Key");
|
||||||
|
interactive_variable!(self, key_id, "S3 Key ID");
|
||||||
|
interactive_variable!(self, region, "S3 Region");
|
||||||
|
interactive_variable!(self, bucket_name, "S3 Bucket Name");
|
||||||
|
interactive_optional_variable!(self, endpoint, "S3 Endpoint (leave blank for none");
|
||||||
|
Ok(ConfigOption::S3(S3Config {
|
||||||
|
secret_key,
|
||||||
|
key_id,
|
||||||
|
region,
|
||||||
|
bucket_name,
|
||||||
|
endpoint,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl S3Config {
|
impl S3Config {
|
||||||
pub fn generate_bucket(&self) -> anyhow::Result<s3::Bucket> {
|
pub fn generate_bucket(&self) -> anyhow::Result<s3::Bucket> {
|
||||||
let credentials =
|
let credentials =
|
||||||
@@ -62,4 +62,4 @@ impl S3Config {
|
|||||||
|
|
||||||
Ok(*bucket)
|
Ok(*bucket)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
use clap::Args;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
|
use anyhow::{Result, anyhow};
|
||||||
|
use dialoguer::{Confirm, Input, theme::ColorfulTheme};
|
||||||
|
use reqwest::Client;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
use crate::commands::config::{config_option::ConfigOption, configure::Configurable};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
pub struct ServerConfig {
|
||||||
|
url: String,
|
||||||
|
token: String,
|
||||||
|
}
|
||||||
|
#[derive(Args, Clone)]
|
||||||
|
pub struct ServerConfigCli {
|
||||||
|
/// Endpoint of the Drop server
|
||||||
|
url: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
token: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
const TOKEN_CREATE_PAYLOAD: &str =
|
||||||
|
"eyJuYW1lIjoiZG93bnBvdXIgKGNsaSkiLCJhY2xzIjpbImRlcG90Om5ldyJdfQ==";
|
||||||
|
|
||||||
|
impl Configurable for ServerConfigCli {
|
||||||
|
async fn configure(self) -> anyhow::Result<ConfigOption> {
|
||||||
|
let base_url = Url::parse(&self.url)?;
|
||||||
|
let mut token_create_url = base_url.join("/admin/settings/tokens")?;
|
||||||
|
{
|
||||||
|
let mut query = token_create_url.query_pairs_mut();
|
||||||
|
query.append_pair("payload", TOKEN_CREATE_PAYLOAD);
|
||||||
|
};
|
||||||
|
|
||||||
|
let confirm = Confirm::with_theme(&ColorfulTheme::default())
|
||||||
|
.with_prompt(format!(
|
||||||
|
"Open \"{}\" in your default browser?",
|
||||||
|
token_create_url.as_str()
|
||||||
|
))
|
||||||
|
.interact()?;
|
||||||
|
|
||||||
|
if !confirm {
|
||||||
|
return Err(anyhow!("User cancelled action"));
|
||||||
|
}
|
||||||
|
|
||||||
|
webbrowser::open(token_create_url.as_str())?;
|
||||||
|
|
||||||
|
let token: String = Input::with_theme(&ColorfulTheme::default())
|
||||||
|
.with_prompt("API token")
|
||||||
|
.interact_text()?;
|
||||||
|
|
||||||
|
validate_configuration(&self.url, &token).await?;
|
||||||
|
|
||||||
|
Ok(ConfigOption::Server(ServerConfig {
|
||||||
|
url: self.url,
|
||||||
|
token,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static CLIENT: LazyLock<Client> = LazyLock::new(|| reqwest::Client::new());
|
||||||
|
const REQUIRED_ACLS: [&str; 1] = ["depot:new"];
|
||||||
|
|
||||||
|
pub async fn validate_configuration(url: &str, token: &str) -> Result<()> {
|
||||||
|
let base_url = Url::parse(&url)?;
|
||||||
|
let token_check_url = base_url.join("/api/v1/token")?;
|
||||||
|
|
||||||
|
let acl_check = CLIENT
|
||||||
|
.get(token_check_url)
|
||||||
|
.bearer_auth(token)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if !acl_check.status().is_success() {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"ACL check failed with response code: {}",
|
||||||
|
acl_check.status()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let acls: Vec<String> = acl_check.json().await?;
|
||||||
|
|
||||||
|
for acl in REQUIRED_ACLS {
|
||||||
|
if !acls.contains(&acl.to_string()) {
|
||||||
|
return Err(anyhow!("Token missing {} acl", acl));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
use std::sync::LazyLock;
|
|
||||||
|
|
||||||
use anyhow::{Result, anyhow};
|
|
||||||
use dialoguer::{Confirm, Input, theme::ColorfulTheme};
|
|
||||||
use reqwest::Client;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
const TOKEN_CREATE_PAYLOAD: &str =
|
|
||||||
"eyJuYW1lIjoiZG93bnBvdXIgKGNsaSkiLCJhY2xzIjpbImRlcG90Om5ldyJdfQ==";
|
|
||||||
|
|
||||||
static CLIENT: LazyLock<Client> = LazyLock::new(|| reqwest::Client::new());
|
|
||||||
const REQUIRED_ACLS: [&str; 1] = ["depot:new"];
|
|
||||||
|
|
||||||
pub async fn interactive_configure(url: String) -> Result<()> {
|
|
||||||
let base_url = Url::parse(&url)?;
|
|
||||||
let mut token_create_url = base_url.join("/admin/settings/tokens")?;
|
|
||||||
{
|
|
||||||
let mut query = token_create_url.query_pairs_mut();
|
|
||||||
query.append_pair("payload", TOKEN_CREATE_PAYLOAD);
|
|
||||||
};
|
|
||||||
|
|
||||||
let confirm = Confirm::with_theme(&ColorfulTheme::default())
|
|
||||||
.with_prompt(format!(
|
|
||||||
"Open \"{}\" in your default browser?",
|
|
||||||
token_create_url.as_str()
|
|
||||||
))
|
|
||||||
.interact()?;
|
|
||||||
|
|
||||||
if !confirm {
|
|
||||||
return Err(anyhow!("User cancelled action"));
|
|
||||||
}
|
|
||||||
|
|
||||||
webbrowser::open(token_create_url.as_str())?;
|
|
||||||
|
|
||||||
let token: String = Input::with_theme(&ColorfulTheme::default())
|
|
||||||
.with_prompt("API token")
|
|
||||||
.interact_text()?;
|
|
||||||
|
|
||||||
validate_configuration(url, token).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn validate_configuration(url: String, token: String) -> Result<()> {
|
|
||||||
let base_url = Url::parse(&url)?;
|
|
||||||
let token_check_url = base_url.join("/api/v1/token")?;
|
|
||||||
|
|
||||||
let acl_check = CLIENT
|
|
||||||
.get(token_check_url)
|
|
||||||
.bearer_auth(token)
|
|
||||||
.send()
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if !acl_check.status().is_success() {
|
|
||||||
return Err(anyhow!(
|
|
||||||
"ACL check failed with response code: {}",
|
|
||||||
acl_check.status()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let acls: Vec<String> = acl_check.json().await?;
|
|
||||||
|
|
||||||
for acl in REQUIRED_ACLS {
|
|
||||||
if !acls.contains(&acl.to_string()) {
|
|
||||||
return Err(anyhow!("Token missing {} acl", acl));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct ServerConfiguration {
|
|
||||||
pub endpoint: String,
|
|
||||||
pub token: String,
|
|
||||||
}
|
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
pub mod configure;
|
pub mod config;
|
||||||
pub mod upload;
|
pub mod upload;
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::UploadInfo, commands::upload::{s3::S3, uploadable::Uploadable}, config::config::Config, manifest::generate_manifest
|
cli::UploadInfo,
|
||||||
|
commands::config::config::Config,
|
||||||
|
commands::upload::{s3::S3, uploadable::Uploadable},
|
||||||
|
manifest::generate_manifest,
|
||||||
};
|
};
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
|
commands::config::s3::S3Config,
|
||||||
commands::upload::{
|
commands::upload::{
|
||||||
speedtest::{SPEEDTEST_PATH, Speedtest},
|
speedtest::{SPEEDTEST_PATH, Speedtest},
|
||||||
uploadable::Uploadable,
|
uploadable::Uploadable,
|
||||||
}, config::s3::S3Config,
|
},
|
||||||
};
|
};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use droplet_rs::manifest::{ChunkData, Manifest};
|
use droplet_rs::manifest::{ChunkData, Manifest};
|
||||||
|
|||||||
@@ -30,4 +30,4 @@ impl Speedtest {
|
|||||||
to_write: SPEEDTEST_BYTES,
|
to_write: SPEEDTEST_BYTES,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,5 +11,10 @@ pub trait Uploadable {
|
|||||||
chunk: &ChunkData,
|
chunk: &ChunkData,
|
||||||
) -> anyhow::Result<()>;
|
) -> anyhow::Result<()>;
|
||||||
async fn upload_speedtest(&mut self) -> anyhow::Result<()>;
|
async fn upload_speedtest(&mut self) -> anyhow::Result<()>;
|
||||||
async fn upload_manifest(&mut self, manifest: Manifest, game_id: &String, version_id: &String) -> anyhow::Result<()>;
|
async fn upload_manifest(
|
||||||
|
&mut self,
|
||||||
|
manifest: Manifest,
|
||||||
|
game_id: &String,
|
||||||
|
version_id: &String,
|
||||||
|
) -> anyhow::Result<()>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
pub trait Configurable {
|
|
||||||
type Out;
|
|
||||||
fn configure(self) -> Self::Out;
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
use clap::Args;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Args, Clone)]
|
|
||||||
pub struct ServerConfig {
|
|
||||||
/// Endpoint of the Drop server
|
|
||||||
url: String,
|
|
||||||
#[arg(short, long)]
|
|
||||||
token: String,
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,6 @@ use std::env;
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
|
|
||||||
pub fn configure_logging() -> anyhow::Result<()> {
|
pub fn configure_logging() -> anyhow::Result<()> {
|
||||||
let log_level = env::var("RUST_LOG")
|
let log_level = env::var("RUST_LOG")
|
||||||
.unwrap_or_else(|_| "info".to_string())
|
.unwrap_or_else(|_| "info".to_string())
|
||||||
|
|||||||
+10
-10
@@ -1,13 +1,13 @@
|
|||||||
use crate::config::configure::Configurable;
|
use crate::commands::config::config_option::ConfigOptionCli;
|
||||||
|
use crate::commands::config::configure::Configurable;
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::{Cli, Commands},
|
cli::{Cli, Commands},
|
||||||
|
commands::config::config::Config,
|
||||||
commands::upload,
|
commands::upload,
|
||||||
config::config::Config,
|
|
||||||
};
|
};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
mod cli;
|
mod cli;
|
||||||
mod commands;
|
mod commands;
|
||||||
mod config;
|
|
||||||
mod logging;
|
mod logging;
|
||||||
mod manifest;
|
mod manifest;
|
||||||
|
|
||||||
@@ -19,13 +19,13 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
let mut config = Config::read();
|
let mut config = Config::read();
|
||||||
match &cli.command {
|
match &cli.command {
|
||||||
Commands::Configure { name, option } => match option {
|
Commands::Configure { name, option } => config.add_item(
|
||||||
config::config::ConfigOptionCli::Server(server_config) => todo!(),
|
name.clone(),
|
||||||
config::config::ConfigOptionCli::S3(s3_config_cli) => config.add_item(
|
match option {
|
||||||
name.clone(),
|
ConfigOptionCli::Server(server_config) => server_config.clone().configure().await?,
|
||||||
config::config::ConfigOption::S3(s3_config_cli.clone().configure()),
|
ConfigOptionCli::S3(s3_config_cli) => s3_config_cli.clone().configure().await?,
|
||||||
),
|
},
|
||||||
},
|
),
|
||||||
Commands::Upload(info) => {
|
Commands::Upload(info) => {
|
||||||
upload::interface::upload(info, config).await?;
|
upload::interface::upload(info, config).await?;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-3
@@ -1,6 +1,4 @@
|
|||||||
use std::{
|
use std::path::Path;
|
||||||
path::Path,
|
|
||||||
};
|
|
||||||
|
|
||||||
use droplet_rs::manifest::{Manifest, generate_manifest_rusty};
|
use droplet_rs::manifest::{Manifest, generate_manifest_rusty};
|
||||||
use indicatif::{ProgressBar, ProgressStyle};
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
|
|||||||
Reference in New Issue
Block a user