Skip to content

Commit

Permalink
Merge pull request #340 from bavix/cobra
Browse files Browse the repository at this point in the history
[3.x] refactoring v3. cobra
  • Loading branch information
rez1dent3 authored Jul 10, 2024
2 parents a995ee4 + 04deb65 commit d76e86c
Show file tree
Hide file tree
Showing 31 changed files with 738 additions and 362 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ COPY . /go/src/github.com/bavix/gripmock

WORKDIR /go/src/github.com/bavix/gripmock

RUN go install -v -ldflags "-X 'main.version=${version:-dev}' -s -w"
RUN go install -v -ldflags "-X 'github.com/bavix/gripmock/cmd.version=${version:-dev}' -s -w"

EXPOSE 4770 4771

Expand Down
63 changes: 63 additions & 0 deletions cmd/check.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//nolint:gochecknoglobals
package cmd

import (
"errors"
"time"

"github.com/rs/zerolog"
"github.com/spf13/cobra"

"github.com/bavix/gripmock/internal/deps"
"github.com/bavix/gripmock/internal/domain/waiter"
)

var (
pingTimeout time.Duration
errServerIsNotRunning = errors.New("server is not running")
)

const serviceName = "gripmock"

var checkCmd = &cobra.Command{
Use: "check",
Short: "The command checks whether the gripmock server is alive or dead by accessing it via the API",
RunE: func(cmd *cobra.Command, _ []string) error {
builder := deps.NewBuilder(deps.WithDefaultConfig())
ctx, cancel := builder.SignalNotify(cmd.Context())
defer cancel()

ctx = builder.Logger(ctx)

pingService, err := builder.PingService()
if err != nil {
zerolog.Ctx(ctx).Err(err).Msg("create ping service failed")

return err
}

status, err := pingService.PingWithTimeout(ctx, pingTimeout, serviceName)
if err != nil {
zerolog.Ctx(ctx).Err(err).Msg("unable to connect to server")

return err
}

if status != waiter.Serving {
zerolog.Ctx(ctx).Error().Uint32("code", uint32(status)).Msg("server is not running")

return errServerIsNotRunning
}

return nil
},
}

//nolint:gochecknoinits
func init() {
rootCmd.AddCommand(checkCmd)

const defaultPingTimeout = time.Second * 5

checkCmd.Flags().DurationVarP(&pingTimeout, "timeout", "t", defaultPingTimeout, "timeout")
}
105 changes: 105 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
//nolint:gochecknoglobals
package cmd

import (
"context"
"errors"
"net/http"
"os"

"github.com/rs/zerolog"
"github.com/spf13/cobra"

"github.com/bavix/gripmock/internal/deps"
"github.com/bavix/gripmock/internal/domain/proto"
)

var (
outputFlag string
stubFlag string
importsFlag []string
version = "development"
)

var rootCmd = &cobra.Command{
Use: "gripmock",
Short: "gRPC Mock Server",
Version: version,
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
builder := deps.NewBuilder(deps.WithDefaultConfig())
ctx, cancel := builder.SignalNotify(cmd.Context())
defer cancel()

ctx = builder.Logger(ctx)

zerolog.Ctx(ctx).Info().Str("release", version).Msg("Starting GripMock")

go func() {
if err := restServe(ctx, builder); err != nil {
zerolog.Ctx(ctx).Err(err).Msg("failed to start rest server")
}
}()

return builder.GRPCServe(cmd.Context(), proto.NewProtocParam(args, outputFlag, importsFlag))
},
}

func restServe(ctx context.Context, builder *deps.Builder) error {
srv, err := builder.RestServe(ctx, stubFlag)
if err != nil {
return err
}

ch := make(chan error)

go func() {
zerolog.Ctx(ctx).
Info().
Str("addr", builder.Config().HTTPAddr).
Msg("Serving stub-manager")

ch <- srv.ListenAndServe()
}()

select {
case err = <-ch:
if errors.Is(err, http.ErrServerClosed) {
return nil
}

return err
case <-ctx.Done():
return ctx.Err()
}
}

//nolint:gochecknoinits
func init() {
rootCmd.Flags().StringVarP(
&outputFlag,
"output",
"o",
os.Getenv("GOPATH")+"/src/grpc",
"Server generation directory server.go")

rootCmd.Flags().StringVarP(
&stubFlag,
"stub",
"s",
"",
"Path where the stub files are (Optional)")

rootCmd.Flags().StringSliceVarP(
&importsFlag,
"imports",
"i",
[]string{"/protobuf", "/googleapis"},
"Path to import proto-libraries")
}

func Execute(ctx context.Context) {
if err := rootCmd.ExecuteContext(ctx); err != nil {
os.Exit(1)
}
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ require (
github.com/jhump/protoreflect v1.16.0
github.com/oapi-codegen/runtime v1.1.1
github.com/rs/zerolog v1.33.0
github.com/spf13/cobra v1.8.1
github.com/stretchr/testify v1.9.0
golang.org/x/text v0.16.0
google.golang.org/genproto/googleapis/api v0.0.0-20240709173604-40e1e62336c5
Expand All @@ -36,11 +37,13 @@ require (
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/gripmock/deeply v1.1.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/exp v0.0.0-20240707233637-46b078467d37 // indirect
golang.org/x/net v0.27.0 // indirect
golang.org/x/sys v0.22.0 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ github.com/bufbuild/protocompile v0.14.0/go.mod h1:N6J1NYzkspJo3ZwyL4Xjvli86XOj1
github.com/caarlos0/env/v10 v10.0.0 h1:yIHUBZGsyqCnpTkbjk8asUlx6RFhhEs+h7TOBdgdzXA=
github.com/caarlos0/env/v10 v10.0.0/go.mod h1:ZfulV76NvVPw3tm591U4SwL3Xx9ldzBP9aGxzeN7G18=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cristalhq/base64 v0.1.2 h1:edsefYyYDiac7Ytdh2xdaiiSSJzcI2f0yIkdGEf1qY0=
github.com/cristalhq/base64 v0.1.2/go.mod h1:sy4+2Hale2KbtSqkzpdMeYTP/IrB+HCvxVHWsh2VSYk=
Expand Down Expand Up @@ -60,6 +61,8 @@ github.com/gripmock/shutdown v1.0.0 h1:ESDCCBeNHazgAstCpIskaORNWH3b+P03a2gznW+8I
github.com/gripmock/shutdown v1.0.0/go.mod h1:YwyI7uYgIPPdR9k8QNHwzDI2mQNpUSu+WT9mvqVoty4=
github.com/gripmock/stuber v1.0.4 h1:XqdZF/yz6cVPuAjahgBYFKOQjh8oNBTQMB3tXrnwe58=
github.com/gripmock/stuber v1.0.4/go.mod h1:bYmpJTIc4Mwl4/2CM1cREOWLZfweFFg05xEUxeOwPCY=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jhump/protoreflect v1.16.0 h1:54fZg+49widqXYQ0b+usAFHbMkBGR4PpXrsHc8+TBDg=
github.com/jhump/protoreflect v1.16.0/go.mod h1:oYPd7nPvcBw/5wlDfm/AVmU9zH9BgqGCI469pGxfj/8=
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
Expand Down Expand Up @@ -90,6 +93,11 @@ github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
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/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
Expand Down
2 changes: 1 addition & 1 deletion go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLI
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnThWgvH2wg8376yUJmPhEH4H3kw=
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI=
github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0=
Expand Down Expand Up @@ -121,7 +122,6 @@ github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk=
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
Expand Down
80 changes: 80 additions & 0 deletions internal/app/grpc_server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package app

import (
"context"
"os"
"os/exec"

"github.com/rs/zerolog"

"github.com/bavix/gripmock/internal/domain/proto"
"github.com/bavix/gripmock/internal/domain/servergen"
)

type GRPCServer struct {
params *proto.ProtocParam
}

func NewGRPCServer(params *proto.ProtocParam) *GRPCServer {
return &GRPCServer{params}
}

func (s *GRPCServer) Serve(ctx context.Context) error {
err := servergen.ServerGenerate(ctx, s.params)
if err != nil {
return err
}

server, ch := s.newServer(ctx)

// Wait for the gRPC server to exit or the context to be done.
select {
case err := <-ch:
return err
case <-ctx.Done():
// If the context is done, check if there was an error.
if err := ctx.Err(); err != nil {
return err
}

// Kill the gRPC server process.
if err := server.Process.Kill(); err != nil {
return err
}
}

return nil
}

// newServer runs the gRPC server in a separate process.
//
// ctx is the context.Context to use for the command.
// output is the output directory where the server.go file is located.
// It returns the exec.Cmd object representing the running process, and a channel
// that receives an error when the process exits.
func (s *GRPCServer) newServer(ctx context.Context) (*exec.Cmd, <-chan error) {
// Construct the command to run the gRPC server.
run := exec.CommandContext(ctx, "go", "run", s.params.Output()+"/server.go") //nolint:gosec
run.Env = os.Environ()
run.Stdout = os.Stdout
run.Stderr = os.Stderr

// Start the command.
if err := run.Start(); err != nil {
zerolog.Ctx(ctx).Fatal().Err(err).Msg("unable to start gRPC service")
}

// Log the process ID.
zerolog.Ctx(ctx).Info().Int("pid", run.Process.Pid).Msg("gRPC-service started")

// Create a channel to receive the process exit error.
runErr := make(chan error)

// Start a goroutine to wait for the process to exit and send the error
// to the channel.
go func() {
runErr <- run.Wait()
}()

return run, runErr
}
4 changes: 0 additions & 4 deletions internal/app/rest_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ import (

"github.com/google/uuid"
"github.com/gripmock/stuber"
"golang.org/x/text/cases"
"golang.org/x/text/language"

"github.com/bavix/features"
"github.com/bavix/gripmock/internal/domain/rest"
Expand All @@ -34,7 +32,6 @@ type RestServer struct {
ok atomic.Bool
stuber *stuber.Budgerigar
convertor *yaml2json.Convertor
caser cases.Caser
reflector *grpcreflector.GReflector
}

Expand All @@ -44,7 +41,6 @@ func NewRestServer(path string, reflector *grpcreflector.GReflector) (*RestServe
server := &RestServer{
stuber: stuber.NewBudgerigar(features.New(stuber.MethodTitle)),
convertor: yaml2json.New(),
caser: cases.Title(language.English, cases.NoLower),
reflector: reflector,
}

Expand Down
40 changes: 40 additions & 0 deletions internal/deps/builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package deps

import (
"github.com/gripmock/environment"
"github.com/gripmock/shutdown"
)

type Option func(*Builder)

type Builder struct {
config environment.Config
ender *shutdown.Shutdown
}

func NewBuilder(opts ...Option) *Builder {
builder := &Builder{ender: shutdown.New(nil)}
for _, opt := range opts {
opt(builder)
}

return builder
}

func WithDefaultConfig() Option {
config, _ := environment.New()

return WithConfig(config)
}

func WithConfig(config environment.Config) Option {
return func(builder *Builder) {
builder.config = config
}
}

func WithEnder(ender *shutdown.Shutdown) Option {
return func(builder *Builder) {
builder.ender = ender
}
}
Loading

0 comments on commit d76e86c

Please sign in to comment.