From 57039425b6e7c01b3367a065c5e07f45990246a5 Mon Sep 17 00:00:00 2001 From: Charlie Drage Date: Tue, 3 Jan 2017 14:40:23 -0500 Subject: [PATCH 1/3] Update vendoring as well as libcompose This commit updates libcompose in order to merge in https://github.com/docker/libcompose/pull/423 which affected https://github.com/kubernetes-incubator/kompose/issues/92 by not erroring out when an image name wasn't provided. Closes https://github.com/kubernetes-incubator/kompose/issues/92 As well as knocks out the last required milestone for a 0.2.1 release https://github.com/kubernetes-incubator/kompose/milestone/2 --- glide.lock | 20 +- glide.yaml | 2 +- .../docker/libcompose/config/interpolation.go | 48 ++-- .../docker/libcompose/config/merge.go | 73 ++++- .../docker/libcompose/config/merge_v1.go | 17 +- .../docker/libcompose/config/merge_v2.go | 31 +-- .../docker/libcompose/config/types.go | 35 ++- .../docker/libcompose/config/validation.go | 69 ++--- .../docker/libcompose/lookup/composable.go | 4 +- .../docker/libcompose/lookup/envfile.go | 2 +- .../docker/libcompose/lookup/simple_env.go | 2 +- .../docker/libcompose/project/project.go | 10 +- .../libcompose/project/project_create.go | 3 + .../docker/libcompose/project/project_ps.go | 12 +- .../docker/libcompose/utils/util.go | 25 ++ .../docker/libcompose/yaml/types_yaml.go | 28 ++ vendor/github.com/fatih/structs/structs.go | 17 +- vendor/github.com/pelletier/go-toml/lexer.go | 20 +- vendor/github.com/spf13/afero/memmap.go | 22 +- vendor/github.com/spf13/cast/caste.go | 12 +- .../jwalterweatherman/default_notepad.go | 103 +++++++ .../spf13/jwalterweatherman/log_counter.go | 56 ++++ .../spf13/jwalterweatherman/notepad.go | 177 ++++++++++++ .../thatswhyyoualwaysleaveanote.go | 256 ------------------ .../github.com/xeipuuv/gojsonschema/errors.go | 21 +- .../xeipuuv/gojsonschema/jsonLoader.go | 4 +- 26 files changed, 640 insertions(+), 429 deletions(-) create mode 100644 vendor/github.com/spf13/jwalterweatherman/default_notepad.go create mode 100644 vendor/github.com/spf13/jwalterweatherman/log_counter.go create mode 100644 vendor/github.com/spf13/jwalterweatherman/notepad.go delete mode 100644 vendor/github.com/spf13/jwalterweatherman/thatswhyyoualwaysleaveanote.go diff --git a/glide.lock b/glide.lock index 8eea6d7c..77902429 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: c7cb14f4249738a47020f9dc1964832921c3f5b8bf5a1c50f5b2fa15eaebb6fe -updated: 2016-12-26T10:22:49.439519344+05:30 +hash: 88aef2926941901e180522117085c9a72141a988d1284778fc867f704e43dab0 +updated: 2017-01-03T14:38:14.561105912-05:00 imports: - name: cloud.google.com/go version: 3b1ae45394a234c385be014e9a488f2bb6eef821 @@ -190,7 +190,7 @@ imports: - name: github.com/docker/go-units version: 0bbddae09c5a5419a8c6dcdd7ff90da3d450393b - name: github.com/docker/libcompose - version: fbdac0a6a80837c63eb6c8f43514f7bb3f32df6c + version: 2e320f69cafc70683514ee6226d40e2fe868e6d3 subpackages: - config - logger @@ -210,7 +210,7 @@ imports: - name: github.com/evanphx/json-patch version: 465937c80b3c07a7c7ad20cc934898646a91c1de - name: github.com/fatih/structs - version: dc3312cb1a4513a366c4c9e622ad55c32df12ed3 + version: a720dfa8df582c51dee1b36feabb906bde1588bd - name: github.com/flynn/go-shlex version: 3f9db97f856818214da2e1057f8ad84803971cff - name: github.com/fsnotify/fsnotify @@ -405,7 +405,7 @@ imports: - name: github.com/pelletier/go-buffruneio version: df1e16fde7fc330a0ca68167c23bf7ed6ac31d6d - name: github.com/pelletier/go-toml - version: 017119f7a78a0b5fc0ea39ef6be09f03acf3345d + version: 439fbba1f887c286024370cb4f281ba815c4c7d7 - name: github.com/prometheus/client_golang version: e51041b3fa41cece0dca035740ba6411905be473 subpackages: @@ -425,15 +425,15 @@ imports: - name: github.com/Sirupsen/logrus version: 881bee4e20a5d11a6a88a5667c6f292072ac1963 - name: github.com/spf13/afero - version: 2f30b2a92c0e5700bcfe4715891adb1f2a7a406d + version: 90dd71edc4d0a8b3511dc12ea15d617d03be09e0 subpackages: - mem - name: github.com/spf13/cast - version: 24b6558033ffe202bf42f0f3b870dcc798dd2ba8 + version: 56a7ecbeb18dde53c6db4bd96b541fd9741b8d44 - name: github.com/spf13/cobra - version: b62566898a99f2db9c68ed0026aa0a052e59678d + version: 1dd5ff2e11b6dca62fdcb275eb804b94607d8b06 - name: github.com/spf13/jwalterweatherman - version: 33c24e77fb80341fe7130ee7c594256ff08ccc46 + version: c3ba57c1a2668b9484e43bf9932c88f71992f977 - name: github.com/spf13/pflag version: 25f8b5b07aece3207895bf19f7ab517eb3b22a40 - name: github.com/spf13/viper @@ -447,7 +447,7 @@ imports: - name: github.com/xeipuuv/gojsonreference version: e02fc20de94c78484cd5ffb007f8af96be030a45 - name: github.com/xeipuuv/gojsonschema - version: 59f99ebfe5f712a0055e321231fc3be94e4e00b2 + version: f06f290571ce81ab347174c6f7ad2e1865af41a7 - name: golang.org/x/net version: e90d6d0afc4c315a0d87a568ae68577cc15149a0 subpackages: diff --git a/glide.yaml b/glide.yaml index 491060be..1af47f13 100644 --- a/glide.yaml +++ b/glide.yaml @@ -11,7 +11,7 @@ import: - package: github.com/spf13/viper - package: github.com/docker/libcompose - version: fbdac0a6a80837c63eb6c8f43514f7bb3f32df6c + version: 2e320f69cafc70683514ee6226d40e2fe868e6d3 subpackages: - config - lookup diff --git a/vendor/github.com/docker/libcompose/config/interpolation.go b/vendor/github.com/docker/libcompose/config/interpolation.go index fc420de9..66c987a7 100644 --- a/vendor/github.com/docker/libcompose/config/interpolation.go +++ b/vendor/github.com/docker/libcompose/config/interpolation.go @@ -102,7 +102,7 @@ func parseLine(line string, mapping func(string) string) (string, bool) { return buffer.String(), true } -func parseConfig(option, service string, data *interface{}, mapping func(string) string) error { +func parseConfig(key string, data *interface{}, mapping func(string) string) error { switch typedData := (*data).(type) { case string: var success bool @@ -110,11 +110,11 @@ func parseConfig(option, service string, data *interface{}, mapping func(string) *data, success = parseLine(typedData, mapping) if !success { - return fmt.Errorf("Invalid interpolation format for \"%s\" option in service \"%s\": \"%s\"", option, service, typedData) + return fmt.Errorf("Invalid interpolation format for key \"%s\": \"%s\"", key, typedData) } case []interface{}: for k, v := range typedData { - err := parseConfig(option, service, &v, mapping) + err := parseConfig(key, &v, mapping) if err != nil { return err @@ -124,7 +124,7 @@ func parseConfig(option, service string, data *interface{}, mapping func(string) } case map[interface{}]interface{}: for k, v := range typedData { - err := parseConfig(option, service, &v, mapping) + err := parseConfig(key, &v, mapping) if err != nil { return err @@ -137,33 +137,21 @@ func parseConfig(option, service string, data *interface{}, mapping func(string) return nil } -// Interpolate replaces variables in the raw map representation of the project file -func Interpolate(environmentLookup EnvironmentLookup, config *RawServiceMap) error { - for k, v := range *config { - for k2, v2 := range v { - err := parseConfig(k2, k, &v2, func(s string) string { - values := environmentLookup.Lookup(s, k, nil) +// Interpolate replaces variables in a map entry +func Interpolate(key string, data *interface{}, environmentLookup EnvironmentLookup) error { + return parseConfig(key, data, func(s string) string { + values := environmentLookup.Lookup(s, nil) - if len(values) == 0 { - logrus.Warnf("The %s variable is not set. Substituting a blank string.", s) - return "" - } - - // Use first result if many are given - value := values[0] - - // Environment variables come in key=value format - // Return everything past first '=' - return strings.SplitN(value, "=", 2)[1] - }) - - if err != nil { - return err - } - - (*config)[k][k2] = v2 + if len(values) == 0 { + logrus.Warnf("The %s variable is not set. Substituting a blank string.", s) + return "" } - } - return nil + // Use first result if many are given + value := values[0] + + // Environment variables come in key=value format + // Return everything past first '=' + return strings.SplitN(value, "=", 2)[1] + }) } diff --git a/vendor/github.com/docker/libcompose/config/merge.go b/vendor/github.com/docker/libcompose/config/merge.go index 1c56d7be..f40619d4 100644 --- a/vendor/github.com/docker/libcompose/config/merge.go +++ b/vendor/github.com/docker/libcompose/config/merge.go @@ -29,18 +29,8 @@ func CreateConfig(bytes []byte) (*Config, error) { if err := yaml.Unmarshal(bytes, &config); err != nil { return nil, err } - if config.Version == "2" { - for key, value := range config.Networks { - if value == nil { - config.Networks[key] = &NetworkConfig{} - } - } - for key, value := range config.Volumes { - if value == nil { - config.Volumes[key] = &VolumeConfig{} - } - } - } else { + + if config.Version != "2" { var baseRawServices RawServiceMap if err := yaml.Unmarshal(bytes, &baseRawServices); err != nil { return nil, err @@ -48,6 +38,13 @@ func CreateConfig(bytes []byte) (*Config, error) { config.Services = baseRawServices } + if config.Volumes == nil { + config.Volumes = make(map[string]interface{}) + } + if config.Networks == nil { + config.Networks = make(map[string]interface{}) + } + return &config, nil } @@ -63,6 +60,34 @@ func Merge(existingServices *ServiceConfigs, environmentLookup EnvironmentLookup } baseRawServices := config.Services + if options.Interpolate { + if err := InterpolateRawServiceMap(&baseRawServices, environmentLookup); err != nil { + return "", nil, nil, nil, err + } + + for k, v := range config.Volumes { + if err := Interpolate(k, &v, environmentLookup); err != nil { + return "", nil, nil, nil, err + } + config.Volumes[k] = v + } + + for k, v := range config.Networks { + if err := Interpolate(k, &v, environmentLookup); err != nil { + return "", nil, nil, nil, err + } + config.Networks[k] = v + } + } + + if options.Preprocess != nil { + var err error + baseRawServices, err = options.Preprocess(baseRawServices) + if err != nil { + return "", nil, nil, nil, err + } + } + var serviceConfigs map[string]*ServiceConfig if config.Version == "2" { var err error @@ -91,7 +116,29 @@ func Merge(existingServices *ServiceConfigs, environmentLookup EnvironmentLookup } } - return config.Version, serviceConfigs, config.Volumes, config.Networks, nil + var volumes map[string]*VolumeConfig + var networks map[string]*NetworkConfig + if err := utils.Convert(config.Volumes, &volumes); err != nil { + return "", nil, nil, nil, err + } + if err := utils.Convert(config.Networks, &networks); err != nil { + return "", nil, nil, nil, err + } + + return config.Version, serviceConfigs, volumes, networks, nil +} + +// InterpolateRawServiceMap replaces varialbse in raw service map struct based on environment lookup +func InterpolateRawServiceMap(baseRawServices *RawServiceMap, environmentLookup EnvironmentLookup) error { + for k, v := range *baseRawServices { + for k2, v2 := range v { + if err := Interpolate(k2, &v2, environmentLookup); err != nil { + return err + } + (*baseRawServices)[k][k2] = v2 + } + } + return nil } func adjustValues(configs map[string]*ServiceConfig) { diff --git a/vendor/github.com/docker/libcompose/config/merge_v1.go b/vendor/github.com/docker/libcompose/config/merge_v1.go index c1eeeae7..dab39144 100644 --- a/vendor/github.com/docker/libcompose/config/merge_v1.go +++ b/vendor/github.com/docker/libcompose/config/merge_v1.go @@ -10,20 +10,6 @@ import ( // MergeServicesV1 merges a v1 compose file into an existing set of service configs func MergeServicesV1(existingServices *ServiceConfigs, environmentLookup EnvironmentLookup, resourceLookup ResourceLookup, file string, datas RawServiceMap, options *ParseOptions) (map[string]*ServiceConfigV1, error) { - if options.Interpolate { - if err := Interpolate(environmentLookup, &datas); err != nil { - return nil, err - } - } - - if options.Preprocess != nil { - var err error - datas, err = options.Preprocess(datas) - if err != nil { - return nil, err - } - } - if options.Validate { if err := validate(datas); err != nil { return nil, err @@ -117,8 +103,7 @@ func parseV1(resourceLookup ResourceLookup, environmentLookup EnvironmentLookup, baseRawServices := config.Services if options.Interpolate { - err = Interpolate(environmentLookup, &baseRawServices) - if err != nil { + if err = InterpolateRawServiceMap(&baseRawServices, environmentLookup); err != nil { return nil, err } } diff --git a/vendor/github.com/docker/libcompose/config/merge_v2.go b/vendor/github.com/docker/libcompose/config/merge_v2.go index e9e5678b..1f7bbd34 100644 --- a/vendor/github.com/docker/libcompose/config/merge_v2.go +++ b/vendor/github.com/docker/libcompose/config/merge_v2.go @@ -3,6 +3,7 @@ package config import ( "fmt" "path" + "strings" "github.com/Sirupsen/logrus" "github.com/docker/libcompose/utils" @@ -10,20 +11,6 @@ import ( // MergeServicesV2 merges a v2 compose file into an existing set of service configs func MergeServicesV2(existingServices *ServiceConfigs, environmentLookup EnvironmentLookup, resourceLookup ResourceLookup, file string, datas RawServiceMap, options *ParseOptions) (map[string]*ServiceConfig, error) { - if options.Interpolate { - if err := Interpolate(environmentLookup, &datas); err != nil { - return nil, err - } - } - - if options.Preprocess != nil { - var err error - datas, err = options.Preprocess(datas) - if err != nil { - return nil, err - } - } - if options.Validate { if err := validateV2(datas); err != nil { return nil, err @@ -49,6 +36,19 @@ func MergeServicesV2(existingServices *ServiceConfigs, environmentLookup Environ datas[name] = data } + if options.Validate { + var errs []string + for name, data := range datas { + err := validateServiceConstraintsv2(data, name) + if err != nil { + errs = append(errs, err.Error()) + } + } + if len(errs) != 0 { + return nil, fmt.Errorf(strings.Join(errs, "\n")) + } + } + serviceConfigs := make(map[string]*ServiceConfig) if err := utils.Convert(datas, &serviceConfigs); err != nil { return nil, err @@ -108,8 +108,7 @@ func parseV2(resourceLookup ResourceLookup, environmentLookup EnvironmentLookup, baseRawServices := config.Services if options.Interpolate { - err = Interpolate(environmentLookup, &baseRawServices) - if err != nil { + if err = InterpolateRawServiceMap(&baseRawServices, environmentLookup); err != nil { return nil, err } } diff --git a/vendor/github.com/docker/libcompose/config/types.go b/vendor/github.com/docker/libcompose/config/types.go index d548e206..18291ac7 100644 --- a/vendor/github.com/docker/libcompose/config/types.go +++ b/vendor/github.com/docker/libcompose/config/types.go @@ -8,7 +8,7 @@ import ( // EnvironmentLookup defines methods to provides environment variable loading. type EnvironmentLookup interface { - Lookup(key, serviceName string, config *ServiceConfig) []string + Lookup(key string, config *ServiceConfig) []string } // ResourceLookup defines methods to provides file loading. @@ -30,22 +30,27 @@ type ServiceConfigV1 struct { ContainerName string `yaml:"container_name,omitempty"` Devices []string `yaml:"devices,omitempty"` DNS yaml.Stringorslice `yaml:"dns,omitempty"` + DNSOpts []string `yaml:"dns_opt,omitempty"` DNSSearch yaml.Stringorslice `yaml:"dns_search,omitempty"` Dockerfile string `yaml:"dockerfile,omitempty"` DomainName string `yaml:"domainname,omitempty"` Entrypoint yaml.Command `yaml:"entrypoint,flow,omitempty"` EnvFile yaml.Stringorslice `yaml:"env_file,omitempty"` Environment yaml.MaporEqualSlice `yaml:"environment,omitempty"` + GroupAdd []string `yaml:"group_add,omitempty"` Hostname string `yaml:"hostname,omitempty"` Image string `yaml:"image,omitempty"` + Isolation string `yaml:"isolation,omitempty"` Labels yaml.SliceorMap `yaml:"labels,omitempty"` Links yaml.MaporColonSlice `yaml:"links,omitempty"` LogDriver string `yaml:"log_driver,omitempty"` MacAddress string `yaml:"mac_address,omitempty"` - MemLimit yaml.StringorInt `yaml:"mem_limit,omitempty"` - MemSwapLimit yaml.StringorInt `yaml:"memswap_limit,omitempty"` + MemLimit yaml.MemStringorInt `yaml:"mem_limit,omitempty"` + MemSwapLimit yaml.MemStringorInt `yaml:"memswap_limit,omitempty"` + MemSwappiness yaml.MemStringorInt `yaml:"mem_swappiness,omitempty"` Name string `yaml:"name,omitempty"` Net string `yaml:"net,omitempty"` + OomScoreAdj yaml.StringorInt `yaml:"oom_score_adj,omitempty"` Pid string `yaml:"pid,omitempty"` Uts string `yaml:"uts,omitempty"` Ipc string `yaml:"ipc,omitempty"` @@ -53,9 +58,11 @@ type ServiceConfigV1 struct { Privileged bool `yaml:"privileged,omitempty"` Restart string `yaml:"restart,omitempty"` ReadOnly bool `yaml:"read_only,omitempty"` - ShmSize yaml.StringorInt `yaml:"shm_size,omitempty"` + ShmSize yaml.MemStringorInt `yaml:"shm_size,omitempty"` StdinOpen bool `yaml:"stdin_open,omitempty"` SecurityOpt []string `yaml:"security_opt,omitempty"` + StopSignal string `yaml:"stop_signal,omitempty"` + Tmpfs yaml.Stringorslice `yaml:"tmpfs,omitempty"` Tty bool `yaml:"tty,omitempty"` User string `yaml:"user,omitempty"` VolumeDriver string `yaml:"volume_driver,omitempty"` @@ -89,6 +96,7 @@ type ServiceConfig struct { Devices []string `yaml:"devices,omitempty"` DependsOn []string `yaml:"depends_on,omitempty"` DNS yaml.Stringorslice `yaml:"dns,omitempty"` + DNSOpts []string `yaml:"dns_opt,omitempty"` DNSSearch yaml.Stringorslice `yaml:"dns_search,omitempty"` DomainName string `yaml:"domainname,omitempty"` Entrypoint yaml.Command `yaml:"entrypoint,flow,omitempty"` @@ -98,23 +106,28 @@ type ServiceConfig struct { Extends yaml.MaporEqualSlice `yaml:"extends,omitempty"` ExternalLinks []string `yaml:"external_links,omitempty"` ExtraHosts []string `yaml:"extra_hosts,omitempty"` + GroupAdd []string `yaml:"group_add,omitempty"` Image string `yaml:"image,omitempty"` + Isolation string `yaml:"isolation,omitempty"` Hostname string `yaml:"hostname,omitempty"` Ipc string `yaml:"ipc,omitempty"` Labels yaml.SliceorMap `yaml:"labels,omitempty"` Links yaml.MaporColonSlice `yaml:"links,omitempty"` Logging Log `yaml:"logging,omitempty"` MacAddress string `yaml:"mac_address,omitempty"` - MemLimit yaml.StringorInt `yaml:"mem_limit,omitempty"` - MemSwapLimit yaml.StringorInt `yaml:"memswap_limit,omitempty"` + MemLimit yaml.MemStringorInt `yaml:"mem_limit,omitempty"` + MemSwapLimit yaml.MemStringorInt `yaml:"memswap_limit,omitempty"` + MemSwappiness yaml.MemStringorInt `yaml:"mem_swappiness,omitempty"` NetworkMode string `yaml:"network_mode,omitempty"` Networks *yaml.Networks `yaml:"networks,omitempty"` + OomScoreAdj yaml.StringorInt `yaml:"oom_score_adj,omitempty"` Pid string `yaml:"pid,omitempty"` Ports []string `yaml:"ports,omitempty"` Privileged bool `yaml:"privileged,omitempty"` SecurityOpt []string `yaml:"security_opt,omitempty"` - ShmSize yaml.StringorInt `yaml:"shm_size,omitempty"` + ShmSize yaml.MemStringorInt `yaml:"shm_size,omitempty"` StopSignal string `yaml:"stop_signal,omitempty"` + Tmpfs yaml.Stringorslice `yaml:"tmpfs,omitempty"` VolumeDriver string `yaml:"volume_driver,omitempty"` Volumes *yaml.Volumes `yaml:"volumes,omitempty"` VolumesFrom []string `yaml:"volumes_from,omitempty"` @@ -159,10 +172,10 @@ type NetworkConfig struct { // Config holds libcompose top level configuration type Config struct { - Version string `yaml:"version,omitempty"` - Services RawServiceMap `yaml:"services,omitempty"` - Volumes map[string]*VolumeConfig `yaml:"volumes,omitempty"` - Networks map[string]*NetworkConfig `yaml:"networks,omitempty"` + Version string `yaml:"version,omitempty"` + Services RawServiceMap `yaml:"services,omitempty"` + Volumes map[string]interface{} `yaml:"volumes,omitempty"` + Networks map[string]interface{} `yaml:"networks,omitempty"` } // NewServiceConfigs initializes a new Configs struct diff --git a/vendor/github.com/docker/libcompose/config/validation.go b/vendor/github.com/docker/libcompose/config/validation.go index 3f5c7c1a..a459c1ed 100644 --- a/vendor/github.com/docker/libcompose/config/validation.go +++ b/vendor/github.com/docker/libcompose/config/validation.go @@ -5,6 +5,7 @@ import ( "strconv" "strings" + "github.com/docker/libcompose/utils" "github.com/xeipuuv/gojsonschema" ) @@ -70,55 +71,22 @@ func getValue(val interface{}, context string) string { return "" } -// Converts map[interface{}]interface{} to map[string]interface{} recursively -// gojsonschema only accepts map[string]interface{} func convertServiceMapKeysToStrings(serviceMap RawServiceMap) RawServiceMap { newServiceMap := make(RawServiceMap) - for k, v := range serviceMap { newServiceMap[k] = convertServiceKeysToStrings(v) } - return newServiceMap } func convertServiceKeysToStrings(service RawService) RawService { newService := make(RawService) - for k, v := range service { - newService[k] = convertKeysToStrings(v) + newService[k] = utils.ConvertKeysToStrings(v) } - return newService } -func convertKeysToStrings(item interface{}) interface{} { - switch typedDatas := item.(type) { - - case map[interface{}]interface{}: - newMap := make(map[string]interface{}) - - for key, value := range typedDatas { - stringKey := key.(string) - newMap[stringKey] = convertKeysToStrings(value) - } - return newMap - - case []interface{}: - // newArray := make([]interface{}, 0) will cause golint to complain - var newArray []interface{} - newArray = make([]interface{}, 0) - - for _, value := range typedDatas { - newArray = append(newArray, convertKeysToStrings(value)) - } - return newArray - - default: - return item - } -} - var dockerConfigHints = map[string]string{ "cpu_share": "cpu_shares", "add_host": "extra_hosts", @@ -319,3 +287,36 @@ func validateServiceConstraints(service RawService, serviceName string) error { return nil } + +func validateServiceConstraintsv2(service RawService, serviceName string) error { + if err := setupSchemaLoaders(servicesSchemaDataV2, &schemaV2, &schemaLoaderV2, &constraintSchemaLoaderV2); err != nil { + return err + } + + service = convertServiceKeysToStrings(service) + + var validationErrors []string + + dataLoader := gojsonschema.NewGoLoader(service) + + result, err := gojsonschema.Validate(constraintSchemaLoaderV2, dataLoader) + if err != nil { + return err + } + + if !result.Valid() { + for _, err := range result.Errors() { + if err.Type() == "required" { + _, containsImage := service["image"] + _, containsBuild := service["build"] + + if containsBuild || !containsImage && !containsBuild { + validationErrors = append(validationErrors, fmt.Sprintf("Service '%s' has neither an image nor a build context specified. At least one must be provided.", serviceName)) + } + } + } + return fmt.Errorf(strings.Join(validationErrors, "\n")) + } + + return nil +} diff --git a/vendor/github.com/docker/libcompose/lookup/composable.go b/vendor/github.com/docker/libcompose/lookup/composable.go index c48987fe..ff76480b 100644 --- a/vendor/github.com/docker/libcompose/lookup/composable.go +++ b/vendor/github.com/docker/libcompose/lookup/composable.go @@ -13,10 +13,10 @@ type ComposableEnvLookup struct { // Lookup creates a string slice of string containing a "docker-friendly" environment string // in the form of 'key=value'. It loop through the lookups and returns the latest value if // more than one lookup return a result. -func (l *ComposableEnvLookup) Lookup(key, serviceName string, config *config.ServiceConfig) []string { +func (l *ComposableEnvLookup) Lookup(key string, config *config.ServiceConfig) []string { result := []string{} for _, lookup := range l.Lookups { - env := lookup.Lookup(key, serviceName, config) + env := lookup.Lookup(key, config) if len(env) == 1 { result = env } diff --git a/vendor/github.com/docker/libcompose/lookup/envfile.go b/vendor/github.com/docker/libcompose/lookup/envfile.go index 65bd9867..62241255 100644 --- a/vendor/github.com/docker/libcompose/lookup/envfile.go +++ b/vendor/github.com/docker/libcompose/lookup/envfile.go @@ -16,7 +16,7 @@ type EnvfileLookup struct { // Lookup creates a string slice of string containing a "docker-friendly" environment string // in the form of 'key=value'. It gets environment values using a '.env' file in the specified // path. -func (l *EnvfileLookup) Lookup(key, serviceName string, config *config.ServiceConfig) []string { +func (l *EnvfileLookup) Lookup(key string, config *config.ServiceConfig) []string { envs, err := opts.ParseEnvFile(l.Path) if err != nil { return []string{} diff --git a/vendor/github.com/docker/libcompose/lookup/simple_env.go b/vendor/github.com/docker/libcompose/lookup/simple_env.go index 6f8c25bf..40ce1284 100644 --- a/vendor/github.com/docker/libcompose/lookup/simple_env.go +++ b/vendor/github.com/docker/libcompose/lookup/simple_env.go @@ -15,7 +15,7 @@ type OsEnvLookup struct { // in the form of 'key=value'. It gets environment values using os.Getenv. // If the os environment variable does not exists, the slice is empty. serviceName and config // are not used at all in this implementation. -func (o *OsEnvLookup) Lookup(key, serviceName string, config *config.ServiceConfig) []string { +func (o *OsEnvLookup) Lookup(key string, config *config.ServiceConfig) []string { ret := os.Getenv(key) if ret == "" { return []string{} diff --git a/vendor/github.com/docker/libcompose/project/project.go b/vendor/github.com/docker/libcompose/project/project.go index d74398dd..48a42428 100644 --- a/vendor/github.com/docker/libcompose/project/project.go +++ b/vendor/github.com/docker/libcompose/project/project.go @@ -141,7 +141,7 @@ func (p *Project) CreateService(name string) (Service, error) { env = parts[0] } - for _, value := range p.context.EnvironmentLookup.Lookup(env, name, &config) { + for _, value := range p.context.EnvironmentLookup.Lookup(env, &config) { parsedEnv = append(parsedEnv, value) } } @@ -151,7 +151,7 @@ func (p *Project) CreateService(name string) (Service, error) { // check the environment for extra build Args that are set but not given a value in the compose file for arg, value := range config.Build.Args { if value == "\x00" { - envValue := p.context.EnvironmentLookup.Lookup(arg, name, &config) + envValue := p.context.EnvironmentLookup.Lookup(arg, &config) // depending on what we get back we do different things switch l := len(envValue); l { case 0: @@ -160,7 +160,7 @@ func (p *Project) CreateService(name string) (Service, error) { parts := strings.SplitN(envValue[0], "=", 2) config.Build.Args[parts[0]] = parts[1] default: - return nil, fmt.Errorf("Tried to set Build Arg %#v to multi-value %#v.", arg, envValue) + return nil, fmt.Errorf("tried to set Build Arg %#v to multi-value %#v", arg, envValue) } } } @@ -267,10 +267,12 @@ func (p *Project) handleNetworkConfig() { serviceConfig.Networks = &yaml.Networks{ Networks: []*yaml.Network{ { - Name: "default", + Name: "default", + RealName: fmt.Sprintf("%s_%s", p.Name, "default"), }, }, } + p.AddNetworkConfig("default", &config.NetworkConfig{}) } // Consolidate the name of the network // FIXME(vdemeester) probably shouldn't be there, maybe move that to interface/factory diff --git a/vendor/github.com/docker/libcompose/project/project_create.go b/vendor/github.com/docker/libcompose/project/project_create.go index 7efe2b3c..9141b719 100644 --- a/vendor/github.com/docker/libcompose/project/project_create.go +++ b/vendor/github.com/docker/libcompose/project/project_create.go @@ -14,6 +14,9 @@ func (p *Project) Create(ctx context.Context, options options.Create, services . if options.NoRecreate && options.ForceRecreate { return fmt.Errorf("no-recreate and force-recreate cannot be combined") } + if err := p.initialize(ctx); err != nil { + return err + } return p.perform(events.ProjectCreateStart, events.ProjectCreateDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) { wrapper.Do(wrappers, events.ServiceCreateStart, events.ServiceCreate, func(service Service) error { return service.Create(ctx, options) diff --git a/vendor/github.com/docker/libcompose/project/project_ps.go b/vendor/github.com/docker/libcompose/project/project_ps.go index f02c3416..2c69018b 100644 --- a/vendor/github.com/docker/libcompose/project/project_ps.go +++ b/vendor/github.com/docker/libcompose/project/project_ps.go @@ -1,13 +1,17 @@ package project -import ( - "golang.org/x/net/context" -) +import "golang.org/x/net/context" // Ps list containers for the specified services. func (p *Project) Ps(ctx context.Context, services ...string) (InfoSet, error) { allInfo := InfoSet{} - for _, name := range p.ServiceConfigs.Keys() { + + if len(services) == 0 { + services = p.ServiceConfigs.Keys() + } + + for _, name := range services { + service, err := p.CreateService(name) if err != nil { return nil, err diff --git a/vendor/github.com/docker/libcompose/utils/util.go b/vendor/github.com/docker/libcompose/utils/util.go index 51383cf3..971f9433 100644 --- a/vendor/github.com/docker/libcompose/utils/util.go +++ b/vendor/github.com/docker/libcompose/utils/util.go @@ -135,3 +135,28 @@ func Merge(coll1, coll2 []string) []string { } return r } + +// ConvertKeysToStrings converts map[interface{}] to map[string] recursively +func ConvertKeysToStrings(item interface{}) interface{} { + switch typedDatas := item.(type) { + case map[string]interface{}: + for key, value := range typedDatas { + typedDatas[key] = ConvertKeysToStrings(value) + } + return typedDatas + case map[interface{}]interface{}: + newMap := make(map[string]interface{}) + for key, value := range typedDatas { + stringKey := key.(string) + newMap[stringKey] = ConvertKeysToStrings(value) + } + return newMap + case []interface{}: + for i, value := range typedDatas { + typedDatas[i] = ConvertKeysToStrings(value) + } + return typedDatas + default: + return item + } +} diff --git a/vendor/github.com/docker/libcompose/yaml/types_yaml.go b/vendor/github.com/docker/libcompose/yaml/types_yaml.go index b3c1126c..5e75e5ec 100644 --- a/vendor/github.com/docker/libcompose/yaml/types_yaml.go +++ b/vendor/github.com/docker/libcompose/yaml/types_yaml.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/docker/docker/api/types/strslice" + "github.com/docker/go-units" ) // StringorInt represents a string or an integer. @@ -23,6 +24,7 @@ func (s *StringorInt) UnmarshalYAML(unmarshal func(interface{}) error) error { var stringType string if err := unmarshal(&stringType); err == nil { intType, err := strconv.ParseInt(stringType, 10, 64) + if err != nil { return err } @@ -33,6 +35,32 @@ func (s *StringorInt) UnmarshalYAML(unmarshal func(interface{}) error) error { return errors.New("Failed to unmarshal StringorInt") } +// MemStringorInt represents a string or an integer +// the String supports notations like 10m for then Megabyte of memory +type MemStringorInt int64 + +// UnmarshalYAML implements the Unmarshaller interface. +func (s *MemStringorInt) UnmarshalYAML(unmarshal func(interface{}) error) error { + var intType int64 + if err := unmarshal(&intType); err == nil { + *s = MemStringorInt(intType) + return nil + } + + var stringType string + if err := unmarshal(&stringType); err == nil { + intType, err := units.RAMInBytes(stringType) + + if err != nil { + return err + } + *s = MemStringorInt(intType) + return nil + } + + return errors.New("Failed to unmarshal MemStringorInt") +} + // Stringorslice represents // Using engine-api Strslice and augment it with YAML marshalling stuff. a string or an array of strings. type Stringorslice strslice.StrSlice diff --git a/vendor/github.com/fatih/structs/structs.go b/vendor/github.com/fatih/structs/structs.go index 06da6209..be3816ab 100644 --- a/vendor/github.com/fatih/structs/structs.go +++ b/vendor/github.com/fatih/structs/structs.go @@ -530,15 +530,22 @@ func (s *Struct) nested(val reflect.Value) interface{} { finalVal = m } case reflect.Map: - v := val.Type().Elem() - if v.Kind() == reflect.Ptr { - v = v.Elem() + // get the element type of the map + mapElem := val.Type() + switch val.Type().Kind() { + case reflect.Ptr, reflect.Array, reflect.Map, + reflect.Slice, reflect.Chan: + mapElem = val.Type().Elem() + if mapElem.Kind() == reflect.Ptr { + mapElem = mapElem.Elem() + } } // only iterate over struct types, ie: map[string]StructType, // map[string][]StructType, - if v.Kind() == reflect.Struct || - (v.Kind() == reflect.Slice && v.Elem().Kind() == reflect.Struct) { + if mapElem.Kind() == reflect.Struct || + (mapElem.Kind() == reflect.Slice && + mapElem.Elem().Kind() == reflect.Struct) { m := make(map[string]interface{}, val.Len()) for _, k := range val.MapKeys() { m[k.String()] = s.nested(val.MapIndex(k)) diff --git a/vendor/github.com/pelletier/go-toml/lexer.go b/vendor/github.com/pelletier/go-toml/lexer.go index 4b378d4e..4ba134c3 100644 --- a/vendor/github.com/pelletier/go-toml/lexer.go +++ b/vendor/github.com/pelletier/go-toml/lexer.go @@ -131,7 +131,7 @@ func (l *tomlLexer) lexVoid() tomlLexStateFn { case '[': return l.lexTableKey case '#': - return l.lexComment + return l.lexComment(l.lexVoid) case '=': return l.lexEqual case '\r': @@ -182,7 +182,7 @@ func (l *tomlLexer) lexRvalue() tomlLexStateFn { case '}': return l.lexRightCurlyBrace case '#': - return l.lexComment + return l.lexComment(l.lexRvalue) case '"': return l.lexString case '\'': @@ -309,15 +309,17 @@ func (l *tomlLexer) lexKey() tomlLexStateFn { return l.lexVoid } -func (l *tomlLexer) lexComment() tomlLexStateFn { - for next := l.peek(); next != '\n' && next != eof; next = l.peek() { - if next == '\r' && l.follow("\r\n") { - break +func (l *tomlLexer) lexComment(previousState tomlLexStateFn) tomlLexStateFn { + return func() tomlLexStateFn { + for next := l.peek(); next != '\n' && next != eof; next = l.peek() { + if next == '\r' && l.follow("\r\n") { + break + } + l.next() } - l.next() + l.ignore() + return previousState } - l.ignore() - return l.lexVoid } func (l *tomlLexer) lexLeftBracket() tomlLexStateFn { diff --git a/vendor/github.com/spf13/afero/memmap.go b/vendor/github.com/spf13/afero/memmap.go index 735bdafb..494ba545 100644 --- a/vendor/github.com/spf13/afero/memmap.go +++ b/vendor/github.com/spf13/afero/memmap.go @@ -128,14 +128,16 @@ func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error { m.mu.RUnlock() if ok { return &os.PathError{"mkdir", name, ErrFileExists} - } else { - m.mu.Lock() - item := mem.CreateDir(name) - m.getData()[name] = item - m.registerWithParent(item) - m.mu.Unlock() - m.Chmod(name, perm) } + + m.mu.Lock() + item := mem.CreateDir(name) + m.getData()[name] = item + m.registerWithParent(item) + m.mu.Unlock() + + m.Chmod(name, perm) + return nil } @@ -313,7 +315,10 @@ func (m *MemMapFs) Stat(name string) (os.FileInfo, error) { func (m *MemMapFs) Chmod(name string, mode os.FileMode) error { name = normalizePath(name) + + m.mu.RLock() f, ok := m.getData()[name] + m.mu.RUnlock() if !ok { return &os.PathError{"chmod", name, ErrFileNotFound} } @@ -327,7 +332,10 @@ func (m *MemMapFs) Chmod(name string, mode os.FileMode) error { func (m *MemMapFs) Chtimes(name string, atime time.Time, mtime time.Time) error { name = normalizePath(name) + + m.mu.RLock() f, ok := m.getData()[name] + m.mu.RUnlock() if !ok { return &os.PathError{"chtimes", name, ErrFileNotFound} } diff --git a/vendor/github.com/spf13/cast/caste.go b/vendor/github.com/spf13/cast/caste.go index 23f0fe8c..1aaa1ff8 100644 --- a/vendor/github.com/spf13/cast/caste.go +++ b/vendor/github.com/spf13/cast/caste.go @@ -18,15 +18,21 @@ import ( func ToTimeE(i interface{}) (tim time.Time, err error) { i = indirect(i) - switch s := i.(type) { + switch v := i.(type) { case time.Time: - return s, nil + return v, nil case string: - d, e := StringToDate(s) + d, e := StringToDate(v) if e == nil { return d, nil } return time.Time{}, fmt.Errorf("Could not parse Date/Time format: %v\n", e) + case int: + return time.Unix(int64(v), 0), nil + case int32: + return time.Unix(int64(v), 0), nil + case int64: + return time.Unix(v, 0), nil default: return time.Time{}, fmt.Errorf("Unable to Cast %#v to Time\n", i) } diff --git a/vendor/github.com/spf13/jwalterweatherman/default_notepad.go b/vendor/github.com/spf13/jwalterweatherman/default_notepad.go new file mode 100644 index 00000000..ea8003d9 --- /dev/null +++ b/vendor/github.com/spf13/jwalterweatherman/default_notepad.go @@ -0,0 +1,103 @@ +// Copyright © 2016 Steve Francia . +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +package jwalterweatherman + +import ( + "io" + "io/ioutil" + "log" + "os" +) + +var ( + TRACE *log.Logger + DEBUG *log.Logger + INFO *log.Logger + WARN *log.Logger + ERROR *log.Logger + CRITICAL *log.Logger + FATAL *log.Logger + + LOG *log.Logger + FEEDBACK *Feedback + + defaultNotepad *Notepad +) + +func reloadDefaultNotepad() { + TRACE = defaultNotepad.TRACE + DEBUG = defaultNotepad.DEBUG + INFO = defaultNotepad.INFO + WARN = defaultNotepad.WARN + ERROR = defaultNotepad.ERROR + CRITICAL = defaultNotepad.CRITICAL + FATAL = defaultNotepad.FATAL + + LOG = defaultNotepad.LOG + FEEDBACK = defaultNotepad.FEEDBACK +} + +func init() { + defaultNotepad = NewNotepad(LevelInfo, LevelTrace, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime) + reloadDefaultNotepad() +} + +// SetLogThreshold set the log threshold for the default notepad. Trace by default. +func SetLogThreshold(threshold Threshold) { + defaultNotepad.SetLogThreshold(threshold) + reloadDefaultNotepad() +} + +// SetLogOutput set the log output for the default notepad. Discarded by default. +func SetLogOutput(handle io.Writer) { + defaultNotepad.SetLogOutput(handle) + reloadDefaultNotepad() +} + +// SetStdoutThreshold set the standard output threshold for the default notepad. +// Info by default. +func SetStdoutThreshold(threshold Threshold) { + defaultNotepad.SetStdoutThreshold(threshold) + reloadDefaultNotepad() +} + +// SetPrefix set the prefix for the default logger. Empty by default. +func SetPrefix(prefix string) { + defaultNotepad.SetPrefix(prefix) + reloadDefaultNotepad() +} + +// SetFlags set the flags for the default logger. "log.Ldate | log.Ltime" by default. +func SetFlags(flags int) { + defaultNotepad.SetFlags(flags) + reloadDefaultNotepad() +} + +// Level returns the current global log threshold. +func LogThreshold() Threshold { + return defaultNotepad.logThreshold +} + +// Level returns the current global output threshold. +func StdoutThreshold() Threshold { + return defaultNotepad.stdoutThreshold +} + +// LogCountForLevel returns the number of log invocations for a given threshold. +func LogCountForLevel(l Threshold) uint64 { + return defaultNotepad.LogCountForLevel(l) +} + +// LogCountForLevelsGreaterThanorEqualTo returns the number of log invocations +// greater than or equal to a given threshold. +func LogCountForLevelsGreaterThanorEqualTo(threshold Threshold) uint64 { + return defaultNotepad.LogCountForLevelsGreaterThanorEqualTo(threshold) +} + +// ResetLogCounters resets the invocation counters for all levels. +func ResetLogCounters() { + defaultNotepad.ResetLogCounters() +} diff --git a/vendor/github.com/spf13/jwalterweatherman/log_counter.go b/vendor/github.com/spf13/jwalterweatherman/log_counter.go new file mode 100644 index 00000000..570db1d4 --- /dev/null +++ b/vendor/github.com/spf13/jwalterweatherman/log_counter.go @@ -0,0 +1,56 @@ +// Copyright © 2016 Steve Francia . +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +package jwalterweatherman + +import ( + "sync/atomic" +) + +type logCounter struct { + counter uint64 +} + +func (c *logCounter) incr() { + atomic.AddUint64(&c.counter, 1) +} + +func (c *logCounter) resetCounter() { + atomic.StoreUint64(&c.counter, 0) +} + +func (c *logCounter) getCount() uint64 { + return atomic.LoadUint64(&c.counter) +} + +func (c *logCounter) Write(p []byte) (n int, err error) { + c.incr() + + return len(p), nil +} + +// LogCountForLevel returns the number of log invocations for a given threshold. +func (n *Notepad) LogCountForLevel(l Threshold) uint64 { + return n.logCounters[l].getCount() +} + +// LogCountForLevelsGreaterThanorEqualTo returns the number of log invocations +// greater than or equal to a given threshold. +func (n *Notepad) LogCountForLevelsGreaterThanorEqualTo(threshold Threshold) uint64 { + var cnt uint64 + + for i := int(threshold); i < len(n.logCounters); i++ { + cnt += n.LogCountForLevel(Threshold(i)) + } + + return cnt +} + +// ResetLogCounters resets the invocation counters for all levels. +func (n *Notepad) ResetLogCounters() { + for _, np := range n.logCounters { + np.resetCounter() + } +} diff --git a/vendor/github.com/spf13/jwalterweatherman/notepad.go b/vendor/github.com/spf13/jwalterweatherman/notepad.go new file mode 100644 index 00000000..ea345866 --- /dev/null +++ b/vendor/github.com/spf13/jwalterweatherman/notepad.go @@ -0,0 +1,177 @@ +// Copyright © 2016 Steve Francia . +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +package jwalterweatherman + +import ( + "fmt" + "io" + "log" + "os" +) + +type Threshold int + +const ( + LevelTrace Threshold = iota + LevelDebug + LevelInfo + LevelWarn + LevelError + LevelCritical + LevelFatal +) + +var prefixes map[Threshold]string = map[Threshold]string{ + LevelTrace: "TRACE ", + LevelDebug: "DEBUG ", + LevelInfo: "INFO ", + LevelWarn: "WARN ", + LevelError: "ERROR ", + LevelCritical: "CRITICAL ", + LevelFatal: "FATAL ", +} + +// Notepad is where you leave a note ! +type Notepad struct { + TRACE *log.Logger + DEBUG *log.Logger + INFO *log.Logger + WARN *log.Logger + ERROR *log.Logger + CRITICAL *log.Logger + FATAL *log.Logger + + LOG *log.Logger + FEEDBACK *Feedback + + loggers []**log.Logger + logHandle io.Writer + outHandle io.Writer + logThreshold Threshold + stdoutThreshold Threshold + prefix string + flags int + + // One per Threshold + logCounters [7]*logCounter +} + +// NewNotepad create a new notepad. +func NewNotepad(outThreshold Threshold, logThreshold Threshold, outHandle, logHandle io.Writer, prefix string, flags int) *Notepad { + n := &Notepad{} + + n.loggers = append(n.loggers, &n.TRACE, &n.DEBUG, &n.INFO, &n.WARN, &n.ERROR, &n.CRITICAL, &n.FATAL) + n.logHandle = logHandle + n.outHandle = outHandle + n.logThreshold = logThreshold + n.stdoutThreshold = outThreshold + + if len(prefix) != 0 { + n.prefix = "[" + prefix + "] " + } else { + n.prefix = "" + } + + n.flags = flags + + n.LOG = log.New(n.logHandle, + "LOG: ", + n.flags) + + n.FEEDBACK = &Feedback{n} + + n.init() + + return n +} + +// Feedback is special. It writes plainly to the output while +// logging with the standard extra information (date, file, etc) +// Only Println and Printf are currently provided for this +type Feedback struct { + *Notepad +} + +// init create the loggers for each level depending on the notepad thresholds +func (n *Notepad) init() { + bothHandle := io.MultiWriter(n.outHandle, n.logHandle) + + for t, logger := range n.loggers { + threshold := Threshold(t) + counter := &logCounter{} + n.logCounters[t] = counter + + switch { + case threshold >= n.logThreshold && threshold >= n.stdoutThreshold: + *logger = log.New(io.MultiWriter(counter, bothHandle), n.prefix+prefixes[threshold], n.flags) + + case threshold >= n.logThreshold: + *logger = log.New(io.MultiWriter(counter, n.logHandle), n.prefix+prefixes[threshold], n.flags) + + case threshold >= n.stdoutThreshold: + *logger = log.New(io.MultiWriter(counter, os.Stdout), n.prefix+prefixes[threshold], n.flags) + + default: + *logger = log.New(counter, n.prefix+prefixes[threshold], n.flags) + } + } +} + +// SetLogThreshold change the threshold above which messages are written to the +// log file +func (n *Notepad) SetLogThreshold(threshold Threshold) { + n.logThreshold = threshold + n.init() +} + +// SetLogOutput change the file where log messages are written +func (n *Notepad) SetLogOutput(handle io.Writer) { + n.logHandle = handle + n.init() +} + +// SetStdoutThreshold change the threshold above which messages are written to the +// standard output +func (n *Notepad) SetStdoutThreshold(threshold Threshold) { + n.stdoutThreshold = threshold + n.init() +} + +// SetPrefix change the prefix used by the notepad. Prefixes are displayed between +// brackets at the begining of the line. An empty prefix won't be displayed at all. +func (n *Notepad) SetPrefix(prefix string) { + if len(prefix) != 0 { + n.prefix = "[" + prefix + "] " + } else { + n.prefix = "" + } + n.init() +} + +// SetFlags choose which flags the logger will display (after prefix and message +// level). See the package log for more informations on this. +func (n *Notepad) SetFlags(flags int) { + n.flags = flags + n.init() +} + +// Feedback is special. It writes plainly to the output while +// logging with the standard extra information (date, file, etc) +// Only Println and Printf are currently provided for this +func (fb *Feedback) Println(v ...interface{}) { + s := fmt.Sprintln(v...) + fmt.Print(s) + fb.LOG.Output(2, s) +} + +// Feedback is special. It writes plainly to the output while +// logging with the standard extra information (date, file, etc) +// Only Println and Printf are currently provided for this +func (fb *Feedback) Printf(format string, v ...interface{}) { + s := fmt.Sprintf(format, v...) + fmt.Print(s) + fb.LOG.Output(2, s) +} diff --git a/vendor/github.com/spf13/jwalterweatherman/thatswhyyoualwaysleaveanote.go b/vendor/github.com/spf13/jwalterweatherman/thatswhyyoualwaysleaveanote.go deleted file mode 100644 index b64ed469..00000000 --- a/vendor/github.com/spf13/jwalterweatherman/thatswhyyoualwaysleaveanote.go +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright © 2016 Steve Francia . -// -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -package jwalterweatherman - -import ( - "fmt" - "io" - "io/ioutil" - "log" - "os" - "sync/atomic" -) - -// Level describes the chosen log level between -// debug and critical. -type Level int - -type NotePad struct { - Handle io.Writer - Level Level - Prefix string - Logger **log.Logger - counter uint64 -} - -func (n *NotePad) incr() { - atomic.AddUint64(&n.counter, 1) -} - -func (n *NotePad) resetCounter() { - atomic.StoreUint64(&n.counter, 0) -} - -func (n *NotePad) getCount() uint64 { - return atomic.LoadUint64(&n.counter) -} - -type countingWriter struct { - incrFunc func() -} - -func (cw *countingWriter) Write(p []byte) (n int, err error) { - cw.incrFunc() - - return 0, nil -} - -// Feedback is special. It writes plainly to the output while -// logging with the standard extra information (date, file, etc) -// Only Println and Printf are currently provided for this -type Feedback struct{} - -const ( - LevelTrace Level = iota - LevelDebug - LevelInfo - LevelWarn - LevelError - LevelCritical - LevelFatal - DefaultLogThreshold = LevelWarn - DefaultStdoutThreshold = LevelError -) - -var ( - TRACE *log.Logger - DEBUG *log.Logger - INFO *log.Logger - WARN *log.Logger - ERROR *log.Logger - CRITICAL *log.Logger - FATAL *log.Logger - LOG *log.Logger - FEEDBACK Feedback - LogHandle io.Writer = ioutil.Discard - OutHandle io.Writer = os.Stdout - BothHandle io.Writer = io.MultiWriter(LogHandle, OutHandle) - NotePads []*NotePad = []*NotePad{trace, debug, info, warn, err, critical, fatal} - - trace *NotePad = &NotePad{Level: LevelTrace, Handle: os.Stdout, Logger: &TRACE, Prefix: "TRACE: "} - debug *NotePad = &NotePad{Level: LevelDebug, Handle: os.Stdout, Logger: &DEBUG, Prefix: "DEBUG: "} - info *NotePad = &NotePad{Level: LevelInfo, Handle: os.Stdout, Logger: &INFO, Prefix: "INFO: "} - warn *NotePad = &NotePad{Level: LevelWarn, Handle: os.Stdout, Logger: &WARN, Prefix: "WARN: "} - err *NotePad = &NotePad{Level: LevelError, Handle: os.Stdout, Logger: &ERROR, Prefix: "ERROR: "} - critical *NotePad = &NotePad{Level: LevelCritical, Handle: os.Stdout, Logger: &CRITICAL, Prefix: "CRITICAL: "} - fatal *NotePad = &NotePad{Level: LevelFatal, Handle: os.Stdout, Logger: &FATAL, Prefix: "FATAL: "} - logThreshold Level = DefaultLogThreshold - outputThreshold Level = DefaultStdoutThreshold -) - -const ( - DATE = log.Ldate - TIME = log.Ltime - SFILE = log.Lshortfile - LFILE = log.Llongfile - MSEC = log.Lmicroseconds -) - -var logFlags = DATE | TIME | SFILE - -func init() { - SetStdoutThreshold(DefaultStdoutThreshold) -} - -// initialize will setup the jWalterWeatherman standard approach of providing the user -// some feedback and logging a potentially different amount based on independent log and output thresholds. -// By default the output has a lower threshold than logged -// Don't use if you have manually set the Handles of the different levels as it will overwrite them. -func initialize() { - BothHandle = io.MultiWriter(LogHandle, OutHandle) - - for _, n := range NotePads { - if n.Level < outputThreshold && n.Level < logThreshold { - n.Handle = ioutil.Discard - } else if n.Level >= outputThreshold && n.Level >= logThreshold { - n.Handle = BothHandle - } else if n.Level >= outputThreshold && n.Level < logThreshold { - n.Handle = OutHandle - } else { - n.Handle = LogHandle - } - } - - for _, n := range NotePads { - n.Handle = io.MultiWriter(n.Handle, &countingWriter{n.incr}) - *n.Logger = log.New(n.Handle, n.Prefix, logFlags) - } - - LOG = log.New(LogHandle, - "LOG: ", - logFlags) -} - -// Set the log Flags (Available flag: DATE, TIME, SFILE, LFILE and MSEC) -func SetLogFlag(flags int) { - logFlags = flags - initialize() -} - -// Level returns the current global log threshold. -func LogThreshold() Level { - return logThreshold -} - -// Level returns the current global output threshold. -func StdoutThreshold() Level { - return outputThreshold -} - -// Ensures that the level provided is within the bounds of available levels -func levelCheck(level Level) Level { - switch { - case level <= LevelTrace: - return LevelTrace - case level >= LevelFatal: - return LevelFatal - default: - return level - } -} - -// Establishes a threshold where anything matching or above will be logged -func SetLogThreshold(level Level) { - logThreshold = levelCheck(level) - initialize() -} - -// Establishes a threshold where anything matching or above will be output -func SetStdoutThreshold(level Level) { - outputThreshold = levelCheck(level) - initialize() -} - -// Conveniently Sets the Log Handle to a io.writer created for the file behind the given filepath -// Will only append to this file -func SetLogFile(path string) { - file, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666) - if err != nil { - CRITICAL.Println("Failed to open log file:", path, err) - os.Exit(-1) - } - - INFO.Println("Logging to", file.Name()) - - LogHandle = file - initialize() -} - -// Conveniently Creates a temporary file and sets the Log Handle to a io.writer created for it -func UseTempLogFile(prefix string) { - file, err := ioutil.TempFile(os.TempDir(), prefix) - if err != nil { - CRITICAL.Println(err) - } - - INFO.Println("Logging to", file.Name()) - - LogHandle = file - initialize() -} - -// LogCountForLevel returns the number of log invocations for a given level. -func LogCountForLevel(l Level) uint64 { - for _, np := range NotePads { - if np.Level == l { - return np.getCount() - } - } - return 0 -} - -// LogCountForLevelsGreaterThanorEqualTo returns the number of log invocations -// greater than or equal to a given level threshold. -func LogCountForLevelsGreaterThanorEqualTo(threshold Level) uint64 { - var cnt uint64 - for _, np := range NotePads { - if np.Level >= threshold { - cnt += np.getCount() - } - } - return cnt -} - -// ResetLogCounters resets the invocation counters for all levels. -func ResetLogCounters() { - for _, np := range NotePads { - np.resetCounter() - } -} - -// Disables logging for the entire JWW system -func DiscardLogging() { - LogHandle = ioutil.Discard - initialize() -} - -// Feedback is special. It writes plainly to the output while -// logging with the standard extra information (date, file, etc) -// Only Println and Printf are currently provided for this -func (fb *Feedback) Println(v ...interface{}) { - s := fmt.Sprintln(v...) - fmt.Print(s) - LOG.Output(2, s) -} - -// Feedback is special. It writes plainly to the output while -// logging with the standard extra information (date, file, etc) -// Only Println and Printf are currently provided for this -func (fb *Feedback) Printf(format string, v ...interface{}) { - s := fmt.Sprintf(format, v...) - fmt.Print(s) - LOG.Output(2, s) -} diff --git a/vendor/github.com/xeipuuv/gojsonschema/errors.go b/vendor/github.com/xeipuuv/gojsonschema/errors.go index f22fa653..f69f22d3 100644 --- a/vendor/github.com/xeipuuv/gojsonschema/errors.go +++ b/vendor/github.com/xeipuuv/gojsonschema/errors.go @@ -2,10 +2,18 @@ package gojsonschema import ( "bytes" + "sync" "text/template" ) -var errorTemplates *template.Template +var errorTemplates errorTemplate = errorTemplate{template.New("errors-new"),sync.RWMutex{}} + +// template.Template is not thread-safe for writing, so some locking is done +// sync.RWMutex is used for efficiently locking when new templates are created +type errorTemplate struct { + *template.Template + sync.RWMutex +} type ( // RequiredError. ErrorDetails: property string @@ -241,14 +249,17 @@ func formatErrorDescription(s string, details ErrorDetails) string { var descrAsBuffer bytes.Buffer var err error - if errorTemplates == nil { - errorTemplates = template.New("all-errors") - } - + errorTemplates.RLock() tpl = errorTemplates.Lookup(s) + errorTemplates.RUnlock() + if tpl == nil { + errorTemplates.Lock() tpl = errorTemplates.New(s) + tpl, err = tpl.Parse(s) + errorTemplates.Unlock() + if err != nil { return err.Error() } diff --git a/vendor/github.com/xeipuuv/gojsonschema/jsonLoader.go b/vendor/github.com/xeipuuv/gojsonschema/jsonLoader.go index 0e865eb0..1edc702e 100644 --- a/vendor/github.com/xeipuuv/gojsonschema/jsonLoader.go +++ b/vendor/github.com/xeipuuv/gojsonschema/jsonLoader.go @@ -101,7 +101,9 @@ func (l *jsonReferenceLoader) JsonReference() (gojsonreference.JsonReference, er } func (l *jsonReferenceLoader) LoaderFactory() JSONLoaderFactory { - return &DefaultJSONLoaderFactory{} + return &FileSystemJSONLoaderFactory{ + fs: l.fs, + } } // NewReferenceLoader returns a JSON reference loader using the given source and the local OS file system. From 39fbc4ab9c435c09bd6af22aef099372b94bc9a7 Mon Sep 17 00:00:00 2001 From: Charlie Drage Date: Tue, 10 Jan 2017 09:45:17 -0500 Subject: [PATCH 2/3] Update checking to see if a default network has been provided Due to changes to libcompose, NetworkConfigs now returns a default network regardless if one has been provided or not. An if statement is added that will debug output and ignore the default network provided that it's the only network available. --- pkg/loader/compose/compose.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pkg/loader/compose/compose.go b/pkg/loader/compose/compose.go index f8e4d59b..5a105219 100644 --- a/pkg/loader/compose/compose.go +++ b/pkg/loader/compose/compose.go @@ -81,11 +81,16 @@ func checkUnsupportedKey(composeProject *project.Project) []string { // collect all keys found in project var keysFound []string - // Root level keys - // volume config and network config are not supported - if len(composeProject.NetworkConfigs) > 0 { + // Root level keys are not yet supported + // Check to see if the default network is available and length is only equal to one. + // Else, warn the user that root level networks are not supported (yet) + if _, ok := composeProject.NetworkConfigs["default"]; ok && len(composeProject.NetworkConfigs) == 1 { + logrus.Debug("Default network found") + } else if len(composeProject.NetworkConfigs) > 0 { keysFound = append(keysFound, "root level networks") } + + // Root level volumes are not yet supported if len(composeProject.VolumeConfigs) > 0 { keysFound = append(keysFound, "root level volumes") } From 15b482698a94899b2362d163f88490a4a414bb32 Mon Sep 17 00:00:00 2001 From: Charlie Drage Date: Thu, 12 Jan 2017 08:14:41 -0500 Subject: [PATCH 3/3] Uncomment test case for image handling --- script/test/cmd/tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/test/cmd/tests.sh b/script/test/cmd/tests.sh index 1d61bf55..37d631f5 100755 --- a/script/test/cmd/tests.sh +++ b/script/test/cmd/tests.sh @@ -22,7 +22,7 @@ source $KOMPOSE_ROOT/script/test/cmd/lib.sh convert::expect_failure "kompose -f $KOMPOSE_ROOT/script/test/fixtures/etherpad/docker-compose.yml convert --stdout" # commenting this test case out until image handling is fixed -#convert::expect_failure "kompose -f $KOMPOSE_ROOT/script/test/fixtures/etherpad/docker-compose-no-image.yml convert --stdout" +convert::expect_failure "kompose -f $KOMPOSE_ROOT/script/test/fixtures/etherpad/docker-compose-no-image.yml convert --stdout" convert::expect_warning "kompose -f $KOMPOSE_ROOT/script/test/fixtures/etherpad/docker-compose-no-ports.yml convert --stdout" "Service cannot be created because of missing port." export $(cat $KOMPOSE_ROOT/script/test/fixtures/etherpad/envs) # kubernetes test