github.com/joey-fossa/fossa-cli@v0.7.34-0.20190708193710-569f1e8679f0/analyzers/haskell/discover.go (about)

     1  package haskell
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"strings"
     7  
     8  	"github.com/apex/log"
     9  
    10  	"github.com/fossas/fossa-cli/errors"
    11  	"github.com/fossas/fossa-cli/module"
    12  	"github.com/fossas/fossa-cli/pkg"
    13  )
    14  
    15  func NewModule(moduleName string, relativeDir string, strategy Strategy) module.Module {
    16  	return module.Module{
    17  		Name:        moduleName,
    18  		Type:        pkg.Haskell,
    19  		BuildTarget: relativeDir,
    20  		Dir:         relativeDir,
    21  		Options:     map[string]interface{}{"strategy": strategy},
    22  	}
    23  }
    24  
    25  func Discover(baseDir string, options map[string]interface{}) ([]module.Module, error) {
    26  	// List of discovered projects. Projects can be defined in
    27  	// `cabal.project` or `stack.yaml` files
    28  	projects := make(map[string]module.Module)
    29  	// List of discovered cabal files. These will be used in the case that:
    30  	// - No projects are found; or
    31  	// - A project doesn't exist in the current or a parent directory
    32  	cabalFiles := make(map[string]module.Module)
    33  
    34  	err := filepath.Walk(baseDir, func(path string, info os.FileInfo, err error) error {
    35  		if err != nil {
    36  			log.WithError(err).WithField("filename", path).Debug("failed to access path")
    37  			return err
    38  		}
    39  
    40  		if info.IsDir() {
    41  			return nil
    42  		}
    43  
    44  		moduleName := filepath.Base(path)
    45  		relativeDir, _ := filepath.Rel(baseDir, filepath.Dir(path))
    46  
    47  		if info.Name() == "cabal.project" {
    48  			projects[relativeDir] = NewModule(moduleName, relativeDir, CabalInstall)
    49  		} else if info.Name() == "stack.yaml" {
    50  			projects[relativeDir] = NewModule(moduleName, relativeDir, Stack)
    51  		} else if strings.HasSuffix(info.Name(), ".cabal") {
    52  			cabalFiles[relativeDir] = NewModule(moduleName, relativeDir, CabalInstall)
    53  		}
    54  
    55  		return nil
    56  	})
    57  
    58  	if err != nil {
    59  		return nil, errors.Wrap(err, "could not find Haskell package manifests")
    60  	}
    61  
    62  	// Prune .cabal files where parent projects are present
    63  	for cabalFilePath := range cabalFiles {
    64  		for projectPath := range projects {
    65  			// TODO: parse cabal.project and stack.yaml instead of using their paths?
    66  			rel, err := filepath.Rel(projectPath, cabalFilePath)
    67  			// filepath.Rel will produce a path containing ".." when the cabal
    68  			// file isn't in a subdirectory of the project
    69  			if err == nil && !strings.Contains(rel, "..") {
    70  				delete(cabalFiles, cabalFilePath)
    71  				break
    72  			}
    73  		}
    74  	}
    75  
    76  	var modules []module.Module
    77  	for _, m := range projects {
    78  		modules = append(modules, m)
    79  	}
    80  	for _, m := range cabalFiles {
    81  		modules = append(modules, m)
    82  	}
    83  
    84  	return modules, nil
    85  }