Support caller-supplied and filtered license corpora - #64
abhinavgautam01 wants to merge 2 commits into
Conversation
andrew
left a comment
There was a problem hiding this comment.
The direction matches what #59 proposed, and the implementation is in the right place: filtering runs before the vocabulary is built, so vocabulary, token IDs, stopword remapping and the automaton are all rebuilt over the reduced rule set, and the default all mask leaves generation byte-identical. corpus.Read already validates framing, counts, sortedness and token/stopword ranges, so exposing it through a public constructor does not open a decoding hole. A few things before merge.
Blocking:
matcher.go:216and the README both state that a program using onlyNewFromReadercan omit the embedded corpus from its binary. That is the point of the change and the one claim with no test behind it. It also regresses invisibly: the day some shared code path callscorpus.Load, every reader-only caller silently gets the 12.7 MB back and no existing test notices. Add a guard that builds two fixture programs int.TempDir()against the module with areplacedirective, one callingNewand one calling onlyNewFromReader, and asserts a multi-megabyte size delta (skip when no Go toolchain is available).internal/corpus/embed_test.goalready budgets the embed size, so a size assertion fits the existing shape.
Non-blocking:
reader_test.gocovers code inmatcher.go, andcmd/corpusgen/filter_test.gocovers code inmain.go. Test files here pair with their source file (scan.go/scan_test.go,spdx.go/spdx_test.go,filter.go/filter_test.go). Either moveNewFromReaderandconfigureMatcherinto a newreader.go, or fold the tests intomatcher_test.goandcmd/corpusgen/main_test.go.cmd/corpusgen/main.go:166: the comment about a zero mask describes the filter at line 216 rather than the parser it is attached to, and as a doc comment it should start with the function name. Move it to theif ruleFlags != 0block.
One note on the numbers: at 10.35 MB for text-only, flag filtering does not get close to the 2.9 MB figure in #59, because the per-rule token arrays for the 6,959 license texts are the bulk of the corpus rather than the auxiliary rules. Reaching that size needs a different axis, so #59 should stay open after this lands.
|
Thanks, added the binary-size guard and verified it fails when corpus.Load is accidentally retained. Also aligned the source/test files, moved the zero-mask comment and removed the closing reference to #59. |
Related to #59. Further corpus size reductions remain follow-up work; this PR does not close the issue.
Summary
Applications currently must load the full embedded ScanCode corpus through
licenses.New(). This adds the entire corpus to their binaries even when they only need a subset of license rules.This change adds
NewFromReader(io.Reader, ...Option)and corpus generation filtering, allowing applications to supply and embed their own reduced corpus.Changes
NewFromReader, supporting the same options asNew.corpusgen -rule-flags, selecting rules with any of the requested flags.Size measurements
Measured with Go 1.26.7 on darwin/arm64:
An external test program using only
NewFromReaderproduced a binary of approximately 6.1 MB, compared with 19.0 MB usingNew. The full corpus bytes were absent from the reader-only binary.Embedding the text-only corpus produced a binary of approximately 16.5 MB. This enables smaller, caller-controlled corpora, but text-only filtering does not reach the approximately 2.9 MB corpus size discussed in the issue.
Filtered corpora can change detection behavior because omitted rules and vocabulary are unavailable.
Validation
go vetpassed.golangci-lint run: 0 issues.git diff --checkpassed.Regression tests cover independent matchers, options, reader ownership, malformed and truncated data, checksum and read errors, flag validation, deterministic filtering, token remapping, stopwords and included/excluded rule matching.