/
cmd_docker.go
167 lines (153 loc) · 5.84 KB
/
cmd_docker.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
package cmd
import (
"context"
"fmt"
"runtime"
"github.com/wowqhb/gf/v2/frame/g"
"github.com/wowqhb/gf/v2/os/gfile"
"github.com/wowqhb/gf/v2/os/gproc"
"github.com/wowqhb/gf/v2/text/gstr"
"github.com/wowqhb/gf/v2/util/gtag"
"github.com/wowqhb/gf/cmd/gf/v2/internal/utility/mlog"
)
var (
Docker = cDocker{}
)
type cDocker struct {
g.Meta `name:"docker" usage:"{cDockerUsage}" brief:"{cDockerBrief}" eg:"{cDockerEg}" dc:"{cDockerDc}"`
}
const (
cDockerUsage = `gf docker [MAIN] [OPTION]`
cDockerBrief = `build docker image for current GoFrame project`
cDockerEg = `
gf docker
gf docker -t hub.docker.com/john/image:tag
gf docker -p -t hub.docker.com/john/image:tag
gf docker main.go
gf docker main.go -t hub.docker.com/john/image:tag
gf docker main.go -t hub.docker.com/john/image:tag
gf docker main.go -p -t hub.docker.com/john/image:tag
gf docker main.go -p -tp ["hub.docker.com/john","hub.docker.com/smith"] -tn image:tag
`
cDockerDc = `
The "docker" command builds the GF project to a docker images.
It runs "gf build" firstly to compile the project to binary file.
It then runs "docker build" command automatically to generate the docker image.
You should have docker installed, and there must be a Dockerfile in the root of the project.
`
cDockerMainBrief = `main file path for "gf build", it's "main.go" in default. empty string for no binary build`
cDockerBuildBrief = `binary build options before docker image build, it's "-a amd64 -s linux" in default`
cDockerFileBrief = `file path of the Dockerfile. it's "manifest/docker/Dockerfile" in default`
cDockerShellBrief = `path of the shell file which is executed before docker build`
cDockerPushBrief = `auto push the docker image to docker registry if "-t" option passed`
cDockerTagBrief = `full tag for this docker, pattern like "xxx.xxx.xxx/image:tag"`
cDockerTagNameBrief = `tag name for this docker, pattern like "image:tag". this option is required with TagPrefixes`
cDockerTagPrefixesBrief = `tag prefixes for this docker, which are used for docker push. this option is required with TagName`
cDockerExtraBrief = `extra build options passed to "docker image"`
)
func init() {
gtag.Sets(g.MapStrStr{
`cDockerUsage`: cDockerUsage,
`cDockerBrief`: cDockerBrief,
`cDockerEg`: cDockerEg,
`cDockerDc`: cDockerDc,
`cDockerMainBrief`: cDockerMainBrief,
`cDockerFileBrief`: cDockerFileBrief,
`cDockerShellBrief`: cDockerShellBrief,
`cDockerBuildBrief`: cDockerBuildBrief,
`cDockerPushBrief`: cDockerPushBrief,
`cDockerTagBrief`: cDockerTagBrief,
`cDockerTagNameBrief`: cDockerTagNameBrief,
`cDockerTagPrefixesBrief`: cDockerTagPrefixesBrief,
`cDockerExtraBrief`: cDockerExtraBrief,
})
}
type cDockerInput struct {
g.Meta `name:"docker" config:"gfcli.docker"`
Main string `name:"MAIN" arg:"true" brief:"{cDockerMainBrief}" d:"main.go"`
File string `name:"file" short:"f" brief:"{cDockerFileBrief}" d:"manifest/docker/Dockerfile"`
Shell string `name:"shell" short:"s" brief:"{cDockerShellBrief}" d:"manifest/docker/docker.sh"`
Build string `name:"build" short:"b" brief:"{cDockerBuildBrief}" d:"-a amd64 -s linux"`
Tag string `name:"tag" short:"t" brief:"{cDockerTagBrief}"`
TagName string `name:"tagName" short:"tn" brief:"{cDockerTagNameBrief}" v:"required-with:TagPrefixes"`
TagPrefixes []string `name:"tagPrefixes" short:"tp" brief:"{cDockerTagPrefixesBrief}" v:"required-with:TagName"`
Push bool `name:"push" short:"p" brief:"{cDockerPushBrief}" orphan:"true"`
Extra string `name:"extra" short:"e" brief:"{cDockerExtraBrief}"`
}
type cDockerOutput struct{}
func (c cDocker) Index(ctx context.Context, in cDockerInput) (out *cDockerOutput, err error) {
// Necessary check.
if gproc.SearchBinary("docker") == "" {
mlog.Fatalf(`command "docker" not found in your environment, please install docker first to proceed this command`)
}
// Binary build.
in.Build += " --exit"
if in.Main != "" {
if err = gproc.ShellRun(ctx, fmt.Sprintf(`gf build %s %s`, in.Main, in.Build)); err != nil {
return
}
}
// Shell executing.
if in.Shell != "" && gfile.Exists(in.Shell) {
if err = c.exeDockerShell(ctx, in.Shell); err != nil {
return
}
}
// Docker build.
var (
dockerBuildOptions string
dockerTags []string
dockerTagBase string
)
if len(in.TagPrefixes) > 0 {
for _, tagPrefix := range in.TagPrefixes {
tagPrefix = gstr.TrimRight(tagPrefix, "/")
dockerTags = append(dockerTags, fmt.Sprintf(`%s/%s`, tagPrefix, in.TagName))
}
}
if len(dockerTags) == 0 {
dockerTags = []string{in.Tag}
}
for i, dockerTag := range dockerTags {
if i > 0 {
err = gproc.ShellRun(ctx, fmt.Sprintf(`docker tag %s %s`, dockerTagBase, dockerTag))
if err != nil {
return
}
continue
}
dockerTagBase = dockerTag
dockerBuildOptions = ""
if dockerTag != "" {
dockerBuildOptions = fmt.Sprintf(`-t %s`, dockerTag)
}
if in.Extra != "" {
dockerBuildOptions = fmt.Sprintf(`%s %s`, dockerBuildOptions, in.Extra)
}
err = gproc.ShellRun(ctx, fmt.Sprintf(`docker build -f %s . %s`, in.File, dockerBuildOptions))
if err != nil {
return
}
}
// Docker push.
if !in.Push {
return
}
for _, dockerTag := range dockerTags {
if dockerTag == "" {
continue
}
err = gproc.ShellRun(ctx, fmt.Sprintf(`docker push %s`, dockerTag))
if err != nil {
return
}
}
return
}
func (c cDocker) exeDockerShell(ctx context.Context, shellFilePath string) error {
if gfile.ExtName(shellFilePath) == "sh" && runtime.GOOS == "windows" {
mlog.Debugf(`ignore shell file "%s", as it cannot be run on windows system`, shellFilePath)
return nil
}
return gproc.ShellRun(ctx, gfile.GetContents(shellFilePath))
}