github.com/joomcode/pegomock@v2.9.2-0.20220414140958-14f53b6b2a6c+incompatible/pegomock/watch/watch.go (about) 1 // Copyright 2016 Peter Goetz 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package watch 16 17 import ( 18 "fmt" 19 "io/ioutil" 20 "os" 21 "path/filepath" 22 "regexp" 23 "strings" 24 25 "gopkg.in/alecthomas/kingpin.v2" 26 27 "github.com/petergtz/pegomock/pegomock/filehandling" 28 "github.com/petergtz/pegomock/pegomock/util" 29 ) 30 31 const wellKnownInterfaceListFile = "interfaces_to_mock" 32 33 var join = strings.Join 34 35 type MockFileUpdater struct { 36 recursive bool 37 targetPaths []string 38 lastErrors map[string]string 39 } 40 41 func NewMockFileUpdater(targetPaths []string, recursive bool) *MockFileUpdater { 42 return &MockFileUpdater{ 43 targetPaths: targetPaths, 44 recursive: recursive, 45 lastErrors: make(map[string]string), 46 } 47 } 48 49 func (updater *MockFileUpdater) Update() { 50 for _, targetPath := range updater.targetPaths { 51 if updater.recursive { 52 filepath.Walk(targetPath, func(path string, info os.FileInfo, err error) error { 53 if err == nil && info.IsDir() { 54 util.WithinWorkingDir(path, updater.updateMockFiles) 55 } 56 return nil 57 }) 58 } else { 59 util.WithinWorkingDir(targetPath, updater.updateMockFiles) 60 } 61 } 62 } 63 64 func (updater *MockFileUpdater) updateMockFiles(targetPath string) { 65 if _, err := os.Stat(wellKnownInterfaceListFile); os.IsNotExist(err) { 66 return 67 } 68 for _, lineParts := range linesIn(wellKnownInterfaceListFile) { 69 lineCmd := kingpin.New("What should go in here", "And what should go in here") 70 destination := lineCmd.Flag("output", "Output file; defaults to mock_<interface>_test.go.").Short('o').String() 71 nameOut := lineCmd.Flag("name", "Struct name of the generated code; defaults to the name of the interface prefixed with Mock").Default(filepath.Base(targetPath) + "_test").String() 72 packageOut := lineCmd.Flag("package", "Package of the generated code; defaults to the package from which pegomock was executed suffixed with _test").Default(filepath.Base(targetPath) + "_test").String() 73 selfPackage := lineCmd.Flag("self_package", "If set, the package this mock will be part of.").String() 74 lineArgs := lineCmd.Arg("args", "A (optional) Go package path + space-separated interface or a .go file").Required().Strings() 75 76 _, parseErr := lineCmd.Parse(lineParts) 77 if parseErr != nil { 78 fmt.Println("Error while trying to generate mock for line", join(lineParts, " "), ":", parseErr) 79 continue 80 } 81 defer func() { 82 err := recover() 83 if err != nil { 84 if updater.lastErrors[errorKey(*lineArgs)] != fmt.Sprint(err) { 85 fmt.Println("Error while trying to generate mock for", join(lineParts, " "), ":", err) 86 updater.lastErrors[errorKey(*lineArgs)] = fmt.Sprint(err) 87 } 88 } 89 }() 90 91 util.PanicOnError(util.ValidateArgs(*lineArgs)) 92 sourceArgs, err := util.SourceArgs(*lineArgs) 93 util.PanicOnError(err) 94 95 generatedMockSourceCode, _ := filehandling.GenerateMockSourceCode(sourceArgs, *nameOut, *packageOut, *selfPackage, false, os.Stdout, false) 96 mockFilePath := filehandling.OutputFilePath(sourceArgs, ".", *destination) 97 hasChanged := util.WriteFileIfChanged(mockFilePath, generatedMockSourceCode) 98 99 if hasChanged || updater.lastErrors[errorKey(*lineArgs)] != "" { 100 fmt.Println("(Re)generated mock for", errorKey(*lineArgs), "in", mockFilePath) 101 } 102 delete(updater.lastErrors, errorKey(*lineArgs)) 103 } 104 } 105 106 func errorKey(args []string) string { 107 return join(args, "_") 108 } 109 110 func CreateWellKnownInterfaceListFilesIfNecessary(targetPaths []string) { 111 for _, targetPath := range targetPaths { 112 CreateWellKnownInterfaceListFileIfNecessary(targetPath) 113 } 114 } 115 116 func CreateWellKnownInterfaceListFileIfNecessary(targetPath string) { 117 file, err := os.OpenFile(filepath.Join(targetPath, wellKnownInterfaceListFile), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666) 118 if err != nil { 119 if os.IsExist(err) { 120 return 121 } 122 panic(err) 123 } 124 defer file.Close() 125 file.WriteString("### List here all interfaces you would like to mock. One per line.\n") 126 } 127 128 func linesIn(file string) (result [][]string) { 129 content, err := ioutil.ReadFile(file) 130 util.PanicOnError(err) 131 for _, line := range strings.Split(string(content), "\n") { 132 if strings.HasPrefix(strings.TrimSpace(line), "#") || line == "" { 133 continue 134 } 135 parts := regexp.MustCompile(`\s`).Split(line, -1) 136 // TODO: do validation here like in main 137 result = append(result, parts) 138 } 139 return 140 }