github.com/jfrog/jfrog-cli-core@v1.12.1/artifactory/utils/pip/setuppy.go (about)

     1  package pip
     2  
     3  import (
     4  	"errors"
     5  	"os"
     6  	"os/exec"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	"github.com/jfrog/jfrog-client-go/utils"
    11  	"github.com/jfrog/jfrog-client-go/utils/errorutils"
    12  	"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
    13  )
    14  
    15  // Get the project-name by running 'egg_info' command on setup.py and extracting it from 'PKG-INFO' file.
    16  func ExtractPackageNameFromSetupPy(setuppyFilePath, pythonExecutablePath string) (string, error) {
    17  	// Execute egg_info command and return PKG-INFO content.
    18  	content, err := getEgginfoPkginfoContent(setuppyFilePath, pythonExecutablePath)
    19  	if err != nil {
    20  		return "", err
    21  	}
    22  
    23  	// Extract project name from file content.
    24  	return getProjectNameFromFileContent(content)
    25  }
    26  
    27  // Get package-name from PKG-INFO file content.
    28  // If pattern of package-name not found, return an error.
    29  func getProjectNameFromFileContent(content []byte) (string, error) {
    30  	// Create package-name regexp.
    31  	packageNameRegexp, err := utils.GetRegExp(`(?m)^Name\:\s(\w[\w-\.]+)`)
    32  	if err != nil {
    33  		return "", err
    34  	}
    35  
    36  	// Find first match of packageNameRegexp.
    37  	match := packageNameRegexp.FindStringSubmatch(string(content))
    38  	if len(match) < 2 {
    39  		return "", errorutils.CheckError(errors.New("Failed extracting package name from content."))
    40  	}
    41  
    42  	return match[1], nil
    43  }
    44  
    45  // Run egg-info command on setup.py, the command generates metadata files.
    46  // Return the content of the 'PKG-INFO' file.
    47  func getEgginfoPkginfoContent(setuppyFilePath, pythonExecutablePath string) ([]byte, error) {
    48  	eggBase, err := fileutils.CreateTempDir()
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  	defer fileutils.RemoveTempDir(eggBase)
    53  
    54  	// Execute the egg_info command.
    55  	if err = exec.Command(pythonExecutablePath, setuppyFilePath, "egg_info", "--egg-base", eggBase).Run(); err != nil {
    56  		return nil, errorutils.CheckError(err)
    57  	}
    58  
    59  	// Read PKG_INFO under <eggBase>/*.egg-info/PKG-INFO.
    60  	return extractPackageNameFromEggBase(eggBase)
    61  }
    62  
    63  // Parse the output of 'python egg_info' command, in order to find the path of generated file 'PKG-INFO'.
    64  func extractPackageNameFromEggBase(eggBase string) ([]byte, error) {
    65  	files, err := os.ReadDir(eggBase)
    66  	if errorutils.CheckError(err) != nil {
    67  		return nil, err
    68  	}
    69  	for _, file := range files {
    70  		if strings.HasSuffix(file.Name(), ".egg-info") {
    71  			pkginfoPath := filepath.Join(eggBase, file.Name(), "PKG-INFO")
    72  			// Read PKG-INFO file.
    73  			pkginfoFileExists, err := fileutils.IsFileExists(pkginfoPath, false)
    74  			if errorutils.CheckError(err) != nil {
    75  				return nil, err
    76  			}
    77  			if !pkginfoFileExists {
    78  				return nil, errorutils.CheckError(errors.New("File 'PKG-INFO' couldn't be found in its designated location: " + pkginfoPath))
    79  			}
    80  
    81  			return os.ReadFile(pkginfoPath)
    82  		}
    83  	}
    84  
    85  	return nil, errorutils.CheckError(errors.New("couldn't find pkg info files"))
    86  }