setup.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  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/static"
  11. "github.com/langgenius/dify-sandbox/internal/core/runner"
  12. python_dependencies "github.com/langgenius/dify-sandbox/internal/core/runner/python/dependencies"
  13. "github.com/langgenius/dify-sandbox/internal/core/runner/types"
  14. "github.com/langgenius/dify-sandbox/internal/utils/log"
  15. )
  16. //go:embed python.so
  17. var python_lib []byte
  18. const (
  19. LIB_PATH = "/var/sandbox/sandbox-python"
  20. LIB_NAME = "python.so"
  21. )
  22. func init() {
  23. releaseLibBinary(true)
  24. }
  25. func releaseLibBinary(force_remove_old_lib bool) {
  26. log.Info("initializing python runner environment...")
  27. // remove the old lib
  28. if _, err := os.Stat(path.Join(LIB_PATH, LIB_NAME)); err == nil {
  29. if force_remove_old_lib {
  30. err := os.Remove(path.Join(LIB_PATH, LIB_NAME))
  31. if err != nil {
  32. log.Panic(fmt.Sprintf("failed to remove %s", path.Join(LIB_PATH, LIB_NAME)))
  33. }
  34. // write the new lib
  35. err = os.MkdirAll(LIB_PATH, 0755)
  36. if err != nil {
  37. log.Panic(fmt.Sprintf("failed to create %s", LIB_PATH))
  38. }
  39. err = os.WriteFile(path.Join(LIB_PATH, LIB_NAME), python_lib, 0755)
  40. if err != nil {
  41. log.Panic(fmt.Sprintf("failed to write %s", path.Join(LIB_PATH, LIB_NAME)))
  42. }
  43. }
  44. } else {
  45. err = os.MkdirAll(LIB_PATH, 0755)
  46. if err != nil {
  47. log.Panic(fmt.Sprintf("failed to create %s", LIB_PATH))
  48. }
  49. err = os.WriteFile(path.Join(LIB_PATH, LIB_NAME), python_lib, 0755)
  50. if err != nil {
  51. log.Panic(fmt.Sprintf("failed to write %s", path.Join(LIB_PATH, LIB_NAME)))
  52. }
  53. log.Info("python runner environment initialized")
  54. }
  55. }
  56. func checkLibAvaliable() bool {
  57. if _, err := os.Stat(path.Join(LIB_PATH, LIB_NAME)); err != nil {
  58. return false
  59. }
  60. return true
  61. }
  62. func ExtractOnelineDepency(dependency string) (string, string) {
  63. delimiters := []string{"==", ">=", "<=", "~="}
  64. for _, delimiter := range delimiters {
  65. if strings.Contains(dependency, delimiter) {
  66. parts := strings.Split(dependency, delimiter)
  67. if len(parts) >= 2 {
  68. return parts[0], parts[1]
  69. } else if len(parts) == 1 {
  70. return parts[0], ""
  71. } else if len(parts) == 0 {
  72. return "", ""
  73. }
  74. }
  75. }
  76. preg := regexp.MustCompile(`([a-zA-Z0-9_-]+)`)
  77. if preg.MatchString(dependency) {
  78. return dependency, ""
  79. }
  80. return "", ""
  81. }
  82. func InstallDependencies(requirements string) error {
  83. if requirements == "" {
  84. return nil
  85. }
  86. runner := runner.TempDirRunner{}
  87. return runner.WithTempDir("/", []string{}, func(root_path string) error {
  88. defer os.RemoveAll(root_path)
  89. // create a requirements file
  90. err := os.WriteFile(path.Join(root_path, "requirements.txt"), []byte(requirements), 0644)
  91. if err != nil {
  92. log.Error("failed to create requirements.txt")
  93. return nil
  94. }
  95. // install dependencies
  96. pipMirrorURL := static.GetDifySandboxGlobalConfigurations().PythonPipMirrorURL
  97. // Create the base command
  98. args := []string{"install", "-r", "requirements.txt"}
  99. if pipMirrorURL != "" {
  100. // If a mirror URL is provided, include it in the command arguments
  101. args = append(args, "-i", pipMirrorURL)
  102. }
  103. cmd := exec.Command("pip3", args...)
  104. reader, err := cmd.StdoutPipe()
  105. if err != nil {
  106. log.Panic("failed to get stdout pipe of pip3")
  107. }
  108. defer reader.Close()
  109. err = cmd.Start()
  110. if err != nil {
  111. log.Error("failed to start pip3")
  112. return nil
  113. }
  114. for {
  115. buf := make([]byte, 1024)
  116. n, err := reader.Read(buf)
  117. if err != nil {
  118. break
  119. }
  120. log.Info(string(buf[:n]))
  121. }
  122. status := cmd.Wait()
  123. if status != nil {
  124. log.Error("failed to install dependencies")
  125. return nil
  126. }
  127. // split the requirements
  128. requirements = strings.ReplaceAll(requirements, "\r\n", "\n")
  129. requirements = strings.ReplaceAll(requirements, "\r", "\n")
  130. lines := strings.Split(requirements, "\n")
  131. for _, line := range lines {
  132. package_name, version := ExtractOnelineDepency(line)
  133. if package_name == "" {
  134. continue
  135. }
  136. python_dependencies.SetupDependency(package_name, version)
  137. log.Info("Python dependency installed: %s %s", package_name, version)
  138. }
  139. return nil
  140. })
  141. }
  142. func ListDependencies() []types.Dependency {
  143. return python_dependencies.ListDependencies()
  144. }
  145. func RefreshDependencies() []types.Dependency {
  146. log.Info("updating python dependencies...")
  147. dependencies := static.GetRunnerDependencies()
  148. err := InstallDependencies(dependencies.PythonRequirements)
  149. if err != nil {
  150. log.Error("failed to update python dependencies: %v", err)
  151. }
  152. log.Info("python dependencies updated")
  153. return python_dependencies.ListDependencies()
  154. }