Skip to content

Commit

Permalink
refactor: move package filtering to app implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
michenriksen committed Oct 21, 2023
1 parent e86418d commit 6080de9
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 102 deletions.
4 changes: 4 additions & 0 deletions cmd/pkgdmp/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ func main() {
parsed := make([]*pkgdmp.Package, 0, len(unparsed))

for _, uPkg := range unparsed {
if !cfg.IncludePackage(uPkg.Name) {
continue
}

pkg, err := pkgParser.Package(doc.New(uPkg, "", doc.AllDecls))
if err != nil {
log.Fatal(err)
Expand Down
43 changes: 0 additions & 43 deletions filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,49 +208,6 @@ func (f *filterMatchingIdents) String() string {
return fmt.Sprintf("filterMatchingIdents(action=%s,pattern=%s)", f.action, f.pattern)
}

// FilterPackages creates a filter function that determines whether to include
// or exclude packages matching provided names.
func FilterPackages(action FilterAction, names ...string) SymbolFilter {
pkgMap := make(map[string]struct{}, len(names))

for _, n := range names {
pkgMap[n] = struct{}{}
}

return &filterPackages{pkgMap: pkgMap, action: action}
}

type filterPackages struct {
pkgMap map[string]struct{}
action FilterAction
}

func (f *filterPackages) Include(s Symbol) bool {
if s.SymbolType() != SymbolPackage {
return true
}

_, ok := f.pkgMap[s.Ident()]

if f.action == Include {
return ok
}

return !ok
}

func (f *filterPackages) String() string {
names := make([]string, 0, len(f.pkgMap))

for n := range f.pkgMap {
names = append(names, n)
}

sort.Strings(names)

return fmt.Sprintf("filterPackages(action=%s,names=%s)", f.action, strings.Join(names, ","))
}

func isUnfilterable(s Symbol) bool {
if _, ok := unfilterableMap[s.SymbolType()]; ok {
return true
Expand Down
40 changes: 0 additions & 40 deletions filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,46 +179,6 @@ func TestFilterMatchingIdents(t *testing.T) {
}
}

func TestFilterPackages(t *testing.T) {
pkg := newSymbol(t, "mypackage", pkgdmp.SymbolPackage)

tt := []struct {
s pkgdmp.Symbol
names []string
action pkgdmp.FilterAction
want bool
}{
{pkg, []string{"otherpackage", pkg.Ident()}, pkgdmp.Include, true},
{pkg, []string{pkg.Ident(), "otherpackage"}, pkgdmp.Exclude, false},
{pkg, []string{"somepackage", "otherpackage"}, pkgdmp.Include, false},
{pkg, []string{"somepackage", "otherpackage"}, pkgdmp.Exclude, true},
{newSymbol(t, "test", pkgdmp.SymbolStructType), []string{"test"}, pkgdmp.Exclude, true},
{newSymbol(t, "test", pkgdmp.SymbolFunc), []string{"mypackage"}, pkgdmp.Include, true},
}

for _, tc := range tt {
tc := tc

name := fmt.Sprintf("returns %t for %s with action %s and names %s",
tc.want, tc.s, tc.action, strings.Join(tc.names, ","),
)

t.Run(name, func(t *testing.T) {
t.Parallel()

f := pkgdmp.FilterPackages(tc.action, tc.names...)

if f.Include(tc.s) == tc.want {
return
}

t.Errorf("expected FilterPackages(%v, %s) to return %t for %s",
tc.action, strings.Join(tc.names, ", "), tc.want, tc.s,
)
})
}
}

type stubSymbol struct {
ident string
st pkgdmp.SymbolType
Expand Down
73 changes: 54 additions & 19 deletions internal/cli/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,21 +54,40 @@ var flagSet *flag.FlagSet

// Config represents CLI configuration from flags.
type Config struct {
Matching string
ExcludeMatching string
Only string
Exclude string
OnlyPackages string
onlyPackages map[string]struct{}
excludePackages map[string]struct{}
ExcludePackages string
Only string
ExcludeMatching string
Theme string
Matching string
OnlyPackages string
Exclude string
Dirs []string `env:"skip"`
NoDocs bool
JSON bool
NoEnv bool `env:"skip"`
NoHighlight bool
FullDocs bool
Unexported bool
Version bool `env:"skip"`
NoEnv bool `env:"skip"`
JSON bool
}

// IncludePackage returns true if package with provided name should be included
// in the report according to configuration, or false otherwise.
func (c *Config) IncludePackage(name string) bool {
if len(c.onlyPackages) != 0 {
_, ok := c.onlyPackages[name]
return ok
}

if len(c.excludePackages) != 0 {
if _, ok := c.excludePackages[name]; ok {
return false
}
}

return true
}

// ParseFlags parses command line arguments as flags and returns a CLI
Expand Down Expand Up @@ -105,6 +124,34 @@ func ParseFlags(args []string, output io.Writer) (*Config, int, error) {

envConfig(cfg)

if cfg.OnlyPackages != "" {
names := strings.Split(cfg.OnlyPackages, ",")
cfg.onlyPackages = make(map[string]struct{}, len(names))

for _, name := range names {
name = strings.TrimSpace(name)
if name == "" {
continue
}

cfg.onlyPackages[name] = struct{}{}
}
}

if cfg.ExcludePackages != "" {
names := strings.Split(cfg.ExcludePackages, ",")
cfg.excludePackages = make(map[string]struct{}, len(names))

for _, name := range names {
name = strings.TrimSpace(name)
if name == "" {
continue
}

cfg.excludePackages[name] = struct{}{}
}
}

return cfg, 0, nil
}

Expand Down Expand Up @@ -175,18 +222,6 @@ func filtersFromCfg(cfg *Config) ([]pkgdmp.SymbolFilter, error) {
filters = append(filters, pkgdmp.FilterMatchingIdents(pkgdmp.Exclude, p))
}

if cfg.ExcludePackages != "" {
names := strToSlice(cfg.ExcludePackages)

filters = append(filters, pkgdmp.FilterPackages(pkgdmp.Exclude, names...))
}

if cfg.OnlyPackages != "" {
names := strToSlice(cfg.ExcludePackages)

filters = append(filters, pkgdmp.FilterPackages(pkgdmp.Include, names...))
}

return filters, nil
}

Expand Down
41 changes: 41 additions & 0 deletions internal/cli/flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package cli_test
import (
"errors"
"flag"
"fmt"
"io"
"reflect"
"regexp"
"strings"
"testing"

"github.com/michenriksen/pkgdmp/internal/cli"
Expand Down Expand Up @@ -78,6 +80,45 @@ func TestParseFlags(t *testing.T) {
}
}

func TestParseFlags_PackageFiltering(t *testing.T) {
tt := []struct {
args []string
pkg string
want bool
}{
{nil, "mypackage", true},
{[]string{"-only-packages", "mypackage"}, "mypackage", true},
{[]string{"-only-packages", "otherpackage,mypackage"}, "mypackage", true},
{[]string{"-only-packages", "otherpackage"}, "mypackage", false},
{[]string{"-exclude-packages", "otherpackage"}, "mypackage", true},
{[]string{"-exclude-packages", "mypackage"}, "mypackage", false},
{[]string{"-exclude-packages", "otherpackage,mypackage"}, "mypackage", false},
}

for _, tc := range tt {
name := fmt.Sprintf("returns %t with args %s", tc.want, strings.Join(tc.args, " "))

t.Run(name, func(t *testing.T) {
args := append(tc.args, "directory")

cfg, exitCode, err := cli.ParseFlags(args, io.Discard)
if err != nil {
t.Fatalf("did not expect error, but got: %v", err)
}

if exitCode != 0 {
t.Fatalf("expected exit code 0, but got %d", exitCode)
}

if cfg.IncludePackage(tc.pkg) == tc.want {
return
}

t.Fatalf("expected cfg.IncludePackage(%q) to return %t", tc.pkg, tc.want)
})
}
}

func TestParserOptsFromCfg(t *testing.T) {
tt := []struct {
name string
Expand Down

0 comments on commit 6080de9

Please sign in to comment.