Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #3 - Try to set the version number automatically #4

Merged
merged 1 commit into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
}
}