You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by du...@apache.org on 2018/03/14 20:59:51 UTC

[incubator-openwhisk] branch master updated: Add swift:4.1 with Codable to default set of runtimes (#3420)

This is an automated email from the ASF dual-hosted git repository.

dubeejw pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk.git


The following commit(s) were added to refs/heads/master by this push:
     new c8bf76b  Add swift:4.1 with Codable to default set of runtimes (#3420)
c8bf76b is described below

commit c8bf76b92566bc3f48fa53a6360f509e1a19a8a0
Author: Carlos Santana <cs...@gmail.com>
AuthorDate: Wed Mar 14 16:59:47 2018 -0400

    Add swift:4.1 with Codable to default set of runtimes (#3420)
    
    * runtime and tests for swift41
    
    * no more need for softlink dat
    
    * update swift 4 docs
    
    * add example of swift4 action with no input
    
    * add example of error handling
---
 actionRuntimes/swift4.1Action/Dockerfile           |   1 +
 actionRuntimes/swift4.1Action/build.gradle         |   2 +
 ansible/files/runtimes.json                        |   9 +-
 docs/actions.md                                    | 227 ++++++++++++++++-----
 docs/reference.md                                  |   8 +-
 .../scala/system/basic/WskBasicSwift3Tests.scala   |   2 +-
 .../system/basic/WskRestBasicSwift41Tests.scala    |  30 +++
 .../system/basic/WskRestUnicodeSwift41Tests.scala  |  32 +++
 tools/build/compile_swift.sh                       |  79 +++++++
 9 files changed, 340 insertions(+), 50 deletions(-)

diff --git a/actionRuntimes/swift4.1Action/Dockerfile b/actionRuntimes/swift4.1Action/Dockerfile
new file mode 100755
index 0000000..3a225fe
--- /dev/null
+++ b/actionRuntimes/swift4.1Action/Dockerfile
@@ -0,0 +1 @@
+FROM openwhisk/action-swift-v4.1:1.0.1
diff --git a/actionRuntimes/swift4.1Action/build.gradle b/actionRuntimes/swift4.1Action/build.gradle
new file mode 100755
index 0000000..7e91809
--- /dev/null
+++ b/actionRuntimes/swift4.1Action/build.gradle
@@ -0,0 +1,2 @@
+ext.dockerImageName = 'action-swift-v4.1'
+apply from: '../../gradle/docker.gradle'
diff --git a/ansible/files/runtimes.json b/ansible/files/runtimes.json
index 42858d6..1866b69 100644
--- a/ansible/files/runtimes.json
+++ b/ansible/files/runtimes.json
@@ -66,11 +66,18 @@
             },
             {
                 "kind": "swift:3.1.1",
-                "default": true,
                 "image": {
                     "name": "action-swift-v3.1.1"
                 },
                 "deprecated": false
+            },
+            {
+                "kind": "swift:4.1",
+                "default": true,
+                "image": {
+                    "name": "action-swift-v4.1"
+                },
+                "deprecated": false
             }
         ],
         "java": [
diff --git a/docs/actions.md b/docs/actions.md
index 327daf2..61e2fa6 100644
--- a/docs/actions.md
+++ b/docs/actions.md
@@ -666,13 +666,14 @@ wsk action create helloPHP --kind php:7.1 helloPHP.zip
 
 The process of creating Swift actions is similar to that of JavaScript actions. The following sections guide you through creating and invoking a single swift action, and packaging an action in a zip file. 
 
-You can also use the online [Swift Sandbox](https://swiftlang.ng.bluemix.net) to test your Swift code without having to install Xcode on your machine.
+You can also use the online [Online Swift Playground](http://online.swiftplayground.run) to test your Swift code without having to install Xcode on your machine.
 
 **Attention:** Swift actions run in a Linux environment. Swift on Linux is still in
 development, and OpenWhisk usually uses the latest available release, which is not necessarily stable. In addition, the version of Swift that is used with OpenWhisk might be inconsistent with versions of Swift from stable releases of Xcode on MacOS.
 
 ### Creating and invoking an action
 
+#### Swift 3
 An action is simply a top-level Swift function. For example, create a file called
 `hello.swift` with the following content:
 
@@ -685,17 +686,55 @@ func main(args: [String:Any]) -> [String:Any] {
     }
 }
 ```
+In this example the Swift action consumes a dictionary and produces a dictionary.
+
+You can create an OpenWhisk action called `helloSwift` from this function as
+follows:
+
+```
+wsk action create helloSwift hello.swift --kind swift:3.1.1
+```
+
+#### Swift 4
+
+New in Swift 4 in addition of the above main function signature there are two more signatures out of the box taking advantage of the [Codable](https://developer.apple.com/documentation/swift/codable) type. You can learn more about data types encodable and decodable for compatibility with external representations such as JSON [here](https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types).
+
+The following takes as input parameter a Codable Input with field `name`, and returns a Codable output with a field `greetings`
+```swift
+struct Input: Codable {
+    let name: String?
+}
+struct Output: Codable {
+    let greeting: String
+}
+func main(param: Input, completion: (Output?, Error?) -> Void) -> Void {
+    let result = Output(greeting: "Hello \(param.name ?? "stranger")!")
+    print("Log greeting:\(result.greeting)")
+    completion(result, nil)
+}
+```
+In this example the Swift action consumes a Codable and produces a Codable type.
+If you don't need to handle any input you can use the function signature that doesn't take any input, only Codable output.
+```swift
+struct Output: Codable {
+    let greeting: String
+}
+func main(completion: (Output?, Error?) -> Void) -> Void {
+    let result = Output(greeting: "Hello OpenWhisk!")
+    completion(result, nil)
+}
+```
 
-Swift actions always consume a dictionary and produce a dictionary.
 
 You can create a OpenWhisk action called `helloSwift` from this function as
 follows:
 
 ```
-wsk action create helloSwift hello.swift
+wsk action create helloSwift hello.swift --kind swift:4.1
 ```
 
-The CLI automatically infers the type of the action from the source file extension. For `.swift` source files, the action runs using a Swift 3.1.1 runtime. See the Swift [reference](./reference.md#swift-actions) for more information about the Swift runtime.
+
+See the Swift [reference](./reference.md#swift-actions) for more information about the Swift runtime.
 
 Action invocation is the same for Swift actions as it is for JavaScript actions:
 
@@ -715,28 +754,87 @@ Find out more about parameters in the [Working with parameters](./parameters.md)
 
 When you create an OpenWhisk Swift action with a Swift source file, it has to be compiled into a binary before the action is run. Once done, subsequent calls to the action are much faster until the container holding your action is purged. This delay is known as the cold-start delay.
 
-To avoid the cold-start delay, you can compile your Swift file into a binary and then upload to OpenWhisk in a zip file. As you need the OpenWhisk scaffolding, the easiest way to create the binary is to build it within the same environment as it will be run in. These are the steps:
-
-- Run an interactive Swift action container.
-  ```
-  docker run --rm -it -v "$(pwd):/owexec" openwhisk/action-swift-v3.1.1 bash
-  ```
-  This puts you in a bash shell within the Docker container.
+To avoid the cold-start delay, you can compile your Swift file into a binary and then upload to OpenWhisk in a zip file. As you need the OpenWhisk scaffolding, the easiest way to create the binary is to build it within the same environment as it will be run in. 
 
-- Copy the source code and prepare to build it.
-  ```
-  cp /owexec/hello.swift /swift3Action/spm-build/main.swift
-  ```
-  ```
-  cat /swift3Action/epilogue.swift >> /swift3Action/spm-build/main.swift
-  ```
-  ```
-  echo '_run_main(mainFunction:main)' >> /swift3Action/spm-build/main.swift
-  ```
-  Copy any additional source files to `/swift3Action/spm-build/`
+### Using a script to build Swift packaged action
+You can use a script to automate the packaging of the action. Create  script `compile.sh`h file the following.
+```bash
+#!/bin/bash
+set -ex
+
+if [ -z "$1" ] ; then
+    echo 'Error: Missing action name'
+    exit 1
+fi
+if [ -z "$2" ] ; then
+    echo 'Error: Missing runtime docker image name, for example openwhisk/action-swift-v4.0'
+    exit 2
+fi
+OUTPUT_DIR="build"
+if [ ${2} == "swift:3.1.1" ]; then
+  BASE_PATH="/swift3Action"
+  DEST_SOURCE="$BASE_PATH/spm-build"
+  RUNTIME="openwhisk/action-swift-v3.1.1"
+elif [ ${2} == "swift:4.1" ]; then
+  RUNTIME="openwhisk/action-swift-v4.1"
+  BASE_PATH="/swift4Action"
+  DEST_SOURCE="/$BASE_PATH/spm-build/Sources/Action"
+else
+  echo "Error: Kind $2 not recognize"
+  exit 3
+fi
+DEST_PACKAGE_SWIFT="$BASE_PATH/spm-build/Package.swift"
+
+BUILD_FLAGS=""
+if [ -n "$3" ] ; then
+    BUILD_FLAGS=${3}
+fi
+
+echo "Using runtime $RUNTIME to compile swift"
+docker run --rm --name=compile-ow-swift -it -v "$(pwd):/owexec" $RUNTIME bash -ex -c "
+
+if [ -f \"/owexec/$OUTPUT_DIR/$1.zip\" ] ; then
+    rm \"/owexec/$OUTPUT_DIR/$1.zip\"
+fi
+
+echo 'Setting up build...'
+cp /owexec/actions/$1/Sources/*.swift $DEST_SOURCE/
+
+# action file can be either {action name}.swift or main.swift
+if [ -f \"$DEST_SOURCE/$1.swift\" ] ; then
+    echo 'renaming $DEST_SOURCE/$1.swift $DEST_SOURCE/main.swift'
+    mv \"$DEST_SOURCE/$1.swift\" $DEST_SOURCE/main.swift
+fi
+# Add in the OW specific bits
+cat $BASE_PATH/epilogue.swift >> $DEST_SOURCE/main.swift
+echo '_run_main(mainFunction:main)' >> $DEST_SOURCE/main.swift
+
+echo \"Compiling $1...\"
+cd /$BASE_PATH/spm-build
+cp /owexec/actions/$1/Package.swift $DEST_PACKAGE_SWIFT
+# we have our own Package.swift, do a full compile
+swift build ${BUILD_FLAGS} -c release
+
+echo 'Creating archive $1.zip...'
+#.build/release/Action
+mkdir -p /owexec/$OUTPUT_DIR
+zip \"/owexec/$OUTPUT_DIR/$1.zip\" .build/release/Action
+
+"
+```
 
+The script assumes you have a directory `actions` with each top level directory representing an action.
+```
+actions/
+├── hello
+│   ├── Package.swift
+│   └── Sources
+│       └── main.swift
+```
 
-- (Optional) Create the `Package.swift` file to add dependencies.
+- Create the `Package.swift` file to add dependencies.
+The syntax is different from Swift 3 to Swift 4 tools.
+For Swift 3 here is an example:
   ```swift
   import PackageDescription
 
@@ -751,40 +849,53 @@ To avoid the cold-start delay, you can compile your Swift file into a binary and
         ]
   )
   ```
-  As you can see this example adds `swift-watson-sdk` and `example-package-deckofplayingcards` dependencies.
-  Notice that `CCurl`, `Kitura-net` and `SwiftyJSON` are provided in the standard Swift action
-and so you should include them in your own `Package.swift`.
-
-- Copy Package.swift to spm-build directory
-  ```
-  cp /owexec/Package.swift /swift3Action/spm-build/Package.swift
-  ```
+  For Swift 4 here is an example:
+  ```swift
+  // swift-tools-version:4.0
+  import PackageDescription
 
-- Change to the spm-build directory.
-  ```
-  cd /swift3Action/spm-build
+  let package = Package(
+      name: "Action",
+      products: [
+        .executable(
+          name: "Action",
+          targets:  ["Action"]
+        )
+      ],
+      dependencies: [
+        .package(url: "https://github.com/apple/example-package-deckofplayingcards.git", .upToNextMajor(from: "3.0.0"))
+      ],
+      targets: [
+        .target(
+          name: "Action",
+          dependencies: ["DeckOfPlayingCards"],
+          path: "."
+        )
+      ]
+  )
   ```
+  As you can see this example adds `example-package-deckofplayingcards` as a dependency.
+  Notice that `CCurl`, `Kitura-net` and `SwiftyJSON` are provided in the standard Swift action
+and so you should include them in your own `Package.swift` only for Swift 3 actions.
 
-- Compile your Swift Action.
+- Build the action by runing the following command for a Swift 3 action:
   ```
-  swift build -c release
+  bash compile.sh hello swift:3.1.1
   ```
-
-- Create the zip archive.
+  To compile for Swift 4 use `swift:4.1` instead of `swift:3.1.1`
   ```
-  zip /owexec/hello.zip .build/release/Action
+  bash compile.sh hello swift:4.1
   ```
+  This has created hello.zip in the `build`.
 
-- Exit the Docker container.
+- Upload it to OpenWhisk with the action name helloSwifty:
+  For Swift 3 use the kind `swift:3.1.1`
   ```
-  exit
+  wsk action update helloSwiftly build/hello.zip --kind swift:3.1.1
   ```
-
-  This has created hello.zip in the same directory as hello.swift.
-
-- Upload it to OpenWhisk with the action name helloSwifty:
+  For Swift 4 use the kind `swift:3.1.1`
   ```
-  wsk action update helloSwiftly hello.zip --kind swift:3.1.1
+  wsk action update helloSwiftly build/hello.zip --kind swift:4.1
   ```
 
 - To check how much faster it is, run
@@ -792,8 +903,30 @@ and so you should include them in your own `Package.swift`.
   wsk action invoke helloSwiftly --blocking
   ```
 
+  The time it took for the action to run is in the "duration" property and compare to the time it takes to run with a compilation step in the hello action.
+
+### Erro Handling in Swift 4
+
+With the new Codable completion handler, you can pass an Error to indicate a failure in your Action.
+[Error handling in Swift](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html) resembles exception handling in other languages, with the use of the `try, catch` and `throw` keywords.
+The following example shows a an example on hanlding an error
+```swift
+enum VendingMachineError: Error {
+    case invalidSelection
+    case insufficientFunds(coinsNeeded: Int)
+    case outOfStock
+}
+func main(param: Input, completion: (Output?, Error?) -> Void) -> Void {
+    // Return real error
+    do{
+        throw VendingMachineError.insufficientFunds(coinsNeeded: 5)
+    } catch {
+        completion(nil, error)
+    } 
+}
+```
+
 
-The time it took for the action to run is in the "duration" property and compare to the time it takes to run with a compilation step in the hello action.
 
 ## Creating Java actions
 
diff --git a/docs/reference.md b/docs/reference.md
index ae621ec..335f287 100644
--- a/docs/reference.md
+++ b/docs/reference.md
@@ -378,13 +378,19 @@ Python 2 actions are executed using Python 2.7.12. This is the default runtime f
 
 ### Swift 3
 Swift 3 actions are executed using Swift 3.1.1  `--kind swift:3.1.1`.  
-The default `--kind swift:default` is Swift 3.1.1.
 
 Swift 3.1.1 actions can use the following packages:
 - KituraNet version 1.7.6, https://github.com/IBM-Swift/Kitura-net
 - SwiftyJSON version 15.0.1, https://github.com/IBM-Swift/SwiftyJSON
 - Watson Developer Cloud SDK version 0.16.0, https://github.com/watson-developer-cloud/swift-sdk
 
+### Swift 4
+Swift 4 actions are executed using Swift 4.1  `--kind swift:4.1`.  
+The default `--kind swift:default` is Swift 4.1.
+
+Swift 4.1 action runtime doesn't embed any packages, follow the instructions for [packaged swift actions](./actions.md#packaging-an-action-as-a-swift-executable) to include dependencies using a Package.swift.
+ 
+
 ## PHP actions
 
 PHP actions are executed using PHP 7.1. To use this runtime, specify the `wsk` CLI parameter `--kind php:7.1` when creating or updating an action. This is the default when creating an action with file that has a `.php` extension.
diff --git a/tests/src/test/scala/system/basic/WskBasicSwift3Tests.scala b/tests/src/test/scala/system/basic/WskBasicSwift3Tests.scala
index bd95619..ea6e14c 100644
--- a/tests/src/test/scala/system/basic/WskBasicSwift3Tests.scala
+++ b/tests/src/test/scala/system/basic/WskBasicSwift3Tests.scala
@@ -37,7 +37,7 @@ abstract class WskBasicSwift3Tests extends TestHelpers with WskTestHelpers with
   implicit val wskprops: common.WskProps = WskProps()
   val wsk: BaseWsk
   val defaultAction: Some[String] = Some(TestUtils.getTestActionFilename("hello.swift"))
-  lazy val currentSwiftDefaultKind = "swift:3.1.1"
+  lazy val actionKind = "swift:3.1.1"
 
   behavior of "Swift runtime"
 
diff --git a/tests/src/test/scala/system/basic/WskRestBasicSwift41Tests.scala b/tests/src/test/scala/system/basic/WskRestBasicSwift41Tests.scala
new file mode 100644
index 0000000..2a44ccb
--- /dev/null
+++ b/tests/src/test/scala/system/basic/WskRestBasicSwift41Tests.scala
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package system.basic
+
+import common.rest.WskRest
+
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
+
+@RunWith(classOf[JUnitRunner])
+class WskRestBasicSwift41Tests extends WskBasicSwift3Tests {
+  override val wsk: common.rest.WskRest = new WskRest
+  override lazy val actionKind = "swift:4.1"
+
+}
diff --git a/tests/src/test/scala/system/basic/WskRestUnicodeSwift41Tests.scala b/tests/src/test/scala/system/basic/WskRestUnicodeSwift41Tests.scala
new file mode 100644
index 0000000..3ea4553
--- /dev/null
+++ b/tests/src/test/scala/system/basic/WskRestUnicodeSwift41Tests.scala
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package system.basic
+
+import common.{JsHelpers, WskTestHelpers}
+import common.rest.WskRest
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
+
+@RunWith(classOf[JUnitRunner])
+class WskRestUnicodeSwift41Tests extends WskUnicodeTests with WskTestHelpers with JsHelpers {
+
+  override val wsk: common.rest.WskRest = new WskRest
+  override lazy val actionKind = "swift:4.1"
+  override lazy val actionSource = "unicode.swift"
+
+}
diff --git a/tools/build/compile_swift.sh b/tools/build/compile_swift.sh
new file mode 100755
index 0000000..7deb934
--- /dev/null
+++ b/tools/build/compile_swift.sh
@@ -0,0 +1,79 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+set -ex
+
+if [ -z "$1" ] ; then
+    echo 'Error: Missing action name'
+    exit 1
+fi
+if [ -z "$2" ] ; then
+    echo 'Error: Missing runtime docker image name, for example openwhisk/action-swift-v4.0'
+    exit 2
+fi
+OUTPUT_DIR="build"
+if [ ${2} == "swift:3.1.1" ]; then
+  BASE_PATH="/swift3Action"
+  DEST_SOURCE="$BASE_PATH/spm-build"
+  RUNTIME="openwhisk/action-swift-v3.1.1"
+elif [ ${2} == "swift:4.1" ]; then
+  RUNTIME="openwhisk/action-swift-v4.1"
+  BASE_PATH="/swift4Action"
+  DEST_SOURCE="/$BASE_PATH/spm-build/Sources/Action"
+else
+  echo "Error: Kind $2 not recognize"
+  exit 3
+fi
+DEST_PACKAGE_SWIFT="$BASE_PATH/spm-build/Package.swift"
+
+BUILD_FLAGS=""
+if [ -n "$3" ] ; then
+    BUILD_FLAGS=${3}
+fi
+
+echo "Using runtime $RUNTIME to compile swift"
+docker run --rm --name=compile-ow-swift -it -v "$(pwd):/owexec" $RUNTIME bash -ex -c "
+
+if [ -f \"/owexec/$OUTPUT_DIR/$1.zip\" ] ; then
+    rm \"/owexec/$OUTPUT_DIR/$1.zip\"
+fi
+
+echo 'Setting up build...'
+cp /owexec/actions/$1/Sources/*.swift $DEST_SOURCE/
+
+# action file can be either {action name}.swift or main.swift
+if [ -f \"$DEST_SOURCE/$1.swift\" ] ; then
+    echo 'renaming $DEST_SOURCE/$1.swift $DEST_SOURCE/main.swift'
+    mv \"$DEST_SOURCE/$1.swift\" $DEST_SOURCE/main.swift
+fi
+# Add in the OW specific bits
+cat $BASE_PATH/epilogue.swift >> $DEST_SOURCE/main.swift
+echo '_run_main(mainFunction:main)' >> $DEST_SOURCE/main.swift
+
+echo \"Compiling $1...\"
+cd /$BASE_PATH/spm-build
+cp /owexec/actions/$1/Package.swift $DEST_PACKAGE_SWIFT
+# we have our own Package.swift, do a full compile
+swift build ${BUILD_FLAGS} -c release
+
+echo 'Creating archive $1.zip...'
+#.build/release/Action
+mkdir -p /owexec/$OUTPUT_DIR
+zip \"/owexec/$OUTPUT_DIR/$1.zip\" .build/release/Action
+
+"
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
dubeejw@apache.org.