setup.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. package python
  2. import (
  3. _ "embed"
  4. "fmt"
  5. "os"
  6. "os/exec"
  7. "path"
  8. "regexp"
  9. "strings"
  10. "github.com/langgenius/dify-sandbox/internal/core/runner"
  11. python_dependencies "github.com/langgenius/dify-sandbox/internal/core/runner/python/dependencies"
  12. "github.com/langgenius/dify-sandbox/internal/core/runner/types"
  13. "github.com/langgenius/dify-sandbox/internal/utils/log"
  14. )
  15. //go:embed python.so
  16. var python_lib []byte
  17. func init() {
  18. log.Info("initializing python runner environment...")
  19. // remove /tmp/sandbox-python
  20. os.RemoveAll("/tmp/sandbox-python")
  21. os.Remove("/tmp/sandbox-python")
  22. err := os.MkdirAll("/tmp/sandbox-python", 0755)
  23. if err != nil {
  24. log.Panic("failed to create /tmp/sandbox-python")
  25. }
  26. err = os.WriteFile("/tmp/sandbox-python/python.so", python_lib, 0755)
  27. if err != nil {
  28. log.Panic("failed to write /tmp/sandbox-python/python.so")
  29. }
  30. log.Info("python runner environment initialized")
  31. }
  32. func ExtractOnelineDepency(dependency string) (string, string) {
  33. delimiters := []string{"==", ">=", "<=", "~="}
  34. for _, delimiter := range delimiters {
  35. if strings.Contains(dependency, delimiter) {
  36. parts := strings.Split(dependency, delimiter)
  37. if len(parts) >= 2 {
  38. return parts[0], parts[1]
  39. } else if len(parts) == 1 {
  40. return parts[0], ""
  41. } else if len(parts) == 0 {
  42. return "", ""
  43. }
  44. }
  45. }
  46. preg := regexp.MustCompile(`([a-zA-Z0-9_-]+)`)
  47. if preg.MatchString(dependency) {
  48. return dependency, ""
  49. }
  50. return "", ""
  51. }
  52. func InstallDependencies(requirements string) error {
  53. if requirements == "" {
  54. return nil
  55. }
  56. runner := runner.TempDirRunner{}
  57. return runner.WithTempDir([]string{}, func(root_path string) error {
  58. defer os.Remove(root_path)
  59. defer os.RemoveAll(root_path)
  60. // create a requirements file
  61. err := os.WriteFile(path.Join(root_path, "requirements.txt"), []byte(requirements), 0644)
  62. if err != nil {
  63. log.Error("failed to create requirements.txt")
  64. return nil
  65. }
  66. // install dependencies
  67. cmd := exec.Command("pip3", "install", "-r", "requirements.txt")
  68. reader, err := cmd.StdoutPipe()
  69. if err != nil {
  70. log.Panic("failed to get stdout pipe of pip3")
  71. }
  72. defer reader.Close()
  73. err = cmd.Start()
  74. if err != nil {
  75. log.Error("failed to start pip3")
  76. return nil
  77. }
  78. for {
  79. buf := make([]byte, 1024)
  80. n, err := reader.Read(buf)
  81. if err != nil {
  82. break
  83. }
  84. log.Info(string(buf[:n]))
  85. }
  86. status := cmd.Wait()
  87. if status != nil {
  88. log.Error("failed to install dependencies")
  89. return nil
  90. }
  91. // split the requirements
  92. requirements = strings.ReplaceAll(requirements, "\r\n", "\n")
  93. requirements = strings.ReplaceAll(requirements, "\r", "\n")
  94. lines := strings.Split(requirements, "\n")
  95. for _, line := range lines {
  96. package_name, version := ExtractOnelineDepency(line)
  97. if package_name == "" {
  98. continue
  99. }
  100. python_dependencies.SetupDependency(package_name, version, fmt.Sprintf("import %s", package_name))
  101. log.Info("Python dependency installed: %s %s", package_name, version)
  102. }
  103. return nil
  104. })
  105. }
  106. func ListDependencies() []types.Dependency {
  107. return python_dependencies.ListDependencies()
  108. }