-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: add go bindings package * fix readme * fix readme * fix: naming. remove executable. add vendor --------- Co-authored-by: puria <[email protected]>
- Loading branch information
1 parent
004ebda
commit e9ca9a1
Showing
342 changed files
with
181,347 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Top-most EditorConfig file | ||
root = true | ||
|
||
# Every file should according to these default configurations if not specified | ||
[*] | ||
# Use UNIX-style line endings | ||
end_of_line = LF | ||
# Use utf-8 file encoding | ||
charset = utf-8 | ||
# 4 space indent | ||
indent_style = space | ||
indent_size = 4 | ||
# Ensure file ends with a newline when saving(prevent `no newline at EOF`) | ||
insert_final_newline = true | ||
# Remove any whitespace characters preceding newline characters | ||
trim_trailing_whitespace = true | ||
|
||
# For YAML | ||
[*.{yml,yaml}] | ||
indent_size = 2 | ||
|
||
# For Go files | ||
[*.go] | ||
# `gofmt` uses tabs for indentation | ||
indent_style = tab |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
# Based on a true story on: | ||
# https://gist.github.com/thomaspoignant/5b72d579bd5f311904d973652180c705 | ||
|
||
GOCMD=go | ||
GOTEST=$(GOCMD) test | ||
GOVET=$(GOCMD) vet | ||
BINARY_NAME=slangroom_go | ||
VERSION?=0.0.0 | ||
SERVICE_PORT?=3000 | ||
DOCKER_REGISTRY?= #if set it should finished by / | ||
EXPORT_RESULT?=false # for CI please set EXPORT_RESULT to true | ||
|
||
GREEN := $(shell tput -Txterm setaf 2) | ||
YELLOW := $(shell tput -Txterm setaf 3) | ||
WHITE := $(shell tput -Txterm setaf 7) | ||
CYAN := $(shell tput -Txterm setaf 6) | ||
RESET := $(shell tput -Txterm sgr0) | ||
|
||
.PHONY: all test build vendor | ||
|
||
all: help | ||
|
||
slangroom-exec: | ||
cd ../.. && make slangroom-exec && cp slangroom-exec bindings/go | ||
|
||
## Build: | ||
build: vendor slangroom-exec ## Build your project and put the output binary in out/bin/ | ||
mkdir -p out/bin | ||
GO111MODULE=on $(GOCMD) build -mod vendor -o out/bin/$(BINARY_NAME) . | ||
|
||
clean: ## Remove build related file | ||
rm -fr ./bin | ||
rm -fr ./out | ||
rm -f ./junit-report.xml checkstyle-report.xml ./coverage.xml ./profile.cov yamllint-checkstyle.xml | ||
|
||
vendor: ## Copy of all packages needed to support builds and tests in the vendor directory | ||
$(GOCMD) mod vendor | ||
|
||
watch: ## Run the code with cosmtrek/air to have automatic reload on changes | ||
$(eval PACKAGE_NAME=$(shell head -n 1 go.mod | cut -d ' ' -f2)) | ||
docker run -it --rm -w /go/src/$(PACKAGE_NAME) -v $(shell pwd):/go/src/$(PACKAGE_NAME) -p $(SERVICE_PORT):$(SERVICE_PORT) cosmtrek/air | ||
|
||
## Test: | ||
test: ## Run the tests of the project | ||
ifeq ($(EXPORT_RESULT), true) | ||
GO111MODULE=off go get -u github.com/jstemmer/go-junit-report | ||
$(eval OUTPUT_OPTIONS = | tee /dev/tty | go-junit-report -set-exit-code > junit-report.xml) | ||
endif | ||
$(GOTEST) -v -race ./... $(OUTPUT_OPTIONS) | ||
|
||
coverage: ## Run the tests of the project and export the coverage | ||
$(GOTEST) -cover -covermode=count -coverprofile=profile.cov ./... | ||
$(GOCMD) tool cover -func profile.cov | ||
ifeq ($(EXPORT_RESULT), true) | ||
GO111MODULE=off go get -u github.com/AlekSi/gocov-xml | ||
GO111MODULE=off go get -u github.com/axw/gocov/gocov | ||
gocov convert profile.cov | gocov-xml > coverage.xml | ||
endif | ||
|
||
## Lint: | ||
lint: lint-go lint-dockerfile lint-yaml ## Run all available linters | ||
|
||
lint-dockerfile: ## Lint your Dockerfile | ||
# If dockerfile is present we lint it. | ||
ifeq ($(shell test -e ./Dockerfile && echo -n yes),yes) | ||
$(eval CONFIG_OPTION = $(shell [ -e $(shell pwd)/.hadolint.yaml ] && echo "-v $(shell pwd)/.hadolint.yaml:/root/.config/hadolint.yaml" || echo "" )) | ||
$(eval OUTPUT_OPTIONS = $(shell [ "${EXPORT_RESULT}" == "true" ] && echo "--format checkstyle" || echo "" )) | ||
$(eval OUTPUT_FILE = $(shell [ "${EXPORT_RESULT}" == "true" ] && echo "| tee /dev/tty > checkstyle-report.xml" || echo "" )) | ||
docker run --rm -i $(CONFIG_OPTION) hadolint/hadolint hadolint $(OUTPUT_OPTIONS) - < ./Dockerfile $(OUTPUT_FILE) | ||
endif | ||
|
||
lint-go: ## Use golintci-lint on your project | ||
$(eval OUTPUT_OPTIONS = $(shell [ "${EXPORT_RESULT}" == "true" ] && echo "--out-format checkstyle ./... | tee /dev/tty > checkstyle-report.xml" || echo "" )) | ||
docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:latest-alpine golangci-lint run --deadline=65s $(OUTPUT_OPTIONS) | ||
|
||
lint-yaml: ## Use yamllint on the yaml file of your projects | ||
ifeq ($(EXPORT_RESULT), true) | ||
GO111MODULE=off go get -u github.com/thomaspoignant/yamllint-checkstyle | ||
$(eval OUTPUT_OPTIONS = | tee /dev/tty | yamllint-checkstyle > yamllint-checkstyle.xml) | ||
endif | ||
docker run --rm -it -v $(shell pwd):/data cytopia/yamllint -f parsable $(shell git ls-files '*.yml' '*.yaml') $(OUTPUT_OPTIONS) | ||
|
||
## Docker: | ||
docker-build: ## Use the dockerfile to build the container | ||
docker build --rm --tag $(BINARY_NAME) . | ||
|
||
docker-release: ## Release the container with tag latest and version | ||
docker tag $(BINARY_NAME) $(DOCKER_REGISTRY)$(BINARY_NAME):latest | ||
docker tag $(BINARY_NAME) $(DOCKER_REGISTRY)$(BINARY_NAME):$(VERSION) | ||
# Push the docker images | ||
docker push $(DOCKER_REGISTRY)$(BINARY_NAME):latest | ||
docker push $(DOCKER_REGISTRY)$(BINARY_NAME):$(VERSION) | ||
|
||
## Help: | ||
help: ## Show this help. | ||
@echo '' | ||
@echo 'Usage:' | ||
@echo ' ${YELLOW}make${RESET} ${GREEN}<target>${RESET}' | ||
@echo '' | ||
@echo 'Targets:' | ||
@awk 'BEGIN {FS = ":.*?## "} { \ | ||
if (/^[a-zA-Z_-]+:.*?##.*$$/) {printf " ${YELLOW}%-20s${GREEN}%s${RESET}\n", $$1, $$2} \ | ||
else if (/^## .*$$/) {printf " ${CYAN}%s${RESET}\n", substr($$1,4)} \ | ||
}' $(MAKEFILE_LIST) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
|
||
|
||
### Usage | ||
This Go package provides an interface to execute Slangroom using an embedded binary. To use this package, include it in your Go project by importing it: | ||
|
||
```go | ||
import "github.com/dyne/slangroom-exec/bindings/go" | ||
``` | ||
|
||
### Example | ||
|
||
```go | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"github.com/dyne/slangroom-exec/bindings/go" | ||
) | ||
|
||
func main() { | ||
// Define your contract and inputs | ||
contract := `Rule unknown ignore | ||
Given I fetch the local timestamp in seconds and output into 'timestamp' | ||
Given I have a 'time' named 'timestamp' | ||
Then print the string '😘 Welcome to the Slangroom World 🌈' | ||
Then print the 'timestamp'` | ||
|
||
// Execute Slangroom | ||
result, err := slangroom.SlangroomExec("", contract, "", "", "", "") | ||
if err != nil { | ||
log.Fatalf("Execution Failed: %v", err) | ||
} | ||
|
||
// Print the execution output | ||
fmt.Println("Execution Output:", result.Output) | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
module github.com/dyne/slangroom-exec/bindings/go | ||
|
||
go 1.22 | ||
|
||
require ( | ||
github.com/amenzhinsky/go-memexec v0.7.1 | ||
github.com/stretchr/testify v1.9.0 | ||
) | ||
|
||
require ( | ||
github.com/davecgh/go-spew v1.1.1 // indirect | ||
github.com/pmezard/go-difflib v1.0.0 // indirect | ||
golang.org/x/sys v0.0.0-20210903071746-97244b99971b // indirect | ||
gopkg.in/yaml.v3 v3.0.1 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
github.com/amenzhinsky/go-memexec v0.7.1 h1:DVm4cXzklaNWZoTJgZUi/dlXtelhC7QBtX4luKjl1qk= | ||
github.com/amenzhinsky/go-memexec v0.7.1/go.mod h1:ApTO9/i2bcii7kvIXi74gum+/zYDzkiOXtuBZoYOKVE= | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= | ||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= | ||
golang.org/x/sys v0.0.0-20210903071746-97244b99971b h1:3Dq0eVHn0uaQJmPO+/aYPI/fRMqdrVDbu7MQcku54gg= | ||
golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package slangroom | ||
|
||
import ( | ||
_ "embed" | ||
"fmt" | ||
"io" | ||
"log" | ||
"strings" | ||
|
||
b64 "encoding/base64" | ||
|
||
"github.com/amenzhinsky/go-memexec" | ||
) | ||
|
||
// Embedding Zenroom binary using go:embed | ||
// | ||
//go:embed slangroom-exec | ||
var slangroomBinary []byte | ||
|
||
type SlangResult struct { | ||
Output string | ||
Logs string | ||
} | ||
|
||
func SlangroomExec(conf string, contract string, data string, keys string, extra string, context string) (SlangResult, bool) { | ||
exec, err := memexec.New(slangroomBinary) | ||
if err != nil { | ||
log.Fatalf("Failed to load Slangroom executable from memory: %v", err) | ||
} | ||
defer exec.Close() | ||
|
||
execCmd := exec.Command("slangroom-exec") | ||
|
||
stdout, err := execCmd.StdoutPipe() | ||
if err != nil { | ||
log.Fatalf("Failed to create stdout pipe: %v", err) | ||
} | ||
|
||
stderr, err := execCmd.StderrPipe() | ||
if err != nil { | ||
log.Fatalf("Failed to create stderr pipe: %v", err) | ||
} | ||
|
||
stdin, err := execCmd.StdinPipe() | ||
if err != nil { | ||
log.Fatalf("Failed to create stdin pipe: %v", err) | ||
} | ||
|
||
b64conf := b64.StdEncoding.EncodeToString([]byte(conf)) | ||
fmt.Fprintln(stdin, b64conf) | ||
|
||
b64contract := b64.StdEncoding.EncodeToString([]byte(contract)) | ||
fmt.Fprintln(stdin, b64contract) | ||
|
||
b64keys := b64.StdEncoding.EncodeToString([]byte(keys)) | ||
fmt.Fprintln(stdin, b64keys) | ||
|
||
b64data := b64.StdEncoding.EncodeToString([]byte(data)) | ||
fmt.Fprintln(stdin, b64data) | ||
|
||
b64extra := b64.StdEncoding.EncodeToString([]byte(extra)) | ||
fmt.Fprintln(stdin, b64extra) | ||
|
||
b64context := b64.StdEncoding.EncodeToString([]byte(context)) | ||
fmt.Fprintln(stdin, b64context) | ||
|
||
stdin.Close() | ||
|
||
err = execCmd.Start() | ||
if err != nil { | ||
log.Fatalf("Failed to start command: %v", err) | ||
} | ||
|
||
stdoutOutput := make(chan string) | ||
stderrOutput := make(chan string) | ||
go captureOutput(stdout, stdoutOutput) | ||
go captureOutput(stderr, stderrOutput) | ||
|
||
err = execCmd.Wait() | ||
|
||
stdoutStr := <-stdoutOutput | ||
stderrStr := <-stderrOutput | ||
|
||
return SlangResult{Output: stdoutStr, Logs: stderrStr}, err == nil | ||
} | ||
|
||
func captureOutput(pipe io.ReadCloser, output chan<- string) { | ||
defer close(output) | ||
|
||
buf := new(strings.Builder) | ||
_, err := io.Copy(buf, pipe) | ||
if err != nil { | ||
log.Printf("Failed to capture output: %v", err) | ||
return | ||
} | ||
output <- buf.String() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package slangroom | ||
|
||
import ( | ||
"encoding/json" | ||
"os" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestExecuteSimpleZencode(t *testing.T) { | ||
contract := `Given nothing | ||
Then print the string 'Welcome to slangroom-exec 🥳'` | ||
res, success := SlangroomExec("", contract, "", "", "", "") | ||
assert.JSONEq(t, `{"output":["Welcome_to_slangroom-exec_🥳"]}`, res.Output) | ||
assert.True(t, success, "Expected success but got failure") | ||
} | ||
|
||
func TestExecuteSimpleSlangroom(t *testing.T) { | ||
contract := `Rule unknown ignore | ||
Given I fetch the local timestamp in seconds and output into 'timestamp' | ||
Given I have a 'number' named 'timestamp' | ||
Then print the 'timestamp'` | ||
res, success := SlangroomExec("", contract, "", "", "", "") | ||
assert.Contains(t, res.Output, "timestamp") | ||
var result map[string]interface{} | ||
if err := json.Unmarshal([]byte(res.Output), &result); err == nil { | ||
ts, ok := result["timestamp"].(float64) | ||
assert.True(t, ok, "Expected timestamp to be present") | ||
assert.True(t, ts == float64(int(ts)), "Expected timestamp to be a number") | ||
} else { | ||
t.Errorf("Failed to unmarshal output: %v", err) | ||
} | ||
assert.True(t, success, "Expected success but got failure") | ||
} | ||
|
||
func TestFailOnBrokenSlangroom(t *testing.T) { | ||
contract := `Gibberish` | ||
res, success := SlangroomExec("", contract, "", "", "", "") | ||
assert.Contains(t, res.Logs, "Invalid Zencode prefix 1: 'Gibberish'") | ||
assert.False(t, success, "Expected failure but got success") | ||
} | ||
|
||
func TestFailOnEmptyContract(t *testing.T) { | ||
contract := `` | ||
res, success := SlangroomExec("", contract, "", "", "", "") | ||
assert.Equal(t, "Malformed input: Slangroom contract is empty\n", res.Logs) | ||
assert.False(t, success, "Expected failure but got success") | ||
} | ||
|
||
func TestReadDataCorrectly(t *testing.T) { | ||
os.Setenv("FILES_DIR", ".") | ||
filePath := "test/test.txt" | ||
if _, err := os.Stat(filePath); os.IsNotExist(err) { | ||
t.Fatalf("Test file does not exist: %v", err) | ||
} | ||
contract := `Rule unknown ignore | ||
Given I send path 'filename' and read verbatim file content and output into 'content' | ||
Given I have a 'string' named 'filename' | ||
Given I have a 'string' named 'content' | ||
Then print data` | ||
data := `{ | ||
"filename": "` + filePath + `" | ||
}` | ||
res, success := SlangroomExec("", contract, data, "", "", "") | ||
assert.Contains(t, res.Output, "Do you know who greets you? 🥒") | ||
assert.True(t, success, "Expected success but got failure") | ||
} | ||
|
||
func TestFailOnEmptyOrBrokenContract(t *testing.T) { | ||
contract := `` | ||
conf := `error` | ||
res, success := SlangroomExec(conf, contract, "", "", "", "") | ||
assert.Equal(t, "Malformed input: Slangroom contract is empty\n", res.Logs) | ||
assert.False(t, success, "Expected failure but got success") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Do you know who greets you? 🥒 |
Oops, something went wrong.