diff --git a/pkg/cmd/modeline.go b/pkg/cmd/modeline.go index 7d6a848fdf..0833511be5 100644 --- a/pkg/cmd/modeline.go +++ b/pkg/cmd/modeline.go @@ -38,6 +38,12 @@ var ( nonRunOptions = map[string]bool{ "language": true, // language is a marker modeline option for other tools } + disallowedOptions = map[string]bool{ + "dev": true, + "wait": true, + "logs": true, + "sync": true, + } // file options must be considered relative to the source files they belong to fileOptions = map[string]bool{ @@ -116,6 +122,10 @@ func createKamelWithModelineCommand(ctx context.Context, args []string, processe return nil, nil, errors.Wrapf(err, "cannot process file %s", f) } for i, o := range ops { + if disallowedOptions[o.Name] { + return nil, nil, fmt.Errorf("option %q is disallowed in modeline", o.Name) + } + if fileOptions[o.Name] && isLocal(f) { refPath := o.Value if !filepath.IsAbs(refPath) { @@ -157,8 +167,12 @@ func createKamelWithModelineCommand(ctx context.Context, args []string, processe if len(o.Name) > 1 { prefix = "--" } - args = append(args, fmt.Sprintf("%s%s", prefix, o.Name)) - args = append(args, o.Value) + // Using the k=v syntax to avoid issues with booleans + if len(o.Value) > 0 { + args = append(args, fmt.Sprintf("%s%s=%s", prefix, o.Name, o.Value)) + } else { + args = append(args, fmt.Sprintf("%s%s", prefix, o.Name)) + } } return createKamelWithModelineCommand(ctx, args, processedFiles) diff --git a/pkg/cmd/modeline_test.go b/pkg/cmd/modeline_test.go index 09ff8c37ea..20e91bd038 100644 --- a/pkg/cmd/modeline_test.go +++ b/pkg/cmd/modeline_test.go @@ -42,7 +42,7 @@ func TestModelineRunSimple(t *testing.T) { cmd, flags, err := NewKamelWithModelineCommand(context.TODO(), []string{"kamel", "run", fileName}) assert.NoError(t, err) assert.NotNil(t, cmd) - assert.Equal(t, []string{"run", fileName, "--dependency", "mvn:org.my/lib:1.0"}, flags) + assert.Equal(t, []string{"run", fileName, "--dependency=mvn:org.my/lib:1.0"}, flags) } func TestModelineRunHelp(t *testing.T) { @@ -73,7 +73,7 @@ func TestModelineRunChain(t *testing.T) { cmd, flags, err := NewKamelWithModelineCommand(context.TODO(), []string{"kamel", "run", "-d", "mvn:org.my/lib2:1.0", fileName}) assert.NoError(t, err) assert.NotNil(t, cmd) - assert.Equal(t, []string{"run", "-d", "mvn:org.my/lib2:1.0", fileName, "--dependency", "mvn:org.my/lib:2.0"}, flags) + assert.Equal(t, []string{"run", "-d", "mvn:org.my/lib2:1.0", fileName, "--dependency=mvn:org.my/lib:2.0"}, flags) } func TestModelineRunMultipleFiles(t *testing.T) { @@ -98,7 +98,7 @@ func TestModelineRunMultipleFiles(t *testing.T) { cmd, flags, err := NewKamelWithModelineCommand(context.TODO(), []string{"kamel", "run", fileName}) assert.NoError(t, err) assert.NotNil(t, cmd) - assert.Equal(t, []string{"run", fileName, "--source", fileName2, "--dependency", "mvn:org.my/lib:3.0"}, flags) + assert.Equal(t, []string{"run", fileName, "--source=" + fileName2, "--dependency=mvn:org.my/lib:3.0"}, flags) } func TestModelineRunPropertyFiles(t *testing.T) { @@ -127,5 +127,5 @@ func TestModelineRunPropertyFiles(t *testing.T) { cmd, flags, err := NewKamelWithModelineCommand(context.TODO(), []string{"kamel", "run", fileName}) assert.NoError(t, err) assert.NotNil(t, cmd) - assert.Equal(t, []string{"run", fileName, "--property-file", propFileName}, flags) + assert.Equal(t, []string{"run", fileName, "--property-file=" + propFileName}, flags) } diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go index 0ff0b1526d..35592bde14 100644 --- a/pkg/cmd/root.go +++ b/pkg/cmd/root.go @@ -35,16 +35,21 @@ superpowers. // RootCmdOptions -- type RootCmdOptions struct { - Context context.Context `mapstructure:"-"` - _client client.Client `mapstructure:"-"` - KubeConfig string `mapstructure:"kube-config"` - Namespace string `mapstructure:"namespace"` + RootContext context.Context `mapstructure:"-"` + Context context.Context `mapstructure:"-"` + ContextCancel context.CancelFunc `mapstructure:"-"` + _client client.Client `mapstructure:"-"` + KubeConfig string `mapstructure:"kube-config"` + Namespace string `mapstructure:"namespace"` } // NewKamelCommand -- func NewKamelCommand(ctx context.Context) (*cobra.Command, error) { + childCtx, childCancel := context.WithCancel(ctx) options := RootCmdOptions{ - Context: ctx, + RootContext: ctx, + Context: childCtx, + ContextCancel: childCancel, } var err error diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go index deb845bbf9..5c7e4c3065 100644 --- a/pkg/cmd/run.go +++ b/pkg/cmd/run.go @@ -280,6 +280,10 @@ func (o *runCmdOptions) run(cmd *cobra.Command, args []string) error { signal.Notify(cs, os.Interrupt, syscall.SIGTERM) go func() { <-cs + if o.Context.Err() != nil { + // Context canceled + return + } fmt.Printf("Run integration terminating\n") err := DeleteIntegration(o.Context, c, integration.Name, integration.Namespace) if err != nil { @@ -291,7 +295,7 @@ func (o *runCmdOptions) run(cmd *cobra.Command, args []string) error { } if o.Sync || o.Dev { - err = o.syncIntegration(c, args, catalog) + err = o.syncIntegration(cmd, c, args, catalog) if err != nil { return err } @@ -338,9 +342,9 @@ func (o *runCmdOptions) run(cmd *cobra.Command, args []string) error { } } - if o.Sync && !o.Logs && !o.Dev { + if o.Sync || o.Logs || o.Dev { // Let's add a Wait point, otherwise the script terminates - <-o.Context.Done() + <-o.RootContext.Done() } return nil @@ -387,7 +391,7 @@ func (o *runCmdOptions) waitForIntegrationReady(cmd *cobra.Command, integration return watch.HandleIntegrationStateChanges(o.Context, integration, handler) } -func (o *runCmdOptions) syncIntegration(c client.Client, sources []string, catalog *trait.Catalog) error { +func (o *runCmdOptions) syncIntegration(cmd *cobra.Command, c client.Client, sources []string, catalog *trait.Catalog) error { // Let's watch all relevant files when in dev mode var files []string files = append(files, sources...) @@ -408,7 +412,9 @@ func (o *runCmdOptions) syncIntegration(c client.Client, sources []string, catal return case <-changes: // let's create a new command to parse modeline changes and update our integration - newCmd, _, err := createKamelWithModelineCommand(o.Context, os.Args[1:], make(map[string]bool)) + newCmd, _, err := createKamelWithModelineCommand(o.RootContext, os.Args[1:], make(map[string]bool)) + newCmd.SetOut(cmd.OutOrStdout()) + newCmd.SetErr(cmd.ErrOrStderr()) if err != nil { fmt.Println("Unable to sync integration: ", err.Error()) continue @@ -420,6 +426,10 @@ func (o *runCmdOptions) syncIntegration(c client.Client, sources []string, catal return err } newCmd.PostRunE = nil + + // cancel the existing command to release watchers + o.ContextCancel() + // run the new one err = newCmd.Execute() if err != nil { fmt.Println("Unable to sync integration: ", err.Error())