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

     1  package artifacts
     2  
     3  import (
     4  	"fmt"
     5  	"gopkg.in/yaml.v2"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	"github.com/pkg/errors"
    11  
    12  	"github.com/SAP/cloud-mta-build-tool/internal/archive"
    13  	"github.com/SAP/cloud-mta-build-tool/internal/buildops"
    14  	"github.com/SAP/cloud-mta-build-tool/internal/commands"
    15  	"github.com/SAP/cloud-mta-build-tool/internal/exec"
    16  	"github.com/SAP/cloud-mta-build-tool/internal/logs"
    17  	"github.com/SAP/cloud-mta/mta"
    18  )
    19  
    20  const (
    21  	ignore = "ignore"
    22  )
    23  
    24  // ExecuteBuild - executes build of module from Makefile
    25  func ExecuteBuild(source, target string, extensions []string, moduleName, platform string, wdGetter func() (string, error)) error {
    26  	if moduleName == "" {
    27  		return errors.New(buildFailedOnEmptyModuleMsg)
    28  	}
    29  
    30  	logs.Logger.Infof(buildMsg, moduleName)
    31  	loc, err := dir.Location(source, target, dir.Dev, extensions, wdGetter)
    32  	if err != nil {
    33  		return errors.Wrapf(err, buildFailedMsg, moduleName)
    34  	}
    35  
    36  	err = buildModule(loc, loc, moduleName, platform, true, true, map[string]string{})
    37  	if err != nil {
    38  		return err
    39  	}
    40  	logs.Logger.Infof(buildFinishedMsg, moduleName)
    41  	return nil
    42  }
    43  
    44  // ExecuteSoloBuild - executes build of module from stand alone command
    45  func ExecuteSoloBuild(source, target string, extensions []string, modulesNames []string, allDependencies bool,
    46  	generateMtadFlag bool, platform string,
    47  	wdGetter func() (string, error)) error {
    48  
    49  	if len(modulesNames) == 0 {
    50  		return errors.New(buildFailedOnEmptyModulesMsg)
    51  	}
    52  
    53  	sourceDir, err := getSoloModuleBuildAbsSource(source, wdGetter)
    54  	if err != nil {
    55  		return wrapBuildError(err, modulesNames)
    56  	}
    57  
    58  	loc, err := dir.Location(sourceDir, "", dir.Dev, extensions, wdGetter)
    59  	if err != nil {
    60  		return wrapBuildError(err, modulesNames)
    61  	}
    62  
    63  	mtaObj, err := loc.ParseFile()
    64  	if err != nil {
    65  		return err
    66  	}
    67  
    68  	// Fail-fast check on modules whose build results are resolved (not glob patterns),
    69  	// so we can give the error before building the modules.
    70  	// After the build we perform another check on the actual build result paths (including glob patterns)
    71  	err = checkResolvedBuildResultsConflicts(mtaObj, sourceDir, target, extensions, modulesNames, wdGetter)
    72  	if err != nil {
    73  		return wrapBuildError(err, modulesNames)
    74  	}
    75  
    76  	allModulesSorted, err := buildops.GetModulesNames(mtaObj)
    77  	if err != nil {
    78  		return wrapBuildError(err, modulesNames)
    79  	}
    80  
    81  	selectedModulesMap := make(map[string]bool)
    82  	var selectedModulesWithDependenciesMap map[string]bool
    83  
    84  	for _, moduleName := range modulesNames {
    85  		selectedModulesMap[moduleName] = true
    86  	}
    87  
    88  	if allDependencies {
    89  		selectedModulesWithDependenciesMap = make(map[string]bool)
    90  		for module := range selectedModulesMap {
    91  			err = collectSelectedModulesAndDependencies(mtaObj, selectedModulesWithDependenciesMap, module)
    92  			if err != nil {
    93  				return wrapBuildError(err, modulesNames)
    94  			}
    95  		}
    96  	} else {
    97  		selectedModulesWithDependenciesMap = selectedModulesMap
    98  	}
    99  
   100  	sortedModules := sortModules(allModulesSorted, selectedModulesWithDependenciesMap)
   101  
   102  	if allDependencies && len(sortedModules) > 1 {
   103  		logs.Logger.Infof(buildWithDependenciesMsg, `"`+strings.Join(sortedModules, `","`)+`"`)
   104  	} else if len(sortedModules) > 1 {
   105  		logs.Logger.Infof(multiBuildMsg, `"`+strings.Join(sortedModules, `", "`)+`"`)
   106  	}
   107  
   108  	packedModulePaths, err := buildModules(sourceDir, target, extensions, sortedModules, selectedModulesMap, wdGetter)
   109  	if err != nil {
   110  		return wrapBuildError(err, modulesNames)
   111  	}
   112  
   113  	if generateMtadFlag {
   114  		err = generateMtad(mtaObj, loc, target, platform, packedModulePaths, wdGetter)
   115  		if err != nil {
   116  			return wrapBuildError(err, modulesNames)
   117  		}
   118  	}
   119  
   120  	if len(modulesNames) > 1 {
   121  		logs.Logger.Infof(multiBuildFinishedMsg)
   122  	}
   123  
   124  	return nil
   125  }
   126  
   127  func checkResolvedBuildResultsConflicts(mtaObj *mta.MTA, source, target string, extensions []string, modulesNames []string, wdGetter func() (string, error)) error {
   128  
   129  	resultPathModuleNameMap := make(map[string]string)
   130  
   131  	for _, moduleName := range modulesNames {
   132  
   133  		module, err := mtaObj.GetModuleByName(moduleName)
   134  		if err != nil {
   135  			return err
   136  		}
   137  		moduleLoc, err := getModuleLocation(source, target, module.Name, extensions, wdGetter)
   138  		if err != nil {
   139  			return err
   140  		}
   141  
   142  		_, defaultBuildResult, err := commands.CommandProvider(*module)
   143  		if err != nil {
   144  			return err
   145  		}
   146  		targetArtifact, _, err := buildops.GetModuleTargetArtifactPath(moduleLoc, false, module, defaultBuildResult, false)
   147  		if err != nil {
   148  			return err
   149  		}
   150  
   151  		// we ignore glob patterns and only check actual paths here because the build results don't exist yet
   152  		if strings.ContainsAny(targetArtifact, "*?[]") {
   153  			continue
   154  		}
   155  		moduleName, pathInUse := resultPathModuleNameMap[targetArtifact]
   156  		if pathInUse {
   157  			return errors.Errorf(multiBuildWithPathsConflictMsg, module.Name, moduleName, filepath.Dir(targetArtifact), filepath.Base(targetArtifact))
   158  		}
   159  		resultPathModuleNameMap[targetArtifact] = module.Name
   160  	}
   161  
   162  	return nil
   163  }
   164  
   165  func generateMtad(mtaObj *mta.MTA, loc dir.ITargetPath, target string,
   166  	platform string, packedModulePaths map[string]string, wdGetter func() (string, error)) error {
   167  
   168  	platform, err := validatePlatform(platform)
   169  	if err != nil {
   170  		return err
   171  	}
   172  
   173  	mtadTargetPath, err := getMtadPath(target, wdGetter)
   174  	if err != nil {
   175  		return err
   176  	}
   177  	mtadLocation := mtadLoc{path: mtadTargetPath}
   178  
   179  	return genMtad(mtaObj, &mtadLocation, loc, false, platform, false, packedModulePaths, yaml.Marshal)
   180  }
   181  
   182  func getMtadPath(target string, wdGetter func() (string, error)) (string, error) {
   183  	if target != "" {
   184  		return target, nil
   185  	}
   186  	return wdGetter()
   187  }
   188  
   189  func wrapBuildError(err error, modules []string) error {
   190  	if len(modules) == 1 {
   191  		return errors.Wrapf(err, buildFailedMsg, modules[0])
   192  	}
   193  	return errors.Wrapf(err, multiBuildFailedMsg)
   194  }
   195  
   196  func collectSelectedModulesAndDependencies(mtaObj *mta.MTA, modulesWithDependencies map[string]bool, moduleName string) error {
   197  
   198  	if modulesWithDependencies[moduleName] {
   199  		return nil
   200  	}
   201  
   202  	modulesWithDependencies[moduleName] = true
   203  	module, err := mtaObj.GetModuleByName(moduleName)
   204  	if err != nil {
   205  		return err
   206  	}
   207  	for _, requires := range buildops.GetBuildRequires(module) {
   208  		requiredModule, err := mtaObj.GetModuleByName(requires.Name)
   209  		if err != nil {
   210  			return err
   211  		}
   212  
   213  		err = collectSelectedModulesAndDependencies(mtaObj, modulesWithDependencies, requiredModule.Name)
   214  		if err != nil {
   215  			return err
   216  		}
   217  	}
   218  	return nil
   219  }
   220  
   221  func buildModules(source, target string, extensions []string, modulesToBuild []string,
   222  	modulesToPack map[string]bool, wdGetter func() (string, error)) (packedModulePaths map[string]string, err error) {
   223  
   224  	buildResults := make(map[string]string)
   225  	for _, module := range modulesToBuild {
   226  		err := buildSelectedModule(source, target, extensions, module, modulesToPack[module], buildResults, wdGetter)
   227  
   228  		if err != nil {
   229  			return nil, err
   230  		}
   231  	}
   232  
   233  	packedModulePaths = make(map[string]string)
   234  	for buildResult, moduleName := range buildResults {
   235  		packedModulePaths[moduleName] = buildResult
   236  	}
   237  	return packedModulePaths, nil
   238  }
   239  
   240  func buildSelectedModule(source, target string, extensions []string, module string,
   241  	toPack bool, buildResults map[string]string, wdGetter func() (string, error)) error {
   242  
   243  	logs.Logger.Infof(buildMsg, module)
   244  
   245  	moduleLoc, err := getModuleLocation(source, target, module, extensions, wdGetter)
   246  	if err != nil {
   247  		return err
   248  	}
   249  
   250  	err = buildModule(moduleLoc, moduleLoc, module, "", false, toPack, buildResults)
   251  	if err != nil {
   252  		return err
   253  	}
   254  
   255  	logs.Logger.Infof(buildFinishedMsg, module)
   256  	return nil
   257  }
   258  
   259  func sortModules(allModulesSorted []string, selectedModulesMap map[string]bool) []string {
   260  	var result []string
   261  	for _, module := range allModulesSorted {
   262  		_, selected := selectedModulesMap[module]
   263  		if selected {
   264  			result = append(result, module)
   265  		}
   266  	}
   267  	return result
   268  }
   269  
   270  func getModuleLocation(source, target, moduleName string, extensions []string, wdGetter func() (string, error)) (*dir.ModuleLoc, error) {
   271  	targetDir, err := getSoloModuleBuildAbsTarget(source, target, moduleName, wdGetter)
   272  	if err != nil {
   273  		return nil, err
   274  	}
   275  
   276  	loc, err := dir.Location(source, targetDir, dir.Dev, extensions, wdGetter)
   277  	if err != nil {
   278  		return nil, err
   279  	}
   280  
   281  	return dir.ModuleLocation(loc, target != ""), nil
   282  }
   283  
   284  func getSoloModuleBuildAbsSource(source string, wdGetter func() (string, error)) (string, error) {
   285  	if source == "" {
   286  		return wdGetter()
   287  	}
   288  	return filepath.Abs(source)
   289  }
   290  
   291  func getSoloModuleBuildAbsTarget(absSource, target, moduleName string, wdGetter func() (string, error)) (string, error) {
   292  	if target != "" {
   293  		return filepath.Abs(target)
   294  	}
   295  
   296  	target, err := wdGetter()
   297  	if err != nil {
   298  		return "", err
   299  	}
   300  	_, projectFolderName := filepath.Split(absSource)
   301  	tmpFolderName := "." + projectFolderName + dir.TempFolderSuffix
   302  
   303  	// default target is <current folder>/.<project folder>_mta_tmp/<module_name>
   304  	return filepath.Join(target, tmpFolderName, moduleName), nil
   305  }
   306  
   307  // ExecutePack - executes packing of module
   308  func ExecutePack(source, target string, extensions []string, moduleName, platform string, wdGetter func() (string, error)) error {
   309  	logs.Logger.Infof(packMsg, moduleName)
   310  
   311  	loc, err := dir.Location(source, target, dir.Dev, extensions, wdGetter)
   312  	if err != nil {
   313  		return errors.Wrapf(err, packFailedOnLocMsg, moduleName)
   314  	}
   315  	// validate platform
   316  	platform, err = validatePlatform(platform)
   317  	if err != nil {
   318  		return err
   319  	}
   320  
   321  	module, _, defaultBuildResult, err := commands.GetModuleAndCommands(loc, moduleName)
   322  	if err != nil {
   323  		return errors.Wrapf(err, packFailedOnCommandsMsg, moduleName)
   324  	}
   325  
   326  	if buildops.IfNoSource(module) {
   327  		logs.Logger.Infof(packSkippedMsg, module.Name)
   328  		return nil
   329  	}
   330  
   331  	if module.Path == "" {
   332  		return fmt.Errorf(packFailedOnEmptyPathMsg, moduleName)
   333  	}
   334  
   335  	err = packModule(loc, module, moduleName, platform, defaultBuildResult, true, map[string]string{})
   336  	if err != nil {
   337  		return err
   338  	}
   339  
   340  	return nil
   341  }
   342  
   343  // buildModule - builds module
   344  func buildModule(mtaParser dir.IMtaParser, moduleLoc dir.IModule, moduleName, platform string,
   345  	checkPlatform bool, toPack bool, buildResults map[string]string) error {
   346  
   347  	var err error
   348  	if checkPlatform {
   349  		// validate platform
   350  		platform, err = validatePlatform(platform)
   351  		if err != nil {
   352  			return err
   353  		}
   354  	}
   355  
   356  	// Get module respective command's to execute
   357  	module, mCmd, defaultBuildResults, err := commands.GetModuleAndCommands(mtaParser, moduleName)
   358  	if err != nil {
   359  		return errors.Wrapf(err, buildFailedOnCommandsMsg, moduleName)
   360  	}
   361  
   362  	if buildops.IfNoSource(module) {
   363  		logs.Logger.Infof(buildSkippedMsg, module.Name)
   364  		return nil
   365  	}
   366  
   367  	if module.Path == "" {
   368  		return fmt.Errorf(buildFailedOnEmptyPathMsg, moduleName)
   369  	}
   370  
   371  	// Development descriptor - build includes:
   372  	// 1. module dependencies processing
   373  	e := buildops.ProcessDependencies(mtaParser, moduleLoc, moduleName)
   374  	if e != nil {
   375  		return errors.Wrapf(e, buildFailedOnDepsMsg, moduleName)
   376  	}
   377  
   378  	// 2. module type dependent commands execution
   379  	modulePath := moduleLoc.GetSourceModuleDir(module.Path)
   380  
   381  	// Get module commands
   382  	commandList, e := commands.CmdConverter(modulePath, mCmd)
   383  	if e != nil {
   384  		return errors.Wrapf(e, buildFailedOnCommandsMsg, moduleName)
   385  	}
   386  
   387  	// Execute child-process with module respective commands
   388  	var timeout string
   389  	if module.BuildParams != nil && module.BuildParams["timeout"] != nil {
   390  		var ok bool
   391  		timeout, ok = module.BuildParams["timeout"].(string)
   392  		if !ok {
   393  			return errors.Errorf(exec.ExecInvalidTimeoutMsg, fmt.Sprint(module.BuildParams["timeout"]))
   394  		}
   395  	}
   396  	e = exec.ExecuteWithTimeout(commandList, timeout, true)
   397  	if e != nil {
   398  		return errors.Wrapf(e, buildFailedMsg, moduleName)
   399  	}
   400  
   401  	if toPack {
   402  		// 3. Packing the modules build artifacts (include node modules)
   403  		// into the artifactsPath dir as data zip
   404  		return packModule(moduleLoc, module, moduleName, platform, defaultBuildResults, checkPlatform, buildResults)
   405  	}
   406  
   407  	return nil
   408  }
   409  
   410  // packModule - pack build module artifacts
   411  func packModule(moduleLoc dir.IModule, module *mta.Module, moduleName, platform, defaultBuildResult string,
   412  	checkPlatform bool, buildResults map[string]string) error {
   413  
   414  	if checkPlatform && !buildops.PlatformDefined(module, platform) {
   415  		return nil
   416  	}
   417  
   418  	logs.Logger.Info(fmt.Sprintf(buildResultMsg, moduleName, moduleLoc.GetTargetModuleDir(moduleName)))
   419  
   420  	sourceArtifact, err := buildops.GetModuleSourceArtifactPath(moduleLoc, false, module, defaultBuildResult, true)
   421  	if err != nil {
   422  		return errors.Wrapf(err, packFailedOnBuildArtifactMsg, moduleName)
   423  	}
   424  	targetArtifact, toArchive, err := buildops.GetModuleTargetArtifactPath(moduleLoc, false, module, defaultBuildResult, true)
   425  	if err != nil {
   426  		return errors.Wrapf(err, packFailedOnTargetArtifactMsg, moduleName)
   427  	}
   428  
   429  	conflictingModule, ok := buildResults[targetArtifact]
   430  	if ok {
   431  		return fmt.Errorf(multiBuildWithPathsConflictMsg, conflictingModule, module.Name, filepath.Dir(targetArtifact), filepath.Base(targetArtifact))
   432  	}
   433  	buildResults[targetArtifact] = moduleName
   434  
   435  	if !toArchive {
   436  		return copyModuleArchiveToResultDir(sourceArtifact, targetArtifact, moduleName)
   437  	}
   438  
   439  	return archiveModuleToResultDir(sourceArtifact, targetArtifact, getIgnores(moduleLoc, module, sourceArtifact), moduleName)
   440  }
   441  
   442  func copyModuleArchiveToResultDir(source, target, moduleName string) error {
   443  	// Create empty folder with name as before the zip process
   444  	// to put the file such as data.zip inside
   445  	modulePathInTmpFolder := filepath.Dir(target)
   446  	err := dir.CreateDirIfNotExist(modulePathInTmpFolder)
   447  	if err != nil {
   448  		return errors.Wrapf(err, packFailedOnFolderCreationMsg, moduleName, modulePathInTmpFolder)
   449  	}
   450  
   451  	err = dir.CopyFile(source, target)
   452  	if err != nil {
   453  		return errors.Wrapf(err, packFailedOnCopyMsg, moduleName, source, target)
   454  	}
   455  	return nil
   456  }
   457  
   458  func archiveModuleToResultDir(buildResult string, requestedResultFileName string, ignore []string, moduleName string) error {
   459  	// Archive the folder without the ignored files and/or subfolders, which are excluded from the package.
   460  	err := dir.Archive(buildResult, requestedResultFileName, ignore)
   461  	if err != nil {
   462  		return errors.Wrapf(err, PackFailedOnArchMsg, moduleName)
   463  	}
   464  	return nil
   465  }
   466  
   467  // getIgnores - get files and/or subfolders to exclude from the package.
   468  func getIgnores(moduleLoc dir.IModule, module *mta.Module, moduleResultPath string) []string {
   469  	var ignoreList []string
   470  	// ignore defined in build params is declared
   471  	if module.BuildParams != nil && module.BuildParams[ignore] != nil {
   472  		ignoreList = convert(module.BuildParams[ignore].([]interface{}))
   473  	}
   474  	// we add target folder to the list of ignores to avoid it's packaging
   475  	// it can be the case only when target folder is subfolder (on any level) of the archived folder path
   476  	// the ignored folder is the root where all the build results are created, even if we are building more than one module
   477  	targetFolder := moduleLoc.GetTargetTmpRoot()
   478  	relativeTarget, err := filepath.Rel(moduleResultPath, targetFolder)
   479  	if err == nil && !(relativeTarget == ".." || strings.HasPrefix(relativeTarget, ".."+string(os.PathSeparator))) {
   480  		ignoreList = append(ignoreList, relativeTarget)
   481  	}
   482  
   483  	return ignoreList
   484  }
   485  
   486  // Convert slice []interface{} to slice []string
   487  func convert(data []interface{}) []string {
   488  	aString := make([]string, len(data))
   489  	for i, v := range data {
   490  		aString[i] = v.(string)
   491  	}
   492  	return aString
   493  }
   494  
   495  // CopyMtaContent copies the content of all modules and resources which are presented in the deployment descriptor,
   496  // in the source directory, to the target directory
   497  func CopyMtaContent(source, target string, extensions []string, copyInParallel bool, wdGetter func() (string, error)) error {
   498  
   499  	logs.Logger.Info(copyStartMsg)
   500  	loc, err := dir.Location(source, target, dir.Dep, extensions, wdGetter)
   501  	if err != nil {
   502  		return errors.Wrap(err, copyContentFailedOnLocMsg)
   503  	}
   504  	mtaObj, err := loc.ParseFile()
   505  	if err != nil {
   506  		return errors.Wrapf(err, copyContentFailedMsg)
   507  	}
   508  	err = copyModuleContent(loc.GetSource(), loc.GetTargetTmpDir(), mtaObj, copyInParallel)
   509  	if err != nil {
   510  		return err
   511  	}
   512  
   513  	err = copyRequiredDependencyContent(loc.GetSource(), loc.GetTargetTmpDir(), mtaObj, copyInParallel)
   514  	if err != nil {
   515  		return err
   516  	}
   517  
   518  	return copyResourceContent(loc.GetSource(), loc.GetTargetTmpDir(), mtaObj, copyInParallel)
   519  }
   520  
   521  func copyModuleContent(source, target string, mta *mta.MTA, copyInParallel bool) error {
   522  	return copyMtaContent(source, target, getModulesWithPaths(mta.Modules), copyInParallel)
   523  }
   524  
   525  func copyResourceContent(source, target string, mta *mta.MTA, copyInParallel bool) error {
   526  	return copyMtaContent(source, target, getResourcesPaths(mta.Resources), copyInParallel)
   527  }
   528  
   529  func copyRequiredDependencyContent(source, target string, mta *mta.MTA, copyInParallel bool) error {
   530  	return copyMtaContent(source, target, getRequiredDependencyPaths(mta.Modules), copyInParallel)
   531  }
   532  
   533  func getRequiredDependencyPaths(mtaModules []*mta.Module) []string {
   534  	result := make([]string, 0)
   535  	for _, module := range mtaModules {
   536  		requiredDependenciesWithPaths := getRequiredDependenciesWithPathsForModule(module)
   537  		result = append(result, requiredDependenciesWithPaths...)
   538  	}
   539  	return result
   540  }
   541  
   542  func getRequiredDependenciesWithPathsForModule(module *mta.Module) []string {
   543  	result := make([]string, 0)
   544  	for _, requiredDependency := range module.Requires {
   545  		if requiredDependency.Parameters["path"] != nil {
   546  			result = append(result, requiredDependency.Parameters["path"].(string))
   547  		}
   548  	}
   549  	return result
   550  }
   551  func copyMtaContent(source, target string, mtaPaths []string, copyInParallel bool) error {
   552  	copiedMtaContents := make([]string, 0)
   553  	for _, mtaPath := range mtaPaths {
   554  		sourceMtaContent := filepath.Join(source, mtaPath)
   555  		if doesNotExist(sourceMtaContent) {
   556  			return handleCopyMtaContentFailure(target, copiedMtaContents, pathNotExistsMsg, []interface{}{mtaPath})
   557  		}
   558  		copiedMtaContents = append(copiedMtaContents, mtaPath)
   559  		targetMtaContent := filepath.Join(target, mtaPath)
   560  		err := copyMtaContentFromPath(sourceMtaContent, targetMtaContent, mtaPath, target, copyInParallel)
   561  		if err != nil {
   562  			return handleCopyMtaContentFailure(target, copiedMtaContents, copyContentCopyFailedMsg, []interface{}{mtaPath, source, err.Error()})
   563  		}
   564  		logs.Logger.Debugf(copyDoneMsg, mtaPath)
   565  	}
   566  
   567  	return nil
   568  }
   569  
   570  func handleCopyMtaContentFailure(targetLocation string, copiedMtaContents []string,
   571  	message string, messageArguments []interface{}) error {
   572  	errCleanup := cleanUpCopiedContent(targetLocation, copiedMtaContents)
   573  	if errCleanup == nil {
   574  		return errors.Errorf(message, messageArguments...)
   575  	}
   576  	return errors.Errorf(message+"; "+cleanupFailedMsg, messageArguments...)
   577  }
   578  
   579  func copyMtaContentFromPath(sourceMtaContent, targetMtaContent, mtaContentPath, target string, copyInParallel bool) error {
   580  	mtaContentInfo, _ := os.Stat(sourceMtaContent)
   581  	if mtaContentInfo.IsDir() {
   582  		if copyInParallel {
   583  			return dir.CopyDir(sourceMtaContent, targetMtaContent, true, dir.CopyEntriesInParallel)
   584  		}
   585  		return dir.CopyDir(sourceMtaContent, targetMtaContent, true, dir.CopyEntries)
   586  	}
   587  
   588  	mtaContentParentDir := filepath.Dir(mtaContentPath)
   589  	err := dir.CreateDirIfNotExist(filepath.Join(target, mtaContentParentDir))
   590  	if err != nil {
   591  		return err
   592  	}
   593  	return dir.CopyFileWithMode(sourceMtaContent, targetMtaContent, mtaContentInfo.Mode())
   594  }
   595  
   596  func cleanUpCopiedContent(targetLocation string, copiendMtaContents []string) error {
   597  	for _, copiedMtaContent := range copiendMtaContents {
   598  		err := os.RemoveAll(filepath.Join(targetLocation, copiedMtaContent))
   599  		if err != nil {
   600  			return err
   601  		}
   602  	}
   603  	return nil
   604  }
   605  
   606  func doesNotExist(path string) bool {
   607  	_, err := os.Stat(path)
   608  	return os.IsNotExist(err)
   609  }
   610  
   611  func getModulesWithPaths(mtaModules []*mta.Module) []string {
   612  	result := make([]string, 0)
   613  	for _, module := range mtaModules {
   614  		if module.Path != "" {
   615  			result = append(result, module.Path)
   616  		}
   617  	}
   618  	return result
   619  }
   620  
   621  func getResourcesPaths(resources []*mta.Resource) []string {
   622  	result := make([]string, 0)
   623  	for _, resource := range resources {
   624  		if resource.Parameters["path"] != nil {
   625  			result = append(result, resource.Parameters["path"].(string))
   626  		}
   627  	}
   628  	return result
   629  }