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  }