use log::{info, LevelFilter};
use structopt::StructOpt;
use simplelog::{SimpleLogger, Config as LogConfig};
use s3::{
creds::Credentials,
region::Region,
bucket::Bucket,
};
#[derive(Clone, PartialEq, Debug, StructOpt)]
pub struct Options {
#[structopt(long, env)]
pub access_key: String,
#[structopt(long, env)]
pub secret_key: String,
#[structopt(long, env="S3_BUCKET")]
pub bucket: String,
#[structopt(long, env="S3_REGION")]
pub region: String,
#[structopt(long, env="S3_ENDPOINT")]
pub endpoint: String,
#[structopt(subcommand)]
command: Command,
#[structopt(long, default_value="info")]
pub log_level: LevelFilter,
}
#[derive(Clone, PartialEq, Debug, StructOpt)]
pub enum Command {
List{
#[structopt(long, default_value="")]
prefix: String
},
Upload{
name: String,
file: String,
},
Download{
name: String,
file: String,
},
Delete{
name: String,
}
}
#[async_std::main]
async fn main() -> Result<(), anyhow::Error> {
let opts = Options::from_args();
let _ = SimpleLogger::init(opts.log_level, LogConfig::default());
let creds = Credentials::new(Some(&opts.access_key), Some(&opts.secret_key), None, None, None)?;
let region = Region::Custom{ region: opts.region, endpoint: opts.endpoint };
let bucket = Bucket::new(&opts.bucket, region, creds)?;
match &opts.command {
Command::List{ prefix } => {
for list in bucket.list(prefix.to_string(), None).await? {
println!("{:?}", list);
}
},
Command::Upload{ name, file } => {
info!("Loading file '{}'", file);
let data = std::fs::read(file)?;
info!("Uploading object: '{}'", name);
let (_, code) = bucket.put_object(name, &data).await?;
if code != 200 {
return Err(anyhow::anyhow!("Error uploading object: {}", code));
}
info!("Upload complete");
},
Command::Download{ name, file } => {
info!("Fetching object: '{}'", name);
let (data, code) = bucket.get_object(name).await?;
if code != 200 {
return Err(anyhow::anyhow!("Error fetching object: {}", code));
}
info!("Writing file: '{}'", file);
std::fs::write(file, data)?;
info!("File write done");
},
Command::Delete{ name } => {
let (_, code) = bucket.delete_object( name ).await?;
if code != 204 {
return Err(anyhow::anyhow!("Error deleting object: {}", code));
}
}
}
Ok(())
}