Skip to content

Commit f13e958

Browse files
authored
JavaScript (v3): S3 - Audit 🧵 2/ (#6956)
* JavaScript (v3): S3 - Replace hard coded bucket names with env vars or allowable name. * JavaScript (v3): S3 - Update runners and bucket names to match latest guidance. * JavaScript (v3): S3 - Standardize multipart upload example. * JavaScript (v3): S3 - Update dependencies and add lib-storage. * JavaScript (v3): S3 - Standardize presigned-url upload example. * JavaScript (v3): S3 - Standardize presigned-url download example. * JavaScript (v3): S3 - Standardize multi-part download example. * JavaScript (v3): S3 - Add brief readme to the web example. * JavaScript (v3): S3 - Update multipart upload scenario. The multipart upload scenario was using the lower level "CreateMultipartUpload" API. The JS SDK provides an 'Upload' API as part of 'lib-storage' that simplifies this process. This change replaces the existing example with the lib-storage usage and adds a progress bar util.
1 parent 833fc88 commit f13e958

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+995
-382
lines changed
Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,50 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
3+
import readline from "readline";
4+
35
import { parseString } from "@aws-doc-sdk-examples/lib/utils/util-string.js";
46

5-
const log = (str) => {
7+
export const log = (str) => {
68
const parsed = parseString(str);
79
console.log(parsed);
810
return parsed;
911
};
1012

11-
export { log };
13+
export class ProgressBar {
14+
/**
15+
* Create a progress bar that will display in the console.
16+
* @param {Object} config
17+
* @param {string} config.description - The text that will display next to the progress bar.
18+
* @param {number} config.barLength - The length, in characters, of the progress bar.
19+
*/
20+
constructor({ description, barLength }) {
21+
this._currentProgress = 0;
22+
this._barLength = barLength;
23+
this._description = description;
24+
}
25+
26+
/**
27+
* @param {{ current: number, total: number }} event
28+
*/
29+
update({ current, total }) {
30+
this._currentProgress = current / total;
31+
this._render();
32+
}
33+
34+
_render() {
35+
readline.cursorTo(process.stdout, 0);
36+
readline.clearLine(process.stdout, 0);
37+
38+
const filledLength = Math.round(this._barLength * this._currentProgress);
39+
const bar =
40+
"█".repeat(filledLength) + " ".repeat(this._barLength - filledLength);
41+
42+
process.stdout.write(
43+
`${this._description} [${bar}] ${this._currentProgress * 100}%`,
44+
);
45+
46+
if (this._currentProgress === 1) {
47+
process.stdout.write("\n");
48+
}
49+
}
50+
}

javascriptv3/example_code/libs/utils/util-node.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ export const validateArgs = (config, results) => {
3535

3636
if (optionRequired && !optionPresent) {
3737
errors = errors ?? [];
38-
errors.push(`Missing required argument "${option}".`);
38+
errors.push(`Missing required argument "--${option}".`);
3939
}
40-
41-
return { errors };
4240
}
41+
42+
return { errors };
4343
};

javascriptv3/example_code/s3/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ Code excerpts that show you how to call individual service functions.
4747

4848
- [CopyObject](actions/copy-object.js#L4)
4949
- [CreateBucket](actions/create-bucket.js#L4)
50-
- [DeleteBucket](actions/delete-bucket.js#L6)
50+
- [DeleteBucket](actions/delete-bucket.js#L4)
5151
- [DeleteBucketPolicy](actions/delete-bucket-policy.js#L4)
5252
- [DeleteBucketWebsite](actions/delete-bucket-website.js#L4)
5353
- [DeleteObject](actions/delete-object.js#L4)

javascriptv3/example_code/s3/actions/copy-object.js

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,28 +54,41 @@ export const main = async ({
5454
// snippet-end:[s3.JavaScript.buckets.copyObjectV3]
5555

5656
// Call function if run directly
57-
import { fileURLToPath } from "url";
5857
import { parseArgs } from "util";
58+
import {
59+
isMain,
60+
validateArgs,
61+
} from "@aws-doc-sdk-examples/lib/utils/util-node.js";
5962

60-
if (process.argv[1] === fileURLToPath(import.meta.url)) {
63+
const loadArgs = () => {
6164
const options = {
62-
sourceBucket: {
65+
sourceBucketName: {
6366
type: "string",
64-
default: "source-bucket",
67+
required: true,
6568
},
6669
sourceKey: {
6770
type: "string",
68-
default: "todo.txt",
71+
required: true,
6972
},
7073
destinationBucket: {
7174
type: "string",
72-
default: "destination-bucket",
75+
required: true,
7376
},
7477
destinationKey: {
7578
type: "string",
76-
default: "todo.txt",
79+
required: true,
7780
},
7881
};
79-
const { values } = parseArgs({ options });
80-
main(values);
82+
const results = parseArgs({ options });
83+
const { errors } = validateArgs({ options }, results);
84+
return { errors, results };
85+
};
86+
87+
if (isMain(import.meta.url)) {
88+
const { errors, results } = loadArgs();
89+
if (!errors) {
90+
main(results.values);
91+
} else {
92+
console.error(errors.join("\n"));
93+
}
8194
}

javascriptv3/example_code/s3/actions/create-bucket.js

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,29 @@ export const main = async ({ bucketName }) => {
4949
// snippet-end:[s3.JavaScript.buckets.createBucketV3]
5050

5151
// Call function if run directly
52-
import { fileURLToPath } from "url";
5352
import { parseArgs } from "util";
53+
import {
54+
isMain,
55+
validateArgs,
56+
} from "@aws-doc-sdk-examples/lib/utils/util-node.js";
5457

55-
if (process.argv[1] === fileURLToPath(import.meta.url)) {
58+
const loadArgs = () => {
5659
const options = {
5760
bucketName: {
5861
type: "string",
59-
default: "bucket-name",
62+
required: true,
6063
},
6164
};
62-
const { values } = parseArgs({ options });
63-
main(values);
65+
const results = parseArgs({ options });
66+
const { errors } = validateArgs({ options }, results);
67+
return { errors, results };
68+
};
69+
70+
if (isMain(import.meta.url)) {
71+
const { errors, results } = loadArgs();
72+
if (!errors) {
73+
main(results.values);
74+
} else {
75+
console.error(errors.join("\n"));
76+
}
6477
}

javascriptv3/example_code/s3/actions/delete-bucket-policy.js

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,29 @@ export const main = async ({ bucketName }) => {
4242
// snippet-end:[s3.JavaScript.policy.deleteBucketPolicyV3]
4343

4444
// Call function if run directly
45-
import { fileURLToPath } from "url";
4645
import { parseArgs } from "util";
46+
import {
47+
isMain,
48+
validateArgs,
49+
} from "@aws-doc-sdk-examples/lib/utils/util-node.js";
4750

48-
if (process.argv[1] === fileURLToPath(import.meta.url)) {
51+
const loadArgs = () => {
4952
const options = {
5053
bucketName: {
5154
type: "string",
52-
default: "amzn-s3-demo-bucket",
55+
required: true,
5356
},
5457
};
55-
const { values } = parseArgs({ options });
56-
main(values);
58+
const results = parseArgs({ options });
59+
const { errors } = validateArgs({ options }, results);
60+
return { errors, results };
61+
};
62+
63+
if (isMain(import.meta.url)) {
64+
const { errors, results } = loadArgs();
65+
if (!errors) {
66+
main(results.values);
67+
} else {
68+
console.error(errors.join("\n"));
69+
}
5770
}

javascriptv3/example_code/s3/actions/delete-bucket-website.js

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,29 @@ export const main = async ({ bucketName }) => {
4646
// snippet-end:[s3.JavaScript.website.deleteBucketWebsiteV3]
4747

4848
// Call function if run directly
49-
import { fileURLToPath } from "url";
5049
import { parseArgs } from "util";
50+
import {
51+
isMain,
52+
validateArgs,
53+
} from "@aws-doc-sdk-examples/lib/utils/util-node.js";
5154

52-
if (process.argv[1] === fileURLToPath(import.meta.url)) {
55+
const loadArgs = () => {
5356
const options = {
5457
bucketName: {
5558
type: "string",
56-
default: "amzn-s3-demo-bucket",
59+
required: true,
5760
},
5861
};
59-
const { values } = parseArgs({ options });
60-
main(values);
62+
const results = parseArgs({ options });
63+
const { errors } = validateArgs({ options }, results);
64+
return { errors, results };
65+
};
66+
67+
if (isMain(import.meta.url)) {
68+
const { errors, results } = loadArgs();
69+
if (!errors) {
70+
main(results.values);
71+
} else {
72+
console.error(errors.join("\n"));
73+
}
6174
}
Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,69 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
import { fileURLToPath } from "url";
5-
64
// snippet-start:[s3.JavaScript.buckets.deleteBucketV3]
7-
import { DeleteBucketCommand, S3Client } from "@aws-sdk/client-s3";
8-
9-
const client = new S3Client({});
5+
import {
6+
DeleteBucketCommand,
7+
S3Client,
8+
S3ServiceException,
9+
} from "@aws-sdk/client-s3";
1010

11-
// Delete a bucket.
12-
export const main = async () => {
11+
/**
12+
* Delete an Amazon S3 bucket.
13+
* @param {{ bucketName: string }}
14+
*/
15+
export const main = async ({ bucketName }) => {
16+
const client = new S3Client({});
1317
const command = new DeleteBucketCommand({
14-
Bucket: "test-bucket",
18+
Bucket: bucketName,
1519
});
1620

1721
try {
18-
const response = await client.send(command);
19-
console.log(response);
20-
} catch (err) {
21-
console.error(err);
22+
await client.send(command);
23+
console.log(`Bucket was deleted.`);
24+
} catch (caught) {
25+
if (
26+
caught instanceof S3ServiceException &&
27+
caught.name === "NoSuchBucket"
28+
) {
29+
console.error(
30+
`Error from S3 while deleting bucket. The bucket doesn't exist.`,
31+
);
32+
} else if (caught instanceof S3ServiceException) {
33+
console.error(
34+
`Error from S3 while deleting the bucket. ${caught.name}: ${caught.message}`,
35+
);
36+
} else {
37+
throw caught;
38+
}
2239
}
2340
};
2441
// snippet-end:[s3.JavaScript.buckets.deleteBucketV3]
2542

26-
// Invoke main function if this file was run directly.
27-
if (process.argv[1] === fileURLToPath(import.meta.url)) {
28-
main();
43+
// Call function if run directly
44+
import { parseArgs } from "util";
45+
import {
46+
isMain,
47+
validateArgs,
48+
} from "@aws-doc-sdk-examples/lib/utils/util-node.js";
49+
50+
const loadArgs = () => {
51+
const options = {
52+
bucketName: {
53+
type: "string",
54+
required: true,
55+
},
56+
};
57+
const results = parseArgs({ options });
58+
const { errors } = validateArgs({ options }, results);
59+
return { errors, results };
60+
};
61+
62+
if (isMain(import.meta.url)) {
63+
const { errors, results } = loadArgs();
64+
if (!errors) {
65+
main(results.values);
66+
} else {
67+
console.error(errors.join("\n"));
68+
}
2969
}

javascriptv3/example_code/s3/actions/delete-object.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,20 +52,33 @@ export const main = async ({ bucketName, key }) => {
5252
// snippet-end:[s3.JavaScript.buckets.deleteobjectV3]
5353

5454
// Call function if run directly
55-
import { fileURLToPath } from "url";
5655
import { parseArgs } from "util";
56+
import {
57+
isMain,
58+
validateArgs,
59+
} from "@aws-doc-sdk-examples/lib/utils/util-node.js";
5760

58-
if (process.argv[1] === fileURLToPath(import.meta.url)) {
61+
const loadArgs = () => {
5962
const options = {
6063
bucketName: {
6164
type: "string",
62-
default: "amzn-s3-demo-bucket",
65+
required: true,
6366
},
6467
key: {
6568
type: "string",
66-
default: "todo.txt",
69+
required: true,
6770
},
6871
};
69-
const { values } = parseArgs({ options });
70-
main(values);
72+
const results = parseArgs({ options });
73+
const { errors } = validateArgs({ options }, results);
74+
return { errors, results };
75+
};
76+
77+
if (isMain(import.meta.url)) {
78+
const { errors, results } = loadArgs();
79+
if (!errors) {
80+
main(results.values);
81+
} else {
82+
console.error(errors.join("\n"));
83+
}
7184
}

javascriptv3/example_code/s3/actions/delete-objects.js

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,19 +60,29 @@ export const main = async ({ bucketName, keys }) => {
6060
Example usage:
6161
node delete-objects.js --bucketName amzn-s3-demo-bucket obj1.txt obj2.txt
6262
*/
63-
import { fileURLToPath } from "url";
6463
import { parseArgs } from "util";
64+
import {
65+
isMain,
66+
validateArgs,
67+
} from "@aws-doc-sdk-examples/lib/utils/util-node.js";
6568

66-
if (process.argv[1] === fileURLToPath(import.meta.url)) {
69+
const loadArgs = () => {
6770
const options = {
6871
bucketName: {
6972
type: "string",
70-
default: "amzn-s3-demo-bucket",
73+
required: true,
7174
},
7275
};
73-
const { values, positionals } = parseArgs({
74-
options,
75-
allowPositionals: true,
76-
});
77-
main({ ...values, keys: positionals });
76+
const results = parseArgs({ options, allowPositionals: true });
77+
const { errors } = validateArgs({ options }, results);
78+
return { errors, results };
79+
};
80+
81+
if (isMain(import.meta.url)) {
82+
const { errors, results } = loadArgs();
83+
if (!errors) {
84+
main({ ...results.values, keys: results.positionals });
85+
} else {
86+
console.error(errors.join("\n"));
87+
}
7888
}

0 commit comments

Comments
 (0)