1
1
package dockerexec
2
2
3
3
import (
4
+ "bufio"
4
5
"context"
5
6
"encoding/hex"
7
+ "encoding/json"
6
8
"io"
9
+ "math/rand"
7
10
"time"
8
11
12
+ "github.com/docker/docker/api/types"
9
13
"github.com/docker/docker/api/types/filters"
10
14
"github.com/docker/docker/api/types/image"
11
15
"github.com/docker/docker/client"
16
+ "github.com/docker/docker/pkg/archive"
12
17
"github.com/pkg/errors"
13
18
"go.uber.org/zap"
14
- "golang.org/x/exp/rand"
15
19
)
16
20
17
21
type Options struct {
@@ -34,7 +38,7 @@ func New(opts *Options) (*Docker, error) {
34
38
logger = zap .NewNop ()
35
39
}
36
40
37
- rnd := rand .New (rand .NewSource (uint64 ( time .Now ().UnixNano () )))
41
+ rnd := rand .New (rand .NewSource (time .Now ().UnixNano ()))
38
42
39
43
d := & Docker {
40
44
client : c ,
@@ -77,6 +81,14 @@ func (d *Docker) CommandContext(ctx context.Context, program string, args ...str
77
81
}
78
82
}
79
83
84
+ func (d * Docker ) RemoveImage (ctx context.Context ) error {
85
+ _ , err := d .client .ImageRemove (ctx , d .image , image.RemoveOptions {Force : true , PruneChildren : true })
86
+ if err != nil {
87
+ return errors .WithStack (err )
88
+ }
89
+ return nil
90
+ }
91
+
80
92
func (d * Docker ) containerUniqueName () string {
81
93
var hash [4 ]byte
82
94
_ , _ = d .rnd .Read (hash [:])
@@ -90,8 +102,62 @@ func (d *Docker) buildOrPullImage(ctx context.Context) error {
90
102
return d .pullImage (ctx )
91
103
}
92
104
93
- func (d * Docker ) buildImage (context.Context ) error {
94
- return errors .New ("not implemented" )
105
+ func (d * Docker ) buildImage (ctx context.Context ) error {
106
+ tar , err := archive .TarWithOptions (d .buildContext , & archive.TarOptions {})
107
+ if err != nil {
108
+ return errors .WithMessage (err , "failed to create tar archive" )
109
+ }
110
+
111
+ resp , err := d .client .ImageBuild (
112
+ ctx ,
113
+ tar ,
114
+ types.ImageBuildOptions {
115
+ Dockerfile : d .dockerfile ,
116
+ Tags : []string {d .image },
117
+ Remove : true ,
118
+ ForceRemove : true ,
119
+ NoCache : true ,
120
+ },
121
+ )
122
+ if err != nil {
123
+ return errors .WithMessage (err , "failed to build image" )
124
+ }
125
+ defer resp .Body .Close ()
126
+
127
+ return errors .WithStack (
128
+ printLogs (resp .Body , d .logger ),
129
+ )
130
+ }
131
+
132
+ func printLogs (r io.Reader , logger * zap.Logger ) error {
133
+ type errorLine struct {
134
+ Error string `json:"error"`
135
+ ErrorDetail struct {
136
+ Message string `json:"message"`
137
+ } `json:"errorDetail"`
138
+ }
139
+
140
+ var lastLine string
141
+
142
+ scanner := bufio .NewScanner (r )
143
+
144
+ for scanner .Scan () {
145
+ lastLine = scanner .Text ()
146
+ logger .Debug ("docker build" , zap .String ("log" , lastLine ))
147
+ }
148
+
149
+ if err := scanner .Err (); err != nil {
150
+ return errors .WithMessage (err , "docker build" )
151
+ }
152
+
153
+ errLine := errorLine {}
154
+ if err := json .Unmarshal ([]byte (lastLine ), & errLine ); err != nil {
155
+ return errors .WithMessage (err , "docker build" )
156
+ }
157
+ if errLine .Error != "" {
158
+ return errors .Errorf ("docker build: %s" , errLine .Error )
159
+ }
160
+ return nil
95
161
}
96
162
97
163
func (d * Docker ) pullImage (ctx context.Context ) error {
0 commit comments