You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@camel.apache.org by GitBox <gi...@apache.org> on 2018/09/12 10:52:14 UTC

[GitHub] nicolaferraro closed pull request #53: kamel run should support adding dependencies

nicolaferraro closed pull request #53: kamel run should support adding dependencies
URL: https://github.com/apache/camel-k/pull/53
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/README.md b/README.md
index 228ef59..b7d7f4c 100644
--- a/README.md
+++ b/README.md
@@ -187,9 +187,16 @@ If you want to install everything you have in your source code and see it runnin
 Now you can play with Camel K:
 
 ```
-./kamel run Sample.java
+./kamel run runtime/examples/Sample.java
 ```
 
+To add additional dependencies to your routes: 
+
+```
+./kamel run -d camel:dns runtime/examples/dns.js
+```
+
+
 ### Debugging and Running from IDE
 
 Sometimes it's useful to debug the code from the IDE when troubleshooting.
diff --git a/build/Makefile b/build/Makefile
index 4ff3d6e..74716be 100644
--- a/build/Makefile
+++ b/build/Makefile
@@ -17,6 +17,9 @@ build-runtime:
 dep:
 	dep ensure -v
 
+generate:
+	operator-sdk generate k8s
+
 clean:
 	mvn clean -f ./runtime/pom.xml
 	go clean
@@ -58,4 +61,4 @@ require-kubeconfig:
 	@echo "KUBERNETES_CONFIG set"
 endif
 
-.PHONY: build build-operator build-kamel build-embed-resources build-runtime dep codegen images images-build images-push test check test-integration check-integration clean 
\ No newline at end of file
+.PHONY: build build-operator build-kamel build-embed-resources build-runtime dep codegen images images-build images-push test check test-integration check-integration clean 
diff --git a/pkg/apis/camel/v1alpha1/types.go b/pkg/apis/camel/v1alpha1/types.go
index 324d056..c40b6b1 100644
--- a/pkg/apis/camel/v1alpha1/types.go
+++ b/pkg/apis/camel/v1alpha1/types.go
@@ -39,15 +39,16 @@ type Integration struct {
 }
 
 type IntegrationSpec struct {
-	Replicas *int32     `json:"replicas,omitempty"`
-	Source   SourceSpec `json:"source,omitempty"`
-	Context  string     `json:"context,omitempty"`
+	Replicas     *int32     `json:"replicas,omitempty"`
+	Source       SourceSpec `json:"source,omitempty"`
+	Context      string     `json:"context,omitempty"`
+	Dependencies []string   `json:"dependencies,omitempty"`
 }
 
 type SourceSpec struct {
-	Name     *string `json:"name,omitempty"`
-	Content  *string `json:"content,omitempty"`
-	Language *string `json:"language,omitempty"`
+	Name     string `json:"name,omitempty"`
+	Content  string `json:"content,omitempty"`
+	Language string `json:"language,omitempty"`
 }
 
 type IntegrationStatus struct {
diff --git a/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
index 2e4d8d2..826918a 100644
--- a/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
@@ -218,7 +218,12 @@ func (in *IntegrationSpec) DeepCopyInto(out *IntegrationSpec) {
 		*out = new(int32)
 		**out = **in
 	}
-	in.Source.DeepCopyInto(&out.Source)
+	out.Source = in.Source
+	if in.Dependencies != nil {
+		in, out := &in.Dependencies, &out.Dependencies
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
 	return
 }
 
@@ -267,21 +272,6 @@ func (in *PropertySpec) DeepCopy() *PropertySpec {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *SourceSpec) DeepCopyInto(out *SourceSpec) {
 	*out = *in
-	if in.Name != nil {
-		in, out := &in.Name, &out.Name
-		*out = new(string)
-		**out = **in
-	}
-	if in.Content != nil {
-		in, out := &in.Content, &out.Content
-		*out = new(string)
-		**out = **in
-	}
-	if in.Language != nil {
-		in, out := &in.Language, &out.Language
-		*out = new(string)
-		**out = **in
-	}
 	return
 }
 
diff --git a/pkg/build/api/types.go b/pkg/build/api/types.go
index 5fc1395..5eba444 100644
--- a/pkg/build/api/types.go
+++ b/pkg/build/api/types.go
@@ -19,8 +19,9 @@ package api
 
 // a request to build a specific code
 type BuildSource struct {
-	Identifier BuildIdentifier
-	Code       Code
+	Identifier   BuildIdentifier
+	Code         Code
+	Dependencies []string
 }
 
 type BuildIdentifier struct {
diff --git a/pkg/build/local/local_builder.go b/pkg/build/local/local_builder.go
index f1ed76a..df96879 100644
--- a/pkg/build/local/local_builder.go
+++ b/pkg/build/local/local_builder.go
@@ -20,7 +20,9 @@ package local
 import (
 	"context"
 	"encoding/xml"
+	"fmt"
 	"io/ioutil"
+	"strings"
 	"time"
 
 	buildv1 "github.com/openshift/api/build/v1"
@@ -106,41 +108,15 @@ func (b *localBuilder) buildCycle(ctx context.Context) {
 }
 
 func (b *localBuilder) execute(source build.BuildSource) (string, error) {
-
-	project := maven.ProjectDefinition{
-		Project: maven.Project{
-			XMLName:           xml.Name{Local: "project"},
-			XmlNs:             "http://maven.apache.org/POM/4.0.0",
-			XmlNsXsi:          "http://www.w3.org/2001/XMLSchema-instance",
-			XsiSchemaLocation: "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd",
-			ModelVersion:      "4.0.0",
-			GroupId:           "org.apache.camel.k.integration",
-			ArtifactId:        "camel-k-integration",
-			Version:           "1.0.0",
-			Dependencies: maven.Dependencies{
-				Dependencies: []maven.Dependency{
-					{
-						GroupId:    "org.apache.camel.k",
-						ArtifactId: "camel-k-runtime-jvm",
-						Version:    version.Version,
-					},
-				},
-			},
-		},
-		Resources: map[string]string{
-			source.Code.Name: source.Code.Content,
-		},
-		Env: map[string]string{
-			"JAVA_MAIN_CLASS":         "org.apache.camel.k.jvm.Application",
-			"CAMEL_K_ROUTES_URI":      "classpath:" + source.Code.Name,
-			"CAMEL_K_ROUTES_LANGUAGE": source.Code.Language,
-		},
+	project, err := generateProjectDefinition(source)
+	if err != nil {
+		return "", err
 	}
-
 	tarFileName, err := maven.Build(project)
 	if err != nil {
 		return "", err
 	}
+
 	logrus.Info("Created tar file ", tarFileName)
 
 	image, err := b.publish(tarFileName, source)
@@ -274,3 +250,79 @@ func (b *localBuilder) publish(tarFile string, source build.BuildSource) (string
 	}
 	return is.Status.DockerImageRepository + ":" + source.Identifier.Digest, nil
 }
+
+func generateProjectDefinition(source build.BuildSource) (maven.ProjectDefinition, error) {
+	project := maven.ProjectDefinition{
+		Project: maven.Project{
+			XMLName:           xml.Name{Local: "project"},
+			XmlNs:             "http://maven.apache.org/POM/4.0.0",
+			XmlNsXsi:          "http://www.w3.org/2001/XMLSchema-instance",
+			XsiSchemaLocation: "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd",
+			ModelVersion:      "4.0.0",
+			GroupId:           "org.apache.camel.k.integration",
+			ArtifactId:        "camel-k-integration",
+			Version:           version.Version,
+			DependencyManagement: maven.DependencyManagement{
+				Dependencies: maven.Dependencies{
+					Dependencies: []maven.Dependency{
+						{
+							//TODO: camel version should be retrieved from an external source or provided as static version
+							GroupId:    "org.apache.camel",
+							ArtifactId: "camel-bom",
+							Version:    "2.22.1",
+							Type:       "pom",
+							Scope:      "import",
+						},
+					},
+				},
+			},
+			Dependencies: maven.Dependencies{
+				Dependencies: make([]maven.Dependency, 0),
+			},
+		},
+		Resources: map[string]string{
+			source.Code.Name: source.Code.Content,
+		},
+		Env: make(map[string]string),
+	}
+
+	//
+	// set-up dependencies
+	//
+
+	deps := &project.Project.Dependencies
+	deps.AddGAV("org.apache.camel.k", "camel-k-runtime-jvm", version.Version)
+
+	for _, d := range source.Dependencies {
+		if strings.HasPrefix(d, "camel:") {
+			artifactId := strings.TrimPrefix(d, "camel:")
+
+			if !strings.HasPrefix(artifactId, "camel-") {
+				artifactId = "camel-" + artifactId
+			}
+
+			deps.AddGAV("org.apache.camel", artifactId, "")
+		} else if strings.HasPrefix(d, "mvn:") {
+			mid := strings.TrimPrefix(d, "mvn:")
+			gav := strings.Replace(mid, "/", ":", -1)
+
+			deps.AddEncodedGAV(gav)
+		} else {
+			return maven.ProjectDefinition{}, fmt.Errorf("unknown dependency type: %s", d)
+		}
+	}
+
+	//
+	// set-up env
+	//
+
+	project.Env["JAVA_MAIN_CLASS"] = "org.apache.camel.k.jvm.Application"
+	project.Env["CAMEL_K_ROUTES_URI"] = "classpath:" + source.Code.Name
+
+	// Don't set the language if not set
+	if source.Code.Language != "" {
+		project.Env["CAMEL_K_ROUTES_LANGUAGE"] = source.Code.Language
+	}
+
+	return project, nil
+}
diff --git a/pkg/build/local/local_builder_test.go b/pkg/build/local/local_builder_test.go
new file mode 100644
index 0000000..49decab
--- /dev/null
+++ b/pkg/build/local/local_builder_test.go
@@ -0,0 +1,80 @@
+/*
+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 local
+
+import (
+	"testing"
+
+	"github.com/apache/camel-k/pkg/build/api"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestProjectGeneration(t *testing.T) {
+	source := api.BuildSource{
+		Identifier: api.BuildIdentifier{
+			Name:   "my-integration",
+			Digest: "",
+		},
+		Code: api.Code{
+			Name:     "my-code.js",
+			Content:  `from("timer:start").to("log:end")`,
+			Language: "",
+		},
+		Dependencies: []string{
+			"camel:mail",
+			"camel:camel-netty4",
+			"mvn:org.apache.camel/camel-servicenow/2.21.1",
+			"mvn:org.apache.camel/camel-salesforce",
+		},
+	}
+
+	prj, err := generateProjectDefinition(source)
+	assert.Nil(t, err)
+	assert.NotNil(t, prj)
+	assert.Equal(t, len(prj.Project.Dependencies.Dependencies), 5)
+	assert.Equal(t, prj.Project.Dependencies.Dependencies[0].ArtifactId, "camel-k-runtime-jvm")
+	assert.Equal(t, prj.Project.Dependencies.Dependencies[1].ArtifactId, "camel-mail")
+	assert.Equal(t, prj.Project.Dependencies.Dependencies[2].ArtifactId, "camel-netty4")
+	assert.Equal(t, prj.Project.Dependencies.Dependencies[3].ArtifactId, "camel-servicenow")
+	assert.Equal(t, prj.Project.Dependencies.Dependencies[3].Version, "2.21.1")
+	assert.Equal(t, prj.Project.Dependencies.Dependencies[4].ArtifactId, "camel-salesforce")
+	assert.Equal(t, prj.Project.Dependencies.Dependencies[4].Version, "")
+}
+
+func TestProjectGenerationWithFailure(t *testing.T) {
+	source := api.BuildSource{
+		Identifier: api.BuildIdentifier{
+			Name:   "my-integration",
+			Digest: "",
+		},
+		Code: api.Code{
+			Name:     "my-code.js",
+			Content:  `from("timer:start").to("log:end")`,
+			Language: "",
+		},
+		Dependencies: []string{
+			"other:mail",
+			"camel:camel-netty4",
+			"mvn:org.apache.camel/camel-servicenow/2.21.1",
+			"mvn:org.apache.camel/camel-salesforce",
+		},
+	}
+
+	_, err := generateProjectDefinition(source)
+	assert.NotNil(t, err)
+}
diff --git a/pkg/client/cmd/run.go b/pkg/client/cmd/run.go
index aacb05c..d64a653 100644
--- a/pkg/client/cmd/run.go
+++ b/pkg/client/cmd/run.go
@@ -37,12 +37,14 @@ type RunCmdOptions struct {
 	*RootCmdOptions
 	Language        string
 	IntegrationName string
+	Dependencies    []string
 }
 
 func NewCmdRun(rootCmdOptions *RootCmdOptions) *cobra.Command {
 	options := RunCmdOptions{
 		RootCmdOptions: rootCmdOptions,
 	}
+
 	cmd := cobra.Command{
 		Use:   "run [file to run]",
 		Short: "Run a integration on Kubernetes",
@@ -53,7 +55,7 @@ func NewCmdRun(rootCmdOptions *RootCmdOptions) *cobra.Command {
 
 	cmd.Flags().StringVarP(&options.Language, "language", "l", "", "Programming Language used to write the file")
 	cmd.Flags().StringVarP(&options.IntegrationName, "name", "", "", "The integration name")
-	cmd.ParseFlags(os.Args)
+	cmd.Flags().StringSliceVarP(&options.Dependencies, "dependency", "d", nil, "The integration dependency")
 
 	return &cmd
 }
@@ -107,10 +109,11 @@ func (o *RunCmdOptions) run(cmd *cobra.Command, args []string) error {
 		},
 		Spec: v1alpha1.IntegrationSpec{
 			Source: v1alpha1.SourceSpec{
-				Name:     &codeName,
-				Content:  &code,
-				Language: &o.Language,
+				Name:     codeName,
+				Content:  code,
+				Language: o.Language,
 			},
+			Dependencies: o.Dependencies,
 		},
 	}
 
diff --git a/pkg/stub/action/integration/build.go b/pkg/stub/action/integration/build.go
index 22f006a..373583a 100644
--- a/pkg/stub/action/integration/build.go
+++ b/pkg/stub/action/integration/build.go
@@ -55,10 +55,11 @@ func (b *BuildAction) Handle(integration *v1alpha1.Integration) error {
 		b.buildManager.Start(api.BuildSource{
 			Identifier: buildIdentifier,
 			Code: api.Code{
-				Name:     *integration.Spec.Source.Name,
-				Content:  *integration.Spec.Source.Content,
-				Language: *integration.Spec.Source.Language,
-			}, // FIXME possible panic
+				Name:     integration.Spec.Source.Name,
+				Content:  integration.Spec.Source.Content,
+				Language: integration.Spec.Source.Language,
+			},
+			Dependencies: integration.Spec.Dependencies,
 		})
 		logrus.Info("Build started")
 	} else if buildResult.Status == api.BuildStatusError {
diff --git a/pkg/util/digest/digest.go b/pkg/util/digest/digest.go
index 09bec1c..6f84744 100644
--- a/pkg/util/digest/digest.go
+++ b/pkg/util/digest/digest.go
@@ -34,8 +34,8 @@ func Compute(integration *v1alpha1.Integration) string {
 	// Operator version is relevant
 	hash.Write([]byte(version.Version))
 	// Integration relevant fields
-	if integration.Spec.Source.Content != nil {
-		hash.Write([]byte(*integration.Spec.Source.Content))
+	if integration.Spec.Source.Content != "" {
+		hash.Write([]byte(integration.Spec.Source.Content))
 	}
 	// Add a letter at the beginning and use URL safe encoding
 	return "v" + base64.RawURLEncoding.EncodeToString(hash.Sum(nil))
diff --git a/pkg/util/maven/maven.go b/pkg/util/maven/maven.go
index f474f58..6a0362e 100644
--- a/pkg/util/maven/maven.go
+++ b/pkg/util/maven/maven.go
@@ -168,7 +168,7 @@ func appendToTar(filePath string, tarPath string, writer *tar.Writer) error {
 }
 
 func createMavenStructure(buildDir string, project ProjectDefinition) error {
-	pom, err := pomFileContent(project.Project)
+	pom, err := GeneratePomFileContent(project.Project)
 	if err != nil {
 		return err
 	}
@@ -234,7 +234,7 @@ func envFileContent(env map[string]string) string {
 	return content
 }
 
-func pomFileContent(project Project) (string, error) {
+func GeneratePomFileContent(project Project) (string, error) {
 	w := &bytes.Buffer{}
 	w.WriteString(xml.Header)
 
diff --git a/pkg/util/maven/mavent_test.go b/pkg/util/maven/mavent_test.go
index 3092e4a..a22ab3f 100644
--- a/pkg/util/maven/mavent_test.go
+++ b/pkg/util/maven/mavent_test.go
@@ -30,6 +30,17 @@ const expectedPom = `<?xml version="1.0" encoding="UTF-8"?>
   <groupId>org.apache.camel.k.integration</groupId>
   <artifactId>camel-k-integration</artifactId>
   <version>1.0.0</version>
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-bom</artifactId>
+        <version>2.22.1</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
   <dependencies>
     <dependency>
       <groupId>org.apache.camel.k</groupId>
@@ -49,6 +60,19 @@ func TestPomGeneration(t *testing.T) {
 		GroupId:           "org.apache.camel.k.integration",
 		ArtifactId:        "camel-k-integration",
 		Version:           "1.0.0",
+		DependencyManagement: DependencyManagement{
+			Dependencies: Dependencies{
+				Dependencies: []Dependency{
+					{
+						GroupId:    "org.apache.camel",
+						ArtifactId: "camel-bom",
+						Version:    "2.22.1",
+						Type:       "pom",
+						Scope:      "import",
+					},
+				},
+			},
+		},
 		Dependencies: Dependencies{
 			Dependencies: []Dependency{
 				{
diff --git a/pkg/util/maven/types.go b/pkg/util/maven/types.go
index 1ebebe0..30a80de 100644
--- a/pkg/util/maven/types.go
+++ b/pkg/util/maven/types.go
@@ -29,27 +29,48 @@ type ProjectDefinition struct {
 }
 
 type Project struct {
-	XMLName           xml.Name
-	XmlNs             string       `xml:"xmlns,attr"`
-	XmlNsXsi          string       `xml:"xmlns:xsi,attr"`
-	XsiSchemaLocation string       `xml:"xsi:schemaLocation,attr"`
-	ModelVersion      string       `xml:"modelVersion"`
-	GroupId           string       `xml:"groupId"`
-	ArtifactId        string       `xml:"artifactId"`
-	Version           string       `xml:"version"`
-	Dependencies      Dependencies `xml:"dependencies"`
+	XMLName              xml.Name
+	XmlNs                string               `xml:"xmlns,attr"`
+	XmlNsXsi             string               `xml:"xmlns:xsi,attr"`
+	XsiSchemaLocation    string               `xml:"xsi:schemaLocation,attr"`
+	ModelVersion         string               `xml:"modelVersion"`
+	GroupId              string               `xml:"groupId"`
+	ArtifactId           string               `xml:"artifactId"`
+	Version              string               `xml:"version"`
+	DependencyManagement DependencyManagement `xml:"dependencyManagement"`
+	Dependencies         Dependencies         `xml:"dependencies"`
+}
+
+type DependencyManagement struct {
+	Dependencies Dependencies `xml:"dependencies"`
 }
 
 type Dependencies struct {
 	Dependencies []Dependency `xml:"dependency"`
 }
 
+func (deps *Dependencies) Add(dep Dependency) {
+	deps.Dependencies = append(deps.Dependencies, dep)
+}
+
+func (deps *Dependencies) AddGAV(groupId string, artifactId string, version string) {
+	deps.Add(NewDependency(groupId, artifactId, version))
+}
+
+func (deps *Dependencies) AddEncodedGAV(gav string) {
+	if d, err := ParseGAV(gav); err == nil {
+		// TODO: error handling
+		deps.Add(d)
+	}
+}
+
 type Dependency struct {
 	GroupId    string `xml:"groupId"`
 	ArtifactId string `xml:"artifactId"`
 	Version    string `xml:"version,omitempty"`
 	Type       string `xml:"type,omitempty"`
 	Classifier string `xml:"classifier,omitempty"`
+	Scope      string `xml:"scope,omitempty"`
 }
 
 func NewDependency(groupId string, artifactId string, version string) Dependency {
diff --git a/runtime/examples/dns.js b/runtime/examples/dns.js
new file mode 100644
index 0000000..337682d
--- /dev/null
+++ b/runtime/examples/dns.js
@@ -0,0 +1,12 @@
+//
+// To run this integrations use:
+//
+//     kamel run -d camel:dns runtime/examples/dns.js
+//
+
+from('timer:dns?period=1s')
+    .routeId('dns')
+    .setHeader('dns.domain')
+        .constant('www.google.com')
+    .to('dns:ip')
+    .to('log:dns')
\ No newline at end of file


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services