Open wangming1993 opened 7 years ago
package main import ( "bufio" "encoding/json" "flag" "fmt" "os" "path/filepath" "regexp" "strings" ) var lookup = flag.String("lookup", "", "The root path") var writen = flag.Bool("w", false, "Whether to write to file") var help = flag.Bool("h", false, "List command") var reporter *Reporter func init() { flag.Parse() reporter = &Reporter{ modules: make(map[string]*module), } } func main() { if *help || *lookup == "" { usage() return } filepath.Walk(*lookup, osWalk) var content string content = reporter.Markdown() if *writen { file, err := os.Create("output.md") if err != nil { fmt.Println(err) return } file.WriteString(content) } else { os.Stdout.WriteString(content) } } func usage() { cmd := ` find replaced rpc code in specified directory: -lookup The root directory of php code -w Write to file if ture, default output in console -h The usage ` fmt.Println(cmd) } func osWalk(path string, info os.FileInfo, err error) error { if err != nil { fmt.Println("------------------------------") fmt.Println(err) fmt.Println("------------------------------") } if info.IsDir() || !isController(path) { return nil } controller := initializeController(path, info.Name()) addController(controller) return nil } func isController(file string) bool { controllerFolder := strings.Contains(file, "controllers") if !controllerFolder { return false } return strings.HasSuffix(file, "Controller.php") } func initializeController(file, name string) *controller { lines := readFile(file) controller := &controller{ name: name, file: file, lines: lines, module: getModuleName(file), } max := len(lines) i := 0 for { if i >= max { break } line := lines[i] if isAction(line) { action, step := controller.findAction(i, getActionName(line)) if action != nil { controller.actions = append(controller.actions, action) } i = step } else { i++ } serviceUseName := findServiceUseName(line) if serviceUseName != "" { controller.serviceUserName = append(controller.serviceUserName, serviceUseName) } } return controller } func isAction(line string) bool { pattern, _ := regexp.Compile("^\\s*public\\s+function\\s+action") return pattern.MatchString(line) } func getActionName(line string) string { pattern := "^\\s*public\\s+function\\s+action([A-Za-z]+)\\s?" c, _ := regexp.Compile(pattern) matches := c.FindStringSubmatch(line) if len(matches) < 2 { return "" } return matches[1] } func readFile(file string) []string { f, err := os.Open(file) if err != nil { panic(err) } defer f.Close() var lines []string scanner := bufio.NewScanner(f) for scanner.Scan() { lines = append(lines, scanner.Text()) } if err := scanner.Err(); err != nil { fmt.Fprintln(os.Stderr, err) } return lines } type action struct { controller *controller name string fullName string start int end int needMigrate bool } func (a *action) hasRpcMigrate() bool { i := a.start for { if i >= a.end { return false } line := a.controller.lines[i] if hasServiceCall(line, a.controller.serviceUserName) { return true } i++ } return false } type controller struct { file string module string name string lines []string actions []*action serviceUserName []string } func (c *controller) getMigratedActionNames() []string { var actionNames []string for _, a := range c.actions { if a.hasRpcMigrate() { actionNames = append(actionNames, a.fullName) } } return actionNames } func (c *controller) findAction(start int, name string) (*action, int) { max := len(c.lines) i := start var leftBrace, rightBrace int for { if i >= max { return nil, i } line := c.lines[i] leftBrace += strings.Count(line, "{") rightBrace += strings.Count(line, "}") if leftBrace > 0 && leftBrace == rightBrace { action := &action{ controller: c, name: name, fullName: fmt.Sprintf("action%s", name), start: start, end: i, } return action, i } i++ } return nil, i } func findServiceUseName(line string) string { pattern := "^\\s*use\\s+backend\\\\modules\\\\[a-zA-Z]+\\\\services\\\\([a-zA-Z]+){1}(\\s?as\\s*([A-Za-z]+))?" c, _ := regexp.Compile(pattern) matches := c.FindStringSubmatch(line) if len(matches) < 2 { return "" } useName := matches[1] max := len(matches) if matches[max-1] != "" { useName = matches[max-1] } return useName } func hasServiceCall(line string, serviceName []string) bool { var contains bool for _, service := range serviceName { contains = contains || strings.Contains(line, service) } return contains } func getModuleName(path string) string { pattern := "backend/modules/([A-Za-z]+)/controllers" c, _ := regexp.Compile(pattern) matches := c.FindStringSubmatch(path) if len(matches) < 2 { return "" } return matches[1] } func toJson(v interface{}) string { buf, err := json.MarshalIndent(v, "", "\t") if err != nil { panic(err) } return string(buf) } type module struct { name string controllers []*controller } type Reporter struct { modules map[string]*module } func (r *Reporter) Markdown() string { var md string for _, m := range r.modules { var hasMigratedCode bool moduleMD := fmt.Sprintf("\n# %s \n", m.name) for _, c := range m.controllers { actionNames := c.getMigratedActionNames() if len(actionNames) > 0 { hasMigratedCode = true moduleMD += fmt.Sprintf("\n## %s \n", c.name) moduleMD += fmt.Sprintf("\n```php\n%s\n```\n", toJson(actionNames)) } } if hasMigratedCode { md += moduleMD } } return md } func addController(c *controller) { if module, ok := reporter.modules[c.module]; ok { module.controllers = append(module.controllers, c) return } m := &module{ name: c.module, controllers: []*controller{c}, } reporter.modules[c.module] = m }