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

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


The following commit(s) were added to refs/heads/master by this push:
     new 4296f2e  Add golang 1.22 (#195)
4296f2e is described below

commit 4296f2e4f576194b762d199da2c57b303a8175d7
Author: Luke Roy <[email protected]>
AuthorDate: Thu Feb 8 07:17:37 2024 +0100

    Add golang 1.22 (#195)
---
 .github/workflows/ci.yaml                          |   2 +
 .gitignore                                         |   1 +
 CHANGES.md                                         |   3 +
 golang1.22/Dockerfile                              |  54 ++++++++
 golang1.22/Makefile                                |  44 +++++++
 golang1.22/bin/compile                             | 138 ++++++++++++++++++++
 settings.gradle => golang1.22/build.gradle         |  39 +++---
 golang1.22/lib/launcher.go                         | 141 +++++++++++++++++++++
 settings.gradle                                    |   1 +
 .../ActionLoopBasicGo22Tests.scala                 |  36 ++----
 .../ActionLoopGo22ContainerTests.scala             |  34 ++---
 11 files changed, 424 insertions(+), 69 deletions(-)

diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 6041397..c475af2 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -96,6 +96,8 @@ jobs:
           ./gradlew :golang1.20:distDocker -PdockerRegistry=docker.io 
-PdockerImagePrefix=openwhisk -PdockerImageTag=$SHORT_COMMIT
           ./gradlew :golang1.21:distDocker -PdockerRegistry=docker.io 
-PdockerImagePrefix=openwhisk -PdockerImageTag=nightly
           ./gradlew :golang1.21:distDocker -PdockerRegistry=docker.io 
-PdockerImagePrefix=openwhisk -PdockerImageTag=$SHORT_COMMIT
+          ./gradlew :golang1.22:distDocker -PdockerRegistry=docker.io 
-PdockerImagePrefix=openwhisk -PdockerImageTag=nightly
+          ./gradlew :golang1.22:distDocker -PdockerRegistry=docker.io 
-PdockerImagePrefix=openwhisk -PdockerImageTag=$SHORT_COMMIT
       - name: Push Release Images
         if: ${{ env.PUSH_RELEASE == 'true' }}
         working-directory: runtime
diff --git a/.gitignore b/.gitignore
index bb1e273..c28e4c1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,6 +20,7 @@ actionloop/proxy
 golang1.19/proxy
 golang1.20/proxy
 golang1.21/proxy
+golang1.22/proxy
 
 # Go test transient files
 openwhisk/_test/exec
diff --git a/CHANGES.md b/CHANGES.md
index 464ea6a..fc9ab72 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -16,6 +16,9 @@
 # limitations under the License.
 #
 -->
+# Latest
+- Add support for golang 1.22
+
 # 1.23.0
 - Add support for golang 1.21 (#193)
 
diff --git a/golang1.22/Dockerfile b/golang1.22/Dockerfile
new file mode 100644
index 0000000..97ec30f
--- /dev/null
+++ b/golang1.22/Dockerfile
@@ -0,0 +1,54 @@
+#
+# 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.
+#
+
+# Do not fix the patch level for golang:1.22 to automatically get security 
fixes.
+FROM golang:1.22-bookworm
+
+RUN echo "deb http://deb.debian.org/debian buster-backports main contrib 
non-free" \
+     >>/etc/apt/sources.list &&\
+    echo 'debconf debconf/frontend select Noninteractive' | 
debconf-set-selections &&\
+    apt-get update &&\
+    # Upgrade installed packages to get latest security fixes if the base 
image does not contain them already.
+    apt-get upgrade -y --no-install-recommends &&\
+    apt-get install -y apt-utils &&\
+    apt-get install -y \
+     curl \
+     jq \
+     git \
+     zip \
+     vim && \
+     apt-get -y install \
+     librdkafka1 \
+     librdkafka++1 &&\
+    apt-get -y install \
+     librdkafka-dev &&\
+    # Cleanup apt data, we do not need them later on.
+    apt-get clean && rm -rf /var/lib/apt/lists/* &&\
+    go install github.com/go-delve/delve/cmd/dlv@latest &&\
+    mkdir /action
+#make python 3 react as python
+RUN ln -s /usr/bin/python3 /usr/bin/python
+
+WORKDIR /action
+ADD proxy /bin/proxy
+ADD bin/compile /bin/compile
+ADD lib/launcher.go /lib/launcher.go
+ENV OW_COMPILER=/bin/compile
+ENV OW_LOG_INIT_ERROR=1
+ENV OW_WAIT_FOR_ACK=1
+ENV OW_EXECUTION_ENV=openwhisk/action-golang-v1.22
+ENTRYPOINT [ "/bin/proxy" ]
diff --git a/golang1.22/Makefile b/golang1.22/Makefile
new file mode 100644
index 0000000..7dfbeda
--- /dev/null
+++ b/golang1.22/Makefile
@@ -0,0 +1,44 @@
+#
+# 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.
+#
+IMG=action-golang-v1.22
+
+build:
+       ../gradlew distDocker
+
+localbuild:
+       GOOS=linux GOARCH=amd64 go build -o proxy -a  -ldflags '-extldflags 
"-static"' ../main/proxy.go
+       docker build -t $(IMG) .
+       docker tag $(IMG) whisk/$(IMG)
+
+push: build
+       docker tag $(IMG) actionloop/$(IMG)
+       docker push actionloop/$(IMG):nightly
+
+clean:
+       docker rmi -f whisk/$(IMG) actionloop/$(IMG)
+
+debug: build
+       docker run -p 8080:8080 \
+       --name go-action --rm -ti --entrypoint=/bin/bash \
+       -e OW_COMPILER=/mnt/bin/compile \
+       -v $(PWD):/mnt whisk/$(IMG)
+
+enter:
+       docker exec -ti go-action bash
+
+
+.PHONY: build push clean debug enter
diff --git a/golang1.22/bin/compile b/golang1.22/bin/compile
new file mode 100755
index 0000000..c3f7ebe
--- /dev/null
+++ b/golang1.22/bin/compile
@@ -0,0 +1,138 @@
+#!/usr/bin/python -u
+"""Golang 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, os.path, sys, re, shutil, subprocess, traceback, codecs
+from os.path import dirname, exists
+from time import sleep
+
+# write a file creating intermediate directories
+def write_file(file, body, executable=False):
+    try: os.makedirs(dirname(file), mode=0o755)
+    except: pass
+    with open(file, mode="wb") as f:
+        f.write(body)
+    if executable:
+        os.chmod(file, 0o755)
+
+# copy a file eventually replacing a substring
+def copy_replace(src, dst, match=None, replacement=""):
+    with open(src, 'rb') as s:
+        body = s.read()
+        if match:
+            body = body.replace(match, replacement)
+        write_file(dst, body)
+
+
+def sources(launcher, source_dir, main):
+    func = main.capitalize()
+    has_main = None
+
+    # copy the exec to exec.go
+    # also check if it has a main in it
+    src = "%s/exec" % source_dir
+    dst = "%s/exec__.go" % source_dir
+    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()
+                has_main = 
re.match(r".*package\s+main\W.*func\s+main\s*\(\s*\)", body, flags=re.DOTALL)
+                d.write(body)
+
+    # copy the launcher fixing the main
+    if not has_main:
+        dst = "%s/main__.go" % source_dir
+        if os.path.isdir("%s/main" % source_dir):
+            dst = "%s/main/main__.go" % source_dir
+        with codecs.open(dst, 'w', 'utf-8') as d:
+            with codecs.open(launcher, 'r', 'utf-8') as e:
+                code = e.read()
+                code = code.replace("Main", func)
+                d.write(code)
+
+def build(source_dir, target_dir):
+    # compile...
+    source_dir = os.path.abspath(source_dir)
+    parent = dirname(source_dir)
+    target = os.path.abspath("%s/exec" % target_dir)
+    if os.environ.get("__OW_EXECUTION_ENV"):
+      write_file("%s.env" % target, 
str.encode(os.environ["__OW_EXECUTION_ENV"]))
+
+    env = {
+      "GOROOT": "/usr/local/go",
+      "GOPATH": "/home/go",
+      "PATH": os.environ["PATH"],
+      "GOCACHE": "/tmp",
+      "GO111MODULE": "on"
+    }
+
+    gomod = "%s/go.mod" % source_dir
+    with open(os.devnull, "w") as dn:
+        if exists(gomod):
+            ret = subprocess.call(["go", "mod", "download"], cwd=source_dir, 
env=env, stderr=dn, stdout=dn)
+            if ret != 0:
+                print("cannot download modules")
+                return
+        else:
+            ret = subprocess.call(["go", "mod", "init", "exec"], 
cwd=source_dir, env=env, stdout=dn, stderr=dn)
+            if ret != 0:
+                print("cannot init modules")
+                return
+
+    ldflags = "-s -w"
+    gobuild = ["go", "build", "-o", target, "-ldflags", ldflags]
+    if os.environ.get("__OW_EXECUTION_ENV"):
+        ldflags += " -X main.OwExecutionEnv=%s" % 
os.environ["__OW_EXECUTION_ENV"]
+    ret = subprocess.call(gobuild, cwd=source_dir, env=env)
+    if ret != 0:
+        print("failed", " ".join(gobuild), "\nin", source_dir, "\nenv", env)
+
+def debug(source_dir, target_dir, port):
+    source_dir = os.path.abspath(source_dir)
+    target = os.path.abspath("%s/exec" % target_dir)
+    if os.environ.get("__OW_EXECUTION_ENV"):
+      write_file("%s/exec.env" % source_dir, os.environ["__OW_EXECUTION_ENV"])
+    shutil.rmtree(target_dir)
+    shutil.move(source_dir, target_dir)
+    write_file(target, """#!/bin/bash
+cd "$(dirname $0)"
+export GOCACHE=/tmp
+export PATH=%s
+exec script -q  -c '/go/bin/dlv debug --headless --listen=127.0.0.1:%s 
--continue --accept-multiclient --log-dest /tmp/delve.log'
+""" % (os.environ["PATH"], port) , True)   
+ 
+def main(argv):
+    if len(argv) < 4:
+        print("usage: <main-file> <source-dir> <target-dir>")
+        sys.exit(1)
+
+    main = argv[1]
+    source_dir = argv[2]
+    target_dir = argv[3]
+    launcher = dirname(dirname(argv[0]))+"/lib/launcher.go"
+    sources(launcher, source_dir, main)
+
+    # if the debug port is present and not empty build with debug
+    if os.environ.get("__OW_DEBUG_PORT"):
+        debug(source_dir, target_dir, os.environ["__OW_DEBUG_PORT"])
+    else:
+        build(source_dir, target_dir)
+
+if __name__ == '__main__':
+    main(sys.argv)
diff --git a/settings.gradle b/golang1.22/build.gradle
similarity index 58%
copy from settings.gradle
copy to golang1.22/build.gradle
index e08f904..40cda61 100644
--- a/settings.gradle
+++ b/golang1.22/build.gradle
@@ -15,29 +15,24 @@
  * limitations under the License.
  */
 
-include 'tests'
+ext.dockerImageName = 'action-golang-v1.22'
+apply from: '../gradle/docker.gradle'
 
-include 'actionloop'
-include 'golang1.19'
-include 'golang1.20'
-include 'golang1.21'
+distDocker.dependsOn 'staticBuildProxy'
+distDocker.finalizedBy('cleanup')
 
-rootProject.name = 'runtime-golang'
+task staticBuildProxy(type: Exec) {
+       environment CGO_ENABLED: "0"
+       environment GOOS: "linux"
+       environment GOARCH: "amd64"
+    environment GO111MODULE: "on"
 
-gradle.ext.openwhisk = [
-        version: '1.0.1-SNAPSHOT'
-]
+       commandLine 'go', 'build',
+               '-o',  'proxy', '-a',
+               '-ldflags', '-extldflags "-static"',
+               '../main/proxy.go'
+}
 
-gradle.ext.scala = [
-    version: '2.12.7',
-    depVersion  : '2.12',
-    compileFlags: ['-feature', '-unchecked', '-deprecation', 
'-Xfatal-warnings', '-Ywarn-unused-import']
-]
-
-gradle.ext.scalafmt = [
-    version: '1.5.0',
-    config: new File(rootProject.projectDir, '.scalafmt.conf')
-]
-
-gradle.ext.akka = [version : '2.6.12']
-gradle.ext.akka_http = [version : '10.2.4']
+task cleanup(type: Delete) {
+    delete 'proxy'
+}
diff --git a/golang1.22/lib/launcher.go b/golang1.22/lib/launcher.go
new file mode 100644
index 0000000..b432b88
--- /dev/null
+++ b/golang1.22/lib/launcher.go
@@ -0,0 +1,141 @@
+/*
+ * 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 main
+
+import (
+       "bufio"
+       "bytes"
+       "encoding/json"
+       "fmt"
+       "io"
+       "log"
+       "os"
+       "reflect"
+       "strings"
+)
+
+// OwExecutionEnv is the execution environment set at compile time
+var OwExecutionEnv = ""
+
+func main() {
+       // check if the execution environment is correct
+       if OwExecutionEnv != "" && OwExecutionEnv != 
os.Getenv("__OW_EXECUTION_ENV") {
+               fmt.Println("Execution Environment Mismatch")
+               fmt.Println("Expected: ", OwExecutionEnv)
+               fmt.Println("Actual: ", os.Getenv("__OW_EXECUTION_ENV"))
+               os.Exit(1)
+       }
+
+       // debugging
+       var debug = os.Getenv("OW_DEBUG") != ""
+       if debug {
+               f, err := os.OpenFile("/tmp/action.log", 
os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
+               if err == nil {
+                       log.SetOutput(f)
+               }
+               log.Printf("Environment: %v", os.Environ())
+       }
+
+       resultKind := reflect.TypeOf(Main).Out(0).Kind()
+       if resultKind != reflect.Map && resultKind != reflect.Slice && 
resultKind != reflect.Array {
+               fmt.Println("Support map and slice and array only")
+               os.Exit(1)
+       }
+
+       // input
+       out := os.NewFile(3, "pipe")
+       defer out.Close()
+       reader := bufio.NewReader(os.Stdin)
+
+       // acknowledgement of started action
+       fmt.Fprintf(out, `{ "ok": true}%s`, "\n")
+       if debug {
+               log.Println("action started")
+       }
+
+       // read-eval-print loop
+       for {
+               // read one line
+               inbuf, err := reader.ReadBytes('\n')
+               if err != nil {
+                       if err != io.EOF {
+                               log.Println(err)
+                       }
+                       break
+               }
+               if debug {
+                       log.Printf(">>>'%s'>>>", inbuf)
+               }
+               // parse one line
+               var input map[string]interface{}
+               err = json.Unmarshal(inbuf, &input)
+               if err != nil {
+                       log.Println(err.Error())
+                       fmt.Fprintf(out, "{ error: %q}\n", err.Error())
+                       continue
+               }
+               if debug {
+                       log.Printf("%v\n", input)
+               }
+               // set environment variables
+               for k, v := range input {
+                       if k == "value" {
+                               continue
+                       }
+                       if s, ok := v.(string); ok {
+                               os.Setenv("__OW_"+strings.ToUpper(k), s)
+                       }
+               }
+               // get payload if not empty
+               isJsonObjectParam := true
+               var payloadForJsonObject map[string]interface{}
+               var payloadForJsonArray []interface{}
+               if value, ok := input["value"].(map[string]interface{}); ok {
+                       payloadForJsonObject = value
+               } else {
+                       if value, ok := input["value"].([]interface{}); ok {
+                               payloadForJsonArray = value
+                               isJsonObjectParam = false
+                       }
+               }
+               // process the request
+               var result interface{}
+               funcMain := reflect.ValueOf(Main)
+               if isJsonObjectParam {
+                       param := 
[]reflect.Value{reflect.ValueOf(payloadForJsonObject)}
+                       reflectResult := funcMain.Call(param)
+                       result = reflectResult[0].Interface()
+               } else {
+                       param := 
[]reflect.Value{reflect.ValueOf(payloadForJsonArray)}
+                       reflectResult := funcMain.Call(param)
+                       result = reflectResult[0].Interface()
+               }
+               // encode the answer
+               output, err := json.Marshal(&result)
+               if err != nil {
+                       log.Println(err.Error())
+                       fmt.Fprintf(out, "{ error: %q}\n", err.Error())
+                       continue
+               }
+               output = bytes.Replace(output, []byte("\n"), []byte(""), -1)
+               if debug {
+                       log.Printf("<<<'%s'<<<", output)
+               }
+               fmt.Fprintf(out, "%s\n", output)
+       }
+}
diff --git a/settings.gradle b/settings.gradle
index e08f904..807b165 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -21,6 +21,7 @@ include 'actionloop'
 include 'golang1.19'
 include 'golang1.20'
 include 'golang1.21'
+include 'golang1.22'
 
 rootProject.name = 'runtime-golang'
 
diff --git a/settings.gradle 
b/tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGo22Tests.scala
similarity index 58%
copy from settings.gradle
copy to 
tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGo22Tests.scala
index e08f904..12fae84 100644
--- a/settings.gradle
+++ 
b/tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGo22Tests.scala
@@ -14,30 +14,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package runtime.actionContainers
 
-include 'tests'
+import common.WskActorSystem
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
 
-include 'actionloop'
-include 'golang1.19'
-include 'golang1.20'
-include 'golang1.21'
+@RunWith(classOf[JUnitRunner])
+class ActionLoopBasicGo22Tests
+    extends ActionLoopBasicGoTests
+    with WskActorSystem {
 
-rootProject.name = 'runtime-golang'
-
-gradle.ext.openwhisk = [
-        version: '1.0.1-SNAPSHOT'
-]
-
-gradle.ext.scala = [
-    version: '2.12.7',
-    depVersion  : '2.12',
-    compileFlags: ['-feature', '-unchecked', '-deprecation', 
'-Xfatal-warnings', '-Ywarn-unused-import']
-]
-
-gradle.ext.scalafmt = [
-    version: '1.5.0',
-    config: new File(rootProject.projectDir, '.scalafmt.conf')
-]
-
-gradle.ext.akka = [version : '2.6.12']
-gradle.ext.akka_http = [version : '10.2.4']
+  override lazy val goCompiler = "action-golang-v1.22"
+  override lazy val image = goCompiler
+  override lazy val requireAck = true
+}
diff --git a/settings.gradle 
b/tests/src/test/scala/runtime/actionContainers/ActionLoopGo22ContainerTests.scala
similarity index 58%
copy from settings.gradle
copy to 
tests/src/test/scala/runtime/actionContainers/ActionLoopGo22ContainerTests.scala
index e08f904..1c3e2b9 100644
--- a/settings.gradle
+++ 
b/tests/src/test/scala/runtime/actionContainers/ActionLoopGo22ContainerTests.scala
@@ -15,29 +15,17 @@
  * limitations under the License.
  */
 
-include 'tests'
+package runtime.actionContainers
 
-include 'actionloop'
-include 'golang1.19'
-include 'golang1.20'
-include 'golang1.21'
+import common.WskActorSystem
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
+@RunWith(classOf[JUnitRunner])
+class ActionLoopGo22ContainerTests
+    extends ActionLoopGoContainerTests
+    with WskActorSystem {
 
-rootProject.name = 'runtime-golang'
+  override lazy val goCompiler = "action-golang-v1.22"
+  override lazy val image = goCompiler
 
-gradle.ext.openwhisk = [
-        version: '1.0.1-SNAPSHOT'
-]
-
-gradle.ext.scala = [
-    version: '2.12.7',
-    depVersion  : '2.12',
-    compileFlags: ['-feature', '-unchecked', '-deprecation', 
'-Xfatal-warnings', '-Ywarn-unused-import']
-]
-
-gradle.ext.scalafmt = [
-    version: '1.5.0',
-    config: new File(rootProject.projectDir, '.scalafmt.conf')
-]
-
-gradle.ext.akka = [version : '2.6.12']
-gradle.ext.akka_http = [version : '10.2.4']
+}

Reply via email to