From e9f69cb1bffbf9401377ed5f029e87e78372e180 Mon Sep 17 00:00:00 2001 From: Eric Shepherd Date: Fri, 10 Oct 2025 15:40:56 +0000 Subject: [PATCH 1/4] S3TM examples for Swift --- .../download-streaming/Package.swift | 51 +++++++ .../download-streaming/Sources/Example.swift | 134 ++++++++++++++++++ .../download-streaming/Sources/entry.swift | 47 ++++++ .../upload-file/Package.swift | 51 +++++++ .../upload-file/Sources/Example.swift | 77 ++++++++++ .../upload-file/Sources/entry.swift | 49 +++++++ 6 files changed, 409 insertions(+) create mode 100644 swift/example_code/s3-transfer-manager/download-streaming/Package.swift create mode 100644 swift/example_code/s3-transfer-manager/download-streaming/Sources/Example.swift create mode 100644 swift/example_code/s3-transfer-manager/download-streaming/Sources/entry.swift create mode 100644 swift/example_code/s3-transfer-manager/upload-file/Package.swift create mode 100644 swift/example_code/s3-transfer-manager/upload-file/Sources/Example.swift create mode 100644 swift/example_code/s3-transfer-manager/upload-file/Sources/entry.swift diff --git a/swift/example_code/s3-transfer-manager/download-streaming/Package.swift b/swift/example_code/s3-transfer-manager/download-streaming/Package.swift new file mode 100644 index 00000000000..7875abf7282 --- /dev/null +++ b/swift/example_code/s3-transfer-manager/download-streaming/Package.swift @@ -0,0 +1,51 @@ +// swift-tools-version: 5.9 +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +// +// (swift-tools-version has two lines here because it needs to be the first +// line in the file, but it should also appear in the snippet below) +// +// snippet-start:[swift.rds.scenario.package] +// swift-tools-version: 5.9 +// +// The swift-tools-version declares the minimum version of Swift required to +// build this package. + +import PackageDescription + +let package = Package( + name: "getbucket", + // Let Xcode know the minimum Apple platforms supported. + platforms: [ + .macOS(.v13), + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + .package( + url: "https://github.com/awslabs/aws-sdk-swift", + from: "1.4.0"), + .package( + url: "https://github.com/aws/aws-sdk-swift-s3-transfer-manager.git", + branch: "main" + ), + .package( + url: "https://github.com/apple/swift-argument-parser.git", + branch: "main" + ) + ], + targets: [ + // Targets are the basic building blocks of a package, defining a module or a test suite. + // Targets can depend on other targets in this package and products + // from dependencies. + .executableTarget( + name: "getbucket", + dependencies: [ + .product(name: "AWSS3", package: "aws-sdk-swift"), + .product(name: "S3TransferManager", package: "aws-sdk-swift-s3-transfer-manager"), + .product(name: "ArgumentParser", package: "swift-argument-parser") + ], + path: "Sources") + + ] +) +// snippet-end:[swift.rds.scenario.package] diff --git a/swift/example_code/s3-transfer-manager/download-streaming/Sources/Example.swift b/swift/example_code/s3-transfer-manager/download-streaming/Sources/Example.swift new file mode 100644 index 00000000000..311e2081a88 --- /dev/null +++ b/swift/example_code/s3-transfer-manager/download-streaming/Sources/Example.swift @@ -0,0 +1,134 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +// +// The main code for the streaming bucket download example for the +// S3 Transfer Manager in the AWS SDK for Swift. + +// snippet-start:[swift.s3tm.streaming.imports] +import AWSS3 +import S3TransferManager +import Foundation +// snippet-end:[swift.s3tm.streaming.imports] + +class Example { + let region: String + let bucketName: String + + init(region: String, bucket: String) { + self.region = region + self.bucketName = bucket + } + + /// The body of the example. + func run() async throws { + // snippet-start:[swift.s3tm.streaming.config-create] + let s3Config = try await S3Client.S3ClientConfiguration( + region: region + ) + + // Create an S3TransferManager object. + + let s3tmConfig = try await S3TransferManagerConfig( + s3ClientConfig: s3Config, // Configuration for the S3Client + targetPartSizeBytes: 16 * 1024 * 1024, // 16 MB part size + multipartUploadThresholdBytes: 128 * 1024 * 1024, // 128 MB threshold + multipartDownloadType: .part + ) + + let s3tm = S3TransferManager(config: s3tmConfig) + // snippet-end:[swift.s3tm.streaming.config-create] + + // Create a listener for events from the download of the bucket, to + // monitor the overall state of the download. + + // snippet-start:[swift.s3tm.streaming.bucket-listener] + let downloadBucketStreamingTransferListener = DownloadBucketStreamingTransferListener() + + Task { + for try await downloadBucketTransferEvent in downloadBucketStreamingTransferListener.eventStream { + switch downloadBucketTransferEvent { + case .initiated(let input, _): + print("Download of bucket \(input.bucket) started...") + + case .complete(let input, _, let snapshot): + print("Download of bucket \(input.bucket) complete. Downloaded \(snapshot.transferredFiles) files.") + downloadBucketStreamingTransferListener.closeStream() + + case .failed(let input, let snapshot): + print("*** Download of bucket \(input.bucket) failed after downloading \(snapshot.transferredFiles) files.") + downloadBucketStreamingTransferListener.closeStream() + } + } + } + // snippet-end:[swift.s3tm.streaming.bucket-listener] + + // Create the directory to download the bucket into. The new directory + // is placed into the user's Downloads folder and has the same name as + // the bucket being downloaded. + + guard let downloadsDirectory = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first else { + print("*** Unable to locate the Downloads directory.") + return + } + + let targetDirectory = downloadsDirectory.appending(component: bucketName, directoryHint: .isDirectory) + try FileManager.default.createDirectory(at: targetDirectory, withIntermediateDirectories: true) + + // Start downloading the bucket by calling S3TransferManager.downloadBucket(input:). + + // snippet-start:[swift.s3tm.streaming.downloadBucket] + let downloadBucketTask = try s3tm.downloadBucket( + input: DownloadBucketInput( + bucket: bucketName, + destination: targetDirectory, + // The listener for the overall bucket download process. + directoryTransferListeners: [downloadBucketStreamingTransferListener], + // A factory that creates a listener for each file being downloaded. + objectTransferListenerFactory: { + let objectListener = DownloadObjectStreamingTransferListener() + + Task { + for try await downloadObjectTransferEvent in objectListener.eventStream { + switch downloadObjectTransferEvent { + // The download of a file has begun. + case .initiated(let input, _): + print(" Downloading file \(input.key)...") + + // The number of bytes received so far has been updated. + case .bytesTransferred(let input, let snapshot): + print(" Transferred \(snapshot.transferredBytes) total bytes of file \(input.key)...") + + // A file download has completed. + case .complete(let input, _, let snapshot): + print(" Finished downloading file \(input.key) (\(snapshot.transferredBytes) bytes).") + objectListener.closeStream() + + // The download of the file has failed. + case .failed(let input, let snapshot): + print("*** Download of file \(input.key) failed after \(snapshot.transferredBytes) bytes.") + objectListener.closeStream() + } + } + } + + return [ + objectListener + ] + } + ) + ) + // snippet-end:[swift.s3tm.streaming.downloadBucket] + + // Wait for the bucket to finish downloading, then display the results. + + // snippet-start:[swift.s3tm.streaming.wait-for-download] + do { + let downloadBucketOutput = try await downloadBucketTask.value + print("Total files downloaded: \(downloadBucketOutput.objectsDownloaded)") + print("Number of failed downloads: \(downloadBucketOutput.objectsFailed)") + } catch { + print("*** Error downloading the bucket: \(error.localizedDescription)") + } + // snippet-end:[swift.s3tm.streaming.wait-for-download] + } +} diff --git a/swift/example_code/s3-transfer-manager/download-streaming/Sources/entry.swift b/swift/example_code/s3-transfer-manager/download-streaming/Sources/entry.swift new file mode 100644 index 00000000000..37f0aff6e83 --- /dev/null +++ b/swift/example_code/s3-transfer-manager/download-streaming/Sources/entry.swift @@ -0,0 +1,47 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import ArgumentParser +import Foundation + +struct ExampleCommand: ParsableCommand { + @Option(help: "AWS Region name") + var region = "us-east-1" + @Argument(help: "Name of the Amazon S3 bucket to download") + var bucketName: String + + static var configuration = CommandConfiguration( + commandName: "getbucket", + abstract: """ + Downloads a bucket from Amazon S3 using the S3 Transfer Manager. + """, + discussion: """ + """ + ) + + /// Called by ``main()`` to do the actual running of the AWS + /// example. + func runAsync() async throws { + let example = Example(region: region, bucket: bucketName) + + try await example.run() + } +} + +/// The program's asynchronous entry point. +@main +struct Main { + /// The function that serves as the main asynchronous entry point for the + /// example. It parses the command line using the Swift Argument Parser, + /// then calls the `runAsync()` function to run the example itself. + static func main() async { + let args = Array(CommandLine.arguments.dropFirst()) + + do { + let command = try ExampleCommand.parse(args) + try await command.runAsync() + } catch { + ExampleCommand.exit(withError: error) + } + } +} diff --git a/swift/example_code/s3-transfer-manager/upload-file/Package.swift b/swift/example_code/s3-transfer-manager/upload-file/Package.swift new file mode 100644 index 00000000000..65debdf1cc7 --- /dev/null +++ b/swift/example_code/s3-transfer-manager/upload-file/Package.swift @@ -0,0 +1,51 @@ +// swift-tools-version: 5.9 +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +// +// (swift-tools-version has two lines here because it needs to be the first +// line in the file, but it should also appear in the snippet below) +// +// snippet-start:[swift.rds.scenario.package] +// swift-tools-version: 5.9 +// +// The swift-tools-version declares the minimum version of Swift required to +// build this package. + +import PackageDescription + +let package = Package( + name: "putfile", + // Let Xcode know the minimum Apple platforms supported. + platforms: [ + .macOS(.v13), + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + .package( + url: "https://github.com/awslabs/aws-sdk-swift", + from: "1.4.0"), + .package( + url: "https://github.com/aws/aws-sdk-swift-s3-transfer-manager.git", + branch: "main" + ), + .package( + url: "https://github.com/apple/swift-argument-parser.git", + branch: "main" + ) + ], + targets: [ + // Targets are the basic building blocks of a package, defining a module or a test suite. + // Targets can depend on other targets in this package and products + // from dependencies. + .executableTarget( + name: "putfile", + dependencies: [ + .product(name: "AWSS3", package: "aws-sdk-swift"), + .product(name: "S3TransferManager", package: "aws-sdk-swift-s3-transfer-manager"), + .product(name: "ArgumentParser", package: "swift-argument-parser") + ], + path: "Sources") + + ] +) +// snippet-end:[swift.rds.scenario.package] diff --git a/swift/example_code/s3-transfer-manager/upload-file/Sources/Example.swift b/swift/example_code/s3-transfer-manager/upload-file/Sources/Example.swift new file mode 100644 index 00000000000..6450aacd622 --- /dev/null +++ b/swift/example_code/s3-transfer-manager/upload-file/Sources/Example.swift @@ -0,0 +1,77 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +// +// The main code for file upload download example for the S3 Transfer Manager +// in the AWS SDK for Swift. This example doesn't include progress monitoring. +// +// The bucket downloading example +// (swift/example_code/s3-transfer-manager/download-streaming) includes an +// example of how to use progress monitoring. + + +// snippet-start:[swift.s3tm.upload.imports] +import AWSS3 +import AWSClientRuntime +import S3TransferManager +import Foundation +import Smithy +import SmithyStreams +// snippet-end:[swift.s3tm.upload.imports] + +class Example { + let region: String + let filePath: String + let bucketName: String + + init(region: String, path: String, bucket: String) { + self.region = region + self.filePath = path + self.bucketName = bucket + } + + /// The body of the example. + func run() async throws { + // snippet-start:[swift.s3tm.upload.uploadObject] + let s3tm = try await S3TransferManager() + + let fileURL = URL(string: filePath) + guard let fileURL else { + print("*** The file at \(filePath) doesn't exist.") + return + } + + // Prepare the upload request. + + let fileName = fileURL.lastPathComponent + let fileHandle = try FileHandle(forReadingFrom: fileURL) + let byteStream = ByteStream.stream(FileStream(fileHandle: fileHandle)) + + let uploadObjectInput = UploadObjectInput( + body: byteStream, + bucket: bucketName, + key: fileName, + transferListeners: [UploadObjectLoggingTransferListener()] + ) + + // Start the upload, then wait for it to complete. + + do { + let uploadObjectTask = try s3tm.uploadObject( + input: uploadObjectInput + ) + + _ = try await uploadObjectTask.value + } catch let error as AWSServiceError { + if error.errorCode == "NoSuchBucket" { + print("*** The specified bucket, \(bucketName), doesn't exist.") + return + } else { + print("An unrecognized error occurred: \(error.message ?? "")") + return + } + } catch { + print("*** An error occurred uploading the file: \(error.localizedDescription)") + } + // snippet-end:[swift.s3tm.upload.uploadObject] + } +} diff --git a/swift/example_code/s3-transfer-manager/upload-file/Sources/entry.swift b/swift/example_code/s3-transfer-manager/upload-file/Sources/entry.swift new file mode 100644 index 00000000000..d71f60a1b30 --- /dev/null +++ b/swift/example_code/s3-transfer-manager/upload-file/Sources/entry.swift @@ -0,0 +1,49 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import ArgumentParser +import Foundation + +struct ExampleCommand: ParsableCommand { + @Option(help: "AWS Region name") + var region = "us-east-1" + @Argument(help: "Path of the file to write to Amazon S3") + var filePath: String + @Argument(help: "Name of the Amazon S3 bucket to upload the file to") + var bucketName: String + + static var configuration = CommandConfiguration( + commandName: "putfile", + abstract: """ + Writes a file into an Amazon S3 bucket using the S3 Transfer Manager. + """, + discussion: """ + """ + ) + + /// Called by ``main()`` to do the actual running of the AWS + /// example. + func runAsync() async throws { + let example = Example(region: region, path: filePath, bucket: bucketName) + + try await example.run() + } +} + +/// The program's asynchronous entry point. +@main +struct Main { + /// The function that serves as the main asynchronous entry point for the + /// example. It parses the command line using the Swift Argument Parser, + /// then calls the `runAsync()` function to run the example itself. + static func main() async { + let args = Array(CommandLine.arguments.dropFirst()) + + do { + let command = try ExampleCommand.parse(args) + try await command.runAsync() + } catch { + ExampleCommand.exit(withError: error) + } + } +} From 0e6213b855c7a50a1b37e0362506160f865c4e4d Mon Sep 17 00:00:00 2001 From: Eric Shepherd Date: Fri, 10 Oct 2025 15:47:47 +0000 Subject: [PATCH 2/4] Remove unused region argument --- .../s3-transfer-manager/upload-file/Sources/Example.swift | 4 +--- .../s3-transfer-manager/upload-file/Sources/entry.swift | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/swift/example_code/s3-transfer-manager/upload-file/Sources/Example.swift b/swift/example_code/s3-transfer-manager/upload-file/Sources/Example.swift index 6450aacd622..e162c08040b 100644 --- a/swift/example_code/s3-transfer-manager/upload-file/Sources/Example.swift +++ b/swift/example_code/s3-transfer-manager/upload-file/Sources/Example.swift @@ -19,12 +19,10 @@ import SmithyStreams // snippet-end:[swift.s3tm.upload.imports] class Example { - let region: String let filePath: String let bucketName: String - init(region: String, path: String, bucket: String) { - self.region = region + init(path: String, bucket: String) { self.filePath = path self.bucketName = bucket } diff --git a/swift/example_code/s3-transfer-manager/upload-file/Sources/entry.swift b/swift/example_code/s3-transfer-manager/upload-file/Sources/entry.swift index d71f60a1b30..ab03a5a510f 100644 --- a/swift/example_code/s3-transfer-manager/upload-file/Sources/entry.swift +++ b/swift/example_code/s3-transfer-manager/upload-file/Sources/entry.swift @@ -5,8 +5,6 @@ import ArgumentParser import Foundation struct ExampleCommand: ParsableCommand { - @Option(help: "AWS Region name") - var region = "us-east-1" @Argument(help: "Path of the file to write to Amazon S3") var filePath: String @Argument(help: "Name of the Amazon S3 bucket to upload the file to") @@ -24,7 +22,7 @@ struct ExampleCommand: ParsableCommand { /// Called by ``main()`` to do the actual running of the AWS /// example. func runAsync() async throws { - let example = Example(region: region, path: filePath, bucket: bucketName) + let example = Example(path: filePath, bucket: bucketName) try await example.run() } From 697e9d9ff0958d6685e4a6a17b7d95ce448bc836 Mon Sep 17 00:00:00 2001 From: Eric Shepherd Date: Thu, 16 Oct 2025 17:16:51 +0000 Subject: [PATCH 3/4] Clean up, add s3Prefix to downloader --- .../download-streaming/Package.swift | 11 ++--------- .../download-streaming/Sources/Example.swift | 9 ++++++--- .../download-streaming/Sources/entry.swift | 8 +++++--- .../s3-transfer-manager/upload-file/Package.swift | 4 ++-- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/swift/example_code/s3-transfer-manager/download-streaming/Package.swift b/swift/example_code/s3-transfer-manager/download-streaming/Package.swift index 7875abf7282..2520a1fb59c 100644 --- a/swift/example_code/s3-transfer-manager/download-streaming/Package.swift +++ b/swift/example_code/s3-transfer-manager/download-streaming/Package.swift @@ -2,19 +2,13 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 // -// (swift-tools-version has two lines here because it needs to be the first -// line in the file, but it should also appear in the snippet below) -// -// snippet-start:[swift.rds.scenario.package] -// swift-tools-version: 5.9 -// // The swift-tools-version declares the minimum version of Swift required to // build this package. import PackageDescription let package = Package( - name: "getbucket", + name: "downloadbucket", // Let Xcode know the minimum Apple platforms supported. platforms: [ .macOS(.v13), @@ -38,7 +32,7 @@ let package = Package( // Targets can depend on other targets in this package and products // from dependencies. .executableTarget( - name: "getbucket", + name: "downloadbucket", dependencies: [ .product(name: "AWSS3", package: "aws-sdk-swift"), .product(name: "S3TransferManager", package: "aws-sdk-swift-s3-transfer-manager"), @@ -48,4 +42,3 @@ let package = Package( ] ) -// snippet-end:[swift.rds.scenario.package] diff --git a/swift/example_code/s3-transfer-manager/download-streaming/Sources/Example.swift b/swift/example_code/s3-transfer-manager/download-streaming/Sources/Example.swift index 311e2081a88..b7dd5d38795 100644 --- a/swift/example_code/s3-transfer-manager/download-streaming/Sources/Example.swift +++ b/swift/example_code/s3-transfer-manager/download-streaming/Sources/Example.swift @@ -13,10 +13,12 @@ import Foundation class Example { let region: String let bucketName: String + let s3Prefix: String? - init(region: String, bucket: String) { + init(region: String, bucket: String, s3Prefix: String?) { self.region = region self.bucketName = bucket + self.s3Prefix = s3Prefix } /// The body of the example. @@ -81,6 +83,7 @@ class Example { input: DownloadBucketInput( bucket: bucketName, destination: targetDirectory, + s3Prefix: s3Prefix, // The listener for the overall bucket download process. directoryTransferListeners: [downloadBucketStreamingTransferListener], // A factory that creates a listener for each file being downloaded. @@ -92,7 +95,7 @@ class Example { switch downloadObjectTransferEvent { // The download of a file has begun. case .initiated(let input, _): - print(" Downloading file \(input.key)...") + print("Downloading file \(input.key)...") // The number of bytes received so far has been updated. case .bytesTransferred(let input, let snapshot): @@ -100,7 +103,7 @@ class Example { // A file download has completed. case .complete(let input, _, let snapshot): - print(" Finished downloading file \(input.key) (\(snapshot.transferredBytes) bytes).") + print("Finished downloading file \(input.key) (\(snapshot.transferredBytes) bytes).") objectListener.closeStream() // The download of the file has failed. diff --git a/swift/example_code/s3-transfer-manager/download-streaming/Sources/entry.swift b/swift/example_code/s3-transfer-manager/download-streaming/Sources/entry.swift index 37f0aff6e83..2305ebdb457 100644 --- a/swift/example_code/s3-transfer-manager/download-streaming/Sources/entry.swift +++ b/swift/example_code/s3-transfer-manager/download-streaming/Sources/entry.swift @@ -9,11 +9,13 @@ struct ExampleCommand: ParsableCommand { var region = "us-east-1" @Argument(help: "Name of the Amazon S3 bucket to download") var bucketName: String + @Argument(help: "Prefix to download (allows downloading a subset of the bucket)") + var s3Prefix: String? static var configuration = CommandConfiguration( - commandName: "getbucket", + commandName: "downloadbucket", abstract: """ - Downloads a bucket from Amazon S3 using the S3 Transfer Manager. + Downloads a bucket from Amazon S3 using the S3 Transfer Manager, with progress updates. """, discussion: """ """ @@ -22,7 +24,7 @@ struct ExampleCommand: ParsableCommand { /// Called by ``main()`` to do the actual running of the AWS /// example. func runAsync() async throws { - let example = Example(region: region, bucket: bucketName) + let example = Example(region: region, bucket: bucketName, s3Prefix: s3Prefix) try await example.run() } diff --git a/swift/example_code/s3-transfer-manager/upload-file/Package.swift b/swift/example_code/s3-transfer-manager/upload-file/Package.swift index 65debdf1cc7..25d39def45e 100644 --- a/swift/example_code/s3-transfer-manager/upload-file/Package.swift +++ b/swift/example_code/s3-transfer-manager/upload-file/Package.swift @@ -5,7 +5,7 @@ // (swift-tools-version has two lines here because it needs to be the first // line in the file, but it should also appear in the snippet below) // -// snippet-start:[swift.rds.scenario.package] +// snippet-start:[swift.s3tm.scenario.package] // swift-tools-version: 5.9 // // The swift-tools-version declares the minimum version of Swift required to @@ -48,4 +48,4 @@ let package = Package( ] ) -// snippet-end:[swift.rds.scenario.package] +// snippet-end:[swift.s3tm.scenario.package] From 5c32a00614c1c595d6b64eb0a2dafddaffdbaa67 Mon Sep 17 00:00:00 2001 From: Eric Shepherd Date: Fri, 17 Oct 2025 15:07:34 +0000 Subject: [PATCH 4/4] Revamp and enhance S3TM examples --- .../download-streaming/Package.swift | 4 +- .../download-streaming/Sources/Example.swift | 1 + .../download-streaming/Sources/entry.swift | 2 +- .../get-bucket/Package.swift | 44 ++++++++++++ .../get-bucket/Sources/Example.swift | 70 +++++++++++++++++++ .../get-bucket/Sources/entry.swift | 47 +++++++++++++ .../upload-file/Package.swift | 4 +- .../upload-file/Sources/entry.swift | 4 +- 8 files changed, 169 insertions(+), 7 deletions(-) create mode 100644 swift/example_code/s3-transfer-manager/get-bucket/Package.swift create mode 100644 swift/example_code/s3-transfer-manager/get-bucket/Sources/Example.swift create mode 100644 swift/example_code/s3-transfer-manager/get-bucket/Sources/entry.swift diff --git a/swift/example_code/s3-transfer-manager/download-streaming/Package.swift b/swift/example_code/s3-transfer-manager/download-streaming/Package.swift index 2520a1fb59c..3c4f09c68ad 100644 --- a/swift/example_code/s3-transfer-manager/download-streaming/Package.swift +++ b/swift/example_code/s3-transfer-manager/download-streaming/Package.swift @@ -8,7 +8,7 @@ import PackageDescription let package = Package( - name: "downloadbucket", + name: "download-streaming", // Let Xcode know the minimum Apple platforms supported. platforms: [ .macOS(.v13), @@ -32,7 +32,7 @@ let package = Package( // Targets can depend on other targets in this package and products // from dependencies. .executableTarget( - name: "downloadbucket", + name: "download-streaming", dependencies: [ .product(name: "AWSS3", package: "aws-sdk-swift"), .product(name: "S3TransferManager", package: "aws-sdk-swift-s3-transfer-manager"), diff --git a/swift/example_code/s3-transfer-manager/download-streaming/Sources/Example.swift b/swift/example_code/s3-transfer-manager/download-streaming/Sources/Example.swift index b7dd5d38795..8ec35afa99b 100644 --- a/swift/example_code/s3-transfer-manager/download-streaming/Sources/Example.swift +++ b/swift/example_code/s3-transfer-manager/download-streaming/Sources/Example.swift @@ -131,6 +131,7 @@ class Example { print("Number of failed downloads: \(downloadBucketOutput.objectsFailed)") } catch { print("*** Error downloading the bucket: \(error.localizedDescription)") + dump(error) } // snippet-end:[swift.s3tm.streaming.wait-for-download] } diff --git a/swift/example_code/s3-transfer-manager/download-streaming/Sources/entry.swift b/swift/example_code/s3-transfer-manager/download-streaming/Sources/entry.swift index 2305ebdb457..08cd8a40556 100644 --- a/swift/example_code/s3-transfer-manager/download-streaming/Sources/entry.swift +++ b/swift/example_code/s3-transfer-manager/download-streaming/Sources/entry.swift @@ -13,7 +13,7 @@ struct ExampleCommand: ParsableCommand { var s3Prefix: String? static var configuration = CommandConfiguration( - commandName: "downloadbucket", + commandName: "download-streaming", abstract: """ Downloads a bucket from Amazon S3 using the S3 Transfer Manager, with progress updates. """, diff --git a/swift/example_code/s3-transfer-manager/get-bucket/Package.swift b/swift/example_code/s3-transfer-manager/get-bucket/Package.swift new file mode 100644 index 00000000000..b0e3fc18b69 --- /dev/null +++ b/swift/example_code/s3-transfer-manager/get-bucket/Package.swift @@ -0,0 +1,44 @@ +// swift-tools-version: 5.9 +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +// +// The swift-tools-version declares the minimum version of Swift required to +// build this package. + +import PackageDescription + +let package = Package( + name: "get-bucket", + // Let Xcode know the minimum Apple platforms supported. + platforms: [ + .macOS(.v13), + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + .package( + url: "https://github.com/awslabs/aws-sdk-swift", + from: "1.4.0"), + .package( + url: "https://github.com/aws/aws-sdk-swift-s3-transfer-manager.git", + branch: "main" + ), + .package( + url: "https://github.com/apple/swift-argument-parser.git", + branch: "main" + ) + ], + targets: [ + // Targets are the basic building blocks of a package, defining a module or a test suite. + // Targets can depend on other targets in this package and products + // from dependencies. + .executableTarget( + name: "get-bucket", + dependencies: [ + .product(name: "AWSS3", package: "aws-sdk-swift"), + .product(name: "S3TransferManager", package: "aws-sdk-swift-s3-transfer-manager"), + .product(name: "ArgumentParser", package: "swift-argument-parser") + ], + path: "Sources") + + ] +) diff --git a/swift/example_code/s3-transfer-manager/get-bucket/Sources/Example.swift b/swift/example_code/s3-transfer-manager/get-bucket/Sources/Example.swift new file mode 100644 index 00000000000..7afb143c6aa --- /dev/null +++ b/swift/example_code/s3-transfer-manager/get-bucket/Sources/Example.swift @@ -0,0 +1,70 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +// +// The main code for the streaming bucket download example for the +// S3 Transfer Manager in the AWS SDK for Swift. + +// snippet-start:[swift.s3tm.getbucket.imports] +import AWSS3 +import S3TransferManager +import Foundation +// snippet-end:[swift.s3tm.getbucket.imports] + +class Example { + let region: String + let bucketName: String + + init(region: String, bucket: String) { + self.region = region + self.bucketName = bucket + } + + /// The body of the example. + func run() async throws { + // snippet-start:[swift.s3tm.getbucket.config-create] + // Create an S3ClientConfiguration object. + let s3Config = try await S3Client.S3ClientConfiguration( + region: region + ) + + // Create an S3TransferManager using the S3 configuration. + + let s3tmConfig = try await S3TransferManagerConfig( + s3ClientConfig: s3Config + ) + + let s3tm = S3TransferManager(config: s3tmConfig) + // snippet-end:[swift.s3tm.getbucket.config-create] + + // Create the directory to download the bucket into. The new directory + // is placed into the user's Downloads folder and has the same name as + // the bucket being downloaded. + + guard let downloadsDirectory = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first else { + print("*** Unable to locate the Downloads directory.") + return + } + + let targetDirectory = downloadsDirectory.appending(component: bucketName, directoryHint: .isDirectory) + try FileManager.default.createDirectory(at: targetDirectory, withIntermediateDirectories: true) + + // Start downloading the bucket by calling S3TransferManager.downloadBucket(input:). + + // snippet-start:[swift.s3tm.getbucket.downloadBucket] + let downloadBucketTask = try s3tm.downloadBucket( + input: DownloadBucketInput( + bucket: bucketName, + destination: targetDirectory + ) + ) + + do { + let downloadBucketOutput = try await downloadBucketTask.value + print("Total files downloaded: \(downloadBucketOutput.objectsDownloaded)") + print("Number of failed downloads: \(downloadBucketOutput.objectsFailed)") + } catch { + print("*** Error downloading the bucket: \(error.localizedDescription)") + } + // snippet-end:[swift.s3tm.getbucket.downloadBucket] + } +} diff --git a/swift/example_code/s3-transfer-manager/get-bucket/Sources/entry.swift b/swift/example_code/s3-transfer-manager/get-bucket/Sources/entry.swift new file mode 100644 index 00000000000..5c241f05931 --- /dev/null +++ b/swift/example_code/s3-transfer-manager/get-bucket/Sources/entry.swift @@ -0,0 +1,47 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import ArgumentParser +import Foundation + +struct ExampleCommand: ParsableCommand { + @Option(help: "AWS Region name") + var region = "us-east-1" + @Argument(help: "Name of the Amazon S3 bucket to download") + var bucketName: String + + static var configuration = CommandConfiguration( + commandName: "get-bucket", + abstract: """ + Quietly fetch an entire bucket from Amazon S3. + """, + discussion: """ + """ + ) + + /// Called by ``main()`` to do the actual running of the AWS + /// example. + func runAsync() async throws { + let example = Example(region: region, bucket: bucketName) + + try await example.run() + } +} + +/// The program's asynchronous entry point. +@main +struct Main { + /// The function that serves as the main asynchronous entry point for the + /// example. It parses the command line using the Swift Argument Parser, + /// then calls the `runAsync()` function to run the example itself. + static func main() async { + let args = Array(CommandLine.arguments.dropFirst()) + + do { + let command = try ExampleCommand.parse(args) + try await command.runAsync() + } catch { + ExampleCommand.exit(withError: error) + } + } +} diff --git a/swift/example_code/s3-transfer-manager/upload-file/Package.swift b/swift/example_code/s3-transfer-manager/upload-file/Package.swift index 25d39def45e..b8d1c792ee6 100644 --- a/swift/example_code/s3-transfer-manager/upload-file/Package.swift +++ b/swift/example_code/s3-transfer-manager/upload-file/Package.swift @@ -14,7 +14,7 @@ import PackageDescription let package = Package( - name: "putfile", + name: "upload-file", // Let Xcode know the minimum Apple platforms supported. platforms: [ .macOS(.v13), @@ -38,7 +38,7 @@ let package = Package( // Targets can depend on other targets in this package and products // from dependencies. .executableTarget( - name: "putfile", + name: "upload-file", dependencies: [ .product(name: "AWSS3", package: "aws-sdk-swift"), .product(name: "S3TransferManager", package: "aws-sdk-swift-s3-transfer-manager"), diff --git a/swift/example_code/s3-transfer-manager/upload-file/Sources/entry.swift b/swift/example_code/s3-transfer-manager/upload-file/Sources/entry.swift index ab03a5a510f..0895e5d69a6 100644 --- a/swift/example_code/s3-transfer-manager/upload-file/Sources/entry.swift +++ b/swift/example_code/s3-transfer-manager/upload-file/Sources/entry.swift @@ -11,9 +11,9 @@ struct ExampleCommand: ParsableCommand { var bucketName: String static var configuration = CommandConfiguration( - commandName: "putfile", + commandName: "upload-file", abstract: """ - Writes a file into an Amazon S3 bucket using the S3 Transfer Manager. + Uploads a file into an Amazon S3 bucket using the S3 Transfer Manager. """, discussion: """ """