Skip to content

Commit

Permalink
introduce experimental watch command (skeletton)
Browse files Browse the repository at this point in the history
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
  • Loading branch information
ndeloof committed Jan 12, 2023
1 parent 4ad8746 commit 6a44f03
Show file tree
Hide file tree
Showing 14 changed files with 284 additions and 6 deletions.
31 changes: 31 additions & 0 deletions cmd/compose/alpha.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
Copyright 2020 Docker Compose CLI authors
Licensed 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 compose

import (
"github.com/docker/compose/v2/pkg/api"
"github.com/spf13/cobra"
)

// alphaCommand groups all experimental subcommands
func alphaCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
cmd := &cobra.Command{
Short: "Experimental commands",
Use: "alpha [COMMAND]",
Hidden: true,
}
cmd.AddCommand(watchCommand(p, backend))
return cmd
}
2 changes: 2 additions & 0 deletions cmd/compose/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,9 @@ func RootCommand(streams api.Streams, backend api.Service) *cobra.Command { //no
pullCommand(&opts, backend),
createCommand(&opts, backend),
copyCommand(&opts, backend),
alphaCommand(&opts, backend),
)

c.Flags().SetInterspersed(false)
opts.addProjectFlags(c.Flags())
c.RegisterFlagCompletionFunc( //nolint:errcheck
Expand Down
61 changes: 61 additions & 0 deletions cmd/compose/watch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
Copyright 2020 Docker Compose CLI authors
Licensed 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 compose

import (
"context"
"fmt"
"os"

"github.com/docker/compose/v2/pkg/api"
"github.com/spf13/cobra"
)

type watchOptions struct {
*ProjectOptions
quiet bool
}

func watchCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
opts := watchOptions{
ProjectOptions: p,
}
cmd := &cobra.Command{
Use: "watch [SERVICE...]",
Short: "EXPERIMENTAL - Watch build context for service and rebuild/refresh containers when files are updated",
PreRunE: Adapt(func(ctx context.Context, args []string) error {
return nil
}),
RunE: Adapt(func(ctx context.Context, args []string) error {
return runWatch(ctx, backend, opts, args)
}),
ValidArgsFunction: completeServiceNames(p),
}

cmd.Flags().BoolVar(&opts.quiet, "quiet", false, "hide build output")
return cmd
}

func runWatch(ctx context.Context, backend api.Service, opts watchOptions, services []string) error {
fmt.Fprintln(os.Stderr, "watch command is EXPERIMENTAL")
project, err := opts.ToProject(nil)
if err != nil {
return err
}

return backend.Watch(ctx, project, services, api.WatchOptions{})
}
1 change: 1 addition & 0 deletions docs/reference/compose.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Docker Compose

| Name | Description |
|:--------------------------------|:------------------------------------------------------------------------|
| [`alpha`](compose_alpha.md) | Experimental commands |
| [`build`](compose_build.md) | Build or rebuild services |
| [`convert`](compose_convert.md) | Converts the compose file to platform's canonical format |
| [`cp`](compose_cp.md) | Copy files/folders between a service container and the local filesystem |
Expand Down
15 changes: 15 additions & 0 deletions docs/reference/compose_alpha.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# docker compose alpha

<!---MARKER_GEN_START-->
Experimental commands

### Subcommands

| Name | Description |
|:----------------------------------|:-----------------------------------------------------------------------------------------------------|
| [`watch`](compose_alpha_watch.md) | EXPERIMENTAL - Watch build context for service and rebuild/refresh containers when files are updated |



<!---MARKER_GEN_END-->

14 changes: 14 additions & 0 deletions docs/reference/compose_alpha_watch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# docker compose alpha watch

<!---MARKER_GEN_START-->
EXPERIMENTAL - Watch build context for service and rebuild/refresh containers when files are updated

### Options

| Name | Type | Default | Description |
|:----------|:-----|:--------|:------------------|
| `--quiet` | | | hide build output |


<!---MARKER_GEN_END-->

15 changes: 15 additions & 0 deletions docs/reference/docker_compose_alpha.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
command: docker compose alpha
short: Experimental commands
long: Experimental commands
pname: docker compose
plink: docker_compose.yaml
cname:
- docker compose alpha watch
clink:
- docker_compose_alpha_watch.yaml
deprecated: false
experimental: false
experimentalcli: false
kubernetes: false
swarm: false

25 changes: 25 additions & 0 deletions docs/reference/docker_compose_alpha_watch.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
command: docker compose alpha watch
short: |
EXPERIMENTAL - Watch build context for service and rebuild/refresh containers when files are updated
long: |
EXPERIMENTAL - Watch build context for service and rebuild/refresh containers when files are updated
usage: docker compose alpha watch [SERVICE...]
pname: docker compose alpha
plink: docker_compose_alpha.yaml
options:
- option: quiet
value_type: bool
default_value: "false"
description: hide build output
deprecated: false
hidden: false
experimental: false
experimentalcli: false
kubernetes: false
swarm: false
deprecated: false
experimental: false
experimentalcli: false
kubernetes: false
swarm: false

9 changes: 6 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ require (
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/miekg/pkcs11 v1.1.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/mapstructure v1.5.0
github.com/moby/locker v1.0.1 // indirect
github.com/moby/patternmatcher v0.5.0 // indirect
github.com/moby/spdystream v0.2.0 // indirect
Expand Down Expand Up @@ -119,7 +119,7 @@ require (
golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88 // indirect
golang.org/x/net v0.4.0 // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/sys v0.3.0 // indirect
golang.org/x/sys v0.4.0 // indirect
golang.org/x/term v0.3.0 // indirect
golang.org/x/text v0.6.0 // indirect
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
Expand All @@ -137,7 +137,10 @@ require (
sigs.k8s.io/yaml v1.2.0 // indirect
)

require github.com/cucumber/godog v0.0.0-00010101000000-000000000000
require (
github.com/cucumber/godog v0.0.0-00010101000000-000000000000
github.com/fsnotify/fsnotify v1.6.0
)

require (
github.com/bugsnag/bugsnag-go v1.5.0 // indirect
Expand Down
8 changes: 5 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,9 @@ github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoD
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo=
github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
github.com/getsentry/raven-go v0.0.0-20180121060056-563b81fc02b7/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
Expand Down Expand Up @@ -903,8 +904,9 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
Expand Down
6 changes: 6 additions & 0 deletions pkg/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ type Service interface {
Images(ctx context.Context, projectName string, options ImagesOptions) ([]ImageSummary, error)
// MaxConcurrency defines upper limit for concurrent operations against engine API
MaxConcurrency(parallel int)
// Watch services' development context and sync/notify/rebuild/restart on changes
Watch(ctx context.Context, project *types.Project, services []string, options WatchOptions) error
}

// WatchOptions group options of the Watch API
type WatchOptions struct {
}

// BuildOptions group options of the Build API
Expand Down
10 changes: 10 additions & 0 deletions pkg/api/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type ServiceProxy struct {
EventsFn func(ctx context.Context, project string, options EventsOptions) error
PortFn func(ctx context.Context, project string, service string, port uint16, options PortOptions) (string, int, error)
ImagesFn func(ctx context.Context, projectName string, options ImagesOptions) ([]ImageSummary, error)
WatchFn func(ctx context.Context, project *types.Project, services []string, options WatchOptions) error
MaxConcurrencyFn func(parallel int)
interceptors []Interceptor
}
Expand Down Expand Up @@ -88,6 +89,7 @@ func (s *ServiceProxy) WithService(service Service) *ServiceProxy {
s.EventsFn = service.Events
s.PortFn = service.Port
s.ImagesFn = service.Images
s.WatchFn = service.Watch
s.MaxConcurrencyFn = service.MaxConcurrency
return s
}
Expand Down Expand Up @@ -311,6 +313,14 @@ func (s *ServiceProxy) Images(ctx context.Context, project string, options Image
return s.ImagesFn(ctx, project, options)
}

// Watch implements Service interface
func (s *ServiceProxy) Watch(ctx context.Context, project *types.Project, services []string, options WatchOptions) error {
if s.WatchFn == nil {
return ErrNotImplemented
}
return s.WatchFn(ctx, project, services, options)
}

func (s *ServiceProxy) MaxConcurrency(i int) {
s.MaxConcurrencyFn(i)
}
79 changes: 79 additions & 0 deletions pkg/compose/watch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
Copyright 2020 Docker Compose CLI authors
Licensed 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 compose

import (
"context"
"fmt"
"log"

"github.com/compose-spec/compose-go/types"
"github.com/docker/compose/v2/pkg/api"
"github.com/fsnotify/fsnotify"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
)

type DevelopmentConfig struct {
}

func (s *composeService) Watch(ctx context.Context, project *types.Project, services []string, options api.WatchOptions) error {
fmt.Fprintln(s.stderr(), "not implemented yet")

eg, ctx := errgroup.WithContext(ctx)
err := project.WithServices(services, func(service types.ServiceConfig) error {
var config DevelopmentConfig
if y, ok := service.Extensions["x-develop"]; ok {
err := mapstructure.Decode(y, &config)
if err != nil {
return err
}
}
if service.Build == nil {
return errors.New("can't watch a service without a build section")
}
context := service.Build.Context

watcher, err := fsnotify.NewWatcher()
if err != nil {
return err
}
fmt.Println("watching " + context)
err = watcher.Add(context)
if err != nil {
return err
}
eg.Go(func() error {
defer watcher.Close() //nolint:errcheck
for {
select {
case <-ctx.Done():
return nil
case event := <-watcher.Events:
log.Println("fs event :", event.String())
case err := <-watcher.Errors:
return err
}
}
})
return nil
})
if err != nil {
return err
}

return eg.Wait()
}
14 changes: 14 additions & 0 deletions pkg/mocks/mock_docker_compose_api.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 6a44f03

Please sign in to comment.