Skip to content

Commit

Permalink
Fixed absolute doc_opt paths on Windows (pseudomuto#497)
Browse files Browse the repository at this point in the history
  • Loading branch information
S1artie committed Feb 3, 2023
1 parent 00cf69c commit 5f770dd
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 7 deletions.
49 changes: 42 additions & 7 deletions plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,15 +121,50 @@ func ParseOptions(req *plugin_go.CodeGeneratorRequest) (*PluginOptions, error) {
if strings.Contains(params, ":") {
// Parse out exclude patterns if any
parts := strings.Split(params, ":")
for _, pattern := range strings.Split(parts[1], ",") {
r, err := regexp.Compile(pattern)
if err != nil {
return nil, err

// On Windows, there can legitimately be up to two ":" in the first part: one for each filename in case absolute paths
// are used, as a divider between the drive letter and the remainder of the path. That makes it really ugly: we now
// need to do some heuristics to "match" Windows path patterns to detect if a : is not to be treated as a divider
// between the first parameter half and the second half with the exclude patterns.
// This fixes GitHub issue #497.
winPathHeuristic := func(first, second string) bool {
// A Windows path in our doc_opt parameter is assumed to have a backslash in the second part...
if strings.HasPrefix(second, "\\") {
// ...and a drive letter either directly at the start of the first part or being preceded by a comma.
// If both of these conditions match, it is assumed that the : separation actually splitted a Windows
// path in two parts which belong together.
firstMatches, _ := regexp.MatchString("(?:^|,)[a-zA-z]$", first)
return firstMatches
}
return false
}
excludePart := ""
if winPathHeuristic(parts[0], parts[1]) {
params = parts[0] + ":" + parts[1]
if len(parts) > 2 {
if winPathHeuristic(params, parts[2]) {
params = params + ":" + parts[2]
if len(parts) > 3 {
excludePart = parts[3]
}
} else {
excludePart = parts[2]
}
}
} else {
params = parts[0]
excludePart = parts[1]
}

if len(excludePart) > 0 {
for _, pattern := range strings.Split(excludePart, ",") {
r, err := regexp.Compile(pattern)
if err != nil {
return nil, err
}
options.ExcludePatterns = append(options.ExcludePatterns, r)
}
options.ExcludePatterns = append(options.ExcludePatterns, r)
}
// The first part is parsed below
params = parts[0]
}
if params == "" {
return options, nil
Expand Down
25 changes: 25 additions & 0 deletions plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,31 @@ func TestParseOptionsWithInvalidValues(t *testing.T) {
}
}

func TestParseOptionsForCustomTemplateWindowsAbsolutePath(t *testing.T) {
req := new(plugin_go.CodeGeneratorRequest)
req.Parameter = proto.String("C:\\path\\to\\template.tmpl,C:\\path\\to\\output")

options, err := ParseOptions(req)
require.NoError(t, err)

require.Equal(t, RenderTypeHTML, options.Type)
require.Equal(t, "C:\\path\\to\\template.tmpl", options.TemplateFile)
require.Equal(t, "C:\\path\\to\\output", options.OutputFile)
}

func TestParseOptionsForCustomTemplateWindowsAbsolutePathPlusExcludes(t *testing.T) {
req := new(plugin_go.CodeGeneratorRequest)
req.Parameter = proto.String("C:\\path\\to\\template.tmpl,C:\\path\\to\\output:test.*")

options, err := ParseOptions(req)
require.NoError(t, err)

require.Equal(t, RenderTypeHTML, options.Type)
require.Equal(t, "C:\\path\\to\\template.tmpl", options.TemplateFile)
require.Equal(t, "C:\\path\\to\\output", options.OutputFile)
require.Equal(t, "test.*", options.ExcludePatterns[0].String())
}

func TestRunPluginForBuiltinTemplate(t *testing.T) {
set, _ := utils.LoadDescriptorSet("fixtures", "fileset.pb")
req := utils.CreateGenRequest(set, "Booking.proto", "Vehicle.proto", "nested/Book.proto")
Expand Down

0 comments on commit 5f770dd

Please sign in to comment.