Skip to content

Commit

Permalink
Fix Pipenv graph invalid JSON (#290)
Browse files Browse the repository at this point in the history
  • Loading branch information
attiasas authored Jan 6, 2025
1 parent 91828d4 commit f25981f
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 5 deletions.
2 changes: 1 addition & 1 deletion build/python.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (pm *PythonModule) RunInstallAndCollectDependencies(commandArgs []string) e
if err != nil {
return err
}
dependenciesGraph, topLevelPackagesList, err := pythonutils.GetPythonDependencies(pm.tool, pm.srcPath, pm.localDependenciesPath)
dependenciesGraph, topLevelPackagesList, err := pythonutils.GetPythonDependencies(pm.tool, pm.srcPath, pm.localDependenciesPath, pm.containingBuild.logger)
if err != nil {
return fmt.Errorf("failed while attempting to get %s dependencies graph: %s", pm.tool, err.Error())
}
Expand Down
24 changes: 22 additions & 2 deletions utils/pythonutils/pipenvutils.go
Original file line number Diff line number Diff line change
@@ -1,29 +1,49 @@
package pythonutils

import (
"bytes"
"encoding/json"
"fmt"

"github.com/jfrog/build-info-go/utils"
"github.com/jfrog/gofrog/io"
)

var (
windowsReplaceBytes = []byte("\r\n")
unixReplaceBytes = []byte("\n")
replacementBytes = []byte("")
)

// Executes pipenv graph.
// Returns a dependency map of all the installed pipenv packages in the current environment and also another list of the top level dependencies
// 'dependenciesGraph' - map between all parent modules and their child dependencies
// 'topLevelPackagesList' - list of all top level dependencies ( root dependencies only)
func getPipenvDependencies(srcPath string) (dependenciesGraph map[string][]string, topLevelDependencies []string, err error) {
func getPipenvDependencies(srcPath string, logger utils.Log) (dependenciesGraph map[string][]string, topLevelDependencies []string, err error) {
// Run pipenv graph
pipenvGraphCmd := io.NewCommand("pipenv", "graph", []string{"--json"})
pipenvGraphCmd.Dir = srcPath
output, err := pipenvGraphCmd.RunWithOutput()
if err != nil {
err = fmt.Errorf("failed to run pipenv graph --json: %s", err.Error())
return
}
logger.Debug("pipenv graph --json output:\n" + string(output))
// Parse into array.
packages := make([]pythonDependencyPackage, 0)
err = json.Unmarshal(output, &packages)
err = json.Unmarshal(cleanJsonOutput(output), &packages)
if err != nil {
err = fmt.Errorf("failed to parse pipenv graph --json output: %s", err.Error())
return
}
dependenciesGraph, topLevelDependencies, err = parseDependenciesToGraph(packages)
return
}

// Sometimes, `pipenv graph --json` command returns output with new line characters in between (not valid json) So, we need to remove them before unmarshaling.
func cleanJsonOutput(output []byte) []byte {
// For Windows
output = bytes.ReplaceAll(output, windowsReplaceBytes, replacementBytes)
// For Unix
return bytes.ReplaceAll(output, unixReplaceBytes, replacementBytes)
}
4 changes: 2 additions & 2 deletions utils/pythonutils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,12 @@ func GetPythonDependenciesFiles(tool PythonTool, args []string, buildName, build
}
}

func GetPythonDependencies(tool PythonTool, srcPath, localDependenciesPath string) (dependenciesGraph map[string][]string, topLevelDependencies []string, err error) {
func GetPythonDependencies(tool PythonTool, srcPath, localDependenciesPath string, logger utils.Log) (dependenciesGraph map[string][]string, topLevelDependencies []string, err error) {
switch tool {
case Pip:
return getPipDependencies(srcPath, localDependenciesPath)
case Pipenv:
return getPipenvDependencies(srcPath)
return getPipenvDependencies(srcPath, logger)
case Poetry:
return getPoetryDependencies(srcPath)
default:
Expand Down

0 comments on commit f25981f

Please sign in to comment.