Repository: apache/camel-k
Pull request #955 (2019-09-25 09:16:21)

chore: Remove unecessary watch on builds while reconciling integrations
No `Integration` CRs own `Build` CRs anymore.


Patch:
diff --git a/pkg/controller/integration/integration_controller.go b/pkg/controller/integration/integration_controller.go
index 0e4eabeda..4e1cd4622 100644
--- a/pkg/controller/integration/integration_controller.go
+++ b/pkg/controller/integration/integration_controller.go
@@ -19,10 +19,6 @@ package integration
 import (
 	"context"
 
-	"github.com/apache/camel-k/pkg/platform"
-
-	"github.com/apache/camel-k/pkg/util/digest"
-
 	"k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/types"
@@ -40,6 +36,8 @@ import (
 
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/apache/camel-k/pkg/client"
+	"github.com/apache/camel-k/pkg/platform"
+	"github.com/apache/camel-k/pkg/util/digest"
 	"github.com/apache/camel-k/pkg/util/log"
 )
 
@@ -94,28 +92,6 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
 		return err
 	}
 
-	// Watch for changes to secondary resource Builds and requeue the owner IntegrationKit
-	err = c.Watch(&source.Kind{Type: &v1alpha1.Build{}},
-		&handler.EnqueueRequestForOwner{
-			IsController: true,
-			OwnerType:    &v1alpha1.Integration{},
-		},
-		predicate.Funcs{
-			UpdateFunc: func(e event.UpdateEvent) bool {
-				oldBuild := e.ObjectOld.(*v1alpha1.Build)
-				newBuild := e.ObjectNew.(*v1alpha1.Build)
-				// Ignore updates to the build CR except when the build phase changes
-				// as it's used to transition the integration from one phase to another
-				// during image build
-				return oldBuild.Status.Phase != newBuild.Status.Phase
-			},
-		},
-	)
-
-	if err != nil {
-		return err
-	}
-
 	// Watch for IntegrationKit phase transitioning to ready or error and
 	// enqueue requests for any integrations that are in phase waiting for
 	// kit
@@ -148,7 +124,6 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
 			return requests
 		}),
 	})
-
 	if err != nil {
 		return err
 	}
@@ -184,7 +159,6 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
 			return requests
 		}),
 	})
-
 	if err != nil {
 		return err
 	}
diff --git a/pkg/trait/camel.go b/pkg/trait/camel.go
index 29f66b203..7cfbc9d03 100644
--- a/pkg/trait/camel.go
+++ b/pkg/trait/camel.go
@@ -23,6 +23,7 @@ import (
 	"os"
 	"path"
 	"regexp"
+	"strings"
 
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/apache/camel-k/pkg/util/camel"
@@ -89,7 +90,10 @@ func (t *camelTrait) Apply(e *Environment) error {
 					return err
 				}
 
-				cx := v1alpha1.NewCamelCatalogWithSpecs(ns, "camel-catalog-"+cv, c.CamelCatalogSpec)
+				// sanitize catalog name
+				catalogName := "camel-catalog-" + strings.ToLower(cv)
+
+				cx := v1alpha1.NewCamelCatalogWithSpecs(ns, catalogName, c.CamelCatalogSpec)
 				cx.Labels = make(map[string]string)
 				cx.Labels["app"] = "camel-k"
 				cx.Labels["camel.apache.org/catalog.version"] = cv
diff --git a/pkg/util/camel/camel_runtime_catalog.go b/pkg/util/camel/camel_runtime_catalog.go
index 8cb90e5fc..da0ee4dce 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 65263cdb9..942900b51 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 fbf13a295..116ed62fa 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 93e8781d3..7a16d1afa 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{})
 


Test patch:
diff --git a/pkg/metadata/metadata_dependencies_test.go b/pkg/metadata/metadata_dependencies_test.go
index f0ad794a5..edaab2113 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: `
+               <from uri="direct:start" />
+               <transform>
+                 <language language="ognl">request.body.name == 'Camel K'</language>
+               </transform>
+               <transform>
+                 <simple>${body.toUpperCase()}</simple>
+               </transform>
+               <transform>
+                 <mvel>resource:classpath:script.mvel</mvel>
+               </transform>
+               <transform>
+                 <jsonpath>$.foo</jsonpath>
+               </transform>
+               <transform>
+                 <groovy>request.body += 'modified'</groovy>
+               </transform>
+               <transform>
+                 <tokenize>request.body += 'modified'</tokenize>
+               </transform>
+               <transform>
+                 <xtokenize>/ns:foo/bar</xtokenize>
+               </transform>
+               <transform>
+                 <xpath>//foo/bar</xpath>
+               </transform>
+               <transform>
+                 <xquery>//ns:foo/bar</xquery>
+               </transform>
+               <split>
+                 <tokenize token=","/>
+               </split>
+          `,
+		},
+		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())
+}