github.com/profzone/eden-framework@v1.0.10/internal/project/project.go (about) 1 package project 2 3 import ( 4 "fmt" 5 "github.com/profzone/eden-framework/pkg/executil" 6 "gopkg.in/yaml.v2" 7 "io/ioutil" 8 "os" 9 "os/exec" 10 "path" 11 "reflect" 12 "runtime" 13 "strconv" 14 "strings" 15 ) 16 17 const DefaultConfigFile = "project.yml" 18 19 const ( 20 DockerRegistry = "registry.cn-hangzhou.aliyuncs.com" 21 ) 22 23 type Project struct { 24 Name string `env:"name" yaml:"name"` 25 Group string `env:"group" yaml:"group,omitempty"` 26 Owner string `env:"owner" yaml:"owner,omitempty"` 27 Version Version `env:"version" yaml:"version"` 28 Desc string `env:"description" yaml:"description"` 29 ProgramLanguage string `env:"program_language" yaml:"program_language"` 30 Workflow Workflow `yaml:"workflow,omitempty"` 31 Scripts map[string]Script `yaml:"scripts,omitempty"` 32 Feature string `yaml:"feature,omitempty"` 33 Selector string `env:"selector" yaml:"-"` 34 } 35 36 func (p *Project) UnmarshalFromFile(filePath, fileName string) error { 37 if fileName == "" { 38 fileName = DefaultConfigFile 39 } 40 bytes, err := ioutil.ReadFile(path.Join(filePath, fileName)) 41 if err != nil { 42 return err 43 } 44 errForUnmarshal := yaml.Unmarshal(bytes, p) 45 if errForUnmarshal != nil { 46 return errForUnmarshal 47 } 48 return nil 49 } 50 51 func (p Project) WithVersion(s string) Project { 52 v, err := FromVersionString(s) 53 if err != nil { 54 panic(err) 55 } 56 p.Version = *v 57 return p 58 } 59 60 func (p Project) WithGroup(group string) Project { 61 p.Group = group 62 return p 63 } 64 65 func (p Project) WithOwner(owner string) Project { 66 p.Owner = owner 67 return p 68 } 69 70 func (p Project) WithDesc(desc string) Project { 71 p.Desc = desc 72 return p 73 } 74 75 func (p Project) WithName(name string) Project { 76 p.Name = name 77 return p 78 } 79 80 func (p Project) WithLanguage(pl string) Project { 81 p.ProgramLanguage = pl 82 return p 83 } 84 85 func (p Project) WithWorkflow(workflow string) Project { 86 p.Workflow.Extends = workflow 87 return p 88 } 89 90 func (p Project) WithFeature(f string) Project { 91 p.Feature = f 92 return p 93 } 94 95 func (p Project) WithScripts(key string, scripts ...string) Project { 96 if p.Scripts == nil { 97 p.Scripts = map[string]Script{} 98 } 99 p.Scripts[key] = append(Script{}, scripts...) 100 return p 101 } 102 103 func WrapEnv(s string) string { 104 return strings.ToUpper("PROJECT_" + s) 105 } 106 107 func SetEnv(k string, v string) { 108 os.Setenv(k, v) 109 fmt.Printf("export %s=%s\n", k, v) 110 } 111 112 func (p *Project) SetEnviron() { 113 if os.Getenv(EnvKeyDockerRegistryKey) == "" { 114 SetEnv(EnvKeyDockerRegistryKey, DockerRegistry) 115 } 116 117 tpe := reflect.TypeOf(p).Elem() 118 rv := reflect.Indirect(reflect.ValueOf(p)) 119 120 for i := 0; i < tpe.NumField(); i++ { 121 field := tpe.Field(i) 122 env := field.Tag.Get("env") 123 124 if len(env) > 0 { 125 value := rv.FieldByName(field.Name) 126 127 if stringer, ok := value.Interface().(fmt.Stringer); ok { 128 v := stringer.String() 129 if len(v) > 0 { 130 SetEnv(WrapEnv(env), v) 131 } 132 } else { 133 SetEnv(WrapEnv(env), value.String()) 134 } 135 } 136 } 137 } 138 139 func (p *Project) Command(args ...string) *exec.Cmd { 140 p.SetEnviron() 141 142 sh := "sh" 143 if runtime.GOOS == "windows" { 144 sh = "bash" 145 } 146 147 envVars := executil.EnvVars{} 148 envVars.LoadFromEnviron() 149 150 return exec.Command(sh, "-c", envVars.Parse(strings.Join(args, " "))) 151 } 152 153 func (p *Project) Run(commands ...*exec.Cmd) { 154 for _, cmd := range commands { 155 if cmd != nil { 156 executil.StdRun(cmd) 157 } 158 } 159 } 160 161 func (p *Project) RunScript(key string, inDocker bool) error { 162 if _, ok := p.Scripts[key]; !ok { 163 return fmt.Errorf("script %s not defined", key) 164 } 165 166 s := p.Scripts[key] 167 168 if inDocker { 169 builder := RegisteredBuilders.GetBuilderBy(p.ProgramLanguage) 170 if builder == nil { 171 return fmt.Errorf("no builder for %s", p.ProgramLanguage) 172 } 173 p.Run( 174 p.Command(fmt.Sprintf( 175 "docker run --rm -v ${PWD}:%s -w %s %s sh -c %s", 176 builder.WorkingDir, 177 builder.WorkingDir, 178 FullImage(builder.Image), 179 strconv.Quote(s.String()), 180 )), 181 ) 182 return nil 183 } 184 185 p.Run(p.Command(s.String())) 186 return nil 187 } 188 189 func (p *Project) Execute(args ...string) { 190 p.Run(p.Command(args...)) 191 } 192 193 func (p *Project) WriteToFile(filePath, fileName string) { 194 if fileName == "" { 195 fileName = DefaultConfigFile 196 } 197 bytes, err := yaml.Marshal(p) 198 if err != nil { 199 panic(err) 200 } 201 ioutil.WriteFile(path.Join(filePath, fileName), bytes, os.ModePerm) 202 } 203 204 func (p *Project) String() string { 205 bytes, err := yaml.Marshal(p) 206 if err != nil { 207 panic(err) 208 } 209 210 return string(bytes) 211 } 212 213 type Script []string 214 215 func (s Script) IsZero() bool { 216 return len(s) == 0 217 } 218 219 func (s Script) String() string { 220 return strings.Join(s, " && ") 221 } 222 223 func (s Script) MarshalYAML() (interface{}, error) { 224 if len(s) > 1 { 225 return s, nil 226 } 227 return s[0], nil 228 } 229 230 func (s *Script) UnmarshalYAML(unmarshal func(interface{}) error) error { 231 var str string 232 err := unmarshal(&str) 233 if err == nil { 234 *s = []string{str} 235 } else { 236 var values []string 237 err := unmarshal(&values) 238 if err != nil { 239 return err 240 } 241 *s = values 242 } 243 return nil 244 }