Skip to content

Commit b56a28f

Browse files
ConradIrwinmatloob
authored andcommitted
modfile: Add support for tool lines
Add new tool directive to go.mod parser and functions to add and drop them. For golang/go#48429 Change-Id: I37667a69ded9d59ea248ec48ad35c87592103218 Reviewed-on: https://go-review.googlesource.com/c/mod/+/508355 Reviewed-by: Michael Matloob <matloob@golang.org> Reviewed-by: Sam Thanawalla <samthanawalla@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
1 parent 79169e9 commit b56a28f

File tree

3 files changed

+205
-6
lines changed

3 files changed

+205
-6
lines changed

modfile/rule.go

+75-5
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ type File struct {
4343
Exclude []*Exclude
4444
Replace []*Replace
4545
Retract []*Retract
46+
Tool []*Tool
4647

4748
Syntax *FileSyntax
4849
}
@@ -93,6 +94,12 @@ type Retract struct {
9394
Syntax *Line
9495
}
9596

97+
// A Tool is a single tool statement.
98+
type Tool struct {
99+
Path string
100+
Syntax *Line
101+
}
102+
96103
// A VersionInterval represents a range of versions with upper and lower bounds.
97104
// Intervals are closed: both bounds are included. When Low is equal to High,
98105
// the interval may refer to a single version ('v1.2.3') or an interval
@@ -297,7 +304,7 @@ func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (parse
297304
})
298305
}
299306
continue
300-
case "module", "godebug", "require", "exclude", "replace", "retract":
307+
case "module", "godebug", "require", "exclude", "replace", "retract", "tool":
301308
for _, l := range x.Line {
302309
f.add(&errs, x, l, x.Token[0], l.Token, fix, strict)
303310
}
@@ -509,6 +516,21 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a
509516
Syntax: line,
510517
}
511518
f.Retract = append(f.Retract, retract)
519+
520+
case "tool":
521+
if len(args) != 1 {
522+
errorf("tool directive expects exactly one argument")
523+
return
524+
}
525+
s, err := parseString(&args[0])
526+
if err != nil {
527+
errorf("invalid quoted string: %v", err)
528+
return
529+
}
530+
f.Tool = append(f.Tool, &Tool{
531+
Path: s,
532+
Syntax: line,
533+
})
512534
}
513535
}
514536

@@ -1567,6 +1589,36 @@ func (f *File) DropRetract(vi VersionInterval) error {
15671589
return nil
15681590
}
15691591

1592+
// AddTool adds a new tool directive with the given path.
1593+
// It does nothing if the tool line already exists.
1594+
func (f *File) AddTool(path string) error {
1595+
for _, t := range f.Tool {
1596+
if t.Path == path {
1597+
return nil
1598+
}
1599+
}
1600+
1601+
f.Tool = append(f.Tool, &Tool{
1602+
Path: path,
1603+
Syntax: f.Syntax.addLine(nil, "tool", path),
1604+
})
1605+
1606+
f.SortBlocks()
1607+
return nil
1608+
}
1609+
1610+
// RemoveTool removes a tool directive with the given path.
1611+
// It does nothing if no such tool directive exists.
1612+
func (f *File) DropTool(path string) error {
1613+
for _, t := range f.Tool {
1614+
if t.Path == path {
1615+
t.Syntax.markRemoved()
1616+
*t = Tool{}
1617+
}
1618+
}
1619+
return nil
1620+
}
1621+
15701622
func (f *File) SortBlocks() {
15711623
f.removeDups() // otherwise sorting is unsafe
15721624

@@ -1593,9 +1645,9 @@ func (f *File) SortBlocks() {
15931645
}
15941646
}
15951647

1596-
// removeDups removes duplicate exclude and replace directives.
1648+
// removeDups removes duplicate exclude, replace and tool directives.
15971649
//
1598-
// Earlier exclude directives take priority.
1650+
// Earlier exclude and tool directives take priority.
15991651
//
16001652
// Later replace directives take priority.
16011653
//
@@ -1605,10 +1657,10 @@ func (f *File) SortBlocks() {
16051657
// retract directives are not de-duplicated since comments are
16061658
// meaningful, and versions may be retracted multiple times.
16071659
func (f *File) removeDups() {
1608-
removeDups(f.Syntax, &f.Exclude, &f.Replace)
1660+
removeDups(f.Syntax, &f.Exclude, &f.Replace, &f.Tool)
16091661
}
16101662

1611-
func removeDups(syntax *FileSyntax, exclude *[]*Exclude, replace *[]*Replace) {
1663+
func removeDups(syntax *FileSyntax, exclude *[]*Exclude, replace *[]*Replace, tool *[]*Tool) {
16121664
kill := make(map[*Line]bool)
16131665

16141666
// Remove duplicate excludes.
@@ -1649,6 +1701,24 @@ func removeDups(syntax *FileSyntax, exclude *[]*Exclude, replace *[]*Replace) {
16491701
}
16501702
*replace = repl
16511703

1704+
if tool != nil {
1705+
haveTool := make(map[string]bool)
1706+
for _, t := range *tool {
1707+
if haveTool[t.Path] {
1708+
kill[t.Syntax] = true
1709+
continue
1710+
}
1711+
haveTool[t.Path] = true
1712+
}
1713+
var newTool []*Tool
1714+
for _, t := range *tool {
1715+
if !kill[t.Syntax] {
1716+
newTool = append(newTool, t)
1717+
}
1718+
}
1719+
*tool = newTool
1720+
}
1721+
16521722
// Duplicate require and retract directives are not removed.
16531723

16541724
// Drop killed statements from the syntax tree.

modfile/rule_test.go

+129
Original file line numberDiff line numberDiff line change
@@ -1714,6 +1714,72 @@ var dropGodebugTests = []struct {
17141714
},
17151715
}
17161716

1717+
var addToolTests = []struct {
1718+
desc, in, path, want string
1719+
}{
1720+
{
1721+
`add_first`,
1722+
`module example.com/m`,
1723+
`example.com/tool/v1`,
1724+
`module example.com/m
1725+
tool example.com/tool/v1`,
1726+
},
1727+
{
1728+
`sorted_correctly`,
1729+
`module example.com/m
1730+
tool example.com/tool2
1731+
`,
1732+
`example.com/tool1`,
1733+
`module example.com/m
1734+
tool (
1735+
example.com/tool1
1736+
example.com/tool2
1737+
)`,
1738+
},
1739+
{
1740+
`duplicates_ignored`,
1741+
`module example.com/m
1742+
tool example.com/tool1
1743+
`,
1744+
`example.com/tool1`,
1745+
`module example.com/m
1746+
tool example.com/tool1`,
1747+
},
1748+
}
1749+
1750+
var dropToolTests = []struct {
1751+
desc, in, path, want string
1752+
}{
1753+
{
1754+
`only`,
1755+
`module example.com/m
1756+
tool example.com/tool1`,
1757+
`example.com/tool1`,
1758+
`module example.com/m`,
1759+
},
1760+
{
1761+
`parenthesized`,
1762+
`module example.com/m
1763+
tool (
1764+
example.com/tool1
1765+
example.com/tool2
1766+
)`,
1767+
`example.com/tool1`,
1768+
`module example.com/m
1769+
tool example.com/tool2`,
1770+
},
1771+
{
1772+
`missing`,
1773+
`module example.com/m
1774+
tool (
1775+
example.com/tool2
1776+
)`,
1777+
`example.com/tool1`,
1778+
`module example.com/m
1779+
tool example.com/tool2`,
1780+
},
1781+
}
1782+
17171783
func fixV(path, version string) (string, error) {
17181784
if path != "example.com/m" {
17191785
return "", fmt.Errorf("module path must be example.com/m")
@@ -2051,6 +2117,7 @@ func TestAddOnEmptyFile(t *testing.T) {
20512117
t.Fatal(err)
20522118
}
20532119
got, err := f.Format()
2120+
20542121
if err != nil {
20552122
t.Fatal(err)
20562123
}
@@ -2061,3 +2128,65 @@ func TestAddOnEmptyFile(t *testing.T) {
20612128
})
20622129
}
20632130
}
2131+
2132+
func TestAddTool(t *testing.T) {
2133+
for _, tt := range addToolTests {
2134+
t.Run(tt.desc, func(t *testing.T) {
2135+
inFile, err := Parse("in", []byte(tt.in), nil)
2136+
if err != nil {
2137+
t.Fatal(err)
2138+
}
2139+
if err := inFile.AddTool(tt.path); err != nil {
2140+
t.Fatal(err)
2141+
}
2142+
inFile.Cleanup()
2143+
got, err := inFile.Format()
2144+
if err != nil {
2145+
t.Fatal(err)
2146+
}
2147+
2148+
outFile, err := Parse("out", []byte(tt.want), nil)
2149+
if err != nil {
2150+
t.Fatal(err)
2151+
}
2152+
want, err := outFile.Format()
2153+
if err != nil {
2154+
t.Fatal(err)
2155+
}
2156+
if !bytes.Equal(got, want) {
2157+
t.Fatalf("got:\n%s\nwant:\n%s", got, want)
2158+
}
2159+
})
2160+
}
2161+
}
2162+
2163+
func TestDropTool(t *testing.T) {
2164+
for _, tt := range dropToolTests {
2165+
t.Run(tt.desc, func(t *testing.T) {
2166+
inFile, err := Parse("in", []byte(tt.in), nil)
2167+
if err != nil {
2168+
t.Fatal(err)
2169+
}
2170+
if err := inFile.DropTool(tt.path); err != nil {
2171+
t.Fatal(err)
2172+
}
2173+
inFile.Cleanup()
2174+
got, err := inFile.Format()
2175+
if err != nil {
2176+
t.Fatal(err)
2177+
}
2178+
2179+
outFile, err := Parse("out", []byte(tt.want), nil)
2180+
if err != nil {
2181+
t.Fatal(err)
2182+
}
2183+
want, err := outFile.Format()
2184+
if err != nil {
2185+
t.Fatal(err)
2186+
}
2187+
if !bytes.Equal(got, want) {
2188+
t.Fatalf("got:\n%s\nwant:\n%s", got, want)
2189+
}
2190+
})
2191+
}
2192+
}

modfile/work.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -331,5 +331,5 @@ func (f *WorkFile) SortBlocks() {
331331
// retract directives are not de-duplicated since comments are
332332
// meaningful, and versions may be retracted multiple times.
333333
func (f *WorkFile) removeDups() {
334-
removeDups(f.Syntax, nil, &f.Replace)
334+
removeDups(f.Syntax, nil, &f.Replace, nil)
335335
}

0 commit comments

Comments
 (0)