This is an automated email from the ASF dual-hosted git repository.

nferraro pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit 552e6a8cddd5e4d2a293e6333c0171fbf4f881b0
Author: Doru Bercea <gheorghe-teod.ber...@ibm.com>
AuthorDate: Thu Oct 8 18:41:04 2020 -0400

    Support computing and outputting of transitive dependencies.
---
 pkg/builder/builder_steps.go |  47 +++++++-----
 pkg/builder/runtime/main.go  |  65 ++++++++++++----
 pkg/cmd/inspect.go           | 175 ++++++++++++++++++++++++++++++++++++++++---
 pkg/util/camel/catalog.go    |   6 +-
 pkg/util/util.go             |  18 +++++
 5 files changed, 265 insertions(+), 46 deletions(-)

diff --git a/pkg/builder/builder_steps.go b/pkg/builder/builder_steps.go
index a1ce547..0c29790 100644
--- a/pkg/builder/builder_steps.go
+++ b/pkg/builder/builder_steps.go
@@ -25,6 +25,7 @@ import (
        "reflect"
        "strings"
 
+       "github.com/apache/camel-k/pkg/util/camel"
        "github.com/apache/camel-k/pkg/util/jitpack"
 
        "github.com/rs/xid"
@@ -140,7 +141,17 @@ func generateProjectSettings(ctx *Context) error {
 
 func injectDependencies(ctx *Context) error {
        // Add dependencies from build
-       for _, d := range ctx.Build.Dependencies {
+       return InjectDependenciesCommon(&ctx.Maven.Project, 
ctx.Build.Dependencies, ctx.Catalog)
+}
+
+// InjectDependenciesCommon --
+func InjectDependenciesCommon(
+       project *maven.Project,
+       dependencies []string,
+       catalog *camel.RuntimeCatalog) error {
+
+       // Add dependencies from build
+       for _, d := range dependencies {
                switch {
                case strings.HasPrefix(d, "bom:"):
                        mid := strings.TrimPrefix(d, "bom:")
@@ -151,7 +162,7 @@ func injectDependencies(ctx *Context) error {
                                return err
                        }
 
-                       ctx.Maven.Project.DependencyManagement.Dependencies = 
append(ctx.Maven.Project.DependencyManagement.Dependencies, maven.Dependency{
+                       project.DependencyManagement.Dependencies = 
append(project.DependencyManagement.Dependencies, maven.Dependency{
                                GroupID:    d.GroupID,
                                ArtifactID: d.ArtifactID,
                                Version:    d.Version,
@@ -165,7 +176,7 @@ func injectDependencies(ctx *Context) error {
                                artifactID = "camel-" + artifactID
                        }
 
-                       ctx.Maven.Project.AddDependencyGAV("org.apache.camel", 
artifactID, "")
+                       project.AddDependencyGAV("org.apache.camel", 
artifactID, "")
                case strings.HasPrefix(d, "camel-k:"):
                        artifactID := strings.TrimPrefix(d, "camel-k:")
 
@@ -173,7 +184,7 @@ func injectDependencies(ctx *Context) error {
                                artifactID = "camel-k-" + artifactID
                        }
 
-                       
ctx.Maven.Project.AddDependencyGAV("org.apache.camel.k", artifactID, "")
+                       project.AddDependencyGAV("org.apache.camel.k", 
artifactID, "")
                case strings.HasPrefix(d, "camel-quarkus:"):
                        artifactID := strings.TrimPrefix(d, "camel-quarkus:")
 
@@ -181,25 +192,25 @@ func injectDependencies(ctx *Context) error {
                                artifactID = "camel-quarkus-" + artifactID
                        }
 
-                       
ctx.Maven.Project.AddDependencyGAV("org.apache.camel.quarkus", artifactID, "")
+                       project.AddDependencyGAV("org.apache.camel.quarkus", 
artifactID, "")
                case strings.HasPrefix(d, "mvn:"):
                        mid := strings.TrimPrefix(d, "mvn:")
                        gav := strings.Replace(mid, "/", ":", -1)
 
-                       ctx.Maven.Project.AddEncodedDependencyGAV(gav)
+                       project.AddEncodedDependencyGAV(gav)
                default:
                        if dep := jitpack.ToDependency(d); dep != nil {
-                               ctx.Maven.Project.AddDependency(*dep)
+                               project.AddDependency(*dep)
 
                                addRepo := true
-                               for _, repo := range 
ctx.Maven.Project.Repositories {
+                               for _, repo := range project.Repositories {
                                        if repo.URL == jitpack.RepoURL {
                                                addRepo = false
                                                break
                                        }
                                }
                                if addRepo {
-                                       ctx.Maven.Project.Repositories = 
append(ctx.Maven.Project.Repositories, maven.Repository{
+                                       project.Repositories = 
append(project.Repositories, maven.Repository{
                                                ID:  "jitpack.io-" + 
xid.New().String(),
                                                URL: jitpack.RepoURL,
                                                Releases: 
maven.RepositoryPolicy{
@@ -219,18 +230,18 @@ func injectDependencies(ctx *Context) error {
        }
 
        // Add dependencies from catalog
-       deps := make([]maven.Dependency, len(ctx.Maven.Project.Dependencies))
-       copy(deps, ctx.Maven.Project.Dependencies)
+       deps := make([]maven.Dependency, len(project.Dependencies))
+       copy(deps, project.Dependencies)
 
        for _, d := range deps {
-               if a, ok := ctx.Catalog.Artifacts[d.ArtifactID]; ok {
+               if a, ok := catalog.Artifacts[d.ArtifactID]; ok {
                        for _, dep := range a.Dependencies {
                                md := maven.Dependency{
                                        GroupID:    dep.GroupID,
                                        ArtifactID: dep.ArtifactID,
                                }
 
-                               ctx.Maven.Project.AddDependency(md)
+                               project.AddDependency(md)
 
                                for _, e := range dep.Exclusions {
                                        me := maven.Exclusion{
@@ -238,18 +249,18 @@ func injectDependencies(ctx *Context) error {
                                                ArtifactID: e.ArtifactID,
                                        }
 
-                                       
ctx.Maven.Project.AddDependencyExclusion(md, me)
+                                       project.AddDependencyExclusion(md, me)
                                }
                        }
                }
        }
 
        // Post process dependencies
-       deps = make([]maven.Dependency, len(ctx.Maven.Project.Dependencies))
-       copy(deps, ctx.Maven.Project.Dependencies)
+       deps = make([]maven.Dependency, len(project.Dependencies))
+       copy(deps, project.Dependencies)
 
        for _, d := range deps {
-               if a, ok := ctx.Catalog.Artifacts[d.ArtifactID]; ok {
+               if a, ok := catalog.Artifacts[d.ArtifactID]; ok {
                        md := maven.Dependency{
                                GroupID:    a.GroupID,
                                ArtifactID: a.ArtifactID,
@@ -261,7 +272,7 @@ func injectDependencies(ctx *Context) error {
                                        ArtifactID: e.ArtifactID,
                                }
 
-                               ctx.Maven.Project.AddDependencyExclusion(md, me)
+                               project.AddDependencyExclusion(md, me)
                        }
                }
        }
diff --git a/pkg/builder/runtime/main.go b/pkg/builder/runtime/main.go
index 991f548..d6f973a 100644
--- a/pkg/builder/runtime/main.go
+++ b/pkg/builder/runtime/main.go
@@ -60,32 +60,39 @@ func loadCamelCatalog(ctx *builder.Context) error {
 }
 
 func generateProject(ctx *builder.Context) error {
-       p := maven.NewProjectWithGAV("org.apache.camel.k.integration", 
"camel-k-integration", defaults.Version)
+       p := GenerateProjectCommon(ctx.Build.Runtime.Metadata["camel.version"], 
ctx.Build.Runtime.Version)
 
        // Add all the properties from the build configuration
        p.Properties.AddAll(ctx.Build.Properties)
 
+       ctx.Maven.Project = p
+
+       return nil
+}
+
+// GenerateProjectCommon --
+func GenerateProjectCommon(camelVersion string, runtimeVersion string) 
maven.Project {
+       p := maven.NewProjectWithGAV("org.apache.camel.k.integration", 
"camel-k-integration", defaults.Version)
+
        p.Dependencies = make([]maven.Dependency, 0)
        p.DependencyManagement = &maven.DependencyManagement{Dependencies: 
make([]maven.Dependency, 0)}
 
        p.DependencyManagement.Dependencies = 
append(p.DependencyManagement.Dependencies, maven.Dependency{
                GroupID:    "org.apache.camel",
                ArtifactID: "camel-bom",
-               Version:    ctx.Build.Runtime.Metadata["camel.version"],
+               Version:    camelVersion,
                Type:       "pom",
                Scope:      "import",
        })
        p.DependencyManagement.Dependencies = 
append(p.DependencyManagement.Dependencies, maven.Dependency{
                GroupID:    "org.apache.camel.k",
                ArtifactID: "camel-k-runtime-bom",
-               Version:    ctx.Build.Runtime.Version,
+               Version:    runtimeVersion,
                Type:       "pom",
                Scope:      "import",
        })
 
-       ctx.Maven.Project = p
-
-       return nil
+       return p
 }
 
 func computeDependencies(ctx *builder.Context) error {
@@ -93,30 +100,56 @@ func computeDependencies(ctx *builder.Context) error {
        mc.SettingsContent = ctx.Maven.SettingsData
        mc.LocalRepository = ctx.Build.Maven.LocalRepository
        mc.Timeout = ctx.Build.Maven.GetTimeout().Duration
-       
mc.AddArgumentf("org.apache.camel.k:camel-k-maven-plugin:%s:generate-dependency-list",
 ctx.Catalog.Runtime.Version)
+
+       // Compute dependencies.
+       content, err := ComputeDependenciesCommon(mc, 
ctx.Catalog.Runtime.Version)
+       if err != nil {
+               return err
+       }
+
+       // Process artifacts list and add it to existing artifacts.
+       artifacts := []v1.Artifact{}
+       artifacts, err = ProcessTransitiveDependencies(content, "dependencies")
+       if err != nil {
+               return err
+       }
+       ctx.Artifacts = append(ctx.Artifacts, artifacts...)
+
+       return nil
+}
+
+// ComputeDependenciesCommon --
+func ComputeDependenciesCommon(mc maven.Context, runtimeVersion string) 
([]byte, error) {
+       
mc.AddArgumentf("org.apache.camel.k:camel-k-maven-plugin:%s:generate-dependency-list",
 runtimeVersion)
 
        if err := maven.Run(mc); err != nil {
-               return errors.Wrap(err, "failure while determining classpath")
+               return nil, errors.Wrap(err, "failure while determining 
classpath")
        }
 
        dependencies := path.Join(mc.Path, "target", "dependencies.yaml")
        content, err := ioutil.ReadFile(dependencies)
        if err != nil {
-               return err
+               return nil, err
        }
 
+       return content, nil
+}
+
+// ProcessTransitiveDependencies --
+func ProcessTransitiveDependencies(content []byte, outputDir string) 
([]v1.Artifact, error) {
        cp := make(map[string][]v1.Artifact)
-       err = yaml2.Unmarshal(content, &cp)
+       err := yaml2.Unmarshal(content, &cp)
        if err != nil {
-               return err
+               return nil, err
        }
 
+       artifacts := []v1.Artifact{}
        for _, e := range cp["dependencies"] {
                _, fileName := path.Split(e.Location)
 
                gav, err := maven.ParseGAV(e.ID)
                if err != nil {
-                       return nil
+                       return nil, err
                }
 
                //
@@ -125,19 +158,19 @@ func computeDependencies(ctx *builder.Context) error {
                if e.Checksum == "" {
                        chksum, err := digest.ComputeSHA1(e.Location)
                        if err != nil {
-                               return err
+                               return nil, err
                        }
 
                        e.Checksum = "sha1:" + chksum
                }
 
-               ctx.Artifacts = append(ctx.Artifacts, v1.Artifact{
+               artifacts = append(artifacts, v1.Artifact{
                        ID:       e.ID,
                        Location: e.Location,
-                       Target:   path.Join("dependencies", 
gav.GroupID+"."+fileName),
+                       Target:   path.Join(outputDir, 
gav.GroupID+"."+fileName),
                        Checksum: e.Checksum,
                })
        }
 
-       return nil
+       return artifacts, nil
 }
diff --git a/pkg/cmd/inspect.go b/pkg/cmd/inspect.go
index f899c95..b10d32a 100644
--- a/pkg/cmd/inspect.go
+++ b/pkg/cmd/inspect.go
@@ -20,9 +20,13 @@ package cmd
 import (
        "errors"
        "fmt"
+       "os"
        "path"
+       "strings"
 
        v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+       "github.com/apache/camel-k/pkg/builder"
+       "github.com/apache/camel-k/pkg/builder/runtime"
        "github.com/apache/camel-k/pkg/trait"
        "github.com/apache/camel-k/pkg/util"
        "github.com/apache/camel-k/pkg/util/camel"
@@ -32,6 +36,14 @@ import (
        "github.com/spf13/cobra"
 )
 
+var acceptedDependencyTypes = []string{"bom", "camel", "camel-k", 
"camel-quarkus", "mvn", "github"}
+
+const (
+       defaultRuntimeVersion         = "1.3.0"
+       defaultCamelVersion           = "3.3.0"
+       defaultWorkspaceDirectoryName = "workspace"
+)
+
 func newCmdInspect(rootCmdOptions *RootCmdOptions) (*cobra.Command, 
*inspectCmdOptions) {
        options := inspectCmdOptions{
                RootCmdOptions: rootCmdOptions,
@@ -40,7 +52,7 @@ func newCmdInspect(rootCmdOptions *RootCmdOptions) 
(*cobra.Command, *inspectCmdO
        cmd := cobra.Command{
                Use:     "inspect [files to inspect]",
                Short:   "Generate dependencies list the given integration 
files.",
-               Long:    `Compute and emit the dependencies for a list of 
integration files.`,
+               Long:    "Output dependencies for a list of integration files. 
By default this command returns the top level dependencies only.",
                PreRunE: decode(&options),
                RunE: func(_ *cobra.Command, args []string) error {
                        if err := options.validate(args); err != nil {
@@ -57,14 +69,24 @@ func newCmdInspect(rootCmdOptions *RootCmdOptions) 
(*cobra.Command, *inspectCmdO
                },
        }
 
+       cmd.Flags().Bool("all-dependencies", false, "Compute and output 
transitive dependencies.")
+       cmd.Flags().String("additional-dependencies", "", `Comma-separated list 
of additional top-level dependencies with the format:
+               <type>:<dependency-name>
+                       where <type> is one of 
{`+strings.Join(acceptedDependencyTypes, "|")+`}.`)
+       cmd.Flags().String("workspace", "", "Absolute path to workspace 
directory. Default: <kamel-invocation-directory>/workspace")
        cmd.Flags().StringP("output", "o", "", "Output format. One of: 
json|yaml")
+       cmd.Flags().String("dependencies-directory", "", "Absolute path to 
directory containing all dependencies. Default: 
<kamel-invocation-directory>/workspace/dependencies")
 
        return &cmd, &options
 }
 
 type inspectCmdOptions struct {
        *RootCmdOptions
-       OutputFormat string `mapstructure:"output"`
+       AllDependencies        bool   `mapstructure:"all-dependencies"`
+       OutputFormat           string `mapstructure:"output"`
+       AdditionalDependencies string `mapstructure:"additional-dependencies"`
+       Workspace              string `mapstructure:"workspace"`
+       DependenciesDirectory  string `mapstructure:"dependencies-directory"`
 }
 
 func (command *inspectCmdOptions) validate(args []string) error {
@@ -89,6 +111,41 @@ func (command *inspectCmdOptions) validate(args []string) 
error {
                }
        }
 
+       // Validate list of additional dependencies i.e. make sure that each 
dependency has
+       // a valid type.
+       if command.AdditionalDependencies != "" {
+               additionalDependencies := 
strings.Split(command.AdditionalDependencies, ",")
+
+               for _, dependency := range additionalDependencies {
+                       dependencyComponents := strings.Split(dependency, ":")
+
+                       TypeIsValid := false
+                       for _, dependencyType := range acceptedDependencyTypes {
+                               if dependencyType == dependencyComponents[0] {
+                                       TypeIsValid = true
+                               }
+                       }
+
+                       if !TypeIsValid {
+                               return errors.New("Unexpected type for 
user-provided dependency: " + dependency + ", check command usage for valid 
format.")
+                       }
+               }
+       }
+
+       // If provided, ensure that that the dependencies directory exists.
+       if command.DependenciesDirectory != "" {
+               dependenciesDirectoryExists, err := 
util.DirectoryExists(command.DependenciesDirectory)
+               // Report any error.
+               if err != nil {
+                       return err
+               }
+
+               // Signal file not found.
+               if !dependenciesDirectoryExists {
+                       return errors.New("input file " + 
command.DependenciesDirectory + " file does not exist")
+               }
+       }
+
        return nil
 }
 
@@ -107,6 +164,43 @@ func (command *inspectCmdOptions) run(args []string) error 
{
                }
        }
 
+       // Get top-level dependencies, this is the default behavior when no 
other options are provided.
+       dependencies, err := getTopLevelDependencies(catalog, 
command.OutputFormat, args)
+       if err != nil {
+               return err
+       }
+
+       // Add additional user-provided dependencies.
+       if command.AdditionalDependencies != "" {
+               additionalDependencies := 
strings.Split(command.AdditionalDependencies, ",")
+               for _, dependency := range additionalDependencies {
+                       dependencies = append(dependencies, dependency)
+               }
+       }
+
+       // If --all-dependencies flag is set, add transitive dependencies.
+       if command.AllDependencies {
+               // Create workspace directory to hold all intermediate files.
+               workspaceDirectory, err := getWorkspaceDirectory(command)
+               if err != nil {
+                       return err
+               }
+
+               // The dependencies var will contain both top level and 
transitive dependencies.
+               dependencies, err = getTransitiveDependencies(catalog, 
dependencies, workspaceDirectory)
+               if err != nil {
+                       return err
+               }
+       }
+
+       for _, dep := range dependencies {
+               fmt.Printf("%v\n", dep)
+       }
+
+       return nil
+}
+
+func getTopLevelDependencies(catalog *camel.RuntimeCatalog, format string, 
args []string) ([]string, error) {
        // List of top-level dependencies.
        dependencies := strset.New()
 
@@ -114,7 +208,7 @@ func (command *inspectCmdOptions) run(args []string) error {
        for _, source := range args {
                data, _, err := loadContent(source, false, false)
                if err != nil {
-                       return err
+                       return []string{}, err
                }
 
                sourceSpec := v1.SourceSpec{
@@ -129,10 +223,10 @@ func (command *inspectCmdOptions) run(args []string) 
error {
                dependencies.Merge(trait.AddSourceDependencies(sourceSpec, 
catalog))
        }
 
-       if command.OutputFormat != "" {
-               err := printDependencies(command.OutputFormat, dependencies)
+       if format != "" {
+               err := printDependencies(format, dependencies)
                if err != nil {
-                       return err
+                       return []string{}, err
                }
        } else {
                // Print output in text form.
@@ -140,8 +234,7 @@ func (command *inspectCmdOptions) run(args []string) error {
                        fmt.Printf("%v\n", dep)
                }
        }
-
-       return nil
+       return dependencies.List(), nil
 }
 
 func generateCatalog() (*camel.RuntimeCatalog, error) {
@@ -155,7 +248,7 @@ func generateCatalog() (*camel.RuntimeCatalog, error) {
                Provider: v1.RuntimeProviderMain,
        }
        providerDependencies := []maven.Dependency{}
-       catalog, err := camel.GenerateLocalCatalog(settings, mvn, runtime, 
providerDependencies)
+       catalog, err := camel.GenerateCatalogCommon(settings, mvn, runtime, 
providerDependencies)
        if err != nil {
                return nil, err
        }
@@ -182,3 +275,67 @@ func printDependencies(format string, dependecies 
*strset.Set) error {
        }
        return nil
 }
+
+func getTransitiveDependencies(
+       catalog *camel.RuntimeCatalog,
+       dependencies []string,
+       workspaceDirectory string) ([]string, error) {
+
+       mvn := v1.MavenSpec{
+               LocalRepository: "",
+       }
+
+       // Create Maven project.
+       project := runtime.GenerateProjectCommon(defaultCamelVersion, 
defaultRuntimeVersion)
+
+       // Inject dependencies into Maven project.
+       err := builder.InjectDependenciesCommon(&project, dependencies, catalog)
+       if err != nil {
+               return []string{}, err
+       }
+
+       // Create local Maven context.
+       mc := maven.NewContext(path.Join(workspaceDirectory, "maven"), project)
+       mc.LocalRepository = mvn.LocalRepository
+       mc.Timeout = mvn.GetTimeout().Duration
+
+       // Compute dependencies.
+       content, err := runtime.ComputeDependenciesCommon(mc, 
catalog.Runtime.Version)
+       if err != nil {
+               return nil, err
+       }
+
+       // Compose artifcats list.
+       artifacts := []v1.Artifact{}
+       artifacts, err = runtime.ProcessTransitiveDependencies(content, 
"dependencies")
+       if err != nil {
+               return nil, err
+       }
+
+       allDependencies := strset.New()
+       for _, entry := range artifacts {
+               allDependencies.Add(fmt.Sprintf("%s\n", entry.Location))
+       }
+
+       return allDependencies.List(), nil
+}
+
+func getWorkspaceDirectory(command *inspectCmdOptions) (string, error) {
+       // Path to workspace directory.
+       workspaceDirectory := command.Workspace
+       if command.Workspace == "" {
+               currentDirectory, err := os.Getwd()
+               if err != nil {
+                       return "", err
+               }
+               workspaceDirectory = path.Join(currentDirectory, 
defaultWorkspaceDirectoryName)
+       }
+
+       // Create the workspace directory if it does not already exist.
+       err := util.CreateDirectory(workspaceDirectory)
+       if err != nil {
+               return "", err
+       }
+
+       return workspaceDirectory, nil
+}
diff --git a/pkg/util/camel/catalog.go b/pkg/util/camel/catalog.go
index d073251..2d3d5e9 100644
--- a/pkg/util/camel/catalog.go
+++ b/pkg/util/camel/catalog.go
@@ -85,11 +85,11 @@ func GenerateCatalog(
                return nil, err
        }
 
-       return GenerateLocalCatalog(settings, mvn, runtime, 
providerDependencies)
+       return GenerateCatalogCommon(settings, mvn, runtime, 
providerDependencies)
 }
 
-// GenerateLocalCatalog --
-func GenerateLocalCatalog(
+// GenerateCatalogCommon --
+func GenerateCatalogCommon(
        settings string,
        mvn v1.MavenSpec,
        runtime v1.RuntimeSpec,
diff --git a/pkg/util/util.go b/pkg/util/util.go
index 1ecff9b..30ff77b 100644
--- a/pkg/util/util.go
+++ b/pkg/util/util.go
@@ -247,6 +247,24 @@ func DirectoryExists(directory string) (bool, error) {
        return info.IsDir(), nil
 }
 
+// CreateDirectory --
+func CreateDirectory(directory string) error {
+       // If directory does not exist, create it.
+       directoryExists, err := DirectoryExists(directory)
+       if err != nil {
+               return err
+       }
+
+       if !directoryExists {
+               err := os.MkdirAll(directory, 0777)
+               if err != nil {
+                       return err
+               }
+       }
+
+       return nil
+}
+
 // BytesMarshaller --
 type BytesMarshaller interface {
        MarshalBytes() ([]byte, error)

Reply via email to