mirror of
https://github.com/foomo/gograpple.git
synced 2025-10-16 12:35:37 +00:00
chore: reorganize, fix goreleaser and update readme
This commit is contained in:
parent
e4b0f420fd
commit
a3d29b4915
@ -2,11 +2,11 @@
|
||||
# Build customization
|
||||
builds:
|
||||
- binary: gograpple
|
||||
main: ./cmd/main.go
|
||||
main: ./main.go
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
ldflags:
|
||||
- -s -w -X github.com/foomo/gograpple/cmd/actions.version={{.Version}}
|
||||
- -s -w -X github.com/foomo/gograpple/cmd.version={{.Version}}
|
||||
goos:
|
||||
- darwin
|
||||
- linux
|
||||
|
||||
4
Makefile
4
Makefile
@ -1,8 +1,8 @@
|
||||
build:
|
||||
go build -o bin/gograpple cmd/gograpple/main.go
|
||||
go build -o bin/gograpple main.go
|
||||
|
||||
install:
|
||||
go build -o /usr/local/bin/gograpple cmd/gograpple/main.go
|
||||
go build -o /usr/local/bin/gograpple main.go
|
||||
|
||||
test:
|
||||
go test ./...
|
||||
15
README.md
15
README.md
@ -3,9 +3,16 @@
|
||||
gograpple that go program and delve into the high seas ...
|
||||
or in other words: delve debugger injection for your golang code running in k8 pods
|
||||
|
||||
## requirements
|
||||
- helm
|
||||
- kubectl
|
||||
- docker
|
||||
|
||||
## quick start
|
||||
```
|
||||
go install github.com/foomo/gograpple/cmd/gograpple@latest
|
||||
brew install foomo/gograpple/gograpple
|
||||
OR
|
||||
go install github.com/foomo/gograpple@latest
|
||||
```
|
||||
start patch debugging in interactive mode
|
||||
```
|
||||
@ -15,6 +22,12 @@ when you configure your patch correctly a file will be saved in your cwd and the
|
||||
|
||||
## common issues
|
||||
|
||||
### stuck with patched deployment
|
||||
in case your deployment is styck in patched state, use
|
||||
```
|
||||
gograpple rollback [namespace] [deployment]
|
||||
```
|
||||
|
||||
### vscode
|
||||
> The debug session doesnt start until the entrypoint is triggered more than once.
|
||||
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
package actions
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/foomo/gograpple"
|
||||
"github.com/foomo/gograpple/internal/grapple"
|
||||
)
|
||||
|
||||
type HostPort struct {
|
||||
@ -14,7 +14,7 @@ type HostPort struct {
|
||||
}
|
||||
|
||||
func NewHostPort(host string, port int) *HostPort {
|
||||
addr, err := gograpple.CheckTCPConnection(host, port)
|
||||
addr, err := grapple.CheckTCPConnection(host, port)
|
||||
if err == nil {
|
||||
host = addr.IP.String()
|
||||
port = addr.Port
|
||||
@ -45,7 +45,7 @@ func (lf *HostPort) Set(value string) error {
|
||||
default:
|
||||
return fmt.Errorf("invalid address %q provided", value)
|
||||
}
|
||||
addr, err := gograpple.CheckTCPConnection(lf.Host, lf.Port)
|
||||
addr, err := grapple.CheckTCPConnection(lf.Host, lf.Port)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1,124 +0,0 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"github.com/foomo/gograpple"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
rootCmd.PersistentFlags().StringVarP(&flagDir, "dir", "d", ".", "Specifies working directory")
|
||||
rootCmd.PersistentFlags().StringVarP(&flagNamespace, "namespace", "n", "default", "namespace name")
|
||||
rootCmd.PersistentFlags().BoolVarP(&flagVerbose, "verbose", "v", false, "Specifies should command output be displayed")
|
||||
rootCmd.PersistentFlags().StringVarP(&flagPod, "pod", "p", "", "pod name (default most recent one)")
|
||||
rootCmd.PersistentFlags().StringVarP(&flagContainer, "container", "c", "", "container name (default deployment name)")
|
||||
rootCmd.PersistentFlags().BoolVarP(&flagDebug, "debug", "", false, "debug mode")
|
||||
patchCmd.Flags().StringVar(&flagImage, "image", "alpine:latest", "image to be used for patching (default alpine:latest)")
|
||||
patchCmd.Flags().StringArrayVarP(&flagMounts, "mount", "m", []string{}, "host path to be mounted (default none)")
|
||||
patchCmd.Flags().BoolVar(&flagRollback, "rollback", false, "rollback deployment to a previous state")
|
||||
delveCmd.Flags().StringVar(&flagSourcePath, "source", "", ".go file source path (default cwd)")
|
||||
delveCmd.Flags().Var(flagArgs, "args", "go file args")
|
||||
delveCmd.Flags().Var(flagListen, "listen", "delve host:port to listen on")
|
||||
delveCmd.Flags().BoolVar(&flagVscode, "vscode", false, "launch a debug configuration in vscode")
|
||||
delveCmd.Flags().BoolVar(&flagContinue, "continue", false, "start delve server execution without waiting for client connection")
|
||||
delveCmd.Flags().BoolVar(&flagJSONLog, "json-log", false, "log as json")
|
||||
interactiveCmd.Flags().BoolVar(&flagAttach, "attach", false, "debug with attach (default will patch)")
|
||||
interactiveCmd.Flags().StringVar(&flagSaveDir, "save", ".", "directory to save interactive configuration")
|
||||
rootCmd.AddCommand(versionCmd, patchCmd, shellCmd, delveCmd, interactiveCmd)
|
||||
}
|
||||
|
||||
var (
|
||||
flagImage string
|
||||
flagDir string
|
||||
flagVerbose bool
|
||||
flagNamespace string
|
||||
flagPod string
|
||||
flagContainer string
|
||||
flagRepo string
|
||||
flagMounts []string
|
||||
flagSourcePath string
|
||||
flagArgs = NewStringList(" ")
|
||||
flagRollback bool
|
||||
flagListen = NewHostPort("127.0.0.1", 0)
|
||||
flagVscode bool
|
||||
flagContinue bool
|
||||
flagJSONLog bool
|
||||
flagDebug bool
|
||||
)
|
||||
|
||||
var (
|
||||
l *logrus.Entry
|
||||
grapple *gograpple.Grapple
|
||||
|
||||
rootCmd = &cobra.Command{
|
||||
Use: "gograpple",
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
if cmd.Name() == commandNameVersion || cmd.Name() == commandNameInteractive {
|
||||
return nil
|
||||
}
|
||||
l = newLogger(flagVerbose, flagJSONLog)
|
||||
var err error
|
||||
err = gograpple.ValidatePath(".", &flagDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
grapple, err = gograpple.NewGrapple(l, flagNamespace, args[0], flagDebug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return gograpple.ValidatePath(flagDir, &flagSourcePath)
|
||||
},
|
||||
}
|
||||
patchCmd = &cobra.Command{
|
||||
Use: "patch [DEPLOYMENT] -c {CONTAINER} -n {NAMESPACE} -i {IMAGE} -t {TAG} -m {MOUNT}",
|
||||
Short: "applies a development patch for a deployment",
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if flagRollback {
|
||||
return grapple.Rollback()
|
||||
}
|
||||
mounts, err := gograpple.ValidateMounts(flagDir, flagMounts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return grapple.Patch(flagImage, flagContainer, mounts)
|
||||
},
|
||||
}
|
||||
shellCmd = &cobra.Command{
|
||||
Use: "shell [DEPLOYMENT] -n {NAMESPACE} -c {CONTAINER}",
|
||||
Short: "shell into the dev patched deployment",
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return grapple.Shell(flagPod)
|
||||
},
|
||||
}
|
||||
delveCmd = &cobra.Command{
|
||||
Use: "delve [DEPLOYMENT] --source {SRC} -n {NAMESPACE} -c {CONTAINER}",
|
||||
Short: "start a headless delve debug server for .go input on a patched deployment",
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return grapple.Delve(flagPod, flagContainer, flagSourcePath, flagArgs.items, flagListen.Host, flagListen.Port, flagVscode, flagContinue)
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func Execute() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
l = logrus.NewEntry(logrus.New())
|
||||
l.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func newLogger(verbose, jsonLog bool) *logrus.Entry {
|
||||
logger := logrus.New()
|
||||
if jsonLog {
|
||||
logger.SetFormatter(&logrus.JSONFormatter{
|
||||
DisableTimestamp: true,
|
||||
})
|
||||
}
|
||||
if verbose {
|
||||
logger.SetLevel(logrus.TraceLevel)
|
||||
}
|
||||
return logrus.NewEntry(logger)
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var version = "latest"
|
||||
|
||||
const commandNameVersion = "version"
|
||||
|
||||
var (
|
||||
versionCmd = &cobra.Command{
|
||||
Use: commandNameVersion,
|
||||
Short: "prints cli version",
|
||||
Long: "prints the current installed cli version",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println(version)
|
||||
},
|
||||
}
|
||||
)
|
||||
@ -1,7 +0,0 @@
|
||||
package main
|
||||
|
||||
import "github.com/foomo/gograpple/cmd/gograpple/actions"
|
||||
|
||||
func main() {
|
||||
actions.Execute()
|
||||
}
|
||||
@ -1,15 +1,19 @@
|
||||
package actions
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"path"
|
||||
|
||||
"github.com/foomo/gograpple"
|
||||
"github.com/foomo/gograpple/config"
|
||||
"github.com/foomo/gograpple/kubectl"
|
||||
"github.com/foomo/gograpple/internal/config"
|
||||
"github.com/foomo/gograpple/internal/grapple"
|
||||
"github.com/foomo/gograpple/internal/kubectl"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const commandNameInteractive = "interactive"
|
||||
func init() {
|
||||
interactiveCmd.Flags().BoolVar(&flagAttach, "attach", false, "debug with attach (default will patch)")
|
||||
interactiveCmd.Flags().StringVar(&flagSaveDir, "save", ".", "directory to save interactive configuration")
|
||||
rootCmd.AddCommand(interactiveCmd)
|
||||
}
|
||||
|
||||
var (
|
||||
flagAttach bool
|
||||
@ -37,7 +41,7 @@ func attachDebug(baseDir string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g, err := gograpple.NewGrapple(newLogger(flagVerbose, flagJSONLog), c.Namespace, c.Deployment, flagDebug)
|
||||
g, err := grapple.NewGrapple(newLogEntry(flagDebug), c.Namespace, c.Deployment)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -48,7 +52,7 @@ func attachDebug(baseDir string) error {
|
||||
if err := kubectl.SetContext(c.Cluster); err != nil {
|
||||
return err
|
||||
}
|
||||
return g.Attach(c.Namespace, c.Deployment, c.Container, c.AttachTo, c.Arch, host, port)
|
||||
return g.Attach(c.Namespace, c.Deployment, c.Container, c.AttachTo, c.Arch, host, port, flagDebug)
|
||||
}
|
||||
|
||||
func patchDebug(baseDir string) error {
|
||||
@ -64,7 +68,7 @@ func patchDebug(baseDir string) error {
|
||||
if &c == nil {
|
||||
return nil
|
||||
}
|
||||
g, err := gograpple.NewGrapple(newLogger(flagVerbose, flagJSONLog), c.Namespace, c.Deployment, flagDebug)
|
||||
g, err := grapple.NewGrapple(newLogEntry(flagDebug), c.Namespace, c.Deployment)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
25
cmd/rollback.go
Normal file
25
cmd/rollback.go
Normal file
@ -0,0 +1,25 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/foomo/gograpple/internal/grapple"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(rollbackCmd)
|
||||
}
|
||||
|
||||
var (
|
||||
rollbackCmd = &cobra.Command{
|
||||
Use: "rollback [namespace] [deployment]",
|
||||
Short: "rollback the patched deployment",
|
||||
Args: cobra.MinimumNArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
g, err := grapple.NewGrapple(newLogEntry(flagDebug), args[0], args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return g.Rollback()
|
||||
},
|
||||
}
|
||||
)
|
||||
50
cmd/root.go
Normal file
50
cmd/root.go
Normal file
@ -0,0 +1,50 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.PersistentFlags().BoolVarP(&flagDebug, "debug", "", false, "debug mode")
|
||||
}
|
||||
|
||||
var (
|
||||
// flagImage string
|
||||
// flagDir string
|
||||
flagDebug bool
|
||||
// flagNamespace string
|
||||
// flagPod string
|
||||
// flagContainer string
|
||||
// flagRepo string
|
||||
// flagMounts []string
|
||||
// flagSourcePath string
|
||||
// flagArgs = NewStringList(" ")
|
||||
// flagRollback bool
|
||||
// flagListen = NewHostPort("127.0.0.1", 0)
|
||||
// flagVscode bool
|
||||
// flagContinue bool
|
||||
// flagJSONLog bool
|
||||
// flagDebug bool
|
||||
)
|
||||
|
||||
var (
|
||||
rootCmd = &cobra.Command{
|
||||
Use: "gograpple",
|
||||
}
|
||||
)
|
||||
|
||||
func Execute() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
le := newLogEntry(flagDebug)
|
||||
le.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func newLogEntry(debug bool) *logrus.Entry {
|
||||
logger := logrus.New()
|
||||
if debug {
|
||||
logger.SetLevel(logrus.TraceLevel)
|
||||
}
|
||||
return logrus.NewEntry(logger)
|
||||
}
|
||||
32
cmd/version.go
Normal file
32
cmd/version.go
Normal file
@ -0,0 +1,32 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(versionCmd)
|
||||
}
|
||||
|
||||
// set on build
|
||||
var version = ""
|
||||
|
||||
var (
|
||||
versionCmd = &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "prints cli version",
|
||||
Long: "prints the current installed cli version",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println(getVersion())
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func getVersion() string {
|
||||
if version == "" {
|
||||
return "latest"
|
||||
}
|
||||
return version
|
||||
}
|
||||
@ -8,8 +8,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/c-bata/go-prompt"
|
||||
"github.com/foomo/gograpple/kubectl"
|
||||
"github.com/foomo/gograpple/suggest"
|
||||
"github.com/foomo/gograpple/internal/kubectl"
|
||||
"github.com/foomo/gograpple/internal/suggest"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
@ -8,8 +8,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/c-bata/go-prompt"
|
||||
"github.com/foomo/gograpple/kubectl"
|
||||
"github.com/foomo/gograpple/suggest"
|
||||
"github.com/foomo/gograpple/internal/kubectl"
|
||||
"github.com/foomo/gograpple/internal/suggest"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/foomo/gograpple/exec"
|
||||
"github.com/foomo/gograpple/internal/exec"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@ -1,4 +1,4 @@
|
||||
package gograpple
|
||||
package grapple
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -7,12 +7,12 @@ import (
|
||||
"runtime"
|
||||
|
||||
"github.com/bitfield/script"
|
||||
"github.com/foomo/gograpple/kubectl"
|
||||
"github.com/foomo/gograpple/log"
|
||||
"github.com/foomo/gograpple/internal/kubectl"
|
||||
"github.com/foomo/gograpple/internal/log"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (g Grapple) Attach(namespace, deployment, container, bin, arch, host string, port int) error {
|
||||
func (g Grapple) Attach(namespace, deployment, container, bin, arch, host string, port int, debug bool) error {
|
||||
pod, err := kubectl.GetMostRecentRunningPodBySelectors(namespace, g.deployment.Spec.Selector.MatchLabels)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -35,7 +35,7 @@ func (g Grapple) Attach(namespace, deployment, container, bin, arch, host string
|
||||
if len(pids) != 1 {
|
||||
return fmt.Errorf("found none or more than one process named %q", bin)
|
||||
}
|
||||
go attachDelveOnPod(namespace, pod, container, dlvDest, pids[0], host, port, g.debug)
|
||||
go attachDelveOnPod(namespace, pod, container, dlvDest, pids[0], host, port, debug)
|
||||
// launchVSCode(context.Background(), g.l, "./test/app", "", port, 3)
|
||||
return kubectl.PortForwardPod(namespace, pod, port)
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package gograpple
|
||||
package grapple
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -7,8 +7,9 @@ import (
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/foomo/gograpple/delve"
|
||||
"github.com/foomo/gograpple/exec"
|
||||
"github.com/foomo/gograpple/internal/delve"
|
||||
"github.com/foomo/gograpple/internal/exec"
|
||||
"github.com/foomo/gograpple/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
@ -41,7 +42,7 @@ func (g Grapple) Delve(pod, container, sourcePath string, binArgs []string, host
|
||||
return fmt.Errorf("couldnt find go.mod path for source %q", sourcePath)
|
||||
}
|
||||
|
||||
RunWithInterrupt(g.l, func(ctx context.Context) {
|
||||
util.RunWithInterrupt(g.l, func(ctx context.Context) {
|
||||
g.l.Infof("waiting for deployment to get ready")
|
||||
_, err := g.kubeCmd.WaitForRollout(g.deployment.Name, defaultWaitTimeout).Run(ctx)
|
||||
if err != nil {
|
||||
@ -1,4 +1,4 @@
|
||||
package gograpple
|
||||
package grapple
|
||||
|
||||
import (
|
||||
"net"
|
||||
@ -10,7 +10,7 @@ import (
|
||||
const testNamespace = "test"
|
||||
|
||||
func testGrapple(t *testing.T, deployment string) *Grapple {
|
||||
g, err := NewGrapple(logrus.NewEntry(logrus.StandardLogger()), testNamespace, deployment, false)
|
||||
g, err := NewGrapple(logrus.NewEntry(logrus.StandardLogger()), testNamespace, deployment)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -1,9 +1,9 @@
|
||||
package gograpple
|
||||
package grapple
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/foomo/gograpple/exec"
|
||||
"github.com/foomo/gograpple/internal/exec"
|
||||
"github.com/sirupsen/logrus"
|
||||
v1 "k8s.io/api/apps/v1"
|
||||
)
|
||||
@ -30,11 +30,10 @@ type Grapple struct {
|
||||
kubeCmd *exec.KubectlCmd
|
||||
dockerCmd *exec.DockerCmd
|
||||
goCmd *exec.GoCmd
|
||||
debug bool
|
||||
}
|
||||
|
||||
func NewGrapple(l *logrus.Entry, namespace, deployment string, debug bool) (*Grapple, error) {
|
||||
g := &Grapple{l: l, debug: debug}
|
||||
func NewGrapple(l *logrus.Entry, namespace, deployment string) (*Grapple, error) {
|
||||
g := &Grapple{l: l}
|
||||
g.kubeCmd = exec.NewKubectlCommand()
|
||||
g.dockerCmd = exec.NewDockerCommand()
|
||||
g.goCmd = exec.NewGoCommand()
|
||||
@ -1,4 +1,4 @@
|
||||
package gograpple
|
||||
package grapple
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -9,6 +9,7 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/foomo/gograpple/util"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@ -109,7 +110,7 @@ func (g Grapple) Patch(image, container string, mounts []Mount) error {
|
||||
return err
|
||||
}
|
||||
// get repo from deployment image
|
||||
imageRepo, name, tag, err := ParseImage(deploymentImage)
|
||||
imageRepo, name, tag, err := util.ParseImage(deploymentImage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package gograpple
|
||||
package grapple
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@ -1,4 +1,4 @@
|
||||
package gograpple
|
||||
package grapple
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -1,4 +1,4 @@
|
||||
package gograpple
|
||||
package grapple
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -7,13 +7,8 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/foomo/gograpple/exec"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func FindFreePort(host string) (int, error) {
|
||||
@ -37,21 +32,6 @@ func CheckTCPConnection(host string, port int) (*net.TCPAddr, error) {
|
||||
return l.Addr().(*net.TCPAddr), nil
|
||||
}
|
||||
|
||||
func Open(l *logrus.Entry, ctx context.Context, path string) (string, error) {
|
||||
var cmd *exec.Cmd
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
cmd = exec.NewCommand("xdg-open").Logger(l).Args(path)
|
||||
case "windows":
|
||||
cmd = exec.NewCommand("rundll32").Logger(l).Args("url.dll,FileProtocolHandler", path)
|
||||
case "darwin":
|
||||
cmd = exec.NewCommand("open").Logger(l).Args(path)
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported platform")
|
||||
}
|
||||
return cmd.Run(ctx)
|
||||
}
|
||||
|
||||
func TryCall(tries int, waitBetweenAttempts time.Duration, f func(i int) error) error {
|
||||
var err error
|
||||
for i := 1; i < tries+1; i++ {
|
||||
@ -129,24 +109,3 @@ func stringIsInSlice(a string, list []string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func GetPlatformInfo(platform string) (os, arch string, err error) {
|
||||
pieces := strings.Split(platform, "/")
|
||||
if len(pieces) != 2 {
|
||||
return os, arch, fmt.Errorf("invalid format for platform %q", platform)
|
||||
}
|
||||
return pieces[0], pieces[1], nil
|
||||
}
|
||||
|
||||
func ParseImage(s string) (repo, name, tag string, err error) {
|
||||
pieces := strings.Split(s, "/")
|
||||
switch true {
|
||||
case len(pieces) == 1 && pieces[0] == s:
|
||||
imageTag := strings.Split(s, ":")
|
||||
return "", imageTag[0], imageTag[1], nil
|
||||
case len(pieces) > 1:
|
||||
imageTag := strings.Split(pieces[len(pieces)-1], ":")
|
||||
return strings.Join(pieces[:len(pieces)-1], "/"), imageTag[0], imageTag[1], nil
|
||||
}
|
||||
return "", "", "", fmt.Errorf("invalid image value %q provided", s)
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package gograpple
|
||||
package grapple
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -1,4 +1,4 @@
|
||||
package gograpple
|
||||
package grapple
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -10,7 +10,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/foomo/gograpple/exec"
|
||||
"github.com/foomo/gograpple/internal/exec"
|
||||
"github.com/foomo/gograpple/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
@ -79,7 +80,7 @@ func launchVSCode(ctx context.Context, l *logrus.Entry, goModDir, host string, p
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = Open(l, ctx, `vscode://fabiospampinato.vscode-debug-launcher/launch?args=`+url.QueryEscape(la))
|
||||
_, err = util.Open(l, ctx, `vscode://fabiospampinato.vscode-debug-launcher/launch?args=`+url.QueryEscape(la))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -7,8 +7,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/bitfield/script"
|
||||
"github.com/foomo/gograpple/log"
|
||||
"github.com/foomo/gograpple/suggest"
|
||||
"github.com/foomo/gograpple/internal/log"
|
||||
"github.com/foomo/gograpple/internal/suggest"
|
||||
"github.com/life4/genesis/slices"
|
||||
"github.com/pkg/errors"
|
||||
apps "k8s.io/api/apps/v1"
|
||||
38
interrupt.go
38
interrupt.go
@ -1,38 +0,0 @@
|
||||
package gograpple
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/signal"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func RunWithInterrupt(l *logrus.Entry, callback func(ctx context.Context)) {
|
||||
signalChan := make(chan os.Signal, 1)
|
||||
signal.Notify(signalChan, os.Interrupt)
|
||||
durReload := 3 * time.Second
|
||||
for {
|
||||
ctx, cancelCtx := context.WithCancel(context.Background())
|
||||
// do stuff
|
||||
go callback(ctx)
|
||||
select {
|
||||
case <-signalChan: // first signal
|
||||
l.Info("-")
|
||||
l.Infof("interrupt received, trigger one more within %v to terminate", durReload)
|
||||
cancelCtx()
|
||||
select {
|
||||
case <-time.After(durReload): // reloads durReload after first signal
|
||||
l.Info("-")
|
||||
l.Info("reloading")
|
||||
case <-signalChan: // second signal, hard exit
|
||||
l.Info("-")
|
||||
l.Info("terminating")
|
||||
signal.Stop(signalChan)
|
||||
// exit loop
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
main.go
Normal file
7
main.go
Normal file
@ -0,0 +1,7 @@
|
||||
package main
|
||||
|
||||
import "github.com/foomo/gograpple/cmd"
|
||||
|
||||
func main() {
|
||||
cmd.Execute()
|
||||
}
|
||||
78
util/util.go
Normal file
78
util/util.go
Normal file
@ -0,0 +1,78 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/foomo/gograpple/internal/exec"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func RunWithInterrupt(l *logrus.Entry, callback func(ctx context.Context)) {
|
||||
signalChan := make(chan os.Signal, 1)
|
||||
signal.Notify(signalChan, os.Interrupt)
|
||||
durReload := 3 * time.Second
|
||||
for {
|
||||
ctx, cancelCtx := context.WithCancel(context.Background())
|
||||
// do stuff
|
||||
go callback(ctx)
|
||||
select {
|
||||
case <-signalChan: // first signal
|
||||
l.Info("-")
|
||||
l.Infof("interrupt received, trigger one more within %v to terminate", durReload)
|
||||
cancelCtx()
|
||||
select {
|
||||
case <-time.After(durReload): // reloads durReload after first signal
|
||||
l.Info("-")
|
||||
l.Info("reloading")
|
||||
case <-signalChan: // second signal, hard exit
|
||||
l.Info("-")
|
||||
l.Info("terminating")
|
||||
signal.Stop(signalChan)
|
||||
// exit loop
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Open(l *logrus.Entry, ctx context.Context, path string) (string, error) {
|
||||
var cmd *exec.Cmd
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
cmd = exec.NewCommand("xdg-open").Logger(l).Args(path)
|
||||
case "windows":
|
||||
cmd = exec.NewCommand("rundll32").Logger(l).Args("url.dll,FileProtocolHandler", path)
|
||||
case "darwin":
|
||||
cmd = exec.NewCommand("open").Logger(l).Args(path)
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported platform")
|
||||
}
|
||||
return cmd.Run(ctx)
|
||||
}
|
||||
|
||||
func GetPlatformInfo(platform string) (os, arch string, err error) {
|
||||
pieces := strings.Split(platform, "/")
|
||||
if len(pieces) != 2 {
|
||||
return os, arch, fmt.Errorf("invalid format for platform %q", platform)
|
||||
}
|
||||
return pieces[0], pieces[1], nil
|
||||
}
|
||||
|
||||
func ParseImage(s string) (repo, name, tag string, err error) {
|
||||
pieces := strings.Split(s, "/")
|
||||
switch true {
|
||||
case len(pieces) == 1 && pieces[0] == s:
|
||||
imageTag := strings.Split(s, ":")
|
||||
return "", imageTag[0], imageTag[1], nil
|
||||
case len(pieces) > 1:
|
||||
imageTag := strings.Split(pieces[len(pieces)-1], ":")
|
||||
return strings.Join(pieces[:len(pieces)-1], "/"), imageTag[0], imageTag[1], nil
|
||||
}
|
||||
return "", "", "", fmt.Errorf("invalid image value %q provided", s)
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user