github.com/SAP/cloud-mta-build-tool@v1.2.27/internal/artifacts/project.go (about) 1 package artifacts 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "runtime" 8 "strconv" 9 10 "github.com/pkg/errors" 11 12 dir "github.com/SAP/cloud-mta-build-tool/internal/archive" 13 "github.com/SAP/cloud-mta-build-tool/internal/commands" 14 "github.com/SAP/cloud-mta-build-tool/internal/exec" 15 "github.com/SAP/cloud-mta-build-tool/internal/logs" 16 "github.com/SAP/cloud-mta-build-tool/internal/tpl" 17 "github.com/SAP/cloud-mta-build-tool/internal/version" 18 "github.com/SAP/cloud-mta/mta" 19 ) 20 21 const ( 22 copyInParallel = false 23 // MaxMakeParallel - Maximum number of parallel makefile jobs if the parameter is not set by the user 24 MaxMakeParallel = 8 25 ) 26 27 // ExecBuild - Execute MTA project build 28 func ExecBuild(makefileTmp, source, target string, extensions []string, mode, mtar, platform string, 29 strict bool, jobs int, outputSync bool, wdGetter func() (string, error), wdExec func([][]string, bool) error, 30 useDefaultMbt bool, keepMakefile bool, sBomFilePath string) error { 31 message, err := version.GetVersionMessage() 32 if err == nil { 33 logs.Logger.Info(message) 34 } 35 36 // (1) generate build script 37 err = tpl.ExecuteMake(source, "", extensions, makefileTmp, mode, wdGetter, useDefaultMbt) 38 if err != nil { 39 return err 40 } 41 42 // (2) execute make command 43 cmdParams := createMakeCommand(makefileTmp, source, target, mode, mtar, platform, strict, jobs, 44 outputSync, runtime.NumCPU) 45 execMakeFileError := wdExec([][]string{cmdParams}, false) 46 47 // (3) remove temporary Makefile 48 var removeMakeFileError error = nil 49 if !keepMakefile { 50 removeMakeFileError = os.Remove(filepath.Join(source, filepath.FromSlash(makefileTmp))) 51 if removeMakeFileError != nil { 52 removeMakeFileError = errors.Wrapf(removeMakeFileError, removeFailedMsg, makefileTmp) 53 } 54 } 55 56 if execMakeFileError != nil { 57 if removeMakeFileError != nil { 58 logs.Logger.Error(removeMakeFileError) 59 } 60 return errors.Wrap(execMakeFileError, execFailedMsg) 61 } 62 63 if removeMakeFileError != nil { 64 return removeMakeFileError 65 } 66 67 // (4) generate sbom file 68 sBomGenError := ExecuteProjectBuildeSBomGenerate(source, sBomFilePath, wdGetter) 69 if sBomGenError != nil { 70 return errors.Wrap(sBomGenError, execFailedMsg) 71 } 72 return nil 73 } 74 75 func createMakeCommand(makefileName, source, target, mode, mtar, platform string, strict bool, jobs int, 76 outputSync bool, numCPUGetter func() int) []string { 77 cmdParams := []string{source, "make", "-f", makefileName, "p=" + platform, "mtar=" + mtar, "strict=" + strconv.FormatBool(strict), "mode=" + mode} 78 if target != "" { 79 cmdParams = append(cmdParams, `t="`+target+`"`) 80 } 81 if tpl.IsVerboseMode(mode) { 82 if jobs <= 0 { 83 jobs = numCPUGetter() 84 if jobs > MaxMakeParallel { 85 jobs = MaxMakeParallel 86 } 87 } 88 cmdParams = append(cmdParams, fmt.Sprintf("-j%d", jobs)) 89 90 if outputSync { 91 cmdParams = append(cmdParams, "-Otarget") 92 } 93 } 94 return cmdParams 95 } 96 97 // ExecuteProjectBuild - execute pre or post phase of project build 98 func ExecuteProjectBuild(source, target, descriptor string, extensions []string, phase string, getWd func() (string, error)) error { 99 if phase != "pre" && phase != "post" { 100 return fmt.Errorf(UnsupportedPhaseMsg, phase) 101 } 102 loc, err := dir.Location(source, target, descriptor, extensions, getWd) 103 if err != nil { 104 return err 105 } 106 oMta, err := loc.ParseFile() 107 if err != nil { 108 return err 109 } 110 return execProjectBuilders(loc, oMta, phase) 111 } 112 113 func execProjectBuilders(loc *dir.Loc, oMta *mta.MTA, phase string) error { 114 if phase == "pre" && oMta.BuildParams != nil { 115 return execProjectBuilder(oMta.BuildParams.BeforeAll, "before-all") 116 } 117 if phase == "post" { 118 err := copyResourceContent(loc.GetSource(), loc.GetTargetTmpDir(), oMta, copyInParallel) 119 if err != nil { 120 return err 121 } 122 err = copyRequiredDependencyContent(loc.GetSource(), loc.GetTargetTmpDir(), oMta, copyInParallel) 123 if err != nil { 124 return err 125 } 126 if oMta.BuildParams != nil { 127 return execProjectBuilder(oMta.BuildParams.AfterAll, "after-all") 128 } 129 } 130 return nil 131 } 132 133 func execProjectBuilder(builders []mta.ProjectBuilder, phase string) error { 134 errMessage := `the "%s"" build failed` 135 logs.Logger.Infof(`running the "%s" build...`, phase) 136 for _, builder := range builders { 137 builderCommands, err := getProjectBuilderCommands(builder) 138 if err != nil { 139 return errors.Wrapf(err, errMessage, phase) 140 } 141 cmds, err := commands.CmdConverter(".", builderCommands.Command) 142 if err != nil { 143 return errors.Wrapf(err, errMessage, phase) 144 } 145 // Execute commands 146 err = exec.ExecuteWithTimeout(cmds, builder.Timeout, true) 147 if err != nil { 148 return errors.Wrapf(err, errMessage, phase) 149 } 150 } 151 return nil 152 } 153 154 func getProjectBuilderCommands(builder mta.ProjectBuilder) (commands.CommandList, error) { 155 dummyModule := mta.Module{} 156 dummyModule.BuildParams = make(map[string]interface{}) 157 dummyModule.BuildParams["builder"] = builder.Builder 158 dummyModule.BuildParams["commands"] = builder.Commands 159 if builder.Builder == "custom" && builder.Commands == nil && len(builder.Commands) == 0 { 160 logs.Logger.Warn(commandsMissingMsg) 161 return commands.CommandList{Command: []string{}}, nil 162 } 163 if builder.Builder != "custom" && builder.Commands != nil && len(builder.Commands) != 0 { 164 logs.Logger.Warnf(commandsNotSupportedMsg, builder.Builder) 165 } 166 builderCommands, _, err := commands.CommandProvider(dummyModule) 167 return builderCommands, err 168 }