diff --git a/.gitignore b/.gitignore index 0a2493df..dc546ee3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,9 @@ .DS_Store -/.build -/Packages -/*.xcodeproj -Package.pins +*.build +/.xcodeproj *.pem -/docs -Package.resolved .podspecs .swiftpm .swift-version +xcuserdata +Package.resolved diff --git a/Examples/EndToEndDebugging/EndToEndExample.xcworkspace/contents.xcworkspacedata b/Examples/EndToEndDebugging/EndToEndExample.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..92112301 --- /dev/null +++ b/Examples/EndToEndDebugging/EndToEndExample.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/Examples/EndToEndDebugging/EndToEndExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Examples/EndToEndDebugging/EndToEndExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/Examples/EndToEndDebugging/EndToEndExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Examples/EndToEndDebugging/EndToEndExample.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Examples/EndToEndDebugging/EndToEndExample.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/Examples/EndToEndDebugging/EndToEndExample.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/Examples/EndToEndDebugging/MyApp/MyApp.xcodeproj/project.pbxproj b/Examples/EndToEndDebugging/MyApp/MyApp.xcodeproj/project.pbxproj new file mode 100644 index 00000000..e8de1fb5 --- /dev/null +++ b/Examples/EndToEndDebugging/MyApp/MyApp.xcodeproj/project.pbxproj @@ -0,0 +1,345 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + F7B6C1FE246121E800607A89 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B6C1FD246121E800607A89 /* AppDelegate.swift */; }; + F7B6C200246121E800607A89 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B6C1FF246121E800607A89 /* SceneDelegate.swift */; }; + F7B6C202246121E800607A89 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B6C201246121E800607A89 /* ContentView.swift */; }; + F7B6C204246121E900607A89 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F7B6C203246121E900607A89 /* Assets.xcassets */; }; + F7B6C207246121E900607A89 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F7B6C206246121E900607A89 /* Preview Assets.xcassets */; }; + F7B6C20A246121E900607A89 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7B6C208246121E900607A89 /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + F7B6C1FA246121E800607A89 /* MyApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MyApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; + F7B6C1FD246121E800607A89 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + F7B6C1FF246121E800607A89 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + F7B6C201246121E800607A89 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + F7B6C203246121E900607A89 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + F7B6C206246121E900607A89 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + F7B6C209246121E900607A89 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + F7B6C20B246121E900607A89 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + F7B6C1F7246121E800607A89 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + F7B6C1F1246121E800607A89 = { + isa = PBXGroup; + children = ( + F7B6C1FC246121E800607A89 /* MyApp */, + F7B6C1FB246121E800607A89 /* Products */, + ); + sourceTree = ""; + }; + F7B6C1FB246121E800607A89 /* Products */ = { + isa = PBXGroup; + children = ( + F7B6C1FA246121E800607A89 /* MyApp.app */, + ); + name = Products; + sourceTree = ""; + }; + F7B6C1FC246121E800607A89 /* MyApp */ = { + isa = PBXGroup; + children = ( + F7B6C1FD246121E800607A89 /* AppDelegate.swift */, + F7B6C1FF246121E800607A89 /* SceneDelegate.swift */, + F7B6C201246121E800607A89 /* ContentView.swift */, + F7B6C203246121E900607A89 /* Assets.xcassets */, + F7B6C208246121E900607A89 /* LaunchScreen.storyboard */, + F7B6C20B246121E900607A89 /* Info.plist */, + F7B6C205246121E900607A89 /* Preview Content */, + ); + path = MyApp; + sourceTree = ""; + }; + F7B6C205246121E900607A89 /* Preview Content */ = { + isa = PBXGroup; + children = ( + F7B6C206246121E900607A89 /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + F7B6C1F9246121E800607A89 /* MyApp */ = { + isa = PBXNativeTarget; + buildConfigurationList = F7B6C20E246121E900607A89 /* Build configuration list for PBXNativeTarget "MyApp" */; + buildPhases = ( + F7B6C1F6246121E800607A89 /* Sources */, + F7B6C1F7246121E800607A89 /* Frameworks */, + F7B6C1F8246121E800607A89 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MyApp; + productName = MyApp; + productReference = F7B6C1FA246121E800607A89 /* MyApp.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + F7B6C1F2246121E800607A89 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1140; + LastUpgradeCheck = 1140; + ORGANIZATIONNAME = "Tom Doron"; + TargetAttributes = { + F7B6C1F9246121E800607A89 = { + CreatedOnToolsVersion = 11.4.1; + }; + }; + }; + buildConfigurationList = F7B6C1F5246121E800607A89 /* Build configuration list for PBXProject "MyApp" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = F7B6C1F1246121E800607A89; + productRefGroup = F7B6C1FB246121E800607A89 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + F7B6C1F9246121E800607A89 /* MyApp */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + F7B6C1F8246121E800607A89 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F7B6C20A246121E900607A89 /* LaunchScreen.storyboard in Resources */, + F7B6C207246121E900607A89 /* Preview Assets.xcassets in Resources */, + F7B6C204246121E900607A89 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + F7B6C1F6246121E800607A89 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F7B6C1FE246121E800607A89 /* AppDelegate.swift in Sources */, + F7B6C200246121E800607A89 /* SceneDelegate.swift in Sources */, + F7B6C202246121E800607A89 /* ContentView.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + F7B6C208246121E900607A89 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + F7B6C209246121E900607A89 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + F7B6C20C246121E900607A89 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.4; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + F7B6C20D246121E900607A89 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.4; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + F7B6C20F246121E900607A89 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_ASSET_PATHS = "\"MyApp/Preview Content\""; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = MyApp/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.apple.swift.MyApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + F7B6C210246121E900607A89 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_ASSET_PATHS = "\"MyApp/Preview Content\""; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = MyApp/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.apple.swift.MyApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + F7B6C1F5246121E800607A89 /* Build configuration list for PBXProject "MyApp" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F7B6C20C246121E900607A89 /* Debug */, + F7B6C20D246121E900607A89 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F7B6C20E246121E900607A89 /* Build configuration list for PBXNativeTarget "MyApp" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F7B6C20F246121E900607A89 /* Debug */, + F7B6C210246121E900607A89 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = F7B6C1F2246121E800607A89 /* Project object */; +} diff --git a/Examples/EndToEndDebugging/MyApp/MyApp.xcodeproj/xcshareddata/xcschemes/MyApp.xcscheme b/Examples/EndToEndDebugging/MyApp/MyApp.xcodeproj/xcshareddata/xcschemes/MyApp.xcscheme new file mode 100644 index 00000000..dc471464 --- /dev/null +++ b/Examples/EndToEndDebugging/MyApp/MyApp.xcodeproj/xcshareddata/xcschemes/MyApp.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/EndToEndDebugging/MyApp/MyApp/AppDelegate.swift b/Examples/EndToEndDebugging/MyApp/MyApp/AppDelegate.swift new file mode 100644 index 00000000..068d2b7a --- /dev/null +++ b/Examples/EndToEndDebugging/MyApp/MyApp/AppDelegate.swift @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftAWSLambdaRuntime open source project +// +// Copyright (c) 2020 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 +// +//===----------------------------------------------------------------------===// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + true + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + } +} diff --git a/Examples/EndToEndDebugging/MyApp/MyApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/Examples/EndToEndDebugging/MyApp/MyApp/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..9221b9bb --- /dev/null +++ b/Examples/EndToEndDebugging/MyApp/MyApp/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/EndToEndDebugging/MyApp/MyApp/Assets.xcassets/Contents.json b/Examples/EndToEndDebugging/MyApp/MyApp/Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/Examples/EndToEndDebugging/MyApp/MyApp/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/EndToEndDebugging/MyApp/MyApp/Base.lproj/LaunchScreen.storyboard b/Examples/EndToEndDebugging/MyApp/MyApp/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..865e9329 --- /dev/null +++ b/Examples/EndToEndDebugging/MyApp/MyApp/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/EndToEndDebugging/MyApp/MyApp/ContentView.swift b/Examples/EndToEndDebugging/MyApp/MyApp/ContentView.swift new file mode 100644 index 00000000..c73d13ef --- /dev/null +++ b/Examples/EndToEndDebugging/MyApp/MyApp/ContentView.swift @@ -0,0 +1,79 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftAWSLambdaRuntime open source project +// +// Copyright (c) 2020 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 +// +//===----------------------------------------------------------------------===// + +import SwiftUI + +struct ContentView: View { + @State var name: String = "World" + @State var response: String = "" + + var body: some View { + VStack(alignment: .leading, spacing: 20) { + TextField("Enter your name", text: $name) + Button( + action: self.sayHello, + label: { + Text("say hello") + .padding() + .foregroundColor(.white) + .background(Color.black) + .border(Color.black, width: 2) + } + ) + Text(response) + .foregroundColor(response.starts(with: "CommunicationError") ? .red : .black) + }.padding(100) + } + + func sayHello() { + guard let url = URL(string: "http://localhost:7000/invoke") else { + fatalError("invalid url") + } + + var request = URLRequest(url: url) + request.httpMethod = "POST" + request.httpBody = self.name.data(using: .utf8) + + let task = URLSession.shared.dataTask(with: request as URLRequest) { data, response, error in + do { + if let error = error { + throw CommunicationError(reason: error.localizedDescription) + } + guard let httpResponse = response as? HTTPURLResponse else { + throw CommunicationError(reason: "invalid response, expected HTTPURLResponse") + } + guard httpResponse.statusCode == 200 else { + throw CommunicationError(reason: "invalid response code: \(httpResponse.statusCode)") + } + guard let data = data else { + throw CommunicationError(reason: "invald response, empty body") + } + self.response = String(data: data, encoding: .utf8)! + } catch { + self.response = "\(error)" + } + } + task.resume() + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} + +struct CommunicationError: Error { + let reason: String +} diff --git a/Examples/EndToEndDebugging/MyApp/MyApp/Info.plist b/Examples/EndToEndDebugging/MyApp/MyApp/Info.plist new file mode 100644 index 00000000..9742bf0f --- /dev/null +++ b/Examples/EndToEndDebugging/MyApp/MyApp/Info.plist @@ -0,0 +1,60 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + + + + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Examples/EndToEndDebugging/MyApp/MyApp/Preview Content/Preview Assets.xcassets/Contents.json b/Examples/EndToEndDebugging/MyApp/MyApp/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/Examples/EndToEndDebugging/MyApp/MyApp/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/EndToEndDebugging/MyApp/MyApp/SceneDelegate.swift b/Examples/EndToEndDebugging/MyApp/MyApp/SceneDelegate.swift new file mode 100644 index 00000000..71e700d4 --- /dev/null +++ b/Examples/EndToEndDebugging/MyApp/MyApp/SceneDelegate.swift @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftAWSLambdaRuntime open source project +// +// Copyright (c) 2020 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 +// +//===----------------------------------------------------------------------===// + +import SwiftUI +import UIKit + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + var window: UIWindow? + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). + + // Create the SwiftUI view that provides the window contents. + let contentView = ContentView() + + // Use a UIHostingController as window root view controller. + if let windowScene = scene as? UIWindowScene { + let window = UIWindow(windowScene: windowScene) + window.rootViewController = UIHostingController(rootView: contentView) + self.window = window + window.makeKeyAndVisible() + } + } + + func sceneDidDisconnect(_: UIScene) { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). + } + + func sceneDidBecomeActive(_: UIScene) { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + } + + func sceneWillResignActive(_: UIScene) { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). + } + + func sceneWillEnterForeground(_: UIScene) { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. + } + + func sceneDidEnterBackground(_: UIScene) { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. + } +} diff --git a/Examples/EndToEndDebugging/MyLambda/.dockerignore b/Examples/EndToEndDebugging/MyLambda/.dockerignore new file mode 100644 index 00000000..24e5b0a1 --- /dev/null +++ b/Examples/EndToEndDebugging/MyLambda/.dockerignore @@ -0,0 +1 @@ +.build diff --git a/Examples/EndToEndDebugging/MyLambda/Dockerfile b/Examples/EndToEndDebugging/MyLambda/Dockerfile new file mode 100644 index 00000000..c4db2a61 --- /dev/null +++ b/Examples/EndToEndDebugging/MyLambda/Dockerfile @@ -0,0 +1,3 @@ +FROM swiftlang/swift:nightly-master-amazonlinux2 + +RUN yum -y install git zip diff --git a/Examples/EndToEndDebugging/MyLambda/Package.swift b/Examples/EndToEndDebugging/MyLambda/Package.swift new file mode 100644 index 00000000..c35f2a3c --- /dev/null +++ b/Examples/EndToEndDebugging/MyLambda/Package.swift @@ -0,0 +1,26 @@ +// swift-tools-version:5.2 + +import PackageDescription + +let package = Package( + name: "MyLambda", + platforms: [ + .macOS(.v10_13), + ], + products: [ + .executable(name: "MyLambda", targets: ["MyLambda"]), + ], + dependencies: [ + // this is the dependency on the swift-aws-lambda-runtime library + // in real-world projects this would say + // .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "1.0.0") + .package(name: "swift-aws-lambda-runtime", path: "../../.."), + ], + targets: [ + .target( + name: "MyLambda", dependencies: [ + .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"), + ] + ), + ] +) diff --git a/Examples/EndToEndDebugging/MyLambda/Sources/MyLambda/main.swift b/Examples/EndToEndDebugging/MyLambda/Sources/MyLambda/main.swift new file mode 100644 index 00000000..45bd8d83 --- /dev/null +++ b/Examples/EndToEndDebugging/MyLambda/Sources/MyLambda/main.swift @@ -0,0 +1,21 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftAWSLambdaRuntime open source project +// +// Copyright (c) 2020 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 +// +//===----------------------------------------------------------------------===// + +import AWSLambdaRuntime + +try Lambda.withLocalServer { + Lambda.run { (_: Lambda.Context, payload: String, callback: @escaping (Result) -> Void) in + callback(.success("Hello, \(payload)!")) + } +} diff --git a/Examples/EndToEndDebugging/MyLambda/Tests/LinuxMain.swift b/Examples/EndToEndDebugging/MyLambda/Tests/LinuxMain.swift new file mode 100644 index 00000000..c46de763 --- /dev/null +++ b/Examples/EndToEndDebugging/MyLambda/Tests/LinuxMain.swift @@ -0,0 +1,15 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftAWSLambdaRuntime open source project +// +// Copyright (c) 2020 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 +// +//===----------------------------------------------------------------------===// + +preconditionFailure("use `swift test --enable-test-discovery`") diff --git a/Examples/EndToEndDebugging/MyLambda/scripts/deploy.sh b/Examples/EndToEndDebugging/MyLambda/scripts/deploy.sh new file mode 100755 index 00000000..8c137d60 --- /dev/null +++ b/Examples/EndToEndDebugging/MyLambda/scripts/deploy.sh @@ -0,0 +1,65 @@ +#!/bin/bash +##===----------------------------------------------------------------------===## +## +## This source file is part of the SwiftAWSLambdaRuntime open source project +## +## Copyright (c) 2020 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 +## +##===----------------------------------------------------------------------===## + +set -eu + +lambda_name=SwiftSample +s3_bucket=swift-lambda-test +executables=( $(swift package dump-package | sed -e 's|: null|: ""|g' | jq '.products[] | (select(.type.executable)) | .name' | sed -e 's|"||g') ) + +if [[ ${#executables[@]} = 0 ]]; then + echo "no executables found" + exit 1 +elif [[ ${#executables[@]} = 1 ]]; then + executable=${executables[0]} +elif [[ ${#executables[@]} > 1 ]]; then + echo "multiple executables found:" + for executable in ${executables[@]}; do + echo " * $executable" + done + echo "" + read -p "select which executables to deploy: " executable +fi + +echo -e "\ndeploying $executable" + +echo "-------------------------------------------------------------------------" +echo "preparing docker build image" +echo "-------------------------------------------------------------------------" +docker build . -t builder + +echo "-------------------------------------------------------------------------" +echo "building \"$executable\" lambda" +echo "-------------------------------------------------------------------------" +docker run --rm -v `pwd`/../../..:/workspace -w /workspace builder \ + bash -cl "cd Examples/EndToEndDebugging/MyLambda && + swift build --product $executable -c release -Xswiftc -g" +echo "done" + +echo "-------------------------------------------------------------------------" +echo "packaging \"$executable\" lambda" +echo "-------------------------------------------------------------------------" +docker run --rm -v `pwd`:/workspace -w /workspace builder bash -cl "./scripts/package.sh $executable" + +echo "-------------------------------------------------------------------------" +echo "uploading \"$executable\" lambda to s3" +echo "-------------------------------------------------------------------------" + +aws s3 cp .build/lambda/$executable/lambda.zip s3://$s3_bucket/ + +echo "-------------------------------------------------------------------------" +echo "updating \"$lambda_name\" to latest \"$executable\"" +echo "-------------------------------------------------------------------------" +aws lambda update-function-code --function $lambda_name --s3-bucket $s3_bucket --s3-key lambda.zip diff --git a/Examples/EndToEndDebugging/MyLambda/scripts/package.sh b/Examples/EndToEndDebugging/MyLambda/scripts/package.sh new file mode 100755 index 00000000..190be3f8 --- /dev/null +++ b/Examples/EndToEndDebugging/MyLambda/scripts/package.sh @@ -0,0 +1,27 @@ +#!/bin/bash +##===----------------------------------------------------------------------===## +## +## This source file is part of the SwiftAWSLambdaRuntime open source project +## +## Copyright (c) 2020 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 +## +##===----------------------------------------------------------------------===## + +set -eu + +executable=$1 + +target=.build/lambda/$executable +rm -rf "$target" +mkdir -p "$target" +cp ".build/release/$executable" "$target/" +cp -Pv /usr/lib/swift/linux/lib*so* "$target" +cd "$target" +ln -s "$executable" "bootstrap" +zip --symlinks lambda.zip * diff --git a/Examples/EndToEndDebugging/README.md b/Examples/EndToEndDebugging/README.md new file mode 100644 index 00000000..676125a3 --- /dev/null +++ b/Examples/EndToEndDebugging/README.md @@ -0,0 +1,8 @@ +# End-To-End Debugging + +This sample project demonstrates how to write a simple Lambda function in Swift, +and how to use local debugging techniques that emulate how the Lambda function +would be invoked by the AWS Lambda Runtime engine. + +The sample also includes a simple iOS application that calls the Lambda function +through the emulator, providing an end-to-end debugging experience. diff --git a/Examples/LambdaFunctions/.dockerignore b/Examples/LambdaFunctions/.dockerignore new file mode 100644 index 00000000..24e5b0a1 --- /dev/null +++ b/Examples/LambdaFunctions/.dockerignore @@ -0,0 +1 @@ +.build diff --git a/Examples/LambdaFunctions/APIGateway-template.yml b/Examples/LambdaFunctions/APIGateway-template.yml new file mode 100644 index 00000000..4861b60c --- /dev/null +++ b/Examples/LambdaFunctions/APIGateway-template.yml @@ -0,0 +1,33 @@ +AWSTemplateFormatVersion : '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: A sample SAM template for deploying Lambda functions. + +Resources: +# APIGateway Function + apiGatewayFunction: + Type: AWS::Serverless::Function + Properties: + Handler: Provided + Runtime: provided + CodeUri: .build/lambda/APIGateway/lambda.zip +# Add an API Gateway event source for the Lambda + Events: + HttpGet: + Type: Api + Properties: + RestApiId: !Ref lambdaApiGateway + Path: '/samples/apig' + Method: get +# Instructs new versions to be published to an alias named "live". + AutoPublishAlias: live + + lambdaApiGateway: + Type: AWS::Serverless::Api + Properties: + Name: Lambda API Gateway + StageName: Beta + +Outputs: + LambdaApiGatewayEndpoint: + Description: 'API Gateway endpoint URL.' + Value: !Sub 'https://${lambdaApiGateway}.execute-api.${AWS::Region}.amazonaws.com/Beta/samples/apig' diff --git a/Examples/LambdaFunctions/Benchmark-template.yml b/Examples/LambdaFunctions/Benchmark-template.yml new file mode 100644 index 00000000..38941a53 --- /dev/null +++ b/Examples/LambdaFunctions/Benchmark-template.yml @@ -0,0 +1,14 @@ +AWSTemplateFormatVersion : '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: A sample SAM template for deploying Lambda functions. + +Resources: +# Benchmark Function + benchmarkFunction: + Type: AWS::Serverless::Function + Properties: + Handler: Provided + Runtime: provided + CodeUri: .build/lambda/Benchmark/lambda.zip +# Instructs new versions to be published to an alias named "live". + AutoPublishAlias: live diff --git a/Examples/LambdaFunctions/CurrencyExchange-template.yml b/Examples/LambdaFunctions/CurrencyExchange-template.yml new file mode 100644 index 00000000..de09cd4e --- /dev/null +++ b/Examples/LambdaFunctions/CurrencyExchange-template.yml @@ -0,0 +1,15 @@ +AWSTemplateFormatVersion : '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: A sample SAM template for deploying Lambda functions. + +Resources: +# CurrencyExchange Function + currencyExchangeFunction: + Type: AWS::Serverless::Function + Properties: + Handler: Provided + Runtime: provided + CodeUri: .build/lambda/CurrencyExchange/lambda.zip + Timeout: 300 +# Instructs new versions to be published to an alias named "live". + AutoPublishAlias: live diff --git a/Examples/LambdaFunctions/Dockerfile b/Examples/LambdaFunctions/Dockerfile new file mode 100644 index 00000000..c4db2a61 --- /dev/null +++ b/Examples/LambdaFunctions/Dockerfile @@ -0,0 +1,3 @@ +FROM swiftlang/swift:nightly-master-amazonlinux2 + +RUN yum -y install git zip diff --git a/Examples/LambdaFunctions/ErrorHandling-template.yml b/Examples/LambdaFunctions/ErrorHandling-template.yml new file mode 100644 index 00000000..dba76b8e --- /dev/null +++ b/Examples/LambdaFunctions/ErrorHandling-template.yml @@ -0,0 +1,14 @@ +AWSTemplateFormatVersion : '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: A sample SAM template for deploying Lambda functions. + +Resources: +# ErrorHandling Function + errorHandlingFunction: + Type: AWS::Serverless::Function + Properties: + Handler: Provided + Runtime: provided + CodeUri: .build/lambda/ErrorHandling/lambda.zip +# Instructs new versions to be published to an alias named "live". + AutoPublishAlias: live diff --git a/Examples/LambdaFunctions/HelloWorld-template.yml b/Examples/LambdaFunctions/HelloWorld-template.yml new file mode 100644 index 00000000..7eddfbe7 --- /dev/null +++ b/Examples/LambdaFunctions/HelloWorld-template.yml @@ -0,0 +1,14 @@ +AWSTemplateFormatVersion : '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: A sample SAM template for deploying Lambda functions. + +Resources: +# HelloWorld Function + helloWorldFunction: + Type: AWS::Serverless::Function + Properties: + Handler: Provided + Runtime: provided + CodeUri: .build/lambda/HelloWorld/lambda.zip +# Instructs new versions to be published to an alias named "live". + AutoPublishAlias: live diff --git a/Examples/LambdaFunctions/Package.swift b/Examples/LambdaFunctions/Package.swift new file mode 100644 index 00000000..5a94f362 --- /dev/null +++ b/Examples/LambdaFunctions/Package.swift @@ -0,0 +1,45 @@ +// swift-tools-version:5.2 + +import PackageDescription + +let package = Package( + name: "swift-aws-lambda-runtime-samples", + platforms: [ + .macOS(.v10_13), + ], + products: [ + // introductory example + .executable(name: "HelloWorld", targets: ["HelloWorld"]), + // good for benchmarking + .executable(name: "Benchmark", targets: ["Benchmark"]), + // demonstrate different types of error handling + .executable(name: "ErrorHandling", targets: ["ErrorHandling"]), + // demostrate how to integrate with AWS API Gateway + .executable(name: "APIGateway", targets: ["APIGateway"]), + // fully featured example with domain specific business logic + .executable(name: "CurrencyExchange", targets: ["CurrencyExchange"]), + ], + dependencies: [ + // this is the dependency on the swift-aws-lambda-runtime library + // in real-world projects this would say + // .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "1.0.0") + .package(name: "swift-aws-lambda-runtime", path: "../.."), + ], + targets: [ + .target(name: "HelloWorld", dependencies: [ + .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"), + ]), + .target(name: "Benchmark", dependencies: [ + .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"), + ]), + .target(name: "ErrorHandling", dependencies: [ + .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"), + ]), + .target(name: "APIGateway", dependencies: [ + .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"), + ]), + .target(name: "CurrencyExchange", dependencies: [ + .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"), + ]), + ] +) diff --git a/Examples/LambdaFunctions/README.md b/Examples/LambdaFunctions/README.md new file mode 100644 index 00000000..dda328a9 --- /dev/null +++ b/Examples/LambdaFunctions/README.md @@ -0,0 +1,81 @@ +# Lambda Functions Examples + +This sample project is a collection of Lambda functions that demonstrates +how to write a simple Lambda function in Swift, and how to package and deploy it +to the AWS Lambda platform. + +## Deployment instructions using AWS CLI + +Steps to deploy this sample to AWS Lambda using the AWS CLI: + +1. Login to AWS Console and create an AWS Lambda with the following settings: + * Runtime: Custom runtime + * Handler: Can be any string, does not matter in this case + +2. Build, package and deploy the Lambda + + ``` + ./scripts/deploy.sh + ``` + + Note: This script assumes you have AWS CLI installed and credentials setup in `~/.aws/credentials`. + +### Deployment instructions using AWS SAM (Serverless Application Model) + +AWS [Serverless Application Model](https://aws.amazon.com/serverless/sam/) (SAM) is an open-source framework for building serverless applications. This framework allows you to easily deploy other AWS resources and more complex deployment mechanisms such a CI pipelines. + +***Note:*** Deploying using SAM will automatically create resources within your AWS account. Charges may apply for these resources. + +To use SAM to deploy this sample to AWS: + +1. Install the AWS CLI by following the [instructions](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html). + +2. Install SAM CLI by following the [instructions](https://aws.amazon.com/serverless/sam/). + +3. Build, package and deploy the Lambda + + ``` + ./scripts/sam-deploy.sh --guided + ``` + +The script will ask you which sample Lambda you wish to deploy. It will then guide you through the SAM setup process. + + ``` + Setting default arguments for 'sam deploy' + ========================================= + Stack Name [sam-app]: swift-aws-lambda-runtime-sample + AWS Region [us-east-1]: + #Shows you resources changes to be deployed and require a 'Y' to initiate deploy + Confirm changes before deploy [y/N]: Y + #SAM needs permission to be able to create roles to connect to the resources in your template + Allow SAM CLI IAM role creation [Y/n]: Y + Save arguments to samconfig.toml [Y/n]: Y + ``` + +If you said yes to confirm changes, SAM will ask you to accept changes to the infrastructure you are setting up. For more on this, see [Cloud Formation](https://aws.amazon.com/cloudformation/). + +The `sam-deploy` script passes through any parameters to the SAM deploy command. + +4. Subsequent deploys can just use the command minus the `guided` parameter: + + ``` + ./scripts/sam-deploy.sh + ``` + +The script will ask you which sample Lambda you wish to deploy. If you are deploying a different sample lambda, the deploy process will pull down the previous Lambda. + +SAM will still ask you to confirm changes if you said yes to that initially. + +5. Testing + +For the API Gateway sample: + +The SAM template will provide an output labelled `LambdaApiGatewayEndpoint` which you can use to test the Lambda. For example: + + ``` + curl <> + ``` + +***Warning:*** This SAM template is only intended as a sample and creates a publicly accessible HTTP endpoint. + +For all other samples use the AWS Lambda console. diff --git a/Examples/LambdaFunctions/Sources/APIGateway/main.swift b/Examples/LambdaFunctions/Sources/APIGateway/main.swift new file mode 100644 index 00000000..e3606640 --- /dev/null +++ b/Examples/LambdaFunctions/Sources/APIGateway/main.swift @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftAWSLambdaRuntime open source project +// +// Copyright (c) 2020 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 +// +//===----------------------------------------------------------------------===// + +import AWSLambdaRuntime +import NIO + +// MARK: - Run Lambda + +Lambda.run(APIGatewayProxyLambda()) + +// MARK: - Handler, Request and Response + +// FIXME: Use proper Event abstractions once added to AWSLambdaRuntime +struct APIGatewayProxyLambda: EventLoopLambdaHandler { + public typealias In = APIGatewayRequest + public typealias Out = APIGatewayResponse + + public func handle(context: Lambda.Context, payload: APIGatewayRequest) -> EventLoopFuture { + context.logger.debug("hello, api gateway!") + return context.eventLoop.makeSucceededFuture(APIGatewayResponse(statusCode: 200, + headers: nil, + multiValueHeaders: nil, + body: "hello, world!", + isBase64Encoded: false)) + } +} + +struct APIGatewayRequest: Codable { + let resource: String + let path: String + let httpMethod: String? + let headers: [String: String]? + let multiValueHeaders: [String: [String]]? + let queryStringParameters: [String: String]? + let multiValueQueryStringParameters: [String: [String]]? + let pathParameters: [String: String]? + let stageVariables: [String: String]? + let requestContext: Context? + let body: String? + let isBase64Encoded: Bool? + + struct Context: Codable { + let accountId: String? + let resourceId: String? + let stage: String? + let requestId: String? + let identity: Identity? + let resourcePath: String? + let httpMethod: String? + let apiId: String + } + + struct Identity: Codable { + let cognitoIdentityPoolId: String? + let accountId: String? + let cognitoIdentityId: String? + let caller: String? + let apiKey: String? + let sourceIp: String? + let cognitoAuthenticationType: String? + let cognitoAuthenticationProvider: String? + let userArn: String? + let userAgent: String? + let user: String? + } +} + +struct APIGatewayResponse: Codable { + let statusCode: Int + let headers: [String: String]? + let multiValueHeaders: [String: [String]]? + let body: String? + let isBase64Encoded: Bool? +} diff --git a/Examples/LambdaFunctions/Sources/Benchmark/main.swift b/Examples/LambdaFunctions/Sources/Benchmark/main.swift new file mode 100644 index 00000000..2a61d9d3 --- /dev/null +++ b/Examples/LambdaFunctions/Sources/Benchmark/main.swift @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftAWSLambdaRuntime open source project +// +// Copyright (c) 2020 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 +// +//===----------------------------------------------------------------------===// + +import AWSLambdaRuntime +import NIO + +// If you would like to benchmark Swift's Lambda Runtime, +// use this example which is more performant. +// `EventLoopLambdaHandler` does not offload the Lambda processing to a separate thread +// while the closure-based handlers do. +Lambda.run(BenchmarkHandler()) + +struct BenchmarkHandler: EventLoopLambdaHandler { + typealias In = String + typealias Out = String + + func handle(context: Lambda.Context, payload: String) -> EventLoopFuture { + context.eventLoop.makeSucceededFuture("hello, world!") + } +} diff --git a/Examples/LambdaFunctions/Sources/CurrencyExchange/main.swift b/Examples/LambdaFunctions/Sources/CurrencyExchange/main.swift new file mode 100644 index 00000000..22c30563 --- /dev/null +++ b/Examples/LambdaFunctions/Sources/CurrencyExchange/main.swift @@ -0,0 +1,247 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftAWSLambdaRuntime open source project +// +// Copyright (c) 2020 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 +// +//===----------------------------------------------------------------------===// + +import AWSLambdaRuntime +import Dispatch +import Foundation +#if canImport(FoundationNetworking) && canImport(FoundationXML) +import FoundationNetworking +import FoundationXML +#endif +import Logging + +// MARK: - Run Lambda + +Lambda.run { (context: Lambda.Context, _: Request, callback: @escaping (Result<[Exchange], Error>) -> Void) in + let calculator = ExchangeRatesCalculator() + calculator.run(logger: context.logger, callback: callback) +} + +// MARK: - Business Logic + +// This is a contrived example performing currency exchange rate lookup and conversion using URLSession and XML parsing +struct ExchangeRatesCalculator { + static let currencies = ["EUR", "USD", "JPY"] + static let currenciesEmojies = [ + "EUR": "💶", + "JPY": "💴", + "USD": "💵", + ] + + let locale: Locale + let calendar: Calendar + + init() { + // This is data from HMRC, the UK tax authority. Therefore we want to use their locale when interpreting data from the server. + self.locale = Locale(identifier: "en_GB") + // Use the UK calendar, not the system one. + var calendar = self.locale.calendar + calendar.timeZone = TimeZone(identifier: "UTC")! + self.calendar = calendar + } + + func run(logger: Logger, callback: @escaping (Result<[Exchange], Swift.Error>) -> Void) { + let startDate = Date() + let months = (1 ... 12).map { + self.calendar.date(byAdding: DateComponents(month: -$0), to: startDate)! + } + + self.download(logger: logger, + months: months, + monthIndex: months.startIndex, + currencies: Self.currencies, + state: [:]) { result in + + switch result { + case .failure(let error): + return callback(.failure(error)) + case .success(let downloadedDataByMonth): + logger.debug("Downloads complete") + + var result = [Exchange]() + var previousData: [String: Decimal?] = [:] + for (_, exchangeRateData) in downloadedDataByMonth.filter({ $1.period != nil }).sorted(by: { $0.key < $1.key }) { + for (currencyCode, rate) in exchangeRateData.ratesByCurrencyCode.sorted(by: { $0.key < $1.key }) { + if let rate = rate, let currencyEmoji = Self.currenciesEmojies[currencyCode] { + let change: Exchange.Change + switch previousData[currencyCode] { + case .some(.some(let previousRate)) where rate > previousRate: + change = .up + case .some(.some(let previousRate)) where rate < previousRate: + change = .down + case .some(.some(let previousRate)) where rate == previousRate: + change = .none + default: + change = .unknown + } + result.append(Exchange(date: exchangeRateData.period!.start, + from: .init(symbol: "GBP", emoji: "💷"), + to: .init(symbol: currencyCode, emoji: currencyEmoji), + rate: rate, + change: change)) + } + } + previousData = exchangeRateData.ratesByCurrencyCode + } + callback(.success(result)) + } + } + } + + private func download(logger: Logger, + months: [Date], + monthIndex: Array.Index, + currencies: [String], + state: [Date: ExchangeRates], + callback: @escaping ((Result<[Date: ExchangeRates], Swift.Error>) -> Void)) { + if monthIndex == months.count { + return callback(.success(state)) + } + + var newState = state + + let month = months[monthIndex] + let url = self.exchangeRatesURL(forMonthContaining: month) + logger.debug("requesting exchange rate from \(url)") + let dataTask = URLSession.shared.dataTask(with: url) { data, _, error in + do { + guard let data = data else { + throw error! + } + let exchangeRates = try self.parse(data: data, currencyCodes: Set(currencies)) + newState[month] = exchangeRates + logger.debug("Finished downloading month: \(month)") + if let period = exchangeRates.period { + logger.debug("Got data covering period: \(period)") + } + } catch { + return callback(.failure(error)) + } + self.download(logger: logger, + months: months, + monthIndex: monthIndex.advanced(by: 1), + currencies: currencies, + state: newState, + callback: callback) + } + dataTask.resume() + } + + private func parse(data: Data, currencyCodes: Set) throws -> ExchangeRates { + let document = try XMLDocument(data: data) + let dateFormatter = DateFormatter() + dateFormatter.timeZone = TimeZone(identifier: "Etc/UTC")! + dateFormatter.dateFormat = "dd/MMM/yy" + let interval: DateInterval? + if let period = try document.nodes(forXPath: "/exchangeRateMonthList/@Period").first?.stringValue, + period.count == 26 { + // "01/Sep/2018 to 30/Sep/2018" + let startString = period[period.startIndex ..< period.index(period.startIndex, offsetBy: 11)] + let to = period[startString.endIndex ..< period.index(startString.endIndex, offsetBy: 4)] + let endString = period[to.endIndex ..< period.index(to.endIndex, offsetBy: 11)] + if let startDate = dateFormatter.date(from: String(startString)), + let startDay = calendar.dateInterval(of: .day, for: startDate), + to == " to ", + let endDate = dateFormatter.date(from: String(endString)), + let endDay = calendar.dateInterval(of: .day, for: endDate) { + interval = DateInterval(start: startDay.start, end: endDay.end) + } else { + interval = nil + } + } else { + interval = nil + } + + let ratesByCurrencyCode: [String: Decimal?] = Dictionary(uniqueKeysWithValues: try currencyCodes.map { + let xpathCurrency = $0.replacingOccurrences(of: "'", with: "'") + if let rateString = try document.nodes(forXPath: "/exchangeRateMonthList/exchangeRate/currencyCode[text()='\(xpathCurrency)']/../rateNew/text()").first?.stringValue, + // We must parse the decimal data using the UK locale, not the system one. + let rate = Decimal(string: rateString, locale: self.locale) { + return ($0, rate) + } else { + return ($0, nil) + } + }) + + return (period: interval, ratesByCurrencyCode: ratesByCurrencyCode) + } + + private func makeUTCDateFormatter(dateFormat: String) -> DateFormatter { + let utcTimeZone = TimeZone(identifier: "UTC")! + let result = DateFormatter() + result.locale = Locale(identifier: "en_US_POSIX") + result.timeZone = utcTimeZone + result.dateFormat = dateFormat + return result + } + + private func exchangeRatesURL(forMonthContaining date: Date) -> URL { + let exchangeRatesBaseURL = URL(string: "https://www.hmrc.gov.uk/softwaredevelopers/rates")! + let dateFormatter = self.makeUTCDateFormatter(dateFormat: "MMyy") + return exchangeRatesBaseURL.appendingPathComponent("exrates-monthly-\(dateFormatter.string(from: date)).xml") + } + + private typealias ExchangeRates = (period: DateInterval?, ratesByCurrencyCode: [String: Decimal?]) + + private struct Error: Swift.Error, CustomStringConvertible { + let description: String + } +} + +// MARK: - Request and Response + +struct Request: Decodable {} + +struct Exchange: Encodable { + @DateCoding + var date: Date + let from: Currency + let to: Currency + let rate: Decimal + let change: Change + + struct Currency: Encodable { + let symbol: String + let emoji: String + } + + enum Change: String, Encodable { + case up + case down + case none + case unknown + } + + @propertyWrapper + public struct DateCoding: Encodable { + public let wrappedValue: Date + + public init(wrappedValue: Date) { + self.wrappedValue = wrappedValue + } + + func encode(to encoder: Encoder) throws { + let string = Self.dateFormatter.string(from: self.wrappedValue) + var container = encoder.singleValueContainer() + try container.encode(string) + } + + private static var dateFormatter: ISO8601DateFormatter { + let dateFormatter = ISO8601DateFormatter() + dateFormatter.timeZone = TimeZone(identifier: "UTC")! + dateFormatter.formatOptions = [.withYear, .withMonth, .withDashSeparatorInDate] + return dateFormatter + } + } +} diff --git a/Examples/LambdaFunctions/Sources/ErrorHandling/main.swift b/Examples/LambdaFunctions/Sources/ErrorHandling/main.swift new file mode 100644 index 00000000..ab8e04be --- /dev/null +++ b/Examples/LambdaFunctions/Sources/ErrorHandling/main.swift @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftAWSLambdaRuntime open source project +// +// Copyright (c) 2020 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 +// +//===----------------------------------------------------------------------===// + +import AWSLambdaRuntime + +// MARK: - Run Lambda + +// switch over the error type "requested" by thr request, and trigger sucg error accordingly +Lambda.run { (context: Lambda.Context, request: Request, callback: (Result) -> Void) in + switch request.error { + // no error here! + case .none: + callback(.success(Response(awsRequestId: context.requestId, requestId: request.requestId, status: .ok))) + // trigger a "managed" error - domain specific business logic failure + case .managed: + callback(.success(Response(awsRequestId: context.requestId, requestId: request.requestId, status: .error))) + // trigger an "unmanaged" error - an unexpected Swift Error triggered while processing the request + case .unmanaged(let error): + callback(.failure(UnmanagedError(description: error))) + // trigger a "fatal" error - a panic type error which will crash the process + case .fatal: + fatalError("crash!") + } +} + +// MARK: - Request and Response + +struct Request: Codable { + let requestId: String + let error: Error + + public init(requestId: String, error: Error? = nil) { + self.requestId = requestId + self.error = error ?? .none + } + + public enum Error: Codable, RawRepresentable { + case none + case managed + case unmanaged(String) + case fatal + + public init?(rawValue: String) { + switch rawValue { + case "none": + self = .none + case "managed": + self = .managed + case "fatal": + self = .fatal + default: + self = .unmanaged(rawValue) + } + } + + public var rawValue: String { + switch self { + case .none: + return "none" + case .managed: + return "managed" + case .fatal: + return "fatal" + case .unmanaged(let error): + return error + } + } + } +} + +struct Response: Codable { + let awsRequestId: String + let requestId: String + let status: Status + + public init(awsRequestId: String, requestId: String, status: Status) { + self.awsRequestId = awsRequestId + self.requestId = requestId + self.status = status + } + + public enum Status: Int, Codable { + case ok + case error + } +} + +struct UnmanagedError: Error { + let description: String +} diff --git a/Examples/LambdaFunctions/Sources/HelloWorld/main.swift b/Examples/LambdaFunctions/Sources/HelloWorld/main.swift new file mode 100644 index 00000000..7535da97 --- /dev/null +++ b/Examples/LambdaFunctions/Sources/HelloWorld/main.swift @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftAWSLambdaRuntime open source project +// +// Copyright (c) 2020 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 +// +//===----------------------------------------------------------------------===// + +import AWSLambdaRuntime + +// introductory example, the obligatory "hello, world!" +Lambda.run { (_: Lambda.Context, _: String, callback: (Result) -> Void) in + callback(.success("hello, world!")) +} diff --git a/Examples/LambdaFunctions/Tests/LinuxMain.swift b/Examples/LambdaFunctions/Tests/LinuxMain.swift new file mode 100644 index 00000000..c46de763 --- /dev/null +++ b/Examples/LambdaFunctions/Tests/LinuxMain.swift @@ -0,0 +1,15 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftAWSLambdaRuntime open source project +// +// Copyright (c) 2020 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 +// +//===----------------------------------------------------------------------===// + +preconditionFailure("use `swift test --enable-test-discovery`") diff --git a/Examples/LambdaFunctions/scripts/build-and-package.sh b/Examples/LambdaFunctions/scripts/build-and-package.sh new file mode 100755 index 00000000..6634539c --- /dev/null +++ b/Examples/LambdaFunctions/scripts/build-and-package.sh @@ -0,0 +1,29 @@ +#!/bin/bash +##===----------------------------------------------------------------------===## +## +## This source file is part of the SwiftAWSLambdaRuntime open source project +## +## Copyright (c) 2020 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 +## +##===----------------------------------------------------------------------===## + +set -eu + +executable=$1 + +echo "-------------------------------------------------------------------------" +echo "building \"$executable\" lambda" +echo "-------------------------------------------------------------------------" +docker run --rm -v `pwd`:/workspace -w /workspace builder bash -cl "swift build --product $executable -c release -Xswiftc -g" +echo "done" + +echo "-------------------------------------------------------------------------" +echo "packaging \"$executable\" lambda" +echo "-------------------------------------------------------------------------" +docker run --rm -v `pwd`:/workspace -w /workspace builder bash -cl "./scripts/package.sh $executable" diff --git a/Examples/LambdaFunctions/scripts/deploy.sh b/Examples/LambdaFunctions/scripts/deploy.sh new file mode 100755 index 00000000..b234ee6a --- /dev/null +++ b/Examples/LambdaFunctions/scripts/deploy.sh @@ -0,0 +1,65 @@ +#!/bin/bash +##===----------------------------------------------------------------------===## +## +## This source file is part of the SwiftAWSLambdaRuntime open source project +## +## Copyright (c) 2020 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 +## +##===----------------------------------------------------------------------===## + +set -eu + +lambda_name=SwiftSample +s3_bucket=swift-lambda-test +executables=( $(swift package dump-package | sed -e 's|: null|: ""|g' | jq '.products[] | (select(.type.executable)) | .name' | sed -e 's|"||g') ) + +if [[ ${#executables[@]} = 0 ]]; then + echo "no executables found" + exit 1 +elif [[ ${#executables[@]} = 1 ]]; then + executable=${executables[0]} +elif [[ ${#executables[@]} > 1 ]]; then + echo "multiple executables found:" + for executable in ${executables[@]}; do + echo " * $executable" + done + echo "" + read -p "select which executables to deploy: " executable +fi + +echo -e "\ndeploying $executable" + +echo "-------------------------------------------------------------------------" +echo "preparing docker build image" +echo "-------------------------------------------------------------------------" +docker build . -t builder + +echo "-------------------------------------------------------------------------" +echo "building \"$executable\" lambda" +echo "-------------------------------------------------------------------------" +docker run --rm -v `pwd`/../..:/workspace -w /workspace builder \ + bash -cl "cd Examples/LambdaFunctions && \ + swift build --product $executable -c release -Xswiftc -g" +echo "done" + +echo "-------------------------------------------------------------------------" +echo "packaging \"$executable\" lambda" +echo "-------------------------------------------------------------------------" +docker run --rm -v `pwd`:/workspace -w /workspace builder bash -cl "./scripts/package.sh $executable" + +echo "-------------------------------------------------------------------------" +echo "uploading \"$executable\" lambda to s3" +echo "-------------------------------------------------------------------------" + +aws s3 cp .build/lambda/$executable/lambda.zip s3://$s3_bucket/ + +echo "-------------------------------------------------------------------------" +echo "updating \"$lambda_name\" to latest \"$executable\"" +echo "-------------------------------------------------------------------------" +aws lambda update-function-code --function $lambda_name --s3-bucket $s3_bucket --s3-key lambda.zip diff --git a/Examples/LambdaFunctions/scripts/package.sh b/Examples/LambdaFunctions/scripts/package.sh new file mode 100755 index 00000000..190be3f8 --- /dev/null +++ b/Examples/LambdaFunctions/scripts/package.sh @@ -0,0 +1,27 @@ +#!/bin/bash +##===----------------------------------------------------------------------===## +## +## This source file is part of the SwiftAWSLambdaRuntime open source project +## +## Copyright (c) 2020 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 +## +##===----------------------------------------------------------------------===## + +set -eu + +executable=$1 + +target=.build/lambda/$executable +rm -rf "$target" +mkdir -p "$target" +cp ".build/release/$executable" "$target/" +cp -Pv /usr/lib/swift/linux/lib*so* "$target" +cd "$target" +ln -s "$executable" "bootstrap" +zip --symlinks lambda.zip * diff --git a/Examples/LambdaFunctions/scripts/sam-deploy.sh b/Examples/LambdaFunctions/scripts/sam-deploy.sh new file mode 100755 index 00000000..3a937828 --- /dev/null +++ b/Examples/LambdaFunctions/scripts/sam-deploy.sh @@ -0,0 +1,47 @@ +#!/bin/bash +##===----------------------------------------------------------------------===## +## +## This source file is part of the SwiftAWSLambdaRuntime open source project +## +## Copyright (c) 2017-2018 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 +## +##===----------------------------------------------------------------------===## + +DIR="$(cd "$(dirname "$0")" && pwd)" + +executables=( $(swift package dump-package | sed -e 's|: null|: ""|g' | jq '.products[] | (select(.type.executable)) | .name' | sed -e 's|"||g') ) + +if [[ ${#executables[@]} = 0 ]]; then + echo "no executables found" + exit 1 +elif [[ ${#executables[@]} = 1 ]]; then + executable=${executables[0]} +elif [[ ${#executables[@]} > 1 ]]; then + echo "multiple executables found:" + for executable in ${executables[@]}; do + echo " * $executable" + done + echo "" + read -p "select which executables to deploy: " executable +fi + +echo -e "\ndeploying $executable" + +echo "-------------------------------------------------------------------------" +echo "preparing docker build image" +echo "-------------------------------------------------------------------------" +docker build . -q -t builder + +$DIR/build-and-package.sh ${executable} + +echo "-------------------------------------------------------------------------" +echo "deploying using SAM" +echo "-------------------------------------------------------------------------" + +sam deploy --template "${executable}-template.yml" $@ diff --git a/scripts/sanity.sh b/scripts/sanity.sh index d5f9d4f6..d0a66939 100755 --- a/scripts/sanity.sh +++ b/scripts/sanity.sh @@ -112,7 +112,7 @@ EOF ( cd "$here/.." find . \ - \( \! -path './.build/*' -a \ + \( \! -path '*/.build/*' -a \ \( "${matching_files[@]}" \) -a \ \( \! \( "${exceptions[@]}" \) \) \) | while read line; do if [[ "$(cat "$line" | replace_acceptable_years | head -n $expected_lines | shasum)" != "$expected_sha" ]]; then