Skip to content

Add Support for Swift 5.7 #153

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jul 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ jobs:
./gradlew :core:swift53Action:distDocker -PdockerRegistry=docker.io -PdockerImagePrefix=openwhisk -PdockerImageTag=$SHORT_COMMIT
./gradlew :core:swift54Action:distDocker -PdockerRegistry=docker.io -PdockerImagePrefix=openwhisk -PdockerImageTag=nightly
./gradlew :core:swift54Action:distDocker -PdockerRegistry=docker.io -PdockerImagePrefix=openwhisk -PdockerImageTag=$SHORT_COMMIT
./gradlew :core:swift57Action:distDocker -PdockerRegistry=docker.io -PdockerImagePrefix=openwhisk -PdockerImageTag=nightly
./gradlew :core:swift57Action:distDocker -PdockerRegistry=docker.io -PdockerImagePrefix=openwhisk -PdockerImageTag=$SHORT_COMMIT
- name: Push Release Images
if: ${{ env.PUSH_RELEASE == 'true' }}
working-directory: runtime
Expand All @@ -113,5 +115,7 @@ jobs:
RUNTIME="swift53Action"
elif [ ${RUNTIME_VERSION} == "5.4" ]; then
RUNTIME="swift54Action"
elif [ ${RUNTIME_VERSION} == "5.7" ]; then
RUNTIME="swift57Action"
fi
./gradlew :core:$RUNTIME:distDocker -PdockerRegistry=docker.io -PdockerImagePrefix=openwhisk -PdockerImageTag=$IMAGE_TAG
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,6 @@ test.json
*.done
examples/*/*.zip
ActionLoop/

#Swift
**/.swiftpm/
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#

sudo: required
dist: xenial
dist: jammy
jdk: openjdk8
language: java
services:
Expand Down
132 changes: 122 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
- [Swift 5.1 CHANGELOG.md](core/swift51Action/CHANGELOG.md)
- [Swift 5.3 CHANGELOG.md](core/swift53Action/CHANGELOG.md)
- [Swift 5.4 CHANGELOG.md](core/swift54Action/CHANGELOG.md)
- [Swift 5.7 CHANGELOG.md](core/swift57Action/CHANGELOG.md)

## Quick Swift Action
### Simple swift action hello.swift
Expand All @@ -45,7 +46,7 @@ func main(args: Any) -> Any {

For the return result, not only support `dictionary`, but also support `array`

So a very simple `hello array` function woule be:
So a very simple `hello array` function would be:

```swift
func main(args: Any) -> Any {
Expand All @@ -63,7 +64,7 @@ So the function can be:
return args
}
```
When invokes above action, we can pass an array object as the input parameter.
When invoking the above action, we can pass an array object as the input parameter.

## Swift 5.x support

Expand All @@ -85,13 +86,13 @@ func main(input: Employee, respondWith: (Employee?, Error?) -> Void) -> Void {
respondWith(input, nil)
}
```
```
```bash
wsk action update helloCodableAsync helloCodableAsync.swift swift:5.1
```
```
```bash
ok: updated action helloCodableAsync
```
```
```bash
wsk action invoke helloCodableAsync -r -p id 73 -p name Andrea
```
```json
Expand Down Expand Up @@ -125,13 +126,13 @@ func main(input: Employee, respondWith: (Employee?, Error?) -> Void) -> Void {
}
}
```
```
```bash
wsk action update helloCodableError helloCodableError.swift swift:5.1
```
```
```bash
ok: updated action helloCodableError
```
```
```bash
wsk action invoke helloCodableError -b -p id 51 -p name Carlos
```
```json
Expand Down Expand Up @@ -159,14 +160,125 @@ To avoid the cold-start delay, you can compile your Swift file into a binary and

Use the docker container and pass the single source file as stdin.
Pass the name of the method to the flag `-compile`
```
```bash
docker run -i openwhisk/action-swift-v5.1 -compile main <main.swift >../action.zip
```

### Compiling Swift 5.1 multiple files with dependencies
Use the docker container and pass a zip archive containing a `Package.swift` and source files a main source file in the location `Sources/main.swift`.
```
```bash
zip - -r * | docker run -i openwhisk/action-swift-v5.1 -compile main >../action.zip
```

For more build examples see [here](./examples/)

# Swift 5.7

In addition to previous ways of defining an action is now possible to use throwing async/await inside the action.

### Async throwing Action with Any Input and Any Output

```swift
func action(args: Any) async throws -> Any {
//async code sleep for 1 sec
try await Task.sleep(nanoseconds: 1_000_000_000)

let newArgs = args as! [String:Any]
if let name = newArgs["name"] as? String {
return [ "greeting" : "Hello \(name)!" ]
} else {
return [ "greeting" : "Hello stranger!" ]
}
}
```

### Async throwing Action with a Codable Input and a Codable Output

```swift
struct Input: Codable {
let name: String?
}

struct Output: Codable {
let count: Int
}

func action(input: Input) async throws -> Output? {
try await Task.sleep(nanoseconds: 1_000_000_000)
if let name = input.name {
return Output(count: name.count)
} else {
return Output(count: 0)
}
}
```

### Async throwing Action with Codable Output

```swift
struct Input: Codable {
let name: String?
}

struct Output: Codable {
let count: Int
}

func action() async throws -> Output? {
try await Task.sleep(nanoseconds: 1_000_000_000)
return Output(count: 0)
}
```


### Example of an async throwing Action with a Codable Input and a Codable Output

In the following example, the main action decodes the URL from `AnInput`, downloads the content from the URL, decodes the JSON and returns the `response` in `AnOutput`.
In case of failure, the runtime will return an error.

```swift
import AsyncHTTPClient
import Foundation
import _Concurrency
import NIOCore
import NIOFoundationCompat

enum RequestError: Error {
case requestError
}
struct AnInput: Codable {
let url: String?
}

struct AnOutput: Codable {
let args: [String: String]
let headers: [String: String]
let origin: String
let url: String
}

let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
let decoder = JSONDecoder()

func main(param: AnInput) async throws -> AnOutput {

let echoURL = param.url ?? "https://httpbin.org/get"
let request = HTTPClientRequest(url: echoURL)
let response = try await httpClient.execute(request, timeout: .seconds(3))
if response.status == .ok {
let bytes = try await response.body.collect(upTo: 1024 * 1024) // 1 MB Buffer
let data = Data(buffer: bytes)
return try decoder.decode(AnOutput.self, from: data)
} else {
throw RequestError.requestError
}
}
```

The full swift package is [here](/tests/dat/actions/SwiftyRequestAsyncCodable57/).

Note that the package of this action contains a dependency from `AsynHTTPClient`, in such case, it's preferred to build the action.

```shell
zip - -r * | docker run -i openwhisk/action-swift-v5.7 -compile main >../action.zip
```
14 changes: 14 additions & 0 deletions ansible/files/runtimes.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,20 @@
"attachmentName": "codefile",
"attachmentType": "text/plain"
}
},
{
"kind": "swift:5.7",
"default": false,
"image": {
"prefix": "testing",
"name": "action-swift-v5.7",
"tag": "latest"
},
"deprecated": false,
"attached": {
"attachmentName": "codefile",
"attachmentType": "text/plain"
}
}
]
},
Expand Down
25 changes: 25 additions & 0 deletions core/swift57Action/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!--
#
# 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.
#
-->

# Apache OpenWhisk Swift 5.7 Runtime Container

- Support for swift async/await

## 1.17.0
- Next Apache Release
66 changes: 66 additions & 0 deletions core/swift57Action/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#
# 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.
#

# build go proxy from source
FROM golang:1.18 AS builder_source
ARG GO_PROXY_GITHUB_USER=apache
ARG GO_PROXY_GITHUB_BRANCH=master
RUN git clone --branch ${GO_PROXY_GITHUB_BRANCH} \
https://github.com/${GO_PROXY_GITHUB_USER}/openwhisk-runtime-go /src ; \
cd /src ; env GO111MODULE=on CGO_ENABLED=0 go build main/proxy.go && \
mv proxy /bin/proxy

# or build it from a release
FROM golang:1.18 AS builder_release
ARG GO_PROXY_RELEASE_VERSION=1.18@1.20.0
RUN curl -sL https://github.com/apache/openwhisk-runtime-go/archive/{$GO_PROXY_RELEASE_VERSION}.tar.gz | tar xzf - \
&& cd openwhisk-runtime-go-*/main \
&& GO111MODULE=on CGO_ENABLED=0 go build -o /bin/proxy

FROM swift:5.7.2

# select the builder to use
ARG GO_PROXY_BUILD_FROM=release

RUN rm -rf /var/lib/apt/lists/* \
&& apt-get clean && apt-get -qq update \
&& apt-get install -y --no-install-recommends locales python3 vim libssl-dev libicu-dev \
&& rm -rf /var/lib/apt/lists/* \
&& locale-gen en_US.UTF-8

ENV LANG="en_US.UTF-8" \
LANGUAGE="en_US:en" \
LC_ALL="en_US.UTF-8"

RUN mkdir -p /swiftAction
WORKDIR /swiftAction

COPY --from=builder_source /bin/proxy /bin/proxy_source
COPY --from=builder_release /bin/proxy /bin/proxy_release
RUN mv /bin/proxy_${GO_PROXY_BUILD_FROM} /bin/proxy
ADD swiftbuild.py /bin/compile
ADD swiftbuild.py.launcher.swift /bin/compile.launcher.swift
COPY _Whisk.swift /swiftAction/Sources/
COPY Package.swift /swiftAction/
COPY swiftbuildandlink.sh /swiftAction/
COPY main.swift /swiftAction/Sources/
RUN swift build -c release; \
touch /swiftAction/Sources/main.swift; \
rm /swiftAction/.build/release/Action

ENV OW_COMPILER=/bin/compile
ENTRYPOINT [ "/bin/proxy" ]
40 changes: 40 additions & 0 deletions core/swift57Action/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// swift-tools-version:5.7
// The swift-tools-version declares the minimum version of Swift required to build this package.

/*
* 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.
*/

import PackageDescription

let package = Package(
name: "Action",
platforms: [
.macOS(.v12),
],
products: [
.executable(
name: "Action",
targets: ["Action"]
)
],
targets: [
.executableTarget(
name: "Action",
path: "."
)
]
)
Loading