Use latest alizer library version, including .net detection (#5804)

* Use latest alizer library version

* Update quickstart guide
This commit is contained in:
Philippe Martin
2022-06-09 10:40:19 +02:00
committed by GitHub
parent 0b087451de
commit d5935a16cc
11 changed files with 155 additions and 64 deletions

View File

@@ -227,9 +227,9 @@ $ odo init
Interactive mode enabled, please answer the following questions:
Based on the files in the current directory odo detected
Language: javascript
Project type: nodejs
The devfile "nodejs" from the registry "DefaultDevfileRegistry" will be downloaded.
Language: dotnet
Project type: dotnet
The devfile "dotnet50" from the registry "DefaultDevfileRegistry" will be downloaded.
? Is this correct? No
? Select language: dotnet
? Select project type: .NET 6.0

2
go.mod
View File

@@ -34,7 +34,7 @@ require (
github.com/operator-framework/operator-lifecycle-manager v0.17.0
github.com/pborman/uuid v1.2.0
github.com/posener/complete v1.1.1
github.com/redhat-developer/alizer/go v0.0.0-20220215154256-33df7feef4ae
github.com/redhat-developer/alizer/go v0.0.0-20220530162645-f27a60be88a1
github.com/redhat-developer/service-binding-operator v1.0.1-0.20211222115357-5b7bbba3bfb3
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06
github.com/securego/gosec/v2 v2.8.0

2
go.sum
View File

@@ -1152,6 +1152,8 @@ github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/redhat-developer/alizer/go v0.0.0-20220215154256-33df7feef4ae h1:N2wsIYtziHQ51GNcJY5YcB0YldpR5BwPoTvby+l0vy8=
github.com/redhat-developer/alizer/go v0.0.0-20220215154256-33df7feef4ae/go.mod h1:EKkrP0Am7Xt/yg3dF8uH1SSoOcaZmBom8Iy6CJPPDok=
github.com/redhat-developer/alizer/go v0.0.0-20220530162645-f27a60be88a1 h1:uhf+ll3f7uFvNGBndseVpiGEt6vLiw9vjCg2YH13uk4=
github.com/redhat-developer/alizer/go v0.0.0-20220530162645-f27a60be88a1/go.mod h1:EKkrP0Am7Xt/yg3dF8uH1SSoOcaZmBom8Iy6CJPPDok=
github.com/redhat-developer/service-binding-operator v1.0.1-0.20211222115357-5b7bbba3bfb3 h1:hj+Y8vIzfQzzGx0az0MbIqDcW0+MZMc2rht8LuKt8uA=
github.com/redhat-developer/service-binding-operator v1.0.1-0.20211222115357-5b7bbba3bfb3/go.mod h1:pODWh91lgIyjf2n9ZqWYb1EBrLTmvKnjusKw0eG4vcE=
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=

View File

@@ -1,8 +1,6 @@
package alizer
import (
"reflect"
"github.com/redhat-developer/alizer/go/pkg/apis/recognizer"
"github.com/redhat-developer/odo/pkg/api"
"github.com/redhat-developer/odo/pkg/registry"
@@ -38,17 +36,7 @@ func (o *Alizer) DetectFramework(path string) (recognizer.DevFileType, api.Regis
if err != nil {
return recognizer.DevFileType{}, api.Registry{}, err
}
// TODO(feloy): This part won't be necessary when SelectDevFileFromTypes returns the index
var indexOfDetected int
for i, typeFromList := range types {
if reflect.DeepEqual(typeFromList, typ) {
indexOfDetected = i
break
}
}
registry := components.Items[indexOfDetected].Registry
return typ, registry, nil
return types[typ], components.Items[typ].Registry, nil
}
func GetDevfileLocationFromDetection(typ recognizer.DevFileType, registry api.Registry) *api.DevfileLocation {

View File

@@ -49,7 +49,9 @@ func (j GoEnricher) DoEnrichLanguage(language *language.Language, files *[]strin
if err != nil {
return
}
language.Tools = []string{goModFile.Go.Version}
if goModFile.Go != nil {
language.Tools = []string{goModFile.Go.Version}
}
detectGoFrameworks(language, goModFile)
}
}

View File

@@ -11,8 +11,10 @@
package recognizer
import (
"errors"
"io/fs"
"path/filepath"
"regexp"
"strings"
enricher "github.com/redhat-developer/alizer/go/pkg/apis/enricher"
@@ -25,8 +27,21 @@ type Component struct {
Languages []language.Language
}
func DetectComponentsInRoot(path string) ([]Component, error) {
files, err := getFilePathsInRoot(path)
if err != nil {
return []Component{}, err
}
components, err := detectComponents(files)
if err != nil {
return []Component{}, err
}
return components, nil
}
func DetectComponents(path string) ([]Component, error) {
files, err := getFilePaths(path)
files, err := getFilePathsFromRoot(path)
if err != nil {
return []Component{}, err
}
@@ -53,7 +68,7 @@ func DetectComponents(path string) ([]Component, error) {
func getComponentsWithoutConfigFile(directories []string) []Component {
var components []Component
for _, dir := range directories {
component, _ := detectComponent(dir, "")
component, _ := detectComponent(dir, []string{})
if component.Path != "" && isLangForNoConfigComponent(component.Languages) {
components = append(components, component)
}
@@ -106,15 +121,16 @@ func getDirectoriesWithoutConfigFile(root string, components []Component) []stri
return directories
}
/**
* Return all paths which are not sub-folders of some other path within the list
* Target will be added to the list if it is not a sub-folder of any other path within the list
* If a path in the list is sub-folder of Target, that path will be removed.
*
* @param target new path to be added
* @param directories list of all previously added paths
* @return the list containing all paths which are not sub-folders of any other
*/
/*
getParentFolders return all paths which are not sub-folders of some other path within the list
Target will be added to the list if it is not a sub-folder of any other path within the list
If a path in the list is sub-folder of Target, that path will be removed.
Parameters:
target: new path to be added
directories: list of all previously added paths
Returns:
the list containing all paths which are not sub-folders of any other
*/
func getParentFolders(target string, directories []string) []string {
updatedDirectories := []string{}
for _, dir := range directories {
@@ -173,38 +189,62 @@ func detectComponents(files []string) ([]Component, error) {
var components []Component
for _, file := range files {
dir, fileName := filepath.Split(file)
if language, isConfig := configurationPerLanguage[fileName]; isConfig && isConfigurationValid(language, file) {
component, err := detectComponent(dir, language)
if err != nil {
return []Component{}, err
}
if component.Path != "" {
components = append(components, component)
if dir == "" {
dir = "./"
}
languages, err := getLanguagesByConfigurationFile(configurationPerLanguage, fileName)
if err != nil {
continue
}
for _, language := range languages {
if isConfigurationValid(language, file) {
component, _ := detectComponent(dir, languages)
if component.Path != "" {
components = appendIfMissing(components, component)
break
}
}
}
}
return components, nil
}
func appendIfMissing(components []Component, component Component) []Component {
for _, comp := range components {
if strings.EqualFold(comp.Path, component.Path) {
return components
}
}
return append(components, component)
}
func getLanguagesByConfigurationFile(configurationPerLanguage map[string][]string, file string) ([]string, error) {
for regex, languages := range configurationPerLanguage {
if match, _ := regexp.MatchString(regex, file); match {
return languages, nil
}
}
return nil, errors.New("no languages found for configuration file " + file)
}
/*
detectComponent returns a Component if found:
- language must be enabled for component detection
- there should be at least one framework detected
, error otherwise
Parameters:
root: path to be used as root where to start the detection
language: language to be used as target for detection
configLanguages: languages associated to the config file found and to be used as target for detection
Returns:
component detected or error if any error occurs
*/
func detectComponent(root string, language string) (Component, error) {
func detectComponent(root string, configLanguages []string) (Component, error) {
languages, err := Analyze(root)
if err != nil {
return Component{}, err
}
languages = getLanguagesWeightedByConfigFile(languages, language)
languages = getLanguagesWeightedByConfigFile(languages, configLanguages)
if len(languages) > 0 {
if mainLang := languages[0]; mainLang.CanBeComponent && len(mainLang.Frameworks) > 0 {
if mainLang := languages[0]; mainLang.CanBeComponent {
return Component{
Path: root,
Languages: languages,
@@ -218,22 +258,24 @@ func detectComponent(root string, language string) (Component, error) {
/*
getLanguagesWeightedByConfigFile returns the list of languages reordered by importance per config file.
Language found by analyzing the config file is used as target.
Language found by analyzing the config file is used as target.
Parameters:
languages: list of languages to be reordered
languageByConfig: target language
configLanguages: languages associated to the config file found and to be used as target languages
Returns:
list of languages reordered
*/
func getLanguagesWeightedByConfigFile(languages []language.Language, languageByConfig string) []language.Language {
if languageByConfig == "" {
func getLanguagesWeightedByConfigFile(languages []language.Language, configLanguages []string) []language.Language {
if len(configLanguages) == 0 {
return languages
}
for index, lang := range languages {
if strings.EqualFold(lang.Name, languageByConfig) {
sliceWithoutLang := append(languages[:index], languages[index+1:]...)
return append([]language.Language{lang}, sliceWithoutLang...)
for _, configLanguage := range configLanguages {
if strings.EqualFold(lang.Name, configLanguage) {
sliceWithoutLang := append(languages[:index], languages[index+1:]...)
return append([]language.Language{lang}, sliceWithoutLang...)
}
}
}
return languages

View File

@@ -24,34 +24,50 @@ type DevFileType struct {
Tags []string
}
func SelectDevFileFromTypes(path string, devFileTypes []DevFileType) (DevFileType, error) {
func SelectDevFileFromTypes(path string, devFileTypes []DevFileType) (int, error) {
components, _ := DetectComponentsInRoot(path)
if len(components) > 0 {
devfile, err := selectDevFileByLanguage(components[0].Languages[0], devFileTypes)
if err == nil {
return devfile, nil
}
}
components, _ = DetectComponents(path)
if len(components) > 0 {
devfile, err := selectDevFileByLanguage(components[0].Languages[0], devFileTypes)
if err == nil {
return devfile, nil
}
}
languages, err := Analyze(path)
if err != nil {
return DevFileType{}, err
return -1, err
}
devfile, err := SelectDevFileUsingLanguagesFromTypes(languages, devFileTypes)
if err != nil {
return DevFileType{}, errors.New("No valid devfile found for project in " + path)
return -1, errors.New("No valid devfile found for project in " + path)
}
return devfile, nil
}
func SelectDevFileUsingLanguagesFromTypes(languages []language.Language, devFileTypes []DevFileType) (DevFileType, error) {
func SelectDevFileUsingLanguagesFromTypes(languages []language.Language, devFileTypes []DevFileType) (int, error) {
for _, language := range languages {
devfile, err := selectDevFileByLanguage(language, devFileTypes)
if err == nil {
return devfile, nil
}
}
return DevFileType{}, errors.New("no valid devfile found by using those languages")
return -1, errors.New("no valid devfile found by using those languages")
}
func selectDevFileByLanguage(language language.Language, devFileTypes []DevFileType) (DevFileType, error) {
func selectDevFileByLanguage(language language.Language, devFileTypes []DevFileType) (int, error) {
scoreTarget := 0
devfileTarget := DevFileType{}
devfileTarget := -1
FRAMEWORK_WEIGHT := 10
TOOL_WEIGHT := 5
for _, devFile := range devFileTypes {
for index, devFile := range devFileTypes {
score := 0
if strings.EqualFold(devFile.Language, language.Name) || matches(language.Aliases, devFile.Language) {
score++
@@ -69,7 +85,7 @@ func selectDevFileByLanguage(language language.Language, devFileTypes []DevFileT
}
if score > scoreTarget {
scoreTarget = score
devfileTarget = devFile
devfileTarget = index
}
}

View File

@@ -11,9 +11,11 @@
package recognizer
import (
"io/ioutil"
"os"
"path/filepath"
"sort"
"strings"
enricher "github.com/redhat-developer/alizer/go/pkg/apis/enricher"
"github.com/redhat-developer/alizer/go/pkg/apis/language"
@@ -29,7 +31,7 @@ func Analyze(path string) ([]language.Language, error) {
languagesFile := langfile.Get()
languagesDetected := make(map[string]languageItem)
paths, err := getFilePaths(path)
paths, err := getFilePathsFromRoot(path)
if err != nil {
return []language.Language{}, err
}
@@ -106,12 +108,33 @@ func extractExtensions(paths []string) map[string]int {
return extensions
}
func getFilePaths(root string) ([]string, error) {
func getFilePathsFromRoot(root string) ([]string, error) {
var files []string
err := filepath.Walk(root,
func(path string, info os.FileInfo, err error) error {
files = append(files, path)
if !info.IsDir() && isFileInRoot(root, path) {
files = append([]string{path}, files...)
} else {
files = append(files, path)
}
return nil
})
return files, err
}
func isFileInRoot(root string, file string) bool {
dir, _ := filepath.Split(file)
return strings.EqualFold(filepath.Clean(dir), filepath.Clean(root))
}
func getFilePathsInRoot(root string) ([]string, error) {
fileInfos, err := ioutil.ReadDir(root)
if err != nil {
return nil, err
}
var files []string
for _, fileInfo := range fileInfos {
files = append(files, filepath.Join(root, fileInfo.Name()))
}
return files, nil
}

View File

@@ -30,6 +30,7 @@ type LanguageCustomization struct {
ConfigurationFiles []string `yaml:"configuration_files"`
Component bool `yaml:"component"`
ExcludeFolders []string `yaml:"exclude_folders,omitempty"`
Aliases []string `yaml:"aliases"`
}
type LanguagesCustomizations map[string]LanguageCustomization

View File

@@ -83,9 +83,26 @@ func customizeLanguage(languageItem *LanguageItem) {
(*languageItem).ConfigurationFiles = customization.ConfigurationFiles
(*languageItem).ExcludeFolders = customization.ExcludeFolders
(*languageItem).Component = customization.Component
(*languageItem).Aliases = appendSlice((*languageItem).Aliases, customization.Aliases)
}
}
func appendSlice(values []string, toBeAdded []string) []string {
for _, item := range toBeAdded {
values = appendIfMissing(values, item)
}
return values
}
func appendIfMissing(values []string, item string) []string {
for _, value := range values {
if strings.EqualFold(value, item) {
return values
}
}
return append(values, item)
}
func getLanguagesProperties() schema.LanguagesProperties {
yamlFile, err := res.ReadFile("resources/languages.yml")
if err != nil {
@@ -140,12 +157,12 @@ func (l *LanguageFile) GetLanguageByNameOrAlias(name string) (LanguageItem, erro
return l.GetLanguageByAlias(name)
}
func (l *LanguageFile) GetConfigurationPerLanguageMapping() map[string]string {
configurationPerLanguage := make(map[string]string)
func (l *LanguageFile) GetConfigurationPerLanguageMapping() map[string][]string {
configurationPerLanguage := make(map[string][]string)
for langName, langItem := range l.languages {
configurationFiles := langItem.ConfigurationFiles
for _, configFile := range configurationFiles {
configurationPerLanguage[configFile] = langName
configurationPerLanguage[configFile] = append(configurationPerLanguage[configFile], langName)
}
}
return configurationPerLanguage

2
vendor/modules.txt vendored
View File

@@ -623,7 +623,7 @@ github.com/prometheus/common/model
github.com/prometheus/procfs
github.com/prometheus/procfs/internal/fs
github.com/prometheus/procfs/internal/util
# github.com/redhat-developer/alizer/go v0.0.0-20220215154256-33df7feef4ae
# github.com/redhat-developer/alizer/go v0.0.0-20220530162645-f27a60be88a1
## explicit; go 1.17
github.com/redhat-developer/alizer/go/pkg/apis/enricher
github.com/redhat-developer/alizer/go/pkg/apis/enricher/framework/dotnet