Skip to content

Commit

Permalink
feat(cli/run): Support dependencies defined using HTTP URLs
Browse files Browse the repository at this point in the history
  • Loading branch information
essobedo committed Sep 14, 2022
1 parent 6e6aff2 commit db5202d
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 5 deletions.
23 changes: 18 additions & 5 deletions pkg/cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ import (
"github.com/apache/camel-k/pkg/util/watch"
)

const usageDependency = `A dependency that should be included, e.g., "-d camel:mail" for a Camel component, "-d mvn:org.my:app:1.0" for a Maven dependency or "file://localPath[?targetPath=<path>&registry=<registry_URL>&skipChecksums=<true>&skipPOM=<true>]" for local files (experimental)`
const usageDependency = `A dependency that should be included, e.g., "-d camel:mail" for a Camel component, "-d mvn:org.my:app:1.0" for a Maven dependency, "-d http|https://my-repo/my-dependency.jar" for custom dependencies located on an http server or "file://localPath[?targetPath=<path>&registry=<registry_URL>&skipChecksums=<true>&skipPOM=<true>]" for local files (experimental)`

func newCmdRun(rootCmdOptions *RootCmdOptions) (*cobra.Command, *runCmdOptions) {
options := runCmdOptions{
Expand Down Expand Up @@ -799,7 +799,7 @@ func (o *runCmdOptions) applyDependencies(cmd *cobra.Command, c client.Client, i
var platform *v1.IntegrationPlatform
for _, item := range o.Dependencies {
// TODO: accept URLs
if strings.HasPrefix(item, "file://") {
if strings.HasPrefix(item, "file://") || strings.HasPrefix(item, "http://") || strings.HasPrefix(item, "https://") {
if platform == nil {
var err error
platform, err = o.getPlatform(cmd, c, it)
Expand Down Expand Up @@ -967,9 +967,22 @@ func (o *runCmdOptions) getTargetPath() string {
}

func (o *runCmdOptions) uploadFileOrDirectory(platform *v1.IntegrationPlatform, item string, integrationName string, cmd *cobra.Command, integration *v1.Integration) error {
uri := parseFileURI(item)
o.RegistryOptions = uri.Query()
localPath, targetPath := uri.Path, o.getTargetPath()
var targetPath, localPath string
if strings.HasPrefix(item, "http://") || strings.HasPrefix(item, "https://") {
uri, err := url.Parse(item)
if err != nil {
return err
} else if localPath, err = downloadDependency(o.Context, *uri); err != nil {
return err
}
// Remove the temporary file
defer os.Remove(localPath)
} else {
uri := parseFileURI(item)
o.RegistryOptions = uri.Query()
localPath, targetPath = uri.Path, o.getTargetPath()

}
options := o.getSpectrumOptions(platform, cmd)
dirName, err := getDirName(localPath)
if err != nil {
Expand Down
35 changes: 35 additions & 0 deletions pkg/cmd/run_help.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ package cmd
import (
"context"
"fmt"
"io"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
"reflect"
"strings"

Expand Down Expand Up @@ -161,3 +166,33 @@ func fromMapToProperties(data interface{}, toString func(reflect.Value) string,
}
return result, nil
}

// downloadDependency downloads the file located at the given URL into a temporary folder and returns the local path to the generated temporary file.
func downloadDependency(ctx context.Context, url url.URL) (string, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url.String(), nil)
if err != nil {
return "", err
}
res, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
defer res.Body.Close()
base := path.Base(url.Path)
if base == "." || base == "/" || filepath.Ext(base) == "" {
base = path.Base(url.String())
if base == "." || base == "/" {
base = "tmp"
}
}
out, err := os.CreateTemp("", fmt.Sprintf("*.%s", base))
if err != nil {
return "", err
}
defer out.Close()
_, err = io.Copy(out, res.Body)
if err != nil {
return "", err
}
return out.Name(), nil
}
39 changes: 39 additions & 0 deletions pkg/cmd/run_help_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ limitations under the License.
package cmd

import (
"context"
"net/url"
"os"
"strings"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -39,3 +43,38 @@ func TestFilterFileLocation(t *testing.T) {
assert.Equal(t, "app.properties", filteredOptions[1])
assert.Equal(t, "/validfile", filteredOptions[2])
}

func TestDownloadDependencyWithBadURL(t *testing.T) {
u, _ := url.Parse("http://foo")
_, err := downloadDependency(context.Background(), *u)
assert.NotNil(t, err)
}

func TestDownloadDependencyWithFileNameInURL(t *testing.T) {
u, _ := url.Parse("https://repo1.maven.org/maven2/org/apache/camel/camel-core/3.18.2/camel-core-3.18.2.jar")
path, err := downloadDependency(context.Background(), *u)
t.Cleanup(func() { os.Remove(path) })
assert.Nil(t, err)
assert.True(t, strings.HasSuffix(path, "camel-core-3.18.2.jar"), "The name of the jar file is expected")
_, err = os.Stat(path)
assert.Nil(t, err)
}

func TestDownloadDependencyWithFileNameInQuery(t *testing.T) {
u, _ := url.Parse("https://search.maven.org/remotecontent?filepath=org/apache/camel/quarkus/camel-quarkus-file/2.12.0/camel-quarkus-file-2.12.0.jar")
path, err := downloadDependency(context.Background(), *u)
t.Cleanup(func() { os.Remove(path) })
assert.Nil(t, err)
assert.True(t, strings.HasSuffix(path, "camel-quarkus-file-2.12.0.jar"), "The name of the jar file is expected")
_, err = os.Stat(path)
assert.Nil(t, err)
}

func TestDownloadDependencyWithoutFileName(t *testing.T) {
u, _ := url.Parse("https://search.maven.org")
path, err := downloadDependency(context.Background(), *u)
t.Cleanup(func() { os.Remove(path) })
assert.Nil(t, err)
_, err = os.Stat(path)
assert.Nil(t, err)
}

0 comments on commit db5202d

Please sign in to comment.