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