github.com/jfrog/jfrog-cli-go@v1.22.1-0.20200318093948-4826ef344ffd/artifactory/commands/nuget/consume.go (about) 1 package nuget 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "net/url" 7 "os" 8 "path" 9 "strings" 10 11 gofrogcmd "github.com/jfrog/gofrog/io" 12 "github.com/jfrog/jfrog-cli-go/artifactory/utils" 13 "github.com/jfrog/jfrog-cli-go/artifactory/utils/nuget" 14 "github.com/jfrog/jfrog-cli-go/artifactory/utils/nuget/solution" 15 "github.com/jfrog/jfrog-cli-go/utils/config" 16 "github.com/jfrog/jfrog-client-go/auth" 17 clientutils "github.com/jfrog/jfrog-client-go/utils" 18 "github.com/jfrog/jfrog-client-go/utils/errorutils" 19 "github.com/jfrog/jfrog-client-go/utils/io/fileutils" 20 "github.com/jfrog/jfrog-client-go/utils/log" 21 "github.com/mattn/go-shellwords" 22 ) 23 24 type NugetCommandArgs struct { 25 args string 26 flags string 27 repoName string 28 solutionPath string 29 buildConfiguration *utils.BuildConfiguration 30 rtDetails *config.ArtifactoryDetails 31 } 32 33 type NugetCommand struct { 34 configFilePath string 35 *NugetCommandArgs 36 } 37 38 func NewNugetCommand() *NugetCommand { 39 return &NugetCommand{"", &NugetCommandArgs{}} 40 } 41 42 func (nc *NugetCommand) SetConfigFilePath(configFilePath string) *NugetCommand { 43 nc.configFilePath = configFilePath 44 return nc 45 } 46 47 func (nca *NugetCommandArgs) SetRtDetails(rtDetails *config.ArtifactoryDetails) *NugetCommandArgs { 48 nca.rtDetails = rtDetails 49 return nca 50 } 51 52 func (nca *NugetCommandArgs) SetBuildConfiguration(buildConfiguration *utils.BuildConfiguration) *NugetCommandArgs { 53 nca.buildConfiguration = buildConfiguration 54 return nca 55 } 56 57 func (nca *NugetCommandArgs) SetSolutionPath(solutionPath string) *NugetCommandArgs { 58 nca.solutionPath = solutionPath 59 return nca 60 } 61 62 func (nca *NugetCommandArgs) SetRepoName(repoName string) *NugetCommandArgs { 63 nca.repoName = repoName 64 return nca 65 } 66 67 func (nca *NugetCommandArgs) SetFlags(flags string) *NugetCommandArgs { 68 nca.flags = flags 69 return nca 70 } 71 72 func (nca *NugetCommandArgs) SetArgs(args string) *NugetCommandArgs { 73 nca.args = args 74 return nca 75 } 76 77 func (nc *NugetCommand) Run() error { 78 // Read config file. 79 log.Debug("Preparing to read the config file", nc.configFilePath) 80 vConfig, err := utils.ReadConfigFile(nc.configFilePath, utils.YAML) 81 if err != nil { 82 return err 83 } 84 // Extract resolution params. 85 resolveParams, err := utils.GetRepoConfigByPrefix(nc.configFilePath, utils.ProjectConfigResolverPrefix, vConfig) 86 if err != nil { 87 return err 88 } 89 filteredNugetArgs, buildConfiguration, err := utils.ExtractBuildDetailsFromArgs(strings.Split(nc.args, " ")) 90 RtDetails, err := resolveParams.RtDetails() 91 if err != nil { 92 return err 93 } 94 nc.SetArgs(strings.Join(filteredNugetArgs, " ")). 95 SetRepoName(resolveParams.TargetRepo()). 96 SetBuildConfiguration(buildConfiguration). 97 SetRtDetails(RtDetails) 98 return nc.run() 99 } 100 101 // Exec all consume type nuget commands, install, update, add, restore. 102 func (nca *NugetCommandArgs) run() error { 103 log.Info("Running nuget...") 104 // Use temp dir to save config file, the config will be removed at the end. 105 tempDirPath, err := fileutils.CreateTempDir() 106 if err != nil { 107 return err 108 } 109 defer fileutils.RemoveTempDir(tempDirPath) 110 111 nca.solutionPath, err = changeWorkingDir(nca.solutionPath) 112 if err != nil { 113 return err 114 } 115 116 err = nca.prepareAndRunCmd(tempDirPath) 117 if err != nil { 118 return err 119 } 120 121 isCollectBuildInfo := len(nca.buildConfiguration.BuildName) > 0 && len(nca.buildConfiguration.BuildNumber) > 0 122 if !isCollectBuildInfo { 123 return nil 124 } 125 126 slnFile := "" 127 flags := strings.Split(nca.flags, " ") 128 if len(flags) > 0 && strings.HasSuffix(flags[0], ".sln") { 129 slnFile = flags[0] 130 } 131 sol, err := solution.Load(nca.solutionPath, slnFile) 132 if err != nil { 133 return err 134 } 135 136 if err = utils.SaveBuildGeneralDetails(nca.buildConfiguration.BuildName, nca.buildConfiguration.BuildNumber); err != nil { 137 return err 138 } 139 buildInfo, err := sol.BuildInfo(nca.buildConfiguration.Module) 140 if err != nil { 141 return err 142 } 143 return utils.SaveBuildInfo(nca.buildConfiguration.BuildName, nca.buildConfiguration.BuildNumber, buildInfo) 144 } 145 146 func (nca *NugetCommandArgs) RtDetails() (*config.ArtifactoryDetails, error) { 147 return nca.rtDetails, nil 148 } 149 150 func (nca *NugetCommandArgs) CommandName() string { 151 return "rt_nuget" 152 } 153 154 const sourceName = "JFrogCli" 155 156 func DependencyTreeCmd() error { 157 workspace, err := os.Getwd() 158 if err != nil { 159 return errorutils.CheckError(err) 160 } 161 162 sol, err := solution.Load(workspace, "") 163 if err != nil { 164 return err 165 } 166 167 // Create the tree for each project 168 for _, project := range sol.GetProjects() { 169 err = project.CreateDependencyTree() 170 if err != nil { 171 return err 172 } 173 } 174 // Build the tree. 175 content, err := sol.Marshal() 176 if err != nil { 177 return errorutils.CheckError(err) 178 } 179 log.Output(clientutils.IndentJson(content)) 180 return nil 181 } 182 183 // Changes the working directory if provided. 184 // Returns the path to the solution 185 func changeWorkingDir(newWorkingDir string) (string, error) { 186 var err error 187 if newWorkingDir != "" { 188 err = os.Chdir(newWorkingDir) 189 } else { 190 newWorkingDir, err = os.Getwd() 191 } 192 193 return newWorkingDir, errorutils.CheckError(err) 194 } 195 196 // Prepares the nuget configuration file within the temp directory 197 // Runs NuGet itself with the arguments and flags provided. 198 func (nca *NugetCommandArgs) prepareAndRunCmd(configDirPath string) error { 199 cmd, err := nca.createNugetCmd() 200 if err != nil { 201 return err 202 } 203 // To prevent NuGet prompting for credentials 204 err = os.Setenv("NUGET_EXE_NO_PROMPT", "true") 205 if err != nil { 206 return errorutils.CheckError(err) 207 } 208 209 err = nca.prepareConfigFile(cmd, configDirPath) 210 if err != nil { 211 return err 212 } 213 err = gofrogcmd.RunCmd(cmd) 214 if err != nil { 215 return err 216 } 217 218 return nil 219 } 220 221 // Checks if the user provided input such as -configfile flag or -Source flag. 222 // If those flags provided, NuGet will use the provided configs (default config file or the one with -configfile) 223 // If neither provided, we are initializing our own config. 224 func (nca *NugetCommandArgs) prepareConfigFile(cmd *nuget.Cmd, configDirPath string) error { 225 currentConfigPath, err := getFlagValueIfExists("-configfile", cmd) 226 if err != nil { 227 return err 228 } 229 if currentConfigPath != "" { 230 return nil 231 } 232 233 sourceCommandValue, err := getFlagValueIfExists("-source", cmd) 234 if err != nil { 235 return err 236 } 237 if sourceCommandValue != "" { 238 return nil 239 } 240 241 err = nca.initNewConfig(cmd, configDirPath) 242 return err 243 } 244 245 // Returns the value of the flag if exists 246 func getFlagValueIfExists(cmdFlag string, cmd *nuget.Cmd) (string, error) { 247 for i := 0; i < len(cmd.CommandFlags); i++ { 248 if !strings.EqualFold(cmd.CommandFlags[i], cmdFlag) { 249 continue 250 } 251 if i+1 == len(cmd.CommandFlags) { 252 return "", errorutils.CheckError(errorutils.CheckError(fmt.Errorf(cmdFlag, " flag was provided without value"))) 253 } 254 return cmd.CommandFlags[i+1], nil 255 } 256 257 return "", nil 258 } 259 260 // Initializing a new NuGet config file that NuGet will use into a temp file 261 func (nca *NugetCommandArgs) initNewConfig(cmd *nuget.Cmd, configDirPath string) error { 262 // Got to here, means that neither of the flags provided and we need to init our own config. 263 configFile, err := writeToTempConfigFile(cmd, configDirPath) 264 if err != nil { 265 return err 266 } 267 268 return nca.addNugetAuthenticationToNewConfig(configFile) 269 } 270 271 // Runs nuget add sources and setapikey commands to authenticate with Artifactory server 272 func (nca *NugetCommandArgs) addNugetAuthenticationToNewConfig(configFile *os.File) error { 273 sourceUrl, user, password, err := nca.getSourceDetails() 274 if err != nil { 275 return err 276 } 277 278 err = addNugetSource(configFile.Name(), sourceUrl, user, password) 279 if err != nil { 280 return err 281 } 282 283 err = addNugetApiKey(user, password, configFile.Name()) 284 return err 285 } 286 287 // Creates the temp file and writes the config template into the file for NuGet can use it. 288 func writeToTempConfigFile(cmd *nuget.Cmd, tempDirPath string) (*os.File, error) { 289 configFile, err := ioutil.TempFile(tempDirPath, "jfrog.cli.nuget.") 290 if err != nil { 291 return nil, errorutils.CheckError(err) 292 } 293 log.Debug("Nuget config file created at:", configFile.Name()) 294 295 defer configFile.Close() 296 297 cmd.CommandFlags = append(cmd.CommandFlags, "-ConfigFile", configFile.Name()) 298 299 // Set Artifactory repo as source 300 content := nuget.ConfigFileTemplate 301 _, err = configFile.WriteString(content) 302 if err != nil { 303 return nil, errorutils.CheckError(err) 304 } 305 return configFile, nil 306 } 307 308 // Runs nuget sources add command 309 func addNugetSource(configFileName, sourceUrl, user, password string) error { 310 cmd, err := nuget.NewNugetCmd() 311 if err != nil { 312 return err 313 } 314 315 sourceCommand := "sources" 316 cmd.Command = append(cmd.Command, sourceCommand) 317 cmd.CommandFlags = append(cmd.CommandFlags, "-ConfigFile", configFileName) 318 cmd.CommandFlags = append(cmd.CommandFlags, "Add") 319 cmd.CommandFlags = append(cmd.CommandFlags, "-Name", sourceName) 320 cmd.CommandFlags = append(cmd.CommandFlags, "-Source", sourceUrl) 321 cmd.CommandFlags = append(cmd.CommandFlags, "-username", user) 322 cmd.CommandFlags = append(cmd.CommandFlags, "-password", password) 323 output, err := gofrogcmd.RunCmdOutput(cmd) 324 log.Debug("Running command: Add sources. Output:", output) 325 return err 326 } 327 328 // Runs nuget setapikey command 329 func addNugetApiKey(user, password, configFileName string) error { 330 cmd, err := nuget.NewNugetCmd() 331 if err != nil { 332 return err 333 } 334 335 cmd.Command = append(cmd.Command, "setapikey") 336 cmd.CommandFlags = append(cmd.CommandFlags, user+":"+password) 337 cmd.CommandFlags = append(cmd.CommandFlags, "-Source", sourceName) 338 cmd.CommandFlags = append(cmd.CommandFlags, "-ConfigFile", configFileName) 339 340 output, err := gofrogcmd.RunCmdOutput(cmd) 341 log.Debug("Running command: SetApiKey. Output:", output) 342 return err 343 } 344 345 func (nca *NugetCommandArgs) getSourceDetails() (sourceURL, user, password string, err error) { 346 var u *url.URL 347 u, err = url.Parse(nca.rtDetails.Url) 348 if errorutils.CheckError(err) != nil { 349 return 350 } 351 u.Path = path.Join(u.Path, "api/nuget", nca.repoName) 352 sourceURL = u.String() 353 354 user = nca.rtDetails.User 355 password = nca.rtDetails.Password 356 // If access-token is defined, extract user from it. 357 rtDetails, err := nca.RtDetails() 358 if errorutils.CheckError(err) != nil { 359 return 360 } 361 if rtDetails.AccessToken != "" { 362 log.Debug("Using access-token details for nuget authentication.") 363 user, err = auth.ExtractUsernameFromAccessToken(rtDetails.AccessToken) 364 if err != nil { 365 return 366 } 367 password = rtDetails.AccessToken 368 } 369 return 370 } 371 372 func (nca *NugetCommandArgs) createNugetCmd() (*nuget.Cmd, error) { 373 c, err := nuget.NewNugetCmd() 374 if err != nil { 375 return nil, err 376 } 377 if nca.args != "" { 378 c.Command, err = shellwords.Parse(nca.args) 379 if err != nil { 380 return nil, errorutils.CheckError(err) 381 } 382 } 383 384 if nca.flags != "" { 385 c.CommandFlags, err = shellwords.Parse(nca.flags) 386 } 387 388 return c, errorutils.CheckError(err) 389 }