github.com/jfrog/jfrog-cli-go@v1.22.1-0.20200318093948-4826ef344ffd/artifactory/utils/pip/setuppy.go (about) 1 package pip 2 3 import ( 4 "errors" 5 "fmt" 6 gofrogcmd "github.com/jfrog/gofrog/io" 7 "github.com/jfrog/jfrog-client-go/utils" 8 "github.com/jfrog/jfrog-client-go/utils/errorutils" 9 "github.com/jfrog/jfrog-client-go/utils/io/fileutils" 10 "io/ioutil" 11 "os" 12 ) 13 14 // Get the project-name by running 'egg_info' command on setup.py and extracting it from 'PKG-INFO' file. 15 func ExtractPackageNameFromSetupPy(setuppyFilePath, pythonExecutablePath string) (string, error) { 16 // Execute egg_info command and return PKG-INFO content. 17 content, err := getEgginfoPkginfoContent(setuppyFilePath, pythonExecutablePath) 18 if err != nil { 19 return "", err 20 } 21 22 // Extract project name from file content. 23 return getProjectNameFromFileContent(content) 24 } 25 26 // Get package-name from PKG-INFO file content. 27 // If pattern of package-name not found, return an error. 28 func getProjectNameFromFileContent(content []byte) (string, error) { 29 // Create package-name regexp. 30 packageNameRegexp, err := utils.GetRegExp(`(?m)^Name\:\s(\w[\w-\.]+)`) 31 if err != nil { 32 return "", err 33 } 34 35 // Find first match of packageNameRegexp. 36 match := packageNameRegexp.FindStringSubmatch(string(content)) 37 if len(match) < 2 { 38 return "", errorutils.CheckError(errors.New("Failed extracting package name from content.")) 39 } 40 41 return match[1], nil 42 } 43 44 // Run egg-info command on setup.py, the command generates metadata files. 45 // Return the content of the 'PKG-INFO' file. 46 func getEgginfoPkginfoContent(setuppyFilePath, pythonExecutablePath string) ([]byte, error) { 47 tempDirPath, err := fileutils.CreateTempDir() 48 if err != nil { 49 return nil, err 50 } 51 defer fileutils.RemoveTempDir(tempDirPath) 52 53 // Change work-dir to temp, preserve current work-dir when method ends. 54 wd, err := os.Getwd() 55 if errorutils.CheckError(err) != nil { 56 return nil, err 57 } 58 defer os.Chdir(wd) 59 err = os.Chdir(tempDirPath) 60 if errorutils.CheckError(err) != nil { 61 return nil, err 62 } 63 64 // Run python egg_info command. 65 egginfoOutput, err := executeEgginfoCommandWithOutput(pythonExecutablePath, setuppyFilePath) 66 if err != nil { 67 return nil, errorutils.CheckError(err) 68 } 69 70 // Parse egg_info execution output to find PKG-INFO path. 71 pkginfoPath, err := extractPkginfoPathFromCommandOutput(egginfoOutput) 72 if err != nil { 73 return nil, err 74 } 75 76 // Read PKG-INFO file. 77 pkginfoFileExists, err := fileutils.IsFileExists(pkginfoPath, false) 78 if !pkginfoFileExists { 79 return nil, errorutils.CheckError(errors.New(fmt.Sprintf("File 'PKG-INFO' couldn't be found in its designated location: %s", pkginfoPath))) 80 } 81 82 return ioutil.ReadFile(pkginfoPath) 83 } 84 85 // Parse the output of 'python egg_info' command, in order to find the path of generated file 'PKG-INFO'. 86 func extractPkginfoPathFromCommandOutput(egginfoOutput string) (string, error) { 87 // Regexp for extracting 'PKG-INFO' file-path from the 'egg_info' command output. 88 pkginfoRegexp, err := utils.GetRegExp(`(?m)writing\s(\w[\w-\.]+\.egg\-info[\\\/]PKG-INFO)`) 89 if err != nil { 90 return "", err 91 } 92 93 matchedOutputLines := pkginfoRegexp.FindAllString(egginfoOutput, -1) 94 if len(matchedOutputLines) != 1 { 95 return "", errorutils.CheckError(errors.New("Failed parsing egg_info command, couldn't find PKG-INFO location.")) 96 } 97 98 // Extract path from matched line. 99 matchedResults := pkginfoRegexp.FindStringSubmatch(matchedOutputLines[0]) 100 return matchedResults[1], nil 101 } 102 103 // Execute egg_info command for setup.py, return command's output. 104 func executeEgginfoCommandWithOutput(pythonExecutablePath, setuppyFilePath string) (string, error) { 105 pythonEggInfoCmd := &PipCmd{ 106 Executable: pythonExecutablePath, 107 Command: setuppyFilePath, 108 CommandArgs: []string{"egg_info"}, 109 } 110 return gofrogcmd.RunCmdOutput(pythonEggInfoCmd) 111 }