Skip to content

Commit a77b0c4

Browse files
authored
BucketCreate and BucketDelete Commands (#129)
* BucketCreate and BucketDelete Commands * Bump version
1 parent 43964e0 commit a77b0c4

File tree

7 files changed

+396
-176
lines changed

7 files changed

+396
-176
lines changed

README.md

+28-21
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,17 @@ a `PUT` presigned URL, meaning they can upload to a specific key in S3 for the d
2727

2828
`Bucket` struct provides constructors for `path-style` paths, `subdomain` style is the default. `Bucket` exposes methods for configuring and accessing `path-style` configuration.
2929

30+
#### Buckets
31+
32+
| | |
33+
|----------|-------------------------------------------------------------------------------|
34+
| `create` | [async](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.create) |
35+
| `delete` | [async]((https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.delete)) |
36+
3037
#### Presign
3138

32-
| | |
33-
|-------|------------------------------------------------------------------------------------------------|
39+
| | |
40+
|-------|----------------------------------------------------------------------------------------|
3441
| `PUT` | [presign_put](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.presign_put) |
3542
| `GET` | [presign_get](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.presign_get) |
3643

@@ -39,8 +46,8 @@ a `PUT` presigned URL, meaning they can upload to a specific key in S3 for the d
3946
There are a few different options for getting an object. `sync` and `async` methods are generic over `std::io::Write`,
4047
while `tokio` methods are generic over `tokio::io::AsyncWriteExt`.
4148

42-
| | |
43-
|---------|------------------------------------------------------------------------------------------------------------------------------|
49+
| | |
50+
|---------|----------------------------------------------------------------------------------------------------------------------|
4451
| `async` | [get_object](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.get_object) |
4552
| `async` | [get_object_stream](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.get_object_stream) |
4653
| `sync` | [get_object_blocking](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.get_object_blocking) |
@@ -51,41 +58,41 @@ while `tokio` methods are generic over `tokio::io::AsyncWriteExt`.
5158

5259
Each `GET` method has a `PUT` companion `sync` and `async` methods are generic over `std::io::Read`. `async` `stream` methods are generic over `futures::io::AsyncReadExt`, while `tokio` methods are generic over `tokio::io::AsyncReadExt`.
5360

54-
| | |
55-
|---------|----------------------------------------------------------------------------------------------------------------------------------------------------|
56-
| `async` | [put_object](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.put_object) |
57-
| `async` | [put_object_with_content_type](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.put_object_with_content_type) |
58-
| `async` | [put_object_stream](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.put_object_stream) |
59-
| `sync` | [put_object_blocking](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.put_object_blocking) |
60-
| `sync` | [put_object_with_content_type_blocking](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.put_object_with_content_type_blocking) |
61-
| `sync` | [put_object_stream_blocking](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.put_object_stream_blocking) |
62-
| `tokio` | :x: [#110](https://github.com/durch/rust-s3/issues) - [tokio_put_object_stream](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.tokio_put_object_stream) |
61+
| | |
62+
|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
63+
| `async` | [put_object](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.put_object) |
64+
| `async` | [put_object_with_content_type](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.put_object_with_content_type) |
65+
| `async` | [put_object_stream](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.put_object_stream) |
66+
| `sync` | [put_object_blocking](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.put_object_blocking) |
67+
| `sync` | [put_object_with_content_type_blocking](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.put_object_with_content_type_blocking) |
68+
| `sync` | [put_object_stream_blocking](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.put_object_stream_blocking) |
69+
| `tokio` | :x: [#110](https://github.com/durch/rust-s3/issues) - [tokio_put_object_stream](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.tokio_put_object_stream) |
6370

6471
#### List
6572

66-
| | |
67-
|---------|----------------------------------------------------------------------------------------------------|
73+
| | |
74+
|---------|--------------------------------------------------------------------------------------------|
6875
| `async` | [list](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.list) |
6976
| `sync` | [list_blocking](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.list_blocking) |
7077

7178
#### DELETE
7279

73-
| | |
74-
|---------|----------------------------------------------------------------------------------------------------------------------|
80+
| | |
81+
|---------|--------------------------------------------------------------------------------------------------------------|
7582
| `async` | [delete_object](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.delete_object) |
7683
| `sync` | [delete_object_blocking](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.delete_object_blocking) |
7784

7885
#### Location
7986

80-
| | |
81-
|---------|------------------------------------------------------------------------------------------------------------|
87+
| | |
88+
|---------|----------------------------------------------------------------------------------------------------|
8289
| `async` | [location](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.location) |
8390
| `sync` | [location_blocking](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.location_blocking) |
8491

8592
#### Tagging
8693

87-
| | |
88-
|---------|--------------------------------------------------------------------------------------------------------------------------------|
94+
| | |
95+
|---------|------------------------------------------------------------------------------------------------------------------------|
8996
| `async` | [put_object_tagging](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.put_object_tagging) |
9097
| `sync` | [put_object_tagging_blocking](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.put_object_tagging_blocking) |
9198
| `async` | [get_object_tagging](https://docs.rs/rust-s3/s3/bucket/struct.Bucket.html#method.get_object_tagging) |

s3/Cargo.toml

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "rust-s3"
3-
version = "0.26.1"
3+
version = "0.26.2"
44
authors = ["Drazen Urch"]
55
description = "Tiny Rust library for working with Amazon S3 and compatible object storage APIs"
66
repository = "https://github.com/durch/rust-s3"
@@ -39,7 +39,8 @@ log = "0.4"
3939
percent-encoding = "2"
4040
async-std = "1"
4141
http = "0.2"
42-
cfg-if = "0.1"
42+
cfg-if = "1"
43+
uuid = "0.8"
4344

4445

4546
[features]
@@ -51,3 +52,4 @@ rustls-tls = ["reqwest/rustls-tls", "aws-creds/rustls-tls"]
5152

5253
[dev-dependencies]
5354
tokio = {version="0.2", features=["fs"]}
55+
uuid = { version="0.8", features=["v4"]}

s3/src/bucket.rs

+133-6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::collections::HashMap;
44
use std::mem;
55
use tokio::runtime::Runtime;
66

7+
use crate::bucket_ops::{BucketConfiguration, CreateBucketResponse};
78
use crate::command::Command;
89
use crate::creds::Credentials;
910
use crate::region::Region;
@@ -125,17 +126,79 @@ impl Bucket {
125126
);
126127
Ok(request.presigned()?)
127128
}
128-
/// Instantiate a new `Bucket`.
129+
/// Create a new `Bucket` and instantiate it
129130
///
130131
/// # Example
132+
/// ```rust,no_run
133+
/// use s3::{Bucket, BucketConfiguration};
134+
/// use s3::creds::Credentials;
135+
/// use s3::S3Error;
136+
///
137+
/// #[tokio::main]
138+
/// async fn main() -> Result<(), S3Error> {
139+
/// let bucket_name = "rust-s3-test";
140+
/// let region = "us-east-1".parse().unwrap();
141+
/// let credentials = Credentials::default().unwrap();
142+
/// let config = BucketConfiguration::default();
143+
///
144+
/// let create_bucket_response = Bucket::create(bucket_name, region, credentials, config).await.unwrap();
145+
/// Ok(())
146+
/// }
131147
/// ```
132-
/// # // Fake credentials so we don't access user's real credentials in tests
133-
/// # use std::env;
134-
/// # env::set_var("AWS_ACCESS_KEY_ID", "AKIAIOSFODNN7EXAMPLE");
135-
/// # env::set_var("AWS_SECRET_ACCESS_KEY", "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY");
148+
pub async fn create(
149+
name: &str,
150+
region: Region,
151+
credentials: Credentials,
152+
mut config: BucketConfiguration,
153+
) -> Result<CreateBucketResponse> {
154+
config.set_region(region.clone());
155+
let command = Command::CreateBucket { config };
156+
let bucket = Bucket::new(name, region, credentials)?;
157+
let request = Request::new(&bucket, "", command);
158+
let (data, response_code) = request.response_data_future(false).await?;
159+
let response_text = std::str::from_utf8(&data)?;
160+
Ok(CreateBucketResponse {
161+
bucket,
162+
response_text: response_text.to_string(),
163+
response_code,
164+
})
165+
}
166+
167+
/// Delete existing `Bucket`
168+
///
169+
/// # Example
170+
/// ```rust,no_run
171+
/// use s3::Bucket;
172+
/// use s3::creds::Credentials;
173+
/// use s3::S3Error;
174+
///
175+
/// #[tokio::main]
176+
/// async fn main() -> Result<(), S3Error> {
177+
/// let bucket_name = "rust-s3-test";
178+
/// let region = "us-east-1".parse().unwrap();
179+
/// let credentials = Credentials::default().unwrap();
180+
/// let bucket = Bucket::new(bucket_name, region, credentials).unwrap();
181+
///
182+
/// bucket.delete().await.unwrap();
183+
///
184+
/// Ok(())
185+
/// }
186+
/// ```
187+
pub async fn delete(&self) -> Result<u16> {
188+
let command = Command::DeleteBucket;
189+
let request = Request::new(self, "", command);
190+
let (_, response_code) = request.response_data_future(false).await?;
191+
Ok(response_code)
192+
}
193+
194+
/// Instantiate an existing `Bucket`.
195+
///
196+
/// # Example
197+
/// ```rust,no_run
136198
/// use s3::bucket::Bucket;
137199
/// use s3::creds::Credentials;
138200
///
201+
/// // Fake credentials so we don't access user's real credentials in tests
139202
/// let bucket_name = "rust-s3-test";
140203
/// let region = "us-east-1".parse().unwrap();
141204
/// let credentials = Credentials::default().unwrap();
@@ -1305,9 +1368,10 @@ impl Bucket {
13051368
#[cfg(test)]
13061369
mod test {
13071370

1308-
use crate::bucket::Bucket;
13091371
use crate::creds::Credentials;
13101372
use crate::region::Region;
1373+
use crate::Bucket;
1374+
use crate::BucketConfiguration;
13111375
use std::env;
13121376
use std::fs::File;
13131377
use std::io::prelude::*;
@@ -1544,4 +1608,67 @@ mod test {
15441608
let url = bucket.presign_get(s3_path, 86400).unwrap();
15451609
assert!(url.contains("/test%2Ftest.file?"))
15461610
}
1611+
1612+
#[tokio::test]
1613+
#[ignore]
1614+
async fn test_bucket_create_delete_default_region() {
1615+
let config = BucketConfiguration::default();
1616+
let response = Bucket::create(
1617+
&uuid::Uuid::new_v4().to_string(),
1618+
"us-east-1".parse().unwrap(),
1619+
test_aws_credentials(),
1620+
config,
1621+
)
1622+
.await
1623+
.unwrap();
1624+
1625+
assert_eq!(&response.response_text, "");
1626+
1627+
assert_eq!(response.response_code, 200);
1628+
1629+
let response_code = response.bucket.delete().await.unwrap();
1630+
assert!(response_code < 300);
1631+
}
1632+
1633+
#[tokio::test]
1634+
#[ignore]
1635+
async fn test_bucket_create_delete_non_default_region() {
1636+
let config = BucketConfiguration::default();
1637+
let response = Bucket::create(
1638+
&uuid::Uuid::new_v4().to_string(),
1639+
"eu-central-1".parse().unwrap(),
1640+
test_aws_credentials(),
1641+
config,
1642+
)
1643+
.await
1644+
.unwrap();
1645+
1646+
assert_eq!(&response.response_text, "");
1647+
1648+
assert_eq!(response.response_code, 200);
1649+
1650+
let response_code = response.bucket.delete().await.unwrap();
1651+
assert!(response_code < 300);
1652+
}
1653+
1654+
#[tokio::test]
1655+
#[ignore]
1656+
async fn test_bucket_create_delete_non_default_region_public() {
1657+
let config = BucketConfiguration::public();
1658+
let response = Bucket::create(
1659+
&uuid::Uuid::new_v4().to_string(),
1660+
"eu-central-1".parse().unwrap(),
1661+
test_aws_credentials(),
1662+
config,
1663+
)
1664+
.await
1665+
.unwrap();
1666+
1667+
assert_eq!(&response.response_text, "");
1668+
1669+
assert_eq!(response.response_code, 200);
1670+
1671+
let response_code = response.bucket.delete().await.unwrap();
1672+
assert!(response_code < 300);
1673+
}
15471674
}

0 commit comments

Comments
 (0)