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