diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1827629..aef7b5c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,7 +3,7 @@ name: release on: pull_request: push: - branches: [ master, test ] + branches: [ master, dev ] workflow_dispatch: defaults: @@ -41,7 +41,7 @@ jobs: version=$new_ver release="true" else - version=test-$new_ver\($commit\) + version=dev-$new_ver\($commit\) sed -E "s|v[0-9]+\.[0-9]+\.[0-9]+|$version|" cmd/compiledb/main.go -i fi echo "RELEASE=$release" >> $GITHUB_ENV @@ -83,7 +83,7 @@ jobs: mv compiledb.txz $out/compiledb-darwin-arm64.txz # delete draft - gh release delete test --cleanup-tag -y || true + gh release delete dev --cleanup-tag -y || true ls -la $out @@ -100,7 +100,7 @@ jobs: - name: Update latest uses: ncipollo/release-action@v1 with: - tag: test + tag: dev artifactErrorsFailBuild: true generateReleaseNotes: true name: ${{ env.VERSION }} diff --git a/.justfile b/.justfile index f97646d..6a455a8 100644 --- a/.justfile +++ b/.justfile @@ -2,6 +2,7 @@ set unstable set shell := ["nu", "-c"] set script-interpreter := ["nu"] +[private] default: build [script] diff --git a/cmd/compiledb/main.go b/cmd/compiledb/main.go index 3b3ffce..a546bbe 100644 --- a/cmd/compiledb/main.go +++ b/cmd/compiledb/main.go @@ -12,39 +12,62 @@ import ( var Version string = "v1.5.3" -func init() { - log.SetOutput(os.Stdout) - // log.SetLevel(log.InfoLevel) - log.SetLevel(log.WarnLevel) -} - -func updateConfig(ctx *cli.Context) { +func createConfig(ctx *cli.Context) internal.Config { outputFile := ctx.String("output") - internal.ParseConfig.InputFile = ctx.String("parse") - internal.ParseConfig.BuildDir = ctx.String("build-dir") - internal.ParseConfig.Exclude = ctx.String("exclude") - internal.ParseConfig.Macros = ctx.String("macros") - internal.ParseConfig.RegexCompile = ctx.String("regex-compile") - internal.ParseConfig.RegexFile = ctx.String("regex-file") - internal.ParseConfig.NoBuild = ctx.Bool("no-build") - internal.ParseConfig.CommandStyle = ctx.Bool("command-style") - internal.ParseConfig.NoStrict = ctx.Bool("no-strict") - internal.ParseConfig.FullPath = ctx.Bool("full-path") - - if internal.IsAbsPath(outputFile) == false { + if !internal.IsAbsPath(outputFile) { cwd, _ := os.Getwd() outputFile = filepath.Join(cwd, outputFile) } - internal.ParseConfig.OutputFile = outputFile - if internal.ParseConfig.BuildDir != "" { - err := os.Chdir(internal.ParseConfig.BuildDir) + cfg := internal.Config{ + InputFile: ctx.String("parse"), + OutputFile: outputFile, + BuildDir: ctx.String("build-dir"), + Exclude: ctx.String("exclude"), + Macros: ctx.String("macros"), + RegexCompile: ctx.String("regex-compile"), + RegexFile: ctx.String("regex-file"), + NoBuild: ctx.Bool("no-build"), + CommandStyle: ctx.Bool("command-style"), + NoStrict: ctx.Bool("no-strict"), + FullPath: ctx.Bool("full-path"), + } + + if cfg.BuildDir != "" { + err := os.Chdir(cfg.BuildDir) if err != nil { log.Error(err) } } - log.Debugf("Options: %+v", internal.ParseConfig) + return cfg +} + +type ActionFunc func(t *internal.Tool, ctx *cli.Context) error + +func execute(ctx *cli.Context, fn ActionFunc) error { + logger := log.New() + logger.SetOutput(os.Stdout) + + if ctx.Bool("verbose") { + logger.SetLevel(log.DebugLevel) + logger.Info("compiledb-go start, version:", Version) + } else { + logger.SetLevel(log.WarnLevel) + } + + cfg := createConfig(ctx) + logger.Debugf("Options: %+v", cfg) + + tool := internal.NewTool(cfg, logger) + + err := fn(tool, ctx) + + if tool.StatusCode != 0 { + os.Exit(tool.StatusCode) + } + + return err } func newApp() *cli.App { @@ -73,10 +96,11 @@ COMMANDS: "\n\tWhen no subcommand is used it will parse build log/commands and generates" + "\n\tits corresponding Compilation datAbase.", Action: func(ctx *cli.Context) error { - updateConfig(ctx) - internal.Generate() - log.Debugf("Done") - return nil + return execute(ctx, func(t *internal.Tool, c *cli.Context) error { + t.Generate() + t.Logger.Debugf("Done") + return nil + }) }, Commands: []*cli.Command{ { @@ -84,9 +108,10 @@ COMMANDS: Usage: "Generates compilation database file for an arbitrary GNU Make...", SkipFlagParsing: true, Action: func(ctx *cli.Context) error { - updateConfig(ctx) - internal.MakeWrap(ctx.Args().Slice()) - return nil + return execute(ctx, func(t *internal.Tool, c *cli.Context) error { + t.MakeWrap(ctx.Args().Slice()) + return nil + }) }, }, }, @@ -124,11 +149,6 @@ COMMANDS: Aliases: []string{"v"}, Usage: "Print verbose messages.", DisableDefaultText: true, - Action: func(*cli.Context, bool) error { - log.SetLevel(log.DebugLevel) - log.Info("compiledb-go start, version:", Version) - return nil - }, }, // &cli.BoolFlag{ // Name: "overwrite", @@ -180,8 +200,4 @@ func main() { if err := app.Run(os.Args); err != nil { log.Fatal(err) } - - if internal.StatusCode != 0 { - os.Exit(internal.StatusCode) - } } diff --git a/internal/init.go b/internal/init.go index 2cc6d4c..035a0a0 100644 --- a/internal/init.go +++ b/internal/init.go @@ -4,8 +4,7 @@ import ( "bufio" "encoding/json" "os" - - log "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus" ) type Config struct { @@ -22,10 +21,20 @@ type Config struct { NoStrict bool } -var ParseConfig Config -var StatusCode int = 0 +type Tool struct { + Config Config + Logger *logrus.Logger + StatusCode int +} + +func NewTool(cfg Config, logger *logrus.Logger) *Tool { + return &Tool{ + Config: cfg, + Logger: logger, + } +} -func WriteJSON(filename string, cmdCnt int, data *[]Command) { +func (t *Tool) WriteJSON(filename string, cmdCnt int, data *[]Command) { if cmdCnt == 0 { return } @@ -33,7 +42,7 @@ func WriteJSON(filename string, cmdCnt int, data *[]Command) { // format jsonData, err := json.MarshalIndent(data, "", " ") if err != nil { - log.Fatalf("Error encoding JSON:%v", err) + t.Logger.Fatalf("Error encoding JSON:%v", err) } // write file @@ -42,19 +51,19 @@ func WriteJSON(filename string, cmdCnt int, data *[]Command) { } else { outfile, err := os.Create(filename) if err != nil { - log.Fatalf("create %v failed! err:%v", filename, err) + t.Logger.Fatalf("create %v failed! err:%v", filename, err) } defer outfile.Close() _, err = outfile.Write(jsonData) if err != nil { - log.Fatalf("write %v failed! err:%v", filename, err) + t.Logger.Fatalf("write %v failed! err:%v", filename, err) } - log.Infof("write %d entries to %s", cmdCnt, filename) + t.Logger.Infof("write %d entries to %s", cmdCnt, filename) } } -func Generate() { +func (t *Tool) Generate() { var ( buildLog []string scnner *bufio.Scanner @@ -63,21 +72,21 @@ func Generate() { ) defer file.Close() - if ParseConfig.InputFile != "stdin" { - file, err = os.OpenFile(ParseConfig.InputFile, os.O_RDONLY, 0444) + if t.Config.InputFile != "stdin" { + file, err = os.OpenFile(t.Config.InputFile, os.O_RDONLY, 0444) if err != nil { - log.Fatalf("open %v failed!", ParseConfig.InputFile) + t.Logger.Fatalf("open %v failed!", t.Config.InputFile) } scnner = bufio.NewScanner(file) - log.Debugf("Build from file") + t.Logger.Debugf("Build from file") } else { scnner = bufio.NewScanner(os.Stdin) - log.Debugf("Build from stdin") + t.Logger.Debugf("Build from stdin") } scnner.Buffer(make([]byte, 1024*1024), 1024*1024*100) for scnner.Scan() { buildLog = append(buildLog, scnner.Text()) } - Parse(buildLog) + t.Parse(buildLog) } diff --git a/internal/make_wrap.go b/internal/make_wrap.go index 108f6f2..f38c152 100644 --- a/internal/make_wrap.go +++ b/internal/make_wrap.go @@ -6,13 +6,12 @@ import ( "os/exec" "strings" "sync" - - log "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus" ) var makePath = "make" -func MakeWrap(args []string) { +func (t *Tool) MakeWrap(args []string) { var wg sync.WaitGroup wg.Add(1) @@ -26,25 +25,25 @@ func MakeWrap(args []string) { cmd.Stderr = &stdoutBuf cmd.Run() - level := log.GetLevel() + level := t.Logger.GetLevel() // only print make log - if ParseConfig.NoBuild == false { - log.SetLevel(log.PanicLevel) + if t.Config.NoBuild == false { + t.Logger.SetLevel(logrus.PanicLevel) } buildLog := strings.Split(stdoutBuf.String(), "\n") - Parse(buildLog) + t.Parse(buildLog) // restore log level - if ParseConfig.NoBuild == false { - log.SetLevel(level) + if t.Config.NoBuild == false { + t.Logger.SetLevel(level) } wg.Done() }() - if ParseConfig.NoBuild == false { + if t.Config.NoBuild == false { cmd := exec.Command(makePath, args...) // cmd.Stdout = os.Stdout // cmd.Stderr = os.Stderr @@ -68,8 +67,8 @@ func MakeWrap(args []string) { go TransferPrintScanner(stderr) if err := cmd.Wait(); err != nil { - StatusCode = cmd.ProcessState.ExitCode() - fmt.Printf("make failed! errorCode: %d\n", StatusCode) + t.StatusCode = cmd.ProcessState.ExitCode() + fmt.Printf("make failed! errorCode: %d\n", t.StatusCode) } } diff --git a/internal/parser.go b/internal/parser.go index d5f36c4..45ec0af 100644 --- a/internal/parser.go +++ b/internal/parser.go @@ -9,7 +9,6 @@ import ( "strings" "github.com/mattn/go-shellwords" - log "github.com/sirupsen/logrus" ) type Command struct { @@ -42,11 +41,11 @@ var ( checkingMake = regexp.MustCompile(`^\s?checking whether .*(yes|no)$`) ) -func splitArgs(input string) []string { +func (t *Tool) splitArgs(input string) []string { p := shellwords.NewParser() args, err := p.Parse(input) if err != nil { - log.Warnf("parse failed, input: %s", input) + t.Logger.Warnf("parse failed, input: %s", input) return nil } @@ -57,7 +56,7 @@ func splitArgs(input string) []string { return args } -func splitCommands(commands string) []string { +func (t *Tool) splitCommands(commands string) []string { result := []string{} for _, v := range shRegex.Split(commands, -1) { command := strings.TrimSpace(v) @@ -68,10 +67,10 @@ func splitCommands(commands string) []string { return result } -func processCompileCommand(command string, workingDir string) ([]string, string) { +func (t *Tool) processCompileCommand(command string, workingDir string) ([]string, string) { arguments := []string{} filePath := "" - arguments = splitArgs(command) + arguments = t.splitArgs(command) // check compile word findCompile := false @@ -86,7 +85,7 @@ func processCompileCommand(command string, workingDir string) ([]string, string) return nil, "" } - if ParseConfig.FullPath { + if t.Config.FullPath { compileFullPath := "" compileFullPath = GetBinFullPath(arguments[0]) if compileFullPath != "" { @@ -99,36 +98,36 @@ func processCompileCommand(command string, workingDir string) ([]string, string) if group != nil { filePath = group[1] } else { - log.Debugf("found compile:%s, but not found file, ignore command", arguments[0]) + t.Logger.Debugf("found compile:%s, but not found file, ignore command", arguments[0]) return nil, "" } - if ParseConfig.Exclude != "" { + if t.Config.Exclude != "" { if excludeRegex.MatchString(filePath) { - log.Infof("file %s exclude", filePath) + t.Logger.Infof("file %s exclude", filePath) return nil, "" } } - if ParseConfig.NoStrict == false { + if t.Config.NoStrict == false { fileFullPath := filePath if IsAbsPath(filePath) == false { fileFullPath = path.Join(workingDir, filePath) } if FileExist(fileFullPath) == false { - log.Warnf("file %s not exist", fileFullPath) + t.Logger.Warnf("file %s not exist", fileFullPath) return nil, "" } } - if ParseConfig.Macros != "" { - arguments = append(arguments, splitArgs(ParseConfig.Macros)...) + if t.Config.Macros != "" { + arguments = append(arguments, t.splitArgs(t.Config.Macros)...) } return arguments, filePath } -func Parse(buildLog []string) { +func (t *Tool) Parse(buildLog []string) { var ( err error workingDir = "" @@ -139,37 +138,37 @@ func Parse(buildLog []string) { ) // check workingDir - if ParseConfig.BuildDir != "" { - workingDir = ParseConfig.BuildDir + if t.Config.BuildDir != "" { + workingDir = t.Config.BuildDir } else { - if ParseConfig.InputFile != "stdin" { - absPath, _ := filepath.Abs(ParseConfig.InputFile) + if t.Config.InputFile != "stdin" { + absPath, _ := filepath.Abs(t.Config.InputFile) workingDir = filepath.Dir(absPath) } else { workingDir, _ = os.Getwd() } } workingDir = ConvertPath(workingDir) - log.Infof("workingDir: %s", workingDir) + t.Logger.Infof("workingDir: %s", workingDir) dirStack := []string{workingDir} // init regex - if ParseConfig.Exclude != "" { - excludeRegex, err = regexp.Compile(ParseConfig.Exclude) + if t.Config.Exclude != "" { + excludeRegex, err = regexp.Compile(t.Config.Exclude) if err != nil { - log.Fatalln("invalid exclude regex:", err) + t.Logger.Fatalln("invalid exclude regex:", err) return } } - compileRegex, err = regexp.Compile(ParseConfig.RegexCompile) + compileRegex, err = regexp.Compile(t.Config.RegexCompile) if err != nil { - log.Fatalln("invalid compile_regex:", err) + t.Logger.Fatalln("invalid compile_regex:", err) return } - fileRegex, err = regexp.Compile(ParseConfig.RegexFile) + fileRegex, err = regexp.Compile(t.Config.RegexFile) if err != nil { - log.Fatalln("invalid file_regex:", err) + t.Logger.Fatalln("invalid file_regex:", err) return } @@ -178,14 +177,14 @@ func Parse(buildLog []string) { if backupWorkingDir != "" { workingDir = backupWorkingDir backupWorkingDir = "" - log.Infof("Restore workingDir: %s", workingDir) + t.Logger.Infof("Restore workingDir: %s", workingDir) } line = strings.TrimSpace(line) if line == "" { continue } - log.Debug("New command:", line) + t.Logger.Debug("New command:", line) // Parse directory that make entering/leaving {{{ if makeEnterDir.MatchString(line) { @@ -194,7 +193,7 @@ func Parse(buildLog []string) { enterDir := group[1] dirStack = append([]string{ConvertPath(enterDir)}, dirStack...) workingDir = dirStack[0] - log.Infof("entering change workingDir: %s", workingDir) + t.Logger.Infof("entering change workingDir: %s", workingDir) } continue } else if makeLeaveDir.MatchString(line) { @@ -203,7 +202,7 @@ func Parse(buildLog []string) { if len(dirStack) > 0 { workingDir = dirStack[0] } - log.Infof("leaving change workingDir: %s", workingDir) + t.Logger.Infof("leaving change workingDir: %s", workingDir) } continue } @@ -216,7 +215,7 @@ func Parse(buildLog []string) { if dirStack[0] != "." { workingDir = dirStack[0] } - log.Infof("make cmd change workingDir: %s", workingDir) + t.Logger.Infof("make cmd change workingDir: %s", workingDir) } } @@ -232,7 +231,7 @@ func Parse(buildLog []string) { nestedCmd := matchGroup[1] out, err := exec.Command("sh", "-c", nestedCmd).Output() if err != nil { - log.Error("Error executing nested command:", err) + t.Logger.Error("Error executing nested command:", err) out = nil } // update line @@ -245,8 +244,8 @@ func Parse(buildLog []string) { // not escape \", json.MarshalIndent will do it line = strings.ReplaceAll(line, `\"`, `"`) - for _, v := range splitCommands(line) { - // log.Error(v) + for _, v := range t.splitCommands(line) { + // t.Logger.Error(v) // Parse cd xx {{{ matchGroup = cdRegex.FindStringSubmatch(v) @@ -258,20 +257,20 @@ func Parse(buildLog []string) { } else { workingDir = cdPath } - log.Infof("Temporarily change workingDir: %s", workingDir) + t.Logger.Infof("Temporarily change workingDir: %s", workingDir) continue } // Parse compile command {{{ if compileRegex.MatchString(v) { - arguments, filePath := processCompileCommand(v, workingDir) + arguments, filePath := t.processCompileCommand(v, workingDir) if filePath == "" { continue } // append to result command := strings.Join(arguments, " ") - if ParseConfig.CommandStyle { + if t.Config.CommandStyle { result = append(result, Command{ Directory: workingDir, Command: command, @@ -284,12 +283,12 @@ func Parse(buildLog []string) { File: filePath, }) } - log.Infof("Adding command %d: %s", cmdCnt, command) + t.Logger.Infof("Adding command %d: %s", cmdCnt, command) cmdCnt += 1 } } } } - WriteJSON(ParseConfig.OutputFile, cmdCnt, &result) + t.WriteJSON(t.Config.OutputFile, cmdCnt, &result) }