github.com/mattevans/edward@v1.9.2/edward/client.go (about) 1 package edward 2 3 import ( 4 "log" 5 "os" 6 7 "github.com/pkg/errors" 8 "github.com/mattevans/edward/builder" 9 "github.com/mattevans/edward/home" 10 "github.com/mattevans/edward/instance" 11 "github.com/mattevans/edward/output" 12 "github.com/mattevans/edward/services" 13 "github.com/mattevans/edward/tracker" 14 "github.com/mattevans/edward/ui" 15 "github.com/mattevans/edward/ui/terminal" 16 "github.com/mattevans/edward/worker" 17 ) 18 19 type Client struct { 20 UI ui.Provider 21 22 Config string 23 24 ServiceChecks func([]services.ServiceOrGroup) error 25 26 EdwardExecutable string 27 28 LogFile string // Path to log file 29 30 Follower TaskFollower 31 32 // Prevent build, launch and stop phases from running concurrently 33 DisableConcurrentPhases bool 34 35 WorkingDir string 36 37 telemetryScript string 38 39 basePath string 40 groupMap map[string]*services.ServiceGroupConfig 41 serviceMap map[string]*services.ServiceConfig 42 43 Tags []string // Tags to distinguish runners started by this instance of edward 44 45 DirConfig *home.EdwardConfiguration 46 47 Backends map[string]string // Service overrides for backends 48 } 49 50 type TaskFollower interface { 51 Handle(update tracker.Task) 52 Done() 53 } 54 55 // NewClient creates an edward client an empty configuration 56 func NewClient() (*Client, error) { 57 wd, err := os.Getwd() 58 if err != nil { 59 return nil, errors.WithStack(err) 60 } 61 62 dirCfg, err := home.NewConfiguration("") 63 if err != nil { 64 return nil, errors.WithStack(err) 65 } 66 67 return &Client{ 68 UI: &terminal.Provider{}, 69 Follower: output.NewFollower(), 70 WorkingDir: wd, 71 groupMap: make(map[string]*services.ServiceGroupConfig), 72 serviceMap: make(map[string]*services.ServiceConfig), 73 DirConfig: dirCfg, 74 }, nil 75 } 76 77 // NewClientWithConfig creates an Edward client and loads the config from the given path 78 func NewClientWithConfig(configPath, version string) (*Client, error) { 79 wd, err := os.Getwd() 80 if err != nil { 81 return nil, errors.WithStack(err) 82 } 83 84 dirCfg, err := home.NewConfiguration("") 85 if err != nil { 86 return nil, errors.WithStack(err) 87 } 88 89 client := &Client{ 90 UI: &terminal.Provider{}, 91 Follower: output.NewFollower(), 92 WorkingDir: wd, 93 Config: configPath, 94 groupMap: make(map[string]*services.ServiceGroupConfig), 95 serviceMap: make(map[string]*services.ServiceConfig), 96 DirConfig: dirCfg, 97 } 98 err = client.LoadConfig(version) 99 return client, errors.WithStack(err) 100 } 101 102 func (c *Client) BasePath() string { 103 return c.basePath 104 } 105 106 func (c *Client) ServiceMap() map[string]*services.ServiceConfig { 107 return c.serviceMap 108 } 109 110 func (c *Client) startAndTrack(sgs []services.ServiceOrGroup, skipBuild bool, noWatch bool, exclude []string, edwardExecutable string) error { 111 cfg := services.OperationConfig{ 112 WorkingDir: c.WorkingDir, 113 EdwardExecutable: edwardExecutable, 114 Exclusions: exclude, 115 SkipBuild: skipBuild, 116 NoWatch: noWatch, 117 Tags: c.Tags, 118 LogFile: c.LogFile, 119 Backends: c.Backends, 120 } 121 122 task := tracker.NewTask(c.Follower.Handle) 123 defer c.Follower.Done() 124 125 poolSize := 1 126 if c.DisableConcurrentPhases { 127 poolSize = 0 128 } 129 p := worker.NewPool(poolSize) 130 p.Start() 131 var err error 132 err = services.DoForServices(sgs, task, func(s *services.ServiceConfig, overrides services.ContextOverride, task tracker.Task) error { 133 if skipBuild { 134 log.Println("skipping build phase") 135 err = instance.Launch(c.DirConfig, s, cfg, overrides, task, p) 136 if err != nil { 137 return errors.WithMessage(err, "Error launching "+s.GetName()) 138 } 139 } else { 140 if cfg.IsExcluded(s) { 141 return nil 142 } 143 log.Printf("Building: %s", s.Name) 144 b := builder.New(cfg, overrides) 145 err := b.Build(c.DirConfig, task, s) 146 if err != nil { 147 return errors.WithMessage(err, "Error starting "+s.GetName()+": build") 148 } 149 log.Printf("Launching: %s", s.Name) 150 err = instance.Launch(c.DirConfig, s, cfg, overrides, task, p) 151 return errors.WithMessage(err, "Error starting "+s.GetName()+": launch") 152 } 153 return nil 154 }) 155 if err != nil { 156 return errors.WithStack(err) 157 } 158 159 p.Stop() 160 _ = <-p.Complete() 161 return p.Err() 162 } 163 164 func (c *Client) askForConfirmation(question string) bool { 165 166 // Skip confirmations for children. For example, for enabling sudo. 167 isChild := os.Getenv("ISCHILD") 168 if isChild != "" { 169 return true 170 } 171 172 return c.UI.Confirm(question) 173 }