@@ -2,27 +2,23 @@ package main
2
2
3
3
import (
4
4
"context"
5
- "encoding/base64"
6
5
"encoding/json"
7
6
"fmt"
8
- "io"
9
7
"os"
10
- "strings"
11
8
"sync"
12
9
"text/template"
13
10
14
- "github.com/docker/docker/api/types"
15
- "github.com/docker/docker/client"
16
11
"github.com/spf13/pflag"
12
+ "github.com/togettoyou/hub-mirror/pkg"
17
13
)
18
14
19
15
var (
20
16
content = pflag .StringP ("content" , "" , "" , "原始镜像,格式为:{ \" hub-mirror\" : [] }" )
21
- maxContent = pflag .IntP ("maxContent" , "" , 10 , "原始镜像个数限制" )
22
- username = pflag .StringP ("username" , "" , "" , "docker hub 用户名" )
23
- password = pflag .StringP ("password" , "" , "" , "docker hub 密码" )
17
+ maxContent = pflag .IntP ("maxContent" , "" , 11 , "原始镜像个数限制" )
18
+ repository = pflag .StringP ("repository" , "" , "" , "推送仓库地址,为空默认为 hub.docker.com" )
19
+ username = pflag .StringP ("username" , "" , "" , "仓库用户名" )
20
+ password = pflag .StringP ("password" , "" , "" , "仓库密码" )
24
21
outputPath = pflag .StringP ("outputPath" , "" , "output.sh" , "结果输出路径" )
25
- repository = pflag .StringP ("repository" , "" , "" , "仓库地址,如果为空,默认推到dockerHub" )
26
22
)
27
23
28
24
func main () {
@@ -36,123 +32,61 @@ func main() {
36
32
if err != nil {
37
33
panic (err )
38
34
}
35
+
39
36
if len (hubMirrors .Content ) > * maxContent {
40
- panic ("content is too long. " )
37
+ panic ("提交的原始镜像个数超出了最大限制 " )
41
38
}
39
+
42
40
fmt .Printf ("%+v\n " , hubMirrors )
43
41
44
- fmt .Println ("连接 Docker" )
45
- cli , err := client . NewClientWithOpts ( client . FromEnv , client . WithAPIVersionNegotiation () )
42
+ fmt .Println ("初始化 Docker 客户端 " )
43
+ cli , err := pkg . NewCli ( context . Background (), * repository , * username , * password )
46
44
if err != nil {
47
45
panic (err )
48
46
}
49
47
50
- fmt .Println ("验证 Docker 用户名密码" )
51
- if * username == "" || * password == "" {
52
- panic ("username or password cannot be empty." )
53
- }
54
- authConfig := types.AuthConfig {
55
- Username : * username ,
56
- Password : * password ,
57
- ServerAddress : * repository ,
58
- }
59
- encodedJSON , err := json .Marshal (authConfig )
60
- if err != nil {
61
- panic (err )
62
- }
63
- authStr := base64 .URLEncoding .EncodeToString (encodedJSON )
64
- _ , err = cli .RegistryLogin (context .Background (), authConfig )
65
- if err != nil {
66
- panic (err )
67
- }
68
-
69
- fmt .Println ("开始转换镜像" )
70
- output := make ([]struct {
71
- Source string
72
- Target string
73
- Repository string
74
- }, 0 )
75
-
48
+ outputs := make ([]* pkg.Output , 0 )
49
+ mu := sync.Mutex {}
76
50
wg := sync.WaitGroup {}
77
51
78
52
for _ , source := range hubMirrors .Content {
53
+ source := source
54
+
79
55
if source == "" {
80
56
continue
81
57
}
82
-
83
- target := source
84
- // 查看是否配置自定义镜像名,如果配置的话使用自定义镜像名
85
- if strings .Contains (source , "$" ) {
86
- str1 := strings .Split (source , "$" )
87
- repository := strings .Split (str1 [0 ], ":" )
88
- target = str1 [1 ] + ":" + repository [len (repository )- 1 ]
89
- source = str1 [0 ]
90
- }
91
-
92
- // 如果为空,默认推送到 DockerHub 用户名 下
93
- // 如果指定了值,则推动到指定的仓库下,用户名不一定与repository后缀相同
94
- if * repository == "" {
95
- target = * username + "/" + strings .ReplaceAll (target , "/" , "." )
96
- } else {
97
- target = * repository + "/" + strings .ReplaceAll (target , "/" , "." )
98
- }
99
-
58
+ fmt .Println ("开始转换镜像" , source )
100
59
wg .Add (1 )
101
- go func (source , target , repository string ) {
60
+ go func () {
102
61
defer wg .Done ()
103
62
104
- fmt .Println ("开始转换" , source , "=>" , target )
105
- ctx := context .Background ()
106
-
107
- // 拉取镜像
108
- pullOut , err := cli .ImagePull (ctx , source , types.ImagePullOptions {})
63
+ output , err := cli .PullTagPushImage (context .Background (), source )
109
64
if err != nil {
110
- panic ( err )
65
+ return
111
66
}
112
- defer pullOut .Close ()
113
- io .Copy (os .Stdout , pullOut )
114
67
115
- // 重新标签
116
- err = cli .ImageTag (ctx , source , target )
117
- if err != nil {
118
- panic (err )
119
- }
120
-
121
- // 上传镜像
122
- pushOut , err := cli .ImagePush (ctx , target , types.ImagePushOptions {
123
- RegistryAuth : authStr ,
124
- })
125
- if err != nil {
126
- panic (err )
127
- }
128
- defer pushOut .Close ()
129
- io .Copy (os .Stdout , pushOut )
130
-
131
- output = append (output , struct {
132
- Source string
133
- Target string
134
- Repository string
135
- }{Source : source , Target : target , Repository : repository })
136
- fmt .Println ("转换成功" , source , "=>" , target )
137
- }(source , target , * repository )
68
+ mu .Lock ()
69
+ defer mu .Unlock ()
70
+ outputs = append (outputs , output )
71
+ }()
138
72
}
139
73
140
74
wg .Wait ()
141
75
142
- if len (output ) == 0 {
143
- panic ("output is empty. " )
76
+ if len (outputs ) == 0 {
77
+ panic ("没有转换成功的镜像 " )
144
78
}
145
79
146
80
tmpl , err := template .New ("pull_images" ).Parse (`{{- range . -}}
147
81
148
- {{if .Repository}}
149
- # if your repository is private,please login...
150
- # docker login {{ .Repository }} --username={your username}
151
- {{end}}
152
- docker pull {{ .Target }}
153
- docker tag {{ .Target }} {{ .Source }}
154
-
155
- {{ end -}}` )
82
+ {{if .Repository}}
83
+ # if your repository is private,please login...
84
+ # docker login {{ .Repository }} --username={your username}
85
+ {{end}}
86
+ docker pull {{ .Target }}
87
+ docker tag {{ .Target }} {{ .Source }}
88
+
89
+ {{ end -}}` )
156
90
if err != nil {
157
91
panic (err )
158
92
}
@@ -161,9 +95,10 @@ docker tag {{ .Target }} {{ .Source }}
161
95
panic (err )
162
96
}
163
97
defer outputFile .Close ()
164
- err = tmpl .Execute (outputFile , output )
98
+
99
+ err = tmpl .Execute (outputFile , outputs )
165
100
if err != nil {
166
101
panic (err )
167
102
}
168
- fmt .Println (output )
103
+ fmt .Println (outputs )
169
104
}
0 commit comments