15
15
import { Task } from './task' ;
16
16
import { ContainerImage } from '../types' ;
17
17
import { StackContainer } from '../stack' ;
18
- import { dockerodeEvtToString } from '../index' ;
19
- // import rimraf from 'rimraf';
20
-
21
- import tar from 'tar-fs' ;
22
- import Docker from 'dockerode' ;
18
+ import { oneLine } from 'common-tags' ;
19
+ import execa from 'execa' ;
23
20
24
21
interface BuildContainerTaskOptions {
25
22
baseDir : string ;
@@ -29,74 +26,52 @@ interface BuildContainerTaskOptions {
29
26
30
27
export class BuildContainerTask extends Task < ContainerImage > {
31
28
private container : StackContainer ;
32
- // private readonly stack: Stack;
33
29
private readonly provider : string ;
34
30
35
31
constructor ( { container, provider = 'local' } : BuildContainerTaskOptions ) {
36
32
super ( `${ container . getName ( ) } ` ) ;
37
33
this . container = container ;
38
- // this.stack = stack;
39
34
this . provider = provider ;
40
35
}
41
36
42
37
async do ( ) : Promise < ContainerImage > {
43
- const docker = new Docker ( ) ;
44
-
45
- // const ignoreFiles = await Template.getDockerIgnoreFiles(template);
46
-
47
- const pack = tar . pack ( this . container . getContext ( ) , {
48
- // TODO: support ignore again
49
- // ignore: (name) =>
50
- // // Simple filter before more complex multimatch
51
- // ignoreFiles.filter((f) => name.includes(f)).length > 0 || match(name, ignoreFiles).length > 0,
52
- } ) ;
38
+ const imageId = this . container . getImageTagName ( this . provider ) ;
39
+ const { args = { } } = this . container . getDescriptor ( ) ;
53
40
54
- // FIXME: Currently dockerode does not support dockerfiles specified outside of build context
55
- const dockerfile = this . container . getDockerfile ( ) ;
56
-
57
- const options = {
58
- buildargs : {
59
- PROVIDER : this . provider ,
60
- } ,
61
- t : this . container . getImageTagName ( this . provider ) ,
62
- dockerfile ,
63
- } ;
41
+ const cmd = oneLine `
42
+ docker build ${ this . container . getContext ( ) }
43
+ -f ${ this . container . getDockerfile ( ) }
44
+ -t ${ imageId }
45
+ --progress plain
46
+ --build-arg PROVIDER= ${ this . provider }
47
+ ${ Object . keys ( args )
48
+ . map ( ( k ) => `--build-arg ${ k } = ${ args [ k ] } ` )
49
+ . join ( ' ' ) }
50
+ ` ;
64
51
65
- let stream : NodeJS . ReadableStream ;
66
52
try {
67
- stream = await docker . buildImage ( pack , options ) ;
68
- } catch ( error ) {
69
- if ( error . errno && error . errno === - 61 ) {
70
- throw new Error ( 'Unable to connect to docker, is it running locally?' ) ;
71
- }
72
- throw error ;
73
- }
74
-
75
- // Get build updates
76
- const buildResults = await new Promise < any [ ] > ( ( resolve , reject ) => {
77
- docker . modem . followProgress (
78
- stream ,
79
- ( errorInner : Error , resolveInner : Record < string , any > [ ] ) =>
80
- errorInner ? reject ( errorInner ) : resolve ( resolveInner ) ,
81
- ( event : any ) => {
82
- try {
83
- this . update ( dockerodeEvtToString ( event ) ) ;
84
- } catch ( error ) {
85
- reject ( new Error ( error . message . replace ( / \n / g, '' ) ) ) ;
86
- }
53
+ const dockerProcess = execa . command ( cmd , {
54
+ // Enable buildkit for out of context dockerfile
55
+ env : {
56
+ DOCKER_BUILDKIT : '1' ,
87
57
} ,
88
- ) ;
89
- } ) ;
58
+ } ) ;
59
+
60
+ // Only outputs on stderr
61
+ dockerProcess . stderr . on ( 'data' , ( data ) => {
62
+ // fs.writeFileSync('debug.txt', data);
63
+ this . update ( data . toString ( ) ) ;
64
+ } ) ;
90
65
91
- const filteredResults = buildResults . filter ( ( obj ) => 'aux' in obj && 'ID' in obj [ 'aux' ] ) ;
92
- if ( filteredResults . length > 0 ) {
93
- const imageId = filteredResults [ filteredResults . length - 1 ] [ 'aux' ] . ID . split ( ':' ) . pop ( ) as string ;
94
- return { id : imageId , name : this . container . getName ( ) } as ContainerImage ;
95
- } else {
96
- const {
97
- errorDetail : { message } ,
98
- } = buildResults . pop ( ) as any ;
99
- throw new Error ( message ) ;
66
+ // wait for the process to finalize
67
+ await dockerProcess ;
68
+ } catch ( e ) {
69
+ throw new Error ( e . message ) ;
100
70
}
71
+
72
+ return {
73
+ id : imageId ,
74
+ name : this . container . getName ( ) ,
75
+ } ;
101
76
}
102
77
}
0 commit comments