Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
Alex Goodman 2024-05-03 16:12:00 -04:00
parent d6604adaaf
commit 3e21379492
3 changed files with 178 additions and 15 deletions

View file

@ -69,13 +69,16 @@ func buildDotNetPackage(versionResources map[string]string, f file.LocationReadC
}
metadata := pkg.DotnetPortableExecutableEntry{
AssemblyVersion: versionResources["Assembly Version"],
LegalCopyright: versionResources["LegalCopyright"],
Comments: versionResources["Comments"],
InternalName: versionResources["InternalName"],
CompanyName: versionResources["CompanyName"],
ProductName: versionResources["ProductName"],
ProductVersion: versionResources["ProductVersion"],
AssemblyVersion: versionResources["Assembly Version"],
LegalCopyright: versionResources["LegalCopyright"],
Comments: versionResources["Comments"],
InternalName: versionResources["InternalName"],
CompanyName: versionResources["CompanyName"],
ProductName: versionResources["ProductName"],
ProductVersion: versionResources["ProductVersion"],
FileDescription: versionResources["FileDescription"],
FileVersion: versionResources["FileVersion"],
OriginalFilename: versionResources["OriginalFilename"],
}
dnpkg = pkg.Package{
@ -215,7 +218,7 @@ func findName(versionResources map[string]string) string {
}
for _, field := range nameFields {
value := spaceNormalize(versionResources[field])
value := resolveValue(versionResources[field], versionResources, nil)
if value == "" {
continue
}
@ -225,6 +228,40 @@ func findName(versionResources map[string]string) string {
return ""
}
func resolveValue(value string, collection map[string]string, visited map[string]bool) string {
value = spaceNormalize(value)
if value == "" {
return ""
}
if visited == nil {
visited = make(map[string]bool)
}
if visited[value] {
return value
}
visited[value] = true
hasIndirect, nextKey := hasIndirectFieldPrefix(value)
if !hasIndirect {
return value
}
return resolveValue(collection[nextKey], collection, visited)
}
func hasIndirectFieldPrefix(value string) (bool, string) {
for _, prefix := range []string{"f#", "p("} {
cleanValue := strings.TrimPrefix(value, prefix)
if cleanValue != value {
return true, cleanValue
}
}
return false, value
}
// normalizes a string to a trimmed version with all contigous whitespace collapsed to a single space character
func spaceNormalize(value string) string {
value = strings.TrimSpace(value)

View file

@ -346,3 +346,126 @@ func Test_spaceNormalize(t *testing.T) {
})
}
}
func Test_resolveValue(t *testing.T) {
tests := []struct {
name string
value string
collection map[string]string
want string
}{
{
name: "simple value",
value: "value",
collection: map[string]string{
"key": "value",
},
want: "value",
},
{
name: "simple value with spaces",
value: " value ",
collection: map[string]string{
"key": "value",
},
want: "value",
},
{
name: "indirect value - f#",
value: "f#other",
collection: map[string]string{
"key": "f#other",
"other": "value",
},
want: "value",
},
{
name: "indirect value - p(",
value: "f#other",
collection: map[string]string{
"key": "p(other",
"other": "value",
},
want: "value",
},
{
name: "indirect value with cycles",
value: "f#other",
collection: map[string]string{
"key": "f#other",
"other": "f#key",
},
want: "f#other", // this is NOT ideal, but there is no "good" answer here
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, resolveValue(tt.value, tt.collection, nil))
})
}
}
func Test_findVersion(t *testing.T) {
tests := []struct {
name string
versionResources map[string]string
want string
}{
{
name: "prefer file version over product version (when both semver)",
versionResources: map[string]string{
"FileVersion": "1.2.3",
"ProductVersion": "4.5.6",
},
want: "4.5.6",
},
{
name: "prefer file version over product version (when both semver)",
versionResources: map[string]string{
"FileVersion": "1.2.3",
"ProductVersion": "4.5.6.7",
},
want: "1.2.3",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, findVersion(tt.versionResources))
})
}
}
func Test_keepGreaterSemanticVersion(t *testing.T) {
tests := []struct {
name string
productVersion string
fileVersion string
want string
}{
{
name: "product semver is greater",
productVersion: "3.0.0",
fileVersion: "2.0.0",
want: "3.0.0",
},
{
name: "file semver is greater",
productVersion: "2.0.0",
fileVersion: "3.0.0",
want: "3.0.0",
},
{
name: "semver preferred over non-semver",
productVersion: "3.0.0.2",
fileVersion: "3.0.0",
want: "3.0.0",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, keepGreaterSemanticVersion(tt.productVersion, tt.fileVersion))
})
}
}

View file

@ -11,11 +11,14 @@ type DotnetDepsEntry struct {
// DotnetPortableExecutableEntry is a struct that represents a single entry found within "VersionResources" section of a .NET Portable Executable binary file.
type DotnetPortableExecutableEntry struct {
AssemblyVersion string `json:"assemblyVersion"`
LegalCopyright string `json:"legalCopyright"`
Comments string `json:"comments,omitempty"`
InternalName string `json:"internalName,omitempty"`
CompanyName string `json:"companyName"`
ProductName string `json:"productName"`
ProductVersion string `json:"productVersion"`
AssemblyVersion string `json:"assemblyVersion"`
LegalCopyright string `json:"legalCopyright"`
Comments string `json:"comments,omitempty"`
InternalName string `json:"internalName,omitempty"`
CompanyName string `json:"companyName"`
ProductName string `json:"productName"`
ProductVersion string `json:"productVersion"`
FileVersion string `json:"fileVersion,omitempty"`
FileDescription string `json:"fileDescription,omitempty"`
OriginalFilename string `json:"originalFilename,omitempty"`
}