From a030543ebaccbcda9db8e282211be458a1434ca8 Mon Sep 17 00:00:00 2001 From: Uwe Dauernheim Date: Wed, 12 Oct 2022 19:51:58 +0200 Subject: [PATCH 1/5] Only generate moq when interface file is newer than output file --- main.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/main.go b/main.go index 37c3937..1e2c370 100644 --- a/main.go +++ b/main.go @@ -23,6 +23,7 @@ type userFlags struct { stubImpl bool skipEnsure bool remove bool + force bool args []string } @@ -37,6 +38,7 @@ func main() { flag.BoolVar(&flags.skipEnsure, "skip-ensure", false, "suppress mock implementation check, avoid import cycle if mocks generated outside of the tested package") flag.BoolVar(&flags.remove, "rm", false, "first remove output file, if it exists") + flag.BoolVar(&flags.force, "force", false, "force generation, otherwise check if go generate file is newer than output file") flag.Usage = func() { fmt.Println(`moq [flags] source-dir interface [interface2 [interface3 [...]]]`) @@ -65,6 +67,19 @@ func run(flags userFlags) error { return errors.New("not enough arguments") } + if !flags.force && flags.outFile != "" { + inFile := os.Getenv("GOFILE") + if inStat, err := os.Stat(inFile); err != nil { + fmt.Fprintln(os.Stderr, err) + } else if outStat, err := os.Stat(flags.outFile); err != nil { + if !errors.Is(err, os.ErrNotExist) { + fmt.Fprintln(os.Stderr, err) + } + } else if !inStat.ModTime().After(outStat.ModTime()) { + return nil // Assume no changes thus no need to regenerate. + } + } + if flags.remove && flags.outFile != "" { if err := os.Remove(flags.outFile); err != nil { if !errors.Is(err, os.ErrNotExist) { From 8cc0f14ab9ec09309e5f70fbdc5eb1e3a9f6d704 Mon Sep 17 00:00:00 2001 From: Uwe Dauernheim Date: Wed, 12 Oct 2022 20:22:25 +0200 Subject: [PATCH 2/5] Fix import paths --- go.mod | 2 +- internal/template/template.go | 2 +- internal/template/template_data.go | 2 +- internal/template/template_test.go | 2 +- main.go | 2 +- pkg/moq/moq.go | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 4054df2..a00d10e 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/matryer/moq +module github.com/djui/moq go 1.18 diff --git a/internal/template/template.go b/internal/template/template.go index 9d7cd06..173d0e2 100644 --- a/internal/template/template.go +++ b/internal/template/template.go @@ -5,7 +5,7 @@ import ( "strings" "text/template" - "github.com/matryer/moq/internal/registry" + "github.com/djui/moq/internal/registry" ) // Template is the Moq template. It is capable of generating the Moq diff --git a/internal/template/template_data.go b/internal/template/template_data.go index 12c9117..82a2ed6 100644 --- a/internal/template/template_data.go +++ b/internal/template/template_data.go @@ -5,7 +5,7 @@ import ( "go/types" "strings" - "github.com/matryer/moq/internal/registry" + "github.com/djui/moq/internal/registry" ) // Data is the template data used to render the Moq template. diff --git a/internal/template/template_test.go b/internal/template/template_test.go index e977d48..09c04eb 100644 --- a/internal/template/template_test.go +++ b/internal/template/template_test.go @@ -4,7 +4,7 @@ import ( "go/types" "testing" - "github.com/matryer/moq/internal/registry" + "github.com/djui/moq/internal/registry" ) func TestTemplateFuncs(t *testing.T) { diff --git a/main.go b/main.go index 1e2c370..9df20f4 100644 --- a/main.go +++ b/main.go @@ -10,7 +10,7 @@ import ( "os" "path/filepath" - "github.com/matryer/moq/pkg/moq" + "github.com/djui/moq/pkg/moq" ) // Version is the command version, injected at build time. diff --git a/pkg/moq/moq.go b/pkg/moq/moq.go index a33a4cb..666bc88 100644 --- a/pkg/moq/moq.go +++ b/pkg/moq/moq.go @@ -8,8 +8,8 @@ import ( "io" "strings" - "github.com/matryer/moq/internal/registry" - "github.com/matryer/moq/internal/template" + "github.com/djui/moq/internal/registry" + "github.com/djui/moq/internal/template" ) // Mocker can generate mock structs. From 895b4c569182e158b0088ee00ecd91caa9be0f60 Mon Sep 17 00:00:00 2001 From: Uwe Dauernheim Date: Tue, 25 Oct 2022 12:55:22 +0200 Subject: [PATCH 3/5] Improve error handling for force mode --- main.go | 57 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/main.go b/main.go index 9df20f4..c505b55 100644 --- a/main.go +++ b/main.go @@ -67,16 +67,11 @@ func run(flags userFlags) error { return errors.New("not enough arguments") } - if !flags.force && flags.outFile != "" { - inFile := os.Getenv("GOFILE") - if inStat, err := os.Stat(inFile); err != nil { - fmt.Fprintln(os.Stderr, err) - } else if outStat, err := os.Stat(flags.outFile); err != nil { - if !errors.Is(err, os.ErrNotExist) { - fmt.Fprintln(os.Stderr, err) } - } else if !inStat.ModTime().After(outStat.ModTime()) { - return nil // Assume no changes thus no need to regenerate. + if !flags.force { + if !needsRegeneration(inFile, flags.outFile) { + fmt.Fprintln(os.Stderr, "Skipping mock generation as the input file hasn't changed since the mock was generated") + return nil } } @@ -121,4 +116,48 @@ func run(flags userFlags) error { } return ioutil.WriteFile(flags.outFile, buf.Bytes(), 0600) +func needsRegeneration(inFile, outFile string) bool { + if outFile == "" { + // Assume that the user wants to print to stdout thus we have nothing to + // compare files and timestamps with. + return true + } + + if inFile == "" { + // We were not called via go generate, so we have nothing to compare + // with. + return true + } + + inInfo, err := os.Stat(inFile) + if err != nil { + if errors.Is(err, os.ErrNotExist) { + // Somehow the input file does not exist, which is weird as it's + // only provided by Go generate and there it should always exists, + // but let's assume it's run manually with wrong configuration. + return true + } + + // Something went wrong stating the input file, so let's hope + // regeneration should be done and will work. + fmt.Fprintln(os.Stderr, err) + return true + } + + outInfo, err := os.Stat(outFile) + if err != nil { + if errors.Is(err, os.ErrNotExist) { + // Likely the output file does not exist yet/anymore, so we should + // regenerate. + return true + } + + // Something went wrong stating the output file, so let's hope + // regeneration should be done and will work. + fmt.Fprintln(os.Stderr, err) + return true + } + + // The actual comparison. + return inInfo.ModTime().After(outInfo.ModTime()) } From 80814111b6e03a249abe558310c1bf39f863decf Mon Sep 17 00:00:00 2001 From: Uwe Dauernheim Date: Tue, 25 Oct 2022 12:55:40 +0200 Subject: [PATCH 4/5] Add support for verbose output --- main.go | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/main.go b/main.go index c505b55..a745bf5 100644 --- a/main.go +++ b/main.go @@ -24,6 +24,7 @@ type userFlags struct { skipEnsure bool remove bool force bool + verbose bool args []string } @@ -39,6 +40,7 @@ func main() { "suppress mock implementation check, avoid import cycle if mocks generated outside of the tested package") flag.BoolVar(&flags.remove, "rm", false, "first remove output file, if it exists") flag.BoolVar(&flags.force, "force", false, "force generation, otherwise check if go generate file is newer than output file") + flag.BoolVar(&flags.verbose, "verbose", false, "verbose mode") flag.Usage = func() { fmt.Println(`moq [flags] source-dir interface [interface2 [interface3 [...]]]`) @@ -67,7 +69,30 @@ func run(flags userFlags) error { return errors.New("not enough arguments") } + inFile := os.Getenv("GOFILE") + + if flags.verbose { + if inFile == "" { + fmt.Fprintln(os.Stderr, "Mock in-file is unknown") + } else { + p, err := filepath.Abs(inFile) + if err != nil { + p = flags.outFile + } + fmt.Fprintln(os.Stderr, "Mock in-file is "+p) + } + + if flags.outFile == "" { + fmt.Fprintln(os.Stderr, "Mock out-file is stdout") + } else { + p, err := filepath.Abs(flags.outFile) + if err != nil { + p = flags.outFile } + fmt.Fprintln(os.Stderr, "Mock out-file is "+p) + } + } + if !flags.force { if !needsRegeneration(inFile, flags.outFile) { fmt.Fprintln(os.Stderr, "Skipping mock generation as the input file hasn't changed since the mock was generated") @@ -106,6 +131,7 @@ func run(flags userFlags) error { } if flags.outFile == "" { + fmt.Fprintln(os.Stderr, "Mock written.") return nil } @@ -115,7 +141,15 @@ func run(flags userFlags) error { return err } - return ioutil.WriteFile(flags.outFile, buf.Bytes(), 0600) + err = ioutil.WriteFile(flags.outFile, buf.Bytes(), 0600) + + if flags.verbose { + fmt.Fprintln(os.Stderr, "Mock written.") + } + + return err +} + func needsRegeneration(inFile, outFile string) bool { if outFile == "" { // Assume that the user wants to print to stdout thus we have nothing to From 51ae8e8ab4fff14bbf9643450d575d95de9bf8af Mon Sep 17 00:00:00 2001 From: Uwe Dauernheim Date: Tue, 25 Oct 2022 17:37:35 +0200 Subject: [PATCH 5/5] Remove output if not verbose --- main.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/main.go b/main.go index a745bf5..4c4037f 100644 --- a/main.go +++ b/main.go @@ -95,7 +95,9 @@ func run(flags userFlags) error { if !flags.force { if !needsRegeneration(inFile, flags.outFile) { - fmt.Fprintln(os.Stderr, "Skipping mock generation as the input file hasn't changed since the mock was generated") + if flags.verbose { + fmt.Fprintln(os.Stderr, "Skipping mock generation as the input file hasn't changed since the mock was generated") + } return nil } }