github.com/SAP/cloud-mta-build-tool@v1.2.27/internal/buildops/build_params.go (about)

     1  package buildops
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"reflect"
     7  	"strings"
     8  
     9  	"github.com/pkg/errors"
    10  
    11  	"github.com/SAP/cloud-mta-build-tool/internal/archive"
    12  	"github.com/SAP/cloud-mta-build-tool/internal/commands"
    13  	"github.com/SAP/cloud-mta/mta"
    14  )
    15  
    16  const (
    17  	// SupportedPlatformsParam - name of build-params property for supported platforms
    18  	SupportedPlatformsParam = "supported-platforms"
    19  
    20  	// ModuleArtifactDefaultName - the default name of the build artifact.
    21  	// It can be changed using properties like build-result or build-artifact-name in the build parameters.
    22  	ModuleArtifactDefaultName = "data.zip"
    23  	builderParam              = "builder"
    24  	requiresParam             = "requires"
    25  	buildResultParam          = "build-result"
    26  	nameParam                 = "name"
    27  	artifactsParam            = "artifacts"
    28  	buildArtifactNameParam    = "build-artifact-name"
    29  	targetPathParam           = "target-path"
    30  	noSourceParam             = "no-source"
    31  )
    32  
    33  // BuildRequires - build requires section.
    34  type BuildRequires struct {
    35  	Name       string   `yaml:"name,omitempty"`
    36  	Artifacts  []string `yaml:"artifacts,omitempty"`
    37  	TargetPath string   `yaml:"target-path,omitempty"`
    38  }
    39  
    40  // GetBuildRequires - gets Requires property of module's build-params property
    41  // as generic property and converts it to slice of BuildRequires structures
    42  func GetBuildRequires(module *mta.Module) []BuildRequires {
    43  	// check existence of module's build-params.require property
    44  	if module.BuildParams != nil && module.BuildParams[requiresParam] != nil {
    45  		requires := module.BuildParams[requiresParam].([]interface{})
    46  		buildRequires := []BuildRequires{}
    47  		// go through requirements
    48  		for _, reqI := range requires {
    49  			// cast requirement to generic map
    50  			reqMap, ok := reqI.(map[string]interface{})
    51  			if !ok {
    52  				reqMap = commands.ConvertMap(reqI.(map[interface{}]interface{}))
    53  			}
    54  			// init resulting typed requirement
    55  			reqStr := BuildRequires{
    56  				Name:       getStrParam(reqMap, nameParam),
    57  				Artifacts:  []string{},
    58  				TargetPath: getStrParam(reqMap, targetPathParam),
    59  			}
    60  			// fill Artifacts field of resulting requirement
    61  			if reqMap[artifactsParam] == nil {
    62  				reqStr.Artifacts = nil
    63  			} else {
    64  				for _, artifact := range reqMap[artifactsParam].([]interface{}) {
    65  					reqStr.Artifacts = append(reqStr.Artifacts, []string{artifact.(string)}...)
    66  				}
    67  			}
    68  			// add typed requirement to result
    69  			buildRequires = append(buildRequires, []BuildRequires{reqStr}...)
    70  
    71  		}
    72  		return buildRequires
    73  	}
    74  	return nil
    75  }
    76  
    77  // getStrParam - get string parameter from the map
    78  func getStrParam(m map[string]interface{}, param string) string {
    79  	if m[param] == nil {
    80  		return ""
    81  	}
    82  	return m[param].(string)
    83  }
    84  
    85  // Order of modules building is done according to the dependencies defined in build parameters.
    86  // In case of problems in this definition build process should not start and corresponding error must be provided.
    87  // Possible problems:
    88  // 1.	Cyclic dependencies
    89  // 2.	Dependency on not defined module
    90  
    91  // GetRequiresArtifacts returns the source path, target path and patterns of files and folders to copy from a module's requires section
    92  func GetRequiresArtifacts(ep dir.ISourceModule, mta *mta.MTA, requires *BuildRequires, moduleName string, resolveBuildResult bool) (source string, target string, patterns []string, err error) {
    93  	// validate module names - both in process and required
    94  	module, err := mta.GetModuleByName(moduleName)
    95  	if err != nil {
    96  		return "", "", nil, errors.Wrapf(err, reqFailedOnModuleGetMsg, moduleName, requires.Name, moduleName)
    97  	}
    98  
    99  	requiredModule, err := mta.GetModuleByName(requires.Name)
   100  	if err != nil {
   101  		return "", "", nil, errors.Wrapf(err, reqFailedOnModuleGetMsg, moduleName, requires.Name, requires.Name)
   102  	}
   103  
   104  	_, defaultBuildResult, err := commands.CommandProvider(*requiredModule)
   105  	if err != nil {
   106  		return "", "", nil, errors.Wrapf(err, reqFailedOnCommandsGetMsg, moduleName, requires.Name, requires.Name)
   107  	}
   108  
   109  	// Build paths for artifacts copying
   110  	sourcePath, err := GetModuleSourceArtifactPath(ep, false, requiredModule, defaultBuildResult, resolveBuildResult)
   111  	if err != nil {
   112  		return "", "", nil, errors.Wrapf(err, reqFailedOnBuildResultMsg, moduleName, requires.Name)
   113  	}
   114  	targetPath := getRequiredTargetPath(ep, module, requires)
   115  	return sourcePath, targetPath, requires.Artifacts, nil
   116  }
   117  
   118  // ProcessRequirements - Processes build requirement of module (using moduleName).
   119  func ProcessRequirements(ep dir.ISourceModule, mta *mta.MTA, requires *BuildRequires, moduleName string) error {
   120  	sourcePath, targetPath, artifacts, err := GetRequiresArtifacts(ep, mta, requires, moduleName, true)
   121  	if err != nil {
   122  		return err
   123  	}
   124  	// execute copy of artifacts
   125  	err = dir.CopyByPatterns(sourcePath, targetPath, artifacts)
   126  	if err != nil {
   127  		return errors.Wrapf(err, reqFailedOnCopyMsg, moduleName, requires.Name)
   128  	}
   129  	return nil
   130  }
   131  
   132  // GetModuleSourceArtifactPath - get the module's artifact that has to be archived in the mtar, from the project sources
   133  func GetModuleSourceArtifactPath(loc dir.ISourceModule, depDesc bool, module *mta.Module, defaultBuildResult string, resolveBuildResult bool) (path string, e error) {
   134  	if module.Path == "" {
   135  		return "", nil
   136  	}
   137  	path = loc.GetSourceModuleDir(module.Path)
   138  	if !depDesc {
   139  		buildResult := defaultBuildResult
   140  		var ok bool
   141  		if module.BuildParams != nil && module.BuildParams[buildResultParam] != nil {
   142  			buildResult, ok = module.BuildParams[buildResultParam].(string)
   143  			if !ok {
   144  				return "", errors.Errorf(WrongBuildResultMsg, module.BuildParams[buildResultParam], module.Name)
   145  			}
   146  		}
   147  		if buildResult != "" {
   148  			path = filepath.Join(path, buildResult)
   149  			if resolveBuildResult {
   150  				path, e = dir.FindPath(path)
   151  				if e != nil {
   152  					return "", e
   153  				}
   154  			}
   155  		}
   156  	}
   157  	return path, nil
   158  }
   159  
   160  // IsArchive - check if file is a folder or an archive
   161  func IsArchive(path string, resolvePath bool) (isArchive bool, e error) {
   162  
   163  	if !resolvePath {
   164  		return guessIfArchive(path), nil
   165  	}
   166  	info, err := os.Stat(path)
   167  
   168  	if err != nil {
   169  		return false, err
   170  	}
   171  	isFolder := info.IsDir()
   172  	isArchive = false
   173  	if !isFolder {
   174  		isArchive = guessIfArchive(path)
   175  	}
   176  	return isArchive, nil
   177  }
   178  
   179  func guessIfArchive(path string) bool {
   180  	ext := filepath.Ext(path)
   181  	return ext == ".zip" || ext == ".jar" || ext == ".war"
   182  }
   183  
   184  // GetModuleTargetArtifactPath - get the path to where the module's artifact should be created in the temp folder, from which it's archived in the mtar
   185  func GetModuleTargetArtifactPath(moduleLoc dir.IModule, depDesc bool, module *mta.Module, defaultBuildResult string,
   186  	resolveBuildResult bool) (path string, toArchive bool, e error) {
   187  
   188  	if module.Path == "" {
   189  		return "", false, nil
   190  	}
   191  	if depDesc {
   192  		path = filepath.Join(moduleLoc.GetTargetModuleDir(module.Path))
   193  	} else {
   194  		moduleSourceArtifactPath, err := GetModuleSourceArtifactPath(moduleLoc, depDesc, module, defaultBuildResult, resolveBuildResult)
   195  		if err != nil {
   196  			return "", false, err
   197  		}
   198  		isArchive, err := IsArchive(moduleSourceArtifactPath, resolveBuildResult)
   199  		if err != nil {
   200  			return "", false, errors.Wrapf(err, wrongPathMsg, moduleSourceArtifactPath)
   201  		}
   202  		artifactName, artifactExt, err := getArtifactInfo(isArchive, module, moduleSourceArtifactPath)
   203  		if err != nil {
   204  			return "", false, err
   205  		}
   206  		toArchive = !isArchive
   207  
   208  		artifactRelPath, err := moduleLoc.GetSourceModuleArtifactRelPath(module.Path, moduleSourceArtifactPath)
   209  		if err != nil {
   210  			return "", false, err
   211  		}
   212  		path = filepath.Join(moduleLoc.GetTargetModuleDir(module.Name), artifactRelPath, artifactName+artifactExt)
   213  	}
   214  	return path, toArchive, nil
   215  }
   216  
   217  func getArtifactInfo(isArchive bool, module *mta.Module, moduleSourceArtifactPath string) (artifactName, artifactExt string, err error) {
   218  	var ok bool
   219  	var artifactFullName string
   220  	if isArchive {
   221  		artifactFullName = filepath.Base(moduleSourceArtifactPath)
   222  	} else {
   223  		artifactFullName = ModuleArtifactDefaultName
   224  	}
   225  	artifactExt = filepath.Ext(artifactFullName)
   226  	artifactName = artifactFullName[0 : len(artifactFullName)-len(artifactExt)]
   227  	if module.BuildParams != nil && module.BuildParams[buildArtifactNameParam] != nil {
   228  		artifactName, ok = module.BuildParams[buildArtifactNameParam].(string)
   229  		if !ok {
   230  			return "", "", errors.Errorf(WrongBuildArtifactNameMsg, module.BuildParams[buildArtifactNameParam], module.Name)
   231  		}
   232  	}
   233  	return
   234  }
   235  
   236  // getRequiredTargetPath - provides path of required artifacts
   237  func getRequiredTargetPath(ep dir.ISourceModule, module *mta.Module, requires *BuildRequires) string {
   238  	path := ep.GetSourceModuleDir(module.Path)
   239  	if requires.TargetPath != "" {
   240  		// if target folder provided - artifacts will be saved in the sub-folder of the module folder
   241  		path = filepath.Join(path, requires.TargetPath)
   242  	}
   243  	return path
   244  }
   245  
   246  // PlatformDefined - if platform defined
   247  // If platforms parameter not defined then no limitations on platform, method returns true
   248  // Non empty list of platforms has to contain specific platform
   249  func PlatformDefined(module *mta.Module, platform string) bool {
   250  	if module.BuildParams == nil || module.BuildParams[SupportedPlatformsParam] == nil {
   251  		return true
   252  	}
   253  	supportedPlatforms := module.BuildParams[SupportedPlatformsParam]
   254  	if reflect.TypeOf(supportedPlatforms).Elem().Kind() == reflect.String {
   255  		sp := supportedPlatforms.([]string)
   256  		for _, p := range sp {
   257  			if strings.ToLower(p) == platform {
   258  				return true
   259  			}
   260  		}
   261  		return false
   262  	}
   263  	sp := supportedPlatforms.([]interface{})
   264  	for _, p := range sp {
   265  		if strings.ToLower(p.(string)) == platform {
   266  			return true
   267  		}
   268  	}
   269  	return false
   270  }
   271  
   272  // IfNoSource - checks if "no-source" build parameter defined and set to "true"
   273  func IfNoSource(module *mta.Module) bool {
   274  	if module.BuildParams != nil && module.BuildParams[noSourceParam] != nil {
   275  		noSource, ok := module.BuildParams[noSourceParam].(bool)
   276  		return ok && noSource
   277  	}
   278  	return false
   279  }