This is an automated email from the ASF dual-hosted git repository. astefanutti pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-k.git
commit d674eef935c881642e46122a425d87b0a00811ad Author: Antonin Stefanutti <anto...@stefanutti.fr> AuthorDate: Wed Jun 2 12:45:24 2021 +0200 chore(build): Cancellable Maven operations --- .../camel/v1/integrationplatform_types_support.go | 8 - pkg/builder/quarkus.go | 15 +- pkg/cmd/local_build.go | 5 +- pkg/cmd/local_inspect.go | 6 +- pkg/cmd/local_run.go | 3 +- pkg/cmd/util_dependencies.go | 38 ++--- .../integrationplatform/initialize_test.go | 23 +-- pkg/platform/defaults.go | 31 +--- pkg/trait/camel.go | 5 +- pkg/trait/logging.go | 3 +- pkg/trait/openapi.go | 8 +- pkg/util/camel/catalog.go | 8 +- pkg/util/maven/{maven.go => maven_command.go} | 180 ++++++++++++--------- pkg/util/maven/maven_log.go | 9 +- pkg/util/maven/maven_project.go | 49 +++++- pkg/util/maven/maven_settings.go | 16 ++ pkg/util/maven/maven_types.go | 122 +------------- 17 files changed, 226 insertions(+), 303 deletions(-) diff --git a/pkg/apis/camel/v1/integrationplatform_types_support.go b/pkg/apis/camel/v1/integrationplatform_types_support.go index 23acc1a..41de3ea 100644 --- a/pkg/apis/camel/v1/integrationplatform_types_support.go +++ b/pkg/apis/camel/v1/integrationplatform_types_support.go @@ -195,14 +195,6 @@ func (b IntegrationPlatformBuildSpec) GetTimeout() metav1.Duration { return *b.Timeout } -// GetTimeout returns the specified duration or a default one -func (m MavenSpec) GetTimeout() metav1.Duration { - if m.Timeout == nil { - return metav1.Duration{} - } - return *m.Timeout -} - var _ ResourceCondition = IntegrationPlatformCondition{} // GetConditions -- diff --git a/pkg/builder/quarkus.go b/pkg/builder/quarkus.go index 8b7d0c3..f9bc2d9 100644 --- a/pkg/builder/quarkus.go +++ b/pkg/builder/quarkus.go @@ -18,6 +18,7 @@ limitations under the License. package builder import ( + "context" "fmt" "os" "path" @@ -145,10 +146,9 @@ func GenerateQuarkusProjectCommon(camelQuarkusVersion string, runtimeVersion str } func buildQuarkusRunner(ctx *builderContext) error { - mc := maven.NewContext(path.Join(ctx.Path, "maven"), ctx.Maven.Project) + mc := maven.NewContext(path.Join(ctx.Path, "maven")) mc.SettingsContent = ctx.Maven.SettingsData mc.LocalRepository = ctx.Build.Maven.LocalRepository - mc.Timeout = ctx.Build.Maven.GetTimeout().Duration if ctx.Maven.TrustStoreName != "" { mc.ExtraMavenOpts = append(mc.ExtraMavenOpts, @@ -157,7 +157,7 @@ func buildQuarkusRunner(ctx *builderContext) error { ) } - err := BuildQuarkusRunnerCommon(mc) + err := BuildQuarkusRunnerCommon(ctx.C, mc, ctx.Maven.Project) if err != nil { return err } @@ -165,7 +165,7 @@ func buildQuarkusRunner(ctx *builderContext) error { return nil } -func BuildQuarkusRunnerCommon(mc maven.Context) error { +func BuildQuarkusRunnerCommon(ctx context.Context, mc maven.Context, project maven.Project) error { resourcesPath := path.Join(mc.Path, "src", "main", "resources") if err := os.MkdirAll(resourcesPath, os.ModePerm); err != nil { return errors.Wrap(err, "failure while creating resource folder") @@ -182,8 +182,8 @@ func BuildQuarkusRunnerCommon(mc maven.Context) error { mc.AddArgument("package") - // Build the project - if err := maven.Run(mc); err != nil { + // Run the Maven goal + if err := project.Command(mc).Do(ctx); err != nil { return errors.Wrap(err, "failure while building project") } @@ -191,10 +191,9 @@ func BuildQuarkusRunnerCommon(mc maven.Context) error { } func computeQuarkusDependencies(ctx *builderContext) error { - mc := maven.NewContext(path.Join(ctx.Path, "maven"), ctx.Maven.Project) + mc := maven.NewContext(path.Join(ctx.Path, "maven")) mc.SettingsContent = ctx.Maven.SettingsData mc.LocalRepository = ctx.Build.Maven.LocalRepository - mc.Timeout = ctx.Build.Maven.GetTimeout().Duration // Process artifacts list and add it to existing artifacts. artifacts, err := ProcessQuarkusTransitiveDependencies(mc) diff --git a/pkg/cmd/local_build.go b/pkg/cmd/local_build.go index b9606dd..1a09adf 100644 --- a/pkg/cmd/local_build.go +++ b/pkg/cmd/local_build.go @@ -167,15 +167,14 @@ func (command *localBuildCmdOptions) run(cmd *cobra.Command, args []string) erro var dependenciesList, propertyFilesList []string routeFiles := args if !command.BaseImage { - // Fetch dependencies. - dependencies, err := getDependencies(args, command.AdditionalDependencies, command.MavenRepositories, true) + dependencies, err := getDependencies(command.Context, args, command.AdditionalDependencies, command.MavenRepositories, true) if err != nil { return err } var propertyFiles []string if !command.DependenciesOnly { - // Manage integration properties which may come from files or CLI. + // Manage integration properties which may come from files or CLI propertyFiles, err = updateIntegrationProperties(command.Properties, command.PropertyFiles, false) if err != nil { return err diff --git a/pkg/cmd/local_inspect.go b/pkg/cmd/local_inspect.go index c225a77..525e592 100644 --- a/pkg/cmd/local_inspect.go +++ b/pkg/cmd/local_inspect.go @@ -73,13 +73,11 @@ type localInspectCmdOptions struct { } func (command *localInspectCmdOptions) validate(args []string) error { - // Validate integration files. err := validateIntegrationFiles(args) if err != nil { return err } - // Validate additional dependencies specified by the user. err = validateAdditionalDependencies(command.AdditionalDependencies) if err != nil { return err @@ -93,13 +91,11 @@ func (command *localInspectCmdOptions) init() error { } func (command *localInspectCmdOptions) run(args []string) error { - // Fetch dependencies. - dependencies, err := getDependencies(args, command.AdditionalDependencies, command.MavenRepositories, command.AllDependencies) + dependencies, err := getDependencies(command.Context, args, command.AdditionalDependencies, command.MavenRepositories, command.AllDependencies) if err != nil { return err } - // Print dependencies. err = outputDependencies(dependencies, command.OutputFormat) if err != nil { return err diff --git a/pkg/cmd/local_run.go b/pkg/cmd/local_run.go index db8c4b4..418830d 100644 --- a/pkg/cmd/local_run.go +++ b/pkg/cmd/local_run.go @@ -155,8 +155,7 @@ func (command *localRunCmdOptions) run(cmd *cobra.Command, args []string) error } dependencies = localBuildDependencies } else { - // Fetch dependencies. - computedDependencies, err := getDependencies(args, command.AdditionalDependencies, command.MavenRepositories, true) + computedDependencies, err := getDependencies(command.Context, args, command.AdditionalDependencies, command.MavenRepositories, true) if err != nil { return err } diff --git a/pkg/cmd/util_dependencies.go b/pkg/cmd/util_dependencies.go index dc7bede..89c1999 100644 --- a/pkg/cmd/util_dependencies.go +++ b/pkg/cmd/util_dependencies.go @@ -18,6 +18,7 @@ limitations under the License. package cmd import ( + "context" "fmt" "io/ioutil" "os" @@ -42,9 +43,9 @@ var additionalDependencyUsageMessage = `Additional top-level dependencies are sp <type>:<dependency-name> where <type> is one of {` + strings.Join(acceptedDependencyTypes, "|") + `}.` -func getDependencies(args []string, additionalDependencies []string, repositories []string, allDependencies bool) ([]string, error) { +func getDependencies(ctx context.Context, args []string, additionalDependencies []string, repositories []string, allDependencies bool) ([]string, error) { // Fetch existing catalog or create new one if one does not already exist - catalog, err := createCamelCatalog() + catalog, err := createCamelCatalog(ctx) // Get top-level dependencies dependencies, err := getTopLevelDependencies(catalog, args) @@ -67,7 +68,7 @@ func getDependencies(args []string, additionalDependencies []string, repositorie util.StringSliceUniqueAdd(&dependencies, runtimeDep.GetDependencyID()) } - dependencies, err = getTransitiveDependencies(catalog, dependencies, repositories) + dependencies, err = getTransitiveDependencies(ctx, catalog, dependencies, repositories) if err != nil { return nil, err } @@ -101,29 +102,20 @@ func getTopLevelDependencies(catalog *camel.RuntimeCatalog, args []string) ([]st return dependencies.List(), nil } -func getTransitiveDependencies( - catalog *camel.RuntimeCatalog, - dependencies []string, repositories []string) ([]string, error) { - - mvn := v1.MavenSpec{ - LocalRepository: "", - } - - // Create Maven project +func getTransitiveDependencies(ctx context.Context, catalog *camel.RuntimeCatalog, dependencies []string, repositories []string) ([]string, error) { project := builder.GenerateQuarkusProjectCommon( catalog.CamelCatalogSpec.Runtime.Metadata["camel-quarkus.version"], - defaults.DefaultRuntimeVersion, catalog.CamelCatalogSpec.Runtime.Metadata["quarkus.version"]) + defaults.DefaultRuntimeVersion, + catalog.CamelCatalogSpec.Runtime.Metadata["quarkus.version"], + ) - // Inject dependencies into Maven project err := camel.ManageIntegrationDependencies(&project, dependencies, catalog) if err != nil { return nil, err } - // Maven local context to be used for generating the transitive dependencies - mc := maven.NewContext(util.MavenWorkingDirectory, project) - mc.LocalRepository = mvn.LocalRepository - mc.Timeout = mvn.GetTimeout().Duration + mc := maven.NewContext(util.MavenWorkingDirectory) + mc.LocalRepository = "" if len(repositories) > 0 { var repoList []v1.Repository @@ -155,7 +147,7 @@ func getTransitiveDependencies( // Make maven command less verbose mc.AdditionalArguments = append(mc.AdditionalArguments, "-q") - err = builder.BuildQuarkusRunnerCommon(mc) + err = builder.BuildQuarkusRunnerCommon(ctx, mc, project) if err != nil { return nil, err } @@ -217,7 +209,7 @@ func getLocalBuildRoutes(integrationDirectory string) ([]string, error) { return locallyBuiltRoutes, nil } -func generateCatalog() (*camel.RuntimeCatalog, error) { +func generateCatalog(ctx context.Context) (*camel.RuntimeCatalog, error) { // A Camel catalog is required for this operation settings := "" mvn := v1.MavenSpec{ @@ -229,7 +221,7 @@ func generateCatalog() (*camel.RuntimeCatalog, error) { } var providerDependencies []maven.Dependency var caCert []byte - catalog, err := camel.GenerateCatalogCommon(settings, caCert, mvn, runtime, providerDependencies) + catalog, err := camel.GenerateCatalogCommon(ctx, settings, caCert, mvn, runtime, providerDependencies) if err != nil { return nil, err } @@ -237,7 +229,7 @@ func generateCatalog() (*camel.RuntimeCatalog, error) { return catalog, nil } -func createCamelCatalog() (*camel.RuntimeCatalog, error) { +func createCamelCatalog(ctx context.Context) (*camel.RuntimeCatalog, error) { // Attempt to reuse existing Camel catalog if one is present catalog, err := camel.DefaultCatalog() if err != nil { @@ -246,7 +238,7 @@ func createCamelCatalog() (*camel.RuntimeCatalog, error) { // Generate catalog if one was not found if catalog == nil { - catalog, err = generateCatalog() + catalog, err = generateCatalog(ctx) if err != nil { return nil, err } diff --git a/pkg/controller/integrationplatform/initialize_test.go b/pkg/controller/integrationplatform/initialize_test.go index 2e67379..4c7aa12 100644 --- a/pkg/controller/integrationplatform/initialize_test.go +++ b/pkg/controller/integrationplatform/initialize_test.go @@ -22,15 +22,14 @@ import ( "testing" "time" - "github.com/apache/camel-k/pkg/platform" "github.com/rs/xid" + "github.com/stretchr/testify/assert" + v1 "github.com/apache/camel-k/pkg/apis/camel/v1" + "github.com/apache/camel-k/pkg/platform" "github.com/apache/camel-k/pkg/util/log" "github.com/apache/camel-k/pkg/util/test" - - "github.com/stretchr/testify/assert" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -54,10 +53,6 @@ func TestTimeouts_Default(t *testing.T) { assert.Nil(t, err) assert.NotNil(t, answer) - n := answer.Status.Build.GetTimeout().Duration.Seconds() * 0.75 - d := (time.Duration(n) * time.Second).Truncate(time.Second) - - assert.Equal(t, d, answer.Status.Build.Maven.GetTimeout().Duration) assert.Equal(t, 5*time.Minute, answer.Status.Build.GetTimeout().Duration) } @@ -88,10 +83,6 @@ func TestTimeouts_MavenComputedFromBuild(t *testing.T) { assert.Nil(t, err) assert.NotNil(t, answer) - n := answer.Status.Build.GetTimeout().Duration.Seconds() * 0.75 - d := (time.Duration(n) * time.Second).Truncate(time.Second) - - assert.Equal(t, d, answer.Status.Build.Maven.GetTimeout().Duration) assert.Equal(t, 1*time.Minute, answer.Status.Build.GetTimeout().Duration) } @@ -109,13 +100,6 @@ func TestTimeouts_Truncated(t *testing.T) { Duration: bt, } - mt, err := time.ParseDuration("2m1ms") - assert.Nil(t, err) - - ip.Spec.Build.Maven.Timeout = &metav1.Duration{ - Duration: mt, - } - c, err := test.NewFakeClient(&ip) assert.Nil(t, err) @@ -129,7 +113,6 @@ func TestTimeouts_Truncated(t *testing.T) { assert.Nil(t, err) assert.NotNil(t, answer) - assert.Equal(t, 2*time.Minute, answer.Status.Build.Maven.GetTimeout().Duration) assert.Equal(t, 5*time.Minute, answer.Status.Build.GetTimeout().Duration) } diff --git a/pkg/platform/defaults.go b/pkg/platform/defaults.go index 2d7c15d..07f3ed6 100644 --- a/pkg/platform/defaults.go +++ b/pkg/platform/defaults.go @@ -106,8 +106,8 @@ func ConfigureDefaults(ctx context.Context, c client.Client, p *v1.IntegrationPl log.Log.Info("No registry specified for publishing images") } - if verbose && p.Status.Build.Maven.GetTimeout().Duration != 0 { - log.Log.Infof("Maven Timeout set to %s", p.Status.Build.Maven.GetTimeout().Duration) + if verbose && p.Status.Build.GetTimeout().Duration != 0 { + log.Log.Infof("Maven Timeout set to %s", p.Status.Build.GetTimeout().Duration) } return nil @@ -184,24 +184,6 @@ func setPlatformDefaults(ctx context.Context, c client.Client, p *v1.Integration } } - if p.Status.Build.Maven.GetTimeout().Duration != 0 { - d := p.Status.Build.Maven.GetTimeout().Duration.Truncate(time.Second) - - if verbose && p.Status.Build.Maven.GetTimeout().Duration != d { - log.Log.Infof("Maven timeout minimum unit is sec (configured: %s, truncated: %s)", p.Status.Build.Maven.GetTimeout().Duration, d) - } - - p.Status.Build.Maven.Timeout = &metav1.Duration{ - Duration: d, - } - } - if p.Status.Build.Maven.GetTimeout().Duration == 0 { - n := p.Status.Build.GetTimeout().Duration.Seconds() * 0.75 - p.Status.Build.Maven.Timeout = &metav1.Duration{ - Duration: (time.Duration(n) * time.Second).Truncate(time.Second), - } - } - if p.Status.Build.Maven.Settings.ConfigMapKeyRef == nil && p.Status.Build.Maven.Settings.SecretKeyRef == nil { var repositories []v1.Repository var mirrors []maven.Mirror @@ -214,11 +196,11 @@ func setPlatformDefaults(ctx context.Context, c client.Client, p *v1.Integration } mirrors = append(mirrors, mirror) } else { - repository := maven.NewRepository(c.Value) - if repository.ID == "" { - repository.ID = fmt.Sprintf("repository-%03d", i) + repo := maven.NewRepository(c.Value) + if repo.ID == "" { + repo.ID = fmt.Sprintf("repository-%03d", i) } - repositories = append(repositories, repository) + repositories = append(repositories, repo) } } } @@ -260,7 +242,6 @@ func setPlatformDefaults(ctx context.Context, c client.Client, p *v1.Integration log.Log.Infof("BaseImage set to %s", p.Status.Build.BaseImage) log.Log.Infof("LocalRepository set to %s", p.Status.Build.Maven.LocalRepository) log.Log.Infof("Timeout set to %s", p.Status.Build.GetTimeout()) - log.Log.Infof("Maven Timeout set to %s", p.Status.Build.Maven.GetTimeout().Duration) } return nil diff --git a/pkg/trait/camel.go b/pkg/trait/camel.go index 8a82430..d64e54c 100644 --- a/pkg/trait/camel.go +++ b/pkg/trait/camel.go @@ -18,6 +18,7 @@ limitations under the License. package trait import ( + "context" "fmt" "strings" @@ -96,7 +97,9 @@ func (t *camelTrait) loadOrCreateCatalog(e *Environment, runtimeVersion string) // the required versions (camel and runtime) are not expressed as // semver constraints if exactVersionRegexp.MatchString(runtimeVersion) { - catalog, err = camel.GenerateCatalog(e.C, e.Client, ns, e.Platform.Status.Build.Maven, runtime, []maven.Dependency{}) + ctx, cancel := context.WithTimeout(e.C, e.Platform.Status.Build.GetTimeout().Duration) + defer cancel() + catalog, err = camel.GenerateCatalog(ctx, e.Client, ns, e.Platform.Status.Build.Maven, runtime, []maven.Dependency{}) if err != nil { return err } diff --git a/pkg/trait/logging.go b/pkg/trait/logging.go index 3e3fee7..92b5f86 100644 --- a/pkg/trait/logging.go +++ b/pkg/trait/logging.go @@ -18,10 +18,11 @@ limitations under the License. package trait import ( + "strconv" + v1 "github.com/apache/camel-k/pkg/apis/camel/v1" "github.com/apache/camel-k/pkg/util" "github.com/apache/camel-k/pkg/util/envvar" - "strconv" ) const ( diff --git a/pkg/trait/openapi.go b/pkg/trait/openapi.go index 9ba84cf..8ad421e 100644 --- a/pkg/trait/openapi.go +++ b/pkg/trait/openapi.go @@ -18,6 +18,7 @@ limitations under the License. package trait import ( + "context" "fmt" "io/ioutil" "os" @@ -201,9 +202,8 @@ func (t *openAPITrait) createNewOpenAPIConfigMap(e *Environment, resource v1.Res return err } - mc := maven.NewContext(tmpDir, project) + mc := maven.NewContext(tmpDir) mc.LocalRepository = e.Platform.Status.Build.Maven.LocalRepository - mc.Timeout = e.Platform.Status.Build.Maven.GetTimeout().Duration mc.AddArgument("-Dopenapi.spec=" + in) mc.AddArgument("-Ddsl.out=" + out) @@ -232,7 +232,9 @@ func (t *openAPITrait) createNewOpenAPIConfigMap(e *Environment, resource v1.Res ) } - err = maven.Run(mc) + ctx, cancel := context.WithTimeout(e.C, e.Platform.Status.Build.GetTimeout().Duration) + defer cancel() + err = project.Command(mc).Do(ctx) if err != nil { return err } diff --git a/pkg/util/camel/catalog.go b/pkg/util/camel/catalog.go index 47a5359..0aeae20 100644 --- a/pkg/util/camel/catalog.go +++ b/pkg/util/camel/catalog.go @@ -83,10 +83,11 @@ func GenerateCatalog( } } - return GenerateCatalogCommon(settings, caCert, mvn, runtime, providerDependencies) + return GenerateCatalogCommon(ctx, settings, caCert, mvn, runtime, providerDependencies) } func GenerateCatalogCommon( + ctx context.Context, settings string, caCert []byte, mvn v1.MavenSpec, @@ -107,9 +108,8 @@ func GenerateCatalogCommon( project := generateMavenProject(runtime.Version, providerDependencies) - mc := maven.NewContext(tmpDir, project) + mc := maven.NewContext(tmpDir) mc.LocalRepository = mvn.LocalRepository - mc.Timeout = mvn.GetTimeout().Duration mc.AddSystemProperty("catalog.path", tmpDir) mc.AddSystemProperty("catalog.file", "catalog.yaml") mc.AddSystemProperty("catalog.runtime", string(runtime.Provider)) @@ -132,7 +132,7 @@ func GenerateCatalogCommon( ) } - err = maven.Run(mc) + err = project.Command(mc).Do(ctx) if err != nil { return nil, err } diff --git a/pkg/util/maven/maven.go b/pkg/util/maven/maven_command.go similarity index 65% rename from pkg/util/maven/maven.go rename to pkg/util/maven/maven_command.go index 596627f..bca1a97 100644 --- a/pkg/util/maven/maven.go +++ b/pkg/util/maven/maven_command.go @@ -23,7 +23,6 @@ import ( "fmt" "io" "io/ioutil" - "math" "os" "os/exec" "path" @@ -38,47 +37,13 @@ import ( var Log = log.WithName("maven") -func GenerateProjectStructure(context Context) error { - if err := util.WriteFileWithBytesMarshallerContent(context.Path, "pom.xml", context.Project); err != nil { - return err - } - - if context.SettingsContent != nil { - if err := util.WriteFileWithContent(context.Path, "settings.xml", context.SettingsContent); err != nil { - return err - } - } - - for k, v := range context.AdditionalEntries { - var bytes []byte - var err error - - if dc, ok := v.([]byte); ok { - bytes = dc - } else if dc, ok := v.(io.Reader); ok { - bytes, err = ioutil.ReadAll(dc) - if err != nil { - return err - } - } else { - return fmt.Errorf("unknown content type: name=%s, content=%+v", k, v) - } - - if len(bytes) > 0 { - Log.Infof("write entry: %s (%d bytes)", k, len(bytes)) - - err = util.WriteFileWithContent(context.Path, k, bytes) - if err != nil { - return err - } - } - } - - return nil +type Command struct { + context Context + project Project } -func Run(ctx Context) error { - if err := GenerateProjectStructure(ctx); err != nil { +func (c *Command) Do(ctx context.Context) error { + if err := generateProjectStructure(c.context, c.project); err != nil { return err } @@ -90,13 +55,13 @@ func Run(ctx Context) error { args := make([]string, 0) args = append(args, "--batch-mode") - if ctx.LocalRepository == "" { + if c.context.LocalRepository == "" { args = append(args, "-Dcamel.noop=true") - } else if _, err := os.Stat(ctx.LocalRepository); err == nil { - args = append(args, "-Dmaven.repo.local="+ctx.LocalRepository) + } else if _, err := os.Stat(c.context.LocalRepository); err == nil { + args = append(args, "-Dmaven.repo.local="+c.context.LocalRepository) } - settingsPath := path.Join(ctx.Path, "settings.xml") + settingsPath := path.Join(c.context.Path, "settings.xml") settingsExists, err := util.FileExists(settingsPath) if err != nil { return err @@ -106,32 +71,24 @@ func Run(ctx Context) error { args = append(args, "--settings", settingsPath) } - args = append(args, ctx.AdditionalArguments...) - - timeout := ctx.Timeout - if timeout == 0 { - timeout = math.MaxInt64 - } - - c, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() + args = append(args, c.context.AdditionalArguments...) - cmd := exec.CommandContext(c, mvnCmd, args...) - cmd.Dir = ctx.Path + cmd := exec.CommandContext(ctx, mvnCmd, args...) + cmd.Dir = c.context.Path var mavenOptions string - if len(ctx.ExtraMavenOpts) > 0 { + if len(c.context.ExtraMavenOpts) > 0 { // Inherit the parent process environment env := os.Environ() mavenOpts, ok := os.LookupEnv("MAVEN_OPTS") if !ok { - mavenOptions = strings.Join(ctx.ExtraMavenOpts, " ") + mavenOptions = strings.Join(c.context.ExtraMavenOpts, " ") env = append(env, "MAVEN_OPTS="+mavenOptions) } else { var extraOptions []string options := strings.Fields(mavenOpts) - for _, extraOption := range ctx.ExtraMavenOpts { + for _, extraOption := range c.context.ExtraMavenOpts { // Basic duplicated key detection, that should be improved // to support a wider range of JVM options key := strings.SplitN(extraOption, "=", 2)[0] @@ -160,36 +117,32 @@ func Run(ctx Context) error { cmd.Env = env } - Log.WithValues("timeout", timeout.String(), "MAVEN_OPTS", mavenOptions). - Infof("executing: %s", strings.Join(cmd.Args, " ")) + Log.WithValues("MAVEN_OPTS", mavenOptions).Infof("executing: %s", strings.Join(cmd.Args, " ")) - stdOut, error := cmd.StdoutPipe() - if error != nil { + stdOut, err := cmd.StdoutPipe() + if err != nil { return nil } - error = cmd.Start() + err = cmd.Start() - if error != nil { - return error + if err != nil { + return err } scanner := bufio.NewScanner(stdOut) Log.Debug("About to start parsing the Maven output") - for scanner.Scan() { line := scanner.Text() - - mavenLog, parseError := ParseLog(line) - + mavenLog, parseError := parseLog(line) if parseError == nil { - NormalizeLog(mavenLog) + normalizeLog(mavenLog) } else { // Why we are ignoring the parsing errors here: there are a few scenarios where this would likely occur. // For example, if something outside of Maven outputs something (i.e.: the JDK, a misbehaved plugin, // etc). The build may still have succeeded, though. - NonNormalizedLog(line) + nonNormalizedLog(line) } } Log.Debug("Finished parsing Maven output") @@ -197,7 +150,90 @@ func Run(ctx Context) error { return cmd.Wait() } -// ParseGAV decode a maven artifact id to a dependency definition. +func NewContext(buildDir string) Context { + return Context{ + Path: buildDir, + AdditionalArguments: make([]string, 0), + AdditionalEntries: make(map[string]interface{}), + } +} + +type Context struct { + Path string + // Project Project + ExtraMavenOpts []string + SettingsContent []byte + AdditionalArguments []string + AdditionalEntries map[string]interface{} + // Timeout time.Duration + LocalRepository string + // Stdout io.Writer +} + +func (c *Context) AddEntry(id string, entry interface{}) { + if c.AdditionalEntries == nil { + c.AdditionalEntries = make(map[string]interface{}) + } + + c.AdditionalEntries[id] = entry +} + +func (c *Context) AddArgument(argument string) { + c.AdditionalArguments = append(c.AdditionalArguments, argument) +} + +func (c *Context) AddArgumentf(format string, args ...interface{}) { + c.AdditionalArguments = append(c.AdditionalArguments, fmt.Sprintf(format, args...)) +} + +func (c *Context) AddArguments(arguments ...string) { + c.AdditionalArguments = append(c.AdditionalArguments, arguments...) +} + +func (c *Context) AddSystemProperty(name string, value string) { + c.AddArgumentf("-D%s=%s", name, value) +} + +func generateProjectStructure(context Context, project Project) error { + if err := util.WriteFileWithBytesMarshallerContent(context.Path, "pom.xml", project); err != nil { + return err + } + + if context.SettingsContent != nil { + if err := util.WriteFileWithContent(context.Path, "settings.xml", context.SettingsContent); err != nil { + return err + } + } + + for k, v := range context.AdditionalEntries { + var bytes []byte + var err error + + if dc, ok := v.([]byte); ok { + bytes = dc + } else if dc, ok := v.(io.Reader); ok { + bytes, err = ioutil.ReadAll(dc) + if err != nil { + return err + } + } else { + return fmt.Errorf("unknown content type: name=%s, content=%+v", k, v) + } + + if len(bytes) > 0 { + Log.Infof("write entry: %s (%d bytes)", k, len(bytes)) + + err = util.WriteFileWithContent(context.Path, k, bytes) + if err != nil { + return err + } + } + } + + return nil +} + +// ParseGAV decodes the provided Maven GAV into the corresponding Dependency. // // The artifact id is in the form of: // diff --git a/pkg/util/maven/maven_log.go b/pkg/util/maven/maven_log.go index 3b25368..c01957d 100644 --- a/pkg/util/maven/maven_log.go +++ b/pkg/util/maven/maven_log.go @@ -19,10 +19,11 @@ package maven import ( "encoding/json" + "github.com/apache/camel-k/pkg/util/log" ) -type MavenLog struct { +type mavenLog struct { Level string `json:"level"` Ts string `json:"ts"` Logger string `json:"logger"` @@ -45,13 +46,13 @@ const ( var mavenLogger = log.WithName("maven.build") -func ParseLog(line string) (mavenLog MavenLog, error error) { +func parseLog(line string) (mavenLog mavenLog, error error) { error = json.Unmarshal([]byte(line), &mavenLog) return mavenLog, error } -func NormalizeLog(mavenLog MavenLog) { +func normalizeLog(mavenLog mavenLog) { switch mavenLog.Level { case DEBUG, TRACE: mavenLogger.Debug(mavenLog.Msg) @@ -62,6 +63,6 @@ func NormalizeLog(mavenLog MavenLog) { } } -func NonNormalizedLog(rawLog string) { +func nonNormalizedLog(rawLog string) { mavenLogger.Info(rawLog) } diff --git a/pkg/util/maven/maven_project.go b/pkg/util/maven/maven_project.go index bcc461e..e9ed19d 100644 --- a/pkg/util/maven/maven_project.go +++ b/pkg/util/maven/maven_project.go @@ -46,6 +46,13 @@ func NewProjectWithGAV(group string, artifact string, version string) Project { return p } +func (p Project) Command(context Context) *Command { + return &Command{ + context: context, + project: p, + } +} + func (p Project) MarshalBytes() ([]byte, error) { w := &bytes.Buffer{} w.WriteString(xml.Header) @@ -138,7 +145,37 @@ func (p *Project) AddDependencyExclusions(dep Dependency, exclusions ...Exclusio } } -// NewDependency create an new dependency from the given gav info +type propertiesEntry struct { + XMLName xml.Name + Value string `xml:",chardata"` +} + +func (m Properties) AddAll(properties map[string]string) { + for k, v := range properties { + m[k] = v + } +} + +func (m Properties) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + if len(m) == 0 { + return nil + } + + err := e.EncodeToken(start) + if err != nil { + return err + } + + for k, v := range m { + if err := e.Encode(propertiesEntry{XMLName: xml.Name{Local: k}, Value: v}); err != nil { + return err + } + } + + return e.EncodeToken(start.End()) +} + +// NewDependency creates an new dependency from the given GAV func NewDependency(groupID string, artifactID string, version string) Dependency { return Dependency{ GroupID: groupID, @@ -149,16 +186,14 @@ func NewDependency(groupID string, artifactID string, version string) Dependency } } +// NewRepository parses the given repository URL and generates the corresponding v1.Repository. // -// NewRepository parse the given repo url ang generated the related struct. -// -// The repository can be customized by appending @instruction to the repository -// uri, as example: +// The repository can be customized by appending @param to the repository +// URL, e.g.: // // http://my-nexus:8081/repository/publicc@id=my-repo@snapshots // -// Will enable snapshots and sets the repo it to my-repo -// +// That enables snapshots and sets the repository id to `my-repo` func NewRepository(repo string) v1.Repository { r := v1.Repository{ URL: repo, diff --git a/pkg/util/maven/maven_settings.go b/pkg/util/maven/maven_settings.go index a9cfab1..6fff121 100644 --- a/pkg/util/maven/maven_settings.go +++ b/pkg/util/maven/maven_settings.go @@ -18,6 +18,7 @@ limitations under the License. package maven import ( + "bytes" "encoding/xml" "strings" @@ -32,6 +33,21 @@ import ( // This variable can be overridden at build time var DefaultMavenRepositories = "https://repo.maven.apache.org/maven2@id=central" +func (s Settings) MarshalBytes() ([]byte, error) { + w := &bytes.Buffer{} + w.WriteString(xml.Header) + + e := xml.NewEncoder(w) + e.Indent("", " ") + + err := e.Encode(s) + if err != nil { + return []byte{}, err + } + + return w.Bytes(), nil +} + func NewSettings() Settings { return Settings{ XMLName: xml.Name{Local: "settings"}, diff --git a/pkg/util/maven/maven_types.go b/pkg/util/maven/maven_types.go index c99742c..ecf3cc5 100644 --- a/pkg/util/maven/maven_types.go +++ b/pkg/util/maven/maven_types.go @@ -18,16 +18,11 @@ limitations under the License. package maven import ( - "bytes" "encoding/xml" - "fmt" - "io" - "time" v1 "github.com/apache/camel-k/pkg/apis/camel/v1" ) -// Mirror -- type Mirror struct { ID string `xml:"id"` Name string `xml:"name,omitempty"` @@ -35,13 +30,11 @@ type Mirror struct { MirrorOf string `xml:"mirrorOf"` } -// Build -- type Build struct { DefaultGoal string `xml:"defaultGoal,omitempty"` Plugins []Plugin `xml:"plugins>plugin,omitempty"` } -// Plugin -- type Plugin struct { GroupID string `xml:"groupId"` ArtifactID string `xml:"artifactId"` @@ -50,101 +43,15 @@ type Plugin struct { Dependencies []Dependency `xml:"dependencies>dependency,omitempty"` } -// Execution -- type Execution struct { ID string `xml:"id,omitempty"` Phase string `xml:"phase,omitempty"` Goals []string `xml:"goals>goal,omitempty"` } -// Properties -- type Properties map[string]string -type propertiesEntry struct { - XMLName xml.Name - Value string `xml:",chardata"` -} - -// AddAll -- -func (m Properties) AddAll(properties map[string]string) { - for k, v := range properties { - m[k] = v - } -} - -// MarshalXML -- -func (m Properties) MarshalXML(e *xml.Encoder, start xml.StartElement) error { - if len(m) == 0 { - return nil - } - - err := e.EncodeToken(start) - if err != nil { - return err - } - - for k, v := range m { - if err := e.Encode(propertiesEntry{XMLName: xml.Name{Local: k}, Value: v}); err != nil { - return err - } - } - - return e.EncodeToken(start.End()) -} - -// NewContext -- -func NewContext(buildDir string, project Project) Context { - return Context{ - Path: buildDir, - Project: project, - AdditionalArguments: make([]string, 0), - AdditionalEntries: make(map[string]interface{}), - } -} - -// Context -- -type Context struct { - Path string - Project Project - ExtraMavenOpts []string - SettingsContent []byte - AdditionalArguments []string - AdditionalEntries map[string]interface{} - Timeout time.Duration - LocalRepository string - Stdout io.Writer -} - -// AddEntry -- -func (c *Context) AddEntry(id string, entry interface{}) { - if c.AdditionalEntries == nil { - c.AdditionalEntries = make(map[string]interface{}) - } - - c.AdditionalEntries[id] = entry -} - -// AddArgument -- -func (c *Context) AddArgument(argument string) { - c.AdditionalArguments = append(c.AdditionalArguments, argument) -} - -// AddArgumentf -- -func (c *Context) AddArgumentf(format string, args ...interface{}) { - c.AdditionalArguments = append(c.AdditionalArguments, fmt.Sprintf(format, args...)) -} - -// AddArguments -- -func (c *Context) AddArguments(arguments ...string) { - c.AdditionalArguments = append(c.AdditionalArguments, arguments...) -} - -// AddSystemProperty -- -func (c *Context) AddSystemProperty(name string, value string) { - c.AddArgumentf("-D%s=%s", name, value) -} - -// Settings represent a maven settings +// Settings models a Maven settings type Settings struct { XMLName xml.Name XMLNs string `xml:"xmlns,attr"` @@ -155,23 +62,7 @@ type Settings struct { Mirrors []Mirror `xml:"mirrors>mirror,omitempty"` } -// MarshalBytes -- -func (s Settings) MarshalBytes() ([]byte, error) { - w := &bytes.Buffer{} - w.WriteString(xml.Header) - - e := xml.NewEncoder(w) - e.Indent("", " ") - - err := e.Encode(s) - if err != nil { - return []byte{}, err - } - - return w.Bytes(), nil -} - -// Project represent a maven project +// Project models a Maven project type Project struct { XMLName xml.Name XMLNs string `xml:"xmlns,attr"` @@ -189,18 +80,18 @@ type Project struct { Build *Build `xml:"build,omitempty"` } -// Exclusion represent a maven's dependency exlucsion +// Exclusion models a dependency exclusion type Exclusion struct { GroupID string `xml:"groupId" yaml:"groupId"` ArtifactID string `xml:"artifactId" yaml:"artifactId"` } -// DependencyManagement represent maven's dependency management block +// DependencyManagement models dependency management type DependencyManagement struct { Dependencies []Dependency `xml:"dependencies>dependency,omitempty"` } -// Dependency represent a maven's dependency +// Dependency models a dependency type Dependency struct { GroupID string `xml:"groupId" yaml:"groupId"` ArtifactID string `xml:"artifactId" yaml:"artifactId"` @@ -211,7 +102,6 @@ type Dependency struct { Exclusions *[]Exclusion `xml:"exclusions>exclusion,omitempty" yaml:"exclusions,omitempty"` } -// Profile -- type Profile struct { ID string `xml:"id"` Activation Activation `xml:"activation,omitempty"` @@ -220,13 +110,11 @@ type Profile struct { PluginRepositories []v1.Repository `xml:"pluginRepositories>pluginRepository,omitempty"` } -// Activation -- type Activation struct { ActiveByDefault bool `xml:"activeByDefault"` Property *PropertyActivation `xml:"property,omitempty"` } -// PropertyActivation -- type PropertyActivation struct { Name string `xml:"name"` Value string `xml:"value"`