introduce config --services, --volumes, --hash for backward compatibility

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2021-03-19 14:03:27 +01:00
parent 3366131096
commit ec5489a08c
No known key found for this signature in database
GPG Key ID: 9858809D6F8F6E7E
7 changed files with 87 additions and 27 deletions

View File

@ -22,6 +22,7 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"strings"
"github.com/cnabio/cnab-to-oci/remotes" "github.com/cnabio/cnab-to-oci/remotes"
"github.com/distribution/distribution/v3/reference" "github.com/distribution/distribution/v3/reference"
@ -32,6 +33,7 @@ import (
"github.com/docker/compose-cli/api/client" "github.com/docker/compose-cli/api/client"
"github.com/docker/compose-cli/api/compose" "github.com/docker/compose-cli/api/compose"
"github.com/docker/compose-cli/api/config" "github.com/docker/compose-cli/api/config"
"github.com/docker/compose-cli/utils"
) )
type convertOptions struct { type convertOptions struct {
@ -40,6 +42,9 @@ type convertOptions struct {
Output string Output string
quiet bool quiet bool
resolve bool resolve bool
services bool
volumes bool
hash string
} }
var addFlagsFuncs []func(cmd *cobra.Command, opts *convertOptions) var addFlagsFuncs []func(cmd *cobra.Command, opts *convertOptions)
@ -60,6 +65,16 @@ func convertCommand(p *projectOptions) *cobra.Command {
} }
os.Stdout = devnull os.Stdout = devnull
} }
if opts.services {
return runServices(opts)
}
if opts.volumes {
return runVolumes(opts)
}
if opts.hash != "" {
return runHash(opts)
}
return runConvert(cmd.Context(), opts, args) return runConvert(cmd.Context(), opts, args)
}, },
} }
@ -68,6 +83,10 @@ func convertCommand(p *projectOptions) *cobra.Command {
flags.BoolVar(&opts.resolve, "resolve-image-digests", false, "Pin image tags to digests.") flags.BoolVar(&opts.resolve, "resolve-image-digests", false, "Pin image tags to digests.")
flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Only validate the configuration, don't print anything.") flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Only validate the configuration, don't print anything.")
flags.BoolVar(&opts.services, "services", false, "Print the service names, one per line.")
flags.BoolVar(&opts.volumes, "volumes", false, "Print the volume names, one per line.")
flags.StringVar(&opts.hash, "hash", "", "Print the service config hash, one per line.")
// add flags for hidden backends // add flags for hidden backends
for _, f := range addFlagsFuncs { for _, f := range addFlagsFuncs {
f(cmd, &opts) f(cmd, &opts)
@ -126,3 +145,44 @@ func runConvert(ctx context.Context, opts convertOptions, services []string) err
_, err = fmt.Fprint(out, string(json)) _, err = fmt.Fprint(out, string(json))
return err return err
} }
func runServices(opts convertOptions) error {
project, err := opts.toProject(nil)
if err != nil {
return err
}
for _, s := range project.Services {
fmt.Println(s.Name)
}
return nil
}
func runVolumes(opts convertOptions) error {
project, err := opts.toProject(nil)
if err != nil {
return err
}
for _, v := range project.Volumes {
fmt.Println(v.Name)
}
return nil
}
func runHash(opts convertOptions) error {
var services []string
if opts.hash != "*" {
services = append(services, strings.Split(opts.hash, ",")...)
}
project, err := opts.toProject(services)
if err != nil {
return err
}
for _, s := range project.Services {
hash, err := utils.ServiceHash(s)
if err != nil {
return err
}
fmt.Printf("%s %s\n", s.Name, hash)
}
return nil
}

View File

@ -24,6 +24,8 @@ import (
"github.com/compose-spec/compose-go/types" "github.com/compose-spec/compose-go/types"
moby "github.com/docker/docker/api/types" moby "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/filters"
"github.com/docker/compose-cli/utils"
) )
// Containers is a set of moby Container // Containers is a set of moby Container
@ -69,14 +71,14 @@ type containerPredicate func(c moby.Container) bool
func isService(services ...string) containerPredicate { func isService(services ...string) containerPredicate {
return func(c moby.Container) bool { return func(c moby.Container) bool {
service := c.Labels[serviceLabel] service := c.Labels[serviceLabel]
return contains(services, service) return utils.StringContains(services, service)
} }
} }
func isNotService(services ...string) containerPredicate { func isNotService(services ...string) containerPredicate {
return func(c moby.Container) bool { return func(c moby.Container) bool {
service := c.Labels[serviceLabel] service := c.Labels[serviceLabel]
return !contains(services, service) return !utils.StringContains(services, service)
} }
} }

View File

@ -33,6 +33,7 @@ import (
"github.com/docker/compose-cli/api/compose" "github.com/docker/compose-cli/api/compose"
"github.com/docker/compose-cli/api/progress" "github.com/docker/compose-cli/api/progress"
status "github.com/docker/compose-cli/local/moby" status "github.com/docker/compose-cli/local/moby"
"github.com/docker/compose-cli/utils"
) )
const ( const (
@ -97,7 +98,7 @@ func (s *composeService) ensureService(ctx context.Context, project *types.Proje
return nil return nil
} }
expected, err := jsonHash(service) expected, err := utils.ServiceHash(service)
if err != nil { if err != nil {
return err return err
} }
@ -249,7 +250,7 @@ func (s *composeService) recreateContainer(ctx context.Context, project *types.P
// setDependentLifecycle define the Lifecycle strategy for all services to depend on specified service // setDependentLifecycle define the Lifecycle strategy for all services to depend on specified service
func setDependentLifecycle(project *types.Project, service string, strategy string) { func setDependentLifecycle(project *types.Project, service string, strategy string) {
for i, s := range project.Services { for i, s := range project.Services {
if contains(s.GetDependencies(), service) { if utils.StringContains(s.GetDependencies(), service) {
if s.Extensions == nil { if s.Extensions == nil {
s.Extensions = map[string]interface{}{} s.Extensions = map[string]interface{}{}
} }

View File

@ -40,6 +40,7 @@ import (
"github.com/docker/compose-cli/api/compose" "github.com/docker/compose-cli/api/compose"
"github.com/docker/compose-cli/api/progress" "github.com/docker/compose-cli/api/progress"
convert "github.com/docker/compose-cli/local/moby" convert "github.com/docker/compose-cli/local/moby"
"github.com/docker/compose-cli/utils"
) )
func (s *composeService) Create(ctx context.Context, project *types.Project, opts compose.CreateOptions) error { func (s *composeService) Create(ctx context.Context, project *types.Project, opts compose.CreateOptions) error {
@ -102,7 +103,7 @@ func (s *composeService) Create(ctx context.Context, project *types.Project, opt
prepareNetworkMode(project) prepareNetworkMode(project)
return InDependencyOrder(ctx, project, func(c context.Context, service types.ServiceConfig) error { return InDependencyOrder(ctx, project, func(c context.Context, service types.ServiceConfig) error {
if contains(opts.Services, service.Name) { if utils.StringContains(opts.Services, service.Name) {
return s.ensureService(c, project, service, opts.Recreate, opts.Inherit, opts.Timeout) return s.ensureService(c, project, service, opts.Recreate, opts.Inherit, opts.Timeout)
} }
return s.ensureService(c, project, service, opts.RecreateDependencies, opts.Inherit, opts.Timeout) return s.ensureService(c, project, service, opts.RecreateDependencies, opts.Inherit, opts.Timeout)
@ -121,7 +122,7 @@ func prepareVolumes(p *types.Project) error {
p.Services[i].DependsOn = make(types.DependsOnConfig, len(dependServices)) p.Services[i].DependsOn = make(types.DependsOnConfig, len(dependServices))
} }
for _, service := range p.Services { for _, service := range p.Services {
if contains(dependServices, service.Name) { if utils.StringContains(dependServices, service.Name) {
p.Services[i].DependsOn[service.Name] = types.ServiceDependency{ p.Services[i].DependsOn[service.Name] = types.ServiceDependency{
Condition: types.ServiceConditionStarted, Condition: types.ServiceConditionStarted,
} }
@ -196,7 +197,7 @@ func getImageName(service types.ServiceConfig, projectName string) string {
func (s *composeService) getCreateOptions(ctx context.Context, p *types.Project, service types.ServiceConfig, number int, inherit *moby.Container, func (s *composeService) getCreateOptions(ctx context.Context, p *types.Project, service types.ServiceConfig, number int, inherit *moby.Container,
autoRemove bool) (*container.Config, *container.HostConfig, *network.NetworkingConfig, error) { autoRemove bool) (*container.Config, *container.HostConfig, *network.NetworkingConfig, error) {
hash, err := jsonHash(service) hash, err := utils.ServiceHash(service)
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }

View File

@ -24,6 +24,8 @@ import (
"github.com/compose-spec/compose-go/types" "github.com/compose-spec/compose-go/types"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
"github.com/docker/compose-cli/utils"
) )
// ServiceStatus indicates the status of a service // ServiceStatus indicates the status of a service
@ -313,7 +315,7 @@ func (g *Graph) HasCycles() (bool, error) {
path := []string{ path := []string{
vertex.Key, vertex.Key,
} }
if !contains(discovered, vertex.Key) && !contains(finished, vertex.Key) { if !utils.StringContains(discovered, vertex.Key) && !utils.StringContains(finished, vertex.Key) {
var err error var err error
discovered, finished, err = g.visit(vertex.Key, path, discovered, finished) discovered, finished, err = g.visit(vertex.Key, path, discovered, finished)
@ -331,11 +333,11 @@ func (g *Graph) visit(key string, path []string, discovered []string, finished [
for _, v := range g.Vertices[key].Children { for _, v := range g.Vertices[key].Children {
path := append(path, v.Key) path := append(path, v.Key)
if contains(discovered, v.Key) { if utils.StringContains(discovered, v.Key) {
return nil, nil, fmt.Errorf("cycle found: %s", strings.Join(path, " -> ")) return nil, nil, fmt.Errorf("cycle found: %s", strings.Join(path, " -> "))
} }
if !contains(finished, v.Key) { if !utils.StringContains(finished, v.Key) {
if _, _, err := g.visit(v.Key, path, discovered, finished); err != nil { if _, _, err := g.visit(v.Key, path, discovered, finished); err != nil {
return nil, nil, err return nil, nil, err
} }

View File

@ -43,7 +43,7 @@ func (s *composeService) Logs(ctx context.Context, projectName string, consumer
} }
if len(options.Services) > 0 { if len(options.Services) > 0 {
ignore = func(s string) bool { ignore = func(s string) bool {
return !contains(options.Services, s) return !utils.StringContains(options.Services, s)
} }
} }

View File

@ -14,27 +14,21 @@
limitations under the License. limitations under the License.
*/ */
package compose package utils
import ( import (
"encoding/json" "encoding/json"
"github.com/compose-spec/compose-go/types"
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
) )
func jsonHash(o interface{}) (string, error) { // ServiceHash compute configuration has for a service
// TODO move this to compose-go
func ServiceHash(o types.ServiceConfig) (string, error) {
bytes, err := json.Marshal(o) bytes, err := json.Marshal(o)
if err != nil { if err != nil {
return "", err return "", err
} }
return digest.SHA256.FromBytes(bytes).String(), nil return digest.SHA256.FromBytes(bytes).Encoded(), nil
}
func contains(slice []string, item string) bool {
for _, v := range slice {
if v == item {
return true
}
}
return false
} }