123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- package common
- import (
- "encoding/json"
- "fmt"
- "os/exec"
- "regexp"
- "strings"
- "github.com/jeremywohl/flatten"
- )
- type Command struct {
- Id string `json:"id"`
- Cmd string `json:"cmd"`
- IgnoreErros bool `json:"ignore.errors"`
- }
- type BuildSet struct {
- Modes map[string]*BuildMode `json:"modes"`
- Cmd string `json:"cmd"`
- Workdir string `json:"workdir"`
- Steps []*Command `json:"steps"`
- Options *BuildOptions `json:"options"`
- }
- func (b *BuildSet) Commands() []*Command {
- var (
- mode *BuildMode
- ok, ignore bool
- steps = []*Command{}
- modeKey = b.Options.Mode
- )
- if modeKey == "" {
- modeKey = "default"
- }
- if mode, ok = b.Modes[modeKey]; !ok {
- panic(fmt.Sprintf("Build mode '%s' not defined", modeKey))
- }
- if (len(mode.Ignore) == 0) &&
- len(mode.ExecuteOnly) == 0 {
- return b.Steps
- }
- ignore = len(mode.Ignore) > 0
- if ignore && len(mode.ExecuteOnly) > 0 {
- panic("Ignore and ExecuteOnly are mutually exclusive")
- }
- ids := map[string]bool{}
- for _, v := range append(mode.Ignore, mode.ExecuteOnly...) {
- ids[v] = true
- }
- if ignore {
- for _, step := range b.Steps {
- if _, ok := ids[step.Id]; !ok {
- steps = append(steps, step)
- }
- }
- } else {
- for _, step := range b.Steps {
- if _, ok := ids[step.Id]; ok {
- steps = append(steps, step)
- }
- }
- }
- return steps
- }
- type BuildMode struct {
- Ignore []string `json:"ignore"`
- ExecuteOnly []string `json:"executeOnly"`
- }
- var (
- buildSet = &BuildSet{
- Steps: []*Command{},
- Modes: map[string]*BuildMode{
- "default": &BuildMode{},
- },
- }
- )
- func NewBuildOptions() *BuildOptions {
- return &BuildOptions{
- Mode: "default",
- }
- }
- func RunBuildCommads(project *Project, buildOptions *BuildOptions) (err error) {
- var (
- instance *exec.Cmd
- variables = map[string]interface{}{}
- variablesJson, cmd string
- step int
- out []byte
- buildfile = "build/build"
- mode = project.Mode
- )
- if out, err = json.Marshal(project); err != nil {
- return
- }
- if variablesJson, err = flatten.FlattenString(string(out), "project.", flatten.DotStyle); err != nil {
- return
- }
- if err = json.Unmarshal([]byte(variablesJson), &variables); err != nil {
- return
- }
- if buildOptions == nil {
- buildOptions = NewBuildOptions()
- }
- buildOptions.Parse()
- if err = JsonParseMode(buildfile, mode, &buildSet); err != nil {
- return
- }
- buildSet.Options = buildOptions
- fmt.Println("Running build commands... on mode ", mode)
- cmds := buildSet.Commands()
- total := len(cmds)
- for k, command := range cmds {
- if cmd, err = parseCommand(command, variables); err != nil {
- return
- }
- step = k + 1
- if buildOptions.IgnoreStep(step) {
- fmt.Printf("Step (%d / %d) - [ Skiped ] %s\n", step, total, cmd)
- continue
- }
- fmt.Printf("Step (%d / %d) - %s\n", step, total, cmd)
- instance = exec.Command("sh", "-c", cmd)
- instance.Dir = buildSet.Workdir
- if out, err = instance.CombinedOutput(); err != nil {
- fmt.Println(string(out))
- return
- }
- }
- return
- }
- var (
- expressionRegexp = regexp.MustCompile(`\{([\w\.]+)\}`)
- )
- func parseCommand(c *Command, variables map[string]interface{}) (string, error) {
- var (
- expression, replace, dotPathName string
- cmd = c.Cmd
- matches = expressionRegexp.FindAllStringSubmatch(cmd, -1)
- )
- for _, match := range matches {
- dotPathName = match[1]
- if value, exists := variables[dotPathName]; !exists || value == nil {
- return "", fmt.Errorf("Value for expression '%s' not defined", dotPathName)
- }
- expression = match[0]
- replace = fmt.Sprintf("%v", variables[dotPathName])
- cmd = strings.ReplaceAll(cmd, expression, replace)
- }
- return cmd, nil
- }
|