Skip to content

Commit

Permalink
Fix: #3
Browse files Browse the repository at this point in the history
  • Loading branch information
vorlif committed Dec 5, 2023
1 parent 15a5c7e commit 24773e5
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 145 deletions.
18 changes: 12 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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: |
Expand Down
138 changes: 138 additions & 0 deletions commands/extractor.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
168 changes: 29 additions & 139 deletions commands/root.go
Original file line number Diff line number Diff line change
@@ -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()
Expand All @@ -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")
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
}
}

0 comments on commit 24773e5

Please sign in to comment.