/
assetsjson.go
197 lines (171 loc) · 6.04 KB
/
assetsjson.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
package dependencies
import (
"encoding/json"
"errors"
"fmt"
buildinfo "github.com/jfrog/build-info-go/entities"
"github.com/jfrog/build-info-go/utils"
"os"
"path/filepath"
"strings"
)
const (
AssetFileName = "project.assets.json"
AssetDirName = "obj"
)
// Register project.assets.json extractor
func init() {
register(&assetsExtractor{})
}
// project.assets.json dependency extractor
type assetsExtractor struct {
assets *assets
}
func (extractor *assetsExtractor) IsCompatible(projectName, dependenciesSource string, log utils.Log) bool {
if strings.HasSuffix(dependenciesSource, AssetFileName) {
log.Debug("Found", dependenciesSource, "file for project:", projectName)
return true
}
return false
}
func (extractor *assetsExtractor) DirectDependencies() ([]string, error) {
return extractor.assets.getDirectDependencies(), nil
}
func (extractor *assetsExtractor) AllDependencies(log utils.Log) (map[string]*buildinfo.Dependency, error) {
return extractor.assets.getAllDependencies(log)
}
func (extractor *assetsExtractor) ChildrenMap() (map[string][]string, error) {
return extractor.assets.getChildrenMap(), nil
}
// Create new assets json extractor.
func (extractor *assetsExtractor) new(dependenciesSource string, log utils.Log) (Extractor, error) {
newExtractor := &assetsExtractor{}
content, err := os.ReadFile(dependenciesSource)
if err != nil {
return nil, err
}
assets := &assets{}
err = json.Unmarshal(content, assets)
if err != nil {
return nil, err
}
newExtractor.assets = assets
return newExtractor, nil
}
func (assets *assets) getChildrenMap() map[string][]string {
dependenciesRelations := map[string][]string{}
for _, dependencies := range assets.Targets {
for dependencyId, targetDependencies := range dependencies {
var transitive []string
for transitiveName := range targetDependencies.Dependencies {
transitive = append(transitive, strings.ToLower(transitiveName))
}
dependencyName := getDependencyName(dependencyId)
dependenciesRelations[dependencyName] = transitive
}
}
return dependenciesRelations
}
func (assets *assets) getDirectDependencies() []string {
var directDependencies []string
for _, framework := range assets.Project.Frameworks {
for dependencyName := range framework.Dependencies {
directDependencies = append(directDependencies, strings.ToLower(dependencyName))
}
}
return directDependencies
}
func (assets *assets) getAllDependencies(log utils.Log) (map[string]*buildinfo.Dependency, error) {
dependencies := map[string]*buildinfo.Dependency{}
packagesPath := assets.Project.Restore.PackagesPath
for dependencyId, library := range assets.Libraries {
if library.Type == "project" {
continue
}
nupkgFileName, err := library.getNupkgFileName()
if err != nil {
return nil, err
}
nupkgFilePath := filepath.Join(packagesPath, library.Path, nupkgFileName)
exists, err := utils.IsFileExists(nupkgFilePath, false)
if err != nil {
return nil, err
}
if !exists {
if assets.isPackagePartOfTargetDependencies(library.Path) {
log.Warn("The file", nupkgFilePath, "doesn't exist in the NuGet cache directory but it does exist as a target in the assets files."+absentNupkgWarnMsg)
continue
}
return nil, errors.New("The file " + nupkgFilePath + " doesn't exist in the NuGet cache directory.")
}
fileDetails, err := utils.GetFileDetails(nupkgFilePath, true)
if err != nil {
return nil, err
}
dependencyName := getDependencyName(dependencyId)
dependencies[dependencyName] = &buildinfo.Dependency{Id: getDependencyIdForBuildInfo(dependencyId), Checksum: buildinfo.Checksum{Sha1: fileDetails.Checksum.Sha1, Md5: fileDetails.Checksum.Md5}}
}
return dependencies, nil
}
// If the package is included in the targets section of the assets.json file,
// then this is a .NET dependency that shouldn't be included in the build-info dependencies list
// (it come with the SDK).
// Those files are located in the following path: C:\Program Files\dotnet\sdk\NuGetFallbackFolder
func (assets *assets) isPackagePartOfTargetDependencies(nugetPackageName string) bool {
for _, dependencies := range assets.Targets {
for dependencyId := range dependencies {
// The package names in the targets section of the assets.json file are
// case insensitive.
if strings.EqualFold(dependencyId, nugetPackageName) {
return true
}
}
}
return false
}
// Dependencies-id in assets is built in form of: <package-name>/<version>.
// The Build-info format of dependency id is: <package-name>:<version>.
func getDependencyIdForBuildInfo(dependencyAssetId string) string {
return strings.Replace(dependencyAssetId, "/", ":", 1)
}
func getDependencyName(dependencyId string) string {
return strings.ToLower(dependencyId)[0:strings.Index(dependencyId, "/")]
}
// Assets json objects for unmarshalling
type assets struct {
Version int
Targets map[string]map[string]targetDependency `json:"targets,omitempty"`
Libraries map[string]library `json:"libraries,omitempty"`
Project project `json:"project"`
}
type targetDependency struct {
Dependencies map[string]string `json:"dependencies,omitempty"` // Transitive dependencies
}
type library struct {
Type string `json:"type,omitempty"`
Path string `json:"path,omitempty"`
Files []string `json:"files,omitempty"`
}
func (library *library) getNupkgFileName() (string, error) {
for _, fileName := range library.Files {
if strings.HasSuffix(fileName, "nupkg.sha512") {
return strings.TrimSuffix(fileName, ".sha512"), nil
}
}
return "", fmt.Errorf("could not find nupkg file name for: %s", library.Path)
}
type project struct {
Version string `json:"version,omitempty"`
Restore restore `json:"restore"`
Frameworks map[string]framework `json:"frameworks,omitempty"`
}
type restore struct {
PackagesPath string `json:"packagesPath"`
}
type framework struct {
Dependencies map[string]dependency `json:"dependencies,omitempty"` // Direct dependencies
}
type dependency struct {
Target string `json:"target"`
Version string `json:"version,omitempty"`
}