github.com/artisanhe/tools@v1.0.1-0.20210607022958-19a8fef2eb04/docker/dockerfile.go (about) 1 package docker 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "reflect" 7 "strconv" 8 "strings" 9 10 "github.com/artisanhe/tools/executil" 11 "github.com/artisanhe/tools/godash" 12 ) 13 14 func EnvVarInDocker(key string) string { 15 return fmt.Sprintf("$${%s}", key) 16 } 17 18 func EnvVar(key string) string { 19 return fmt.Sprintf("${%s}", key) 20 } 21 22 type Dockerfile struct { 23 From string `docker:"FROM" yaml:"from,omitempty"` 24 Image string `yaml:"image"` 25 Label map[string]string `docker:"LABEL,multi" yaml:"label,omitempty"` 26 Run string `docker:"RUN,inline" yaml:"run,omitempty"` 27 WorkDir string `docker:"WORKDIR" yaml:"workdir,omitempty"` 28 Env map[string]string `docker:"ENV,multi" yaml:"env,omitempty"` 29 Add map[string]string `docker:"ADD,join" yaml:"add,omitempty"` 30 Expose []string `docker:"EXPOSE" yaml:"expose,omitempty"` 31 Volume []string `docker:"VOLUME,array" yaml:"volume,omitempty"` 32 Cmd []string `docker:"CMD,array" yaml:"cmd,omitempty"` 33 EntryPoint []string `docker:"ENTRYPOINT,array" yaml:"entrypoint,omitempty"` 34 } 35 36 func (d *Dockerfile) String() string { 37 envVars := executil.EnvVars{} 38 envVars.LoadFromEnviron() 39 return envVars.Parse(GetDockerfileTemplate(*d)) 40 } 41 42 func (d Dockerfile) AddContent(from string, to string) *Dockerfile { 43 if d.Add == nil { 44 d.Add = map[string]string{} 45 } 46 d.Add[from] = to 47 return &d 48 } 49 50 func (d Dockerfile) AddLabel(label string, content string) *Dockerfile { 51 if d.Label == nil { 52 d.Label = map[string]string{} 53 } 54 d.Label[label] = content 55 return &d 56 } 57 58 func (d Dockerfile) AddEnv(key string, value string) *Dockerfile { 59 if d.Env == nil { 60 d.Env = map[string]string{} 61 } 62 d.Env[key] = value 63 return &d 64 } 65 66 func (d Dockerfile) WithExpose(exposes ...string) *Dockerfile { 67 d.Expose = exposes 68 return &d 69 } 70 71 func (d Dockerfile) WithVolume(volumes ...string) *Dockerfile { 72 d.Volume = volumes 73 return &d 74 } 75 76 func (d Dockerfile) WithWorkDir(dir string) *Dockerfile { 77 d.WorkDir = dir 78 return &d 79 } 80 81 func (d Dockerfile) WithCmd(cmd ...string) *Dockerfile { 82 d.Cmd = cmd 83 return &d 84 } 85 86 func GetDockerfileTemplate(d Dockerfile) string { 87 dockerfileConfig := make([]string, 0) 88 89 appendDockerConfig := func(dockerKey string, value string) { 90 dockerfileConfig = append( 91 dockerfileConfig, 92 strings.Join([]string{dockerKey, value}, " "), 93 ) 94 } 95 96 tpe := reflect.TypeOf(d) 97 rv := reflect.Indirect(reflect.ValueOf(d)) 98 99 for i := 0; i < tpe.NumField(); i++ { 100 field := tpe.Field(i) 101 dockerTag := field.Tag.Get("docker") 102 dockerKeys := strings.Split(dockerTag, ",") 103 dockerKey := dockerKeys[0] 104 dockerFlags := dockerKeys[1:] 105 106 if len(dockerKey) > 0 { 107 value := rv.FieldByName(field.Name) 108 109 switch field.Type.Kind() { 110 case reflect.String: 111 if len(value.String()) > 0 { 112 inline := godash.StringIncludes(dockerFlags, "inline") 113 if inline { 114 appendDockerConfig(dockerKey, value.String()) 115 } else { 116 appendDockerConfig(dockerKey, mayQuote(value.String())) 117 } 118 } 119 case reflect.Slice: 120 jsonArray := godash.StringIncludes(dockerFlags, "array") 121 slice := make([]string, 0) 122 for i := 0; i < value.Len(); i++ { 123 slice = append(slice, value.Index(i).String()) 124 } 125 if len(slice) > 0 { 126 if jsonArray { 127 jsonString, err := json.Marshal(slice) 128 if err != nil { 129 panic(err) 130 } 131 appendDockerConfig( 132 dockerKey, 133 string(jsonString), 134 ) 135 } else { 136 appendDockerConfig( 137 dockerKey, 138 strings.Join(slice, ""), 139 ) 140 } 141 } 142 143 case reflect.Map: 144 multi := godash.StringIncludes(dockerFlags, "multi") 145 join := godash.StringIncludes(dockerFlags, "join") 146 147 if join { 148 destMap := map[string][]string{} 149 for _, key := range value.MapKeys() { 150 dest := value.MapIndex(key).String() 151 if destMap[dest] == nil { 152 destMap[dest] = []string{} 153 } 154 destMap[dest] = append(destMap[dest], key.String()) 155 } 156 for dest, src := range destMap { 157 appendDockerConfig( 158 dockerKey, 159 strings.Join(append(src, dest), " "), 160 ) 161 } 162 } else if multi { 163 keyValues := []string{} 164 for _, key := range value.MapKeys() { 165 keyValues = append( 166 keyValues, 167 key.String()+"="+mayQuote(value.MapIndex(key).String()), 168 ) 169 } 170 if len(keyValues) > 0 { 171 appendDockerConfig( 172 dockerKey, 173 strings.Join(keyValues, " "), 174 ) 175 } 176 } else { 177 for _, key := range value.MapKeys() { 178 appendDockerConfig( 179 dockerKey, 180 strings.Join([]string{key.String(), mayQuote(value.MapIndex(key).String())}, " "), 181 ) 182 } 183 } 184 } 185 } 186 } 187 188 return strings.Join(dockerfileConfig, "\n") 189 } 190 191 func mayQuote(s string) string { 192 if s == "" || strings.Index(s, " ") > -1 { 193 return strconv.Quote(s) 194 } 195 return s 196 }