|
|
|
use std::collections::HashSet;
|
|
|
|
use std::env;
|
|
|
|
use std::path::Path;
|
|
|
|
|
|
|
|
use rusoto_core::Region;
|
|
|
|
use rusoto_core::request::HttpClient;
|
|
|
|
use rusoto_credential::StaticProvider;
|
|
|
|
use rusoto_s3::ListObjectsRequest;
|
|
|
|
use rusoto_s3::PutObjectRequest;
|
|
|
|
use rusoto_s3::S3;
|
|
|
|
use rusoto_s3::S3Client;
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
let region_name = env::var("NC_REGION").expect("export NC_REGION with the endpoint region");
|
|
|
|
let endpoint = env::var("NC_ENDPOINT").expect("export NC_ENDPOINT with the endpot URL");
|
|
|
|
let bucket = env::var("NC_BUCKET").expect("export NC_BUCKET with the bucket to be accessed");
|
|
|
|
let access_key = env::var("NC_ACCESS_KEY").expect("export NC_ACCESS_KEY with the access key to the bucket");
|
|
|
|
let secret_key = env::var("NC_SECRET_KEY").expect("export NC_SECRET_KEY with the secret key to the bucket");
|
|
|
|
|
|
|
|
println!("Accessing {}::{}",
|
|
|
|
region_name,
|
|
|
|
endpoint);
|
|
|
|
|
|
|
|
let region = Region::Custom {
|
|
|
|
name: region_name.to_owned(),
|
|
|
|
endpoint: endpoint.to_owned()
|
|
|
|
};
|
|
|
|
|
|
|
|
let client = S3Client::new_with(
|
|
|
|
HttpClient::new().expect("Failed to create http client"),
|
|
|
|
StaticProvider::new_minimal(access_key, secret_key),
|
|
|
|
region
|
|
|
|
);
|
|
|
|
|
|
|
|
let mut truncated = Some(true);
|
|
|
|
let mut start_at = None;
|
|
|
|
let mut files_dirs: HashSet<String> = HashSet::new();
|
|
|
|
let mut directory_files: HashSet<String> = HashSet::new();
|
|
|
|
|
|
|
|
while truncated.unwrap_or(false) {
|
|
|
|
let list_objects_request = ListObjectsRequest {
|
|
|
|
bucket: bucket.to_owned(),
|
|
|
|
marker: start_at,
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
println!("Request: {:?}", list_objects_request);
|
|
|
|
|
|
|
|
let result = client
|
|
|
|
.list_objects(list_objects_request)
|
|
|
|
.sync()
|
|
|
|
.expect("Can't list contents of buckets");
|
|
|
|
truncated = result.is_truncated;
|
|
|
|
start_at = result.next_marker;
|
|
|
|
|
|
|
|
result.contents
|
|
|
|
.expect("Didn't get any objects")
|
|
|
|
.iter()
|
|
|
|
.for_each(|item| {
|
|
|
|
let filename = item.key.as_ref().unwrap();
|
|
|
|
if filename.ends_with("/") {
|
|
|
|
files_dirs.insert(filename.clone());
|
|
|
|
} else {
|
|
|
|
let mut path = Path::new(filename);
|
|
|
|
while path.parent().is_some() {
|
|
|
|
directory_files.insert(path.parent().unwrap().to_str().unwrap().to_string() + "/");
|
|
|
|
path = path.parent().unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
let missing: HashSet<_> = directory_files.difference(&files_dirs).collect();
|
|
|
|
|
|
|
|
println!("Directories with files:\n{:#?}", directory_files);
|
|
|
|
println!("Directories with controllers:\n{:#?}", files_dirs);
|
|
|
|
println!("Difference:\n{:#?}", directory_files.difference(&files_dirs));
|
|
|
|
|
|
|
|
for control in missing.iter() {
|
|
|
|
println!("Creating {}", control);
|
|
|
|
let control_file = PutObjectRequest {
|
|
|
|
bucket: bucket.to_owned(),
|
|
|
|
content_type: Some("httpd/unix-directory".to_owned()),
|
|
|
|
content_length: Some(0),
|
|
|
|
key: control.to_string(),
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
match client.put_object(control_file).sync() {
|
|
|
|
Ok(_) => println!("Success!"),
|
|
|
|
Err(error) => println!("Failed to create file: {}", error)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|