diff --git a/pkg/metadata/metadata_dependencies_test.go b/pkg/metadata/metadata_dependencies_test.go index f0ad794a53..edaab2113d 100644 --- a/pkg/metadata/metadata_dependencies_test.go +++ b/pkg/metadata/metadata_dependencies_test.go @@ -135,6 +135,55 @@ func TestJacksonDependency(t *testing.T) { assert.ElementsMatch(t, []string{"camel:http4", "camel:jackson", "camel:log"}, meta.Dependencies.List()) } +func TestLanguageDependencies(t *testing.T) { + code := v1alpha1.SourceSpec{ + DataSpec: v1alpha1.DataSpec{ + Name: "Languages.java", + Content: ` + from("direct:start") + .transform().ognl("request.body.name == 'Camel K'") + .transform().simple("${body.toUpperCase()}") + .transform().mvel("resource:classpath:script.mvel") + .transform().xquery("/ns:foo/bar", String.class, new Namespaces("ns", "http://foo/bar")) + .transform().xpath("//foo/bar") + .transform().jsonpath("$.foo") + .transform().groovy("request.body += 'modified'") + .split().xtokenize("/ns:foo/bar", new Namespaces("ns", "http://foo/bar")); + `, + }, + Language: v1alpha1.LanguageJavaSource, + } + + catalog, err := test.DefaultCatalog() + assert.Nil(t, err) + + meta := Extract(catalog, code) + assert.ElementsMatch(t, []string{"camel:direct", "camel:bean", "camel:ognl", "camel:saxon", "camel:xpath", + "camel:jsonpath", "camel:groovy", "camel:jaxp", "camel:mvel"}, meta.Dependencies.List()) +} + +func TestLanguageDependenciesTransformExpression(t *testing.T) { + code := v1alpha1.SourceSpec{ + DataSpec: v1alpha1.DataSpec{ + Name: "Languages.java", + Content: ` + from("direct:start") + .transform(language("ognl", "request.body.name == 'Camel K'")) + .transform(simple("${body.toUpperCase()}")) + .transform(xpath("//foo/bar")) + .transform(jsonpath("$.foo")) + `, + }, + Language: v1alpha1.LanguageJavaSource, + } + + catalog, err := test.DefaultCatalog() + assert.Nil(t, err) + + meta := Extract(catalog, code) + assert.ElementsMatch(t, []string{"camel:direct", "camel:bean", "camel:ognl", "camel:xpath", "camel:jsonpath"}, meta.Dependencies.List()) +} + func TestHystrixDependency(t *testing.T) { code := v1alpha1.SourceSpec{ DataSpec: v1alpha1.DataSpec{ @@ -232,7 +281,7 @@ func TestRestClosureDependency(t *testing.T) { Name: "Request.groovy", Content: ` rest { - } + } from("http4:test") .to("log:info") `, @@ -304,19 +353,94 @@ func TestXMLRestDependency(t *testing.T) { assert.ElementsMatch(t, []string{"camel:direct", "camel:rest", "camel:mock"}, meta.Dependencies.List()) } +func TestXMLLanguageDependencies(t *testing.T) { + code := v1alpha1.SourceSpec{ + DataSpec: v1alpha1.DataSpec{ + Name: "routes.xml", + Content: ` + + + request.body.name == 'Camel K' + + + ${body.toUpperCase()} + + + resource:classpath:script.mvel + + + $.foo + + + request.body += 'modified' + + + request.body += 'modified' + + + /ns:foo/bar + + + //foo/bar + + + //ns:foo/bar + + + + + `, + }, + Language: v1alpha1.LanguageXML, + } + + catalog, err := test.DefaultCatalog() + assert.Nil(t, err) + + meta := Extract(catalog, code) + assert.ElementsMatch(t, []string{"camel:direct", "camel:bean", "camel:ognl", "camel:saxon", "camel:xpath", + "camel:jsonpath", "camel:groovy", "camel:jaxp", "camel:mvel"}, meta.Dependencies.List()) +} + const yamlWithRest = ` - rest: path: "/" steps: - to: "log:info" - - to: "direct:hello" + - to: "direct:hello" ` const yamlWithHystrix = ` - from: uri: "direct:start" steps: - hystrix: - todo: "not implemented" + todo: "not implemented" +` + +const yamlWithLanguages = ` +- from: + uri: "direct:start" + steps: + - set-body: + constant: "Hello Camel K" + - transform: + language: + language: "ognl" + expression: "request.body.name == 'Camel K'" + - transform: + simple: "${body.toUpperCase()}" + - transform: + mvel: "resource:classpath:script.mvel" + - transform: + xquery: "/ns:foo/bar" + - transform: + xpath: "//foo/bar" + - transform: + jsonpath: "$.foo" + - transform: + groovy: "request.body += 'modified'" + - split: + xtokenize: "/ns:foo/bar" ` func TestYAMLRestDependency(t *testing.T) { @@ -354,3 +478,21 @@ func TestYAMLHystrixDependency(t *testing.T) { assert.ElementsMatch(t, []string{"camel:direct", "camel:hystrix"}, meta.Dependencies.List()) } + +func TestYAMLLanguageDependencies(t *testing.T) { + code := v1alpha1.SourceSpec{ + DataSpec: v1alpha1.DataSpec{ + Name: "routes.yaml", + Content: yamlWithLanguages, + }, + Language: v1alpha1.LanguageYaml, + } + + catalog, err := test.DefaultCatalog() + assert.Nil(t, err) + + meta := Extract(catalog, code) + + assert.ElementsMatch(t, []string{"camel:direct", "camel:bean", "camel:ognl", "camel:saxon", "camel:xpath", + "camel:jsonpath", "camel:groovy", "camel:jaxp", "camel:mvel"}, meta.Dependencies.List()) +} diff --git a/pkg/util/camel/camel_runtime_catalog.go b/pkg/util/camel/camel_runtime_catalog.go index 8cb90e5fc7..da0ee4dce9 100644 --- a/pkg/util/camel/camel_runtime_catalog.go +++ b/pkg/util/camel/camel_runtime_catalog.go @@ -29,6 +29,7 @@ func NewRuntimeCatalog(spec v1alpha1.CamelCatalogSpec) *RuntimeCatalog { catalog.CamelCatalogSpec = spec catalog.artifactByScheme = make(map[string]string) catalog.schemesByID = make(map[string]v1alpha1.CamelScheme) + catalog.languageDependencies = make(map[string]string) for id, artifact := range catalog.Artifacts { for _, scheme := range artifact.Schemes { @@ -36,6 +37,12 @@ func NewRuntimeCatalog(spec v1alpha1.CamelCatalogSpec) *RuntimeCatalog { catalog.artifactByScheme[scheme.ID] = id catalog.schemesByID[scheme.ID] = scheme } + for _, language := range artifact.Languages { + // Skip languages in common dependencies since they are always available to integrations + if artifact.ArtifactID != "camel-base" { + catalog.languageDependencies[language] = strings.Replace(artifact.ArtifactID, "camel-", "camel:", 1) + } + } } return &catalog @@ -45,8 +52,9 @@ func NewRuntimeCatalog(spec v1alpha1.CamelCatalogSpec) *RuntimeCatalog { type RuntimeCatalog struct { v1alpha1.CamelCatalogSpec - artifactByScheme map[string]string - schemesByID map[string]v1alpha1.CamelScheme + artifactByScheme map[string]string + schemesByID map[string]v1alpha1.CamelScheme + languageDependencies map[string]string } // HasArtifact -- @@ -76,6 +84,12 @@ func (c *RuntimeCatalog) GetScheme(id string) (v1alpha1.CamelScheme, bool) { return scheme, ok } +// GetLanguageDependency returns the maven dependency for the given language name +func (c *RuntimeCatalog) GetLanguageDependency(language string) (string, bool) { + language, ok := c.languageDependencies[language] + return language, ok +} + // VisitArtifacts -- func (c *RuntimeCatalog) VisitArtifacts(visitor func(string, v1alpha1.CamelArtifact) bool) { for id, artifact := range c.Artifacts { diff --git a/pkg/util/source/inspector.go b/pkg/util/source/inspector.go index 65263cdb90..942900b513 100644 --- a/pkg/util/source/inspector.go +++ b/pkg/util/source/inspector.go @@ -35,13 +35,22 @@ var ( doubleQuotedTo = regexp.MustCompile(`\.to\s*\(\s*"([a-zA-Z0-9-]+:[^"]+)"`) doubleQuotedToD = regexp.MustCompile(`\.toD\s*\(\s*"([a-zA-Z0-9-]+:[^"]+)"`) doubleQuotedToF = regexp.MustCompile(`\.toF\s*\(\s*"([a-zA-Z0-9-]+:[^"]+)"`) + languageRegexp = regexp.MustCompile(`language\s*\(\s*["|']([a-zA-Z0-9-]+[^"|']+)["|']\s*,.*\)`) additionalDependencies = map[string]string{ - `.*JsonLibrary\.Jackson.*`: "camel:jackson", - `.*\.hystrix().*`: "camel:hystrix", - `.*restConfiguration().*`: "camel:rest", - `.*rest(("[a-zA-Z0-9-/]+")*).*`: "camel:rest", - `^\s*rest\s*{.*`: "camel:rest", + `.*JsonLibrary\.Jackson.*`: "camel:jackson", + `.*\.hystrix().*`: "camel:hystrix", + `.*restConfiguration().*`: "camel:rest", + `.*rest(("[a-zA-Z0-9-/]+")*).*`: "camel:rest", + `^\s*rest\s*{.*`: "camel:rest", + `.*\.groovy\s*\(.*\).*`: "camel:groovy", + `.*\.?(jsonpath|jsonpathWriteAsString)\s*\(.*\).*`: "camel:jsonpath", + `.*\.ognl\s*\(.*\).*`: "camel:ognl", + `.*\.mvel\s*\(.*\).*`: "camel:mvel", + `.*\.?simple\s*\(.*\).*`: "camel:bean", + `.*\.xquery\s*\(.*\).*`: "camel:saxon", + `.*\.?xpath\s*\(.*\).*`: "camel:xpath", + `.*\.xtokenize\s*\(.*\).*`: "camel:jaxp", } ) @@ -118,6 +127,14 @@ func (i *baseInspector) discoverDependencies(source v1alpha1.SourceSpec, meta *M meta.Dependencies.Add(dep) } } + + for _, match := range languageRegexp.FindAllStringSubmatch(source.Content, -1) { + if len(match) > 1 { + if dependency, ok := i.catalog.GetLanguageDependency(match[1]); ok { + meta.Dependencies.Add(dependency) + } + } + } } func (i *baseInspector) decodeComponent(uri string) string { diff --git a/pkg/util/source/inspector_xml.go b/pkg/util/source/inspector_xml.go index fbf13a2959..116ed62fa5 100644 --- a/pkg/util/source/inspector_xml.go +++ b/pkg/util/source/inspector_xml.go @@ -47,6 +47,16 @@ func (i XMLInspector) Extract(source v1alpha1.SourceSpec, meta *Metadata) error meta.Dependencies.Add("camel:rest") case "hystrix": meta.Dependencies.Add("camel:hystrix") + case "simple": + meta.Dependencies.Add("camel:bean") + case "language": + for _, a := range se.Attr { + if a.Name.Local == "language" { + if dependency, ok := i.catalog.GetLanguageDependency(a.Value); ok { + meta.Dependencies.Add(dependency) + } + } + } case "from", "fromF": for _, a := range se.Attr { if a.Name.Local == "uri" { @@ -60,6 +70,10 @@ func (i XMLInspector) Extract(source v1alpha1.SourceSpec, meta *Metadata) error } } } + + if dependency, ok := i.catalog.GetLanguageDependency(se.Name.Local); ok { + meta.Dependencies.Add(dependency) + } } } diff --git a/pkg/util/source/inspector_yaml.go b/pkg/util/source/inspector_yaml.go index 93e8781d3f..7a16d1afab 100644 --- a/pkg/util/source/inspector_yaml.go +++ b/pkg/util/source/inspector_yaml.go @@ -69,6 +69,31 @@ func (inspector YAMLInspector) parseStep(key string, content interface{}, meta * if u, ok := t["uri"]; ok { maybeURI = u.(string) } + + if _, ok := t["simple"]; ok { + meta.Dependencies.Add("camel:bean") + } + + if _, ok := t["language"]; ok { + if s, ok := t["language"].(string); ok { + if dependency, ok := inspector.catalog.GetLanguageDependency(s); ok { + meta.Dependencies.Add(dependency) + } + } else if m, ok := t["language"].(map[interface{}]interface{}); ok { + if err := inspector.parseStep("language", m, meta); err != nil { + return err + } + } + } + + for k := range t { + if s, ok := k.(string); ok { + if dependency, ok := inspector.catalog.GetLanguageDependency(s); ok { + meta.Dependencies.Add(dependency) + } + } + } + if u, ok := t["steps"]; ok { steps := u.([]interface{})