From 24773e55aa5e64fb2dfef021829cbf1bf9888d39 Mon Sep 17 00:00:00 2001 From: Florian Vogt Date: Wed, 6 Dec 2023 00:22:29 +0100 Subject: [PATCH] Fix: #3 --- .github/workflows/release.yml | 18 ++-- commands/extractor.go | 138 ++++++++++++++++++++++++++++ commands/root.go | 168 ++++++---------------------------- 3 files changed, 179 insertions(+), 145 deletions(-) create mode 100644 commands/extractor.go diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e7b5940..c375e81 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,16 +12,22 @@ jobs: - name: Checkout repository uses: actions/checkout@v3 - name: Install Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: - go-version: '>=1.18.0' + go-version: '>=1.19.0' - name: Build binaries run: | - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o "xspreak-$(git describe --tags)-linux-amd64" - CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o "xspreak-$(git describe --tags)-darwin-amd64" - CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o "xspreak-$(git describe --tags)-windows-amd64.exe" + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \ + -ldflags="-X 'github.com/vorlif/xspreak/commands.Version=$(git describe --tags)'" \ + -o "xspreak-$(git describe --tags)-linux-amd64" + CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build \ + -ldflags="-X 'github.com/vorlif/xspreak/commands.Version=$(git describe --tags)'" \ + -o "xspreak-$(git describe --tags)-darwin-amd64" + CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build \ + -ldflags="-X 'github.com/vorlif/xspreak/commands.Version=$(git describe --tags)'" \ + -o "xspreak-$(git describe --tags)-windows-amd64.exe" - name: Upload release artifacts - uses: actions/github-script@v3 + uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/commands/extractor.go b/commands/extractor.go new file mode 100644 index 0000000..bbb8e84 --- /dev/null +++ b/commands/extractor.go @@ -0,0 +1,138 @@ +package commands + +import ( + "context" + "fmt" + "os" + "path/filepath" + "time" + + log "github.com/sirupsen/logrus" + + "github.com/vorlif/xspreak/config" + "github.com/vorlif/xspreak/encoder" + "github.com/vorlif/xspreak/extract" + "github.com/vorlif/xspreak/extract/extractors" + "github.com/vorlif/xspreak/goextractors" + "github.com/vorlif/xspreak/result" + "github.com/vorlif/xspreak/tmplextractors" + "github.com/vorlif/xspreak/util" +) + +type Extractor struct { + cfg *config.Config + log *log.Entry + + contextLoader *extract.ContextLoader +} + +func NewExtractor() *Extractor { + return &Extractor{ + cfg: extractCfg, + log: log.WithField("service", "extractor"), + contextLoader: extract.NewContextLoader(extractCfg), + } +} + +func (e *Extractor) extract() { + ctx, cancel := context.WithTimeout(context.Background(), e.cfg.Timeout) + defer cancel() + + extractedIssues, errE := e.runExtraction(ctx) + if errE != nil { + e.log.Fatalf("Running error: %s", errE) + } + + domainIssues := make(map[string][]result.Issue) + start := time.Now() + for _, iss := range extractedIssues { + if _, ok := domainIssues[iss.Domain]; !ok { + domainIssues[iss.Domain] = []result.Issue{iss} + } else { + domainIssues[iss.Domain] = append(domainIssues[iss.Domain], iss) + } + } + log.Debugf("sort extractions took %s", time.Since(start)) + + if len(extractedIssues) == 0 { + domainIssues[""] = make([]result.Issue, 0) + log.Println("No Strings found") + } + + e.saveDomains(domainIssues) +} + +func (e *Extractor) runExtraction(ctx context.Context) ([]result.Issue, error) { + util.TrackTime(time.Now(), "run all extractors") + extractorsToRun := []extractors.Extractor{ + goextractors.NewDefinitionExtractor(), + goextractors.NewCommentsExtractor(), + goextractors.NewFuncCallExtractor(), + goextractors.NewFuncReturnExtractor(), + goextractors.NewGlobalAssignExtractor(), + goextractors.NewSliceDefExtractor(), + goextractors.NewMapsDefExtractor(), + goextractors.NewStructDefExtractor(), + goextractors.NewVariablesExtractor(), + goextractors.NewErrorExtractor(), + goextractors.NewInlineTemplateExtractor(), + tmplextractors.NewCommandExtractor(), + } + + extractCtx, err := e.contextLoader.Load(ctx) + if err != nil { + return nil, fmt.Errorf("context loading failed: %w", err) + } + + runner, err := extract.NewRunner(e.cfg, extractCtx.Packages) + if err != nil { + return nil, err + } + + issues, err := runner.Run(ctx, extractCtx, extractorsToRun) + if err != nil { + return nil, err + } + + return issues, nil +} + +func (e *Extractor) saveDomains(domains map[string][]result.Issue) { + util.TrackTime(time.Now(), "save files") + for domainName, issues := range domains { + var outputFile string + if domainName == "" { + outputFile = filepath.Join(e.cfg.OutputDir, e.cfg.OutputFile) + } else { + outputFile = filepath.Join(e.cfg.OutputDir, domainName+"."+e.cfg.ExtractFormat) + } + + outputDir := filepath.Dir(outputFile) + if _, err := os.Stat(outputDir); os.IsNotExist(err) { + log.Printf("Output folder does not exist, trying to create it: %s\n", outputDir) + if errC := os.MkdirAll(outputDir, os.ModePerm); errC != nil { + log.Fatalf("Output folder does not exist and could not be created: %s", errC) + } + } + + dst, err := os.Create(outputFile) + if err != nil { + e.log.WithError(err).Fatal("Output file could not be created") + } + defer dst.Close() + + var enc encoder.Encoder + if e.cfg.ExtractFormat == config.ExtractFormatPot { + enc = encoder.NewPotEncoder(e.cfg, dst) + } else { + enc = encoder.NewJSONEncoder(dst, " ") + } + + if errEnc := enc.Encode(issues); errEnc != nil { + e.log.WithError(errEnc).Fatal("Output file could not be written") + } + + _ = dst.Close() + log.Printf("File written: %s\n", outputFile) + } +} diff --git a/commands/root.go b/commands/root.go index 124115c..5eb25b5 100644 --- a/commands/root.go +++ b/commands/root.go @@ -1,27 +1,17 @@ package commands import ( - "context" - "fmt" - "os" - "path/filepath" - "time" + "runtime/debug" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/vorlif/xspreak/config" - "github.com/vorlif/xspreak/encoder" - "github.com/vorlif/xspreak/extract" - "github.com/vorlif/xspreak/extract/extractors" - "github.com/vorlif/xspreak/goextractors" - "github.com/vorlif/xspreak/result" "github.com/vorlif/xspreak/tmpl" - "github.com/vorlif/xspreak/tmplextractors" - "github.com/vorlif/xspreak/util" ) -var Version = "v0.9.0" +// Version is initialized via ldflags or debug.BuildInfo. +var Version = "" var ( extractCfg = config.NewDefault() @@ -40,6 +30,8 @@ func Execute() error { } func init() { + initVersionNumber() + def := config.NewDefault() rootCmd.PersistentFlags().BoolVarP(&extractCfg.IsVerbose, "verbose", "V", def.IsVerbose, "increase verbosity level") @@ -72,6 +64,30 @@ func init() { fs.StringVar(&extractCfg.BugsAddress, "msgid-bugs-address", def.BugsAddress, "Set report address for msgid bugs") } +func initVersionNumber() { + // If already set via ldflags, the value is retained. + if Version != "" { + return + } + + info, available := debug.ReadBuildInfo() + if available { + Version = info.Main.Version + } else { + Version = "dev" + } + + rootCmd.Version = Version +} + +func extractCmdF(cmd *cobra.Command, args []string) { + validateExtractConfig(cmd) + extractCfg.Args = args + + extractor := NewExtractor() + extractor.extract() +} + func validateExtractConfig(cmd *cobra.Command) { fs := cmd.Flags() if keywordPrefix, errP := fs.GetString("template-prefix"); errP != nil { @@ -102,129 +118,3 @@ func validateExtractConfig(cmd *cobra.Command) { log.Debug("Starting execution...") } - -func extractCmdF(cmd *cobra.Command, args []string) { - validateExtractConfig(cmd) - extractCfg.Args = args - - extractor := NewExtractor() - extractor.extract() -} - -type Extractor struct { - cfg *config.Config - log *log.Entry - - contextLoader *extract.ContextLoader -} - -func NewExtractor() *Extractor { - return &Extractor{ - cfg: extractCfg, - log: log.WithField("service", "extractor"), - contextLoader: extract.NewContextLoader(extractCfg), - } -} - -func (e *Extractor) extract() { - ctx, cancel := context.WithTimeout(context.Background(), e.cfg.Timeout) - defer cancel() - - extractedIssues, errE := e.runExtraction(ctx) - if errE != nil { - e.log.Fatalf("Running error: %s", errE) - } - - domainIssues := make(map[string][]result.Issue) - start := time.Now() - for _, iss := range extractedIssues { - if _, ok := domainIssues[iss.Domain]; !ok { - domainIssues[iss.Domain] = []result.Issue{iss} - } else { - domainIssues[iss.Domain] = append(domainIssues[iss.Domain], iss) - } - } - log.Debugf("sort extractions took %s", time.Since(start)) - - if len(extractedIssues) == 0 { - domainIssues[""] = make([]result.Issue, 0) - log.Println("No Strings found") - } - - e.saveDomains(domainIssues) -} - -func (e *Extractor) runExtraction(ctx context.Context) ([]result.Issue, error) { - util.TrackTime(time.Now(), "run all extractors") - extractorsToRun := []extractors.Extractor{ - goextractors.NewDefinitionExtractor(), - goextractors.NewCommentsExtractor(), - goextractors.NewFuncCallExtractor(), - goextractors.NewFuncReturnExtractor(), - goextractors.NewGlobalAssignExtractor(), - goextractors.NewSliceDefExtractor(), - goextractors.NewMapsDefExtractor(), - goextractors.NewStructDefExtractor(), - goextractors.NewVariablesExtractor(), - goextractors.NewErrorExtractor(), - goextractors.NewInlineTemplateExtractor(), - tmplextractors.NewCommandExtractor(), - } - - extractCtx, err := e.contextLoader.Load(ctx) - if err != nil { - return nil, fmt.Errorf("context loading failed: %w", err) - } - - runner, err := extract.NewRunner(e.cfg, extractCtx.Packages) - if err != nil { - return nil, err - } - - issues, err := runner.Run(ctx, extractCtx, extractorsToRun) - if err != nil { - return nil, err - } - - return issues, nil -} - -func (e *Extractor) saveDomains(domains map[string][]result.Issue) { - util.TrackTime(time.Now(), "save files") - for domainName, issues := range domains { - var outputFile string - if domainName == "" { - outputFile = filepath.Join(e.cfg.OutputDir, e.cfg.OutputFile) - } else { - outputFile = filepath.Join(e.cfg.OutputDir, domainName+"."+e.cfg.ExtractFormat) - } - - outputDir := filepath.Dir(outputFile) - if _, err := os.Stat(outputDir); os.IsNotExist(err) { - log.Printf("Output folder does not exist, trying to create it: %s\n", outputDir) - if errC := os.MkdirAll(outputDir, os.ModePerm); errC != nil { - log.Fatalf("Output folder does not exist and could not be created: %s", errC) - } - } - - dst, err := os.Create(outputFile) - if err != nil { - e.log.WithError(err).Fatal("Output file could not be created") - } - defer dst.Close() - - var enc encoder.Encoder - if e.cfg.ExtractFormat == config.ExtractFormatPot { - enc = encoder.NewPotEncoder(e.cfg, dst) - } else { - enc = encoder.NewJSONEncoder(dst, " ") - } - - if errEnc := enc.Encode(issues); errEnc != nil { - e.log.WithError(errEnc).Fatal("Output file could not be written") - } - - _ = dst.Close() - log.Printf("File written: %s\n", outputFile) - } -}