You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by lb...@apache.org on 2018/09/18 16:01:21 UTC
[camel-k] 01/03: Add sync and dev mode
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...@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)
+}