diff --git a/cmd/odo/alizer_test.go b/cmd/odo/alizer_test.go index 88c453653..ba55e1394 100644 --- a/cmd/odo/alizer_test.go +++ b/cmd/odo/alizer_test.go @@ -53,7 +53,7 @@ func TestOdoAlizer(t *testing.T) { path := "/" alizerClient.EXPECT().DetectFramework(gomock.Any(), path). Return(alizer.DetectedFramework{ - Type: model.DevFileType{ + Type: model.DevfileType{ Name: "framework-name", }, DefaultVersion: "1.1.1", @@ -94,7 +94,7 @@ func TestOdoAlizer(t *testing.T) { path := "/" alizerClient.EXPECT().DetectFramework(gomock.Any(), path). Return(alizer.DetectedFramework{ - Type: model.DevFileType{ + Type: model.DevfileType{ Name: "framework-name", }, DefaultVersion: "1.1.1", diff --git a/go.mod b/go.mod index a379ab36c..5fdce62ae 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/AlecAivazis/survey/v2 v2.3.5 github.com/Xuanwo/go-locale v1.1.0 github.com/blang/semver v3.5.1+incompatible - github.com/devfile/alizer v1.0.1 + github.com/devfile/alizer v1.2.1 github.com/devfile/api/v2 v2.2.1-alpha.0.20230413012049-a6c32fca0dbd github.com/devfile/library/v2 v2.2.1-0.20230524160049-04a8b3fc66c0 github.com/devfile/registry-support/index/generator v0.0.0-20230322155332-33914affc83b diff --git a/go.sum b/go.sum index f8e2cc0c7..f505a84b6 100644 --- a/go.sum +++ b/go.sum @@ -362,8 +362,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= -github.com/devfile/alizer v1.0.1 h1:VcqX8kVGvCbRTzt66S2F132q83e9vbkV2U6ShmUl3Ew= -github.com/devfile/alizer v1.0.1/go.mod h1:s08rBJWzwGFAAhdrJP0LduJDfSESfaVn/3dkUlK7Kmc= +github.com/devfile/alizer v1.2.1 h1:0CrHYGjT0xTw5CYoK/U1pYGmcpKxw9YUUVaqJWF3pZM= +github.com/devfile/alizer v1.2.1/go.mod h1:kRCsbXuzCwXIbnSR4xpVZDr8Pl8j01rl+gPfkukbf/c= github.com/devfile/api/v2 v2.0.0-20211021164004-dabee4e633ed/go.mod h1:d99eTN6QxgzihOOFyOZA+VpUyD4Q1pYRYHZ/ci9J96Q= github.com/devfile/api/v2 v2.0.0-20220117162434-6e6e6a8bc14c/go.mod h1:d99eTN6QxgzihOOFyOZA+VpUyD4Q1pYRYHZ/ci9J96Q= github.com/devfile/api/v2 v2.2.0/go.mod h1:dN7xFrOVG+iPqn4UKGibXLd5oVsdE8XyK9OEb5JL3aI= diff --git a/pkg/alizer/alizer.go b/pkg/alizer/alizer.go index 1d3c82ce9..c82f201bc 100644 --- a/pkg/alizer/alizer.go +++ b/pkg/alizer/alizer.go @@ -30,13 +30,13 @@ func NewAlizerClient(registryClient registry.Client) *Alizer { // DetectFramework uses the alizer library in order to detect the devfile // to use depending on the files in the path func (o *Alizer) DetectFramework(ctx context.Context, path string) (DetectedFramework, error) { - types := []model.DevFileType{} + types := []model.DevfileType{} components, err := o.registryClient.ListDevfileStacks(ctx, "", "", "", false, false) if err != nil { return DetectedFramework{}, err } for _, component := range components.Items { - types = append(types, model.DevFileType{ + types = append(types, model.DevfileType{ Name: component.Name, Language: component.Language, ProjectType: component.ProjectType, @@ -144,7 +144,7 @@ func (o *Alizer) DetectPorts(path string) ([]int, error) { return components[0].Ports, nil } -func NewDetectionResult(typ model.DevFileType, registry api.Registry, appPorts []int, devfileVersion, name string) *api.DetectionResult { +func NewDetectionResult(typ model.DevfileType, registry api.Registry, appPorts []int, devfileVersion, name string) *api.DetectionResult { return &api.DetectionResult{ Devfile: typ.Name, DevfileRegistry: registry.Name, diff --git a/pkg/alizer/interface.go b/pkg/alizer/interface.go index c857baba8..0c857db10 100644 --- a/pkg/alizer/interface.go +++ b/pkg/alizer/interface.go @@ -4,11 +4,12 @@ import ( "context" "github.com/devfile/alizer/pkg/apis/model" + "github.com/redhat-developer/odo/pkg/api" ) type DetectedFramework struct { - Type model.DevFileType + Type model.DevfileType DefaultVersion string Registry api.Registry Architectures []string diff --git a/pkg/init/backend/alizer_test.go b/pkg/init/backend/alizer_test.go index cb7c41478..6a7745b5e 100644 --- a/pkg/init/backend/alizer_test.go +++ b/pkg/init/backend/alizer_test.go @@ -95,7 +95,7 @@ func TestAlizerBackend_SelectDevfile(t *testing.T) { alizerClient: func(ctrl *gomock.Controller) alizer.Client { alizerClient := alizer.NewMockClient(ctrl) alizerClient.EXPECT().DetectFramework(gomock.Any(), gomock.Any()).Return(alizer.DetectedFramework{ - Type: model.DevFileType{ + Type: model.DevfileType{ Name: "a-devfile-name", }, DefaultVersion: "1.0.0", @@ -124,7 +124,7 @@ func TestAlizerBackend_SelectDevfile(t *testing.T) { alizerClient: func(ctrl *gomock.Controller) alizer.Client { alizerClient := alizer.NewMockClient(ctrl) alizerClient.EXPECT().DetectFramework(gomock.Any(), gomock.Any()).Return(alizer.DetectedFramework{ - Type: model.DevFileType{ + Type: model.DevfileType{ Name: "a-devfile-name", }, DefaultVersion: "1.0.0", @@ -178,7 +178,7 @@ func TestAlizerBackend_SelectDevfile(t *testing.T) { alizerClient: func(ctrl *gomock.Controller) alizer.Client { alizerClient := alizer.NewMockClient(ctrl) alizerClient.EXPECT().DetectFramework(gomock.Any(), gomock.Any()).Return(alizer.DetectedFramework{ - Type: model.DevFileType{ + Type: model.DevfileType{ Name: "a-devfile-name", }, DefaultVersion: "1.0.0", diff --git a/pkg/odo/cli/alizer/alizer.go b/pkg/odo/cli/alizer/alizer.go index 53a259a2d..e6db752b0 100644 --- a/pkg/odo/cli/alizer/alizer.go +++ b/pkg/odo/cli/alizer/alizer.go @@ -3,6 +3,7 @@ package alizer import ( "context" "errors" + "fmt" "github.com/redhat-developer/odo/pkg/alizer" "github.com/redhat-developer/odo/pkg/api" @@ -56,7 +57,8 @@ func (o *AlizerOptions) RunForJsonOutput(ctx context.Context) (out interface{}, workingDir := odocontext.GetWorkingDirectory(ctx) detected, err := o.clientset.AlizerClient.DetectFramework(ctx, workingDir) if err != nil { - return nil, err + //revive:disable:error-strings This is a top-level error message displayed as is to the end user + return nil, fmt.Errorf("No valid devfile found for project in %s: %w", workingDir, err) } appPorts, err := o.clientset.AlizerClient.DetectPorts(workingDir) if err != nil { diff --git a/tests/integration/interactive_init_test.go b/tests/integration/interactive_init_test.go index 5b94d438d..69fac11be 100644 --- a/tests/integration/interactive_init_test.go +++ b/tests/integration/interactive_init_test.go @@ -604,19 +604,23 @@ var _ = Describe("odo init interactive command tests", func() { lines, err := helper.ExtractLines(output) Expect(err).To(BeNil()) - Expect(len(lines)).To(BeNumerically(">", 2)) - Expect(lines[len(lines)-1]).To(Equal("Your new component 'my-dotnet-app' is ready in the current directory")) + Expect(len(lines)).To(BeNumerically(">", 2), output) + Expect(lines[len(lines)-1]).To(Equal("Your new component 'my-dotnet-app' is ready in the current directory"), output) componentNameQuestionIdx, ok := helper.FindFirstElementIndexMatchingRegExp(lines, ".*Enter component name:.*") - Expect(ok).To(BeTrue()) + Expect(ok).To(BeTrue(), + fmt.Sprintf("'Enter component name:' not found in output below:\n===OUTPUT===\n%s============\n", output)) starterProjectDownloadActionIdx, found := helper.FindFirstElementIndexMatchingRegExp(lines, ".*Downloading starter project \"([^\\s]+)\" \\[.*") - Expect(found).To(BeTrue()) - Expect(starterProjectDownloadActionIdx).To(SatisfyAll( - Not(BeZero()), - // #5495: component name question should be displayed before starter project is actually downloaded - BeNumerically(">", componentNameQuestionIdx), - ), "Action 'Downloading starter project' should have been displayed after the last interactive question ('Enter component name')") + Expect(found).To(BeTrue(), + fmt.Sprintf("'Downloading starter project \"([^\\s]+)\"' not found in output below:\n===OUTPUT===\n%s============\n", output)) + Expect(starterProjectDownloadActionIdx).To( + SatisfyAll( + Not(BeZero()), + // #5495: component name question should be displayed before starter project is actually downloaded + BeNumerically(">", componentNameQuestionIdx)), + fmt.Sprintf("Action 'Downloading starter project' should have been displayed after the last interactive question ('Enter component name').\n===OUTPUT===\n%s============\n", + output)) Expect(helper.ListFilesInDir(commonVar.Context)).To(ContainElements("devfile.yaml")) }) diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/docker_enricher.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/docker_enricher.go new file mode 100644 index 000000000..8a14364a3 --- /dev/null +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/docker_enricher.go @@ -0,0 +1,52 @@ +// +// Copyright 2023 Red Hat, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package enricher + +import ( + "context" + "github.com/devfile/alizer/pkg/apis/model" +) + +type DockerEnricher struct{} + +type DockerFrameworkDetector interface { + DoPortsDetection(component *model.Component, ctx *context.Context) +} + +func (d DockerEnricher) GetSupportedLanguages() []string { + return []string{"dockerfile"} +} + +func (d DockerEnricher) DoEnrichLanguage(language *model.Language, _ *[]string) { + // The Dockerfile language does not contain frameworks + return +} + +func (d DockerEnricher) DoEnrichComponent(component *model.Component, _ model.DetectionSettings, _ *context.Context) { + projectName := GetDefaultProjectName(component.Path) + component.Name = projectName + + var ports []int + ports = GetPortsFromDockerFile(component.Path) + if len(ports) > 0 { + component.Ports = ports + } + return +} + +func (d DockerEnricher) IsConfigValidForComponentDetection(language string, config string) bool { + return IsConfigurationValidForLanguage(language, config) +} diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/enricher.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/enricher.go index 1ab28e7ed..85a5823b5 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/enricher.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/enricher.go @@ -19,18 +19,14 @@ package enricher import ( "context" "fmt" - "io" - "io/ioutil" "os" "path/filepath" "regexp" - "strconv" "strings" "github.com/devfile/alizer/pkg/apis/model" "github.com/devfile/alizer/pkg/utils" "github.com/devfile/alizer/pkg/utils/langfiles" - "github.com/moby/buildkit/frontend/dockerfile/parser" "gopkg.in/yaml.v3" ) @@ -93,6 +89,7 @@ func getEnrichers() []Enricher { &DotNetEnricher{}, &GoEnricher{}, &PHPEnricher{}, + &DockerEnricher{}, } } @@ -123,7 +120,7 @@ func GetDefaultProjectName(path string) string { // GetPortsFromDockerFile returns a slice of port numbers from Dockerfiles in the given directory. func GetPortsFromDockerFile(root string) []int { - locations := getLocations(root) + locations := utils.GetLocations(root) for _, location := range locations { filePath := filepath.Join(root, location) cleanFilePath := filepath.Clean(filePath) @@ -135,57 +132,12 @@ func GetPortsFromDockerFile(root string) []int { } return nil }() - return getPortsFromReader(file) + return utils.ReadPortsFromDockerfile(file) } } return []int{} } -func getLocations(root string) []string { - locations := []string{"Dockerfile", "Containerfile"} - dirItems, err := ioutil.ReadDir(root) - if err != nil { - return locations - } - for _, item := range dirItems { - if strings.HasPrefix(item.Name(), ".") { - continue - } - tmpPath := fmt.Sprintf("%s%s", root, item.Name()) - fileInfo, err := os.Stat(tmpPath) - if err != nil { - continue - } - if fileInfo.IsDir() { - locations = append(locations, fmt.Sprintf("%s/%s", item.Name(), "Dockerfile")) - locations = append(locations, fmt.Sprintf("%s/%s", item.Name(), "Containerfile")) - } - } - return locations -} - -// getPortsFromReader returns a slice of port numbers. -func getPortsFromReader(file io.Reader) []int { - var ports []int - res, err := parser.Parse(file) - if err != nil { - return ports - } - - for _, child := range res.AST.Children { - // check for the potential port number in a Dockerfile/Containerfile - if strings.ToLower(child.Value) == "expose" { - for n := child.Next; n != nil; n = n.Next { - if port, err := strconv.Atoi(n.Value); err == nil { - ports = append(ports, port) - } - - } - } - } - return ports -} - // GetPortsFromDockerComposeFile returns a slice of port numbers from a compose file. func GetPortsFromDockerComposeFile(componentPath string, settings model.DetectionSettings) []int { var ports []int diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/dotnet/dotnet_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/dotnet/dotnet_detector.go index f7b05e232..eb349a3ab 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/dotnet/dotnet_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/dotnet/dotnet_detector.go @@ -15,7 +15,7 @@ import ( "context" "encoding/xml" "fmt" - "io/ioutil" + "io" "os" "path/filepath" "strings" @@ -31,6 +31,11 @@ func (d DotNetDetector) GetSupportedFrameworks() []string { return []string{""} } +func (d DotNetDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + // not implemented yet + return []model.ApplicationFileInfo{} +} + // DoFrameworkDetection uses configFilePath to check for the name of the framework func (d DotNetDetector) DoFrameworkDetection(language *model.Language, configFilePath string) { framework := getFrameworks(configFilePath) @@ -52,6 +57,7 @@ func (d DotNetDetector) DoFrameworkDetection(language *model.Language, configFil } func (d DotNetDetector) DoPortsDetection(component *model.Component, ctx *context.Context) { + // not implemented yet } func getFrameworks(configFilePath string) string { @@ -60,7 +66,7 @@ func getFrameworks(configFilePath string) string { if err != nil { return "" } - byteValue, _ := ioutil.ReadAll(xmlFile) + byteValue, _ := io.ReadAll(xmlFile) var proj schema.DotNetProject err = xml.Unmarshal(byteValue, &proj) diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/beego_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/beego_detector.go index 978017870..7225a8e87 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/beego_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/beego_detector.go @@ -26,6 +26,17 @@ func (b BeegoDetector) GetSupportedFrameworks() []string { return []string{"Beego"} } +func (b BeegoDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + return []model.ApplicationFileInfo{ + { + Context: ctx, + Root: componentPath, + Dir: "conf", + File: "app.conf", + }, + } +} + // DoFrameworkDetection uses a tag to check for the framework name func (b BeegoDetector) DoFrameworkDetection(language *model.Language, goMod *modfile.File) { if hasFramework(goMod.Require, "github.com/beego/beego") { @@ -40,15 +51,16 @@ type ApplicationPropertiesFile struct { // DoPortsDetection searches for the port in conf/app.conf func (b BeegoDetector) DoPortsDetection(component *model.Component, ctx *context.Context) { - bytes, err := utils.ReadAnyApplicationFile(component.Path, []model.ApplicationFileInfo{ - { - Dir: "conf", - File: "app.conf", - }, - }, ctx) + fileContents, err := utils.GetApplicationFileContents(b.GetApplicationFileInfos(component.Path, ctx)) if err != nil { return } - re := regexp.MustCompile(`httpport\s*=\s*(\d+)`) - component.Ports = utils.FindAllPortsSubmatch(re, string(bytes), 1) + for _, fileContent := range fileContents { + re := regexp.MustCompile(`httpport\s*=\s*(\d+)`) + ports := utils.FindAllPortsSubmatch(re, fileContent, 1) + if len(ports) > 0 { + component.Ports = ports + return + } + } } diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/echo_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/echo_detector.go index d0a9ba815..1651efa49 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/echo_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/echo_detector.go @@ -26,6 +26,14 @@ func (e EchoDetector) GetSupportedFrameworks() []string { return []string{"Echo"} } +func (e EchoDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + files, err := utils.GetCachedFilePathsFromRoot(componentPath, ctx) + if err != nil { + return []model.ApplicationFileInfo{} + } + return utils.GenerateApplicationFileFromFilters(files, componentPath, ".go", ctx) +} + // DoFrameworkDetection uses a tag to check for the framework name func (e EchoDetector) DoFrameworkDetection(language *model.Language, goMod *modfile.File) { if hasFramework(goMod.Require, "github.com/labstack/echo") { @@ -34,11 +42,10 @@ func (e EchoDetector) DoFrameworkDetection(language *model.Language, goMod *modf } func (e EchoDetector) DoPortsDetection(component *model.Component, ctx *context.Context) { - files, err := utils.GetCachedFilePathsFromRoot(component.Path, ctx) + fileContents, err := utils.GetApplicationFileContents(e.GetApplicationFileInfos(component.Path, ctx)) if err != nil { return } - matchRegexRules := model.PortMatchRules{ MatchIndexRegexes: []model.PortMatchRule{ { @@ -58,8 +65,11 @@ func (e EchoDetector) DoPortsDetection(component *model.Component, ctx *context. }, } - ports := GetPortFromFilesGo(matchRegexRules, files) - if len(ports) > 0 { - component.Ports = ports + for _, fileContent := range fileContents { + ports := GetPortFromFileGo(matchRegexRules, fileContent) + if len(ports) > 0 { + component.Ports = ports + return + } } } diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/fasthttp_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/fasthttp_detector.go index 1ef9d9418..7c2c17f1f 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/fasthttp_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/fasthttp_detector.go @@ -26,6 +26,14 @@ func (f FastHttpDetector) GetSupportedFrameworks() []string { return []string{"FastHttp"} } +func (f FastHttpDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + files, err := utils.GetCachedFilePathsFromRoot(componentPath, ctx) + if err != nil { + return []model.ApplicationFileInfo{} + } + return utils.GenerateApplicationFileFromFilters(files, componentPath, ".go", ctx) +} + // DoFrameworkDetection uses a tag to check for the framework name func (f FastHttpDetector) DoFrameworkDetection(language *model.Language, goMod *modfile.File) { if hasFramework(goMod.Require, "github.com/valyala/fasthttp") { @@ -34,7 +42,7 @@ func (f FastHttpDetector) DoFrameworkDetection(language *model.Language, goMod * } func (f FastHttpDetector) DoPortsDetection(component *model.Component, ctx *context.Context) { - files, err := utils.GetCachedFilePathsFromRoot(component.Path, ctx) + fileContents, err := utils.GetApplicationFileContents(f.GetApplicationFileInfos(component.Path, ctx)) if err != nil { return } @@ -47,8 +55,11 @@ func (f FastHttpDetector) DoPortsDetection(component *model.Component, ctx *cont }, }, } - ports := GetPortFromFilesGo(matchRegexRules, files) - if len(ports) > 0 { - component.Ports = ports + for _, fileContent := range fileContents { + ports := GetPortFromFileGo(matchRegexRules, fileContent) + if len(ports) > 0 { + component.Ports = ports + return + } } } diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/gin_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/gin_detector.go index c41ae37b4..b54b9f1ac 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/gin_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/gin_detector.go @@ -26,6 +26,14 @@ func (g GinDetector) GetSupportedFrameworks() []string { return []string{"Gin"} } +func (g GinDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + files, err := utils.GetCachedFilePathsFromRoot(componentPath, ctx) + if err != nil { + return []model.ApplicationFileInfo{} + } + return utils.GenerateApplicationFileFromFilters(files, componentPath, ".go", ctx) +} + // DoFrameworkDetection uses a tag to check for the framework name func (g GinDetector) DoFrameworkDetection(language *model.Language, goMod *modfile.File) { if hasFramework(goMod.Require, "github.com/gin-gonic/gin") { @@ -34,7 +42,7 @@ func (g GinDetector) DoFrameworkDetection(language *model.Language, goMod *modfi } func (g GinDetector) DoPortsDetection(component *model.Component, ctx *context.Context) { - files, err := utils.GetCachedFilePathsFromRoot(component.Path, ctx) + fileContents, err := utils.GetApplicationFileContents(g.GetApplicationFileInfos(component.Path, ctx)) if err != nil { return } @@ -48,8 +56,11 @@ func (g GinDetector) DoPortsDetection(component *model.Component, ctx *context.C }, } - ports := GetPortFromFilesGo(matchRegexRules, files) - if len(ports) > 0 { - component.Ports = ports + for _, fileContent := range fileContents { + ports := GetPortFromFileGo(matchRegexRules, fileContent) + if len(ports) > 0 { + component.Ports = ports + return + } } } diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/go_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/go_detector.go index 1721dad02..01be17ad2 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/go_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/go_detector.go @@ -13,8 +13,6 @@ package enricher import ( "context" - "os" - "path/filepath" "regexp" "strings" @@ -38,7 +36,11 @@ func DoGoPortsDetection(component *model.Component, ctx *context.Context) { if err != nil { return } - + appFileInfos := utils.GenerateApplicationFileFromFilters(files, component.Path, ".go", ctx) + fileContents, err := utils.GetApplicationFileContents(appFileInfos) + if err != nil { + return + } matchRegexRules := model.PortMatchRules{ MatchIndexRegexes: []model.PortMatchRule{ { @@ -58,9 +60,12 @@ func DoGoPortsDetection(component *model.Component, ctx *context.Context) { }, } - ports := GetPortFromFilesGo(matchRegexRules, files) - if len(ports) > 0 { - component.Ports = ports + for _, fileContent := range fileContents { + ports := GetPortFromFileGo(matchRegexRules, fileContent) + if len(ports) > 0 { + component.Ports = ports + return + } } } @@ -135,20 +140,3 @@ func GetPortWithMatchIndexesGo(content string, matchIndexes []int, toBeReplaced return -1 } - -// GetPortFromFilesGo loops through a list of paths and tries to find a port matching the -// given set PortMatchRules -func GetPortFromFilesGo(matchRegexRules model.PortMatchRules, files []string) []int { - for _, file := range files { - cleanFile := filepath.Clean(file) - bytes, err := os.ReadFile(cleanFile) - if err != nil { - continue - } - ports := GetPortFromFileGo(matchRegexRules, string(bytes)) - if len(ports) > 0 { - return ports - } - } - return []int{} -} diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/gofiber_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/gofiber_detector.go index 3ebe7b39c..82eb0fdae 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/gofiber_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/gofiber_detector.go @@ -26,6 +26,14 @@ func (g GoFiberDetector) GetSupportedFrameworks() []string { return []string{"GoFiber"} } +func (g GoFiberDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + files, err := utils.GetCachedFilePathsFromRoot(componentPath, ctx) + if err != nil { + return []model.ApplicationFileInfo{} + } + return utils.GenerateApplicationFileFromFilters(files, componentPath, ".go", ctx) +} + // DoFrameworkDetection uses a tag to check for the framework name func (g GoFiberDetector) DoFrameworkDetection(language *model.Language, goMod *modfile.File) { if hasFramework(goMod.Require, "github.com/gofiber/fiber") { @@ -34,7 +42,7 @@ func (g GoFiberDetector) DoFrameworkDetection(language *model.Language, goMod *m } func (g GoFiberDetector) DoPortsDetection(component *model.Component, ctx *context.Context) { - files, err := utils.GetCachedFilePathsFromRoot(component.Path, ctx) + fileContents, err := utils.GetApplicationFileContents(g.GetApplicationFileInfos(component.Path, ctx)) if err != nil { return } @@ -47,8 +55,12 @@ func (g GoFiberDetector) DoPortsDetection(component *model.Component, ctx *conte }, }, } - ports := GetPortFromFilesGo(matchRegexRules, files) - if len(ports) > 0 { - component.Ports = ports + + for _, fileContent := range fileContents { + ports := GetPortFromFileGo(matchRegexRules, fileContent) + if len(ports) > 0 { + component.Ports = ports + return + } } } diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/mux_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/mux_detector.go index 021b9a0b2..80b97e25d 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/mux_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/go/mux_detector.go @@ -26,6 +26,14 @@ func (m MuxDetector) GetSupportedFrameworks() []string { return []string{"Mux"} } +func (m MuxDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + files, err := utils.GetCachedFilePathsFromRoot(componentPath, ctx) + if err != nil { + return []model.ApplicationFileInfo{} + } + return utils.GenerateApplicationFileFromFilters(files, componentPath, ".go", ctx) +} + // DoFrameworkDetection uses a tag to check for the framework name func (m MuxDetector) DoFrameworkDetection(language *model.Language, goMod *modfile.File) { if hasFramework(goMod.Require, "github.com/gorilla/mux") { @@ -34,7 +42,7 @@ func (m MuxDetector) DoFrameworkDetection(language *model.Language, goMod *modfi } func (m MuxDetector) DoPortsDetection(component *model.Component, ctx *context.Context) { - files, err := utils.GetCachedFilePathsFromRoot(component.Path, ctx) + fileContents, err := utils.GetApplicationFileContents(m.GetApplicationFileInfos(component.Path, ctx)) if err != nil { return } @@ -54,8 +62,11 @@ func (m MuxDetector) DoPortsDetection(component *model.Component, ctx *context.C }, } - ports := GetPortFromFilesGo(matchRegexRules, files) - if len(ports) > 0 { - component.Ports = ports + for _, fileContent := range fileContents { + ports := GetPortFromFileGo(matchRegexRules, fileContent) + if len(ports) > 0 { + component.Ports = ports + return + } } } diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/java_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/java_detector.go index bbe54557e..31497cd00 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/java_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/java_detector.go @@ -15,6 +15,7 @@ import ( "regexp" "strings" + "github.com/devfile/alizer/pkg/schema" "github.com/devfile/alizer/pkg/utils" ) @@ -36,13 +37,8 @@ func hasFramework(configFile, groupId, artifactId string) (bool, error) { // GetPortsForJBossFrameworks tries to detect any port information inside javaOpts of configuration // of a given profiles plugin -func GetPortsForJBossFrameworks(pomFilePath, pluginArtifactId, pluginGroupId string) string { +func GetPortsForJBossFrameworks(pom schema.Pom, pluginArtifactId string, pluginGroupId string) string { portPlaceholder := "" - pom, err := utils.GetPomFileContent(pomFilePath) - if err != nil { - return portPlaceholder - } - re := regexp.MustCompile(`jboss.https?.port=\d*`) // Check for port configuration inside profiles for _, profile := range pom.Profiles.Profile { diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/jboss_eap_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/jboss_eap_detector.go index a20da910f..680e6ee1b 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/jboss_eap_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/jboss_eap_detector.go @@ -13,8 +13,10 @@ package enricher import ( "context" + "encoding/xml" "github.com/devfile/alizer/pkg/apis/model" + "github.com/devfile/alizer/pkg/schema" "github.com/devfile/alizer/pkg/utils" ) @@ -24,6 +26,17 @@ func (o JBossEAPDetector) GetSupportedFrameworks() []string { return []string{"JBoss EAP"} } +func (o JBossEAPDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + return []model.ApplicationFileInfo{ + { + Context: ctx, + Root: componentPath, + Dir: "", + File: "pom.xml", + }, + } +} + // DoFrameworkDetection uses the groupId and artifactId to check for the framework name func (o JBossEAPDetector) DoFrameworkDetection(language *model.Language, config string) { if hasFwk, _ := hasFramework(config, "org.jboss.eap.plugins", "eap-maven-plugin"); hasFwk { @@ -34,22 +47,35 @@ func (o JBossEAPDetector) DoFrameworkDetection(language *model.Language, config func (o JBossEAPDetector) DoPortsDetection(component *model.Component, ctx *context.Context) { ports := []int{} // Fetch the content of xml for this component - paths, err := utils.GetCachedFilePathsFromRoot(component.Path, ctx) - if err != nil { - return - } - pomXML := utils.GetFile(&paths, "pom.xml") - portPlaceholder := GetPortsForJBossFrameworks(pomXML, "eap-maven-plugin", "org.jboss.eap.plugins") - if portPlaceholder == "" { + appFileInfos := o.GetApplicationFileInfos(component.Path, ctx) + if len(appFileInfos) == 0 { return } - if port, err := utils.GetValidPort(portPlaceholder); err == nil { - ports = append(ports, port) - } + for _, appFileInfo := range appFileInfos { + fileBytes, err := utils.GetApplicationFileBytes(appFileInfo) + if err != nil { + continue + } - if len(ports) > 0 { - component.Ports = ports - return + var pom schema.Pom + err = xml.Unmarshal(fileBytes, &pom) + if err != nil { + continue + } + + portPlaceholder := GetPortsForJBossFrameworks(pom, "eap-maven-plugin", "org.jboss.eap.plugins") + if portPlaceholder == "" { + continue + } + + if port, err := utils.GetValidPort(portPlaceholder); err == nil { + ports = append(ports, port) + } + + if len(ports) > 0 { + component.Ports = ports + return + } } } diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/micronaut_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/micronaut_detector.go index 66967fd6c..7c369c825 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/micronaut_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/micronaut_detector.go @@ -22,22 +22,27 @@ import ( type MicronautDetector struct{} -type MicronautApplicationProps struct { - Micronaut struct { - Server struct { - Port int `yaml:"port,omitempty"` - SSL struct { - Enabled bool `yaml:"enabled,omitempty"` - Port int `yaml:"port,omitempty"` - } `yaml:"ssl,omitempty"` - } `yaml:"server,omitempty"` - } `yaml:"micronaut,omitempty"` -} - func (m MicronautDetector) GetSupportedFrameworks() []string { return []string{"Micronaut"} } +func (m MicronautDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + return []model.ApplicationFileInfo{ + { + Context: ctx, + Root: componentPath, + Dir: "src/main/resources", + File: "application.yml", + }, + { + Context: ctx, + Root: componentPath, + Dir: "src/main/resources", + File: "application.yaml", + }, + } +} + // DoFrameworkDetection uses the groupId to check for the framework name func (m MicronautDetector) DoFrameworkDetection(language *model.Language, config string) { if hasFwk, _ := hasFramework(config, "io.micronaut", ""); hasFwk { @@ -54,28 +59,36 @@ func (m MicronautDetector) DoPortsDetection(component *model.Component, ctx *con return } - bytes, err := utils.ReadAnyApplicationFile(component.Path, []model.ApplicationFileInfo{ - { - Dir: "src/main/resources", - File: "application.yml", - }, - { - Dir: "src/main/resources", - File: "application.yaml", - }, - }, ctx) - if err != nil { - return - } - ports = getMicronautPortsFromBytes(bytes) + // check if port is set on dockerfile as env var + ports = getMicronautPortsFromEnvDockerfile(component.Path) if len(ports) > 0 { component.Ports = ports + return + } + + // check source code + appFileInfos := m.GetApplicationFileInfos(component.Path, ctx) + if len(appFileInfos) == 0 { + return + } + + for _, appFileInfo := range appFileInfos { + fileBytes, err := utils.GetApplicationFileBytes(appFileInfo) + if err != nil { + continue + } + + ports = getMicronautPortsFromBytes(fileBytes) + if len(ports) > 0 { + component.Ports = ports + return + } } } func getMicronautPortsFromBytes(bytes []byte) []int { var ports []int - var data MicronautApplicationProps + var data model.MicronautApplicationProps err := yaml.Unmarshal(bytes, &data) if err != nil { return []int{} @@ -97,3 +110,24 @@ func getMicronautPortsFromEnvs() []int { } return utils.GetValidPortsFromEnvs(envs) } + +func getMicronautPortsFromEnvDockerfile(path string) []int { + envVars, err := utils.GetEnvVarsFromDockerFile(path) + if err != nil { + return nil + } + sslEnabled := "" + envs := []string{"MICRONAUT_SERVER_PORT"} + for _, envVar := range envVars { + if envVar.Name == "MICRONAUT_SERVER_SSL_ENABLED" { + sslEnabled = envVar.Value + break + } + } + + if sslEnabled == "true" { + envs = append(envs, "MICRONAUT_SERVER_SSL_PORT") + } + + return utils.GetValidPortsFromEnvDockerfile(envs, envVars) +} diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/openliberty_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/openliberty_detector.go index 7a7c29fc2..b09cfb1c9 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/openliberty_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/openliberty_detector.go @@ -21,17 +21,27 @@ import ( type OpenLibertyDetector struct{} -type ServerXml struct { - HttpEndpoint struct { - HttpPort string `xml:"httpPort,attr"` - HttpsPort string `xml:"httpsPort,attr"` - } `xml:"httpEndpoint"` -} - func (o OpenLibertyDetector) GetSupportedFrameworks() []string { return []string{"OpenLiberty"} } +func (o OpenLibertyDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + return []model.ApplicationFileInfo{ + { + Context: ctx, + Root: componentPath, + Dir: "", + File: "server.xml", + }, + { + Context: ctx, + Root: componentPath, + Dir: "src/main/liberty/config", + File: "server.xml", + }, + } +} + // DoFrameworkDetection uses the groupId to check for the framework name func (o OpenLibertyDetector) DoFrameworkDetection(language *model.Language, config string) { if hasFwk, _ := hasFramework(config, "io.openliberty", ""); hasFwk { @@ -41,26 +51,26 @@ func (o OpenLibertyDetector) DoFrameworkDetection(language *model.Language, conf // DoPortsDetection searches for the port in src/main/liberty/config/server.xml and /server.xml func (o OpenLibertyDetector) DoPortsDetection(component *model.Component, ctx *context.Context) { - bytes, err := utils.ReadAnyApplicationFile(component.Path, []model.ApplicationFileInfo{ - { - Dir: "", - File: "server.xml", - }, - { - Dir: "src/main/liberty/config", - File: "server.xml", - }, - }, ctx) - if err != nil { + appFileInfos := o.GetApplicationFileInfos(component.Path, ctx) + if len(appFileInfos) == 0 { return } - var data ServerXml - err = xml.Unmarshal(bytes, &data) - if err != nil { - return - } - ports := utils.GetValidPorts([]string{data.HttpEndpoint.HttpPort, data.HttpEndpoint.HttpsPort}) - if len(ports) > 0 { - component.Ports = ports + + for _, appFileInfo := range appFileInfos { + fileBytes, err := utils.GetApplicationFileBytes(appFileInfo) + if err != nil { + continue + } + + var data model.OpenLibertyServerXml + err = xml.Unmarshal(fileBytes, &data) + if err != nil { + continue + } + ports := utils.GetValidPorts([]string{data.HttpEndpoint.HttpPort, data.HttpEndpoint.HttpsPort}) + if len(ports) > 0 { + component.Ports = ports + return + } } } diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/quarkus_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/quarkus_detector.go index c7487765d..653cdb436 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/quarkus_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/quarkus_detector.go @@ -14,7 +14,6 @@ package enricher import ( "context" "errors" - "io/ioutil" "os" "path/filepath" @@ -25,24 +24,33 @@ import ( type QuarkusDetector struct{} -type QuarkusApplicationYaml struct { - Quarkus QuarkusHttp `yaml:"quarkus,omitempty"` -} - -type QuarkusHttp struct { - Http QuarkusHttpPort `yaml:"http,omitempty"` -} - -type QuarkusHttpPort struct { - Port int `yaml:"port,omitempty"` - InsecureRequests string `yaml:"insecure-requests,omitempty"` - SSLPort int `yaml:"ssl-port,omitempty"` -} - func (q QuarkusDetector) GetSupportedFrameworks() []string { return []string{"Quarkus"} } +func (q QuarkusDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + return []model.ApplicationFileInfo{ + { + Context: ctx, + Root: componentPath, + Dir: "src/main/resources", + File: "application.properties", + }, + { + Context: ctx, + Root: componentPath, + Dir: "src/main/resources", + File: "application.yml", + }, + { + Context: ctx, + Root: componentPath, + Dir: "src/main/resources", + File: "application.yaml", + }, + } +} + // DoFrameworkDetection uses the groupId to check for the framework name func (q QuarkusDetector) DoFrameworkDetection(language *model.Language, config string) { if hasFwk, _ := hasFramework(config, "io.quarkus", ""); hasFwk { @@ -59,6 +67,14 @@ func (q QuarkusDetector) DoPortsDetection(component *model.Component, ctx *conte component.Ports = ports return } + + // check if port is set on env var of a dockerfile + ports = getQuarkusPortsFromEnvDockerfile(component.Path) + if len(ports) > 0 { + component.Ports = ports + return + } + // check if port is set on .env file insecureRequestEnabled := utils.GetStringValueFromEnvFile(component.Path, `QUARKUS_HTTP_INSECURE_REQUESTS=(\w*)`) regexes := []string{`QUARKUS_HTTP_SSL_PORT=(\d*)`} @@ -71,20 +87,13 @@ func (q QuarkusDetector) DoPortsDetection(component *model.Component, ctx *conte return } - applicationFile := utils.GetAnyApplicationFilePath(component.Path, []model.ApplicationFileInfo{ - { - Dir: "src/main/resources", - File: "application.properties", - }, - { - Dir: "src/main/resources", - File: "application.yml", - }, - { - Dir: "src/main/resources", - File: "application.yaml", - }, - }, ctx) + appFileInfos := q.GetApplicationFileInfos(component.Path, ctx) + if len(appFileInfos) == 0 { + return + } + + // case: no port found as env var. Look into source code. + applicationFile := utils.GetAnyApplicationFilePath(component.Path, appFileInfos, ctx) if applicationFile == "" { return } @@ -110,6 +119,27 @@ func getQuarkusPortsFromEnvs() []int { return utils.GetValidPortsFromEnvs(envs) } +func getQuarkusPortsFromEnvDockerfile(path string) []int { + envVars, err := utils.GetEnvVarsFromDockerFile(path) + if err != nil { + return nil + } + insecureRequestEnabled := "" + envs := []string{"QUARKUS_HTTP_SSL_PORT"} + for _, envVar := range envVars { + if envVar.Name == "QUARKUS_HTTP_INSECURE_REQUESTS" { + insecureRequestEnabled = envVar.Value + break + } + } + + if insecureRequestEnabled == "true" { + envs = append(envs, "QUARKUS_HTTP_PORT") + } + + return utils.GetValidPortsFromEnvDockerfile(envs, envVars) +} + func getServerPortsFromQuarkusPropertiesFile(file string) ([]int, error) { var ports []int props, err := utils.ConvertPropertiesFileAsPathToMap(file) @@ -135,11 +165,11 @@ func getServerPortsFromQuarkusPropertiesFile(file string) ([]int, error) { } func getServerPortsFromQuarkusApplicationYamlFile(file string) ([]int, error) { - yamlFile, err := ioutil.ReadFile(file) + yamlFile, err := os.ReadFile(filepath.Clean(file)) if err != nil { return []int{}, err } - var data QuarkusApplicationYaml + var data model.QuarkusApplicationYaml err = yaml.Unmarshal(yamlFile, &data) if err != nil { return []int{}, err diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/spring_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/spring_detector.go index f796131ff..e1ea39bce 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/spring_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/spring_detector.go @@ -14,7 +14,7 @@ package enricher import ( "context" "errors" - "io/ioutil" + "os" "path/filepath" "github.com/devfile/alizer/pkg/apis/model" @@ -24,19 +24,33 @@ import ( type SpringDetector struct{} -type ApplicationProsServer struct { - Server struct { - Port int `yaml:"port,omitempty"` - Http struct { - Port int `yaml:"port,omitempty"` - } `yaml:"http,omitempty"` - } `yaml:"server,omitempty"` -} - func (s SpringDetector) GetSupportedFrameworks() []string { return []string{"Spring", "Spring Boot"} } +func (s SpringDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + return []model.ApplicationFileInfo{ + { + Context: ctx, + Root: componentPath, + Dir: "src/main/resources", + File: "application.properties", + }, + { + Context: ctx, + Root: componentPath, + Dir: "src/main/resources", + File: "application.yml", + }, + { + Context: ctx, + Root: componentPath, + Dir: "src/main/resources", + File: "application.yaml", + }, + } +} + // DoFrameworkDetection uses the groupId to check for the framework name func (s SpringDetector) DoFrameworkDetection(language *model.Language, config string) { if hasFwk, _ := hasFramework(config, "org.springframework", ""); hasFwk { @@ -47,30 +61,31 @@ func (s SpringDetector) DoFrameworkDetection(language *model.Language, config st // DoPortsDetection searches for ports in the env var and // src/main/resources/application.properties, or src/main/resources/application.yaml func (s SpringDetector) DoPortsDetection(component *model.Component, ctx *context.Context) { - // check if port is set on env var + // case: port is set on env var ports := getSpringPortsFromEnvs() if len(ports) > 0 { component.Ports = ports return } - applicationFile := utils.GetAnyApplicationFilePath(component.Path, []model.ApplicationFileInfo{ - { - Dir: "src/main/resources", - File: "application.properties", - }, - { - Dir: "src/main/resources", - File: "application.yml", - }, - { - Dir: "src/main/resources", - File: "application.yaml", - }, - }, ctx) + // check if port is set on env var of dockerfile + ports = getSpringPortsFromEnvDockerfile(component.Path) + if len(ports) > 0 { + component.Ports = ports + return + } + + // check if port is set inside application file + appFileInfos := s.GetApplicationFileInfos(component.Path, ctx) + if len(appFileInfos) == 0 { + return + } + + applicationFile := utils.GetAnyApplicationFilePath(component.Path, appFileInfos, ctx) if applicationFile == "" { return } + var err error if filepath.Ext(applicationFile) == ".yml" || filepath.Ext(applicationFile) == ".yaml" { ports, err = getServerPortsFromYamlFile(applicationFile) @@ -88,6 +103,15 @@ func getSpringPortsFromEnvs() []int { return utils.GetValidPortsFromEnvs([]string{"SERVER_PORT", "SERVER_HTTP_PORT"}) } +func getSpringPortsFromEnvDockerfile(path string) []int { + envVars, err := utils.GetEnvVarsFromDockerFile(path) + if err != nil { + return nil + } + envs := []string{"SERVER_PORT", "SERVER_HTTP_PORT"} + return utils.GetValidPortsFromEnvDockerfile(envs, envVars) +} + func getServerPortsFromPropertiesFile(file string) ([]int, error) { props, err := utils.ConvertPropertiesFileAsPathToMap(file) if err != nil { @@ -122,11 +146,11 @@ func getPortFromMap(props map[string]string, key string) int { } func getServerPortsFromYamlFile(file string) ([]int, error) { - yamlFile, err := ioutil.ReadFile(file) + yamlFile, err := os.ReadFile(filepath.Clean(file)) if err != nil { return []int{}, err } - var data ApplicationProsServer + var data model.SpringApplicationProsServer err = yaml.Unmarshal(yamlFile, &data) if err != nil { return []int{}, err diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/vertx_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/vertx_detector.go index b681fb44c..549d01822 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/vertx_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/vertx_detector.go @@ -21,18 +21,21 @@ import ( type VertxDetector struct{} -type VertxConf struct { - Port int `json:"http.port,omitempty"` - ServerConfig ServerConfig `json:"http.server,omitempty"` -} -type ServerConfig struct { - Port int `json:"http.server.port,omitempty"` -} - func (v VertxDetector) GetSupportedFrameworks() []string { return []string{"Vertx"} } +func (v VertxDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + return []model.ApplicationFileInfo{ + { + Context: ctx, + Root: componentPath, + Dir: "src/main/conf", + File: ".*.json", + }, + } +} + // DoFrameworkDetection uses the groupId to check for the framework name func (v VertxDetector) DoFrameworkDetection(language *model.Language, config string) { if hasFwk, _ := hasFramework(config, "io.vertx", ""); hasFwk { @@ -42,24 +45,31 @@ func (v VertxDetector) DoFrameworkDetection(language *model.Language, config str // DoPortsDetection searches for the port in json files under src/main/conf/ func (v VertxDetector) DoPortsDetection(component *model.Component, ctx *context.Context) { - bytes, err := utils.ReadAnyApplicationFile(component.Path, []model.ApplicationFileInfo{ - { - Dir: "src/main/conf", - File: ".*.json", - }, - }, ctx) - if err != nil { + appFileInfos := v.GetApplicationFileInfos(component.Path, ctx) + if len(appFileInfos) == 0 { return } - var data VertxConf - err = json.Unmarshal(bytes, &data) - if err != nil { - return - } - if utils.IsValidPort(data.Port) { - component.Ports = []int{data.Port} - } else if utils.IsValidPort(data.ServerConfig.Port) { - component.Ports = []int{data.ServerConfig.Port} - } + for _, appFileInfo := range appFileInfos { + fileBytes, err := utils.GetApplicationFileBytes(appFileInfo) + if err != nil { + continue + } + + var data model.VertxConf + err = json.Unmarshal(fileBytes, &data) + if err != nil { + continue + } + + if utils.IsValidPort(data.Port) { + component.Ports = []int{data.Port} + return + } + + if utils.IsValidPort(data.ServerConfig.Port) { + component.Ports = []int{data.ServerConfig.Port} + return + } + } } diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/wildfly_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/wildfly_detector.go index d82ff0088..35174b360 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/wildfly_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/java/wildfly_detector.go @@ -13,19 +13,30 @@ package enricher import ( "context" + "encoding/xml" "github.com/devfile/alizer/pkg/apis/model" + "github.com/devfile/alizer/pkg/schema" "github.com/devfile/alizer/pkg/utils" ) type WildFlyDetector struct{} -func (o WildFlyDetector) GetSupportedFrameworks() []string { +func (w WildFlyDetector) GetSupportedFrameworks() []string { return []string{"WildFly"} } +func (w WildFlyDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + files, err := utils.GetCachedFilePathsFromRoot(componentPath, ctx) + if err != nil { + return []model.ApplicationFileInfo{} + } + pomXML := utils.GetFile(&files, "pom.xml") + return utils.GenerateApplicationFileFromFilters([]string{pomXML}, componentPath, "", ctx) +} + // DoFrameworkDetection uses the groupId and artifactId to check for the framework name -func (o WildFlyDetector) DoFrameworkDetection(language *model.Language, config string) { +func (w WildFlyDetector) DoFrameworkDetection(language *model.Language, config string) { if hasFwk, _ := hasFramework(config, "org.wildfly.plugins", "wildfly-maven-plugin"); hasFwk { language.Frameworks = append(language.Frameworks, "WildFly") } @@ -33,25 +44,38 @@ func (o WildFlyDetector) DoFrameworkDetection(language *model.Language, config s // DoPortsDetection for wildfly fetches the pom.xml and tries to find any javaOpts under // the wildfly-maven-plugin profiles. If there is one it looks if jboss.http.port is defined. -func (o WildFlyDetector) DoPortsDetection(component *model.Component, ctx *context.Context) { +func (w WildFlyDetector) DoPortsDetection(component *model.Component, ctx *context.Context) { ports := []int{} // Fetch the content of xml for this component - paths, err := utils.GetCachedFilePathsFromRoot(component.Path, ctx) - if err != nil { - return - } - pomXML := utils.GetFile(&paths, "pom.xml") - portPlaceholder := GetPortsForJBossFrameworks(pomXML, "wildfly-maven-plugin", "org.wildfly.plugins") - if portPlaceholder == "" { + appFileInfos := w.GetApplicationFileInfos(component.Path, ctx) + if len(appFileInfos) == 0 { return } - if port, err := utils.GetValidPort(portPlaceholder); err == nil { - ports = append(ports, port) - } + for _, appFileInfo := range appFileInfos { + fileBytes, err := utils.GetApplicationFileBytes(appFileInfo) + if err != nil { + continue + } - if len(ports) > 0 { - component.Ports = ports - return + var pom schema.Pom + err = xml.Unmarshal(fileBytes, &pom) + if err != nil { + continue + } + + portPlaceholder := GetPortsForJBossFrameworks(pom, "wildfly-maven-plugin", "org.wildfly.plugins") + if portPlaceholder == "" { + continue + } + + if port, err := utils.GetValidPort(portPlaceholder); err == nil { + ports = append(ports, port) + } + + if len(ports) > 0 { + component.Ports = ports + return + } } } diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/angular_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/angular_detector.go index 175b63c3b..16e391b3b 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/angular_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/angular_detector.go @@ -19,35 +19,29 @@ import ( "github.com/devfile/alizer/pkg/utils" ) -type AngularCliJson struct { - Defaults struct { - Serve HostPort `json:"serve"` - } `json:"defaults"` -} - -type AngularJson struct { - Projects map[string]ProjectBody `json:"projects"` -} - -type ProjectBody struct { - Architect struct { - Serve struct { - Options HostPort `json:"options"` - } `json:"serve"` - } `json:"architect"` -} - -type HostPort struct { - Host string `json:"host"` - Port int `json:"port"` -} - type AngularDetector struct{} func (a AngularDetector) GetSupportedFrameworks() []string { return []string{"Angular"} } +func (a AngularDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + return []model.ApplicationFileInfo{ + { + Context: ctx, + Root: componentPath, + Dir: "", + File: "angular.json", + }, + { + Context: ctx, + Root: componentPath, + Dir: "", + File: "angular-cli.json", + }, + } +} + // DoFrameworkDetection uses a tag to check for the framework name func (a AngularDetector) DoFrameworkDetection(language *model.Language, config string) { if hasFramework(config, "angular") { @@ -58,17 +52,26 @@ func (a AngularDetector) DoFrameworkDetection(language *model.Language, config s // DoPortsDetection searches for the port in angular.json, package.json, and angular-cli.json func (a AngularDetector) DoPortsDetection(component *model.Component, ctx *context.Context) { // check if port is set on angular.json file - bytes, err := utils.ReadAnyApplicationFile(component.Path, []model.ApplicationFileInfo{ - { - Dir: "", - File: "angular.json", - }, - }, ctx) + appFileInfos := a.GetApplicationFileInfos(component.Path, ctx) + if len(appFileInfos) == 0 { + return + } + + appFileInfo, err := utils.GetApplicationFileInfo(appFileInfos, "angular.json") if err != nil { return } - var data AngularJson - err = json.Unmarshal(bytes, &data) + + fileBytes, err := utils.GetApplicationFileBytes(appFileInfo) + if err != nil { + return + } + + if err != nil { + return + } + var data model.AngularJson + err = json.Unmarshal(fileBytes, &data) if err != nil { return } @@ -89,17 +92,18 @@ func (a AngularDetector) DoPortsDetection(component *model.Component, ctx *conte } // check if port is set on angular-cli.json file - bytes, err = utils.ReadAnyApplicationFile(component.Path, []model.ApplicationFileInfo{ - { - Dir: "", - File: "angular-cli.json", - }, - }, ctx) + appFileInfoCli, err := utils.GetApplicationFileInfo(appFileInfos, "angular-cli.json") if err != nil { return } - var dataCli AngularCliJson - err = json.Unmarshal(bytes, &dataCli) + + fileBytesCli, err := utils.GetApplicationFileBytes(appFileInfoCli) + if err != nil { + return + } + + var dataCli model.AngularCliJson + err = json.Unmarshal(fileBytesCli, &dataCli) if err != nil { return } diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/express_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/express_detector.go index c4c0a098f..4237a38cf 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/express_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/express_detector.go @@ -14,7 +14,6 @@ package enricher import ( "context" "os" - "path/filepath" "regexp" "strings" @@ -28,6 +27,14 @@ func (e ExpressDetector) GetSupportedFrameworks() []string { return []string{"Express"} } +func (e ExpressDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + files, err := utils.GetCachedFilePathsFromRoot(componentPath, ctx) + if err != nil { + return []model.ApplicationFileInfo{} + } + return utils.GenerateApplicationFileFromFilters(files, componentPath, ".js", ctx) +} + // DoFrameworkDetection uses a tag to check for the framework name func (e ExpressDetector) DoFrameworkDetection(language *model.Language, config string) { if hasFramework(config, "express") { @@ -36,25 +43,19 @@ func (e ExpressDetector) DoFrameworkDetection(language *model.Language, config s } func (e ExpressDetector) DoPortsDetection(component *model.Component, ctx *context.Context) { - files, err := utils.GetCachedFilePathsFromRoot(component.Path, ctx) + fileContents, err := utils.GetApplicationFileContents(e.GetApplicationFileInfos(component.Path, ctx)) if err != nil { return } re := regexp.MustCompile(`\.listen\([^,)]*`) var ports []int - for _, file := range files { - cleanFile := filepath.Clean(file) - bytes, err := os.ReadFile(cleanFile) - if err != nil { - continue - } - content := string(bytes) + for _, content := range fileContents { matchesIndexes := re.FindAllStringSubmatchIndex(content, -1) for _, matchIndexes := range matchesIndexes { - port := getPort(content, matchIndexes) - if port != -1 { - ports = append(ports, port) + portList := getPorts(content, matchIndexes, component.Path) + if len(portList) != 0 { + ports = append(ports, portList...) } } if len(ports) > 0 { @@ -82,14 +83,39 @@ func GetEnvPort(envPlaceholder string) int { return -1 } -func getPort(content string, matchIndexes []int) int { +// GetEnvPortFromDockerfile returns a port value from the Dockerfile (locations provided by the 'utils.GetLocations' function) +// matching the specified 'envPlaceHolder'. +// It first extracts the environment variable name to lookup from 'envPlaceholder' by removing any 'process.env.' prefix. +// It then searches through all environment variables detected from the Dockerfile (as determined by 'utils.GetEnvVarsFromDockerFile'). +// And if the environment variable specified via 'envPlaceholder' is found in the Dockerfile environment variables +// and its corresponding value is a valid port (as determined by 'utils.GetValidPort'), it returns this valid port value. +// +// If there is an error reading the Dockerfile or if the environment variable specified via 'envPlaceholder' is not found among +// the Dockerfile environment variables, the function returns -1. +func GetEnvPortFromDockerfile(envPlaceholder string, path string) int { + envPlaceholder = strings.Replace(envPlaceholder, "process.env.", "", -1) + envVars, err := utils.GetEnvVarsFromDockerFile(path) + if err != nil { + return -1 + } + for _, envVar := range envVars { + if envVar.Name == envPlaceholder { + if port, err := utils.GetValidPort(envVar.Value); err == nil { + return port + } + } + } + return -1 +} + +func getPorts(content string, matchIndexes []int, path string) []int { // Express configures its port with app.listen() portPlaceholder := content[matchIndexes[0]:matchIndexes[1]] portPlaceholder = strings.Replace(portPlaceholder, ".listen(", "", -1) // Case: Raw port value -> return it directly if port, err := utils.GetValidPort(portPlaceholder); err == nil { - return port + return []int{port} } // Case: Env var given as value in app.listen -> Get env value @@ -115,13 +141,20 @@ func getPort(content string, matchIndexes []int) int { } } } + var result []int // After double-checking for env vars try to get the value of this port if len(envMatchIndexes) > 1 { envPlaceholder := envPortValue[envMatchIndexes[0]:envMatchIndexes[1]] port := GetEnvPort(envPlaceholder) // The port will be return only if a value was found for the given env var if port > 0 { - return port + result = append(result, port) + } else { + // If no env var was found on system try to find one in a root dockerfile + port = GetEnvPortFromDockerfile(envPlaceholder, path) + if port > 0 { + result = append(result, port) + } } } // Case: No env var or raw value found -> check for raw value into a var @@ -131,9 +164,10 @@ func getPort(content string, matchIndexes []int) int { portValues := strings.Split(potentialPortGroup, " || ") for _, portValue := range portValues { if port, err := utils.GetValidPort(portValue); err == nil { - return port + result = append(result, port) + break } } } - return -1 + return result } diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/next_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/next_detector.go index c921074b7..09432168c 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/next_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/next_detector.go @@ -24,6 +24,12 @@ func (n NextDetector) GetSupportedFrameworks() []string { return []string{"Next"} } +func (a NextDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + // Next.js enricher does not apply source code detection. + // It only detects ports from start/dev script + return []model.ApplicationFileInfo{} +} + // DoFrameworkDetection uses a tag to check for the framework name func (n NextDetector) DoFrameworkDetection(language *model.Language, config string) { if hasFramework(config, "next") { diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/nuxt_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/nuxt_detector.go index 90db041f8..dd3af930a 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/nuxt_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/nuxt_detector.go @@ -25,6 +25,17 @@ func (n NuxtDetector) GetSupportedFrameworks() []string { return []string{"Nuxt"} } +func (n NuxtDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + return []model.ApplicationFileInfo{ + { + Context: ctx, + Root: componentPath, + Dir: "", + File: "nuxt.config.js", + }, + } +} + // DoFrameworkDetection uses a tag to check for the framework name func (n NuxtDetector) DoFrameworkDetection(language *model.Language, config string) { if hasFramework(config, "nuxt") { @@ -34,6 +45,7 @@ func (n NuxtDetector) DoFrameworkDetection(language *model.Language, config stri // DoPortsDetection searches for the port in package.json, and nuxt.config.js func (n NuxtDetector) DoPortsDetection(component *model.Component, ctx *context.Context) { + ports := []int{} regexes := []string{`--port=(\d*)`} // check if port is set in start script in package.json port := getPortFromStartScript(component.Path, regexes) @@ -50,15 +62,22 @@ func (n NuxtDetector) DoPortsDetection(component *model.Component, ctx *context. } //check inside the nuxt.config.js file - bytes, err := utils.ReadAnyApplicationFile(component.Path, []model.ApplicationFileInfo{ - { - Dir: "", - File: "nuxt.config.js", - }, - }, ctx) - if err != nil { + appFileInfos := n.GetApplicationFileInfos(component.Path, ctx) + if len(appFileInfos) == 0 { return } - re := regexp.MustCompile(`port:\s*(\d+)*`) - component.Ports = utils.FindAllPortsSubmatch(re, string(bytes), 1) + + for _, appFileInfo := range appFileInfos { + fileBytes, err := utils.GetApplicationFileBytes(appFileInfo) + if err != nil { + continue + } + + re := regexp.MustCompile(`port:\s*(\d+)*`) + ports = utils.FindAllPortsSubmatch(re, string(fileBytes), 1) + if len(ports) > 0 { + component.Ports = ports + return + } + } } diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/reactjs_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/reactjs_detector.go index 43c329984..6967c5947 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/reactjs_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/reactjs_detector.go @@ -25,6 +25,12 @@ func (r ReactJsDetector) GetSupportedFrameworks() []string { return []string{"React"} } +func (r ReactJsDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + // React.js enricher does not apply source code detection. + // It only detects ports from start script or env vars + return nil +} + // DoFrameworkDetection uses a tag to check for the framework name func (r ReactJsDetector) DoFrameworkDetection(language *model.Language, config string) { if hasFramework(config, "react") { @@ -46,6 +52,14 @@ func (r ReactJsDetector) DoPortsDetection(component *model.Component, ctx *conte component.Ports = []int{port} return } + + // check if port is set on as env var inside a dockerfile + ports, err := utils.GetEnvVarPortValueFromDockerfile(component.Path, []string{"PORT"}) + if err == nil { + component.Ports = ports + return + } + // check if port is set in start script in package.json port = getPortFromStartScript(component.Path, []string{`PORT=(\d*)`}) if utils.IsValidPort(port) { diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/svelte_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/svelte_detector.go index 1b2808906..db0424c63 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/svelte_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/svelte_detector.go @@ -24,6 +24,12 @@ func (s SvelteDetector) GetSupportedFrameworks() []string { return []string{"Svelte"} } +func (s SvelteDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + // Svelte.js enricher does not apply source code detection. + // It only detects ports from dev script + return nil +} + // DoFrameworkDetection uses a tag to check for the framework name func (s SvelteDetector) DoFrameworkDetection(language *model.Language, config string) { if hasFramework(config, "svelte") { diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/vue_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/vue_detector.go index 34bae42bf..dc7e456df 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/vue_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/javascript/nodejs/vue_detector.go @@ -25,6 +25,17 @@ func (v VueDetector) GetSupportedFrameworks() []string { return []string{"Vue"} } +func (v VueDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + return []model.ApplicationFileInfo{ + { + Context: ctx, + Root: componentPath, + Dir: "", + File: "vue.config.js", + }, + } +} + // DoFrameworkDetection uses a tag to check for the framework name func (v VueDetector) DoFrameworkDetection(language *model.Language, config string) { if hasFramework(config, "vue") { @@ -35,6 +46,7 @@ func (v VueDetector) DoFrameworkDetection(language *model.Language, config strin // DoPortsDetection searches for the port in package.json, .env file, and vue.config.js func (v VueDetector) DoPortsDetection(component *model.Component, ctx *context.Context) { regexes := []string{`--port (\d*)`, `PORT=(\d*)`} + ports := []int{} // check if --port or PORT is set in start script in package.json port := getPortFromStartScript(component.Path, regexes) if utils.IsValidPort(port) { @@ -54,16 +66,30 @@ func (v VueDetector) DoPortsDetection(component *model.Component, ctx *context.C return } - //check inside the vue.config.js file - bytes, err := utils.ReadAnyApplicationFile(component.Path, []model.ApplicationFileInfo{ - { - Dir: "", - File: "vue.config.js", - }, - }, ctx) - if err != nil { + // check if port is set on as env var inside a dockerfile + ports, err := utils.GetEnvVarPortValueFromDockerfile(component.Path, []string{"PORT"}) + if err == nil { + component.Ports = ports return } - re := regexp.MustCompile(`port:\s*(\d+)*`) - component.Ports = utils.FindAllPortsSubmatch(re, string(bytes), 1) + + //check inside the vue.config.js file + appFileInfos := v.GetApplicationFileInfos(component.Path, ctx) + if len(appFileInfos) == 0 { + return + } + + for _, appFileInfo := range appFileInfos { + fileBytes, err := utils.GetApplicationFileBytes(appFileInfo) + if err != nil { + continue + } + + re := regexp.MustCompile(`port:\s*(\d+)*`) + ports = utils.FindAllPortsSubmatch(re, string(fileBytes), 1) + if len(ports) > 0 { + component.Ports = ports + return + } + } } diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/php/laravel_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/php/laravel_detector.go index 28551b448..55a71e572 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/php/laravel_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/php/laravel_detector.go @@ -13,6 +13,7 @@ package enricher import ( "context" + "github.com/devfile/alizer/pkg/apis/model" "github.com/devfile/alizer/pkg/utils" ) @@ -23,6 +24,12 @@ func (d LaravelDetector) GetSupportedFrameworks() []string { return []string{"Laravel"} } +func (d LaravelDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + // laravel enricher does not apply source code detection. + // It only detects ports declared as env vars + return nil +} + // DoFrameworkDetection uses a tag to check for the framework name func (d LaravelDetector) DoFrameworkDetection(language *model.Language, config string) { if hasFramework(config, "laravel") { @@ -34,8 +41,17 @@ func (d LaravelDetector) DoFrameworkDetection(language *model.Language, config s // configuring the APP_PORT variable which is dedicated to port configuration. func (d LaravelDetector) DoPortsDetection(component *model.Component, ctx *context.Context) { regexes := []string{`APP_PORT=(\d*)`} + // Case ENV file ports := utils.GetPortValuesFromEnvFile(component.Path, regexes) if len(ports) > 0 { component.Ports = ports + return } + // Case env var defined inside dockerfile + ports, err := utils.GetEnvVarPortValueFromDockerfile(component.Path, []string{"APP_PORT"}) + if len(ports) > 0 && err != nil { + component.Ports = ports + return + } + } diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/python/django_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/python/django_detector.go index cfa5d9385..99969838b 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/python/django_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/python/django_detector.go @@ -25,46 +25,66 @@ func (d DjangoDetector) GetSupportedFrameworks() []string { return []string{"Django"} } +func (d DjangoDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + return []model.ApplicationFileInfo{ + { + Context: ctx, + Root: componentPath, + Dir: "", + File: "manage.py", + }, + } +} + +func (d DjangoDetector) GetDjangoFilenames() []string { + return []string{"manage.py", "urls.py", "wsgi.py", "asgi.py"} +} + +func (d DjangoDetector) GetConfigDjangoFilenames() []string { + return []string{"requirements.txt", "pyproject.toml"} +} + // DoFrameworkDetection uses a tag to check for the framework name // with django files and django config files func (d DjangoDetector) DoFrameworkDetection(language *model.Language, files *[]string) { - managePy := utils.GetFile(files, "manage.py") - urlsPy := utils.GetFile(files, "urls.py") - wsgiPy := utils.GetFile(files, "wsgi.py") - asgiPy := utils.GetFile(files, "asgi.py") - requirementsTxt := utils.GetFile(files, "requirements.txt") - projectToml := utils.GetFile(files, "pyproject.toml") - var djangoFiles []string var configDjangoFiles []string - utils.AddToArrayIfValueExist(&djangoFiles, managePy) - utils.AddToArrayIfValueExist(&djangoFiles, urlsPy) - utils.AddToArrayIfValueExist(&djangoFiles, wsgiPy) - utils.AddToArrayIfValueExist(&djangoFiles, asgiPy) - utils.AddToArrayIfValueExist(&configDjangoFiles, requirementsTxt) - utils.AddToArrayIfValueExist(&configDjangoFiles, projectToml) + + for _, filename := range d.GetDjangoFilenames() { + filePy := utils.GetFile(files, filename) + utils.AddToArrayIfValueExist(&djangoFiles, filePy) + } + + for _, filename := range d.GetConfigDjangoFilenames() { + configFile := utils.GetFile(files, filename) + utils.AddToArrayIfValueExist(&configDjangoFiles, configFile) + } if hasFramework(&djangoFiles, "from django.") || hasFramework(&configDjangoFiles, "django") || hasFramework(&configDjangoFiles, "Django") { language.Frameworks = append(language.Frameworks, "Django") } } -type ApplicationPropertiesFile struct { - Dir string - File string -} - // DoPortsDetection searches for the port in /manage.py func (d DjangoDetector) DoPortsDetection(component *model.Component, ctx *context.Context) { - bytes, err := utils.ReadAnyApplicationFile(component.Path, []model.ApplicationFileInfo{ - { - Dir: "", - File: "manage.py", - }, - }, ctx) - if err != nil { + ports := []int{} + appFileInfos := d.GetApplicationFileInfos(component.Path, ctx) + if len(appFileInfos) == 0 { return } - re := regexp.MustCompile(`.default_port\s*=\s*"([^"]*)`) - component.Ports = utils.FindAllPortsSubmatch(re, string(bytes), 1) + + for _, appFileInfo := range appFileInfos { + fileBytes, err := utils.GetApplicationFileBytes(appFileInfo) + if err != nil { + continue + } + + re := regexp.MustCompile(`.default_port\s*=\s*"([^"]*)`) + component.Ports = utils.FindAllPortsSubmatch(re, string(fileBytes), 1) + if len(ports) > 0 { + component.Ports = ports + return + } + } + } diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/python/flask_detector.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/python/flask_detector.go index cedbfbad8..8d5cff7fa 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/python/flask_detector.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/framework/python/flask_detector.go @@ -22,30 +22,92 @@ import ( type FlaskDetector struct{} -func (d FlaskDetector) GetSupportedFrameworks() []string { +func (f FlaskDetector) GetSupportedFrameworks() []string { return []string{"Flask"} } +func (f FlaskDetector) GetApplicationFileInfos(componentPath string, ctx *context.Context) []model.ApplicationFileInfo { + return []model.ApplicationFileInfo{ + { + Context: ctx, + Root: componentPath, + Dir: "", + File: "app.py", + }, + { + Context: ctx, + Root: componentPath, + Dir: "", + File: "wsgi.py", + }, + { + Context: ctx, + Root: componentPath, + Dir: "app", + File: "__init__.py", + }, + } +} + +func (f FlaskDetector) GetFlaskFilenames() []string { + return []string{"app.py", "wsgi.py"} +} + +func (f FlaskDetector) GetConfigFlaskFilenames() []string { + return []string{"requirements.txt", "pyproject.toml"} +} + // DoFrameworkDetection uses a tag to check for the framework name // with flask files and flask config files -func (d FlaskDetector) DoFrameworkDetection(language *model.Language, files *[]string) { - appPy := utils.GetFile(files, "app.py") - wsgiPy := utils.GetFile(files, "wsgi.py") - requirementsTxt := utils.GetFile(files, "requirements.txt") - projectToml := utils.GetFile(files, "pyproject.toml") +func (f FlaskDetector) DoFrameworkDetection(language *model.Language, files *[]string) { + var flaskFiles []string + var configFlaskFiles []string - flaskFiles := []string{} - configFlaskFiles := []string{} - utils.AddToArrayIfValueExist(&flaskFiles, appPy) - utils.AddToArrayIfValueExist(&flaskFiles, wsgiPy) - utils.AddToArrayIfValueExist(&configFlaskFiles, requirementsTxt) - utils.AddToArrayIfValueExist(&configFlaskFiles, projectToml) + for _, filename := range f.GetFlaskFilenames() { + filePy := utils.GetFile(files, filename) + utils.AddToArrayIfValueExist(&flaskFiles, filePy) + } + + for _, filename := range f.GetConfigFlaskFilenames() { + configFile := utils.GetFile(files, filename) + utils.AddToArrayIfValueExist(&configFlaskFiles, configFile) + } if hasFramework(&flaskFiles, "from flask ") || hasFramework(&configFlaskFiles, "Flask") || hasFramework(&configFlaskFiles, "flask") { language.Frameworks = append(language.Frameworks, "Flask") } } +// DoPortsDetection searches for the port in app/__init__.py, app.py or /wsgi.py +func (f FlaskDetector) DoPortsDetection(component *model.Component, ctx *context.Context) { + appFileInfos := f.GetApplicationFileInfos(component.Path, ctx) + if len(appFileInfos) == 0 { + return + } + + for _, appFileInfo := range appFileInfos { + fileBytes, err := utils.GetApplicationFileBytes(appFileInfo) + if err != nil { + continue + } + + matchIndexRegexes := []model.PortMatchRule{ + { + Regex: regexp.MustCompile(`.run\([^)]*`), + ToReplace: ".run(", + }, + } + if err != nil { + continue + } + ports := getPortFromFileFlask(matchIndexRegexes, string(fileBytes)) + if len(ports) > 0 { + component.Ports = ports + return + } + } +} + // getPortFromFileFlask tries to find a port configuration inside a given file content func getPortFromFileFlask(matchIndexRegexes []model.PortMatchRule, text string) []int { var ports []int @@ -99,36 +161,3 @@ func getPortWithMatchIndexesFlask(content string, matchIndexes []int, toBeReplac return -1 } - -// DoPortsDetection searches for the port in app/__init__.py, app.py or /wsgi.py -func (d FlaskDetector) DoPortsDetection(component *model.Component, ctx *context.Context) { - bytes, err := utils.ReadAnyApplicationFile(component.Path, []model.ApplicationFileInfo{ - { - Dir: "", - File: "app.py", - }, - { - Dir: "", - File: "wsgi.py", - }, - { - Dir: "app", - File: "__init__.py", - }, - }, ctx) - - matchIndexRegexes := []model.PortMatchRule{ - { - Regex: regexp.MustCompile(`.run\([^)]*`), - ToReplace: ".run(", - }, - } - if err != nil { - return - } - ports := getPortFromFileFlask(matchIndexRegexes, string(bytes)) - if len(ports) > 0 { - component.Ports = ports - return - } -} diff --git a/vendor/github.com/devfile/alizer/pkg/apis/enricher/go_enricher.go b/vendor/github.com/devfile/alizer/pkg/apis/enricher/go_enricher.go index 835c74d6b..c00f85bee 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/enricher/go_enricher.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/enricher/go_enricher.go @@ -14,12 +14,12 @@ package enricher import ( "context" "errors" - "io/ioutil" - framework "github.com/devfile/alizer/pkg/apis/enricher/framework/go" "github.com/devfile/alizer/pkg/apis/model" "github.com/devfile/alizer/pkg/utils" "golang.org/x/mod/modfile" + "os" + "path/filepath" ) type GoEnricher struct{} @@ -108,7 +108,7 @@ func (g GoEnricher) IsConfigValidForComponentDetection(language string, config s } func getGoModFile(filePath string) (*modfile.File, error) { - b, err := ioutil.ReadFile(filePath) + b, err := os.ReadFile(filepath.Clean(filePath)) if err != nil { return nil, errors.New("unable to read go.mod file") } diff --git a/vendor/github.com/devfile/alizer/pkg/apis/model/model.go b/vendor/github.com/devfile/alizer/pkg/apis/model/model.go index 947402907..12594947f 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/model/model.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/model/model.go @@ -11,9 +11,10 @@ package model -import "regexp" - -type PortDetectionAlgorithm int +import ( + "context" + "regexp" +) const ( DockerFile PortDetectionAlgorithm = 0 @@ -21,66 +22,242 @@ const ( Source PortDetectionAlgorithm = 2 ) -type DetectionSettings struct { - BasePath string - PortDetectionStrategy []PortDetectionAlgorithm +// All models inside model.go are sorted by name A-Z + +// AngularCliJson represents the angular-cli.json file +type AngularCliJson struct { + Defaults struct { + Serve AngularHostPort `json:"serve"` + } `json:"defaults"` } -type Language struct { - Name string - Aliases []string - Weight float64 - Frameworks []string - Tools []string - CanBeComponent bool +// AngularHostPort represents the value of AngularCliJson.Defaults.Serve +type AngularHostPort struct { + Host string `json:"host"` + Port int `json:"port"` } -type Component struct { - Name string - Path string - Languages []Language - Ports []int +// AngularJson represents angular.json +type AngularJson struct { + Projects map[string]AngularProjectBody `json:"projects"` } -type Version struct { - SchemaVersion string - Default bool - Version string -} - -type DevFileType struct { - Name string - Language string - ProjectType string - Tags []string -} - -type DevfileFilter struct { - MinVersion string - MaxVersion string +// AngularProjectBody represents the value of each key of the map for AngularJson.Projects +type AngularProjectBody struct { + Architect struct { + Serve struct { + Options AngularHostPort `json:"options"` + } `json:"serve"` + } `json:"architect"` } +// ApplicationFileInfo is the main struct used to select potential application files +// for detectors type ApplicationFileInfo struct { - Dir string + // Context is the given context + Context *context.Context + + // Root is the root path of the component + Root string + + // Dir is the directory of the application file + Dir string + + // File is the filename of the application file File string } -type PortMatchRules struct { - MatchIndexRegexes []PortMatchRule - MatchRegexes []PortMatchSubRule +// Component represents every component detected from analysis process +type Component struct { + // Name is the name of the component + Name string + + // Path is the root path of the component + Path string + + // Languages is the slice of languages detected inside the component + Languages []Language + + // Ports is the slice of integers (port values) detected + Ports []int } +// DetectionSettings represents the required settings for component detection +type DetectionSettings struct { + // BasePath is the root path we need to apply detection process + BasePath string + + // PortDetectionStrategy is the list of areas that we will apply port detection + // Accepted values can be found at PortDetectionAlgorithm + PortDetectionStrategy []PortDetectionAlgorithm +} + +// DevfileFilter represents all filters passed to registry api upon requests +type DevfileFilter struct { + // MinSchemaVersion is the minimum schemaVersion of the fetched devfiles + MinSchemaVersion string + + // MaxSchemaVersion is the maximum schemaVersion of the fetched devfiles + MaxSchemaVersion string +} + +// DevfileScore represents the score that each devfile gets upon devfile matching process +type DevfileScore struct { + // DevfileIndex is the index of the fetched registry stacks slice + DevfileIndex int + + // Score is the score that a devfile has. The biggest score gets matched with a given source code + Score int +} + +// DevfileType represents a devfile.y(a)ml file +type DevfileType struct { + // Name is the name of a devfile + Name string + + // Language is the language of a devfile + Language string + + // ProjectType is the projectType of a devfile + ProjectType string + + // Tags is a slice of tags of a devfile + Tags []string + + // Versions is a slice of versions of a devfile + Versions []Version +} + +// EnvVar represents an environment variable with a name and a corresponding value. +type EnvVar struct { + // Name is the name of the environment variable. + Name string + + // Value is the value associated with the environment variable. + Value string +} + +// Language represents every language detected from language analysis process +type Language struct { + // Name is the name of the language + Name string + + // Aliases is the slice of aliases for this language + Aliases []string + + // Weight is the float value which shows the importance of this language inside a given source code + Weight float64 + + // Frameworks is the slice of frameworks detected for this language + Frameworks []string + + // Tools is the slice of tools detected for this language + Tools []string + + // CanBeComponent is the bool value shows if this language can be detected as component + CanBeComponent bool + + // CanBeContainerComponent is the bool value shows if this language can be detected as container component + CanBeContainerComponent bool +} + +// MicronautApplicationProps represents the application.properties file of micronaut applications +type MicronautApplicationProps struct { + Micronaut struct { + Server struct { + Port int `yaml:"port,omitempty"` + SSL struct { + Enabled bool `yaml:"enabled,omitempty"` + Port int `yaml:"port,omitempty"` + } `yaml:"ssl,omitempty"` + } `yaml:"server,omitempty"` + } `yaml:"micronaut,omitempty"` +} + +// OpenLibertyServerXml represents the server.xml file inside an open liberty application +type OpenLibertyServerXml struct { + HttpEndpoint struct { + HttpPort string `xml:"httpPort,attr"` + HttpsPort string `xml:"httpsPort,attr"` + } `xml:"httpEndpoint"` +} + +// PortDetectionAlgorithm represents one of port detection algorithm values +type PortDetectionAlgorithm int + +// PortMatchRule represents a rule for port matching with a given regex and a string to replace type PortMatchRule struct { - Regex *regexp.Regexp + // Regex is the regexp.Regexp value which will be used to match ports + Regex *regexp.Regexp + + // ToReplace is the string value which will be replaced once the Regex is matched ToReplace string } +// PortMatchRules represents a struct of rules and subrules for port matching +type PortMatchRules struct { + // MatchIndexRegexes is a slice of PortMatchRule + MatchIndexRegexes []PortMatchRule + + // MatchRegexes is a slice of PortMatchSubRule + MatchRegexes []PortMatchSubRule +} + +// PortMatchSubRule represents a sub rule for port matching type PortMatchSubRule struct { - Regex *regexp.Regexp + // Regex is the primary regexp.Regexp value for the sub rule + Regex *regexp.Regexp + + // Regex is the secondary regexp.Regexp value for the sub rule SubRegex *regexp.Regexp } -type DevFileScore struct { - DevFileIndex int - Score int +// QuarkusApplicationYaml represents the application.yaml used for quarkus applications +type QuarkusApplicationYaml struct { + Quarkus QuarkusHttp `yaml:"quarkus,omitempty"` +} + +// QuarkusHttp represents the port field from application.yaml of quarkus applications +type QuarkusHttp struct { + Http QuarkusHttpPort `yaml:"http,omitempty"` +} + +// QuarkusHttpPort represents the port value from application.yaml of quarkus applications +type QuarkusHttpPort struct { + Port int `yaml:"port,omitempty"` + InsecureRequests string `yaml:"insecure-requests,omitempty"` + SSLPort int `yaml:"ssl-port,omitempty"` +} + +// SpringApplicationProsServer represents the application.properties file used for spring applications +type SpringApplicationProsServer struct { + Server struct { + Port int `yaml:"port,omitempty"` + Http struct { + Port int `yaml:"port,omitempty"` + } `yaml:"http,omitempty"` + } `yaml:"server,omitempty"` +} + +// Version represents a version of a devfile +type Version struct { + // SchemaVersion is the schemaVersion value of a devfile version + SchemaVersion string + + // Default is the default value of a devfile version + Default bool + + // Version is the version tag of a devfile version + Version string +} + +// VertxConf represents the config file for vertx applications +type VertxConf struct { + Port int `json:"http.port,omitempty"` + ServerConfig VertexServerConfig `json:"http.server,omitempty"` +} + +// VertexServerConfig represents the server config file for vertx applications +type VertexServerConfig struct { + Port int `json:"http.server.port,omitempty"` } diff --git a/vendor/github.com/devfile/alizer/pkg/apis/recognizer/component_recognizer.go b/vendor/github.com/devfile/alizer/pkg/apis/recognizer/component_recognizer.go index 57af9a010..3f065e248 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/recognizer/component_recognizer.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/recognizer/component_recognizer.go @@ -38,6 +38,11 @@ func DetectComponents(path string) ([]model.Component, error) { return detectComponentsWithPathAndPortStartegy(path, []model.PortDetectionAlgorithm{model.DockerFile, model.Compose, model.Source}, &ctx) } +func DetectComponentsWithoutPortDetection(path string) ([]model.Component, error) { + ctx := context.Background() + return detectComponentsWithPathAndPortStartegy(path, []model.PortDetectionAlgorithm{}, &ctx) +} + func DetectComponentsInRootWithPathAndPortStartegy(path string, portDetectionStrategy []model.PortDetectionAlgorithm) ([]model.Component, error) { ctx := context.Background() return detectComponentsInRootWithPathAndPortStartegy(path, portDetectionStrategy, &ctx) @@ -182,6 +187,17 @@ func isAnyComponentInPath(path string, components []model.Component) bool { return false } +// isAnyComponentInDirectPath checks if a component is present in the exact path. +// Search starts from path and will return true if a component is found. +func isAnyComponentInDirectPath(path string, components []model.Component) bool { + for _, component := range components { + if strings.Contains(path, component.Path) { + return true + } + } + return false +} + // isFirstPathParentOfSecond check if first path is parent (direct or not) of second path. func isFirstPathParentOfSecond(firstPath string, secondPath string) bool { return strings.Contains(secondPath, firstPath) @@ -194,6 +210,7 @@ func DetectComponentsFromFilesList(files []string, settings model.DetectionSetti alizerLogger.V(0).Info(fmt.Sprintf("Detecting components for %d fetched file paths", len(files))) configurationPerLanguage := langfiles.Get().GetConfigurationPerLanguageMapping() var components []model.Component + var containerComponents []model.Component for _, file := range files { alizerLogger.V(1).Info(fmt.Sprintf("Accessing %s", file)) languages, err := getLanguagesByConfigurationFile(configurationPerLanguage, file) @@ -210,8 +227,20 @@ func DetectComponentsFromFilesList(files []string, settings model.DetectionSetti alizerLogger.V(1).Info(err.Error()) continue } - alizerLogger.V(0).Info(fmt.Sprintf("Component %s found", component.Name)) - components = appendIfMissing(components, component) + if component.Languages[0].CanBeComponent { + alizerLogger.V(0).Info(fmt.Sprintf("Component %s found", component.Name)) + components = appendIfMissing(components, component) + } + if component.Languages[0].CanBeContainerComponent { + alizerLogger.V(0).Info(fmt.Sprintf("Container component %s found", component.Name)) + containerComponents = appendIfMissing(containerComponents, component) + } + } + + for _, component := range containerComponents { + if !isAnyComponentInDirectPath(component.Path, components) { + components = appendIfMissing(components, component) + } } return components } @@ -226,8 +255,9 @@ func appendIfMissing(components []model.Component, component model.Component) [] } func getLanguagesByConfigurationFile(configurationPerLanguage map[string][]string, file string) ([]string, error) { + filename := filepath.Base(file) for regex, languages := range configurationPerLanguage { - if match, _ := regexp.MatchString(regex, file); match { + if match, _ := regexp.MatchString(regex, filename); match { return languages, nil } } diff --git a/vendor/github.com/devfile/alizer/pkg/apis/recognizer/devfile_recognizer.go b/vendor/github.com/devfile/alizer/pkg/apis/recognizer/devfile_recognizer.go index 407494b74..347f37070 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/recognizer/devfile_recognizer.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/recognizer/devfile_recognizer.go @@ -16,7 +16,7 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" + "io" "net/http" "regexp" "strings" @@ -28,192 +28,219 @@ import ( const MinimumAllowedVersion = "2.0.0" -func SelectDevFilesFromTypes(path string, devFileTypes []model.DevFileType) ([]int, error) { +// DEPRECATION WARNING: This function is deprecated, please use devfile_recognizer.MatchDevfiles +// instead. +// func SelectDevFilesFromTypes: Returns a list of devfiles matched for the given application +func SelectDevFilesFromTypes(path string, devfileTypes []model.DevfileType) ([]int, error) { alizerLogger := utils.GetOrCreateLogger() ctx := context.Background() alizerLogger.V(0).Info("Applying component detection to match a devfile") - devFilesIndexes := selectDevFilesFromComponentsDetectedInPath(path, devFileTypes) - if len(devFilesIndexes) > 0 { - alizerLogger.V(0).Info(fmt.Sprintf("Found %d potential matches", len(devFilesIndexes))) - return devFilesIndexes, nil + devfilesIndexes := selectDevfilesFromComponentsDetectedInPath(path, devfileTypes) + if len(devfilesIndexes) > 0 { + alizerLogger.V(0).Info(fmt.Sprintf("Found %d potential matches", len(devfilesIndexes))) + return devfilesIndexes, nil } alizerLogger.V(0).Info("No components found, applying language analysis for devfile matching") languages, err := analyze(path, &ctx) if err != nil { return []int{}, err } - devfile, err := SelectDevFileUsingLanguagesFromTypes(languages, devFileTypes) + mainLanguage, err := getMainLanguage(languages) + if err != nil { + return []int{}, err + } + devfiles, err := selectDevfilesByLanguage(mainLanguage, devfileTypes) if err != nil { return []int{}, errors.New("No valid devfile found for project in " + path) } - return []int{devfile}, nil + return devfiles, nil } -func selectDevFilesFromComponentsDetectedInPath(path string, devFileTypes []model.DevFileType) []int { +func getMainLanguage(languages []model.Language) (model.Language, error) { + if len(languages) == 0 { + return model.Language{}, fmt.Errorf("cannot detect main language due to empty languages list") + } + + mainLanguage := languages[0] + for _, language := range languages { + if language.Weight > mainLanguage.Weight { + mainLanguage = language + } + } + return mainLanguage, nil +} + +func selectDevfilesFromComponentsDetectedInPath(path string, devfileTypes []model.DevfileType) []int { components, _ := DetectComponentsInRoot(path) - devFilesIndexes := selectDevFilesFromComponents(components, devFileTypes) - if len(devFilesIndexes) > 0 { - return devFilesIndexes + devfilesIndexes := selectDevfilesFromComponents(components, devfileTypes) + if len(devfilesIndexes) > 0 { + return devfilesIndexes } components, _ = DetectComponents(path) - return selectDevFilesFromComponents(components, devFileTypes) + return selectDevfilesFromComponents(components, devfileTypes) } -func selectDevFilesFromComponents(components []model.Component, devFileTypes []model.DevFileType) []int { - var devFilesIndexes []int +func selectDevfilesFromComponents(components []model.Component, devfileTypes []model.DevfileType) []int { + var devfilesIndexes []int for _, component := range components { - devFiles, err := selectDevFilesByLanguage(component.Languages[0], devFileTypes) + devfiles, err := selectDevfilesByLanguage(component.Languages[0], devfileTypes) if err == nil { - devFilesIndexes = append(devFilesIndexes, devFiles...) + devfilesIndexes = append(devfilesIndexes, devfiles...) } } - return devFilesIndexes + return devfilesIndexes } -func SelectDevFileFromTypes(path string, devFileTypes []model.DevFileType) (int, error) { - devfiles, err := SelectDevFilesFromTypes(path, devFileTypes) +// DEPRECATION WARNING: This function is deprecated, please use devfile_recognizer.MatchDevfiles +// instead. +// func SelectDevFileFromTypes: Returns the first devfile from the list of devfiles returned +// from SelectDevFilesFromTypes func. It also returns an error if exists. +func SelectDevFileFromTypes(path string, devfileTypes []model.DevfileType) (int, error) { + devfiles, err := SelectDevFilesFromTypes(path, devfileTypes) if err != nil { return -1, err } return devfiles[0], nil } -func SelectDevFilesUsingLanguagesFromTypes(languages []model.Language, devFileTypes []model.DevFileType) ([]int, error) { - var devFilesIndexes []int +func SelectDevfilesUsingLanguagesFromTypes(languages []model.Language, devfileTypes []model.DevfileType) ([]int, error) { + var devfilesIndexes []int alizerLogger := utils.GetOrCreateLogger() alizerLogger.V(1).Info("Searching potential matches from detected languages") for _, language := range languages { alizerLogger.V(1).Info(fmt.Sprintf("Accessing %s language", language.Name)) - devFiles, err := selectDevFilesByLanguage(language, devFileTypes) + devfiles, err := selectDevfilesByLanguage(language, devfileTypes) if err == nil { - alizerLogger.V(1).Info(fmt.Sprintf("Found %d potential matches for language %s", len(devFiles), language.Name)) - devFilesIndexes = append(devFilesIndexes, devFiles...) + alizerLogger.V(1).Info(fmt.Sprintf("Found %d potential matches for language %s", len(devfiles), language.Name)) + devfilesIndexes = append(devfilesIndexes, devfiles...) } } - if len(devFilesIndexes) > 0 { - return devFilesIndexes, nil + if len(devfilesIndexes) > 0 { + return devfilesIndexes, nil } return []int{}, errors.New("no valid devfile found by using those languages") } -func SelectDevFileUsingLanguagesFromTypes(languages []model.Language, devFileTypes []model.DevFileType) (int, error) { - devFilesIndexes, err := SelectDevFilesUsingLanguagesFromTypes(languages, devFileTypes) +func SelectDevfileUsingLanguagesFromTypes(languages []model.Language, devfileTypes []model.DevfileType) (int, error) { + devfilesIndexes, err := SelectDevfilesUsingLanguagesFromTypes(languages, devfileTypes) if err != nil { return -1, err } - return devFilesIndexes[0], nil + return devfilesIndexes[0], nil } -func MatchDevfiles(path string, url string, filter model.DevfileFilter) ([]model.DevFileType, error) { +func MatchDevfiles(path string, url string, filter model.DevfileFilter) ([]model.DevfileType, error) { alizerLogger := utils.GetOrCreateLogger() alizerLogger.V(0).Info("Starting devfile matching") alizerLogger.V(1).Info(fmt.Sprintf("Downloading devfiles from registry %s", url)) - devFileTypesFromRegistry, err := downloadDevFileTypesFromRegistry(url, filter) + devfileTypesFromRegistry, err := DownloadDevfileTypesFromRegistry(url, filter) if err != nil { - return []model.DevFileType{}, err + return []model.DevfileType{}, err } - return selectDevfiles(path, devFileTypesFromRegistry) + return selectDevfiles(path, devfileTypesFromRegistry) } -func SelectDevFilesFromRegistry(path string, url string) ([]model.DevFileType, error) { +func SelectDevfilesFromRegistry(path string, url string) ([]model.DevfileType, error) { alizerLogger := utils.GetOrCreateLogger() alizerLogger.V(0).Info("Starting devfile matching") alizerLogger.V(1).Info(fmt.Sprintf("Downloading devfiles from registry %s", url)) - devFileTypesFromRegistry, err := downloadDevFileTypesFromRegistry(url, model.DevfileFilter{MinVersion: "", MaxVersion: ""}) + devfileTypesFromRegistry, err := DownloadDevfileTypesFromRegistry(url, model.DevfileFilter{MinSchemaVersion: "", MaxSchemaVersion: ""}) if err != nil { - return []model.DevFileType{}, err + return []model.DevfileType{}, err } - return selectDevfiles(path, devFileTypesFromRegistry) + return selectDevfiles(path, devfileTypesFromRegistry) } -func selectDevfiles(path string, devFileTypesFromRegistry []model.DevFileType) ([]model.DevFileType, error) { - indexes, err := SelectDevFilesFromTypes(path, devFileTypesFromRegistry) +// selectDevfiles is exposed as global var in the purpose of mocking tests +var selectDevfiles = func(path string, devfileTypesFromRegistry []model.DevfileType) ([]model.DevfileType, error) { + indexes, err := SelectDevFilesFromTypes(path, devfileTypesFromRegistry) if err != nil { - return []model.DevFileType{}, err + return []model.DevfileType{}, err } - var devFileTypes []model.DevFileType + var devfileTypes []model.DevfileType for _, index := range indexes { - devFileTypes = append(devFileTypes, devFileTypesFromRegistry[index]) + devfileTypes = append(devfileTypes, devfileTypesFromRegistry[index]) } - return devFileTypes, nil + return devfileTypes, nil } -func SelectDevFileFromRegistry(path string, url string) (model.DevFileType, error) { - devFileTypes, err := downloadDevFileTypesFromRegistry(url, model.DevfileFilter{MinVersion: "", MaxVersion: ""}) +func SelectDevfileFromRegistry(path string, url string) (model.DevfileType, error) { + devfileTypes, err := DownloadDevfileTypesFromRegistry(url, model.DevfileFilter{MinSchemaVersion: "", MaxSchemaVersion: ""}) if err != nil { - return model.DevFileType{}, err + return model.DevfileType{}, err } - index, err := SelectDevFileFromTypes(path, devFileTypes) + index, err := SelectDevFileFromTypes(path, devfileTypes) if err != nil { - return model.DevFileType{}, err + return model.DevfileType{}, err } - return devFileTypes[index], nil + return devfileTypes[index], nil } -func GetUrlWithVersions(url, minVersion, maxVersion string) (string, error) { +func GetUrlWithVersions(url, minSchemaVersion, maxSchemaVersion string) (string, error) { minAllowedVersion, err := version.NewVersion(MinimumAllowedVersion) if err != nil { return "", nil } - if minVersion != "" && maxVersion != "" { - minV, err := version.NewVersion(minVersion) + if minSchemaVersion != "" && maxSchemaVersion != "" { + minV, err := version.NewVersion(minSchemaVersion) if err != nil { return url, nil } - maxV, err := version.NewVersion(maxVersion) + maxV, err := version.NewVersion(maxSchemaVersion) if err != nil { return url, nil } if maxV.LessThan(minV) { - return "", fmt.Errorf("max-version cannot be lower than min-version") + return "", fmt.Errorf("max-schema-version cannot be lower than min-schema-version") } if maxV.LessThan(minAllowedVersion) || minV.LessThan(minAllowedVersion) { return "", fmt.Errorf("min and/or max version are lower than the minimum allowed version (2.0.0)") } - return fmt.Sprintf("%s?minSchemaVersion=%s&maxSchemaVersion=%s", url, minVersion, maxVersion), nil - } else if minVersion != "" { - minV, err := version.NewVersion(minVersion) + return fmt.Sprintf("%s?minSchemaVersion=%s&maxSchemaVersion=%s", url, minSchemaVersion, maxSchemaVersion), nil + } else if minSchemaVersion != "" { + minV, err := version.NewVersion(minSchemaVersion) if err != nil { return "", nil } if minV.LessThan(minAllowedVersion) { return "", fmt.Errorf("min version is lower than the minimum allowed version (2.0.0)") } - return fmt.Sprintf("%s?minSchemaVersion=%s", url, minVersion), nil - } else if maxVersion != "" { - maxV, err := version.NewVersion(maxVersion) + return fmt.Sprintf("%s?minSchemaVersion=%s", url, minSchemaVersion), nil + } else if maxSchemaVersion != "" { + maxV, err := version.NewVersion(maxSchemaVersion) if err != nil { return "", nil } if maxV.LessThan(minAllowedVersion) { return "", fmt.Errorf("max version is lower than the minimum allowed version (2.0.0)") } - return fmt.Sprintf("%s?maxSchemaVersion=%s", url, maxVersion), nil + return fmt.Sprintf("%s?maxSchemaVersion=%s", url, maxSchemaVersion), nil } else { return url, nil } } -func downloadDevFileTypesFromRegistry(url string, filter model.DevfileFilter) ([]model.DevFileType, error) { +// DownloadDevfileTypesFromRegistry is exposed as a global variable for the purpose of running mock tests +var DownloadDevfileTypesFromRegistry = func(url string, filter model.DevfileFilter) ([]model.DevfileType, error) { url = adaptUrl(url) tmpUrl := appendIndexPath(url) - url, err := GetUrlWithVersions(tmpUrl, filter.MinVersion, filter.MaxVersion) + url, err := GetUrlWithVersions(tmpUrl, filter.MinSchemaVersion, filter.MaxSchemaVersion) if err != nil { return nil, err } // This value is set by the user in order to configure the registry resp, err := http.Get(url) // #nosec G107 if err != nil { - return []model.DevFileType{}, err + return []model.DevfileType{}, err } defer func() error { if err := resp.Body.Close(); err != nil { @@ -224,21 +251,21 @@ func downloadDevFileTypesFromRegistry(url string, filter model.DevfileFilter) ([ // Check server response if resp.StatusCode != http.StatusOK { - return []model.DevFileType{}, errors.New("unable to fetch devfiles from the registry") + return []model.DevfileType{}, errors.New("unable to fetch devfiles from the registry") } - body, err2 := ioutil.ReadAll(resp.Body) + body, err2 := io.ReadAll(resp.Body) if err2 != nil { - return []model.DevFileType{}, errors.New("unable to fetch devfiles from the registry") + return []model.DevfileType{}, errors.New("unable to fetch devfiles from the registry") } - var devFileTypes []model.DevFileType - err = json.Unmarshal(body, &devFileTypes) + var devfileTypes []model.DevfileType + err = json.Unmarshal(body, &devfileTypes) if err != nil { - return []model.DevFileType{}, errors.New("unable to fetch devfiles from the registry") + return []model.DevfileType{}, errors.New("unable to fetch devfiles from the registry") } - return devFileTypes, nil + return devfileTypes, nil } func appendIndexPath(url string) string { @@ -261,7 +288,7 @@ func adaptUrl(url string) string { return url } -// selectDevFilesByLanguage detects devfiles that fit best with a project. +// selectDevfilesByLanguage detects devfiles that fit best with a project. // // Performs a search in two steps looping through all devfiles available. // When a framework is detected, this is stored in a map but still not saved. A check is made eventually as there could be that a future or @@ -270,21 +297,21 @@ func adaptUrl(url string) string { // // At the end, if some framework is supported by some devfile, they are returned. Otherwise, Alizer was not able to find any // specific devfile for the frameworks detected and returned the devfiles which got the largest score. -func selectDevFilesByLanguage(language model.Language, devFileTypes []model.DevFileType) ([]int, error) { - var devFileIndexes []int - frameworkPerDevFile := make(map[string]model.DevFileScore) +func selectDevfilesByLanguage(language model.Language, devfileTypes []model.DevfileType) ([]int, error) { + var devfileIndexes []int + frameworkPerDevfile := make(map[string]model.DevfileScore) scoreTarget := 0 - for index, devFile := range devFileTypes { + for index, devfile := range devfileTypes { score := 0 frameworkPerDevfileTmp := make(map[string]interface{}) - if strings.EqualFold(devFile.Language, language.Name) || matches(language.Aliases, devFile.Language) != "" { + if strings.EqualFold(devfile.Language, language.Name) || matches(language.Aliases, devfile.Language) != "" { score++ - if frw := matchesFormatted(language.Frameworks, devFile.ProjectType); frw != "" { + if frw := matchesFormatted(language.Frameworks, devfile.ProjectType); frw != "" { frameworkPerDevfileTmp[frw] = nil score += utils.FRAMEWORK_WEIGHT } - for _, tag := range devFile.Tags { + for _, tag := range devfile.Tags { if frw := matchesFormatted(language.Frameworks, tag); frw != "" { frameworkPerDevfileTmp[frw] = nil score += utils.FRAMEWORK_WEIGHT @@ -295,37 +322,37 @@ func selectDevFilesByLanguage(language model.Language, devFileTypes []model.DevF } for framework := range frameworkPerDevfileTmp { - devFileObj := frameworkPerDevFile[framework] - if score > devFileObj.Score { - frameworkPerDevFile[framework] = model.DevFileScore{ - DevFileIndex: index, + devfileObj := frameworkPerDevfile[framework] + if score > devfileObj.Score { + frameworkPerDevfile[framework] = model.DevfileScore{ + DevfileIndex: index, Score: score, } } } - if len(frameworkPerDevFile) == 0 { + if len(frameworkPerDevfile) == 0 { if score == scoreTarget { - devFileIndexes = append(devFileIndexes, index) + devfileIndexes = append(devfileIndexes, index) } else if score > scoreTarget { scoreTarget = score - devFileIndexes = []int{index} + devfileIndexes = []int{index} } } } } - if len(frameworkPerDevFile) > 0 { - devFileIndexes = []int{} - for _, val := range frameworkPerDevFile { - devFileIndexes = append(devFileIndexes, val.DevFileIndex) + if len(frameworkPerDevfile) > 0 { + devfileIndexes = []int{} + for _, val := range frameworkPerDevfile { + devfileIndexes = append(devfileIndexes, val.DevfileIndex) } } - if len(devFileIndexes) == 0 { - return devFileIndexes, errors.New("No valid devfile found for current language " + language.Name) + if len(devfileIndexes) == 0 { + return devfileIndexes, errors.New("No valid devfile found for current language " + language.Name) } - return devFileIndexes, nil + return devfileIndexes, nil } func matchesFormatted(values []string, valueToFind string) string { diff --git a/vendor/github.com/devfile/alizer/pkg/apis/recognizer/language_recognizer.go b/vendor/github.com/devfile/alizer/pkg/apis/recognizer/language_recognizer.go index c6b868dc0..6474b9062 100644 --- a/vendor/github.com/devfile/alizer/pkg/apis/recognizer/language_recognizer.go +++ b/vendor/github.com/devfile/alizer/pkg/apis/recognizer/language_recognizer.go @@ -127,12 +127,14 @@ func AnalyzeFile(configFile string, targetLanguage string) (model.Language, erro return model.Language{}, err } tmpLanguage := model.Language{ - Name: lang.Name, - Aliases: lang.Aliases, - Frameworks: []string{}, - Tools: []string{}, - Weight: 100, - CanBeComponent: true} + Name: lang.Name, + Aliases: lang.Aliases, + Frameworks: []string{}, + Tools: []string{}, + Weight: 100, + CanBeComponent: lang.Component, + CanBeContainerComponent: lang.ContainerComponent, + } langEnricher := enricher.GetEnricherByLanguage(targetLanguage) if langEnricher != nil { langEnricher.DoEnrichLanguage(&tmpLanguage, &[]string{configFile}) diff --git a/vendor/github.com/devfile/alizer/pkg/schema/devfile_yaml.go b/vendor/github.com/devfile/alizer/pkg/schema/devfile_yaml.go new file mode 100644 index 000000000..a737e7974 --- /dev/null +++ b/vendor/github.com/devfile/alizer/pkg/schema/devfile_yaml.go @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2023 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. + ******************************************************************************/ + +package schema + +type DevfileYaml struct { + StarterProjects []struct { + Git struct { + CheckoutFrom struct { + Remote string `yaml:"remote"` + Revision string `yaml:"revision"` + } `yaml:"checkoutFrom"` + Remotes struct { + Origin string `yaml:"origin"` + } `yaml:"remotes"` + } `yaml:"git"` + SubDir string `yaml:"subDir"` + } `yaml:"starterProjects"` +} diff --git a/vendor/github.com/devfile/alizer/pkg/schema/languages.go b/vendor/github.com/devfile/alizer/pkg/schema/languages.go index 295e2deae..d9a04505d 100644 --- a/vendor/github.com/devfile/alizer/pkg/schema/languages.go +++ b/vendor/github.com/devfile/alizer/pkg/schema/languages.go @@ -29,6 +29,7 @@ type LanguagesProperties map[string]LanguageProperties type LanguageCustomization struct { ConfigurationFiles []string `yaml:"configuration_files"` Component bool `yaml:"component"` + ContainerComponent bool `yaml:"container_component"` ExcludeFolders []string `yaml:"exclude_folders,omitempty"` Aliases []string `yaml:"aliases"` Disabled bool `default:"false" yaml:"disable_detection"` diff --git a/vendor/github.com/devfile/alizer/pkg/utils/detector.go b/vendor/github.com/devfile/alizer/pkg/utils/detector.go index f0e71c9a2..370c7e4c4 100644 --- a/vendor/github.com/devfile/alizer/pkg/utils/detector.go +++ b/vendor/github.com/devfile/alizer/pkg/utils/detector.go @@ -19,17 +19,18 @@ import ( "encoding/xml" "errors" "fmt" - "io/ioutil" + "io" + "io/fs" "os" "path/filepath" "regexp" "strconv" "strings" - "github.com/devfile/alizer/pkg/utils/langfiles" - "github.com/devfile/alizer/pkg/apis/model" "github.com/devfile/alizer/pkg/schema" + "github.com/devfile/alizer/pkg/utils/langfiles" + "github.com/moby/buildkit/frontend/dockerfile/parser" ignore "github.com/sabhiram/go-gitignore" ) @@ -65,16 +66,6 @@ func GetFile(filePaths *[]string, wantedFile string) string { return "" } -// HasFile checks if the file is in a filePaths path. -func HasFile(files *[]string, wantedFile string) bool { - for _, path := range *files { - if IsPathOfWantedFile(path, wantedFile) { - return true - } - } - return false -} - // IsPathOfWantedFile checks if the file is in the path. func IsPathOfWantedFile(path string, wantedFile string) bool { _, file := filepath.Split(path) @@ -83,7 +74,7 @@ func IsPathOfWantedFile(path string, wantedFile string) bool { // IsTagInFile checks if the file contains the tag. func IsTagInFile(file string, tag string) (bool, error) { - contentInByte, err := ioutil.ReadFile(file) + contentInByte, err := os.ReadFile(filepath.Clean(file)) if err != nil { return false, err } @@ -143,7 +134,7 @@ func GetPomFileContent(pomFilePath string) (schema.Pom, error) { if err != nil { return schema.Pom{}, err } - byteValue, _ := ioutil.ReadAll(xmlFile) + byteValue, _ := io.ReadAll(xmlFile) var pom schema.Pom err = xml.Unmarshal(byteValue, &pom) @@ -298,7 +289,7 @@ func isFileInRoot(root string, file string) bool { // GetFilePathsInRoot returns a slice of all files in the root. func GetFilePathsInRoot(root string) ([]string, error) { - fileInfos, err := ioutil.ReadDir(root) + fileInfos, err := os.ReadDir(root) if err != nil { return nil, err } @@ -309,14 +300,16 @@ func GetFilePathsInRoot(root string) ([]string, error) { return files, nil } +// ConvertPropertiesFileAsPathToMap fetches a file from a given path and transforms it into a map func ConvertPropertiesFileAsPathToMap(path string) (map[string]string, error) { - bytes, err := ioutil.ReadFile(path) + bytes, err := os.ReadFile(filepath.Clean(path)) if err != nil { return nil, err } return ConvertPropertiesFileToMap(bytes) } +// ConvertPropertiesFileAsPathToMap transforms a slice of bytes it into a map func ConvertPropertiesFileToMap(fileInBytes []byte) (map[string]string, error) { config := map[string]string{} scanner := bufio.NewScanner(bytes.NewReader(fileInBytes)) @@ -352,6 +345,173 @@ func GetValidPortsFromEnvs(envs []string) []int { return validPorts } +// GetEnvVarsFromDockerFile returns a slice of env vars from Dockerfiles in the given directory. +func GetEnvVarsFromDockerFile(root string) ([]model.EnvVar, error) { + locations := GetLocations(root) + for _, location := range locations { + filePath := filepath.Join(root, location) + cleanFilePath := filepath.Clean(filePath) + file, err := os.Open(cleanFilePath) + if err == nil { + defer func() error { + if err := file.Close(); err != nil { + return fmt.Errorf("error closing file: %s", err) + } + return nil + }() + return readEnvVarsFromDockerfile(file) + } + } + return nil, fmt.Errorf("no dockefile found inside dir: %s", root) +} + +// GetValidPortsFromEnvs returns a slice of valid ports from a dockerfile. +func GetValidPortsFromEnvDockerfile(envs []string, envVars []model.EnvVar) []int { + var validPorts []int + for _, env := range envs { + for _, envVar := range envVars { + if envVar.Name == env { + if port, err := GetValidPort(envVar.Value); err == nil { + validPorts = append(validPorts, port) + } + break + } + } + } + return validPorts +} + +// GetLocations returns a list of file paths representing common locations where Dockerfiles might be found +// within the specified 'root' directory and one level down. +// +// It starts with a predefined list of common file names for a Dockerfile +// ('Dockerfile', 'Containerfile', 'dockerfile', 'containerfile'), and appends such file names to the 'root' subdirectories. +// +// Note that hidden files and directories (starting with a dot, e.g., '.git') are ignored while traversing the 'root' directory. +func GetLocations(root string) []string { + filenames := []string{"Dockerfile", "Containerfile", "dockerfile", "containerfile"} + locations := make([]string, len(filenames)) + + copy(locations, filenames) + + entries, err := os.ReadDir(root) + if err != nil { + return locations + } + dirItems := make([]fs.FileInfo, 0, len(entries)) + for _, entry := range entries { + info, err := entry.Info() + if err != nil { + return locations + } + dirItems = append(dirItems, info) + } + for _, item := range dirItems { + if strings.HasPrefix(item.Name(), ".") { + continue + } + tmpPath := filepath.Join(root, item.Name()) + fileInfo, err := os.Stat(tmpPath) + if err != nil { + continue + } + if fileInfo.IsDir() { + for _, filename := range filenames { + locations = append(locations, filepath.Join(item.Name(), filename)) + } + } + } + return locations +} + +// ReadPortsFromDockerfile returns a slice of port numbers. +func ReadPortsFromDockerfile(file io.Reader) []int { + var ports []int + res, err := parser.Parse(file) + if err != nil { + return ports + } + + for _, child := range res.AST.Children { + // check for the potential port number in a Dockerfile/Containerfile + if strings.ToLower(child.Value) == "expose" { + for n := child.Next; n != nil; n = n.Next { + if port, err := strconv.Atoi(n.Value); err == nil { + ports = append(ports, port) + } + + } + } + } + return ports +} + +func upsertEnvVar(envVars []model.EnvVar, envVar model.EnvVar) []model.EnvVar { + isPresent := false + for i := range envVars { + if envVars[i].Name == envVar.Name { + isPresent = true + envVars[i].Value = envVar.Value + } + } + if !isPresent { + envVars = append(envVars, envVar) + } + return envVars +} + +// readEnvVarsFromDockerfile returns a slice of envVars. +func readEnvVarsFromDockerfile(file io.Reader) ([]model.EnvVar, error) { + var envVars []model.EnvVar + res, err := parser.Parse(file) + if err != nil { + return envVars, err + } + + for _, child := range res.AST.Children { + // check for the potential env var in a Dockerfile/Containerfile + if strings.ToLower(child.Value) != "env" { + continue + } + firstNode := child.Next + var secondNode *parser.Node + if firstNode == nil { + continue + } + secondNode = firstNode.Next + if secondNode == nil { + continue + } + envVar := model.EnvVar{ + Name: firstNode.Value, + Value: secondNode.Value, + } + envVars = upsertEnvVar(envVars, envVar) + } + + return envVars, nil +} + +// GetEnvVarPortValueFromDockerfile gets port value defined as env vars. +func GetEnvVarPortValueFromDockerfile(path string, portPlaceholders []string) ([]int, error) { + envVars, err := GetEnvVarsFromDockerFile(path) + ports := []int{} + if err != nil { + return ports, err + } + for _, envVar := range envVars { + for _, portPlaceholder := range portPlaceholders { + if envVar.Name != portPlaceholder { + continue + } + if port, err := GetValidPort(envVar.Value); err == nil { + ports = append(ports, port) + } + } + } + return ports, nil +} + // GetValidPorts returns a slice of valid ports. func GetValidPorts(ports []string) []int { var validPorts []int @@ -407,9 +567,62 @@ func GetAnyApplicationFilePathExactMatch(root string, propsFiles []model.Applica return "" } -// ReadAnyApplicationFile returns a byte slice of a file if it exists in the directory and the given file name is a substring. -func ReadAnyApplicationFile(root string, propsFiles []model.ApplicationFileInfo, ctx *context.Context) ([]byte, error) { - return readAnyApplicationFile(root, propsFiles, false, ctx) +// GenerateApplicationFileFromFilters generates a slice of model.ApplicationFileInfo +// from a given list of files and the root path of a component. If suffix exists +// it generates items only for files ending with this suffix. +func GenerateApplicationFileFromFilters(files []string, path string, suffix string, ctx *context.Context) []model.ApplicationFileInfo { + applicationFileInfos := []model.ApplicationFileInfo{} + for _, file := range files { + if strings.HasSuffix(file, suffix) { + cleanPath := filepath.Clean(file) + filename := filepath.Base(cleanPath) + tmpDir := strings.ReplaceAll(file, path, "") + dir := strings.ReplaceAll(tmpDir, filename, "") + appFileInfo := model.ApplicationFileInfo{ + Context: ctx, + Root: path, + Dir: dir, + File: filename, + } + applicationFileInfos = append(applicationFileInfos, appFileInfo) + } + } + return applicationFileInfos +} + +// GetApplicationFileContents returns a slice of strings for all file contents found for a given +// slice of ApplicationFileInfo. +func GetApplicationFileContents(appFileInfos []model.ApplicationFileInfo) ([]string, error) { + fileContents := []string{} + for _, appFileInfo := range appFileInfos { + fileContent, err := GetApplicationFileBytes(appFileInfo) + if err == nil { + fileContents = append(fileContents, string(fileContent)) + } + } + if len(fileContents) == 0 { + return fileContents, fmt.Errorf("error: no application file found matching given criteria") + } + return fileContents, nil +} + +// GetApplicationFileBytes returns a slice of bytes of a file if it exists in the directory and the given file name is a substring. +func GetApplicationFileBytes(propsFile model.ApplicationFileInfo) ([]byte, error) { + bytes, err := readAnyApplicationFile(propsFile.Root, []model.ApplicationFileInfo{propsFile}, false, propsFile.Context) + if err != nil { + return bytes, fmt.Errorf("error: %s", err) + } + return bytes, nil +} + +// GetApplicationFileInfo returns an item from a slice of applicationFileInfos if it matches the given filename +func GetApplicationFileInfo(propsFiles []model.ApplicationFileInfo, filename string) (model.ApplicationFileInfo, error) { + for _, propsFile := range propsFiles { + if propsFile.File == filename { + return propsFile, nil + } + } + return model.ApplicationFileInfo{}, fmt.Errorf("no ApplicationFileInfo found") } // ReadAnyApplicationFileExactMatch returns a byte slice if the exact given file exists in the directory. @@ -426,11 +639,12 @@ func readAnyApplicationFile(root string, propsFiles []model.ApplicationFileInfo, path = GetAnyApplicationFilePath(root, propsFiles, ctx) } if path != "" { - return ioutil.ReadFile(path) + return os.ReadFile(filepath.Clean(path)) } return nil, errors.New("no file found") } +// FindPortSubMatch returns a port number in case it finds one for a given regex group func FindPortSubmatch(re *regexp.Regexp, text string, group int) int { potentialPortGroup := FindPotentialPortGroup(re, text, group) if potentialPortGroup != "" { @@ -441,6 +655,7 @@ func FindPortSubmatch(re *regexp.Regexp, text string, group int) int { return -1 } +// FindPotentialPortGroup returns a placeholder for port if is found func FindPotentialPortGroup(re *regexp.Regexp, text string, group int) string { if text != "" { matches := re.FindStringSubmatch(text) @@ -451,6 +666,7 @@ func FindPotentialPortGroup(re *regexp.Regexp, text string, group int) string { return "" } +// FindAllPortsSubmatch returns a slice of port int values, matching a regex inside a given text func FindAllPortsSubmatch(re *regexp.Regexp, text string, group int) []int { var ports []int if text != "" { @@ -467,6 +683,8 @@ func FindAllPortsSubmatch(re *regexp.Regexp, text string, group int) []int { return ports } +// GetPortValueFromEnvFile returns the first port value of a slice of port values +// declared from env var files. func GetPortValueFromEnvFile(root string, regex string) int { ports := GetPortValuesFromEnvFile(root, []string{regex}) if len(ports) > 0 { @@ -475,6 +693,7 @@ func GetPortValueFromEnvFile(root string, regex string) int { return -1 } +// GetPortValuesFromEnvFile returns all port values found inside an env var file func GetPortValuesFromEnvFile(root string, regexes []string) []int { var ports []int text, err := getEnvFileContent(root) @@ -494,6 +713,7 @@ func GetPortValuesFromEnvFile(root string, regexes []string) []int { return ports } +// GetStringValueFromEnvFile returns port values as string from env file func GetStringValueFromEnvFile(root string, regex string) string { text, err := getEnvFileContent(root) if err != nil { @@ -523,6 +743,7 @@ var getEnvFileContent = func(root string) (string, error) { return string(bytes), nil } +// NormalizeSplit splits a filepath into dir and filename func NormalizeSplit(file string) (string, string) { dir, fileName := filepath.Split(file) if dir == "" { diff --git a/vendor/github.com/devfile/alizer/pkg/utils/langfiles/languages_file_handler.go b/vendor/github.com/devfile/alizer/pkg/utils/langfiles/languages_file_handler.go index e36d7ebc1..9237e9903 100644 --- a/vendor/github.com/devfile/alizer/pkg/utils/langfiles/languages_file_handler.go +++ b/vendor/github.com/devfile/alizer/pkg/utils/langfiles/languages_file_handler.go @@ -28,6 +28,7 @@ type LanguageItem struct { ConfigurationFiles []string ExcludeFolders []string Component bool + ContainerComponent bool disabled bool } @@ -87,6 +88,7 @@ func customizeLanguage(languageItem *LanguageItem) { (*languageItem).ConfigurationFiles = customization.ConfigurationFiles (*languageItem).ExcludeFolders = customization.ExcludeFolders (*languageItem).Component = customization.Component + (*languageItem).ContainerComponent = customization.ContainerComponent (*languageItem).Aliases = appendSlice((*languageItem).Aliases, customization.Aliases) (*languageItem).disabled = customization.Disabled } diff --git a/vendor/github.com/devfile/alizer/pkg/utils/langfiles/resources/languages-customization.yml b/vendor/github.com/devfile/alizer/pkg/utils/langfiles/resources/languages-customization.yml index 1f1105b2c..162b69b18 100644 --- a/vendor/github.com/devfile/alizer/pkg/utils/langfiles/resources/languages-customization.yml +++ b/vendor/github.com/devfile/alizer/pkg/utils/langfiles/resources/languages-customization.yml @@ -6,6 +6,13 @@ C#: - ".*\\.\\w+proj" - "appsettings.json" component: true +Dockerfile: + aliases: + - "Containerfile" + configuration_files: + - "[Dd]ockerfile(\\.\\w+)?$" + - "[Cc]ontainerfile(\\.\\w+)?$" + container_component: true F#: aliases: - "dotnet" @@ -33,12 +40,12 @@ JavaScript: exclude_folders: - "node_modules" configuration_files: - - "[^-]package.json" + - "package.json" component: true PHP: configuration_files: - "composer.json" - - "[^-]package.json" + - "package.json" component: true Python: configuration_files: @@ -55,7 +62,7 @@ TypeScript: exclude_folders: - "node_modules" configuration_files: - - "[^-]package.json" + - "package.json" component: true Visual Basic .NET: aliases: diff --git a/vendor/modules.txt b/vendor/modules.txt index c2d32ce72..55bf1731e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -150,7 +150,7 @@ github.com/danieljoos/wincred # github.com/davecgh/go-spew v1.1.1 ## explicit github.com/davecgh/go-spew/spew -# github.com/devfile/alizer v1.0.1 +# github.com/devfile/alizer v1.2.1 ## explicit; go 1.19 github.com/devfile/alizer/pkg/apis/enricher github.com/devfile/alizer/pkg/apis/enricher/framework/dotnet