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