diff --git a/Package.swift b/Package.swift index 90ace14b..78b1c36e 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.4 +// swift-tools-version:5.6 import PackageDescription @@ -9,6 +9,8 @@ let package = Package( .library(name: "AWSLambdaRuntime", targets: ["AWSLambdaRuntime"]), // this has all the main functionality for lambda and it does not link Foundation .library(name: "AWSLambdaRuntimeCore", targets: ["AWSLambdaRuntimeCore"]), + // plugin to package the lambda, creating an archive that can be uploaded to AWS + .plugin(name: "AWSLambdaPackager", targets: ["AWSLambdaPackager"]), // for testing only .library(name: "AWSLambdaTesting", targets: ["AWSLambdaTesting"]), ], @@ -16,6 +18,7 @@ let package = Package( .package(url: "https://github.com/apple/swift-nio.git", .upToNextMajor(from: "2.33.0")), .package(url: "https://github.com/apple/swift-log.git", .upToNextMajor(from: "1.4.2")), .package(url: "https://github.com/swift-server/swift-backtrace.git", .upToNextMajor(from: "1.2.3")), + .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"), ], targets: [ .target(name: "AWSLambdaRuntime", dependencies: [ @@ -31,6 +34,15 @@ let package = Package( .product(name: "NIOConcurrencyHelpers", package: "swift-nio"), .product(name: "NIOPosix", package: "swift-nio"), ]), + .plugin( + name: "AWSLambdaPackager", + capability: .command( + intent: .custom( + verb: "archive", + description: "Archive the Lambda binary and prepare it for uploading to AWS. Requires docker on macOS or non Amazonlinux 2 distributions." + ) + ) + ), .testTarget(name: "AWSLambdaRuntimeCoreTests", dependencies: [ .byName(name: "AWSLambdaRuntimeCore"), .product(name: "NIOTestUtils", package: "swift-nio"), @@ -47,7 +59,7 @@ let package = Package( ]), .testTarget(name: "AWSLambdaTestingTests", dependencies: ["AWSLambdaTesting"]), // for perf testing - .target(name: "MockServer", dependencies: [ + .executableTarget(name: "MockServer", dependencies: [ .product(name: "NIOHTTP1", package: "swift-nio"), .product(name: "NIO", package: "swift-nio"), ]), diff --git a/Package@swift-5.6.swift b/Package@swift-5.4.swift similarity index 80% rename from Package@swift-5.6.swift rename to Package@swift-5.4.swift index e0b7aaf2..90ace14b 100644 --- a/Package@swift-5.6.swift +++ b/Package@swift-5.4.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.6 +// swift-tools-version:5.4 import PackageDescription @@ -9,8 +9,6 @@ let package = Package( .library(name: "AWSLambdaRuntime", targets: ["AWSLambdaRuntime"]), // this has all the main functionality for lambda and it does not link Foundation .library(name: "AWSLambdaRuntimeCore", targets: ["AWSLambdaRuntimeCore"]), - // plugin to package the lambda, creating an archive that can be uploaded to AWS - .plugin(name: "AWSLambdaPackager", targets: ["AWSLambdaPackager"]), // for testing only .library(name: "AWSLambdaTesting", targets: ["AWSLambdaTesting"]), ], @@ -33,15 +31,6 @@ let package = Package( .product(name: "NIOConcurrencyHelpers", package: "swift-nio"), .product(name: "NIOPosix", package: "swift-nio"), ]), - .plugin( - name: "AWSLambdaPackager", - capability: .command( - intent: .custom( - verb: "archive", - description: "Archive the Lambda binary and prepare it for uploading to AWS. Requires docker on macOS or non Amazonlinux 2 distributions." - ) - ) - ), .testTarget(name: "AWSLambdaRuntimeCoreTests", dependencies: [ .byName(name: "AWSLambdaRuntimeCore"), .product(name: "NIOTestUtils", package: "swift-nio"), @@ -58,7 +47,7 @@ let package = Package( ]), .testTarget(name: "AWSLambdaTestingTests", dependencies: ["AWSLambdaTesting"]), // for perf testing - .executableTarget(name: "MockServer", dependencies: [ + .target(name: "MockServer", dependencies: [ .product(name: "NIOHTTP1", package: "swift-nio"), .product(name: "NIO", package: "swift-nio"), ]), diff --git a/Package@swift-5.5.swift b/Package@swift-5.5.swift new file mode 100644 index 00000000..90ace14b --- /dev/null +++ b/Package@swift-5.5.swift @@ -0,0 +1,55 @@ +// swift-tools-version:5.4 + +import PackageDescription + +let package = Package( + name: "swift-aws-lambda-runtime", + products: [ + // this library exports `AWSLambdaRuntimeCore` and adds Foundation convenience methods + .library(name: "AWSLambdaRuntime", targets: ["AWSLambdaRuntime"]), + // this has all the main functionality for lambda and it does not link Foundation + .library(name: "AWSLambdaRuntimeCore", targets: ["AWSLambdaRuntimeCore"]), + // for testing only + .library(name: "AWSLambdaTesting", targets: ["AWSLambdaTesting"]), + ], + dependencies: [ + .package(url: "https://github.com/apple/swift-nio.git", .upToNextMajor(from: "2.33.0")), + .package(url: "https://github.com/apple/swift-log.git", .upToNextMajor(from: "1.4.2")), + .package(url: "https://github.com/swift-server/swift-backtrace.git", .upToNextMajor(from: "1.2.3")), + ], + targets: [ + .target(name: "AWSLambdaRuntime", dependencies: [ + .byName(name: "AWSLambdaRuntimeCore"), + .product(name: "NIOCore", package: "swift-nio"), + .product(name: "NIOFoundationCompat", package: "swift-nio"), + ]), + .target(name: "AWSLambdaRuntimeCore", dependencies: [ + .product(name: "Logging", package: "swift-log"), + .product(name: "Backtrace", package: "swift-backtrace"), + .product(name: "NIOHTTP1", package: "swift-nio"), + .product(name: "NIOCore", package: "swift-nio"), + .product(name: "NIOConcurrencyHelpers", package: "swift-nio"), + .product(name: "NIOPosix", package: "swift-nio"), + ]), + .testTarget(name: "AWSLambdaRuntimeCoreTests", dependencies: [ + .byName(name: "AWSLambdaRuntimeCore"), + .product(name: "NIOTestUtils", package: "swift-nio"), + .product(name: "NIOFoundationCompat", package: "swift-nio"), + ]), + .testTarget(name: "AWSLambdaRuntimeTests", dependencies: [ + .byName(name: "AWSLambdaRuntimeCore"), + .byName(name: "AWSLambdaRuntime"), + ]), + // testing helper + .target(name: "AWSLambdaTesting", dependencies: [ + .byName(name: "AWSLambdaRuntime"), + .product(name: "NIO", package: "swift-nio"), + ]), + .testTarget(name: "AWSLambdaTestingTests", dependencies: ["AWSLambdaTesting"]), + // for perf testing + .target(name: "MockServer", dependencies: [ + .product(name: "NIOHTTP1", package: "swift-nio"), + .product(name: "NIO", package: "swift-nio"), + ]), + ] +) diff --git a/Sources/AWSLambdaRuntime/Docs.docc/index.md b/Sources/AWSLambdaRuntime/Docs.docc/index.md new file mode 100644 index 00000000..0470c73b --- /dev/null +++ b/Sources/AWSLambdaRuntime/Docs.docc/index.md @@ -0,0 +1,370 @@ +# ``AWSLambdaRuntime`` + +An implementation of the AWS Lambda Runtime API in Swift. + +## Overview + +Many modern systems have client components like iOS, macOS or watchOS applications as well as server components that those clients interact with. Serverless functions are often the easiest and most efficient way for client application developers to extend their applications into the cloud. + +Serverless functions are increasingly becoming a popular choice for running event-driven or otherwise ad-hoc compute tasks in the cloud. They power mission critical microservices and data intensive workloads. In many cases, serverless functions allow developers to more easily scale and control compute costs given their on-demand nature. + +When using serverless functions, attention must be given to resource utilization as it directly impacts the costs of the system. This is where Swift shines! With its low memory footprint, deterministic performance, and quick start time, Swift is a fantastic match for the serverless functions architecture. + +Combine this with Swift's developer friendliness, expressiveness, and emphasis on safety, and we have a solution that is great for developers at all skill levels, scalable, and cost effective. + +Swift AWS Lambda Runtime was designed to make building Lambda functions in Swift simple and safe. The library is an implementation of the [AWS Lambda Runtime API](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html) and uses an embedded asynchronous HTTP Client based on [SwiftNIO](http://github.com/apple/swift-nio) that is fine-tuned for performance in the AWS Runtime context. The library provides a multi-tier API that allows building a range of Lambda functions: From quick and simple closures to complex, performance-sensitive event handlers. + +## Getting started + +If you have never used AWS Lambda or Docker before, check out this [getting started guide](https://fabianfett.de/getting-started-with-swift-aws-lambda-runtime) which helps you with every step from zero to a running Lambda. + +First, create a SwiftPM project and pull Swift AWS Lambda Runtime as dependency into your project + + ```swift + // swift-tools-version:5.6 + + import PackageDescription + + let package = Package( + name: "my-lambda", + products: [ + .executable(name: "MyLambda", targets: ["MyLambda"]), + ], + dependencies: [ + .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "0.1.0"), + ], + targets: [ + .executableTarget(name: "MyLambda", dependencies: [ + .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"), + ]), + ] + ) + ``` + +Next, create a `main.swift` and implement your Lambda. + + ### Using Closures + + The simplest way to use `AWSLambdaRuntime` is to pass in a closure, for example: + + ```swift + // Import the module + import AWSLambdaRuntime + + // in this example we are receiving and responding with strings + Lambda.run { (context, name: String, callback: @escaping (Result) -> Void) in + callback(.success("Hello, \(name)")) + } + ``` + + More commonly, the event would be a JSON, which is modeled using `Codable`, for example: + + ```swift + // Import the module + import AWSLambdaRuntime + + // Request, uses Codable for transparent JSON encoding + private struct Request: Codable { + let name: String + } + + // Response, uses Codable for transparent JSON encoding + private struct Response: Codable { + let message: String + } + + // In this example we are receiving and responding with `Codable`. + Lambda.run { (context, request: Request, callback: @escaping (Result) -> Void) in + callback(.success(Response(message: "Hello, \(request.name)"))) + } + ``` + + Since most Lambda functions are triggered by events originating in the AWS platform like `SNS`, `SQS` or `APIGateway`, the [Swift AWS Lambda Events](http://github.com/swift-server/swift-aws-lambda-events) package includes an `AWSLambdaEvents` module that provides implementations for most common AWS event types further simplifying writing Lambda functions. For example, handling an `SQS` message: + +First, add a dependency on the event packages: + + ```swift + // swift-tools-version:5.6 + + import PackageDescription + + let package = Package( + name: "my-lambda", + products: [ + .executable(name: "MyLambda", targets: ["MyLambda"]), + ], + dependencies: [ + .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "0.1.0"), + ], + targets: [ + .executableTarget(name: "MyLambda", dependencies: [ + .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"), + .product(name: "AWSLambdaEvents", package: "swift-aws-lambda-runtime"), + ]), + ] + ) + ``` + + + ```swift + // Import the modules + import AWSLambdaRuntime + import AWSLambdaEvents + + // In this example we are receiving an SQS Event, with no response (Void). + Lambda.run { (context, message: SQS.Event, callback: @escaping (Result) -> Void) in + ... + callback(.success(Void())) + } + ``` + + Modeling Lambda functions as Closures is both simple and safe. Swift AWS Lambda Runtime will ensure that the user-provided code is offloaded from the network processing thread such that even if the code becomes slow to respond or gets hang, the underlying process can continue to function. This safety comes at a small performance penalty from context switching between threads. In many cases, the simplicity and safety of using the Closure based API is often preferred over the complexity of the performance-oriented API. + +### Using EventLoopLambdaHandler + + Performance sensitive Lambda functions may choose to use a more complex API which allows user code to run on the same thread as the networking handlers. Swift AWS Lambda Runtime uses [SwiftNIO](https://github.com/apple/swift-nio) as its underlying networking engine which means the APIs are based on [SwiftNIO](https://github.com/apple/swift-nio) concurrency primitives like the `EventLoop` and `EventLoopFuture`. For example: + + ```swift + // Import the modules + import AWSLambdaRuntime + import AWSLambdaEvents + import NIO + + // Our Lambda handler, conforms to EventLoopLambdaHandler + struct Handler: EventLoopLambdaHandler { + typealias In = SNS.Message // Request type + typealias Out = Void // Response type + + // In this example we are receiving an SNS Message, with no response (Void). + func handle(context: Lambda.Context, event: In) -> EventLoopFuture { + ... + context.eventLoop.makeSucceededFuture(Void()) + } + } + + Lambda.run(Handler()) + ``` + + Beyond the small cognitive complexity of using the `EventLoopFuture` based APIs, note these APIs should be used with extra care. An [`EventLoopLambdaHandler`][ellh] will execute the user code on the same `EventLoop` (thread) as the library, making processing faster but requiring the user code to never call blocking APIs as it might prevent the underlying process from functioning. + +## Deploying to AWS Lambda + +To deploy Lambda functions to AWS Lambda, you need to compile the code for Amazon Linux which is the OS used on AWS Lambda microVMs, package it as a Zip file, and upload to AWS. + +AWS offers several tools to interact and deploy Lambda functions to AWS Lambda including [SAM](https://aws.amazon.com/serverless/sam/) and the [AWS CLI](https://aws.amazon.com/cli/). + +To build the Lambda function for Amazon Linux, use the Docker image published by Swift.org on [Swift toolchains and Docker images for Amazon Linux 2](https://swift.org/download/). + +## Architecture + +The library defines three protocols for the implementation of a Lambda Handler. From low-level to more convenient: + +### ByteBufferLambdaHandler + +An `EventLoopFuture` based processing protocol for a Lambda that takes a `ByteBuffer` and returns a `ByteBuffer?` asynchronously. + +[`ByteBufferLambdaHandler`][bblh] is the lowest level protocol designed to power the higher level [`EventLoopLambdaHandler`][ellh] and [`LambdaHandler`][lh] based APIs. Users are not expected to use this protocol, though some performance sensitive applications that operate at the `ByteBuffer` level or have special serialization needs may choose to do so. + +```swift +public protocol ByteBufferLambdaHandler { + /// The Lambda handling method + /// Concrete Lambda handlers implement this method to provide the Lambda functionality. + /// + /// - parameters: + /// - context: Runtime `Context`. + /// - event: The event or request payload encoded as `ByteBuffer`. + /// + /// - Returns: An `EventLoopFuture` to report the result of the Lambda back to the runtime engine. + /// The `EventLoopFuture` should be completed with either a response encoded as `ByteBuffer` or an `Error` + func handle(context: Lambda.Context, event: ByteBuffer) -> EventLoopFuture +} +``` + +### EventLoopLambdaHandler + +[`EventLoopLambdaHandler`][ellh] is a strongly typed, `EventLoopFuture` based asynchronous processing protocol for a Lambda that takes a user defined `In` and returns a user defined `Out`. + +[`EventLoopLambdaHandler`][ellh] extends [`ByteBufferLambdaHandler`][bblh], providing `ByteBuffer` -> `In` decoding and `Out` -> `ByteBuffer?` encoding for `Codable` and `String`. + +[`EventLoopLambdaHandler`][ellh] executes the user provided Lambda on the same `EventLoop` as the core runtime engine, making the processing fast but requires more care from the implementation to never block the `EventLoop`. It is designed for performance sensitive applications that use `Codable` or `String` based Lambda functions. + +```swift +public protocol EventLoopLambdaHandler: ByteBufferLambdaHandler { + associatedtype In + associatedtype Out + + /// The Lambda handling method + /// Concrete Lambda handlers implement this method to provide the Lambda functionality. + /// + /// - parameters: + /// - context: Runtime `Context`. + /// - event: Event of type `In` representing the event or request. + /// + /// - Returns: An `EventLoopFuture` to report the result of the Lambda back to the runtime engine. + /// The `EventLoopFuture` should be completed with either a response of type `Out` or an `Error` + func handle(context: Lambda.Context, event: In) -> EventLoopFuture + + /// Encode a response of type `Out` to `ByteBuffer` + /// Concrete Lambda handlers implement this method to provide coding functionality. + /// - parameters: + /// - allocator: A `ByteBufferAllocator` to help allocate the `ByteBuffer`. + /// - value: Response of type `Out`. + /// + /// - Returns: A `ByteBuffer` with the encoded version of the `value`. + func encode(allocator: ByteBufferAllocator, value: Out) throws -> ByteBuffer? + + /// Decode a`ByteBuffer` to a request or event of type `In` + /// Concrete Lambda handlers implement this method to provide coding functionality. + /// + /// - parameters: + /// - buffer: The `ByteBuffer` to decode. + /// + /// - Returns: A request or event of type `In`. + func decode(buffer: ByteBuffer) throws -> In +} +``` + +### LambdaHandler + +[`LambdaHandler`][lh] is a strongly typed, completion handler based asynchronous processing protocol for a Lambda that takes a user defined `In` and returns a user defined `Out`. + +[`LambdaHandler`][lh] extends [`ByteBufferLambdaHandler`][bblh], performing `ByteBuffer` -> `In` decoding and `Out` -> `ByteBuffer` encoding for `Codable` and `String`. + +[`LambdaHandler`][lh] offloads the user provided Lambda execution to a `DispatchQueue` making processing safer but slower. + +```swift +public protocol LambdaHandler: EventLoopLambdaHandler { + /// Defines to which `DispatchQueue` the Lambda execution is offloaded to. + var offloadQueue: DispatchQueue { get } + + /// The Lambda handling method + /// Concrete Lambda handlers implement this method to provide the Lambda functionality. + /// + /// - parameters: + /// - context: Runtime `Context`. + /// - event: Event of type `In` representing the event or request. + /// - callback: Completion handler to report the result of the Lambda back to the runtime engine. + /// The completion handler expects a `Result` with either a response of type `Out` or an `Error` + func handle(context: Lambda.Context, event: In, callback: @escaping (Result) -> Void) +} +``` + +### Closures + +In addition to protocol-based Lambda, the library provides support for Closure-based ones, as demonstrated in the overview section above. Closure-based Lambdas are based on the [`LambdaHandler`][lh] protocol which mean they are safer. For most use cases, Closure-based Lambda is a great fit and users are encouraged to use them. + +The library includes implementations for `Codable` and `String` based Lambda. Since AWS Lambda is primarily JSON based, this covers the most common use cases. + +```swift +public typealias CodableClosure = (Lambda.Context, In, @escaping (Result) -> Void) -> Void +``` + +```swift +public typealias StringClosure = (Lambda.Context, String, @escaping (Result) -> Void) -> Void +``` + +This design allows for additional event types as well, and such Lambda implementation can extend one of the above protocols and provided their own `ByteBuffer` -> `In` decoding and `Out` -> `ByteBuffer` encoding. + +### Context + +When calling the user provided Lambda function, the library provides a `Context` class that provides metadata about the execution context, as well as utilities for logging and allocating buffers. + +```swift +public final class Context { + /// The request ID, which identifies the request that triggered the function invocation. + public let requestID: String + + /// The AWS X-Ray tracing header. + public let traceID: String + + /// The ARN of the Lambda function, version, or alias that's specified in the invocation. + public let invokedFunctionARN: String + + /// The timestamp that the function times out + public let deadline: DispatchWallTime + + /// For invocations from the AWS Mobile SDK, data about the Amazon Cognito identity provider. + public let cognitoIdentity: String? + + /// For invocations from the AWS Mobile SDK, data about the client application and device. + public let clientContext: String? + + /// `Logger` to log with + /// + /// - note: The `LogLevel` can be configured using the `LOG_LEVEL` environment variable. + public let logger: Logger + + /// The `EventLoop` the Lambda is executed on. Use this to schedule work with. + /// This is useful when implementing the `EventLoopLambdaHandler` protocol. + /// + /// - note: The `EventLoop` is shared with the Lambda runtime engine and should be handled with extra care. + /// Most importantly the `EventLoop` must never be blocked. + public let eventLoop: EventLoop + + /// `ByteBufferAllocator` to allocate `ByteBuffer` + /// This is useful when implementing `EventLoopLambdaHandler` + public let allocator: ByteBufferAllocator +} +``` + +### Configuration + +The library’s behavior can be fine tuned using environment variables based configuration. The library supported the following environment variables: + +* `LOG_LEVEL`: Define the logging level as defined by [SwiftLog](https://github.com/apple/swift-log). Set to INFO by default. +* `MAX_REQUESTS`: Max cycles the library should handle before exiting. Set to none by default. +* `STOP_SIGNAL`: Signal to capture for termination. Set to `TERM` by default. +* `REQUEST_TIMEOUT`: Max time to wait for responses to come back from the AWS Runtime engine. Set to none by default. + + +### AWS Lambda Runtime Engine Integration + +The library is designed to integrate with AWS Lambda Runtime Engine via the [AWS Lambda Runtime API](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html) which was introduced as part of [AWS Lambda Custom Runtimes](https://aws.amazon.com/about-aws/whats-new/2018/11/aws-lambda-now-supports-custom-runtimes-and-layers/) in 2018. The latter is an HTTP server that exposes three main RESTful endpoint: + +* `/runtime/invocation/next` +* `/runtime/invocation/response` +* `/runtime/invocation/error` + +A single Lambda execution workflow is made of the following steps: + +1. The library calls AWS Lambda Runtime Engine `/next` endpoint to retrieve the next invocation request. +2. The library parses the response HTTP headers and populate the `Context` object. +3. The library reads the `/next` response body and attempt to decode it. Typically it decodes to user provided `In` type which extends `Decodable`, but users may choose to write Lambda functions that receive the input as `String` or `ByteBuffer` which require less, or no decoding. +4. The library hands off the `Context` and `In` event to the user provided handler. In the case of [`LambdaHandler`][lh] based handler this is done on a dedicated `DispatchQueue`, providing isolation between user's and the library's code. +5. User provided handler processes the request asynchronously, invoking a callback or returning a future upon completion, which returns a `Result` type with the `Out` or `Error` populated. +6. In case of error, the library posts to AWS Lambda Runtime Engine `/error` endpoint to provide the error details, which will show up on AWS Lambda logs. +7. In case of success, the library will attempt to encode the response. Typically it encodes from user provided `Out` type which extends `Encodable`, but users may choose to write Lambda functions that return a `String` or `ByteBuffer`, which require less, or no encoding. The library then posts the response to AWS Lambda Runtime Engine `/response` endpoint to provide the response to the callee. + +The library encapsulates the workflow via the internal `LambdaRuntimeClient` and `LambdaRunner` structs respectively. + +### Lifecycle Management + +AWS Lambda Runtime Engine controls the Application lifecycle and in the happy case never terminates the application, only suspends its execution when no work is available. + +As such, the library's main entry point is designed to run forever in a blocking fashion, performing the workflow described above in an endless loop. + +That loop is broken if/when an internal error occurs, such as a failure to communicate with AWS Lambda Runtime Engine API, or under other unexpected conditions. + +By default, the library also registers a Signal handler that traps `INT` and `TERM`, which are typical Signals used in modern deployment platforms to communicate shutdown request. + +### Integration with AWS Platform Events + +AWS Lambda functions can be invoked directly from the AWS Lambda console UI, AWS Lambda API, AWS SDKs, AWS CLI, and AWS toolkits. More commonly, they are invoked as a reaction to an event coming from the AWS platform. To make it easier to integrate with AWS platform events, [Swift AWS Lambda Runtime Events](http://github.com/swift-server/swift-aws-lambda-events) library is available, designed to work together with this runtime library. [Swift AWS Lambda Runtime Events](http://github.com/swift-server/swift-aws-lambda-events) includes an `AWSLambdaEvents` target which provides abstractions for many commonly used events. + +## Performance + +Lambda functions performance is usually measured across two axes: + +- **Cold start times**: The time it takes for a Lambda function to startup, ask for an invocation and process the first invocation. + +- **Warm invocation times**: The time it takes for a Lambda function to process an invocation after the Lambda has been invoked at least once. + +Larger packages size (Zip file uploaded to AWS Lambda) negatively impact the cold start time, since AWS needs to download and unpack the package before starting the process. + +Swift provides great Unicode support via [ICU](http://site.icu-project.org/home). Therefore, Swift-based Lambda functions include the ICU libraries which tend to be large. This impacts the download time mentioned above and an area for further optimization. Some of the alternatives worth exploring are using the system ICU that comes with Amazon Linux (albeit older than the one Swift ships with) or working to remove the ICU dependency altogether. We welcome ideas and contributions to this end. + + + +[lh]: ./AWSLambdaRuntimeCore/Protocols/LambdaHandler.html +[ellh]: ./AWSLambdaRuntimeCore/Protocols/EventLoopLambdaHandler.html +[bblh]: ./AWSLambdaRuntimeCore/Protocols/ByteBufferLambdaHandler.html diff --git a/Sources/AWSLambdaRuntime/Lambda+Codable.swift b/Sources/AWSLambdaRuntime/Lambda+Codable.swift index ac9c70c6..219abe52 100644 --- a/Sources/AWSLambdaRuntime/Lambda+Codable.swift +++ b/Sources/AWSLambdaRuntime/Lambda+Codable.swift @@ -2,7 +2,7 @@ // // This source file is part of the SwiftAWSLambdaRuntime open source project // -// Copyright (c) 2017-2020 Apple Inc. and the SwiftAWSLambdaRuntime project authors +// Copyright (c) 2017-2022 Apple Inc. and the SwiftAWSLambdaRuntime project authors // Licensed under Apache License v2.0 // // See LICENSE.txt for license information @@ -21,7 +21,7 @@ import NIOFoundationCompat // MARK: - Codable support -/// Implementation of a`ByteBuffer` to `Event` decoding +/// Implementation of a`ByteBuffer` to `Event` decoding. extension EventLoopLambdaHandler where Event: Decodable { @inlinable public func decode(buffer: ByteBuffer) throws -> Event { @@ -29,7 +29,7 @@ extension EventLoopLambdaHandler where Event: Decodable { } } -/// Implementation of `Output` to `ByteBuffer` encoding +/// Implementation of `Output` to `ByteBuffer` encoding. extension EventLoopLambdaHandler where Output: Encodable { @inlinable public func encode(allocator: ByteBufferAllocator, value: Output) throws -> ByteBuffer? { @@ -37,7 +37,7 @@ extension EventLoopLambdaHandler where Output: Encodable { } } -/// Default `ByteBuffer` to `Event` decoder using Foundation's JSONDecoder +/// Default `ByteBuffer` to `Event` decoder using Foundation's `JSONDecoder`. /// Advanced users that want to inject their own codec can do it by overriding these functions. extension EventLoopLambdaHandler where Event: Decodable { public var decoder: LambdaCodableDecoder { @@ -45,7 +45,7 @@ extension EventLoopLambdaHandler where Event: Decodable { } } -/// Default `Output` to `ByteBuffer` encoder using Foundation's JSONEncoder +/// Default `Output` to `ByteBuffer` encoder using Foundation's `JSONEncoder`. /// Advanced users that want to inject their own codec can do it by overriding these functions. extension EventLoopLambdaHandler where Output: Encodable { public var encoder: LambdaCodableEncoder { diff --git a/Sources/AWSLambdaRuntimeCore/Lambda+String.swift b/Sources/AWSLambdaRuntimeCore/Lambda+String.swift index f5a68f27..8e3da3e5 100644 --- a/Sources/AWSLambdaRuntimeCore/Lambda+String.swift +++ b/Sources/AWSLambdaRuntimeCore/Lambda+String.swift @@ -2,7 +2,7 @@ // // This source file is part of the SwiftAWSLambdaRuntime open source project // -// Copyright (c) 2017-2018 Apple Inc. and the SwiftAWSLambdaRuntime project authors +// Copyright (c) 2017-2022 Apple Inc. and the SwiftAWSLambdaRuntime project authors // Licensed under Apache License v2.0 // // See LICENSE.txt for license information @@ -14,7 +14,7 @@ import NIOCore extension EventLoopLambdaHandler where Event == String { - /// Implementation of a `ByteBuffer` to `String` decoding + /// Implementation of a `ByteBuffer` to `String` decoding. @inlinable public func decode(buffer: ByteBuffer) throws -> String { var buffer = buffer @@ -26,7 +26,7 @@ extension EventLoopLambdaHandler where Event == String { } extension EventLoopLambdaHandler where Output == String { - /// Implementation of `String` to `ByteBuffer` encoding + /// Implementation of `String` to `ByteBuffer` encoding. @inlinable public func encode(allocator: ByteBufferAllocator, value: String) throws -> ByteBuffer? { // FIXME: reusable buffer diff --git a/Sources/AWSLambdaRuntimeCore/LambdaContext.swift b/Sources/AWSLambdaRuntimeCore/LambdaContext.swift index ae4e16e7..7118a5ac 100644 --- a/Sources/AWSLambdaRuntimeCore/LambdaContext.swift +++ b/Sources/AWSLambdaRuntimeCore/LambdaContext.swift @@ -2,7 +2,7 @@ // // This source file is part of the SwiftAWSLambdaRuntime open source project // -// Copyright (c) 2017-2020 Apple Inc. and the SwiftAWSLambdaRuntime project authors +// Copyright (c) 2017-2022 Apple Inc. and the SwiftAWSLambdaRuntime project authors // Licensed under Apache License v2.0 // // See LICENSE.txt for license information @@ -29,7 +29,7 @@ import NIOCore /// ``ByteBufferLambdaHandler/makeHandler(context:)`` or ``LambdaHandler/init(context:)`` /// as an argument. public struct LambdaInitializationContext: _AWSLambdaSendable { - /// `Logger` to log with + /// `Logger` to log with. /// /// - note: The `LogLevel` can be configured using the `LOG_LEVEL` environment variable. public let logger: Logger @@ -40,10 +40,10 @@ public struct LambdaInitializationContext: _AWSLambdaSendable { /// Most importantly the `EventLoop` must never be blocked. public let eventLoop: EventLoop - /// `ByteBufferAllocator` to allocate `ByteBuffer` + /// `ByteBufferAllocator` to allocate `ByteBuffer`. public let allocator: ByteBufferAllocator - /// ``LambdaTerminator`` to register shutdown operations + /// ``LambdaTerminator`` to register shutdown operations. public let terminator: LambdaTerminator init(logger: Logger, eventLoop: EventLoop, allocator: ByteBufferAllocator, terminator: LambdaTerminator) { @@ -70,7 +70,7 @@ public struct LambdaInitializationContext: _AWSLambdaSendable { // MARK: - Context /// Lambda runtime context. -/// The Lambda runtime generates and passes the `Context` to the Lambda handler as an argument. +/// The Lambda runtime generates and passes the `LambdaContext` to the Lambda handler as an argument. public struct LambdaContext: CustomDebugStringConvertible, _AWSLambdaSendable { final class _Storage: _AWSLambdaSendable { let requestID: String @@ -123,7 +123,7 @@ public struct LambdaContext: CustomDebugStringConvertible, _AWSLambdaSendable { self.storage.invokedFunctionARN } - /// The timestamp that the function times out + /// The timestamp that the function times out. public var deadline: DispatchWallTime { self.storage.deadline } @@ -138,7 +138,7 @@ public struct LambdaContext: CustomDebugStringConvertible, _AWSLambdaSendable { self.storage.clientContext } - /// `Logger` to log with + /// `Logger` to log with. /// /// - note: The `LogLevel` can be configured using the `LOG_LEVEL` environment variable. public var logger: Logger { @@ -146,7 +146,7 @@ public struct LambdaContext: CustomDebugStringConvertible, _AWSLambdaSendable { } /// The `EventLoop` the Lambda is executed on. Use this to schedule work with. - /// This is useful when implementing the `EventLoopLambdaHandler` protocol. + /// This is useful when implementing the ``EventLoopLambdaHandler`` protocol. /// /// - note: The `EventLoop` is shared with the Lambda runtime engine and should be handled with extra care. /// Most importantly the `EventLoop` must never be blocked. @@ -154,8 +154,8 @@ public struct LambdaContext: CustomDebugStringConvertible, _AWSLambdaSendable { self.storage.eventLoop } - /// `ByteBufferAllocator` to allocate `ByteBuffer` - /// This is useful when implementing `EventLoopLambdaHandler` + /// `ByteBufferAllocator` to allocate `ByteBuffer`. + /// This is useful when implementing ``EventLoopLambdaHandler``. public var allocator: ByteBufferAllocator { self.storage.allocator } diff --git a/Sources/AWSLambdaRuntimeCore/LambdaHandler.swift b/Sources/AWSLambdaRuntimeCore/LambdaHandler.swift index 48bdb9bf..8f4b9f6e 100644 --- a/Sources/AWSLambdaRuntimeCore/LambdaHandler.swift +++ b/Sources/AWSLambdaRuntimeCore/LambdaHandler.swift @@ -2,7 +2,7 @@ // // This source file is part of the SwiftAWSLambdaRuntime open source project // -// Copyright (c) 2017-2020 Apple Inc. and the SwiftAWSLambdaRuntime project authors +// Copyright (c) 2017-2022 Apple Inc. and the SwiftAWSLambdaRuntime project authors // Licensed under Apache License v2.0 // // See LICENSE.txt for license information @@ -27,20 +27,20 @@ import NIOCore /// ``ByteBufferLambdaHandler``. @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) public protocol LambdaHandler: EventLoopLambdaHandler { - /// The Lambda initialization method + /// The Lambda initialization method. /// Use this method to initialize resources that will be used in every request. /// /// Examples for this can be HTTP or database clients. /// - parameters: - /// - context: Runtime `InitializationContext`. + /// - context: Runtime ``LambdaInitializationContext``. init(context: LambdaInitializationContext) async throws - /// The Lambda handling method + /// The Lambda handling method. /// Concrete Lambda handlers implement this method to provide the Lambda functionality. /// /// - parameters: /// - event: Event of type `Event` representing the event or request. - /// - context: Runtime `Context`. + /// - context: Runtime ``LambdaContext``. /// /// - Returns: A Lambda result ot type `Output`. func handle(_ event: Event, context: LambdaContext) async throws -> Output @@ -101,40 +101,40 @@ fileprivate struct UncheckedSendableHandler EventLoopFuture - /// Encode a response of type ``Output`` to `ByteBuffer` + /// Encode a response of type ``Output`` to `ByteBuffer`. /// Concrete Lambda handlers implement this method to provide coding functionality. /// - parameters: /// - allocator: A `ByteBufferAllocator` to help allocate the `ByteBuffer`. - /// - value: Response of type `Output`. + /// - value: Response of type ``Output``. /// /// - Returns: A `ByteBuffer` with the encoded version of the `value`. func encode(allocator: ByteBufferAllocator, value: Output) throws -> ByteBuffer? - /// Decode a `ByteBuffer` to a request or event of type ``Event`` + /// Decode a `ByteBuffer` to a request or event of type ``Event``. /// Concrete Lambda handlers implement this method to provide coding functionality. /// /// - parameters: /// - buffer: The `ByteBuffer` to decode. /// - /// - Returns: A request or event of type `Event`. + /// - Returns: A request or event of type ``Event``. func decode(buffer: ByteBuffer) throws -> Event } @@ -159,7 +159,7 @@ extension EventLoopLambdaHandler { } } -/// Implementation of `ByteBuffer` to `Void` decoding +/// Implementation of `ByteBuffer` to `Void` decoding. extension EventLoopLambdaHandler where Output == Void { @inlinable public func encode(allocator: ByteBufferAllocator, value: Void) throws -> ByteBuffer? { @@ -184,20 +184,20 @@ public protocol ByteBufferLambdaHandler { /// minimizes thread hopping. static func makeHandler(context: LambdaInitializationContext) -> EventLoopFuture - /// The Lambda handling method + /// The Lambda handling method. /// Concrete Lambda handlers implement this method to provide the Lambda functionality. /// /// - parameters: - /// - context: Runtime `Context`. + /// - context: Runtime ``LambdaContext``. /// - event: The event or input payload encoded as `ByteBuffer`. /// /// - Returns: An `EventLoopFuture` to report the result of the Lambda back to the runtime engine. - /// The `EventLoopFuture` should be completed with either a response encoded as `ByteBuffer` or an `Error` + /// The `EventLoopFuture` should be completed with either a response encoded as `ByteBuffer` or an `Error`. func handle(_ event: ByteBuffer, context: LambdaContext) -> EventLoopFuture } extension ByteBufferLambdaHandler { - /// Initializes and runs the lambda function. + /// Initializes and runs the Lambda function. /// /// If you precede your ``ByteBufferLambdaHandler`` conformer's declaration with the /// [@main](https://docs.swift.org/swift-book/ReferenceManual/Attributes.html#ID626) diff --git a/Sources/AWSLambdaRuntimeCore/LambdaRuntime.swift b/Sources/AWSLambdaRuntimeCore/LambdaRuntime.swift index ce019532..cd2b9588 100644 --- a/Sources/AWSLambdaRuntimeCore/LambdaRuntime.swift +++ b/Sources/AWSLambdaRuntimeCore/LambdaRuntime.swift @@ -2,7 +2,7 @@ // // This source file is part of the SwiftAWSLambdaRuntime open source project // -// Copyright (c) 2017-2020 Apple Inc. and the SwiftAWSLambdaRuntime project authors +// Copyright (c) 2017-2022 Apple Inc. and the SwiftAWSLambdaRuntime project authors // Licensed under Apache License v2.0 // // See LICENSE.txt for license information @@ -35,7 +35,7 @@ public final class LambdaRuntime { /// Create a new `LambdaRuntime`. /// /// - parameters: - /// - handlerType: The ``ByteBufferLambdaHandler`` type the `LambdaRuntime` shall create and manage + /// - handlerType: The ``ByteBufferLambdaHandler`` type the `LambdaRuntime` shall create and manage. /// - eventLoop: An `EventLoop` to run the Lambda on. /// - logger: A `Logger` to log the Lambda events. public convenience init(_ handlerType: Handler.Type, eventLoop: EventLoop, logger: Logger) { diff --git a/Sources/AWSLambdaRuntimeCore/Terminator.swift b/Sources/AWSLambdaRuntimeCore/Terminator.swift index bd1737e0..6a0b65c0 100644 --- a/Sources/AWSLambdaRuntimeCore/Terminator.swift +++ b/Sources/AWSLambdaRuntimeCore/Terminator.swift @@ -26,14 +26,14 @@ public final class LambdaTerminator { self.storage = Storage() } - /// Register a shutdown handler with the terminator + /// Register a shutdown handler with the terminator. /// /// - parameters: - /// - name: Display name for logging purposes + /// - name: Display name for logging purposes. /// - handler: The shutdown handler to call when terminating the Lambda. /// Shutdown handlers are called in the reverse order of being registered. /// - /// - Returns: A `RegistrationKey` that can be used to de-register the handler when its no longer needed. + /// - Returns: A ``RegistrationKey`` that can be used to de-register the handler when its no longer needed. @discardableResult public func register(name: String, handler: @escaping (EventLoop) -> EventLoopFuture) -> RegistrationKey { let key = RegistrationKey() @@ -41,15 +41,15 @@ public final class LambdaTerminator { return key } - /// De-register a shutdown handler with the terminator + /// De-register a shutdown handler with the terminator. /// /// - parameters: - /// - key: A `RegistrationKey` obtained from calling the register API. + /// - key: A ``RegistrationKey`` obtained from calling the register API. public func deregister(_ key: RegistrationKey) { self.storage.remove(key) } - /// Begin the termination cycle + /// Begin the termination cycle. /// Shutdown handlers are called in the reverse order of being registered. /// /// - parameters: diff --git a/readme.md b/readme.md index 1fef39e2..8ffcff85 100644 --- a/readme.md +++ b/readme.md @@ -75,7 +75,7 @@ Next, create a `main.swift` and implement your Lambda. } ``` - Since most Lambda functions are triggered by events originating in the AWS platform like `SNS`, `SQS` or `APIGateway`, the [Swift AWS Lambda Events](http://github.com/swift-server/swift-aws-lambda-events) package includes a `AWSLambdaEvents` module that provides implementations for most common AWS event types further simplifying writing Lambda functions. For example, handling an `SQS` message: + Since most Lambda functions are triggered by events originating in the AWS platform like `SNS`, `SQS` or `APIGateway`, the [Swift AWS Lambda Events](http://github.com/swift-server/swift-aws-lambda-events) package includes an `AWSLambdaEvents` module that provides implementations for most common AWS event types further simplifying writing Lambda functions. For example, handling an `SQS` message: First, add a dependency on the event packages: @@ -180,11 +180,11 @@ public protocol ByteBufferLambdaHandler { ### EventLoopLambdaHandler -`EventLoopLambdaHandler` is a strongly typed, `EventLoopFuture` based asynchronous processing protocol for a Lambda that takes a user defined In and returns a user defined Out. +`EventLoopLambdaHandler` is a strongly typed, `EventLoopFuture` based asynchronous processing protocol for a Lambda that takes a user defined `In` and returns a user defined `Out`. -`EventLoopLambdaHandler` extends `ByteBufferLambdaHandler`, providing `ByteBuffer` -> `In` decoding and `Out` -> `ByteBuffer?` encoding for `Codable` and String. +`EventLoopLambdaHandler` extends `ByteBufferLambdaHandler`, providing `ByteBuffer` -> `In` decoding and `Out` -> `ByteBuffer?` encoding for `Codable` and `String`. -`EventLoopLambdaHandler` executes the user provided Lambda on the same `EventLoop` as the core runtime engine, making the processing fast but requires more care from the implementation to never block the `EventLoop`. It it designed for performance sensitive applications that use `Codable` or String based Lambda functions. +`EventLoopLambdaHandler` executes the user provided Lambda on the same `EventLoop` as the core runtime engine, making the processing fast but requires more care from the implementation to never block the `EventLoop`. It it designed for performance sensitive applications that use `Codable` or `String` based Lambda functions. ```swift public protocol EventLoopLambdaHandler: ByteBufferLambdaHandler { @@ -224,9 +224,9 @@ public protocol EventLoopLambdaHandler: ByteBufferLambdaHandler { ### LambdaHandler -`LambdaHandler` is a strongly typed, completion handler based asynchronous processing protocol for a Lambda that takes a user defined In and returns a user defined Out. +`LambdaHandler` is a strongly typed, completion handler based asynchronous processing protocol for a Lambda that takes a user defined `In` and returns a user defined `Out`. -`LambdaHandler` extends `ByteBufferLambdaHandler`, performing `ByteBuffer` -> `In` decoding and `Out` -> `ByteBuffer` encoding for `Codable` and String. +`LambdaHandler` extends `ByteBufferLambdaHandler`, performing `ByteBuffer` -> `In` decoding and `Out` -> `ByteBuffer` encoding for `Codable` and `String`. `LambdaHandler` offloads the user provided Lambda execution to a `DispatchQueue` making processing safer but slower. @@ -251,7 +251,7 @@ public protocol LambdaHandler: EventLoopLambdaHandler { In addition to protocol-based Lambda, the library provides support for Closure-based ones, as demonstrated in the overview section above. Closure-based Lambdas are based on the `LambdaHandler` protocol which mean they are safer. For most use cases, Closure-based Lambda is a great fit and users are encouraged to use them. -The library includes implementations for `Codable` and String based Lambda. Since AWS Lambda is primarily JSON based, this covers the most common use cases. +The library includes implementations for `Codable` and `String` based Lambda. Since AWS Lambda is primarily JSON based, this covers the most common use cases. ```swift public typealias CodableClosure = (Lambda.Context, In, @escaping (Result) -> Void) -> Void @@ -311,7 +311,7 @@ The library’s behavior can be fine tuned using environment variables based con * `LOG_LEVEL`: Define the logging level as defined by [SwiftLog](https://github.com/apple/swift-log). Set to INFO by default. * `MAX_REQUESTS`: Max cycles the library should handle before exiting. Set to none by default. -* `STOP_SIGNAL`: Signal to capture for termination. Set to TERM by default. +* `STOP_SIGNAL`: Signal to capture for termination. Set to `TERM` by default. * `REQUEST_TIMEOUT`: Max time to wait for responses to come back from the AWS Runtime engine. Set to none by default. @@ -326,24 +326,24 @@ The library is designed to integrate with AWS Lambda Runtime Engine via the [AWS A single Lambda execution workflow is made of the following steps: 1. The library calls AWS Lambda Runtime Engine `/next` endpoint to retrieve the next invocation request. -2. The library parses the response HTTP headers and populate the Context object. -3. The library reads the `/next` response body and attempt to decode it. Typically it decodes to user provided `In` type which extends `Decodable`, but users may choose to write Lambda functions that receive the input as String or `ByteBuffer` which require less, or no decoding. +2. The library parses the response HTTP headers and populate the `Context` object. +3. The library reads the `/next` response body and attempt to decode it. Typically it decodes to user provided `In` type which extends `Decodable`, but users may choose to write Lambda functions that receive the input as `String` or `ByteBuffer` which require less, or no decoding. 4. The library hands off the `Context` and `In` event to the user provided handler. In the case of `LambdaHandler` based handler this is done on a dedicated `DispatchQueue`, providing isolation between user's and the library's code. -5. User provided handler processes the request asynchronously, invoking a callback or returning a future upon completion, which returns a Result type with the Out or Error populated. -6. In case of error, the library posts to AWS Lambda Runtime Engine `/error` endpoint to provide the error details, which will show up on AWS Lambda logs. -7. In case of success, the library will attempt to encode the response. Typically it encodes from user provided `Out` type which extends `Encodable`, but users may choose to write Lambda functions that return a String or `ByteBuffer`, which require less, or no encoding. The library then posts the response to AWS Lambda Runtime Engine `/response` endpoint to provide the response to the callee. +5. User provided handler processes the request asynchronously, invoking a callback or returning a future upon completion, which returns a `Result` type with the `Out` or `Error` populated. +6. In case of error, the library posts to AWS Lambda Runtime Engine `/error` endpoint to provide the error details, which will show up on AWS Lambda logs. +7. In case of success, the library will attempt to encode the response. Typically it encodes from user provided `Out` type which extends `Encodable`, but users may choose to write Lambda functions that return a `String` or `ByteBuffer`, which require less, or no encoding. The library then posts the response to AWS Lambda Runtime Engine `/response` endpoint to provide the response to the callee. The library encapsulates the workflow via the internal `LambdaRuntimeClient` and `LambdaRunner` structs respectively. ### Lifecycle Management -AWS Lambda Runtime Engine controls the Application lifecycle and in the happy case never terminates the application, only suspends it's execution when no work is available. +AWS Lambda Runtime Engine controls the Application lifecycle and in the happy case never terminates the application, only suspends its execution when no work is available. -As such, the library main entry point is designed to run forever in a blocking fashion, performing the workflow described above in an endless loop. +As such, the library's main entry point is designed to run forever in a blocking fashion, performing the workflow described above in an endless loop. That loop is broken if/when an internal error occurs, such as a failure to communicate with AWS Lambda Runtime Engine API, or under other unexpected conditions. -By default, the library also registers a Signal handler that traps `INT` and `TERM` , which are typical Signals used in modern deployment platforms to communicate shutdown request. +By default, the library also registers a Signal handler that traps `INT` and `TERM`, which are typical Signals used in modern deployment platforms to communicate shutdown request. ### Integration with AWS Platform Events diff --git a/scripts/preview_docc.sh b/scripts/preview_docc.sh new file mode 100755 index 00000000..d3b79690 --- /dev/null +++ b/scripts/preview_docc.sh @@ -0,0 +1,30 @@ +#!/bin/bash +##===----------------------------------------------------------------------===## +## +## This source file is part of the SwiftAWSLambdaRuntime open source project +## +## Copyright (c) 2022 Apple Inc. and the SwiftAWSLambdaRuntime project authors +## Licensed under Apache License v2.0 +## +## See LICENSE.txt for license information +## See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors +## +## SPDX-License-Identifier: Apache-2.0 +## +##===----------------------------------------------------------------------===## + +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift Distributed Actors open source project +## +## Copyright (c) 2018-2019 Apple Inc. and the Swift Distributed Actors project authors +## Licensed under Apache License v2.0 +## +## See LICENSE.txt for license information +## See CONTRIBUTORS.md for the list of Swift Distributed Actors project authors +## +## SPDX-License-Identifier: Apache-2.0 +## +##===----------------------------------------------------------------------===## + +swift package --disable-sandbox preview-documentation --target $1 diff --git a/scripts/soundness.sh b/scripts/soundness.sh index bd291402..26b348ad 100755 --- a/scripts/soundness.sh +++ b/scripts/soundness.sh @@ -3,7 +3,7 @@ ## ## This source file is part of the SwiftAWSLambdaRuntime open source project ## -## Copyright (c) 2017-2018 Apple Inc. and the SwiftAWSLambdaRuntime project authors +## Copyright (c) 2017-2022 Apple Inc. and the SwiftAWSLambdaRuntime project authors ## Licensed under Apache License v2.0 ## ## See LICENSE.txt for license information @@ -19,7 +19,7 @@ here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" function replace_acceptable_years() { # this needs to replace all acceptable forms with 'YEARS' - sed -e 's/2017-2018/YEARS/' -e 's/2017-2020/YEARS/' -e 's/2017-2021/YEARS/' -e 's/2017-2022/YEARS/' -e 's/2020-2021/YEARS/' -e 's/2019/YEARS/' -e 's/2020/YEARS/' -e 's/2021/YEARS/' -e 's/2022/YEARS/' + sed -e 's/20[12][78901]-20[12][89012]/YEARS/' -e 's/201[789]/YEARS/' -e 's/202[012]/YEARS/' } printf "=> Checking for unacceptable language... " @@ -61,7 +61,7 @@ for language in swift-or-c bash dtrace; do matching_files=( -name '*' ) case "$language" in swift-or-c) - exceptions=( -name Package.swift -o -name Package@*.swift ) + exceptions=( -name Package.swift -o -name 'Package@*.swift' ) matching_files=( -name '*.swift' -o -name '*.c' -o -name '*.h' ) cat > "$tmp" <<"EOF" //===----------------------------------------------------------------------===//