Skip to content

Commit 274e2f0

Browse files
combine tools into single binary
0 parents  commit 274e2f0

File tree

9 files changed

+1283
-0
lines changed

9 files changed

+1283
-0
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: Publish version
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
jobs:
9+
create_tag:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
# Step 1: Checkout the repository
14+
- name: Checkout repository
15+
uses: actions/checkout@v3
16+
with:
17+
fetch-depth: 0
18+
19+
# Step 2: Set up Git for tagging
20+
- name: Set up Git for tagging
21+
run: |
22+
git config user.name "${{ github.actor }}"
23+
git config user.email "${{ github.actor }}@users.noreply.github.com"
24+
25+
# Step 3: Get the latest tag and increment the minor version
26+
- name: Get latest tag and increment
27+
id: get_tag
28+
run: |
29+
# Fetch all tags
30+
git fetch --tags
31+
32+
# Get the latest tag version
33+
latest_tag=$(git describe --tags --abbrev=0 || echo "v0.0.0")
34+
echo "Latest tag: $latest_tag"
35+
36+
# Extract the version numbers (major, minor, patch)
37+
major=$(echo $latest_tag | cut -d. -f1 | cut -dv -f2)
38+
minor=$(echo $latest_tag | cut -d. -f2)
39+
patch=$(echo $latest_tag | cut -d. -f3)
40+
41+
# Increment the minor version and reset patch to 0
42+
new_minor=$((minor + 1))
43+
new_version="v${major}.${new_minor}.0"
44+
45+
# Write the new version to the GITHUB_OUTPUT file for later use
46+
echo "tag=$new_version" >> $GITHUB_OUTPUT
47+
48+
# Step 4: Create and push the new tag
49+
- name: Create new tag
50+
run: |
51+
new_tag="${{ steps.get_tag.outputs.tag }}"
52+
git tag $new_tag
53+
git push origin $new_tag

.gitignore

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# If you prefer the allow list template instead of the deny list, see community template:
2+
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
3+
#
4+
# Binaries for programs and plugins
5+
*.exe
6+
*.exe~
7+
*.dll
8+
*.so
9+
*.dylib
10+
11+
# Test binary, built with `go test -c`
12+
*.test
13+
14+
# Output of the go coverage tool, specifically when used with LiteIDE
15+
*.out
16+
17+
# Dependency directories (remove the comment below to include it)
18+
# vendor/
19+
20+
# Go workspace file
21+
go.work
22+
23+
.idea
24+
*.iml
25+
**/.DS_Store

core/generator.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package core
2+
3+
import "github.com/fsnotify/fsnotify"
4+
5+
type Generator interface {
6+
Init() error
7+
OnChange(appPath string, outputPath string, event fsnotify.Event) error
8+
Generate(appPath string, outputPath string) error
9+
}

go.mod

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module github.com/cloudimpl/polycode
2+
3+
go 1.24.5
4+
5+
require github.com/fsnotify/fsnotify v1.7.0
6+
7+
require golang.org/x/sys v0.20.0 // indirect

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
2+
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
3+
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
4+
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

go/generate.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package _go
2+
3+
import (
4+
"fmt"
5+
"github.com/fsnotify/fsnotify"
6+
"log"
7+
"os"
8+
"os/exec"
9+
"path/filepath"
10+
)
11+
12+
// isGoImportsAvailable checks if the `goimports` command is available
13+
func isGoImportsAvailable() bool {
14+
_, err := exec.LookPath("goimports")
15+
return err == nil
16+
}
17+
18+
// installGoImports installs the `goimports` tool using `go install`
19+
func installGoImports() error {
20+
cmd := exec.Command("go", "install", "golang.org/x/tools/cmd/goimports@latest")
21+
cmd.Stdout = os.Stdout
22+
cmd.Stderr = os.Stderr
23+
return cmd.Run()
24+
}
25+
26+
func buildProject(appPath, outPath string) error {
27+
absAppPath, err := filepath.Abs(appPath)
28+
if err != nil {
29+
fmt.Println("failed to resolve absolute app path:", err)
30+
return err
31+
}
32+
33+
// Step 1: go mod download
34+
cmdDownload := exec.Command("go", "mod", "download")
35+
cmdDownload.Dir = absAppPath
36+
cmdDownload.Stdout = os.Stdout
37+
cmdDownload.Stderr = os.Stderr
38+
if err := cmdDownload.Run(); err != nil {
39+
fmt.Println("failed to download modules:", err)
40+
return err
41+
}
42+
43+
// Step 2: GOOS=linux GOARCH=amd64 go build -o "$OUT_PATH" .
44+
cmdBuild := exec.Command("go", "build", "-o", outPath, ".")
45+
cmdBuild.Dir = absAppPath
46+
cmdBuild.Env = append(os.Environ(),
47+
"GOOS=linux",
48+
"GOARCH=amd64",
49+
)
50+
cmdBuild.Stdout = os.Stdout
51+
cmdBuild.Stderr = os.Stderr
52+
if err := cmdBuild.Run(); err != nil {
53+
fmt.Println("failed to build binary:", err)
54+
return err
55+
}
56+
57+
fmt.Println("build completed successfully:", outPath)
58+
return nil
59+
}
60+
61+
type Generator struct {
62+
}
63+
64+
func (g *Generator) Init() error {
65+
// Check if `goimports` is installed
66+
if !isGoImportsAvailable() {
67+
log.Println("goimports is not installed. Installing now...")
68+
69+
err := installGoImports()
70+
if err != nil {
71+
log.Printf("failed to install goimports: %s\nplease install it manually by running:\n\tgo install golang.org/x/tools/cmd/goimports@latest\n", err.Error())
72+
return err
73+
}
74+
75+
log.Println("goimports successfully installed.")
76+
}
77+
78+
return nil
79+
}
80+
81+
func (g *Generator) OnChange(appPath string, outputPath string, event fsnotify.Event) error {
82+
if IsGoFile(event.Name) {
83+
if err := CheckFileCompilable(event.Name); err == nil {
84+
log.Printf("change detected in: %s, triggering generate\n", event.Name)
85+
return g.Generate(appPath, outputPath)
86+
} else {
87+
log.Printf("file not compilable: %s, error: %s\n", event.Name, err.Error())
88+
return err
89+
}
90+
}
91+
92+
return nil
93+
}
94+
95+
func (g *Generator) Generate(appPath string, outputPath string) error {
96+
err := generateServices(appPath, true)
97+
if err != nil {
98+
fmt.Printf("error generating services, error: %s\n", err.Error())
99+
return err
100+
}
101+
102+
err = generateRuntime(appPath)
103+
if err != nil {
104+
fmt.Printf("error generating runtime, error: %s\n", err.Error())
105+
return err
106+
}
107+
108+
err = buildProject(appPath, outputPath)
109+
if err != nil {
110+
fmt.Printf("error building project, error: %s\n", err.Error())
111+
return err
112+
}
113+
114+
return nil
115+
}

go/runtime-gen.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package _go
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"os"
7+
"path/filepath"
8+
"text/template"
9+
)
10+
11+
type RuntimeServiceInfo struct {
12+
ServiceStructName string
13+
}
14+
15+
type RuntimeInfo struct {
16+
Services []RuntimeServiceInfo
17+
}
18+
19+
const runtimeFileTemplate = `package _polycode
20+
21+
import (
22+
runtime "github.com/cloudimpl/polycode-runtime-go"
23+
)
24+
25+
func init() {
26+
var err error
27+
{{range .Services}}err = runtime.RegisterService(&{{.ServiceStructName}}{})
28+
if err != nil {
29+
panic(err)
30+
}
31+
{{end}}
32+
}
33+
`
34+
35+
func generateRuntime(appPath string) error {
36+
servicesFolder := filepath.Join(appPath, "services")
37+
38+
if _, err := os.Stat(servicesFolder); os.IsNotExist(err) {
39+
println("No services folder found")
40+
} else {
41+
entries, err := os.ReadDir(servicesFolder)
42+
if err != nil {
43+
fmt.Printf("Error reading directory: %v\n", err)
44+
return err
45+
}
46+
47+
var services []RuntimeServiceInfo
48+
for i, entry := range entries {
49+
fmt.Printf("Processing entry [%d/%d]\n", i+1, len(entries))
50+
if entry.IsDir() {
51+
serviceName := entry.Name()
52+
serviceStructName := toPascalCase(serviceName)
53+
services = append(services, RuntimeServiceInfo{
54+
ServiceStructName: serviceStructName,
55+
})
56+
}
57+
}
58+
59+
// Use template to generate the code
60+
var buf bytes.Buffer
61+
tmpl, err := template.New("runtime-file-template").Parse(runtimeFileTemplate)
62+
if err != nil {
63+
return err
64+
}
65+
66+
runtimeInfo := RuntimeInfo{
67+
Services: services,
68+
}
69+
70+
err = tmpl.Execute(&buf, runtimeInfo)
71+
if err != nil {
72+
return err
73+
}
74+
75+
err = os.WriteFile(appPath+"/.polycode/runtime.go", []byte(buf.String()), 0644)
76+
if err != nil {
77+
fmt.Printf("Error writing file: %v\n", err)
78+
return err
79+
}
80+
}
81+
82+
return nil
83+
}

0 commit comments

Comments
 (0)