This is an automated email from the ASF dual-hosted git repository. pcongiusti pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-k.git
commit acf77559fb63c2244d0b1959bc185fe7e39d083e Author: Christoph Deppisch <[email protected]> AuthorDate: Mon Jan 9 15:21:16 2023 +0100 fix(#3844): Add service discovery for Kamelet data type converter - Enable service discovery for data type converter resources in order to enable factory finder mechanism when resolving data type implementations - Add proper quarkus-maven-plugin build time properties for quarkus.camel.* properties - Fixes the way camel-quarkus build time properties are set (set properties on the quarkus-maven-plugin instead of using generic Maven system properties) - Explicitly add quarkus.camel.service.discovery.include-patterns for data type converter resources in order to enable lazy loading of Kamelets data type implementations Relates to https://github.com/apache/camel-k/issues/1980 --- docs/modules/ROOT/partials/apis/camel-k-crds.adoc | 34 ++++++ pkg/apis/camel/v1/maven_types.go | 6 + pkg/apis/camel/v1/maven_types_support.go | 62 +++++++++- pkg/apis/camel/v1/maven_types_support_test.go | 142 ++++++++++++++++++++++ pkg/apis/camel/v1/zz_generated.deepcopy.go | 43 +++++++ pkg/builder/project_test.go | 4 +- pkg/builder/quarkus.go | 50 +++++--- pkg/cmd/local/local.go | 2 +- pkg/util/camel/camel_dependencies.go | 18 +-- pkg/util/defaults/defaults.go | 2 +- pkg/util/maven/maven_project.go | 7 +- pkg/util/maven/maven_types.go | 8 +- 12 files changed, 341 insertions(+), 37 deletions(-) diff --git a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc index 122776fcb..0db42b568 100644 --- a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc +++ b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc @@ -2423,6 +2423,12 @@ See https://maven.apache.org/ref/3.8.4/maven-embedder/cli.html. |=== +[#_camel_apache_org_v1_PluginProperties] +=== PluginProperties(`map[string]github.com/apache/camel-k/pkg/apis/camel/v1.StringOrProperties` alias) + + + + [#_camel_apache_org_v1_PodSpec] === PodSpec @@ -2547,6 +2553,7 @@ the specification *Appears on:* * <<#_camel_apache_org_v1_Server, Server>> +* <<#_camel_apache_org_v1_StringOrProperties, StringOrProperties>> @@ -3073,6 +3080,33 @@ SpectrumTask is used to configure Spectrum +|=== + +[#_camel_apache_org_v1_StringOrProperties] +=== StringOrProperties + + + +[cols="2,2a",options="header"] +|=== +|Field +|Description + +|`-` + +string +| + + + + +|`properties` + +*xref:#_camel_apache_org_v1_Properties[Properties]* +| + + + + + |=== [#_camel_apache_org_v1_Task] diff --git a/pkg/apis/camel/v1/maven_types.go b/pkg/apis/camel/v1/maven_types.go index 1d55cb3fd..378d7cfc4 100644 --- a/pkg/apis/camel/v1/maven_types.go +++ b/pkg/apis/camel/v1/maven_types.go @@ -96,4 +96,10 @@ type Server struct { Configuration Properties `xml:"configuration,omitempty" json:"configuration,omitempty"` } +type StringOrProperties struct { + Value string `xml:",chardata" json:"-"` + Properties Properties `xml:"properties,omitempty" json:"properties,omitempty"` +} + type Properties map[string]string +type PluginProperties map[string]StringOrProperties diff --git a/pkg/apis/camel/v1/maven_types_support.go b/pkg/apis/camel/v1/maven_types_support.go index d4777bffc..5ba46f595 100644 --- a/pkg/apis/camel/v1/maven_types_support.go +++ b/pkg/apis/camel/v1/maven_types_support.go @@ -17,7 +17,9 @@ limitations under the License. package v1 -import "encoding/xml" +import ( + "encoding/xml" +) func (in *MavenArtifact) GetDependencyID() string { switch { @@ -35,10 +37,14 @@ type propertiesEntry struct { func (m Properties) AddAll(properties map[string]string) { for k, v := range properties { - m[k] = v + m.Add(k, v) } } +func (m Properties) Add(key string, value string) { + m[key] = value +} + func (m Properties) MarshalXML(e *xml.Encoder, start xml.StartElement) error { if len(m) == 0 { return nil @@ -57,3 +63,55 @@ func (m Properties) MarshalXML(e *xml.Encoder, start xml.StartElement) error { return e.EncodeToken(start.End()) } + +func (m PluginProperties) AddAll(properties map[string]string) { + for k, v := range properties { + m.Add(k, v) + } +} + +func (m PluginProperties) Add(key string, value string) { + m[key] = StringOrProperties{Value: value} +} + +func (m PluginProperties) AddProperties(key string, properties map[string]string) { + m[key] = StringOrProperties{Properties: properties} +} + +func (m PluginProperties) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + if len(m) == 0 { + return nil + } + + if err := e.EncodeToken(start); err != nil { + return err + } + + for k, v := range m { + if v.Value != "" { + if err := e.Encode(propertiesEntry{XMLName: xml.Name{Local: k}, Value: v.Value}); err != nil { + return err + } + } + + if len(v.Properties) > 0 { + nestedPropertyStart := xml.StartElement{Name: xml.Name{Local: k}} + if err := e.EncodeToken(nestedPropertyStart); err != nil { + return err + } + + for key, value := range v.Properties { + if err := e.Encode(propertiesEntry{XMLName: xml.Name{Local: key}, Value: value}); err != nil { + return err + } + } + + if err := e.EncodeToken(nestedPropertyStart.End()); err != nil { + return err + } + + } + } + + return e.EncodeToken(start.End()) +} diff --git a/pkg/apis/camel/v1/maven_types_support_test.go b/pkg/apis/camel/v1/maven_types_support_test.go new file mode 100644 index 000000000..979e6f7e5 --- /dev/null +++ b/pkg/apis/camel/v1/maven_types_support_test.go @@ -0,0 +1,142 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You 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 v1 + +import ( + "bytes" + "encoding/xml" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestMarshalEmptyProperties(t *testing.T) { + buf := new(bytes.Buffer) + e := xml.NewEncoder(buf) + + err := Properties{}.MarshalXML(e, xml.StartElement{ + Name: xml.Name{Local: "root"}, + }) + + assert.NoError(t, err) + + err = e.Flush() + + assert.NoError(t, err) + assert.Equal(t, "", buf.String()) +} + +func TestMarshalProperties(t *testing.T) { + buf := new(bytes.Buffer) + e := xml.NewEncoder(buf) + + properties := Properties{} + properties.Add("v1", "foo") + properties.Add("v2", "bar") + + err := properties.MarshalXML(e, xml.StartElement{ + Name: xml.Name{Local: "root"}, + }) + + assert.NoError(t, err) + + err = e.Flush() + + assert.NoError(t, err) + + result := buf.String() + assert.True(t, strings.HasPrefix(result, "<root>")) + assert.True(t, strings.HasSuffix(result, "</root>")) + assert.Contains(t, result, "<v1>foo</v1>") + assert.Contains(t, result, "<v2>bar</v2>") +} + +func TestMarshalEmptyPluginProperties(t *testing.T) { + buf := new(bytes.Buffer) + e := xml.NewEncoder(buf) + + err := PluginProperties{}.MarshalXML(e, xml.StartElement{ + Name: xml.Name{Local: "root"}, + }) + + assert.NoError(t, err) + + err = e.Flush() + + assert.NoError(t, err) + assert.Equal(t, "", buf.String()) +} + +func TestMarshalPluginProperties(t *testing.T) { + buf := new(bytes.Buffer) + e := xml.NewEncoder(buf) + + properties := PluginProperties{} + properties.Add("v1", "foo") + properties.Add("v2", "bar") + + err := properties.MarshalXML(e, xml.StartElement{ + Name: xml.Name{Local: "root"}, + }) + + assert.NoError(t, err) + + err = e.Flush() + + assert.NoError(t, err) + + result := buf.String() + assert.True(t, strings.HasPrefix(result, "<root>")) + assert.True(t, strings.HasSuffix(result, "</root>")) + assert.Contains(t, result, "<v1>foo</v1>") + assert.Contains(t, result, "<v2>bar</v2>") +} + +func TestMarshalPluginPropertiesWithNestedProps(t *testing.T) { + buf := new(bytes.Buffer) + e := xml.NewEncoder(buf) + + properties := PluginProperties{} + properties.Add("v1", "foo") + properties.AddProperties("props", map[string]string{ + "prop1": "foo", + "prop2": "baz", + }) + properties.Add("v2", "bar") + + err := properties.MarshalXML(e, xml.StartElement{ + Name: xml.Name{Local: "root"}, + }) + + assert.NoError(t, err) + + err = e.Flush() + + assert.NoError(t, err) + + result := buf.String() + assert.True(t, strings.HasPrefix(result, "<root>")) + assert.True(t, strings.HasSuffix(result, "</root>")) + assert.Contains(t, result, "<v1>foo</v1>") + assert.Contains(t, result, "<props>") + assert.Contains(t, result, "</props>") + assert.Contains(t, result, "<prop1>foo</prop1>") + assert.Contains(t, result, "<prop2>baz</prop2>") + assert.Contains(t, result, "<v2>bar</v2>") +} diff --git a/pkg/apis/camel/v1/zz_generated.deepcopy.go b/pkg/apis/camel/v1/zz_generated.deepcopy.go index 7aa25d965..a6082a6c2 100644 --- a/pkg/apis/camel/v1/zz_generated.deepcopy.go +++ b/pkg/apis/camel/v1/zz_generated.deepcopy.go @@ -1304,6 +1304,27 @@ func (in *MavenSpec) DeepCopy() *MavenSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in PluginProperties) DeepCopyInto(out *PluginProperties) { + { + in := &in + *out = make(PluginProperties, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginProperties. +func (in PluginProperties) DeepCopy() PluginProperties { + if in == nil { + return nil + } + out := new(PluginProperties) + in.DeepCopyInto(out) + return *out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PodSpec) DeepCopyInto(out *PodSpec) { *out = *in @@ -1623,6 +1644,28 @@ func (in *SpectrumTask) DeepCopy() *SpectrumTask { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StringOrProperties) DeepCopyInto(out *StringOrProperties) { + *out = *in + if in.Properties != nil { + in, out := &in.Properties, &out.Properties + *out = make(Properties, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StringOrProperties. +func (in *StringOrProperties) DeepCopy() *StringOrProperties { + if in == nil { + return nil + } + out := new(StringOrProperties) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Task) DeepCopyInto(out *Task) { *out = *in diff --git a/pkg/builder/project_test.go b/pkg/builder/project_test.go index 15bd9f212..a529f058d 100644 --- a/pkg/builder/project_test.go +++ b/pkg/builder/project_test.go @@ -452,7 +452,7 @@ func TestInjectServersIntoDefaultMavenSettings(t *testing.T) { ID: "image-repository", Username: "jpoth", Password: "changeit", - Configuration: map[string]string{ + Configuration: v1.Properties{ "allowInsecureRegistries": "false", }, }, @@ -478,7 +478,7 @@ func TestInjectServersIntoCustomMavenSettings(t *testing.T) { ID: "image-repository", Username: "jpoth", Password: "changeit", - Configuration: map[string]string{ + Configuration: v1.Properties{ "allowInsecureRegistries": "false", }, }, diff --git a/pkg/builder/quarkus.go b/pkg/builder/quarkus.go index f5ad3ef79..91d6bfa33 100644 --- a/pkg/builder/quarkus.go +++ b/pkg/builder/quarkus.go @@ -78,12 +78,9 @@ func loadCamelQuarkusCatalog(ctx *builderContext) error { func generateQuarkusProject(ctx *builderContext) error { p := GenerateQuarkusProjectCommon( - ctx.Build.Runtime.Metadata["camel-quarkus.version"], ctx.Build.Runtime.Version, - ctx.Build.Runtime.Metadata["quarkus.version"]) - - // Add all the properties from the build configuration - p.Properties.AddAll(ctx.Build.Maven.Properties) + ctx.Build.Runtime.Metadata["quarkus.version"], + ctx.Build.Maven.Properties) // Add Maven build extensions p.Build.Extensions = ctx.Build.Maven.Extension @@ -96,23 +93,14 @@ func generateQuarkusProject(ctx *builderContext) error { return nil } -func GenerateQuarkusProjectCommon(camelQuarkusVersion string, runtimeVersion string, quarkusVersion string) maven.Project { +func GenerateQuarkusProjectCommon(runtimeVersion string, quarkusVersion string, buildTimeProperties map[string]string) maven.Project { p := maven.NewProjectWithGAV("org.apache.camel.k.integration", "camel-k-integration", defaults.Version) p.DependencyManagement = &maven.DependencyManagement{Dependencies: make([]maven.Dependency, 0)} p.Dependencies = make([]maven.Dependency, 0) p.Build = &maven.Build{Plugins: make([]maven.Plugin, 0)} - // camel-quarkus does route discovery at startup, but we don't want - // this to happen as routes are loaded at runtime and looking for - // routes at build time may try to load camel-k-runtime routes builder - // proxies which in some case may fail. - p.Properties["quarkus.camel.routes-discovery.enabled"] = "false" - - // disable quarkus banner - p.Properties["quarkus.banner.enabled"] = "false" - // set fast-jar packaging by default, since it gives some startup time improvements - p.Properties["quarkus.package.type"] = "fast-jar" + p.Properties.Add("quarkus.package.type", "fast-jar") // DependencyManagement p.DependencyManagement.Dependencies = append(p.DependencyManagement.Dependencies, @@ -125,6 +113,34 @@ func GenerateQuarkusProjectCommon(camelQuarkusVersion string, runtimeVersion str }, ) + // Add all the properties from the build configuration + p.Properties.AddAll(buildTimeProperties) + + // Quarkus build time properties + buildProperties := make(map[string]string) + + // disable quarkus banner + buildProperties["quarkus.banner.enabled"] = "false" + + // camel-quarkus does route discovery at startup, but we don't want + // this to happen as routes are loaded at runtime and looking for + // routes at build time may try to load camel-k-runtime routes builder + // proxies which in some case may fail. + buildProperties["quarkus.camel.routes-discovery.enabled"] = "false" + + // required for Kamelets utils to resolve data type converters at runtime + buildProperties["quarkus.camel.service.discovery.include-patterns"] = "META-INF/services/org/apache/camel/datatype/converter/*" + + // copy all user defined quarkus.camel build time properties to the quarkus-maven-plugin build properties + for key, value := range buildTimeProperties { + if strings.HasPrefix(key, "quarkus.camel.") { + buildProperties[key] = value + } + } + + configuration := v1.PluginProperties{} + configuration.AddProperties("properties", buildProperties) + // Plugins p.Build.Plugins = append(p.Build.Plugins, maven.Plugin{ @@ -133,9 +149,11 @@ func GenerateQuarkusProjectCommon(camelQuarkusVersion string, runtimeVersion str Version: quarkusVersion, Executions: []maven.Execution{ { + ID: "build-integration", Goals: []string{ "build", }, + Configuration: configuration, }, }, }, diff --git a/pkg/cmd/local/local.go b/pkg/cmd/local/local.go index 0032e0eee..b1513a855 100644 --- a/pkg/cmd/local/local.go +++ b/pkg/cmd/local/local.go @@ -118,9 +118,9 @@ func getTopLevelDependencies(ctx context.Context, catalog *camel.RuntimeCatalog, func getTransitiveDependencies(ctx context.Context, catalog *camel.RuntimeCatalog, dependencies []string, repositories []string) ([]string, error) { project := builder.GenerateQuarkusProjectCommon( - catalog.GetCamelQuarkusVersion(), defaults.DefaultRuntimeVersion, catalog.GetQuarkusVersion(), + make(map[string]string), ) if err := camel.ManageIntegrationDependencies(&project, dependencies, catalog); err != nil { diff --git a/pkg/util/camel/camel_dependencies.go b/pkg/util/camel/camel_dependencies.go index 7ef91d326..a3b65b003 100644 --- a/pkg/util/camel/camel_dependencies.go +++ b/pkg/util/camel/camel_dependencies.go @@ -213,20 +213,22 @@ func addRegistryMavenDependency(project *maven.Project, dependency string) error if isClasspath { outputDirectory = "src/main/resources" } + + properties := v1.PluginProperties{} + properties.Add("outputDirectory", filepath.Join(outputDirectory, filepath.Dir(outputFileRelativePath))) + properties.Add("outputFileName", filepath.Base(outputFileRelativePath)) + properties.Add("groupId", gav.GroupID) + properties.Add("artifactId", gav.ArtifactID) + properties.Add("version", gav.Version) + properties.Add("type", gav.Type) + exec := maven.Execution{ ID: fmt.Sprint(len(plugin.Executions)), Phase: "validate", Goals: []string{ "artifact", }, - Configuration: map[string]string{ - "outputDirectory": filepath.Join(outputDirectory, filepath.Dir(outputFileRelativePath)), - "outputFileName": filepath.Base(outputFileRelativePath), - "groupId": gav.GroupID, - "artifactId": gav.ArtifactID, - "version": gav.Version, - "type": gav.Type, - }, + Configuration: properties, } plugin.Executions = append(plugin.Executions, exec) diff --git a/pkg/util/defaults/defaults.go b/pkg/util/defaults/defaults.go index 3297388a4..f2a39043d 100644 --- a/pkg/util/defaults/defaults.go +++ b/pkg/util/defaults/defaults.go @@ -47,5 +47,5 @@ const ( installDefaultKamelets = true ) -//GitCommit must be provided during application build +// GitCommit must be provided during application build var GitCommit string diff --git a/pkg/util/maven/maven_project.go b/pkg/util/maven/maven_project.go index f73eb0d01..9bb125d19 100644 --- a/pkg/util/maven/maven_project.go +++ b/pkg/util/maven/maven_project.go @@ -40,8 +40,9 @@ func NewProjectWithGAV(group string, artifact string, version string) Project { p.GroupID = group p.ArtifactID = artifact p.Version = version - p.Properties = make(map[string]string) - p.Properties["project.build.sourceEncoding"] = "UTF-8" + p.Properties = v1.Properties{ + "project.build.sourceEncoding": "UTF-8", + } return p } @@ -167,7 +168,7 @@ func NewDependency(groupID string, artifactID string, version string) Dependency // The repository can be customized by appending @param to the repository // URL, e.g.: // -// http://my-nexus:8081/repository/publicc@id=my-repo@snapshots +// http://my-nexus:8081/repository/publicc@id=my-repo@snapshots // // That enables snapshots and sets the repository id to `my-repo`. func NewRepository(repo string) v1.Repository { diff --git a/pkg/util/maven/maven_types.go b/pkg/util/maven/maven_types.go index b033a66b4..df8ed5d0a 100644 --- a/pkg/util/maven/maven_types.go +++ b/pkg/util/maven/maven_types.go @@ -45,10 +45,10 @@ type Plugin struct { } type Execution struct { - ID string `xml:"id,omitempty"` - Phase string `xml:"phase,omitempty"` - Goals []string `xml:"goals>goal,omitempty"` - Configuration v1.Properties `xml:"configuration,omitempty"` + ID string `xml:"id,omitempty"` + Phase string `xml:"phase,omitempty"` + Goals []string `xml:"goals>goal,omitempty"` + Configuration v1.PluginProperties `xml:"configuration,omitempty"` } // Settings models a Maven settings.
