diff --git a/go.mod b/go.mod index ce507f4..5e5cef2 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,7 @@ require ( github.com/go-playground/universal-translator v0.18.0 // indirect github.com/go-playground/validator/v10 v10.11.1 // indirect github.com/goccy/go-json v0.9.11 // indirect + github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/leodido/go-urn v1.2.1 // indirect @@ -38,6 +39,8 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.5 // indirect github.com/rivo/uniseg v0.4.2 // indirect + github.com/spf13/cobra v1.6.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect github.com/ugorji/go/codec v1.2.7 // indirect golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be // indirect golang.org/x/net v0.0.0-20220926192436-02166a98028e // indirect diff --git a/go.sum b/go.sum index 9d4061f..af4a0f5 100644 --- a/go.sum +++ b/go.sum @@ -18,6 +18,7 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -77,6 +78,8 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -150,12 +153,17 @@ github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY= github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shirou/gopsutil v2.18.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI= +github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= diff --git a/src/app/process.go b/src/app/process.go index 7e72943..3d71edf 100644 --- a/src/app/process.go +++ b/src/app/process.go @@ -13,7 +13,7 @@ import ( "syscall" "time" - "github.com/f1bonacc1/process-compose/src/cmd" + "github.com/f1bonacc1/process-compose/src/command" "github.com/f1bonacc1/process-compose/src/health" "github.com/f1bonacc1/process-compose/src/pclog" @@ -85,7 +85,7 @@ func (p *Process) run() error { } for { starter := func() error { - p.command = cmd.BuildCommand(p.getCommand()) + p.command = command.BuildCommand(p.getCommand()) p.command.Env = p.getProcessEnvironment() p.setProcArgs() stdout, _ := p.command.StdoutPipe() @@ -223,10 +223,10 @@ func (p *Process) doConfiguredStop(params ShutDownParams) error { defer cancel() defer p.notifyDaemonStopped() - command := cmd.BuildCommandContext(ctx, params.ShutDownCommand) - command.Env = p.getProcessEnvironment() + cmd := command.BuildCommandContext(ctx, params.ShutDownCommand) + cmd.Env = p.getProcessEnvironment() - if err := command.Run(); err != nil { + if err := cmd.Run(); err != nil { // the process termination timedout and it will be killed log.Error().Msgf("terminating %s with timeout %d failed - %s", p.getName(), timeout, err.Error()) return p.stop(int(syscall.SIGKILL)) @@ -393,7 +393,7 @@ func (p *Process) stopProbes() { } } -func (p *Process) onLivenessCheckEnd(isOk, isFatal bool, err string) { +func (p *Process) onLivenessCheckEnd(_, isFatal bool, err string) { if isFatal { log.Info().Msgf("%s is not alive anymore - %s", p.getName(), err) p.logBuffer.Write("Error: liveness check fail - " + err) diff --git a/src/cmd/root.go b/src/cmd/root.go new file mode 100644 index 0000000..543ff40 --- /dev/null +++ b/src/cmd/root.go @@ -0,0 +1,132 @@ +package cmd + +import ( + "fmt" + "github.com/f1bonacc1/process-compose/src/api" + "github.com/f1bonacc1/process-compose/src/app" + "github.com/f1bonacc1/process-compose/src/tui" + "github.com/gin-gonic/gin" + "github.com/rs/zerolog" + "net/http" + "os" + "os/signal" + "syscall" + "time" + + "github.com/rs/zerolog/log" + "github.com/spf13/cobra" +) + +const EnvDebugMode = "PC_DEBUG_MODE" + +var ( + fileName string + port int + isTui bool + version string + + // rootCmd represents the base command when called without any subcommands + rootCmd = &cobra.Command{ + Use: "process-compose", + Short: "A brief description of your application", + Long: `A longer description that spans multiple lines and likely contains +examples and usage of using your application. For example: + +Cobra is a CLI library for Go that empowers applications. +This application is a tool to generate the needed files +to quickly create a Cobra application.`, + // Uncomment the following line if your bare application + // has an action associated with it: + Run: func(cmd *cobra.Command, args []string) { + fmt.Println(fileName) + if !cmd.Flags().Changed("config") { + + pwd, err := os.Getwd() + if err != nil { + log.Fatal().Msg(err.Error()) + } + file, err := app.AutoDiscoverComposeFile(pwd) + if err != nil { + log.Fatal().Msg(err.Error()) + } + fileName = file + } + + if os.Getenv(EnvDebugMode) == "" { + gin.SetMode(gin.ReleaseMode) + } + + routersInit := api.InitRoutes(!isTui) + readTimeout := time.Duration(60) * time.Second + writeTimeout := time.Duration(60) * time.Second + endPoint := fmt.Sprintf(":%d", port) + maxHeaderBytes := 1 << 20 + + server := &http.Server{ + Addr: endPoint, + Handler: routersInit, + ReadTimeout: readTimeout, + WriteTimeout: writeTimeout, + MaxHeaderBytes: maxHeaderBytes, + } + + log.Info().Msgf("start http server listening %s", endPoint) + + go server.ListenAndServe() + + project := app.CreateProject(fileName) + + if isTui { + defer quiet()() + go project.Run() + tui.SetupTui(version, project.LogLength) + } else { + runHeadless(project) + } + + log.Info().Msg("Thank you for using proccess-compose") + }, + } +) + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute(ver string) { + version = ver + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } +} + +func init() { + + rootCmd.Flags().StringVarP(&fileName, "config", "f", app.DefaultFileNames[0], "path to config file to load") + rootCmd.Flags().BoolVarP(&isTui, "tui", "t", true, "disable tui (-t=false)") + rootCmd.Flags().IntVarP(&port, "port", "p", 8080, "port number") +} + +func runHeadless(project *app.Project) { + cancelChan := make(chan os.Signal, 1) + // catch SIGTERM or SIGINTERRUPT + signal.Notify(cancelChan, syscall.SIGTERM, syscall.SIGINT) + go project.Run() + sig := <-cancelChan + log.Info().Msgf("Caught %v - Shutting down the running processes...", sig) + project.ShutDownProject() +} + +func quiet() func() { + null, _ := os.Open(os.DevNull) + sout := os.Stdout + serr := os.Stderr + os.Stdout = null + os.Stderr = null + zerolog.SetGlobalLevel(zerolog.Disabled) + return func() { + defer null.Close() + os.Stdout = sout + os.Stderr = serr + zerolog.SetGlobalLevel(zerolog.DebugLevel) + } +} diff --git a/src/cmd/command.go b/src/command/command.go similarity index 97% rename from src/cmd/command.go rename to src/command/command.go index 682419d..d0c63ce 100644 --- a/src/cmd/command.go +++ b/src/command/command.go @@ -1,4 +1,4 @@ -package cmd +package command import ( "context" diff --git a/src/health/exec_checker.go b/src/health/exec_checker.go index 46eed79..9ead695 100644 --- a/src/health/exec_checker.go +++ b/src/health/exec_checker.go @@ -2,9 +2,8 @@ package health import ( "context" + "github.com/f1bonacc1/process-compose/src/command" "time" - - "github.com/f1bonacc1/process-compose/src/cmd" ) type execChecker struct { @@ -16,7 +15,7 @@ func (c *execChecker) Status() (interface{}, error) { ctx, cancel := context.WithTimeout(context.Background(), time.Duration(c.timeout)*time.Second) defer cancel() - cmd := cmd.BuildCommandContext(ctx, c.command) + cmd := command.BuildCommandContext(ctx, c.command) if err := cmd.Run(); err != nil { return nil, err diff --git a/src/main.go b/src/main.go index b733986..78108ff 100644 --- a/src/main.go +++ b/src/main.go @@ -1,25 +1,12 @@ package main import ( - "flag" - "fmt" - "net/http" - "os/signal" - "syscall" - "time" - - "os" - - "github.com/f1bonacc1/process-compose/src/api" - "github.com/f1bonacc1/process-compose/src/app" - "github.com/f1bonacc1/process-compose/src/tui" - "github.com/gin-gonic/gin" + "github.com/f1bonacc1/process-compose/src/cmd" "github.com/rs/zerolog" "github.com/rs/zerolog/log" + "os" ) -const EnvDebugMode = "PC_DEBUG_MODE" - var version = "undefined" func setupLogger() { @@ -31,99 +18,10 @@ func setupLogger() { zerolog.SetGlobalLevel(zerolog.DebugLevel) } -func isFlagPassed(name string) bool { - found := false - flag.Visit(func(f *flag.Flag) { - if f.Name == name { - found = true - } - }) - return found -} - func init() { setupLogger() } -func quiet() func() { - null, _ := os.Open(os.DevNull) - sout := os.Stdout - serr := os.Stderr - os.Stdout = null - os.Stderr = null - zerolog.SetGlobalLevel(zerolog.Disabled) - return func() { - defer null.Close() - os.Stdout = sout - os.Stderr = serr - zerolog.SetGlobalLevel(zerolog.DebugLevel) - } -} - -func runHeadless(project *app.Project) { - cancelChan := make(chan os.Signal, 1) - // catch SIGTERM or SIGINTERRUPT - signal.Notify(cancelChan, syscall.SIGTERM, syscall.SIGINT) - go func() { - project.Run() - }() - sig := <-cancelChan - log.Info().Msgf("Caught %v - Shutting down the running processes...", sig) - project.ShutDownProject() -} - func main() { - fileName := "" - port := 8080 - isTui := true - flag.StringVar(&fileName, "f", app.DefaultFileNames[0], "path to file to load") - flag.IntVar(&port, "p", port, "port number") - flag.BoolVar(&isTui, "t", isTui, "disable tui (-t=false)") - flag.Parse() - if !isFlagPassed("f") { - pwd, err := os.Getwd() - if err != nil { - log.Fatal().Msg(err.Error()) - } - file, err := app.AutoDiscoverComposeFile(pwd) - if err != nil { - log.Fatal().Msg(err.Error()) - } - fileName = file - } - - if os.Getenv(EnvDebugMode) == "" { - gin.SetMode(gin.ReleaseMode) - } - - routersInit := api.InitRoutes(!isTui) - readTimeout := time.Duration(60) * time.Second - writeTimeout := time.Duration(60) * time.Second - endPoint := fmt.Sprintf(":%d", port) - maxHeaderBytes := 1 << 20 - - server := &http.Server{ - Addr: endPoint, - Handler: routersInit, - ReadTimeout: readTimeout, - WriteTimeout: writeTimeout, - MaxHeaderBytes: maxHeaderBytes, - } - - log.Info().Msgf("start http server listening %s", endPoint) - - go server.ListenAndServe() - - project := app.CreateProject(fileName) - - if isTui { - defer quiet()() - go project.Run() - tui.SetupTui(version, project.LogLength) - } else { - runHeadless(project) - } - - log.Info().Msg("Thank you for using proccess-compose") - + cmd.Execute(version) }