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