You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by cs...@apache.org on 2019/01/08 02:33:05 UTC

[incubator-openwhisk-runtime-swift] 01/02: switf4.2.1 with actionloop base implementation

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

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

commit 3fb47475f95f663d905229f493c42eddd0f4d595
Author: Michele Sciabarra <mi...@sciabarra.com>
AuthorDate: Sat Nov 17 13:02:54 2018 +0100

    switf4.2.1 with actionloop base implementation
    
    whitespaces and headers...
---
 .gitignore                                         |   4 +
 core/swift421ActionLoop/Dockerfile                 |  39 ++++++
 .../swift421ActionLoop/build.gradle                |  23 +---
 core/swift421ActionLoop/swiftbuild.py              | 133 +++++++++++++++++++++
 .../swiftbuild.py.launcher.swift                   |  67 +++++++++++
 examples/swift-main-single/Makefile                |  35 ++++++
 .../swift-main-single/main.swift                   |  28 ++---
 settings.gradle                                    |   2 +
 8 files changed, 289 insertions(+), 42 deletions(-)

diff --git a/.gitignore b/.gitignore
index 039da65..6dc577b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -73,3 +73,7 @@ ansible/roles/nginx/files/*cert.pem
 !tests/dat/build/swift4.1/SwiftyRequestCodable.zip
 !tests/dat/build/swift4.1/HelloSwift4Codable.zip
 
+# Makefile artifacts
+test.json
+*.done
+examples/swift-main-single/main.zip
diff --git a/core/swift421ActionLoop/Dockerfile b/core/swift421ActionLoop/Dockerfile
new file mode 100644
index 0000000..506da76
--- /dev/null
+++ b/core/swift421ActionLoop/Dockerfile
@@ -0,0 +1,39 @@
+#
+# 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.
+#
+FROM openwhisk/actionloop as builder
+
+FROM swift:4.2.1
+
+RUN rm -rf /var/lib/apt/lists/* && apt-get clean && apt-get update \
+	&& apt-get install -y --no-install-recommends locales python3 \
+	&& 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 /bin/proxy /bin/proxy
+ADD swiftbuild.py /bin/compile
+ADD swiftbuild.py.launcher.swift /bin/compile.launcher.swift
+
+ENV OW_COMPILER=/bin/compile
+ENTRYPOINT [ "/bin/proxy" ]
diff --git a/settings.gradle b/core/swift421ActionLoop/build.gradle
old mode 100644
new mode 100755
similarity index 64%
copy from settings.gradle
copy to core/swift421ActionLoop/build.gradle
index 0009fa4..d9bb28f
--- a/settings.gradle
+++ b/core/swift421ActionLoop/build.gradle
@@ -15,24 +15,5 @@
  * limitations under the License.
  */
 
-include 'tests'
-
-include 'core:swift3.1.1Action'
-
-include 'core:swift41Action'
-
-rootProject.name = 'runtime-swift'
-
-gradle.ext.openwhisk = [
-        version: '1.0.0-SNAPSHOT'
-]
-
-gradle.ext.scala = [
-    version: '2.12.7',
-    compileFlags: ['-feature', '-unchecked', '-deprecation', '-Xfatal-warnings', '-Ywarn-unused-import']
-]
-
-gradle.ext.scalafmt = [
-    version: '1.5.0',
-    config: new File(rootProject.projectDir, '.scalafmt.conf')
-]
+ext.dockerImageName = 'actionloop-swift-v4.2.1'
+apply from: '../../gradle/docker.gradle'
diff --git a/core/swift421ActionLoop/swiftbuild.py b/core/swift421ActionLoop/swiftbuild.py
new file mode 100755
index 0000000..49ec29d
--- /dev/null
+++ b/core/swift421ActionLoop/swiftbuild.py
@@ -0,0 +1,133 @@
+#!/usr/bin/env python3
+"""Swift Action Compiler
+#
+# 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.
+#
+"""
+
+from __future__ import print_function
+import os
+import re
+import sys
+import codecs
+import subprocess
+from io import StringIO
+
+package_swift = """// swift-tools-version:4.2
+import PackageDescription
+
+let package = Package(
+    name: "exec",
+    dependencies: [],
+    targets: [
+      .target(
+        name: "exec",
+        dependencies: [])
+    ]
+)
+"""
+output = StringIO()
+
+def eprint(*args, **kwargs):
+    print(*args, file=output, **kwargs)
+
+def sources(launcher, source_dir, main):
+    # create Packages.swift
+    packagefile = "%s/Package.swift" % source_dir
+    if not os.path.isfile(packagefile):
+        with codecs.open(packagefile, 'w', 'utf-8') as s:
+            s.write(package_swift)
+
+    # create Sources/Action dir
+    actiondir = "%s/Sources/exec" % source_dir
+    if not os.path.isdir(actiondir):
+        os.makedirs(actiondir, mode=0o755)
+
+    # copy the exec to exec.go
+    # also check if it has a main in it
+    src = "%s/exec" % source_dir
+    dst = "%s/exec.swift" % actiondir
+    if os.path.isfile(src):
+        with codecs.open(src, 'r', 'utf-8') as s:
+            with codecs.open(dst, 'w', 'utf-8') as d:
+                body = s.read()
+                d.write(body)
+
+    # copy the launcher fixing the main
+    dst = "%s/main.swift" % actiondir
+    with codecs.open(dst, 'w', 'utf-8') as d:
+        with codecs.open(launcher, 'r', 'utf-8') as e:
+            code = e.read()
+            code += "_run_main(mainFunction: %s)\n" % main
+            d.write(code)
+
+def swift_build(dir, extra_args=[]):
+    base_args =  ["swift", "build", "--package-path", dir,  "-c", "release"]
+    # compile...
+    env = {
+      "PATH": os.environ["PATH"]
+    }
+    p = subprocess.Popen(base_args+extra_args,
+        stdout=subprocess.PIPE,
+        stderr=subprocess.PIPE,
+        cwd=dir,
+        env=env)
+    (o, e) = p.communicate()
+    # stdout/stderr may be either text or bytes, depending on Python
+    # version, so if bytes, decode to text. Note that in Python 2
+    # a string will match both types; so also skip decoding in that case
+    if isinstance(o, bytes) and not isinstance(o, str):
+        o = o.decode('utf-8')
+    if isinstance(e, bytes) and not isinstance(e, str):
+        e = e.decode('utf-8')
+    return p.returncode, o, e
+
+def build(source_dir, target_file):
+    r, o, e = swift_build(source_dir)
+    if e: eprint(e)
+    if o: eprint(o)
+    if r != 0:
+        print(output.getvalue())
+        return
+
+    r, o, e = swift_build(source_dir, ["--show-bin-path"])
+    if e: eprint(e)
+    if r != 0:
+        print(output.getvalue())
+        return
+
+    bin_file = "%s/exec" % o.strip()
+    os.rename(bin_file, target_file)
+    if not os.path.isfile(target_file):
+        eprint("failed %s -> %s" % (bin_file, target_file))
+        print(output.getvalue())
+        return
+
+
+def main(argv):
+    if len(argv) < 4:
+        print("usage: <main-function> <source-dir> <target-dir>")
+        sys.exit(1)
+
+    main = argv[1]
+    source_dir = os.path.abspath(argv[2])
+    target = os.path.abspath("%s/exec" % argv[3])
+    launch = os.path.abspath(argv[0]+".launcher.swift")
+    sources(launch, source_dir, main)
+    build(source_dir, target)
+
+if __name__ == '__main__':
+    main(sys.argv)
diff --git a/core/swift421ActionLoop/swiftbuild.py.launcher.swift b/core/swift421ActionLoop/swiftbuild.py.launcher.swift
new file mode 100644
index 0000000..de649ab
--- /dev/null
+++ b/core/swift421ActionLoop/swiftbuild.py.launcher.swift
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+// Imports
+import Foundation
+#if os(Linux)
+    import Glibc
+#else
+    import Darwin
+#endif
+
+func _whisk_print_error(message: String, error: Error?){
+    var errStr =  "{\"error\":\"\(message)\"}\n"
+    if let error = error {
+      errStr = "{\"error\":\"\(message) \(error.localizedDescription)\"\n}"
+    }
+    let buf : [UInt8] = Array(errStr.utf8)
+    write(3, buf, buf.count)
+}
+
+// snippet of code "injected" (wrapper code for invoking traditional main)
+func _run_main(mainFunction: ([String: Any]) -> [String: Any]) -> Void {
+    while let inputStr: String = readLine() {
+        do {
+            let json = inputStr.data(using: .utf8, allowLossyConversion: true)!
+            let parsed = try JSONSerialization.jsonObject(with: json, options: []) as! [String: Any]
+            // TODO put the values in the env
+            let value = parsed["value"] as! [String: Any]
+            let result = mainFunction(value)
+            if JSONSerialization.isValidJSONObject(result) {
+                do {
+                    let jsonData = try JSONSerialization.data(withJSONObject: result, options: [])
+                    var json = [UInt8](jsonData)
+                    json.append(10)
+                    write(3, json, json.count)
+                    fflush(stdout)
+                    fflush(stderr)
+                } catch {
+                    _whisk_print_error(message: "Failed to encode Dictionary type to JSON string:", error: error)
+                }
+            } else {
+                _whisk_print_error(message: "Error serializing JSON, data does not appear to be valid JSON", error: nil)
+            }
+        } catch {
+            _whisk_print_error(message: "Failed to execute action handler with error:", error: error)
+            return
+        }
+    }
+}
+
+// snippets of code "injected", dependending on the type of function the developer
+// wants to use traditional vs codable
+
diff --git a/examples/swift-main-single/Makefile b/examples/swift-main-single/Makefile
new file mode 100644
index 0000000..0545f1b
--- /dev/null
+++ b/examples/swift-main-single/Makefile
@@ -0,0 +1,35 @@
+OW_USER?=openwhisk
+OW_RUNTIME?=$(OW_USER)/actionloop-swift-v4.2.1
+OW_COMPILER?=$(OW_USER)/actionloop-swift-v4.2.1
+WSK?=wsk
+MAIN=main
+PACKAGE=test
+SRC=$(MAIN).swift
+NAME=swift-$(MAIN)-single
+ZIP=$(MAIN).zip
+
+deploy: package.done $(ZIP)
+	$(WSK) action update $(PACKAGE)/$(NAME) $(ZIP) --main $(MAIN) --docker $(OW_RUNTIME)
+
+devel: package.done $(SRC)
+	$(WSK) action update $(PACKAGE)/$(NAME) $(SRC) --main $(MAIN) --docker $(OW_COMPILER)
+
+$(ZIP): $(SRC)
+	docker run -i $(OW_COMPILER) -compile $(MAIN) <$(SRC) >$(ZIP)
+
+clean:
+	wsk action delete $(PACKAGE)/$(NAME)
+	rm $(ZIP) package.done
+
+test: test.json
+	$(WSK) action invoke test/$(NAME) -r
+	$(WSK) action invoke test/$(NAME) -P test.json -r
+
+test.json:
+	echo '{ "name": "Mike" }' >test.json
+
+package.done:
+	$(WSK) package update $(PACKAGE)
+	touch package.done
+
+.PHONY: deploy devel test clean
diff --git a/settings.gradle b/examples/swift-main-single/main.swift
similarity index 64%
copy from settings.gradle
copy to examples/swift-main-single/main.swift
index 0009fa4..7d8521e 100644
--- a/settings.gradle
+++ b/examples/swift-main-single/main.swift
@@ -15,24 +15,10 @@
  * limitations under the License.
  */
 
-include 'tests'
-
-include 'core:swift3.1.1Action'
-
-include 'core:swift41Action'
-
-rootProject.name = 'runtime-swift'
-
-gradle.ext.openwhisk = [
-        version: '1.0.0-SNAPSHOT'
-]
-
-gradle.ext.scala = [
-    version: '2.12.7',
-    compileFlags: ['-feature', '-unchecked', '-deprecation', '-Xfatal-warnings', '-Ywarn-unused-import']
-]
-
-gradle.ext.scalafmt = [
-    version: '1.5.0',
-    config: new File(rootProject.projectDir, '.scalafmt.conf')
-]
+func main(args: [String:Any]) -> [String:Any] {
+    if let name = args["name"] as? String {
+        return [ "greeting" : "Hello \(name)!" ]
+    } else {
+        return [ "greeting" : "Hello swif4!" ]
+    }
+}
diff --git a/settings.gradle b/settings.gradle
index 0009fa4..4627e15 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -21,6 +21,8 @@ include 'core:swift3.1.1Action'
 
 include 'core:swift41Action'
 
+include 'core:swift421ActionLoop'
+
 rootProject.name = 'runtime-swift'
 
 gradle.ext.openwhisk = [