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

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

commit 14f411996fcfdb14ca9c5c432415e84ef317a98a
Author: nferraro <ni.ferr...@gmail.com>
AuthorDate: Tue Sep 18 15:58:34 2018 +0200

    Add sync and dev mode
---
 Gopkg.lock                                  |  9 ++++
 cmd/camel-k-operator/kamel_k_operator.go    |  3 ++
 cmd/kamel/kamel.go                          |  4 ++
 pkg/client/cmd/run.go                       | 54 +++++++++++++++++++++---
 cmd/kamel/kamel.go => pkg/util/sync/file.go | 48 +++++++++++++--------
 pkg/util/sync/file_test.go                  | 65 +++++++++++++++++++++++++++++
 6 files changed, 160 insertions(+), 23 deletions(-)

diff --git a/Gopkg.lock b/Gopkg.lock
index 823b59c..a1699bb 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -318,6 +318,14 @@
   revision = "05ee40e3a273f7245e8777337fc7b46e533a9a92"
 
 [[projects]]
+  digest = "1:669828a2363f1ecad15fff9f008dd1d07d449fb25c9060998b15f83fec896458"
+  name = "github.com/radovskyb/watcher"
+  packages = ["."]
+  pruneopts = "NUT"
+  revision = "6145e1439b9de93806925353403f91d2abbad8a5"
+  version = "v1.0.2"
+
+[[projects]]
   digest = "1:0975c74a2cd70df6c2ae353c6283a25ce759dda7e1e706e5c07458baf3faca22"
   name = "github.com/rs/xid"
   packages = ["."]
@@ -719,6 +727,7 @@
     "github.com/operator-framework/operator-sdk/pkg/util/k8sutil",
     "github.com/operator-framework/operator-sdk/version",
     "github.com/pkg/errors",
+    "github.com/radovskyb/watcher",
     "github.com/rs/xid",
     "github.com/sirupsen/logrus",
     "github.com/spf13/cobra",
diff --git a/cmd/camel-k-operator/kamel_k_operator.go 
b/cmd/camel-k-operator/kamel_k_operator.go
index ff9e088..32ee754 100644
--- a/cmd/camel-k-operator/kamel_k_operator.go
+++ b/cmd/camel-k-operator/kamel_k_operator.go
@@ -19,6 +19,7 @@ package main
 
 import (
        "context"
+       "math/rand"
        "runtime"
        "time"
 
@@ -45,6 +46,8 @@ func watch(resource string, kind string, namespace string, 
resyncPeriod time.Dur
 }
 
 func main() {
+       rand.Seed(time.Now().UTC().UnixNano())
+
        printVersion()
 
        sdk.ExposeMetricsPort()
diff --git a/cmd/kamel/kamel.go b/cmd/kamel/kamel.go
index b1cba54..6c0fff2 100644
--- a/cmd/kamel/kamel.go
+++ b/cmd/kamel/kamel.go
@@ -21,11 +21,15 @@ import (
        "fmt"
        "github.com/apache/camel-k/pkg/client/cmd"
        _ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
+       "math/rand"
        "os"
        "context"
+       "time"
 )
 
 func main() {
+       rand.Seed(time.Now().UTC().UnixNano())
+
        ctx := context.Background()
        rootCmd, err := cmd.NewKamelCommand(ctx)
        exitOnError(err)
diff --git a/pkg/client/cmd/run.go b/pkg/client/cmd/run.go
index 22c0aa4..335cf84 100644
--- a/pkg/client/cmd/run.go
+++ b/pkg/client/cmd/run.go
@@ -20,6 +20,8 @@ package cmd
 import (
        "errors"
        "fmt"
+       "github.com/apache/camel-k/pkg/util/sync"
+       "github.com/sirupsen/logrus"
        "io/ioutil"
        "os"
        "strconv"
@@ -60,6 +62,8 @@ func NewCmdRun(rootCmdOptions *RootCmdOptions) *cobra.Command 
{
        cmd.Flags().StringSliceVar(&options.ConfigMaps, "configmap", nil, "Add 
a ConfigMap")
        cmd.Flags().StringSliceVar(&options.Secrets, "secret", nil, "Add a 
Secret")
        cmd.Flags().BoolVar(&options.Logs, "logs", false, "Print integration 
logs")
+       cmd.Flags().BoolVar(&options.Sync, "sync", false, "Synchronize the 
local source file with the cluster, republishing at each change")
+       cmd.Flags().BoolVar(&options.Dev, "dev", false, "Enable Dev mode 
(equivalent to \"-w --logs --sync\")")
 
        // completion support
        configureKnownCompletions(&cmd)
@@ -78,6 +82,8 @@ type runCmdOptions struct {
        Secrets            []string
        Wait               bool
        Logs               bool
+       Sync               bool
+       Dev                bool
 }
 
 func (*runCmdOptions) validateArgs(cmd *cobra.Command, args []string) error {
@@ -98,18 +104,29 @@ func (o *runCmdOptions) run(cmd *cobra.Command, args 
[]string) error {
        if err != nil {
                return err
        }
-       if o.Wait {
+       if o.Sync || o.Dev {
+               err = o.syncIntegration(args[0])
+               if err != nil {
+                       return err
+               }
+       }
+       if o.Wait || o.Dev {
                err = o.waitForIntegrationReady(integration)
                if err != nil {
                        return err
                }
        }
-       if o.Logs {
+       if o.Logs || o.Dev {
                err = o.printLogs(integration)
                if err != nil {
                        return err
                }
        }
+
+       if o.Sync && !o.Logs && !o.Dev {
+               // Let's add a wait point, otherwise the script terminates
+               <- o.Context.Done()
+       }
        return nil
 }
 
@@ -166,8 +183,33 @@ func (o *runCmdOptions) printLogs(integration 
*v1alpha1.Integration) error {
        return nil
 }
 
+func (o *runCmdOptions) syncIntegration(file string) error {
+       changes, err := sync.File(o.Context, file)
+       if err != nil {
+               return err
+       }
+       go func() {
+               for {
+                       select {
+                       case <- o.Context.Done():
+                               return
+                       case <- changes:
+                               _, err := o.updateIntegrationCode(file)
+                               if err != nil {
+                                       logrus.Error("Unable to sync 
integration: ", err)
+                               }
+                       }
+               }
+       }()
+       return nil
+}
+
 func (o *runCmdOptions) createIntegration(cmd *cobra.Command, args []string) 
(*v1alpha1.Integration, error) {
-       code, err := o.loadCode(args[0])
+       return o.updateIntegrationCode(args[0])
+}
+
+func (o *runCmdOptions) updateIntegrationCode(filename string) 
(*v1alpha1.Integration, error) {
+       code, err := o.loadCode(filename)
        if err != nil {
                return nil, err
        }
@@ -179,15 +221,15 @@ func (o *runCmdOptions) createIntegration(cmd 
*cobra.Command, args []string) (*v
                name = o.IntegrationName
                name = kubernetes.SanitizeName(name)
        } else {
-               name = kubernetes.SanitizeName(args[0])
+               name = kubernetes.SanitizeName(filename)
                if name == "" {
                        name = "integration"
                }
        }
 
-       codeName := args[0]
+       codeName := filename
 
-       if idx := strings.LastIndexByte(args[0], os.PathSeparator); idx > -1 {
+       if idx := strings.LastIndexByte(filename, os.PathSeparator); idx > -1 {
                codeName = codeName[idx+1:]
        }
 
diff --git a/cmd/kamel/kamel.go b/pkg/util/sync/file.go
similarity index 52%
copy from cmd/kamel/kamel.go
copy to pkg/util/sync/file.go
index b1cba54..1be83b8 100644
--- a/cmd/kamel/kamel.go
+++ b/pkg/util/sync/file.go
@@ -15,28 +15,42 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 */
 
-package main
+// Package sync provides useful tools to get notified when a file system 
resource changes
+package sync
 
 import (
-       "fmt"
-       "github.com/apache/camel-k/pkg/client/cmd"
-       _ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
-       "os"
        "context"
+       "github.com/radovskyb/watcher"
+       "github.com/sirupsen/logrus"
+       "time"
 )
 
-func main() {
-       ctx := context.Background()
-       rootCmd, err := cmd.NewKamelCommand(ctx)
-       exitOnError(err)
+// File returns a channel that signals each time the content of the file 
changes
+func File(ctx context.Context, path string) (<-chan bool, error) {
+       w := watcher.New()
+       if err := w.Add(path); err != nil {
+               return nil, err
+       }
+       w.FilterOps(watcher.Write)
 
-       err = rootCmd.Execute()
-       exitOnError(err)
-}
+       out := make(chan bool)
+       go func() {
+               for {
+                       select {
+                       case <-ctx.Done():
+                               return
+                       case <-w.Event:
+                               out <- true
+                       }
+               }
+       }()
 
-func exitOnError(err error) {
-       if err != nil {
-               fmt.Println("Error:", err)
-               os.Exit(1)
-       }
+       go func() {
+               if err := w.Start(200 * time.Millisecond); err != nil {
+                       logrus.Error("Error while starting watcher: ", err)
+                       close(out)
+               }
+       }()
+
+       return out, nil
 }
diff --git a/pkg/util/sync/file_test.go b/pkg/util/sync/file_test.go
new file mode 100644
index 0000000..266b55c
--- /dev/null
+++ b/pkg/util/sync/file_test.go
@@ -0,0 +1,65 @@
+/*
+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 sync
+
+import (
+       "context"
+       "github.com/stretchr/testify/assert"
+       "io/ioutil"
+       "math/rand"
+       "os"
+       "path"
+       "strconv"
+       "testing"
+       "time"
+)
+
+func TestFile(t *testing.T) {
+       tempdir := os.TempDir()
+       fileName := path.Join(tempdir, 
"camel-k-test-"+strconv.FormatUint(rand.Uint64(), 10))
+       _, err := os.Create(fileName)
+       assert.Nil(t, err)
+       defer os.Remove(fileName)
+
+       ctx, _ := context.WithDeadline(context.Background(), 
time.Now().Add(100*time.Second))
+       changes, err := File(ctx, fileName)
+       assert.Nil(t, err)
+
+       time.Sleep(100 * time.Millisecond)
+       expectedNumChanges := 3
+       for i := 0; i < expectedNumChanges; i++ {
+               ioutil.WriteFile(fileName, []byte("data-"+strconv.Itoa(i)), 
0777)
+               time.Sleep(350 * time.Millisecond)
+       }
+
+       numChanges := 0
+watch:
+       for {
+               select {
+               case <-ctx.Done():
+                       return
+               case <-changes:
+                       numChanges++
+                       if (numChanges == expectedNumChanges) {
+                               break watch
+                       }
+               }
+       }
+
+       assert.Equal(t, expectedNumChanges, numChanges)
+}

Reply via email to