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