@@ -30,158 +30,186 @@ import (
3030// Can also be passed as a build arg hence needs to be accessed from commands
3131const AdditionalPackageBuildArg = "ADDITIONAL_PACKAGE"
3232
33- // BuildImage construct Docker image from function parameters
34- // TODO: refactor signature to a struct to simplify the length of the method header
35- func BuildImage (image string , handler string , functionName string , language string , nocache bool , squash bool , shrinkwrap bool , buildArgMap map [string ]string , buildOptions []string , tagFormat schema.BuildFormat , buildLabelMap map [string ]string , quietBuild bool , copyExtraPaths []string , remoteBuilder , payloadSecretPath string , forcePull bool ) error {
33+ func getTemplate (lang string ) (string , * stack.LanguageTemplate , error ) {
3634
37- if stack .IsValidTemplate (language ) {
38- pathToTemplateYAML := fmt .Sprintf ("./template/%s/template.yml" , language )
39- if _ , err := os .Stat (pathToTemplateYAML ); err != nil && os .IsNotExist (err ) {
40- return err
41- }
35+ cwd , err := os .Getwd ()
36+ if err != nil {
37+ return "" , nil , fmt .Errorf ("can't get current working directory: %w" , err )
38+ }
4239
43- langTemplate , err := stack . ParseYAMLForLanguageTemplate ( pathToTemplateYAML )
44- if err != nil {
45- return fmt .Errorf ("error reading language template: %s" , err . Error () )
46- }
40+ templateDir := filepath . Join ( cwd , "template" )
41+ if _ , err := os . Stat ( templateDir ); err != nil {
42+ return "" , nil , fmt .Errorf ("template directory not found" )
43+ }
4744
48- mountSSH := false
49- if langTemplate . MountSSH {
50- mountSSH = true
51- }
45+ files , err := os . ReadDir ( templateDir )
46+ if err != nil {
47+ return "" , nil , fmt . Errorf ( "can't read template directory: %w" , err )
48+ }
5249
53- if err := ensureHandlerPath (handler ); err != nil {
54- return fmt .Errorf ("building %s, %s is an invalid path" , functionName , handler )
50+ found := ""
51+ for _ , file := range files {
52+ if file .IsDir () {
53+ if file .Name () == lang {
54+ found = filepath .Join (templateDir , file .Name ())
55+ break
56+ }
5557 }
58+ }
5659
57- opts := []builder.BuildContextOption {}
58- if len (langTemplate .HandlerFolder ) > 0 {
59- opts = append (opts , builder .WithHandlerOverlay (langTemplate .HandlerFolder ))
60- }
60+ if len (found ) == 0 {
61+ return "" , nil , fmt .Errorf ("template %s not found" , lang )
62+ }
63+ parsed , err := stack .ParseYAMLForLanguageTemplate (filepath .Join (found , "template.yml" ))
64+ if err != nil {
65+ return "" , nil , fmt .Errorf ("can't parse template: %w" , err )
66+ }
67+ return found , parsed , nil
68+ }
6169
62- buildContext , err := builder .CreateBuildContext (functionName , handler , language , copyExtraPaths , opts ... )
63- if err != nil {
64- return err
65- }
70+ // BuildImage construct Docker image from function parameters
71+ // TODO: refactor signature to a struct to simplify the length of the method header
72+ func BuildImage (image string , handler string , functionName string , language string , nocache bool , squash bool , shrinkwrap bool , buildArgMap map [string ]string , buildOptions []string , tagFormat schema.BuildFormat , buildLabelMap map [string ]string , quietBuild bool , copyExtraPaths []string , remoteBuilder , payloadSecretPath string , forcePull bool ) error {
6673
67- if shrinkwrap {
68- fmt . Printf ( "%s shrink-wrapped to %s \n " , functionName , buildContext )
69- return nil
70- }
74+ _ , langTemplate , err := getTemplate ( language )
75+ if err != nil {
76+ return fmt . Errorf ( "language template: %s not supported, build a custom Dockerfile, error: %w" , language , err )
77+ }
7178
72- branch , version , err := GetImageTagValues ( tagFormat , handler )
73- if err != nil {
74- return err
75- }
79+ mountSSH := false
80+ if langTemplate . MountSSH {
81+ mountSSH = true
82+ }
7683
77- imageName := schema .BuildImageName (tagFormat , image , version , branch )
84+ if err := ensureHandlerPath (handler ); err != nil {
85+ return fmt .Errorf ("building %s, %s is an invalid path" , functionName , handler )
86+ }
7887
79- buildOptPackages , err := getBuildOptionPackages (buildOptions , language , langTemplate .BuildOptions )
80- if err != nil {
81- return err
88+ opts := []builder.BuildContextOption {}
89+ if len (langTemplate .HandlerFolder ) > 0 {
90+ opts = append (opts , builder .WithHandlerOverlay (langTemplate .HandlerFolder ))
91+ }
8292
83- }
84- buildArgMap = appendAdditionalPackages (buildArgMap , buildOptPackages )
93+ buildContext , err := builder .CreateBuildContext (functionName , handler , language , copyExtraPaths , opts ... )
94+ if err != nil {
95+ return err
96+ }
8597
86- fmt .Printf ("Building: %s with %s template. Please wait..\n " , imageName , language )
98+ if shrinkwrap {
99+ fmt .Printf ("%s shrink-wrapped to %s\n " , functionName , buildContext )
100+ return nil
101+ }
87102
88- if remoteBuilder != "" {
89- tempDir , err := os .MkdirTemp (os .TempDir (), "openfaas-build-*" )
90- if err != nil {
91- return fmt .Errorf ("failed to create temporary directory: %w" , err )
92- }
93- defer os .RemoveAll (tempDir )
103+ branch , version , err := GetImageTagValues (tagFormat , handler )
104+ if err != nil {
105+ return err
106+ }
94107
95- tarPath := path . Join ( tempDir , "req.tar" )
108+ imageName := schema . BuildImageName ( tagFormat , image , version , branch )
96109
97- buildConfig := builder.BuildConfig {
98- Image : imageName ,
99- BuildArgs : buildArgMap ,
100- }
110+ buildOptPackages , err := getBuildOptionPackages (buildOptions , language , langTemplate .BuildOptions )
111+ if err != nil {
112+ return err
101113
102- // Prepare a tar archive that contains the build config and build context.
103- if err := builder .MakeTar (tarPath , path .Join ("build" , functionName ), & buildConfig ); err != nil {
104- return fmt .Errorf ("failed to create tar file for %s, error: %w" , functionName , err )
105- }
114+ }
115+ buildArgMap = appendAdditionalPackages (buildArgMap , buildOptPackages )
106116
107- // Get the HMAC secret used for payload authentication with the builder API.
108- payloadSecret , err := os .ReadFile (payloadSecretPath )
109- if err != nil {
110- return fmt .Errorf ("failed to read payload secret: %w" , err )
111- }
112- payloadSecret = bytes .TrimSpace (payloadSecret )
117+ fmt .Printf ("Building: %s with %s template. Please wait..\n " , imageName , language )
113118
114- // Initialize a new builder client.
115- u , _ := url .Parse (remoteBuilder )
116- builderURL := & url.URL {
117- Scheme : u .Scheme ,
118- Host : u .Host ,
119- }
120- b := builder .NewFunctionBuilder (builderURL , http .DefaultClient , builder .WithHmacAuth (string (payloadSecret )))
119+ if remoteBuilder != "" {
120+ tempDir , err := os .MkdirTemp (os .TempDir (), "openfaas-build-*" )
121+ if err != nil {
122+ return fmt .Errorf ("failed to create temporary directory: %w" , err )
123+ }
124+ defer os .RemoveAll (tempDir )
121125
122- stream , err := b .BuildWithStream (tarPath )
123- if err != nil {
124- return fmt .Errorf ("failed to invoke builder: %w" , err )
125- }
126- defer stream .Close ()
126+ tarPath := path .Join (tempDir , "req.tar" )
127127
128- for result := range stream .Results () {
129- if ! quietBuild {
130- for _ , logMsg := range result .Log {
131- fmt .Printf ("%s\n " , logMsg )
132- }
133- }
128+ buildConfig := builder.BuildConfig {
129+ Image : imageName ,
130+ BuildArgs : buildArgMap ,
131+ }
132+
133+ // Prepare a tar archive that contains the build config and build context.
134+ if err := builder .MakeTar (tarPath , path .Join ("build" , functionName ), & buildConfig ); err != nil {
135+ return fmt .Errorf ("failed to create tar file for %s, error: %w" , functionName , err )
136+ }
137+
138+ // Get the HMAC secret used for payload authentication with the builder API.
139+ payloadSecret , err := os .ReadFile (payloadSecretPath )
140+ if err != nil {
141+ return fmt .Errorf ("failed to read payload secret: %w" , err )
142+ }
143+ payloadSecret = bytes .TrimSpace (payloadSecret )
144+
145+ // Initialize a new builder client.
146+ u , _ := url .Parse (remoteBuilder )
147+ builderURL := & url.URL {
148+ Scheme : u .Scheme ,
149+ Host : u .Host ,
150+ }
151+ b := builder .NewFunctionBuilder (builderURL , http .DefaultClient , builder .WithHmacAuth (string (payloadSecret )))
134152
135- switch result .Status {
136- case builder .BuildSuccess :
137- log .Printf ("%s success building and pushing image: %s" , functionName , result .Image )
138- case builder .BuildFailed :
139- return fmt .Errorf ("%s failure while building or pushing image %s: %s" , functionName , imageName , result .Error )
153+ stream , err := b .BuildWithStream (tarPath )
154+ if err != nil {
155+ return fmt .Errorf ("failed to invoke builder: %w" , err )
156+ }
157+ defer stream .Close ()
158+
159+ for result := range stream .Results () {
160+ if ! quietBuild {
161+ for _ , logMsg := range result .Log {
162+ fmt .Printf ("%s\n " , logMsg )
140163 }
141164 }
142165
143- } else {
144- dockerBuildVal := dockerBuild {
145- Image : imageName ,
146- NoCache : nocache ,
147- Squash : squash ,
148- HTTPProxy : os .Getenv ("http_proxy" ),
149- HTTPSProxy : os .Getenv ("https_proxy" ),
150- BuildArgMap : buildArgMap ,
151- BuildLabelMap : buildLabelMap ,
152- ForcePull : forcePull ,
166+ switch result .Status {
167+ case builder .BuildSuccess :
168+ log .Printf ("%s success building and pushing image: %s" , functionName , result .Image )
169+ case builder .BuildFailed :
170+ return fmt .Errorf ("%s failure while building or pushing image %s: %s" , functionName , imageName , result .Error )
153171 }
172+ }
154173
155- command , args := getDockerBuildCommand (dockerBuildVal )
174+ } else {
175+ dockerBuildVal := dockerBuild {
176+ Image : imageName ,
177+ NoCache : nocache ,
178+ Squash : squash ,
179+ HTTPProxy : os .Getenv ("http_proxy" ),
180+ HTTPSProxy : os .Getenv ("https_proxy" ),
181+ BuildArgMap : buildArgMap ,
182+ BuildLabelMap : buildLabelMap ,
183+ ForcePull : forcePull ,
184+ }
156185
157- envs := os .Environ ()
158- if mountSSH {
159- envs = append (envs , "DOCKER_BUILDKIT=1" )
160- }
161- log .Printf ("Build flags: %+v\n " , args )
162-
163- task := v2execute.ExecTask {
164- Cwd : buildContext ,
165- Command : command ,
166- Args : args ,
167- StreamStdio : ! quietBuild ,
168- Env : envs ,
169- }
186+ command , args := getDockerBuildCommand (dockerBuildVal )
170187
171- res , err := task .Execute (context .TODO ())
188+ envs := os .Environ ()
189+ if mountSSH {
190+ envs = append (envs , "DOCKER_BUILDKIT=1" )
191+ }
192+ log .Printf ("Build flags: %+v\n " , args )
193+
194+ task := v2execute.ExecTask {
195+ Cwd : buildContext ,
196+ Command : command ,
197+ Args : args ,
198+ StreamStdio : ! quietBuild ,
199+ Env : envs ,
200+ }
172201
173- if err != nil {
174- return err
175- }
202+ res , err := task .Execute (context .TODO ())
176203
177- if res . ExitCode != 0 {
178- return fmt . Errorf ( "[%s] received non-zero exit code from build, error: %s" , functionName , res . Stderr )
179- }
204+ if err != nil {
205+ return err
206+ }
180207
181- fmt .Printf ("Image: %s built.\n " , imageName )
208+ if res .ExitCode != 0 {
209+ return fmt .Errorf ("[%s] received non-zero exit code from build, error: %s" , functionName , res .Stderr )
182210 }
183- } else {
184- return fmt .Errorf ( "language template : %s not supported, build a custom Dockerfile " , language )
211+
212+ fmt .Printf ( "Image : %s built. \n " , imageName )
185213 }
186214
187215 return nil
0 commit comments