context.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. package project
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os"
  6. "path"
  7. "path/filepath"
  8. "regexp"
  9. "strings"
  10. "github.com/Sirupsen/logrus"
  11. "github.com/docker/libcompose/config"
  12. "github.com/docker/libcompose/logger"
  13. )
  14. var projectRegexp = regexp.MustCompile("[^a-zA-Z0-9_.-]")
  15. // Context holds context meta information about a libcompose project, like
  16. // the project name, the compose file, etc.
  17. type Context struct {
  18. ComposeFiles []string
  19. ComposeBytes [][]byte
  20. ProjectName string
  21. isOpen bool
  22. ServiceFactory ServiceFactory
  23. EnvironmentLookup config.EnvironmentLookup
  24. ResourceLookup config.ResourceLookup
  25. LoggerFactory logger.Factory
  26. IgnoreMissingConfig bool
  27. Project *Project
  28. }
  29. func (c *Context) readComposeFiles() error {
  30. if c.ComposeBytes != nil {
  31. return nil
  32. }
  33. logrus.Debugf("Opening compose files: %s", strings.Join(c.ComposeFiles, ","))
  34. // Handle STDIN (`-f -`)
  35. if len(c.ComposeFiles) == 1 && c.ComposeFiles[0] == "-" {
  36. composeBytes, err := ioutil.ReadAll(os.Stdin)
  37. if err != nil {
  38. logrus.Errorf("Failed to read compose file from stdin: %v", err)
  39. return err
  40. }
  41. c.ComposeBytes = [][]byte{composeBytes}
  42. return nil
  43. }
  44. for _, composeFile := range c.ComposeFiles {
  45. composeBytes, err := ioutil.ReadFile(composeFile)
  46. if err != nil && !os.IsNotExist(err) {
  47. logrus.Errorf("Failed to open the compose file: %s", composeFile)
  48. return err
  49. }
  50. if err != nil && !c.IgnoreMissingConfig {
  51. logrus.Errorf("Failed to find the compose file: %s", composeFile)
  52. return err
  53. }
  54. c.ComposeBytes = append(c.ComposeBytes, composeBytes)
  55. }
  56. return nil
  57. }
  58. func (c *Context) determineProject() error {
  59. name, err := c.lookupProjectName()
  60. if err != nil {
  61. return err
  62. }
  63. c.ProjectName = normalizeName(name)
  64. if c.ProjectName == "" {
  65. return fmt.Errorf("Falied to determine project name")
  66. }
  67. return nil
  68. }
  69. func (c *Context) lookupProjectName() (string, error) {
  70. if c.ProjectName != "" {
  71. return c.ProjectName, nil
  72. }
  73. if envProject := os.Getenv("COMPOSE_PROJECT_NAME"); envProject != "" {
  74. return envProject, nil
  75. }
  76. file := "."
  77. if len(c.ComposeFiles) > 0 {
  78. file = c.ComposeFiles[0]
  79. }
  80. f, err := filepath.Abs(file)
  81. if err != nil {
  82. logrus.Errorf("Failed to get absolute directory for: %s", file)
  83. return "", err
  84. }
  85. f = toUnixPath(f)
  86. parent := path.Base(path.Dir(f))
  87. if parent != "" && parent != "." {
  88. return parent, nil
  89. } else if wd, err := os.Getwd(); err != nil {
  90. return "", err
  91. } else {
  92. return path.Base(toUnixPath(wd)), nil
  93. }
  94. }
  95. func normalizeName(name string) string {
  96. r := regexp.MustCompile("[^a-z0-9]+")
  97. return r.ReplaceAllString(strings.ToLower(name), "")
  98. }
  99. func toUnixPath(p string) string {
  100. return strings.Replace(p, "\\", "/", -1)
  101. }
  102. func (c *Context) open() error {
  103. if c.isOpen {
  104. return nil
  105. }
  106. if err := c.readComposeFiles(); err != nil {
  107. return err
  108. }
  109. if err := c.determineProject(); err != nil {
  110. return err
  111. }
  112. c.isOpen = true
  113. return nil
  114. }