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  }