Skip to content

Commit

Permalink
modfile: parse deprecation notices in module comments
Browse files Browse the repository at this point in the history
Deprecation notices start with "Deprecated:" at the beginning of a
line and run until the end of the paragraph.

This CL reuses text extraction code for retraction rationale, so the
same rules apply: comment text may be from the comments above a
"module" directive or as a suffix on the same line.

For golang/go#40357

Change-Id: Id5524149c6bbda3effc64c6b668b701b5cf428af
Reviewed-on: https://go-review.googlesource.com/c/mod/+/301089
Trust: Jay Conrod <jayconrod@google.com>
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
Reviewed-by: Michael Matloob <matloob@golang.org>
  • Loading branch information
Jay Conrod committed Apr 9, 2021
1 parent 244d49f commit 858fdbe
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 8 deletions.
40 changes: 32 additions & 8 deletions modfile/rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ type File struct {

// A Module is the module statement.
type Module struct {
Mod module.Version
Syntax *Line
Mod module.Version
Deprecated string
Syntax *Line
}

// A Go is the go statement.
Expand Down Expand Up @@ -278,7 +279,11 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a
errorf("repeated module statement")
return
}
f.Module = &Module{Syntax: line}
deprecated := parseDeprecation(block, line)
f.Module = &Module{
Syntax: line,
Deprecated: deprecated,
}
if len(args) != 1 {
errorf("usage: module module/path")
return
Expand Down Expand Up @@ -392,7 +397,7 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a
})

case "retract":
rationale := parseRetractRationale(block, line)
rationale := parseDirectiveComment(block, line)
vi, err := parseVersionInterval(verb, "", &args, dontFixRetract)
if err != nil {
if strict {
Expand Down Expand Up @@ -619,10 +624,29 @@ func parseString(s *string) (string, error) {
return t, nil
}

// parseRetractRationale extracts the rationale for a retract directive from the
// surrounding comments. If the line does not have comments and is part of a
// block that does have comments, the block's comments are used.
func parseRetractRationale(block *LineBlock, line *Line) string {
var deprecatedRE = lazyregexp.New(`(?s)(?:^|\n\n)Deprecated: *(.*?)(?:$|\n\n)`)

// parseDeprecation extracts the text of comments on a "module" directive and
// extracts a deprecation message from that.
//
// A deprecation message is contained in a paragraph within a block of comments
// that starts with "Deprecated:" (case sensitive). The message runs until the
// end of the paragraph and does not include the "Deprecated:" prefix. If the
// comment block has multiple paragraphs that start with "Deprecated:",
// parseDeprecation returns the message from the first.
func parseDeprecation(block *LineBlock, line *Line) string {
text := parseDirectiveComment(block, line)
m := deprecatedRE.FindStringSubmatch(text)
if m == nil {
return ""
}
return m[1]
}

// parseDirectiveComment extracts the text of comments on a directive.
// If the directive's line does not have comments and is part of a block that
// does have comments, the block's comments are used.
func parseDirectiveComment(block *LineBlock, line *Line) string {
comments := line.Comment()
if block != nil && len(comments.Before) == 0 && len(comments.Suffix) == 0 {
comments = block.Comment()
Expand Down
126 changes: 126 additions & 0 deletions modfile/rule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,118 @@ suffix`,
},
}

var moduleDeprecatedTests = []struct {
desc, in, want string
}{
// retractRationaleTests exercises some of the same code, so these tests
// don't exhaustively cover comment extraction.
{
`no_comment`,
`module m`,
``,
},
{
`other_comment`,
`// yo
module m`,
``,
},
{
`deprecated_no_colon`,
`//Deprecated
module m`,
``,
},
{
`deprecated_no_space`,
`//Deprecated:blah
module m`,
`blah`,
},
{
`deprecated_simple`,
`// Deprecated: blah
module m`,
`blah`,
},
{
`deprecated_lowercase`,
`// deprecated: blah
module m`,
``,
},
{
`deprecated_multiline`,
`// Deprecated: one
// two
module m`,
"one\ntwo",
},
{
`deprecated_mixed`,
`// some other comment
// Deprecated: blah
module m`,
``,
},
{
`deprecated_middle`,
`// module m is Deprecated: blah
module m`,
``,
},
{
`deprecated_multiple`,
`// Deprecated: a
// Deprecated: b
module m`,
"a\nDeprecated: b",
},
{
`deprecated_paragraph`,
`// Deprecated: a
// b
//
// c
module m`,
"a\nb",
},
{
`deprecated_paragraph_space`,
`// Deprecated: the next line has a space
//
// c
module m`,
"the next line has a space",
},
{
`deprecated_suffix`,
`module m // Deprecated: blah`,
`blah`,
},
{
`deprecated_mixed_suffix`,
`// some other comment
module m // Deprecated: blah`,
``,
},
{
`deprecated_mixed_suffix_paragraph`,
`// some other comment
//
module m // Deprecated: blah`,
`blah`,
},
{
`deprecated_block`,
`// Deprecated: blah
module (
m
)`,
`blah`,
},
}

var sortBlocksTests = []struct {
desc, in, out string
strict bool
Expand Down Expand Up @@ -848,6 +960,20 @@ func TestRetractRationale(t *testing.T) {
}
}

func TestModuleDeprecated(t *testing.T) {
for _, tt := range moduleDeprecatedTests {
t.Run(tt.desc, func(t *testing.T) {
f, err := Parse("in", []byte(tt.in), nil)
if err != nil {
t.Fatal(err)
}
if f.Module.Deprecated != tt.want {
t.Errorf("got %q; want %q", f.Module.Deprecated, tt.want)
}
})
}
}

func TestSortBlocks(t *testing.T) {
for _, tt := range sortBlocksTests {
t.Run(tt.desc, func(t *testing.T) {
Expand Down

0 comments on commit 858fdbe

Please sign in to comment.