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 37c3937..4c4037f 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. @@ -23,6 +23,8 @@ type userFlags struct { stubImpl bool skipEnsure bool remove bool + force bool + verbose bool args []string } @@ -37,6 +39,8 @@ 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.BoolVar(&flags.verbose, "verbose", false, "verbose mode") flag.Usage = func() { fmt.Println(`moq [flags] source-dir interface [interface2 [interface3 [...]]]`) @@ -65,6 +69,39 @@ 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) { + if flags.verbose { + fmt.Fprintln(os.Stderr, "Skipping mock generation as the input file hasn't changed since the mock was generated") + } + return nil + } + } + if flags.remove && flags.outFile != "" { if err := os.Remove(flags.outFile); err != nil { if !errors.Is(err, os.ErrNotExist) { @@ -96,6 +133,7 @@ func run(flags userFlags) error { } if flags.outFile == "" { + fmt.Fprintln(os.Stderr, "Mock written.") return nil } @@ -105,5 +143,57 @@ 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 + // 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()) } 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.