Vendor integration dependencies.
This commit is contained in:
parent
dd5e3fba01
commit
55b57c736b
2451 changed files with 731611 additions and 0 deletions
191
integration/vendor/github.com/docker/libcompose/LICENSE
generated
vendored
Normal file
191
integration/vendor/github.com/docker/libcompose/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015 Docker, Inc.
|
||||
|
||||
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.
|
||||
44
integration/vendor/github.com/docker/libcompose/config/convert.go
generated
vendored
Normal file
44
integration/vendor/github.com/docker/libcompose/config/convert.go
generated
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"github.com/docker/libcompose/utils"
|
||||
"github.com/docker/libcompose/yaml"
|
||||
)
|
||||
|
||||
// ConvertServices converts a set of v1 service configs to v2 service configs
|
||||
func ConvertServices(v1Services map[string]*ServiceConfigV1) (map[string]*ServiceConfig, error) {
|
||||
v2Services := make(map[string]*ServiceConfig)
|
||||
replacementFields := make(map[string]*ServiceConfig)
|
||||
|
||||
for name, service := range v1Services {
|
||||
replacementFields[name] = &ServiceConfig{
|
||||
Build: yaml.Build{
|
||||
Context: service.Build,
|
||||
Dockerfile: service.Dockerfile,
|
||||
},
|
||||
Logging: Log{
|
||||
Driver: service.LogDriver,
|
||||
Options: service.LogOpt,
|
||||
},
|
||||
NetworkMode: service.Net,
|
||||
}
|
||||
|
||||
v1Services[name].Build = ""
|
||||
v1Services[name].Dockerfile = ""
|
||||
v1Services[name].LogDriver = ""
|
||||
v1Services[name].LogOpt = nil
|
||||
v1Services[name].Net = ""
|
||||
}
|
||||
|
||||
if err := utils.Convert(v1Services, &v2Services); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for name := range v2Services {
|
||||
v2Services[name].Build = replacementFields[name].Build
|
||||
v2Services[name].Logging = replacementFields[name].Logging
|
||||
v2Services[name].NetworkMode = replacementFields[name].NetworkMode
|
||||
}
|
||||
|
||||
return v2Services, nil
|
||||
}
|
||||
95
integration/vendor/github.com/docker/libcompose/config/hash.go
generated
vendored
Normal file
95
integration/vendor/github.com/docker/libcompose/config/hash.go
generated
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"sort"
|
||||
|
||||
"github.com/docker/libcompose/yaml"
|
||||
)
|
||||
|
||||
// GetServiceHash computes and returns a hash that will identify a service.
|
||||
// This hash will be then used to detect if the service definition/configuration
|
||||
// have changed and needs to be recreated.
|
||||
func GetServiceHash(name string, config *ServiceConfig) string {
|
||||
hash := sha1.New()
|
||||
|
||||
io.WriteString(hash, name)
|
||||
|
||||
//Get values of Service through reflection
|
||||
val := reflect.ValueOf(config).Elem()
|
||||
|
||||
//Create slice to sort the keys in Service Config, which allow constant hash ordering
|
||||
serviceKeys := []string{}
|
||||
|
||||
//Create a data structure of map of values keyed by a string
|
||||
unsortedKeyValue := make(map[string]interface{})
|
||||
|
||||
//Get all keys and values in Service Configuration
|
||||
for i := 0; i < val.NumField(); i++ {
|
||||
valueField := val.Field(i)
|
||||
keyField := val.Type().Field(i)
|
||||
|
||||
serviceKeys = append(serviceKeys, keyField.Name)
|
||||
unsortedKeyValue[keyField.Name] = valueField.Interface()
|
||||
}
|
||||
|
||||
//Sort serviceKeys alphabetically
|
||||
sort.Strings(serviceKeys)
|
||||
|
||||
//Go through keys and write hash
|
||||
for _, serviceKey := range serviceKeys {
|
||||
serviceValue := unsortedKeyValue[serviceKey]
|
||||
|
||||
io.WriteString(hash, fmt.Sprintf("\n %v: ", serviceKey))
|
||||
|
||||
switch s := serviceValue.(type) {
|
||||
case yaml.SliceorMap:
|
||||
sliceKeys := []string{}
|
||||
for lkey := range s {
|
||||
sliceKeys = append(sliceKeys, lkey)
|
||||
}
|
||||
sort.Strings(sliceKeys)
|
||||
|
||||
for _, sliceKey := range sliceKeys {
|
||||
io.WriteString(hash, fmt.Sprintf("%s=%v, ", sliceKey, s[sliceKey]))
|
||||
}
|
||||
case yaml.MaporEqualSlice:
|
||||
for _, sliceKey := range s {
|
||||
io.WriteString(hash, fmt.Sprintf("%s, ", sliceKey))
|
||||
}
|
||||
case yaml.MaporColonSlice:
|
||||
for _, sliceKey := range s {
|
||||
io.WriteString(hash, fmt.Sprintf("%s, ", sliceKey))
|
||||
}
|
||||
case yaml.MaporSpaceSlice:
|
||||
for _, sliceKey := range s {
|
||||
io.WriteString(hash, fmt.Sprintf("%s, ", sliceKey))
|
||||
}
|
||||
case yaml.Command:
|
||||
for _, sliceKey := range s {
|
||||
io.WriteString(hash, fmt.Sprintf("%s, ", sliceKey))
|
||||
}
|
||||
case yaml.Stringorslice:
|
||||
sort.Strings(s)
|
||||
|
||||
for _, sliceKey := range s {
|
||||
io.WriteString(hash, fmt.Sprintf("%s, ", sliceKey))
|
||||
}
|
||||
case []string:
|
||||
sliceKeys := s
|
||||
sort.Strings(sliceKeys)
|
||||
|
||||
for _, sliceKey := range sliceKeys {
|
||||
io.WriteString(hash, fmt.Sprintf("%s, ", sliceKey))
|
||||
}
|
||||
default:
|
||||
io.WriteString(hash, fmt.Sprintf("%v", serviceValue))
|
||||
}
|
||||
}
|
||||
|
||||
return hex.EncodeToString(hash.Sum(nil))
|
||||
}
|
||||
169
integration/vendor/github.com/docker/libcompose/config/interpolation.go
generated
vendored
Normal file
169
integration/vendor/github.com/docker/libcompose/config/interpolation.go
generated
vendored
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
func isNum(c uint8) bool {
|
||||
return c >= '0' && c <= '9'
|
||||
}
|
||||
|
||||
func validVariableNameChar(c uint8) bool {
|
||||
return c == '_' ||
|
||||
c >= 'A' && c <= 'Z' ||
|
||||
c >= 'a' && c <= 'z' ||
|
||||
isNum(c)
|
||||
}
|
||||
|
||||
func parseVariable(line string, pos int, mapping func(string) string) (string, int, bool) {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
for ; pos < len(line); pos++ {
|
||||
c := line[pos]
|
||||
|
||||
switch {
|
||||
case validVariableNameChar(c):
|
||||
buffer.WriteByte(c)
|
||||
default:
|
||||
return mapping(buffer.String()), pos - 1, true
|
||||
}
|
||||
}
|
||||
|
||||
return mapping(buffer.String()), pos, true
|
||||
}
|
||||
|
||||
func parseVariableWithBraces(line string, pos int, mapping func(string) string) (string, int, bool) {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
for ; pos < len(line); pos++ {
|
||||
c := line[pos]
|
||||
|
||||
switch {
|
||||
case c == '}':
|
||||
bufferString := buffer.String()
|
||||
|
||||
if bufferString == "" {
|
||||
return "", 0, false
|
||||
}
|
||||
|
||||
return mapping(buffer.String()), pos, true
|
||||
case validVariableNameChar(c):
|
||||
buffer.WriteByte(c)
|
||||
default:
|
||||
return "", 0, false
|
||||
}
|
||||
}
|
||||
|
||||
return "", 0, false
|
||||
}
|
||||
|
||||
func parseInterpolationExpression(line string, pos int, mapping func(string) string) (string, int, bool) {
|
||||
c := line[pos]
|
||||
|
||||
switch {
|
||||
case c == '$':
|
||||
return "$", pos, true
|
||||
case c == '{':
|
||||
return parseVariableWithBraces(line, pos+1, mapping)
|
||||
case !isNum(c) && validVariableNameChar(c):
|
||||
// Variables can't start with a number
|
||||
return parseVariable(line, pos, mapping)
|
||||
default:
|
||||
return "", 0, false
|
||||
}
|
||||
}
|
||||
|
||||
func parseLine(line string, mapping func(string) string) (string, bool) {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
for pos := 0; pos < len(line); pos++ {
|
||||
c := line[pos]
|
||||
switch {
|
||||
case c == '$':
|
||||
var replaced string
|
||||
var success bool
|
||||
|
||||
replaced, pos, success = parseInterpolationExpression(line, pos+1, mapping)
|
||||
|
||||
if !success {
|
||||
return "", false
|
||||
}
|
||||
|
||||
buffer.WriteString(replaced)
|
||||
default:
|
||||
buffer.WriteByte(c)
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.String(), true
|
||||
}
|
||||
|
||||
func parseConfig(option, service string, data *interface{}, mapping func(string) string) error {
|
||||
switch typedData := (*data).(type) {
|
||||
case string:
|
||||
var success bool
|
||||
|
||||
*data, success = parseLine(typedData, mapping)
|
||||
|
||||
if !success {
|
||||
return fmt.Errorf("Invalid interpolation format for \"%s\" option in service \"%s\": \"%s\"", option, service, typedData)
|
||||
}
|
||||
case []interface{}:
|
||||
for k, v := range typedData {
|
||||
err := parseConfig(option, service, &v, mapping)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
typedData[k] = v
|
||||
}
|
||||
case map[interface{}]interface{}:
|
||||
for k, v := range typedData {
|
||||
err := parseConfig(option, service, &v, mapping)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
typedData[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
166
integration/vendor/github.com/docker/libcompose/config/merge.go
generated
vendored
Normal file
166
integration/vendor/github.com/docker/libcompose/config/merge.go
generated
vendored
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
yaml "github.com/cloudfoundry-incubator/candiedyaml"
|
||||
"github.com/docker/docker/pkg/urlutil"
|
||||
)
|
||||
|
||||
var (
|
||||
noMerge = []string{
|
||||
"links",
|
||||
"volumes_from",
|
||||
}
|
||||
defaultParseOptions = ParseOptions{
|
||||
Interpolate: true,
|
||||
Validate: true,
|
||||
}
|
||||
)
|
||||
|
||||
// Merge merges a compose file into an existing set of service configs
|
||||
func Merge(existingServices *ServiceConfigs, environmentLookup EnvironmentLookup, resourceLookup ResourceLookup, file string, bytes []byte, options *ParseOptions) (string, map[string]*ServiceConfig, map[string]*VolumeConfig, map[string]*NetworkConfig, error) {
|
||||
if options == nil {
|
||||
options = &defaultParseOptions
|
||||
}
|
||||
|
||||
var config Config
|
||||
if err := yaml.Unmarshal(bytes, &config); err != nil {
|
||||
return "", nil, nil, nil, err
|
||||
}
|
||||
|
||||
var serviceConfigs map[string]*ServiceConfig
|
||||
var volumeConfigs map[string]*VolumeConfig
|
||||
var networkConfigs map[string]*NetworkConfig
|
||||
if config.Version == "2" {
|
||||
var err error
|
||||
serviceConfigs, err = MergeServicesV2(existingServices, environmentLookup, resourceLookup, file, bytes, options)
|
||||
if err != nil {
|
||||
return "", nil, nil, nil, err
|
||||
}
|
||||
volumeConfigs, err = ParseVolumes(bytes)
|
||||
if err != nil {
|
||||
return "", nil, nil, nil, err
|
||||
}
|
||||
networkConfigs, err = ParseNetworks(bytes)
|
||||
if err != nil {
|
||||
return "", nil, nil, nil, err
|
||||
}
|
||||
} else {
|
||||
serviceConfigsV1, err := MergeServicesV1(existingServices, environmentLookup, resourceLookup, file, bytes, options)
|
||||
if err != nil {
|
||||
return "", nil, nil, nil, err
|
||||
}
|
||||
serviceConfigs, err = ConvertServices(serviceConfigsV1)
|
||||
if err != nil {
|
||||
return "", nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
adjustValues(serviceConfigs)
|
||||
|
||||
if options.Postprocess != nil {
|
||||
var err error
|
||||
serviceConfigs, err = options.Postprocess(serviceConfigs)
|
||||
if err != nil {
|
||||
return "", nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return config.Version, serviceConfigs, volumeConfigs, networkConfigs, nil
|
||||
}
|
||||
|
||||
func adjustValues(configs map[string]*ServiceConfig) {
|
||||
// yaml parser turns "no" into "false" but that is not valid for a restart policy
|
||||
for _, v := range configs {
|
||||
if v.Restart == "false" {
|
||||
v.Restart = "no"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func readEnvFile(resourceLookup ResourceLookup, inFile string, serviceData RawService) (RawService, error) {
|
||||
if _, ok := serviceData["env_file"]; !ok {
|
||||
return serviceData, nil
|
||||
}
|
||||
envFiles := serviceData["env_file"].([]interface{})
|
||||
if len(envFiles) == 0 {
|
||||
return serviceData, nil
|
||||
}
|
||||
|
||||
if resourceLookup == nil {
|
||||
return nil, fmt.Errorf("Can not use env_file in file %s no mechanism provided to load files", inFile)
|
||||
}
|
||||
|
||||
var vars []interface{}
|
||||
if _, ok := serviceData["environment"]; ok {
|
||||
vars = serviceData["environment"].([]interface{})
|
||||
}
|
||||
|
||||
for i := len(envFiles) - 1; i >= 0; i-- {
|
||||
envFile := envFiles[i].(string)
|
||||
content, _, err := resourceLookup.Lookup(envFile, inFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(bytes.NewBuffer(content))
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
key := strings.SplitAfter(line, "=")[0]
|
||||
|
||||
found := false
|
||||
for _, v := range vars {
|
||||
if strings.HasPrefix(v.(string), key) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
vars = append(vars, line)
|
||||
}
|
||||
}
|
||||
|
||||
if scanner.Err() != nil {
|
||||
return nil, scanner.Err()
|
||||
}
|
||||
}
|
||||
|
||||
serviceData["environment"] = vars
|
||||
|
||||
delete(serviceData, "env_file")
|
||||
|
||||
return serviceData, nil
|
||||
}
|
||||
|
||||
func mergeConfig(baseService, serviceData RawService) RawService {
|
||||
for k, v := range serviceData {
|
||||
// Image and build are mutually exclusive in merge
|
||||
if k == "image" {
|
||||
delete(baseService, "build")
|
||||
} else if k == "build" {
|
||||
delete(baseService, "image")
|
||||
}
|
||||
existing, ok := baseService[k]
|
||||
if ok {
|
||||
baseService[k] = merge(existing, v)
|
||||
} else {
|
||||
baseService[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return baseService
|
||||
}
|
||||
|
||||
// IsValidRemote checks if the specified string is a valid remote (for builds)
|
||||
func IsValidRemote(remote string) bool {
|
||||
return urlutil.IsGitURL(remote) || urlutil.IsURL(remote)
|
||||
}
|
||||
199
integration/vendor/github.com/docker/libcompose/config/merge_v1.go
generated
vendored
Normal file
199
integration/vendor/github.com/docker/libcompose/config/merge_v1.go
generated
vendored
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
yaml "github.com/cloudfoundry-incubator/candiedyaml"
|
||||
"github.com/docker/libcompose/utils"
|
||||
)
|
||||
|
||||
// MergeServicesV1 merges a v1 compose file into an existing set of service configs
|
||||
func MergeServicesV1(existingServices *ServiceConfigs, environmentLookup EnvironmentLookup, resourceLookup ResourceLookup, file string, bytes []byte, options *ParseOptions) (map[string]*ServiceConfigV1, error) {
|
||||
datas := make(RawServiceMap)
|
||||
if err := yaml.Unmarshal(bytes, &datas); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
for name, data := range datas {
|
||||
data, err := parseV1(resourceLookup, environmentLookup, file, data, datas, options)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to parse service %s: %v", name, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if serviceConfig, ok := existingServices.Get(name); ok {
|
||||
var rawExistingService RawService
|
||||
if err := utils.Convert(serviceConfig, &rawExistingService); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data = mergeConfig(rawExistingService, data)
|
||||
}
|
||||
|
||||
datas[name] = data
|
||||
}
|
||||
|
||||
if options.Validate {
|
||||
for name, data := range datas {
|
||||
err := validateServiceConstraints(data, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
serviceConfigs := make(map[string]*ServiceConfigV1)
|
||||
if err := utils.Convert(datas, &serviceConfigs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return serviceConfigs, nil
|
||||
}
|
||||
|
||||
func parseV1(resourceLookup ResourceLookup, environmentLookup EnvironmentLookup, inFile string, serviceData RawService, datas RawServiceMap, options *ParseOptions) (RawService, error) {
|
||||
serviceData, err := readEnvFile(resourceLookup, inFile, serviceData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
serviceData = resolveContextV1(inFile, serviceData)
|
||||
|
||||
value, ok := serviceData["extends"]
|
||||
if !ok {
|
||||
return serviceData, nil
|
||||
}
|
||||
|
||||
mapValue, ok := value.(map[interface{}]interface{})
|
||||
if !ok {
|
||||
return serviceData, nil
|
||||
}
|
||||
|
||||
if resourceLookup == nil {
|
||||
return nil, fmt.Errorf("Can not use extends in file %s no mechanism provided to files", inFile)
|
||||
}
|
||||
|
||||
file := asString(mapValue["file"])
|
||||
service := asString(mapValue["service"])
|
||||
|
||||
if service == "" {
|
||||
return serviceData, nil
|
||||
}
|
||||
|
||||
var baseService RawService
|
||||
|
||||
if file == "" {
|
||||
if serviceData, ok := datas[service]; ok {
|
||||
baseService, err = parseV1(resourceLookup, environmentLookup, inFile, serviceData, datas, options)
|
||||
} else {
|
||||
return nil, fmt.Errorf("Failed to find service %s to extend", service)
|
||||
}
|
||||
} else {
|
||||
bytes, resolved, err := resourceLookup.Lookup(file, inFile)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to lookup file %s: %v", file, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var baseRawServices RawServiceMap
|
||||
if err := yaml.Unmarshal(bytes, &baseRawServices); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if options.Interpolate {
|
||||
err = Interpolate(environmentLookup, &baseRawServices)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if options.Preprocess != nil {
|
||||
var err error
|
||||
baseRawServices, err = options.Preprocess(baseRawServices)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if options.Validate {
|
||||
if err := validate(baseRawServices); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
baseService, ok = baseRawServices[service]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Failed to find service %s in file %s", service, file)
|
||||
}
|
||||
|
||||
baseService, err = parseV1(resourceLookup, environmentLookup, resolved, baseService, baseRawServices, options)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
baseService = clone(baseService)
|
||||
|
||||
logrus.Debugf("Merging %#v, %#v", baseService, serviceData)
|
||||
|
||||
for _, k := range noMerge {
|
||||
if _, ok := baseService[k]; ok {
|
||||
source := file
|
||||
if source == "" {
|
||||
source = inFile
|
||||
}
|
||||
return nil, fmt.Errorf("Cannot extend service '%s' in %s: services with '%s' cannot be extended", service, source, k)
|
||||
}
|
||||
}
|
||||
|
||||
baseService = mergeConfig(baseService, serviceData)
|
||||
|
||||
logrus.Debugf("Merged result %#v", baseService)
|
||||
|
||||
return baseService, nil
|
||||
}
|
||||
|
||||
func resolveContextV1(inFile string, serviceData RawService) RawService {
|
||||
context := asString(serviceData["build"])
|
||||
if context == "" {
|
||||
return serviceData
|
||||
}
|
||||
|
||||
if IsValidRemote(context) {
|
||||
return serviceData
|
||||
}
|
||||
|
||||
current := path.Dir(inFile)
|
||||
|
||||
if context == "." {
|
||||
context = current
|
||||
} else {
|
||||
current = path.Join(current, context)
|
||||
}
|
||||
|
||||
serviceData["build"] = current
|
||||
|
||||
return serviceData
|
||||
}
|
||||
217
integration/vendor/github.com/docker/libcompose/config/merge_v2.go
generated
vendored
Normal file
217
integration/vendor/github.com/docker/libcompose/config/merge_v2.go
generated
vendored
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
yaml "github.com/cloudfoundry-incubator/candiedyaml"
|
||||
"github.com/docker/libcompose/utils"
|
||||
)
|
||||
|
||||
// MergeServicesV2 merges a v2 compose file into an existing set of service configs
|
||||
func MergeServicesV2(existingServices *ServiceConfigs, environmentLookup EnvironmentLookup, resourceLookup ResourceLookup, file string, bytes []byte, options *ParseOptions) (map[string]*ServiceConfig, error) {
|
||||
var config Config
|
||||
if err := yaml.Unmarshal(bytes, &config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
datas := config.Services
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
for name, data := range datas {
|
||||
data, err := parseV2(resourceLookup, environmentLookup, file, data, datas, options)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to parse service %s: %v", name, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if serviceConfig, ok := existingServices.Get(name); ok {
|
||||
var rawExistingService RawService
|
||||
if err := utils.Convert(serviceConfig, &rawExistingService); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data = mergeConfig(rawExistingService, data)
|
||||
}
|
||||
|
||||
datas[name] = data
|
||||
}
|
||||
|
||||
serviceConfigs := make(map[string]*ServiceConfig)
|
||||
if err := utils.Convert(datas, &serviceConfigs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return serviceConfigs, nil
|
||||
}
|
||||
|
||||
// ParseVolumes parses volumes in a compose file
|
||||
func ParseVolumes(bytes []byte) (map[string]*VolumeConfig, error) {
|
||||
volumeConfigs := make(map[string]*VolumeConfig)
|
||||
|
||||
var config Config
|
||||
if err := yaml.Unmarshal(bytes, &config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := utils.Convert(config.Volumes, &volumeConfigs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return volumeConfigs, nil
|
||||
}
|
||||
|
||||
// ParseNetworks parses networks in a compose file
|
||||
func ParseNetworks(bytes []byte) (map[string]*NetworkConfig, error) {
|
||||
networkConfigs := make(map[string]*NetworkConfig)
|
||||
|
||||
var config Config
|
||||
if err := yaml.Unmarshal(bytes, &config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := utils.Convert(config.Networks, &networkConfigs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return networkConfigs, nil
|
||||
}
|
||||
|
||||
func parseV2(resourceLookup ResourceLookup, environmentLookup EnvironmentLookup, inFile string, serviceData RawService, datas RawServiceMap, options *ParseOptions) (RawService, error) {
|
||||
serviceData, err := readEnvFile(resourceLookup, inFile, serviceData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
serviceData = resolveContextV2(inFile, serviceData)
|
||||
|
||||
value, ok := serviceData["extends"]
|
||||
if !ok {
|
||||
return serviceData, nil
|
||||
}
|
||||
|
||||
mapValue, ok := value.(map[interface{}]interface{})
|
||||
if !ok {
|
||||
return serviceData, nil
|
||||
}
|
||||
|
||||
if resourceLookup == nil {
|
||||
return nil, fmt.Errorf("Can not use extends in file %s no mechanism provided to files", inFile)
|
||||
}
|
||||
|
||||
file := asString(mapValue["file"])
|
||||
service := asString(mapValue["service"])
|
||||
|
||||
if service == "" {
|
||||
return serviceData, nil
|
||||
}
|
||||
|
||||
var baseService RawService
|
||||
|
||||
if file == "" {
|
||||
if serviceData, ok := datas[service]; ok {
|
||||
baseService, err = parseV2(resourceLookup, environmentLookup, inFile, serviceData, datas, options)
|
||||
} else {
|
||||
return nil, fmt.Errorf("Failed to find service %s to extend", service)
|
||||
}
|
||||
} else {
|
||||
bytes, resolved, err := resourceLookup.Lookup(file, inFile)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to lookup file %s: %v", file, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var config Config
|
||||
if err := yaml.Unmarshal(bytes, &config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
baseRawServices := config.Services
|
||||
|
||||
if options.Interpolate {
|
||||
err = Interpolate(environmentLookup, &baseRawServices)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
baseService, ok = baseRawServices[service]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Failed to find service %s in file %s", service, file)
|
||||
}
|
||||
|
||||
baseService, err = parseV2(resourceLookup, environmentLookup, resolved, baseService, baseRawServices, options)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
baseService = clone(baseService)
|
||||
|
||||
logrus.Debugf("Merging %#v, %#v", baseService, serviceData)
|
||||
|
||||
for _, k := range noMerge {
|
||||
if _, ok := baseService[k]; ok {
|
||||
source := file
|
||||
if source == "" {
|
||||
source = inFile
|
||||
}
|
||||
return nil, fmt.Errorf("Cannot extend service '%s' in %s: services with '%s' cannot be extended", service, source, k)
|
||||
}
|
||||
}
|
||||
|
||||
baseService = mergeConfig(baseService, serviceData)
|
||||
|
||||
logrus.Debugf("Merged result %#v", baseService)
|
||||
|
||||
return baseService, nil
|
||||
}
|
||||
|
||||
func resolveContextV2(inFile string, serviceData RawService) RawService {
|
||||
if _, ok := serviceData["build"]; !ok {
|
||||
return serviceData
|
||||
}
|
||||
var build map[interface{}]interface{}
|
||||
if buildAsString, ok := serviceData["build"].(string); ok {
|
||||
build = map[interface{}]interface{}{
|
||||
"context": buildAsString,
|
||||
}
|
||||
} else {
|
||||
build = serviceData["build"].(map[interface{}]interface{})
|
||||
}
|
||||
context := asString(build["context"])
|
||||
if context == "" {
|
||||
return serviceData
|
||||
}
|
||||
|
||||
if IsValidRemote(context) {
|
||||
return serviceData
|
||||
}
|
||||
|
||||
current := path.Dir(inFile)
|
||||
|
||||
if context == "." {
|
||||
context = current
|
||||
} else {
|
||||
current = path.Join(current, context)
|
||||
}
|
||||
|
||||
build["context"] = current
|
||||
|
||||
return serviceData
|
||||
}
|
||||
510
integration/vendor/github.com/docker/libcompose/config/schema.go
generated
vendored
Normal file
510
integration/vendor/github.com/docker/libcompose/config/schema.go
generated
vendored
Normal file
|
|
@ -0,0 +1,510 @@
|
|||
package config
|
||||
|
||||
var schemaV1 = `{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"id": "config_schema_v1.json",
|
||||
|
||||
"type": "object",
|
||||
|
||||
"patternProperties": {
|
||||
"^[a-zA-Z0-9._-]+$": {
|
||||
"$ref": "#/definitions/service"
|
||||
}
|
||||
},
|
||||
|
||||
"additionalProperties": false,
|
||||
|
||||
"definitions": {
|
||||
"service": {
|
||||
"id": "#/definitions/service",
|
||||
"type": "object",
|
||||
|
||||
"properties": {
|
||||
"build": {"type": "string"},
|
||||
"cap_add": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
"cap_drop": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
"cgroup_parent": {"type": "string"},
|
||||
"command": {
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{"type": "array", "items": {"type": "string"}}
|
||||
]
|
||||
},
|
||||
"container_name": {"type": "string"},
|
||||
"cpu_shares": {"type": ["number", "string"]},
|
||||
"cpu_quota": {"type": ["number", "string"]},
|
||||
"cpuset": {"type": "string"},
|
||||
"devices": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
"dns": {"$ref": "#/definitions/string_or_list"},
|
||||
"dns_search": {"$ref": "#/definitions/string_or_list"},
|
||||
"dockerfile": {"type": "string"},
|
||||
"domainname": {"type": "string"},
|
||||
"entrypoint": {
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{"type": "array", "items": {"type": "string"}}
|
||||
]
|
||||
},
|
||||
"env_file": {"$ref": "#/definitions/string_or_list"},
|
||||
"environment": {"$ref": "#/definitions/list_or_dict"},
|
||||
|
||||
"expose": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": ["string", "number"],
|
||||
"format": "expose"
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
|
||||
"extends": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
|
||||
"properties": {
|
||||
"service": {"type": "string"},
|
||||
"file": {"type": "string"}
|
||||
},
|
||||
"required": ["service"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"extra_hosts": {"$ref": "#/definitions/list_or_dict"},
|
||||
"external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
"hostname": {"type": "string"},
|
||||
"image": {"type": "string"},
|
||||
"ipc": {"type": "string"},
|
||||
"labels": {"$ref": "#/definitions/list_or_dict"},
|
||||
"links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
"log_driver": {"type": "string"},
|
||||
"log_opt": {"type": "object"},
|
||||
"mac_address": {"type": "string"},
|
||||
"mem_limit": {"type": ["number", "string"]},
|
||||
"memswap_limit": {"type": ["number", "string"]},
|
||||
"net": {"type": "string"},
|
||||
"pid": {"type": ["string", "null"]},
|
||||
|
||||
"ports": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": ["string", "number"],
|
||||
"format": "ports"
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
|
||||
"privileged": {"type": "boolean"},
|
||||
"read_only": {"type": "boolean"},
|
||||
"restart": {"type": "string"},
|
||||
"security_opt": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
"shm_size": {"type": ["number", "string"]},
|
||||
"stdin_open": {"type": "boolean"},
|
||||
"stop_signal": {"type": "string"},
|
||||
"tty": {"type": "boolean"},
|
||||
"ulimits": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-z]+$": {
|
||||
"oneOf": [
|
||||
{"type": "integer"},
|
||||
{
|
||||
"type":"object",
|
||||
"properties": {
|
||||
"hard": {"type": "integer"},
|
||||
"soft": {"type": "integer"}
|
||||
},
|
||||
"required": ["soft", "hard"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"user": {"type": "string"},
|
||||
"volumes": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
"volume_driver": {"type": "string"},
|
||||
"volumes_from": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
"working_dir": {"type": "string"}
|
||||
},
|
||||
|
||||
"dependencies": {
|
||||
"memswap_limit": ["mem_limit"]
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"string_or_list": {
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{"$ref": "#/definitions/list_of_strings"}
|
||||
]
|
||||
},
|
||||
|
||||
"list_of_strings": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"uniqueItems": true
|
||||
},
|
||||
|
||||
"list_or_dict": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
".+": {
|
||||
"type": ["string", "number", "null"]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{"type": "array", "items": {"type": "string"}, "uniqueItems": true}
|
||||
]
|
||||
},
|
||||
|
||||
"constraints": {
|
||||
"service": {
|
||||
"id": "#/definitions/constraints/service",
|
||||
"anyOf": [
|
||||
{
|
||||
"required": ["build"],
|
||||
"not": {"required": ["image"]}
|
||||
},
|
||||
{
|
||||
"required": ["image"],
|
||||
"not": {"anyOf": [
|
||||
{"required": ["build"]},
|
||||
{"required": ["dockerfile"]}
|
||||
]}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
var schemaV2 = `{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"id": "config_schema_v2.0.json",
|
||||
"type": "object",
|
||||
|
||||
"properties": {
|
||||
"version": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"services": {
|
||||
"id": "#/properties/services",
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-zA-Z0-9._-]+$": {
|
||||
"$ref": "#/definitions/service"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"networks": {
|
||||
"id": "#/properties/networks",
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-zA-Z0-9._-]+$": {
|
||||
"$ref": "#/definitions/network"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"volumes": {
|
||||
"id": "#/properties/volumes",
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-zA-Z0-9._-]+$": {
|
||||
"$ref": "#/definitions/volume"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
|
||||
"additionalProperties": false,
|
||||
|
||||
"definitions": {
|
||||
|
||||
"service": {
|
||||
"id": "#/definitions/service",
|
||||
"type": "object",
|
||||
|
||||
"properties": {
|
||||
"build": {
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"context": {"type": "string"},
|
||||
"dockerfile": {"type": "string"},
|
||||
"args": {"$ref": "#/definitions/list_or_dict"}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"cap_add": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
"cap_drop": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
"cgroup_parent": {"type": "string"},
|
||||
"command": {
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{"type": "array", "items": {"type": "string"}}
|
||||
]
|
||||
},
|
||||
"container_name": {"type": "string"},
|
||||
"cpu_shares": {"type": ["number", "string"]},
|
||||
"cpu_quota": {"type": ["number", "string"]},
|
||||
"cpuset": {"type": "string"},
|
||||
"depends_on": {"$ref": "#/definitions/list_of_strings"},
|
||||
"devices": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
"dns": {"$ref": "#/definitions/string_or_list"},
|
||||
"dns_search": {"$ref": "#/definitions/string_or_list"},
|
||||
"domainname": {"type": "string"},
|
||||
"entrypoint": {
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{"type": "array", "items": {"type": "string"}}
|
||||
]
|
||||
},
|
||||
"env_file": {"$ref": "#/definitions/string_or_list"},
|
||||
"environment": {"$ref": "#/definitions/list_or_dict"},
|
||||
|
||||
"expose": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": ["string", "number"],
|
||||
"format": "expose"
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
|
||||
"extends": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
|
||||
"properties": {
|
||||
"service": {"type": "string"},
|
||||
"file": {"type": "string"}
|
||||
},
|
||||
"required": ["service"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
"extra_hosts": {"$ref": "#/definitions/list_or_dict"},
|
||||
"hostname": {"type": "string"},
|
||||
"image": {"type": "string"},
|
||||
"ipc": {"type": "string"},
|
||||
"labels": {"$ref": "#/definitions/list_or_dict"},
|
||||
"links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
|
||||
"logging": {
|
||||
"type": "object",
|
||||
|
||||
"properties": {
|
||||
"driver": {"type": "string"},
|
||||
"options": {"type": "object"}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"mac_address": {"type": "string"},
|
||||
"mem_limit": {"type": ["number", "string"]},
|
||||
"memswap_limit": {"type": ["number", "string"]},
|
||||
"network_mode": {"type": "string"},
|
||||
|
||||
"networks": {
|
||||
"oneOf": [
|
||||
{"$ref": "#/definitions/list_of_strings"},
|
||||
{
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-zA-Z0-9._-]+$": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aliases": {"$ref": "#/definitions/list_of_strings"},
|
||||
"ipv4_address": {"type": "string"},
|
||||
"ipv6_address": {"type": "string"}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{"type": "null"}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"pid": {"type": ["string", "null"]},
|
||||
|
||||
"ports": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": ["string", "number"],
|
||||
"format": "ports"
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
|
||||
"privileged": {"type": "boolean"},
|
||||
"read_only": {"type": "boolean"},
|
||||
"restart": {"type": "string"},
|
||||
"security_opt": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
"shm_size": {"type": ["number", "string"]},
|
||||
"stdin_open": {"type": "boolean"},
|
||||
"stop_signal": {"type": "string"},
|
||||
"tmpfs": {"$ref": "#/definitions/string_or_list"},
|
||||
"tty": {"type": "boolean"},
|
||||
"ulimits": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-z]+$": {
|
||||
"oneOf": [
|
||||
{"type": "integer"},
|
||||
{
|
||||
"type":"object",
|
||||
"properties": {
|
||||
"hard": {"type": "integer"},
|
||||
"soft": {"type": "integer"}
|
||||
},
|
||||
"required": ["soft", "hard"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"user": {"type": "string"},
|
||||
"volumes": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
"volume_driver": {"type": "string"},
|
||||
"volumes_from": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
"working_dir": {"type": "string"}
|
||||
},
|
||||
|
||||
"dependencies": {
|
||||
"memswap_limit": ["mem_limit"]
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"network": {
|
||||
"id": "#/definitions/network",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"driver": {"type": "string"},
|
||||
"driver_opts": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^.+$": {"type": ["string", "number"]}
|
||||
}
|
||||
},
|
||||
"ipam": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"driver": {"type": "string"},
|
||||
"config": {
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"external": {
|
||||
"type": ["boolean", "object"],
|
||||
"properties": {
|
||||
"name": {"type": "string"}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"volume": {
|
||||
"id": "#/definitions/volume",
|
||||
"type": ["object", "null"],
|
||||
"properties": {
|
||||
"driver": {"type": "string"},
|
||||
"driver_opts": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^.+$": {"type": ["string", "number"]}
|
||||
}
|
||||
},
|
||||
"external": {
|
||||
"type": ["boolean", "object"],
|
||||
"properties": {
|
||||
"name": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"string_or_list": {
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{"$ref": "#/definitions/list_of_strings"}
|
||||
]
|
||||
},
|
||||
|
||||
"list_of_strings": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"uniqueItems": true
|
||||
},
|
||||
|
||||
"list_or_dict": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
".+": {
|
||||
"type": ["string", "number", "null"]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{"type": "array", "items": {"type": "string"}, "uniqueItems": true}
|
||||
]
|
||||
},
|
||||
|
||||
"constraints": {
|
||||
"service": {
|
||||
"id": "#/definitions/constraints/service",
|
||||
"anyOf": [
|
||||
{"required": ["build"]},
|
||||
{"required": ["image"]}
|
||||
],
|
||||
"properties": {
|
||||
"build": {
|
||||
"required": ["context"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
92
integration/vendor/github.com/docker/libcompose/config/schema_helpers.go
generated
vendored
Normal file
92
integration/vendor/github.com/docker/libcompose/config/schema_helpers.go
generated
vendored
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/xeipuuv/gojsonschema"
|
||||
)
|
||||
|
||||
var (
|
||||
schemaLoader gojsonschema.JSONLoader
|
||||
constraintSchemaLoader gojsonschema.JSONLoader
|
||||
schema map[string]interface{}
|
||||
)
|
||||
|
||||
type (
|
||||
environmentFormatChecker struct{}
|
||||
portsFormatChecker struct{}
|
||||
)
|
||||
|
||||
func (checker environmentFormatChecker) IsFormat(input string) bool {
|
||||
// If the value is a boolean, a warning should be given
|
||||
// However, we can't determine type since gojsonschema converts the value to a string
|
||||
// Adding a function with an interface{} parameter to gojsonschema is probably the best way to handle this
|
||||
return true
|
||||
}
|
||||
|
||||
func (checker portsFormatChecker) IsFormat(input string) bool {
|
||||
_, _, err := nat.ParsePortSpecs([]string{input})
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func setupSchemaLoaders() error {
|
||||
if schema != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var schemaRaw interface{}
|
||||
err := json.Unmarshal([]byte(schemaV1), &schemaRaw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
schema = schemaRaw.(map[string]interface{})
|
||||
|
||||
gojsonschema.FormatCheckers.Add("environment", environmentFormatChecker{})
|
||||
gojsonschema.FormatCheckers.Add("ports", portsFormatChecker{})
|
||||
gojsonschema.FormatCheckers.Add("expose", portsFormatChecker{})
|
||||
schemaLoader = gojsonschema.NewGoLoader(schemaRaw)
|
||||
|
||||
definitions := schema["definitions"].(map[string]interface{})
|
||||
constraints := definitions["constraints"].(map[string]interface{})
|
||||
service := constraints["service"].(map[string]interface{})
|
||||
constraintSchemaLoader = gojsonschema.NewGoLoader(service)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// gojsonschema doesn't provide a list of valid types for a property
|
||||
// This parses the schema manually to find all valid types
|
||||
func parseValidTypesFromSchema(schema map[string]interface{}, context string) []string {
|
||||
contextSplit := strings.Split(context, ".")
|
||||
key := contextSplit[len(contextSplit)-1]
|
||||
|
||||
definitions := schema["definitions"].(map[string]interface{})
|
||||
service := definitions["service"].(map[string]interface{})
|
||||
properties := service["properties"].(map[string]interface{})
|
||||
property := properties[key].(map[string]interface{})
|
||||
|
||||
var validTypes []string
|
||||
|
||||
if val, ok := property["oneOf"]; ok {
|
||||
validConditions := val.([]interface{})
|
||||
|
||||
for _, validCondition := range validConditions {
|
||||
condition := validCondition.(map[string]interface{})
|
||||
validTypes = append(validTypes, condition["type"].(string))
|
||||
}
|
||||
} else if val, ok := property["$ref"]; ok {
|
||||
reference := val.(string)
|
||||
if reference == "#/definitions/string_or_list" {
|
||||
return []string{"string", "array"}
|
||||
} else if reference == "#/definitions/list_of_strings" {
|
||||
return []string{"array"}
|
||||
} else if reference == "#/definitions/list_or_dict" {
|
||||
return []string{"array", "object"}
|
||||
}
|
||||
}
|
||||
|
||||
return validTypes
|
||||
}
|
||||
234
integration/vendor/github.com/docker/libcompose/config/types.go
generated
vendored
Normal file
234
integration/vendor/github.com/docker/libcompose/config/types.go
generated
vendored
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/docker/libcompose/yaml"
|
||||
)
|
||||
|
||||
// EnvironmentLookup defines methods to provides environment variable loading.
|
||||
type EnvironmentLookup interface {
|
||||
Lookup(key, serviceName string, config *ServiceConfig) []string
|
||||
}
|
||||
|
||||
// ResourceLookup defines methods to provides file loading.
|
||||
type ResourceLookup interface {
|
||||
Lookup(file, relativeTo string) ([]byte, string, error)
|
||||
ResolvePath(path, inFile string) string
|
||||
}
|
||||
|
||||
// ServiceConfigV1 holds version 1 of libcompose service configuration
|
||||
type ServiceConfigV1 struct {
|
||||
Build string `yaml:"build,omitempty"`
|
||||
CapAdd []string `yaml:"cap_add,omitempty"`
|
||||
CapDrop []string `yaml:"cap_drop,omitempty"`
|
||||
CgroupParent string `yaml:"cgroup_parent,omitempty"`
|
||||
CPUQuota int64 `yaml:"cpu_quota,omitempty"`
|
||||
CPUSet string `yaml:"cpuset,omitempty"`
|
||||
CPUShares int64 `yaml:"cpu_shares,omitempty"`
|
||||
Command yaml.Command `yaml:"command,flow,omitempty"`
|
||||
ContainerName string `yaml:"container_name,omitempty"`
|
||||
Devices []string `yaml:"devices,omitempty"`
|
||||
DNS yaml.Stringorslice `yaml:"dns,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"`
|
||||
Hostname string `yaml:"hostname,omitempty"`
|
||||
Image string `yaml:"image,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 int64 `yaml:"mem_limit,omitempty"`
|
||||
MemSwapLimit int64 `yaml:"memswap_limit,omitempty"`
|
||||
Name string `yaml:"name,omitempty"`
|
||||
Net string `yaml:"net,omitempty"`
|
||||
Pid string `yaml:"pid,omitempty"`
|
||||
Uts string `yaml:"uts,omitempty"`
|
||||
Ipc string `yaml:"ipc,omitempty"`
|
||||
Ports []string `yaml:"ports,omitempty"`
|
||||
Privileged bool `yaml:"privileged,omitempty"`
|
||||
Restart string `yaml:"restart,omitempty"`
|
||||
ReadOnly bool `yaml:"read_only,omitempty"`
|
||||
ShmSize int64 `yaml:"shm_size,omitempty"`
|
||||
StdinOpen bool `yaml:"stdin_open,omitempty"`
|
||||
SecurityOpt []string `yaml:"security_opt,omitempty"`
|
||||
Tty bool `yaml:"tty,omitempty"`
|
||||
User string `yaml:"user,omitempty"`
|
||||
VolumeDriver string `yaml:"volume_driver,omitempty"`
|
||||
Volumes []string `yaml:"volumes,omitempty"`
|
||||
VolumesFrom []string `yaml:"volumes_from,omitempty"`
|
||||
WorkingDir string `yaml:"working_dir,omitempty"`
|
||||
Expose []string `yaml:"expose,omitempty"`
|
||||
ExternalLinks []string `yaml:"external_links,omitempty"`
|
||||
LogOpt map[string]string `yaml:"log_opt,omitempty"`
|
||||
ExtraHosts []string `yaml:"extra_hosts,omitempty"`
|
||||
Ulimits yaml.Ulimits `yaml:"ulimits,omitempty"`
|
||||
}
|
||||
|
||||
// Log holds v2 logging information
|
||||
type Log struct {
|
||||
Driver string `yaml:"driver,omitempty"`
|
||||
Options map[string]string `yaml:"options,omitempty"`
|
||||
}
|
||||
|
||||
// ServiceConfig holds version 2 of libcompose service configuration
|
||||
type ServiceConfig struct {
|
||||
Build yaml.Build `yaml:"build,omitempty"`
|
||||
CapAdd []string `yaml:"cap_add,omitempty"`
|
||||
CapDrop []string `yaml:"cap_drop,omitempty"`
|
||||
CPUSet string `yaml:"cpuset,omitempty"`
|
||||
CPUShares int64 `yaml:"cpu_shares,omitempty"`
|
||||
CPUQuota int64 `yaml:"cpu_quota,omitempty"`
|
||||
Command yaml.Command `yaml:"command,flow,omitempty"`
|
||||
CgroupParent string `yaml:"cgroup_parent,omitempty"`
|
||||
ContainerName string `yaml:"container_name,omitempty"`
|
||||
Devices []string `yaml:"devices,omitempty"`
|
||||
DependsOn []string `yaml:"depends_on,omitempty"`
|
||||
DNS yaml.Stringorslice `yaml:"dns,omitempty"`
|
||||
DNSSearch yaml.Stringorslice `yaml:"dns_search,omitempty"`
|
||||
DomainName string `yaml:"domain_name,omitempty"`
|
||||
Entrypoint yaml.Command `yaml:"entrypoint,flow,omitempty"`
|
||||
EnvFile yaml.Stringorslice `yaml:"env_file,omitempty"`
|
||||
Environment yaml.MaporEqualSlice `yaml:"environment,omitempty"`
|
||||
Expose []string `yaml:"expose,omitempty"`
|
||||
Extends yaml.MaporEqualSlice `yaml:"extends,omitempty"`
|
||||
ExternalLinks []string `yaml:"external_links,omitempty"`
|
||||
ExtraHosts []string `yaml:"extra_hosts,omitempty"`
|
||||
Image string `yaml:"image,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 int64 `yaml:"mem_limit,omitempty"`
|
||||
MemSwapLimit int64 `yaml:"memswap_limit,omitempty"`
|
||||
NetworkMode string `yaml:"network_mode,omitempty"`
|
||||
Networks *yaml.Networks `yaml:"networks,omitempty"`
|
||||
Pid string `yaml:"pid,omitempty"`
|
||||
Ports []string `yaml:"ports,omitempty"`
|
||||
Privileged bool `yaml:"privileged,omitempty"`
|
||||
SecurityOpt []string `yaml:"security_opt,omitempty"`
|
||||
ShmSize int64 `yaml:"shm_size,omitempty"`
|
||||
StopSignal string `yaml:"stop_signal,omitempty"`
|
||||
VolumeDriver string `yaml:"volume_driver,omitempty"`
|
||||
Volumes []string `yaml:"volumes,omitempty"`
|
||||
VolumesFrom []string `yaml:"volumes_from,omitempty"`
|
||||
Uts string `yaml:"uts,omitempty"`
|
||||
Restart string `yaml:"restart,omitempty"`
|
||||
ReadOnly bool `yaml:"read_only,omitempty"`
|
||||
StdinOpen bool `yaml:"stdin_open,omitempty"`
|
||||
Tty bool `yaml:"tty,omitempty"`
|
||||
User string `yaml:"user,omitempty"`
|
||||
WorkingDir string `yaml:"working_dir,omitempty"`
|
||||
Ulimits yaml.Ulimits `yaml:"ulimits,omitempty"`
|
||||
}
|
||||
|
||||
// VolumeConfig holds v2 volume configuration
|
||||
type VolumeConfig struct {
|
||||
Driver string `yaml:"driver,omitempty"`
|
||||
DriverOpts map[string]string `yaml:"driver_opts,omitempty"`
|
||||
External yaml.External `yaml:"external,omitempty"`
|
||||
}
|
||||
|
||||
// Ipam holds v2 network IPAM information
|
||||
type Ipam struct {
|
||||
Driver string `yaml:"driver,omitempty"`
|
||||
Config []IpamConfig `yaml:"config,omitempty"`
|
||||
}
|
||||
|
||||
// IpamConfig holds v2 network IPAM configuration information
|
||||
type IpamConfig struct {
|
||||
Subnet string `yaml:"subnet,omitempty"`
|
||||
IPRange string `yaml:"ip_range,omitempty"`
|
||||
Gateway string `yaml:"gateway,omitempty"`
|
||||
AuxAddress map[string]string `yaml:"aux_addresses,omitempty"`
|
||||
}
|
||||
|
||||
// NetworkConfig holds v2 network configuration
|
||||
type NetworkConfig struct {
|
||||
Driver string `yaml:"driver,omitempty"`
|
||||
DriverOpts map[string]string `yaml:"driver_opts,omitempty"`
|
||||
External yaml.External `yaml:"external,omitempty"`
|
||||
Ipam Ipam `yaml:"ipam,omitempty"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// NewServiceConfigs initializes a new Configs struct
|
||||
func NewServiceConfigs() *ServiceConfigs {
|
||||
return &ServiceConfigs{
|
||||
m: make(map[string]*ServiceConfig),
|
||||
}
|
||||
}
|
||||
|
||||
// ServiceConfigs holds a concurrent safe map of ServiceConfig
|
||||
type ServiceConfigs struct {
|
||||
m map[string]*ServiceConfig
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// Has checks if the config map has the specified name
|
||||
func (c *ServiceConfigs) Has(name string) bool {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
_, ok := c.m[name]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Get returns the config and the presence of the specified name
|
||||
func (c *ServiceConfigs) Get(name string) (*ServiceConfig, bool) {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
service, ok := c.m[name]
|
||||
return service, ok
|
||||
}
|
||||
|
||||
// Add add the specifed config with the specified name
|
||||
func (c *ServiceConfigs) Add(name string, service *ServiceConfig) {
|
||||
c.mu.Lock()
|
||||
c.m[name] = service
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
// Len returns the len of the configs
|
||||
func (c *ServiceConfigs) Len() int {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
return len(c.m)
|
||||
}
|
||||
|
||||
// Keys returns the names of the config
|
||||
func (c *ServiceConfigs) Keys() []string {
|
||||
keys := []string{}
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
for name := range c.m {
|
||||
keys = append(keys, name)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
// RawService is represent a Service in map form unparsed
|
||||
type RawService map[string]interface{}
|
||||
|
||||
// RawServiceMap is a collection of RawServices
|
||||
type RawServiceMap map[string]RawService
|
||||
|
||||
// ParseOptions are a set of options to customize the parsing process
|
||||
type ParseOptions struct {
|
||||
Interpolate bool
|
||||
Validate bool
|
||||
Preprocess func(RawServiceMap) (RawServiceMap, error)
|
||||
Postprocess func(map[string]*ServiceConfig) (map[string]*ServiceConfig, error)
|
||||
}
|
||||
42
integration/vendor/github.com/docker/libcompose/config/utils.go
generated
vendored
Normal file
42
integration/vendor/github.com/docker/libcompose/config/utils.go
generated
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
package config
|
||||
|
||||
func merge(existing, value interface{}) interface{} {
|
||||
// append strings
|
||||
if left, lok := existing.([]interface{}); lok {
|
||||
if right, rok := value.([]interface{}); rok {
|
||||
return append(left, right...)
|
||||
}
|
||||
}
|
||||
|
||||
//merge maps
|
||||
if left, lok := existing.(map[interface{}]interface{}); lok {
|
||||
if right, rok := value.(map[interface{}]interface{}); rok {
|
||||
newLeft := make(map[interface{}]interface{})
|
||||
for k, v := range left {
|
||||
newLeft[k] = v
|
||||
}
|
||||
for k, v := range right {
|
||||
newLeft[k] = v
|
||||
}
|
||||
return newLeft
|
||||
}
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func clone(in RawService) RawService {
|
||||
result := RawService{}
|
||||
for k, v := range in {
|
||||
result[k] = v
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func asString(obj interface{}) string {
|
||||
if v, ok := obj.(string); ok {
|
||||
return v
|
||||
}
|
||||
return ""
|
||||
}
|
||||
300
integration/vendor/github.com/docker/libcompose/config/validation.go
generated
vendored
Normal file
300
integration/vendor/github.com/docker/libcompose/config/validation.go
generated
vendored
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/xeipuuv/gojsonschema"
|
||||
)
|
||||
|
||||
func serviceNameFromErrorField(field string) string {
|
||||
splitKeys := strings.Split(field, ".")
|
||||
return splitKeys[0]
|
||||
}
|
||||
|
||||
func keyNameFromErrorField(field string) string {
|
||||
splitKeys := strings.Split(field, ".")
|
||||
|
||||
if len(splitKeys) > 0 {
|
||||
return splitKeys[len(splitKeys)-1]
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func containsTypeError(resultError gojsonschema.ResultError) bool {
|
||||
contextSplit := strings.Split(resultError.Context().String(), ".")
|
||||
_, err := strconv.Atoi(contextSplit[len(contextSplit)-1])
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func addArticle(s string) string {
|
||||
switch s[0] {
|
||||
case 'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U':
|
||||
return "an " + s
|
||||
default:
|
||||
return "a " + s
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the value in a service map at a given error context
|
||||
func getValue(val interface{}, context string) string {
|
||||
keys := strings.Split(context, ".")
|
||||
|
||||
if keys[0] == "(root)" {
|
||||
keys = keys[1:]
|
||||
}
|
||||
|
||||
for i, k := range keys {
|
||||
switch typedVal := (val).(type) {
|
||||
case string:
|
||||
return typedVal
|
||||
case []interface{}:
|
||||
if index, err := strconv.Atoi(k); err == nil {
|
||||
val = typedVal[index]
|
||||
}
|
||||
case RawServiceMap:
|
||||
val = typedVal[k]
|
||||
case RawService:
|
||||
val = typedVal[k]
|
||||
case map[interface{}]interface{}:
|
||||
val = typedVal[k]
|
||||
}
|
||||
|
||||
if i == len(keys)-1 {
|
||||
return fmt.Sprint(val)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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",
|
||||
"hosts": "extra_hosts",
|
||||
"extra_host": "extra_hosts",
|
||||
"device": "devices",
|
||||
"link": "links",
|
||||
"memory_swap": "memswap_limit",
|
||||
"port": "ports",
|
||||
"privilege": "privileged",
|
||||
"priviliged": "privileged",
|
||||
"privilige": "privileged",
|
||||
"volume": "volumes",
|
||||
"workdir": "working_dir",
|
||||
}
|
||||
|
||||
func unsupportedConfigMessage(key string, nextErr gojsonschema.ResultError) string {
|
||||
service := serviceNameFromErrorField(nextErr.Field())
|
||||
|
||||
message := fmt.Sprintf("Unsupported config option for %s service: '%s'", service, key)
|
||||
if val, ok := dockerConfigHints[key]; ok {
|
||||
message += fmt.Sprintf(" (did you mean '%s'?)", val)
|
||||
}
|
||||
|
||||
return message
|
||||
}
|
||||
|
||||
func oneOfMessage(serviceMap RawServiceMap, schema map[string]interface{}, err, nextErr gojsonschema.ResultError) string {
|
||||
switch nextErr.Type() {
|
||||
case "additional_property_not_allowed":
|
||||
property := nextErr.Details()["property"]
|
||||
|
||||
return fmt.Sprintf("contains unsupported option: '%s'", property)
|
||||
case "invalid_type":
|
||||
if containsTypeError(nextErr) {
|
||||
expectedType := addArticle(nextErr.Details()["expected"].(string))
|
||||
|
||||
return fmt.Sprintf("contains %s, which is an invalid type, it should be %s", getValue(serviceMap, nextErr.Context().String()), expectedType)
|
||||
}
|
||||
|
||||
validTypes := parseValidTypesFromSchema(schema, err.Context().String())
|
||||
|
||||
validTypesMsg := addArticle(strings.Join(validTypes, " or "))
|
||||
|
||||
return fmt.Sprintf("contains an invalid type, it should be %s", validTypesMsg)
|
||||
case "unique":
|
||||
contextWithDuplicates := getValue(serviceMap, nextErr.Context().String())
|
||||
|
||||
return fmt.Sprintf("contains non unique items, please remove duplicates from %s", contextWithDuplicates)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func invalidTypeMessage(service, key string, err gojsonschema.ResultError) string {
|
||||
expectedTypesString := err.Details()["expected"].(string)
|
||||
var expectedTypes []string
|
||||
|
||||
if strings.Contains(expectedTypesString, ",") {
|
||||
expectedTypes = strings.Split(expectedTypesString[1:len(expectedTypesString)-1], ",")
|
||||
} else {
|
||||
expectedTypes = []string{expectedTypesString}
|
||||
}
|
||||
|
||||
validTypesMsg := addArticle(strings.Join(expectedTypes, " or "))
|
||||
|
||||
return fmt.Sprintf("Service '%s' configuration key '%s' contains an invalid type, it should be %s.", service, key, validTypesMsg)
|
||||
}
|
||||
|
||||
func validate(serviceMap RawServiceMap) error {
|
||||
if err := setupSchemaLoaders(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
serviceMap = convertServiceMapKeysToStrings(serviceMap)
|
||||
|
||||
var validationErrors []string
|
||||
|
||||
dataLoader := gojsonschema.NewGoLoader(serviceMap)
|
||||
|
||||
result, err := gojsonschema.Validate(schemaLoader, dataLoader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// gojsonschema can create extraneous "additional_property_not_allowed" errors in some cases
|
||||
// If this is set, and the error is at root level, skip over that error
|
||||
skipRootAdditionalPropertyError := false
|
||||
|
||||
if !result.Valid() {
|
||||
for i := 0; i < len(result.Errors()); i++ {
|
||||
err := result.Errors()[i]
|
||||
|
||||
if skipRootAdditionalPropertyError && err.Type() == "additional_property_not_allowed" && err.Context().String() == "(root)" {
|
||||
skipRootAdditionalPropertyError = false
|
||||
continue
|
||||
}
|
||||
|
||||
if err.Context().String() == "(root)" {
|
||||
switch err.Type() {
|
||||
case "additional_property_not_allowed":
|
||||
validationErrors = append(validationErrors, fmt.Sprintf("Invalid service name '%s' - only [a-zA-Z0-9\\._\\-] characters are allowed", err.Field()))
|
||||
default:
|
||||
validationErrors = append(validationErrors, err.Description())
|
||||
}
|
||||
} else {
|
||||
skipRootAdditionalPropertyError = true
|
||||
|
||||
serviceName := serviceNameFromErrorField(err.Field())
|
||||
key := keyNameFromErrorField(err.Field())
|
||||
|
||||
switch err.Type() {
|
||||
case "additional_property_not_allowed":
|
||||
validationErrors = append(validationErrors, unsupportedConfigMessage(key, result.Errors()[i+1]))
|
||||
case "number_one_of":
|
||||
validationErrors = append(validationErrors, fmt.Sprintf("Service '%s' configuration key '%s' %s", serviceName, key, oneOfMessage(serviceMap, schema, err, result.Errors()[i+1])))
|
||||
|
||||
// Next error handled in oneOfMessage, skip over it
|
||||
i++
|
||||
case "invalid_type":
|
||||
validationErrors = append(validationErrors, invalidTypeMessage(serviceName, key, err))
|
||||
case "required":
|
||||
validationErrors = append(validationErrors, fmt.Sprintf("Service '%s' option '%s' is invalid, %s", serviceName, key, err.Description()))
|
||||
case "missing_dependency":
|
||||
dependency := err.Details()["dependency"].(string)
|
||||
validationErrors = append(validationErrors, fmt.Sprintf("Invalid configuration for '%s' service: dependency '%s' is not satisfied", serviceName, dependency))
|
||||
case "unique":
|
||||
contextWithDuplicates := getValue(serviceMap, err.Context().String())
|
||||
validationErrors = append(validationErrors, fmt.Sprintf("Service '%s' configuration key '%s' value %s has non-unique elements", serviceName, key, contextWithDuplicates))
|
||||
default:
|
||||
validationErrors = append(validationErrors, fmt.Sprintf("Service '%s' configuration key %s value %s", serviceName, key, err.Description()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf(strings.Join(validationErrors, "\n"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateServiceConstraints(service RawService, serviceName string) error {
|
||||
if err := setupSchemaLoaders(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
service = convertServiceKeysToStrings(service)
|
||||
|
||||
var validationErrors []string
|
||||
|
||||
dataLoader := gojsonschema.NewGoLoader(service)
|
||||
|
||||
result, err := gojsonschema.Validate(constraintSchemaLoader, dataLoader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !result.Valid() {
|
||||
for _, err := range result.Errors() {
|
||||
if err.Type() == "number_any_of" {
|
||||
_, containsImage := service["image"]
|
||||
_, containsBuild := service["build"]
|
||||
_, containsDockerfile := service["dockerfile"]
|
||||
|
||||
if containsImage && containsBuild {
|
||||
validationErrors = append(validationErrors, fmt.Sprintf("Service '%s' has both an image and build path specified. A service can either be built to image or use an existing image, not both.", serviceName))
|
||||
} else if !containsImage && !containsBuild {
|
||||
validationErrors = append(validationErrors, fmt.Sprintf("Service '%s' has neither an image nor a build path specified. Exactly one must be provided.", serviceName))
|
||||
} else if containsImage && containsDockerfile {
|
||||
validationErrors = append(validationErrors, fmt.Sprintf("Service '%s' has both an image and alternate Dockerfile. A service can either be built to image or use an existing image, not both.", serviceName))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf(strings.Join(validationErrors, "\n"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
40
integration/vendor/github.com/docker/libcompose/docker/auth.go
generated
vendored
Normal file
40
integration/vendor/github.com/docker/libcompose/docker/auth.go
generated
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/engine-api/types"
|
||||
)
|
||||
|
||||
// AuthLookup defines a method for looking up authentication information
|
||||
type AuthLookup interface {
|
||||
All() map[string]types.AuthConfig
|
||||
Lookup(repoInfo *registry.RepositoryInfo) types.AuthConfig
|
||||
}
|
||||
|
||||
// ConfigAuthLookup implements AuthLookup by reading a Docker config file
|
||||
type ConfigAuthLookup struct {
|
||||
context *Context
|
||||
}
|
||||
|
||||
// NewConfigAuthLookup creates a new ConfigAuthLookup for a given context
|
||||
func NewConfigAuthLookup(context *Context) *ConfigAuthLookup {
|
||||
return &ConfigAuthLookup{
|
||||
context: context,
|
||||
}
|
||||
}
|
||||
|
||||
// Lookup uses a Docker config file to lookup authentication information
|
||||
func (c *ConfigAuthLookup) Lookup(repoInfo *registry.RepositoryInfo) types.AuthConfig {
|
||||
if c.context.ConfigFile == nil || repoInfo == nil || repoInfo.Index == nil {
|
||||
return types.AuthConfig{}
|
||||
}
|
||||
return registry.ResolveAuthConfig(c.context.ConfigFile.AuthConfigs, repoInfo.Index)
|
||||
}
|
||||
|
||||
// All uses a Docker config file to get all authentication information
|
||||
func (c *ConfigAuthLookup) All() map[string]types.AuthConfig {
|
||||
if c.context.ConfigFile == nil {
|
||||
return map[string]types.AuthConfig{}
|
||||
}
|
||||
return c.context.ConfigFile.AuthConfigs
|
||||
}
|
||||
184
integration/vendor/github.com/docker/libcompose/docker/builder/builder.go
generated
vendored
Normal file
184
integration/vendor/github.com/docker/libcompose/docker/builder/builder.go
generated
vendored
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
package builder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/builder"
|
||||
"github.com/docker/docker/builder/dockerignore"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/fileutils"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
"github.com/docker/docker/pkg/term"
|
||||
"github.com/docker/engine-api/client"
|
||||
"github.com/docker/engine-api/types"
|
||||
)
|
||||
|
||||
// DefaultDockerfileName is the default name of a Dockerfile
|
||||
const DefaultDockerfileName = "Dockerfile"
|
||||
|
||||
// Builder defines methods to provide a docker builder. This makes libcompose
|
||||
// not tied up to the docker daemon builder.
|
||||
type Builder interface {
|
||||
Build(imageName string) error
|
||||
}
|
||||
|
||||
// DaemonBuilder is the daemon "docker build" Builder implementation.
|
||||
type DaemonBuilder struct {
|
||||
Client client.ImageAPIClient
|
||||
ContextDirectory string
|
||||
Dockerfile string
|
||||
AuthConfigs map[string]types.AuthConfig
|
||||
NoCache bool
|
||||
ForceRemove bool
|
||||
Pull bool
|
||||
BuildArgs map[string]string
|
||||
}
|
||||
|
||||
// Build implements Builder. It consumes the docker build API endpoint and sends
|
||||
// a tar of the specified service build context.
|
||||
func (d *DaemonBuilder) Build(ctx context.Context, imageName string) error {
|
||||
buildCtx, err := createTar(d.ContextDirectory, d.Dockerfile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer buildCtx.Close()
|
||||
|
||||
var progBuff io.Writer = os.Stdout
|
||||
var buildBuff io.Writer = os.Stdout
|
||||
|
||||
// Setup an upload progress bar
|
||||
progressOutput := streamformatter.NewStreamFormatter().NewProgressOutput(progBuff, true)
|
||||
|
||||
var body io.Reader = progress.NewProgressReader(buildCtx, progressOutput, 0, "", "Sending build context to Docker daemon")
|
||||
|
||||
logrus.Infof("Building %s...", imageName)
|
||||
|
||||
outFd, isTerminalOut := term.GetFdInfo(os.Stdout)
|
||||
|
||||
response, err := d.Client.ImageBuild(ctx, body, types.ImageBuildOptions{
|
||||
Tags: []string{imageName},
|
||||
NoCache: d.NoCache,
|
||||
Remove: true,
|
||||
ForceRemove: d.ForceRemove,
|
||||
PullParent: d.Pull,
|
||||
Dockerfile: d.Dockerfile,
|
||||
AuthConfigs: d.AuthConfigs,
|
||||
BuildArgs: d.BuildArgs,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = jsonmessage.DisplayJSONMessagesStream(response.Body, buildBuff, outFd, isTerminalOut, nil)
|
||||
if err != nil {
|
||||
if jerr, ok := err.(*jsonmessage.JSONError); ok {
|
||||
// If no error code is set, default to 1
|
||||
if jerr.Code == 0 {
|
||||
jerr.Code = 1
|
||||
}
|
||||
return fmt.Errorf("Status: %s, Code: %d", jerr.Message, jerr.Code)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// CreateTar create a build context tar for the specified project and service name.
|
||||
func createTar(contextDirectory, dockerfile string) (io.ReadCloser, error) {
|
||||
// This code was ripped off from docker/api/client/build.go
|
||||
dockerfileName := filepath.Join(contextDirectory, dockerfile)
|
||||
|
||||
absContextDirectory, err := filepath.Abs(contextDirectory)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filename := dockerfileName
|
||||
|
||||
if dockerfile == "" {
|
||||
// No -f/--file was specified so use the default
|
||||
dockerfileName = DefaultDockerfileName
|
||||
filename = filepath.Join(absContextDirectory, dockerfileName)
|
||||
|
||||
// Just to be nice ;-) look for 'dockerfile' too but only
|
||||
// use it if we found it, otherwise ignore this check
|
||||
if _, err = os.Lstat(filename); os.IsNotExist(err) {
|
||||
tmpFN := path.Join(absContextDirectory, strings.ToLower(dockerfileName))
|
||||
if _, err = os.Lstat(tmpFN); err == nil {
|
||||
dockerfileName = strings.ToLower(dockerfileName)
|
||||
filename = tmpFN
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
origDockerfile := dockerfileName // used for error msg
|
||||
if filename, err = filepath.Abs(filename); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Now reset the dockerfileName to be relative to the build context
|
||||
dockerfileName, err = filepath.Rel(absContextDirectory, filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// And canonicalize dockerfile name to a platform-independent one
|
||||
dockerfileName, err = archive.CanonicalTarNameForPath(dockerfileName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Cannot canonicalize dockerfile path %s: %v", dockerfileName, err)
|
||||
}
|
||||
|
||||
if _, err = os.Lstat(filename); os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("Cannot locate Dockerfile: %s", origDockerfile)
|
||||
}
|
||||
var includes = []string{"."}
|
||||
var excludes []string
|
||||
|
||||
dockerIgnorePath := path.Join(contextDirectory, ".dockerignore")
|
||||
dockerIgnore, err := os.Open(dockerIgnorePath)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
logrus.Warnf("Error while reading .dockerignore (%s) : %s", dockerIgnorePath, err.Error())
|
||||
excludes = make([]string, 0)
|
||||
} else {
|
||||
excludes, err = dockerignore.ReadAll(dockerIgnore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// If .dockerignore mentions .dockerignore or the Dockerfile
|
||||
// then make sure we send both files over to the daemon
|
||||
// because Dockerfile is, obviously, needed no matter what, and
|
||||
// .dockerignore is needed to know if either one needs to be
|
||||
// removed. The deamon will remove them for us, if needed, after it
|
||||
// parses the Dockerfile.
|
||||
keepThem1, _ := fileutils.Matches(".dockerignore", excludes)
|
||||
keepThem2, _ := fileutils.Matches(dockerfileName, excludes)
|
||||
if keepThem1 || keepThem2 {
|
||||
includes = append(includes, ".dockerignore", dockerfileName)
|
||||
}
|
||||
|
||||
if err := builder.ValidateContextDirectory(contextDirectory, excludes); err != nil {
|
||||
return nil, fmt.Errorf("Error checking context is accessible: '%s'. Please check permissions and try again.", err)
|
||||
}
|
||||
|
||||
options := &archive.TarOptions{
|
||||
Compression: archive.Uncompressed,
|
||||
ExcludePatterns: excludes,
|
||||
IncludeFiles: includes,
|
||||
}
|
||||
|
||||
return archive.TarWithOptions(contextDirectory, options)
|
||||
}
|
||||
115
integration/vendor/github.com/docker/libcompose/docker/client/client.go
generated
vendored
Normal file
115
integration/vendor/github.com/docker/libcompose/docker/client/client.go
generated
vendored
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/docker/cliconfig"
|
||||
"github.com/docker/docker/pkg/homedir"
|
||||
"github.com/docker/engine-api/client"
|
||||
"github.com/docker/go-connections/sockets"
|
||||
"github.com/docker/go-connections/tlsconfig"
|
||||
"github.com/docker/libcompose/version"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultAPIVersion is the default docker API version set by libcompose
|
||||
DefaultAPIVersion = "v1.20"
|
||||
defaultTrustKeyFile = "key.json"
|
||||
defaultCaFile = "ca.pem"
|
||||
defaultKeyFile = "key.pem"
|
||||
defaultCertFile = "cert.pem"
|
||||
)
|
||||
|
||||
var (
|
||||
dockerCertPath = os.Getenv("DOCKER_CERT_PATH")
|
||||
)
|
||||
|
||||
func init() {
|
||||
if dockerCertPath == "" {
|
||||
dockerCertPath = cliconfig.ConfigDir()
|
||||
}
|
||||
}
|
||||
|
||||
// Options holds docker client options (host, tls, ..)
|
||||
type Options struct {
|
||||
TLS bool
|
||||
TLSVerify bool
|
||||
TLSOptions tlsconfig.Options
|
||||
TrustKey string
|
||||
Host string
|
||||
APIVersion string
|
||||
}
|
||||
|
||||
// Create creates a docker client based on the specified options.
|
||||
func Create(c Options) (client.APIClient, error) {
|
||||
if c.Host == "" {
|
||||
if os.Getenv("DOCKER_API_VERSION") == "" {
|
||||
os.Setenv("DOCKER_API_VERSION", DefaultAPIVersion)
|
||||
}
|
||||
client, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
apiVersion := c.APIVersion
|
||||
if apiVersion == "" {
|
||||
apiVersion = DefaultAPIVersion
|
||||
}
|
||||
|
||||
if c.TLSOptions.CAFile == "" {
|
||||
c.TLSOptions.CAFile = filepath.Join(dockerCertPath, defaultCaFile)
|
||||
}
|
||||
if c.TLSOptions.CertFile == "" {
|
||||
c.TLSOptions.CertFile = filepath.Join(dockerCertPath, defaultCertFile)
|
||||
}
|
||||
if c.TLSOptions.KeyFile == "" {
|
||||
c.TLSOptions.KeyFile = filepath.Join(dockerCertPath, defaultKeyFile)
|
||||
}
|
||||
if c.TrustKey == "" {
|
||||
c.TrustKey = filepath.Join(homedir.Get(), ".docker", defaultTrustKeyFile)
|
||||
}
|
||||
if c.TLSVerify {
|
||||
c.TLS = true
|
||||
}
|
||||
if c.TLS {
|
||||
c.TLSOptions.InsecureSkipVerify = !c.TLSVerify
|
||||
}
|
||||
|
||||
var httpClient *http.Client
|
||||
if c.TLS {
|
||||
config, err := tlsconfig.Client(c.TLSOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: config,
|
||||
}
|
||||
proto, addr, _, err := client.ParseHost(c.Host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := sockets.ConfigureTransport(tr, proto, addr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpClient = &http.Client{
|
||||
Transport: tr,
|
||||
}
|
||||
}
|
||||
|
||||
customHeaders := map[string]string{}
|
||||
customHeaders["User-Agent"] = fmt.Sprintf("Libcompose-Client/%s (%s)", version.VERSION, runtime.GOOS)
|
||||
|
||||
client, err := client.NewClient(c.Host, apiVersion, httpClient, customHeaders)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
35
integration/vendor/github.com/docker/libcompose/docker/client/client_factory.go
generated
vendored
Normal file
35
integration/vendor/github.com/docker/libcompose/docker/client/client_factory.go
generated
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"github.com/docker/engine-api/client"
|
||||
"github.com/docker/libcompose/project"
|
||||
)
|
||||
|
||||
// Factory is a factory to create docker clients.
|
||||
type Factory interface {
|
||||
// Create constructs a Docker client for the given service. The passed in
|
||||
// config may be nil in which case a generic client for the project should
|
||||
// be returned.
|
||||
Create(service project.Service) client.APIClient
|
||||
}
|
||||
|
||||
type defaultFactory struct {
|
||||
client client.APIClient
|
||||
}
|
||||
|
||||
// NewDefaultFactory creates and returns the default client factory that uses
|
||||
// github.com/docker/engine-api client.
|
||||
func NewDefaultFactory(opts Options) (Factory, error) {
|
||||
client, err := Create(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &defaultFactory{
|
||||
client: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *defaultFactory) Create(service project.Service) client.APIClient {
|
||||
return s.client
|
||||
}
|
||||
766
integration/vendor/github.com/docker/libcompose/docker/container.go
generated
vendored
Normal file
766
integration/vendor/github.com/docker/libcompose/docker/container.go
generated
vendored
Normal file
|
|
@ -0,0 +1,766 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/pkg/promise"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
"github.com/docker/docker/pkg/term"
|
||||
"github.com/docker/engine-api/client"
|
||||
"github.com/docker/engine-api/types"
|
||||
"github.com/docker/engine-api/types/container"
|
||||
"github.com/docker/engine-api/types/network"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/docker/libcompose/config"
|
||||
"github.com/docker/libcompose/labels"
|
||||
"github.com/docker/libcompose/logger"
|
||||
"github.com/docker/libcompose/project"
|
||||
"github.com/docker/libcompose/project/events"
|
||||
util "github.com/docker/libcompose/utils"
|
||||
"github.com/docker/libcompose/yaml"
|
||||
)
|
||||
|
||||
// Container holds information about a docker container and the service it is tied on.
|
||||
type Container struct {
|
||||
name string
|
||||
serviceName string
|
||||
projectName string
|
||||
containerNumber int
|
||||
oneOff bool
|
||||
eventNotifier events.Notifier
|
||||
loggerFactory logger.Factory
|
||||
client client.APIClient
|
||||
|
||||
// FIXME(vdemeester) Remove this dependency
|
||||
service *Service
|
||||
}
|
||||
|
||||
// NewContainer creates a container struct with the specified docker client, name and service.
|
||||
func NewContainer(client client.APIClient, name string, containerNumber int, service *Service) *Container {
|
||||
return &Container{
|
||||
client: client,
|
||||
name: name,
|
||||
containerNumber: containerNumber,
|
||||
|
||||
// TODO(vdemeester) Move these to arguments
|
||||
serviceName: service.name,
|
||||
projectName: service.project.Name,
|
||||
eventNotifier: service.project,
|
||||
loggerFactory: service.context.LoggerFactory,
|
||||
|
||||
// TODO(vdemeester) Remove this dependency
|
||||
service: service,
|
||||
}
|
||||
}
|
||||
|
||||
// NewOneOffContainer creates a "oneoff" container struct with the specified docker client, name and service.
|
||||
func NewOneOffContainer(client client.APIClient, name string, containerNumber int, service *Service) *Container {
|
||||
c := NewContainer(client, name, containerNumber, service)
|
||||
c.oneOff = true
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Container) findExisting(ctx context.Context) (*types.ContainerJSON, error) {
|
||||
return GetContainer(ctx, c.client, c.name)
|
||||
}
|
||||
|
||||
// Info returns info about the container, like name, command, state or ports.
|
||||
func (c *Container) Info(ctx context.Context, qFlag bool) (project.Info, error) {
|
||||
container, err := c.findExisting(ctx)
|
||||
if err != nil || container == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
infos, err := GetContainersByFilter(ctx, c.client, map[string][]string{
|
||||
"name": {container.Name},
|
||||
})
|
||||
if err != nil || len(infos) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
info := infos[0]
|
||||
|
||||
result := project.Info{}
|
||||
if qFlag {
|
||||
result = append(result, project.InfoPart{Key: "Id", Value: container.ID})
|
||||
} else {
|
||||
result = append(result, project.InfoPart{Key: "Name", Value: name(info.Names)})
|
||||
result = append(result, project.InfoPart{Key: "Command", Value: info.Command})
|
||||
result = append(result, project.InfoPart{Key: "State", Value: info.Status})
|
||||
result = append(result, project.InfoPart{Key: "Ports", Value: portString(info.Ports)})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func portString(ports []types.Port) string {
|
||||
result := []string{}
|
||||
|
||||
for _, port := range ports {
|
||||
if port.PublicPort > 0 {
|
||||
result = append(result, fmt.Sprintf("%s:%d->%d/%s", port.IP, port.PublicPort, port.PrivatePort, port.Type))
|
||||
} else {
|
||||
result = append(result, fmt.Sprintf("%d/%s", port.PrivatePort, port.Type))
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(result, ", ")
|
||||
}
|
||||
|
||||
func name(names []string) string {
|
||||
max := math.MaxInt32
|
||||
var current string
|
||||
|
||||
for _, v := range names {
|
||||
if len(v) < max {
|
||||
max = len(v)
|
||||
current = v
|
||||
}
|
||||
}
|
||||
|
||||
return current[1:]
|
||||
}
|
||||
|
||||
// Recreate will not refresh the container by means of relaxation and enjoyment,
|
||||
// just delete it and create a new one with the current configuration
|
||||
func (c *Container) Recreate(ctx context.Context, imageName string) (*types.ContainerJSON, error) {
|
||||
container, err := c.findExisting(ctx)
|
||||
if err != nil || container == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hash := container.Config.Labels[labels.HASH.Str()]
|
||||
if hash == "" {
|
||||
return nil, fmt.Errorf("Failed to find hash on old container: %s", container.Name)
|
||||
}
|
||||
|
||||
name := container.Name[1:]
|
||||
newName := fmt.Sprintf("%s_%s", name, container.ID[:12])
|
||||
logrus.Debugf("Renaming %s => %s", name, newName)
|
||||
if err := c.client.ContainerRename(ctx, container.ID, newName); err != nil {
|
||||
logrus.Errorf("Failed to rename old container %s", c.name)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newContainer, err := c.createContainer(ctx, imageName, container.ID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logrus.Debugf("Created replacement container %s", newContainer.ID)
|
||||
|
||||
if err := c.client.ContainerRemove(ctx, container.ID, types.ContainerRemoveOptions{
|
||||
Force: true,
|
||||
RemoveVolumes: false,
|
||||
}); err != nil {
|
||||
logrus.Errorf("Failed to remove old container %s", c.name)
|
||||
return nil, err
|
||||
}
|
||||
logrus.Debugf("Removed old container %s %s", c.name, container.ID)
|
||||
|
||||
return newContainer, nil
|
||||
}
|
||||
|
||||
// Create creates the container based on the specified image name and send an event
|
||||
// to notify the container has been created. If the container already exists, does
|
||||
// nothing.
|
||||
func (c *Container) Create(ctx context.Context, imageName string) (*types.ContainerJSON, error) {
|
||||
return c.CreateWithOverride(ctx, imageName, nil)
|
||||
}
|
||||
|
||||
// CreateWithOverride create container and override parts of the config to
|
||||
// allow special situations to override the config generated from the compose
|
||||
// file
|
||||
func (c *Container) CreateWithOverride(ctx context.Context, imageName string, configOverride *config.ServiceConfig) (*types.ContainerJSON, error) {
|
||||
container, err := c.findExisting(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if container == nil {
|
||||
container, err = c.createContainer(ctx, imageName, "", configOverride)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.eventNotifier.Notify(events.ContainerCreated, c.serviceName, map[string]string{
|
||||
"name": c.Name(),
|
||||
})
|
||||
}
|
||||
|
||||
return container, err
|
||||
}
|
||||
|
||||
// Stop stops the container.
|
||||
func (c *Container) Stop(ctx context.Context, timeout int) error {
|
||||
return c.withContainer(ctx, func(container *types.ContainerJSON) error {
|
||||
timeoutDuration := time.Duration(timeout) * time.Second
|
||||
return c.client.ContainerStop(ctx, container.ID, &timeoutDuration)
|
||||
})
|
||||
}
|
||||
|
||||
// Pause pauses the container. If the containers are already paused, don't fail.
|
||||
func (c *Container) Pause(ctx context.Context) error {
|
||||
return c.withContainer(ctx, func(container *types.ContainerJSON) error {
|
||||
if !container.State.Paused {
|
||||
return c.client.ContainerPause(ctx, container.ID)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Unpause unpauses the container. If the containers are not paused, don't fail.
|
||||
func (c *Container) Unpause(ctx context.Context) error {
|
||||
return c.withContainer(ctx, func(container *types.ContainerJSON) error {
|
||||
if container.State.Paused {
|
||||
return c.client.ContainerUnpause(ctx, container.ID)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Kill kill the container.
|
||||
func (c *Container) Kill(ctx context.Context, signal string) error {
|
||||
return c.withContainer(ctx, func(container *types.ContainerJSON) error {
|
||||
return c.client.ContainerKill(ctx, container.ID, signal)
|
||||
})
|
||||
}
|
||||
|
||||
// Delete removes the container if existing. If the container is running, it tries
|
||||
// to stop it first.
|
||||
func (c *Container) Delete(ctx context.Context, removeVolume bool) error {
|
||||
container, err := c.findExisting(ctx)
|
||||
if err != nil || container == nil {
|
||||
return err
|
||||
}
|
||||
|
||||
info, err := c.client.ContainerInspect(ctx, container.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !info.State.Running {
|
||||
return c.client.ContainerRemove(ctx, container.ID, types.ContainerRemoveOptions{
|
||||
Force: true,
|
||||
RemoveVolumes: removeVolume,
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsRunning returns the running state of the container.
|
||||
func (c *Container) IsRunning(ctx context.Context) (bool, error) {
|
||||
container, err := c.findExisting(ctx)
|
||||
if err != nil || container == nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
info, err := c.client.ContainerInspect(ctx, container.ID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return info.State.Running, nil
|
||||
}
|
||||
|
||||
// Run creates, start and attach to the container based on the image name,
|
||||
// the specified configuration.
|
||||
// It will always create a new container.
|
||||
func (c *Container) Run(ctx context.Context, configOverride *config.ServiceConfig) (int, error) {
|
||||
var (
|
||||
errCh chan error
|
||||
out, stderr io.Writer
|
||||
in io.ReadCloser
|
||||
)
|
||||
|
||||
container, err := c.findExisting(ctx)
|
||||
if err != nil || container == nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if configOverride.StdinOpen {
|
||||
in = os.Stdin
|
||||
}
|
||||
if configOverride.Tty {
|
||||
out = os.Stdout
|
||||
}
|
||||
if configOverride.Tty {
|
||||
stderr = os.Stderr
|
||||
}
|
||||
|
||||
options := types.ContainerAttachOptions{
|
||||
Stream: true,
|
||||
Stdin: configOverride.StdinOpen,
|
||||
Stdout: configOverride.Tty,
|
||||
Stderr: configOverride.Tty,
|
||||
}
|
||||
|
||||
resp, err := c.client.ContainerAttach(ctx, container.ID, options)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
// set raw terminal
|
||||
inFd, _ := term.GetFdInfo(in)
|
||||
state, err := term.SetRawTerminal(inFd)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
// restore raw terminal
|
||||
defer term.RestoreTerminal(inFd, state)
|
||||
// holdHijackedConnection (in goroutine)
|
||||
errCh = promise.Go(func() error {
|
||||
return holdHijackedConnection(configOverride.Tty, in, out, stderr, resp)
|
||||
})
|
||||
|
||||
if err := c.client.ContainerStart(ctx, container.ID, types.ContainerStartOptions{}); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if err := <-errCh; err != nil {
|
||||
logrus.Debugf("Error hijack: %s", err)
|
||||
return -1, err
|
||||
}
|
||||
|
||||
exitedContainer, err := c.client.ContainerInspect(ctx, container.ID)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
return exitedContainer.State.ExitCode, nil
|
||||
}
|
||||
|
||||
func holdHijackedConnection(tty bool, inputStream io.ReadCloser, outputStream, errorStream io.Writer, resp types.HijackedResponse) error {
|
||||
var err error
|
||||
receiveStdout := make(chan error, 1)
|
||||
if outputStream != nil || errorStream != nil {
|
||||
go func() {
|
||||
// When TTY is ON, use regular copy
|
||||
if tty && outputStream != nil {
|
||||
_, err = io.Copy(outputStream, resp.Reader)
|
||||
} else {
|
||||
_, err = stdcopy.StdCopy(outputStream, errorStream, resp.Reader)
|
||||
}
|
||||
logrus.Debugf("[hijack] End of stdout")
|
||||
receiveStdout <- err
|
||||
}()
|
||||
}
|
||||
|
||||
stdinDone := make(chan struct{})
|
||||
go func() {
|
||||
if inputStream != nil {
|
||||
io.Copy(resp.Conn, inputStream)
|
||||
logrus.Debugf("[hijack] End of stdin")
|
||||
}
|
||||
|
||||
if err := resp.CloseWrite(); err != nil {
|
||||
logrus.Debugf("Couldn't send EOF: %s", err)
|
||||
}
|
||||
close(stdinDone)
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-receiveStdout:
|
||||
if err != nil {
|
||||
logrus.Debugf("Error receiveStdout: %s", err)
|
||||
return err
|
||||
}
|
||||
case <-stdinDone:
|
||||
if outputStream != nil || errorStream != nil {
|
||||
if err := <-receiveStdout; err != nil {
|
||||
logrus.Debugf("Error receiveStdout: %s", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Start the specified container with the specified host config
|
||||
func (c *Container) Start(ctx context.Context) error {
|
||||
container, err := c.findExisting(ctx)
|
||||
if err != nil || container == nil {
|
||||
return err
|
||||
}
|
||||
logrus.WithFields(logrus.Fields{"container.ID": container.ID, "c.name": c.name}).Debug("Starting container")
|
||||
if err := c.client.ContainerStart(context.Background(), container.ID, types.ContainerStartOptions{}); err != nil {
|
||||
logrus.WithFields(logrus.Fields{"container.ID": container.ID, "c.name": c.name}).Debug("Failed to start container")
|
||||
return err
|
||||
}
|
||||
c.eventNotifier.Notify(events.ContainerStarted, c.serviceName, map[string]string{
|
||||
"name": c.Name(),
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// OutOfSync checks if the container is out of sync with the service definition.
|
||||
// It looks if the the service hash container label is the same as the computed one.
|
||||
func (c *Container) OutOfSync(ctx context.Context, imageName string) (bool, error) {
|
||||
container, err := c.findExisting(ctx)
|
||||
if err != nil || container == nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if container.Config.Image != imageName {
|
||||
logrus.Debugf("Images for %s do not match %s!=%s", c.name, container.Config.Image, imageName)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if container.Config.Labels[labels.HASH.Str()] != c.getHash() {
|
||||
logrus.Debugf("Hashes for %s do not match %s!=%s", c.name, container.Config.Labels[labels.HASH.Str()], c.getHash())
|
||||
return true, nil
|
||||
}
|
||||
|
||||
image, _, err := c.client.ImageInspectWithRaw(ctx, container.Config.Image, false)
|
||||
if err != nil {
|
||||
if client.IsErrImageNotFound(err) {
|
||||
logrus.Debugf("Image %s do not exist, do not know if it's out of sync", container.Config.Image)
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
logrus.Debugf("Checking existing image name vs id: %s == %s", image.ID, container.Image)
|
||||
return image.ID != container.Image, err
|
||||
}
|
||||
|
||||
func (c *Container) getHash() string {
|
||||
return config.GetServiceHash(c.serviceName, c.service.Config())
|
||||
}
|
||||
|
||||
func volumeBinds(volumes map[string]struct{}, container *types.ContainerJSON) []string {
|
||||
result := make([]string, 0, len(container.Mounts))
|
||||
for _, mount := range container.Mounts {
|
||||
if _, ok := volumes[mount.Destination]; ok {
|
||||
result = append(result, fmt.Sprint(mount.Source, ":", mount.Destination))
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (c *Container) createContainer(ctx context.Context, imageName, oldContainer string, configOverride *config.ServiceConfig) (*types.ContainerJSON, error) {
|
||||
serviceConfig := c.service.serviceConfig
|
||||
if configOverride != nil {
|
||||
serviceConfig.Command = configOverride.Command
|
||||
serviceConfig.Tty = configOverride.Tty
|
||||
serviceConfig.StdinOpen = configOverride.StdinOpen
|
||||
}
|
||||
configWrapper, err := ConvertToAPI(c.service)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
configWrapper.Config.Image = imageName
|
||||
|
||||
if configWrapper.Config.Labels == nil {
|
||||
configWrapper.Config.Labels = map[string]string{}
|
||||
}
|
||||
|
||||
oneOffString := "False"
|
||||
if c.oneOff {
|
||||
oneOffString = "True"
|
||||
}
|
||||
|
||||
configWrapper.Config.Labels[labels.SERVICE.Str()] = c.serviceName
|
||||
configWrapper.Config.Labels[labels.PROJECT.Str()] = c.projectName
|
||||
configWrapper.Config.Labels[labels.HASH.Str()] = c.getHash()
|
||||
configWrapper.Config.Labels[labels.ONEOFF.Str()] = oneOffString
|
||||
configWrapper.Config.Labels[labels.NUMBER.Str()] = fmt.Sprint(c.containerNumber)
|
||||
configWrapper.Config.Labels[labels.VERSION.Str()] = ComposeVersion
|
||||
|
||||
err = c.populateAdditionalHostConfig(configWrapper.HostConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if oldContainer != "" {
|
||||
info, err := c.client.ContainerInspect(ctx, oldContainer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
configWrapper.HostConfig.Binds = util.Merge(configWrapper.HostConfig.Binds, volumeBinds(configWrapper.Config.Volumes, &info))
|
||||
}
|
||||
|
||||
logrus.Debugf("Creating container %s %#v", c.name, configWrapper)
|
||||
|
||||
container, err := c.client.ContainerCreate(ctx, configWrapper.Config, configWrapper.HostConfig, configWrapper.NetworkingConfig, c.name)
|
||||
if err != nil {
|
||||
logrus.Debugf("Failed to create container %s: %v", c.name, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return GetContainer(ctx, c.client, container.ID)
|
||||
}
|
||||
|
||||
func (c *Container) populateAdditionalHostConfig(hostConfig *container.HostConfig) error {
|
||||
links, err := c.getLinks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, link := range c.service.DependentServices() {
|
||||
if !c.service.project.ServiceConfigs.Has(link.Target) {
|
||||
continue
|
||||
}
|
||||
|
||||
service, err := c.service.project.CreateService(link.Target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// FIXME(vdemeester) container should not know service
|
||||
containers, err := service.Containers(context.Background())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if link.Type == project.RelTypeIpcNamespace {
|
||||
hostConfig, err = c.addIpc(hostConfig, service, containers)
|
||||
} else if link.Type == project.RelTypeNetNamespace {
|
||||
hostConfig, err = c.addNetNs(hostConfig, service, containers)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
hostConfig.Links = []string{}
|
||||
for k, v := range links {
|
||||
hostConfig.Links = append(hostConfig.Links, strings.Join([]string{v, k}, ":"))
|
||||
}
|
||||
for _, v := range c.service.Config().ExternalLinks {
|
||||
hostConfig.Links = append(hostConfig.Links, v)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FIXME(vdemeester) this is temporary
|
||||
func (c *Container) getLinks() (map[string]string, error) {
|
||||
links := map[string]string{}
|
||||
for _, link := range c.service.DependentServices() {
|
||||
if !c.service.project.ServiceConfigs.Has(link.Target) {
|
||||
continue
|
||||
}
|
||||
|
||||
service, err := c.service.project.CreateService(link.Target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// FIXME(vdemeester) container should not know service
|
||||
containers, err := service.Containers(context.Background())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if link.Type == project.RelTypeLink {
|
||||
c.addLinks(links, service, link, containers)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return links, nil
|
||||
}
|
||||
|
||||
func (c *Container) addLinks(links map[string]string, service project.Service, rel project.ServiceRelationship, containers []project.Container) {
|
||||
for _, container := range containers {
|
||||
if _, ok := links[rel.Alias]; !ok {
|
||||
links[rel.Alias] = container.Name()
|
||||
}
|
||||
|
||||
links[container.Name()] = container.Name()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Container) addIpc(config *container.HostConfig, service project.Service, containers []project.Container) (*container.HostConfig, error) {
|
||||
if len(containers) == 0 {
|
||||
return nil, fmt.Errorf("Failed to find container for IPC %v", c.service.Config().Ipc)
|
||||
}
|
||||
|
||||
id, err := containers[0].ID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config.IpcMode = container.IpcMode("container:" + id)
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func (c *Container) addNetNs(config *container.HostConfig, service project.Service, containers []project.Container) (*container.HostConfig, error) {
|
||||
if len(containers) == 0 {
|
||||
return nil, fmt.Errorf("Failed to find container for networks ns %v", c.service.Config().NetworkMode)
|
||||
}
|
||||
|
||||
id, err := containers[0].ID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config.NetworkMode = container.NetworkMode("container:" + id)
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// ID returns the container Id.
|
||||
func (c *Container) ID() (string, error) {
|
||||
// FIXME(vdemeester) container should not ask for his ID..
|
||||
container, err := c.findExisting(context.Background())
|
||||
if container == nil {
|
||||
return "", err
|
||||
}
|
||||
return container.ID, err
|
||||
}
|
||||
|
||||
// Name returns the container name.
|
||||
func (c *Container) Name() string {
|
||||
return c.name
|
||||
}
|
||||
|
||||
// Restart restarts the container if existing, does nothing otherwise.
|
||||
func (c *Container) Restart(ctx context.Context, timeout int) error {
|
||||
container, err := c.findExisting(ctx)
|
||||
if err != nil || container == nil {
|
||||
return err
|
||||
}
|
||||
|
||||
timeoutDuration := time.Duration(timeout) * time.Second
|
||||
return c.client.ContainerRestart(ctx, container.ID, &timeoutDuration)
|
||||
}
|
||||
|
||||
// Log forwards container logs to the project configured logger.
|
||||
func (c *Container) Log(ctx context.Context, follow bool) error {
|
||||
container, err := c.findExisting(ctx)
|
||||
if container == nil || err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
info, err := c.client.ContainerInspect(ctx, container.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// FIXME(vdemeester) update container struct to do less API calls
|
||||
name := fmt.Sprintf("%s_%d", c.service.name, c.containerNumber)
|
||||
l := c.loggerFactory.Create(name)
|
||||
|
||||
options := types.ContainerLogsOptions{
|
||||
ShowStdout: true,
|
||||
ShowStderr: true,
|
||||
Follow: follow,
|
||||
Tail: "all",
|
||||
}
|
||||
responseBody, err := c.client.ContainerLogs(ctx, c.name, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer responseBody.Close()
|
||||
|
||||
if info.Config.Tty {
|
||||
_, err = io.Copy(&logger.Wrapper{Logger: l}, responseBody)
|
||||
} else {
|
||||
_, err = stdcopy.StdCopy(&logger.Wrapper{Logger: l}, &logger.Wrapper{Logger: l, Err: true}, responseBody)
|
||||
}
|
||||
logrus.WithFields(logrus.Fields{"Logger": l, "err": err}).Debug("c.client.Logs() returned error")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Container) withContainer(ctx context.Context, action func(*types.ContainerJSON) error) error {
|
||||
container, err := c.findExisting(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if container != nil {
|
||||
return action(container)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Port returns the host port the specified port is mapped on.
|
||||
func (c *Container) Port(ctx context.Context, port string) (string, error) {
|
||||
container, err := c.findExisting(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if bindings, ok := container.NetworkSettings.Ports[nat.Port(port)]; ok {
|
||||
result := []string{}
|
||||
for _, binding := range bindings {
|
||||
result = append(result, binding.HostIP+":"+binding.HostPort)
|
||||
}
|
||||
|
||||
return strings.Join(result, "\n"), nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Networks returns the containers network
|
||||
// FIXME(vdemeester) should not need ctx or calling the API, will take care of it
|
||||
// when refactoring Container.
|
||||
func (c *Container) Networks(ctx context.Context) (map[string]*network.EndpointSettings, error) {
|
||||
container, err := c.findExisting(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if container == nil {
|
||||
return map[string]*network.EndpointSettings{}, nil
|
||||
}
|
||||
return container.NetworkSettings.Networks, nil
|
||||
}
|
||||
|
||||
// NetworkDisconnect disconnects the container from the specified network
|
||||
// FIXME(vdemeester) will be refactor with Container refactoring
|
||||
func (c *Container) NetworkDisconnect(ctx context.Context, net *yaml.Network) error {
|
||||
container, err := c.findExisting(ctx)
|
||||
if err != nil || container == nil {
|
||||
return err
|
||||
}
|
||||
return c.client.NetworkDisconnect(ctx, net.RealName, container.ID, true)
|
||||
}
|
||||
|
||||
// NetworkConnect connects the container to the specified network
|
||||
// FIXME(vdemeester) will be refactor with Container refactoring
|
||||
func (c *Container) NetworkConnect(ctx context.Context, net *yaml.Network) error {
|
||||
container, err := c.findExisting(ctx)
|
||||
if err != nil || container == nil {
|
||||
return err
|
||||
}
|
||||
internalLinks, err := c.getLinks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
links := []string{}
|
||||
// TODO(vdemeester) handle link to self (?)
|
||||
for k, v := range internalLinks {
|
||||
links = append(links, strings.Join([]string{v, k}, ":"))
|
||||
}
|
||||
for _, v := range c.service.Config().ExternalLinks {
|
||||
links = append(links, v)
|
||||
}
|
||||
aliases := []string{}
|
||||
if !c.oneOff {
|
||||
aliases = []string{c.serviceName}
|
||||
}
|
||||
aliases = append(aliases, net.Aliases...)
|
||||
return c.client.NetworkConnect(ctx, net.RealName, container.ID, &network.EndpointSettings{
|
||||
Aliases: aliases,
|
||||
Links: links,
|
||||
IPAddress: net.IPv4Address,
|
||||
IPAMConfig: &network.EndpointIPAMConfig{
|
||||
IPv4Address: net.IPv4Address,
|
||||
IPv6Address: net.IPv6Address,
|
||||
},
|
||||
})
|
||||
}
|
||||
38
integration/vendor/github.com/docker/libcompose/docker/context.go
generated
vendored
Normal file
38
integration/vendor/github.com/docker/libcompose/docker/context.go
generated
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/cliconfig"
|
||||
"github.com/docker/docker/cliconfig/configfile"
|
||||
"github.com/docker/libcompose/docker/client"
|
||||
"github.com/docker/libcompose/project"
|
||||
)
|
||||
|
||||
// Context holds context meta information about a libcompose project and docker
|
||||
// client information (like configuration file, builder to use, …)
|
||||
type Context struct {
|
||||
project.Context
|
||||
ClientFactory client.Factory
|
||||
ConfigDir string
|
||||
ConfigFile *configfile.ConfigFile
|
||||
AuthLookup AuthLookup
|
||||
}
|
||||
|
||||
func (c *Context) open() error {
|
||||
return c.LookupConfig()
|
||||
}
|
||||
|
||||
// LookupConfig tries to load the docker configuration files, if any.
|
||||
func (c *Context) LookupConfig() error {
|
||||
if c.ConfigFile != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
config, err := cliconfig.Load(c.ConfigDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.ConfigFile = config
|
||||
|
||||
return nil
|
||||
}
|
||||
288
integration/vendor/github.com/docker/libcompose/docker/convert.go
generated
vendored
Normal file
288
integration/vendor/github.com/docker/libcompose/docker/convert.go
generated
vendored
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/docker/runconfig/opts"
|
||||
"github.com/docker/engine-api/types/container"
|
||||
"github.com/docker/engine-api/types/network"
|
||||
"github.com/docker/engine-api/types/strslice"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/docker/libcompose/config"
|
||||
composeclient "github.com/docker/libcompose/docker/client"
|
||||
"github.com/docker/libcompose/project"
|
||||
"github.com/docker/libcompose/utils"
|
||||
)
|
||||
|
||||
// ConfigWrapper wraps Config, HostConfig and NetworkingConfig for a container.
|
||||
type ConfigWrapper struct {
|
||||
Config *container.Config
|
||||
HostConfig *container.HostConfig
|
||||
NetworkingConfig *network.NetworkingConfig
|
||||
}
|
||||
|
||||
// Filter filters the specified string slice with the specified function.
|
||||
func Filter(vs []string, f func(string) bool) []string {
|
||||
r := make([]string, 0, len(vs))
|
||||
for _, v := range vs {
|
||||
if f(v) {
|
||||
r = append(r, v)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func isBind(s string) bool {
|
||||
return strings.ContainsRune(s, ':')
|
||||
}
|
||||
|
||||
func isVolume(s string) bool {
|
||||
return !isBind(s)
|
||||
}
|
||||
|
||||
// ConvertToAPI converts a service configuration to a docker API container configuration.
|
||||
func ConvertToAPI(s *Service) (*ConfigWrapper, error) {
|
||||
config, hostConfig, err := Convert(s.serviceConfig, s.context.Context, s.clientFactory)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := ConfigWrapper{
|
||||
Config: config,
|
||||
HostConfig: hostConfig,
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func isNamedVolume(volume string) bool {
|
||||
return !strings.HasPrefix(volume, ".") && !strings.HasPrefix(volume, "/") && !strings.HasPrefix(volume, "~")
|
||||
}
|
||||
|
||||
func volumes(c *config.ServiceConfig, ctx project.Context) map[string]struct{} {
|
||||
volumes := make(map[string]struct{}, len(c.Volumes))
|
||||
for k, v := range c.Volumes {
|
||||
if len(ctx.ComposeFiles) > 0 && !isNamedVolume(v) {
|
||||
v = ctx.ResourceLookup.ResolvePath(v, ctx.ComposeFiles[0])
|
||||
}
|
||||
|
||||
c.Volumes[k] = v
|
||||
if isVolume(v) {
|
||||
volumes[v] = struct{}{}
|
||||
}
|
||||
}
|
||||
return volumes
|
||||
}
|
||||
|
||||
func restartPolicy(c *config.ServiceConfig) (*container.RestartPolicy, error) {
|
||||
restart, err := opts.ParseRestartPolicy(c.Restart)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &container.RestartPolicy{Name: restart.Name, MaximumRetryCount: restart.MaximumRetryCount}, nil
|
||||
}
|
||||
|
||||
func ports(c *config.ServiceConfig) (map[nat.Port]struct{}, nat.PortMap, error) {
|
||||
ports, binding, err := nat.ParsePortSpecs(c.Ports)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
exPorts, _, err := nat.ParsePortSpecs(c.Expose)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
for k, v := range exPorts {
|
||||
ports[k] = v
|
||||
}
|
||||
|
||||
exposedPorts := map[nat.Port]struct{}{}
|
||||
for k, v := range ports {
|
||||
exposedPorts[nat.Port(k)] = v
|
||||
}
|
||||
|
||||
portBindings := nat.PortMap{}
|
||||
for k, bv := range binding {
|
||||
dcbs := make([]nat.PortBinding, len(bv))
|
||||
for k, v := range bv {
|
||||
dcbs[k] = nat.PortBinding{HostIP: v.HostIP, HostPort: v.HostPort}
|
||||
}
|
||||
portBindings[nat.Port(k)] = dcbs
|
||||
}
|
||||
return exposedPorts, portBindings, nil
|
||||
}
|
||||
|
||||
// Convert converts a service configuration to an docker API structures (Config and HostConfig)
|
||||
func Convert(c *config.ServiceConfig, ctx project.Context, clientFactory composeclient.Factory) (*container.Config, *container.HostConfig, error) {
|
||||
restartPolicy, err := restartPolicy(c)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
exposedPorts, portBindings, err := ports(c)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
deviceMappings, err := parseDevices(c.Devices)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var volumesFrom []string
|
||||
if c.VolumesFrom != nil {
|
||||
volumesFrom, err = getVolumesFrom(c.VolumesFrom, ctx.Project.ServiceConfigs, ctx.ProjectName)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
config := &container.Config{
|
||||
Entrypoint: strslice.StrSlice(utils.CopySlice(c.Entrypoint)),
|
||||
Hostname: c.Hostname,
|
||||
Domainname: c.DomainName,
|
||||
User: c.User,
|
||||
Env: utils.CopySlice(c.Environment),
|
||||
Cmd: strslice.StrSlice(utils.CopySlice(c.Command)),
|
||||
Image: c.Image,
|
||||
Labels: utils.CopyMap(c.Labels),
|
||||
ExposedPorts: exposedPorts,
|
||||
Tty: c.Tty,
|
||||
OpenStdin: c.StdinOpen,
|
||||
WorkingDir: c.WorkingDir,
|
||||
Volumes: volumes(c, ctx),
|
||||
MacAddress: c.MacAddress,
|
||||
}
|
||||
|
||||
ulimits := []*units.Ulimit{}
|
||||
if c.Ulimits.Elements != nil {
|
||||
for _, ulimit := range c.Ulimits.Elements {
|
||||
ulimits = append(ulimits, &units.Ulimit{
|
||||
Name: ulimit.Name,
|
||||
Soft: ulimit.Soft,
|
||||
Hard: ulimit.Hard,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
resources := container.Resources{
|
||||
CgroupParent: c.CgroupParent,
|
||||
Memory: c.MemLimit,
|
||||
MemorySwap: c.MemSwapLimit,
|
||||
CPUShares: c.CPUShares,
|
||||
CPUQuota: c.CPUQuota,
|
||||
CpusetCpus: c.CPUSet,
|
||||
Ulimits: ulimits,
|
||||
Devices: deviceMappings,
|
||||
}
|
||||
|
||||
networkMode := c.NetworkMode
|
||||
if c.NetworkMode == "" {
|
||||
if c.Networks != nil && len(c.Networks.Networks) > 0 {
|
||||
networkMode = c.Networks.Networks[0].RealName
|
||||
}
|
||||
} else {
|
||||
switch {
|
||||
case strings.HasPrefix(c.NetworkMode, "service:"):
|
||||
serviceName := c.NetworkMode[8:]
|
||||
if serviceConfig, ok := ctx.Project.ServiceConfigs.Get(serviceName); ok {
|
||||
// FIXME(vdemeester) this is actually not right, should be fixed but not there
|
||||
service, err := ctx.ServiceFactory.Create(ctx.Project, serviceName, serviceConfig)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
containers, err := service.Containers(context.Background())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if len(containers) != 0 {
|
||||
container := containers[0]
|
||||
containerID, err := container.ID()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
networkMode = "container:" + containerID
|
||||
}
|
||||
// FIXME(vdemeester) log/warn in case of len(containers) == 0
|
||||
}
|
||||
case strings.HasPrefix(c.NetworkMode, "container:"):
|
||||
containerName := c.NetworkMode[10:]
|
||||
client := clientFactory.Create(nil)
|
||||
container, err := GetContainer(context.Background(), client, containerName)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
networkMode = "container:" + container.ID
|
||||
default:
|
||||
// do nothing :)
|
||||
}
|
||||
}
|
||||
|
||||
hostConfig := &container.HostConfig{
|
||||
VolumesFrom: volumesFrom,
|
||||
CapAdd: strslice.StrSlice(utils.CopySlice(c.CapAdd)),
|
||||
CapDrop: strslice.StrSlice(utils.CopySlice(c.CapDrop)),
|
||||
ExtraHosts: utils.CopySlice(c.ExtraHosts),
|
||||
Privileged: c.Privileged,
|
||||
Binds: Filter(c.Volumes, isBind),
|
||||
DNS: utils.CopySlice(c.DNS),
|
||||
DNSSearch: utils.CopySlice(c.DNSSearch),
|
||||
LogConfig: container.LogConfig{
|
||||
Type: c.Logging.Driver,
|
||||
Config: utils.CopyMap(c.Logging.Options),
|
||||
},
|
||||
NetworkMode: container.NetworkMode(networkMode),
|
||||
ReadonlyRootfs: c.ReadOnly,
|
||||
PidMode: container.PidMode(c.Pid),
|
||||
UTSMode: container.UTSMode(c.Uts),
|
||||
IpcMode: container.IpcMode(c.Ipc),
|
||||
PortBindings: portBindings,
|
||||
RestartPolicy: *restartPolicy,
|
||||
ShmSize: c.ShmSize,
|
||||
SecurityOpt: utils.CopySlice(c.SecurityOpt),
|
||||
VolumeDriver: c.VolumeDriver,
|
||||
Resources: resources,
|
||||
}
|
||||
|
||||
return config, hostConfig, nil
|
||||
}
|
||||
|
||||
func getVolumesFrom(volumesFrom []string, serviceConfigs *config.ServiceConfigs, projectName string) ([]string, error) {
|
||||
volumes := []string{}
|
||||
for _, volumeFrom := range volumesFrom {
|
||||
if serviceConfig, ok := serviceConfigs.Get(volumeFrom); ok {
|
||||
// It's a service - Use the first one
|
||||
name := fmt.Sprintf("%s_%s_1", projectName, volumeFrom)
|
||||
// If a container name is specified, use that instead
|
||||
if serviceConfig.ContainerName != "" {
|
||||
name = serviceConfig.ContainerName
|
||||
}
|
||||
volumes = append(volumes, name)
|
||||
} else {
|
||||
volumes = append(volumes, volumeFrom)
|
||||
}
|
||||
}
|
||||
return volumes, nil
|
||||
}
|
||||
|
||||
func parseDevices(devices []string) ([]container.DeviceMapping, error) {
|
||||
// parse device mappings
|
||||
deviceMappings := []container.DeviceMapping{}
|
||||
for _, device := range devices {
|
||||
v, err := opts.ParseDevice(device)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
deviceMappings = append(deviceMappings, container.DeviceMapping{
|
||||
PathOnHost: v.PathOnHost,
|
||||
PathInContainer: v.PathInContainer,
|
||||
CgroupPermissions: v.CgroupPermissions,
|
||||
})
|
||||
}
|
||||
|
||||
return deviceMappings, nil
|
||||
}
|
||||
42
integration/vendor/github.com/docker/libcompose/docker/functions.go
generated
vendored
Normal file
42
integration/vendor/github.com/docker/libcompose/docker/functions.go
generated
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/engine-api/client"
|
||||
"github.com/docker/engine-api/types"
|
||||
"github.com/docker/engine-api/types/filters"
|
||||
)
|
||||
|
||||
// GetContainersByFilter looks up the hosts containers with the specified filters and
|
||||
// returns a list of container matching it, or an error.
|
||||
func GetContainersByFilter(ctx context.Context, clientInstance client.APIClient, containerFilters ...map[string][]string) ([]types.Container, error) {
|
||||
filterArgs := filters.NewArgs()
|
||||
|
||||
// FIXME(vdemeester) I don't like 3 for loops >_<
|
||||
for _, filter := range containerFilters {
|
||||
for key, filterValue := range filter {
|
||||
for _, value := range filterValue {
|
||||
filterArgs.Add(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return clientInstance.ContainerList(ctx, types.ContainerListOptions{
|
||||
All: true,
|
||||
Filter: filterArgs,
|
||||
})
|
||||
}
|
||||
|
||||
// GetContainer looks up the hosts containers with the specified ID
|
||||
// or name and returns it, or an error.
|
||||
func GetContainer(ctx context.Context, clientInstance client.APIClient, id string) (*types.ContainerJSON, error) {
|
||||
container, err := clientInstance.ContainerInspect(ctx, id)
|
||||
if err != nil {
|
||||
if client.IsErrContainerNotFound(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &container, nil
|
||||
}
|
||||
80
integration/vendor/github.com/docker/libcompose/docker/image.go
generated
vendored
Normal file
80
integration/vendor/github.com/docker/libcompose/docker/image.go
generated
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/docker/docker/pkg/term"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/engine-api/client"
|
||||
"github.com/docker/engine-api/types"
|
||||
)
|
||||
|
||||
func removeImage(ctx context.Context, client client.APIClient, image string) error {
|
||||
_, err := client.ImageRemove(ctx, image, types.ImageRemoveOptions{})
|
||||
return err
|
||||
}
|
||||
|
||||
func pullImage(ctx context.Context, client client.APIClient, service *Service, image string) error {
|
||||
fmt.Fprintf(os.Stderr, "Pulling %s (%s)...\n", service.name, image)
|
||||
distributionRef, err := reference.ParseNamed(image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
repoInfo, err := registry.ParseRepositoryInfo(distributionRef)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authConfig := service.authLookup.Lookup(repoInfo)
|
||||
|
||||
encodedAuth, err := encodeAuthToBase64(authConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
options := types.ImagePullOptions{
|
||||
RegistryAuth: encodedAuth,
|
||||
}
|
||||
responseBody, err := client.ImagePull(ctx, distributionRef.String(), options)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to pull image %s: %v", image, err)
|
||||
return err
|
||||
}
|
||||
defer responseBody.Close()
|
||||
|
||||
var writeBuff io.Writer = os.Stderr
|
||||
|
||||
outFd, isTerminalOut := term.GetFdInfo(os.Stderr)
|
||||
|
||||
err = jsonmessage.DisplayJSONMessagesStream(responseBody, writeBuff, outFd, isTerminalOut, nil)
|
||||
if err != nil {
|
||||
if jerr, ok := err.(*jsonmessage.JSONError); ok {
|
||||
// If no error code is set, default to 1
|
||||
if jerr.Code == 0 {
|
||||
jerr.Code = 1
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "%s", writeBuff)
|
||||
return fmt.Errorf("Status: %s, Code: %d", jerr.Message, jerr.Code)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// encodeAuthToBase64 serializes the auth configuration as JSON base64 payload
|
||||
func encodeAuthToBase64(authConfig types.AuthConfig) (string, error) {
|
||||
buf, err := json.Marshal(authConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.URLEncoding.EncodeToString(buf), nil
|
||||
}
|
||||
92
integration/vendor/github.com/docker/libcompose/docker/name.go
generated
vendored
Normal file
92
integration/vendor/github.com/docker/libcompose/docker/name.go
generated
vendored
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/engine-api/client"
|
||||
"github.com/docker/engine-api/types"
|
||||
"github.com/docker/engine-api/types/filters"
|
||||
"github.com/docker/libcompose/labels"
|
||||
)
|
||||
|
||||
const format = "%s_%s_%d"
|
||||
|
||||
// Namer defines method to provide container name.
|
||||
type Namer interface {
|
||||
Next() (string, int)
|
||||
}
|
||||
|
||||
type defaultNamer struct {
|
||||
project string
|
||||
service string
|
||||
oneOff bool
|
||||
currentNumber int
|
||||
}
|
||||
|
||||
type singleNamer struct {
|
||||
name string
|
||||
}
|
||||
|
||||
// NewSingleNamer returns a namer that only allows a single name.
|
||||
func NewSingleNamer(name string) Namer {
|
||||
return &singleNamer{name}
|
||||
}
|
||||
|
||||
// NewNamer returns a namer that returns names based on the specified project and
|
||||
// service name and an inner counter, e.g. project_service_1, project_service_2…
|
||||
func NewNamer(ctx context.Context, client client.ContainerAPIClient, project, service string, oneOff bool) (Namer, error) {
|
||||
namer := &defaultNamer{
|
||||
project: project,
|
||||
service: service,
|
||||
oneOff: oneOff,
|
||||
}
|
||||
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("label", fmt.Sprintf("%s=%s", labels.PROJECT.Str(), project))
|
||||
filter.Add("label", fmt.Sprintf("%s=%s", labels.SERVICE.Str(), service))
|
||||
if oneOff {
|
||||
filter.Add("label", fmt.Sprintf("%s=%s", labels.ONEOFF.Str(), "True"))
|
||||
} else {
|
||||
filter.Add("label", fmt.Sprintf("%s=%s", labels.ONEOFF.Str(), "False"))
|
||||
}
|
||||
|
||||
containers, err := client.ContainerList(ctx, types.ContainerListOptions{
|
||||
All: true,
|
||||
Filter: filter,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
maxNumber := 0
|
||||
for _, container := range containers {
|
||||
number, err := strconv.Atoi(container.Labels[labels.NUMBER.Str()])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if number > maxNumber {
|
||||
maxNumber = number
|
||||
}
|
||||
}
|
||||
namer.currentNumber = maxNumber + 1
|
||||
|
||||
return namer, nil
|
||||
}
|
||||
|
||||
func (i *defaultNamer) Next() (string, int) {
|
||||
service := i.service
|
||||
if i.oneOff {
|
||||
service = i.service + "_run"
|
||||
}
|
||||
name := fmt.Sprintf(format, i.project, service, i.currentNumber)
|
||||
number := i.currentNumber
|
||||
i.currentNumber = i.currentNumber + 1
|
||||
return name, number
|
||||
}
|
||||
|
||||
func (s *singleNamer) Next() (string, int) {
|
||||
return s.name, 1
|
||||
}
|
||||
19
integration/vendor/github.com/docker/libcompose/docker/network/factory.go
generated
vendored
Normal file
19
integration/vendor/github.com/docker/libcompose/docker/network/factory.go
generated
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
package network
|
||||
|
||||
import (
|
||||
"github.com/docker/libcompose/config"
|
||||
composeclient "github.com/docker/libcompose/docker/client"
|
||||
"github.com/docker/libcompose/project"
|
||||
)
|
||||
|
||||
// DockerFactory implements project.NetworksFactory
|
||||
type DockerFactory struct {
|
||||
ClientFactory composeclient.Factory
|
||||
}
|
||||
|
||||
// Create implements project.NetworksFactory Create method.
|
||||
// It creates a Networks (that implements project.Networks) from specified configurations.
|
||||
func (f *DockerFactory) Create(projectName string, networkConfigs map[string]*config.NetworkConfig, serviceConfigs *config.ServiceConfigs, networkEnabled bool) (project.Networks, error) {
|
||||
cli := f.ClientFactory.Create(nil)
|
||||
return NetworksFromServices(cli, projectName, networkConfigs, serviceConfigs, networkEnabled)
|
||||
}
|
||||
194
integration/vendor/github.com/docker/libcompose/docker/network/network.go
generated
vendored
Normal file
194
integration/vendor/github.com/docker/libcompose/docker/network/network.go
generated
vendored
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
package network
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/engine-api/client"
|
||||
"github.com/docker/engine-api/types"
|
||||
"github.com/docker/engine-api/types/network"
|
||||
"github.com/docker/libcompose/config"
|
||||
"github.com/docker/libcompose/yaml"
|
||||
)
|
||||
|
||||
// Network holds attributes and method for a network definition in compose
|
||||
type Network struct {
|
||||
client client.NetworkAPIClient
|
||||
name string
|
||||
projectName string
|
||||
driver string
|
||||
driverOptions map[string]string
|
||||
ipam config.Ipam
|
||||
external bool
|
||||
}
|
||||
|
||||
func (n *Network) fullName() string {
|
||||
name := n.projectName + "_" + n.name
|
||||
if n.external {
|
||||
name = n.name
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
// Inspect inspect the current network
|
||||
func (n *Network) Inspect(ctx context.Context) (types.NetworkResource, error) {
|
||||
return n.client.NetworkInspect(ctx, n.fullName())
|
||||
}
|
||||
|
||||
// Remove removes the current network (from docker engine)
|
||||
func (n *Network) Remove(ctx context.Context) error {
|
||||
if n.external {
|
||||
fmt.Printf("Network %s is external, skipping", n.fullName())
|
||||
return nil
|
||||
}
|
||||
fmt.Printf("Removing network %q\n", n.fullName())
|
||||
return n.client.NetworkRemove(ctx, n.fullName())
|
||||
}
|
||||
|
||||
// EnsureItExists make sure the network exists and return an error if it does not exists
|
||||
// and cannot be created.
|
||||
func (n *Network) EnsureItExists(ctx context.Context) error {
|
||||
networkResource, err := n.Inspect(ctx)
|
||||
if n.external {
|
||||
if client.IsErrNetworkNotFound(err) {
|
||||
// FIXME(vdemeester) introduce some libcompose error type
|
||||
return fmt.Errorf("Network %s declared as external, but could not be found. Please create the network manually using docker network create %s and try again", n.fullName(), n.fullName())
|
||||
}
|
||||
return err
|
||||
}
|
||||
if err != nil && client.IsErrNetworkNotFound(err) {
|
||||
return n.create(ctx)
|
||||
}
|
||||
if n.driver != "" && networkResource.Driver != n.driver {
|
||||
return fmt.Errorf("Network %q needs to be recreated - driver has changed", n.fullName())
|
||||
}
|
||||
if len(n.driverOptions) != 0 && !reflect.DeepEqual(networkResource.Options, n.driverOptions) {
|
||||
return fmt.Errorf("Network %q needs to be recreated - options have changed", n.fullName())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (n *Network) create(ctx context.Context) error {
|
||||
fmt.Printf("Creating network %q with driver %q\n", n.fullName(), n.driver)
|
||||
_, err := n.client.NetworkCreate(ctx, n.fullName(), types.NetworkCreate{
|
||||
Driver: n.driver,
|
||||
Options: n.driverOptions,
|
||||
IPAM: convertToAPIIpam(n.ipam),
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func convertToAPIIpam(ipam config.Ipam) network.IPAM {
|
||||
ipamConfigs := []network.IPAMConfig{}
|
||||
for _, config := range ipam.Config {
|
||||
ipamConfigs = append(ipamConfigs, network.IPAMConfig{
|
||||
Subnet: config.Subnet,
|
||||
IPRange: config.IPRange,
|
||||
Gateway: config.Gateway,
|
||||
AuxAddress: config.AuxAddress,
|
||||
})
|
||||
}
|
||||
return network.IPAM{
|
||||
Driver: ipam.Driver,
|
||||
Config: ipamConfigs,
|
||||
}
|
||||
}
|
||||
|
||||
// NewNetwork creates a new network from the specified name and config.
|
||||
func NewNetwork(projectName, name string, config *config.NetworkConfig, client client.NetworkAPIClient) *Network {
|
||||
networkName := name
|
||||
if config.External.External {
|
||||
networkName = config.External.Name
|
||||
}
|
||||
return &Network{
|
||||
client: client,
|
||||
name: networkName,
|
||||
projectName: projectName,
|
||||
driver: config.Driver,
|
||||
driverOptions: config.DriverOpts,
|
||||
external: config.External.External,
|
||||
ipam: config.Ipam,
|
||||
}
|
||||
}
|
||||
|
||||
// Networks holds a list of network
|
||||
type Networks struct {
|
||||
networks []*Network
|
||||
networkEnabled bool
|
||||
}
|
||||
|
||||
// Initialize make sure network exists if network is enabled
|
||||
func (n *Networks) Initialize(ctx context.Context) error {
|
||||
if !n.networkEnabled {
|
||||
return nil
|
||||
}
|
||||
for _, network := range n.networks {
|
||||
err := network.EnsureItExists(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove removes networks (clean-up)
|
||||
func (n *Networks) Remove(ctx context.Context) error {
|
||||
if !n.networkEnabled {
|
||||
return nil
|
||||
}
|
||||
for _, network := range n.networks {
|
||||
err := network.Remove(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NetworksFromServices creates a new Networks struct based on networks configurations and
|
||||
// services configuration. If a network is defined but not used by any service, it will return
|
||||
// an error along the Networks.
|
||||
func NetworksFromServices(cli client.NetworkAPIClient, projectName string, networkConfigs map[string]*config.NetworkConfig, services *config.ServiceConfigs, networkEnabled bool) (*Networks, error) {
|
||||
var err error
|
||||
networks := make([]*Network, 0, len(networkConfigs))
|
||||
networkNames := map[string]*yaml.Network{}
|
||||
for _, serviceName := range services.Keys() {
|
||||
serviceConfig, _ := services.Get(serviceName)
|
||||
if serviceConfig.NetworkMode != "" || serviceConfig.Networks == nil || len(serviceConfig.Networks.Networks) == 0 {
|
||||
continue
|
||||
}
|
||||
for _, network := range serviceConfig.Networks.Networks {
|
||||
if network.Name != "default" {
|
||||
if _, ok := networkConfigs[network.Name]; !ok {
|
||||
return nil, fmt.Errorf(`Service "%s" uses an undefined network "%s"`, serviceName, network.Name)
|
||||
}
|
||||
}
|
||||
networkNames[network.Name] = network
|
||||
}
|
||||
}
|
||||
for name, config := range networkConfigs {
|
||||
network := NewNetwork(projectName, name, config, cli)
|
||||
networks = append(networks, network)
|
||||
}
|
||||
if len(networkNames) != len(networks) {
|
||||
unused := []string{}
|
||||
for name := range networkConfigs {
|
||||
if name == "default" {
|
||||
continue
|
||||
}
|
||||
if _, ok := networkNames[name]; !ok {
|
||||
unused = append(unused, name)
|
||||
}
|
||||
}
|
||||
if len(unused) != 0 {
|
||||
err = fmt.Errorf("Some networks were defined but are not used by any service: %v", strings.Join(unused, " "))
|
||||
}
|
||||
}
|
||||
return &Networks{
|
||||
networks: networks,
|
||||
networkEnabled: networkEnabled,
|
||||
}, err
|
||||
}
|
||||
123
integration/vendor/github.com/docker/libcompose/docker/project.go
generated
vendored
Normal file
123
integration/vendor/github.com/docker/libcompose/docker/project.go
generated
vendored
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/engine-api/types"
|
||||
"github.com/docker/engine-api/types/filters"
|
||||
"github.com/docker/libcompose/config"
|
||||
"github.com/docker/libcompose/docker/client"
|
||||
"github.com/docker/libcompose/docker/network"
|
||||
"github.com/docker/libcompose/labels"
|
||||
"github.com/docker/libcompose/lookup"
|
||||
"github.com/docker/libcompose/project"
|
||||
)
|
||||
|
||||
// ComposeVersion is name of docker-compose.yml file syntax supported version
|
||||
const ComposeVersion = "1.5.0"
|
||||
|
||||
// NewProject creates a Project with the specified context.
|
||||
func NewProject(context *Context, parseOptions *config.ParseOptions) (project.APIProject, error) {
|
||||
if context.ResourceLookup == nil {
|
||||
context.ResourceLookup = &lookup.FileConfigLookup{}
|
||||
}
|
||||
|
||||
if context.EnvironmentLookup == nil {
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
context.EnvironmentLookup = &lookup.ComposableEnvLookup{
|
||||
Lookups: []config.EnvironmentLookup{
|
||||
&lookup.EnvfileLookup{
|
||||
Path: filepath.Join(cwd, ".env"),
|
||||
},
|
||||
&lookup.OsEnvLookup{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if context.AuthLookup == nil {
|
||||
context.AuthLookup = NewConfigAuthLookup(context)
|
||||
}
|
||||
|
||||
if context.ServiceFactory == nil {
|
||||
context.ServiceFactory = &ServiceFactory{
|
||||
context: context,
|
||||
}
|
||||
}
|
||||
|
||||
if context.ClientFactory == nil {
|
||||
factory, err := client.NewDefaultFactory(client.Options{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
context.ClientFactory = factory
|
||||
}
|
||||
|
||||
if context.NetworksFactory == nil {
|
||||
networksFactory := &network.DockerFactory{
|
||||
ClientFactory: context.ClientFactory,
|
||||
}
|
||||
context.NetworksFactory = networksFactory
|
||||
}
|
||||
|
||||
// FIXME(vdemeester) Remove the context duplication ?
|
||||
runtime := &Project{
|
||||
clientFactory: context.ClientFactory,
|
||||
}
|
||||
p := project.NewProject(&context.Context, runtime, parseOptions)
|
||||
|
||||
err := p.Parse()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = context.open(); err != nil {
|
||||
logrus.Errorf("Failed to open project %s: %v", p.Name, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p, err
|
||||
}
|
||||
|
||||
// Project implements project.RuntimeProject and define docker runtime specific methods.
|
||||
type Project struct {
|
||||
clientFactory client.Factory
|
||||
}
|
||||
|
||||
// RemoveOrphans implements project.RuntimeProject.RemoveOrphans.
|
||||
// It will remove orphan containers that are part of the project but not to any services.
|
||||
func (p *Project) RemoveOrphans(ctx context.Context, projectName string, serviceConfigs *config.ServiceConfigs) error {
|
||||
client := p.clientFactory.Create(nil)
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("label", labels.PROJECT.EqString(projectName))
|
||||
containers, err := client.ContainerList(ctx, types.ContainerListOptions{
|
||||
Filter: filter,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currentServices := map[string]struct{}{}
|
||||
for _, serviceName := range serviceConfigs.Keys() {
|
||||
currentServices[serviceName] = struct{}{}
|
||||
}
|
||||
for _, container := range containers {
|
||||
serviceLabel := container.Labels[labels.SERVICE.Str()]
|
||||
if _, ok := currentServices[serviceLabel]; !ok {
|
||||
if err := client.ContainerKill(ctx, container.ID, "SIGKILL"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := client.ContainerRemove(ctx, container.ID, types.ContainerRemoveOptions{
|
||||
Force: true,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
596
integration/vendor/github.com/docker/libcompose/docker/service.go
generated
vendored
Normal file
596
integration/vendor/github.com/docker/libcompose/docker/service.go
generated
vendored
Normal file
|
|
@ -0,0 +1,596 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/engine-api/client"
|
||||
"github.com/docker/engine-api/types"
|
||||
eventtypes "github.com/docker/engine-api/types/events"
|
||||
"github.com/docker/engine-api/types/filters"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/docker/libcompose/config"
|
||||
"github.com/docker/libcompose/docker/builder"
|
||||
composeclient "github.com/docker/libcompose/docker/client"
|
||||
"github.com/docker/libcompose/labels"
|
||||
"github.com/docker/libcompose/project"
|
||||
"github.com/docker/libcompose/project/events"
|
||||
"github.com/docker/libcompose/project/options"
|
||||
"github.com/docker/libcompose/utils"
|
||||
dockerevents "github.com/vdemeester/docker-events"
|
||||
)
|
||||
|
||||
// Service is a project.Service implementations.
|
||||
type Service struct {
|
||||
name string
|
||||
project *project.Project
|
||||
serviceConfig *config.ServiceConfig
|
||||
clientFactory composeclient.Factory
|
||||
authLookup AuthLookup
|
||||
|
||||
// FIXME(vdemeester) remove this at some point
|
||||
context *Context
|
||||
}
|
||||
|
||||
// NewService creates a service
|
||||
func NewService(name string, serviceConfig *config.ServiceConfig, context *Context) *Service {
|
||||
return &Service{
|
||||
name: name,
|
||||
project: context.Project,
|
||||
serviceConfig: serviceConfig,
|
||||
clientFactory: context.ClientFactory,
|
||||
authLookup: context.AuthLookup,
|
||||
context: context,
|
||||
}
|
||||
}
|
||||
|
||||
// Name returns the service name.
|
||||
func (s *Service) Name() string {
|
||||
return s.name
|
||||
}
|
||||
|
||||
// Config returns the configuration of the service (config.ServiceConfig).
|
||||
func (s *Service) Config() *config.ServiceConfig {
|
||||
return s.serviceConfig
|
||||
}
|
||||
|
||||
// DependentServices returns the dependent services (as an array of ServiceRelationship) of the service.
|
||||
func (s *Service) DependentServices() []project.ServiceRelationship {
|
||||
return DefaultDependentServices(s.project, s)
|
||||
}
|
||||
|
||||
// Create implements Service.Create. It ensures the image exists or build it
|
||||
// if it can and then create a container.
|
||||
func (s *Service) Create(ctx context.Context, options options.Create) error {
|
||||
containers, err := s.collectContainers(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
imageName, err := s.ensureImageExists(ctx, options.NoBuild)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(containers) != 0 {
|
||||
return s.eachContainer(ctx, containers, func(c *Container) error {
|
||||
return s.recreateIfNeeded(ctx, imageName, c, options.NoRecreate, options.ForceRecreate)
|
||||
})
|
||||
}
|
||||
|
||||
_, err = s.createOne(ctx, imageName)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Service) collectContainers(ctx context.Context) ([]*Container, error) {
|
||||
client := s.clientFactory.Create(s)
|
||||
containers, err := GetContainersByFilter(ctx, client, labels.SERVICE.Eq(s.name), labels.PROJECT.Eq(s.project.Name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := []*Container{}
|
||||
|
||||
for _, container := range containers {
|
||||
containerNumber, err := strconv.Atoi(container.Labels[labels.NUMBER.Str()])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Compose add "/" before name, so Name[1] will store actaul name.
|
||||
name := strings.SplitAfter(container.Names[0], "/")
|
||||
result = append(result, NewContainer(client, name[1], containerNumber, s))
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *Service) createOne(ctx context.Context, imageName string) (*Container, error) {
|
||||
containers, err := s.constructContainers(ctx, imageName, 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return containers[0], err
|
||||
}
|
||||
|
||||
func (s *Service) ensureImageExists(ctx context.Context, noBuild bool) (string, error) {
|
||||
exists, err := s.ImageExists(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if exists {
|
||||
return s.imageName(), nil
|
||||
}
|
||||
|
||||
if s.Config().Build.Context != "" {
|
||||
if noBuild {
|
||||
return "", fmt.Errorf("Service %q needs to be built, but no-build was specified", s.name)
|
||||
}
|
||||
return s.imageName(), s.build(ctx, options.Build{})
|
||||
}
|
||||
|
||||
return s.imageName(), s.Pull(ctx)
|
||||
}
|
||||
|
||||
// ImageExists returns whether or not the service image already exists
|
||||
func (s *Service) ImageExists(ctx context.Context) (bool, error) {
|
||||
dockerClient := s.clientFactory.Create(s)
|
||||
|
||||
_, _, err := dockerClient.ImageInspectWithRaw(ctx, s.imageName(), false)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if err != nil && client.IsErrImageNotFound(err) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
func (s *Service) imageName() string {
|
||||
if s.Config().Image != "" {
|
||||
return s.Config().Image
|
||||
}
|
||||
return fmt.Sprintf("%s_%s", s.project.Name, s.Name())
|
||||
}
|
||||
|
||||
// Build implements Service.Build. It will try to build the image and returns an error if any.
|
||||
func (s *Service) Build(ctx context.Context, buildOptions options.Build) error {
|
||||
return s.build(ctx, buildOptions)
|
||||
}
|
||||
|
||||
func (s *Service) build(ctx context.Context, buildOptions options.Build) error {
|
||||
if s.Config().Build.Context == "" {
|
||||
return fmt.Errorf("Specified service does not have a build section")
|
||||
}
|
||||
builder := &builder.DaemonBuilder{
|
||||
Client: s.clientFactory.Create(s),
|
||||
ContextDirectory: s.Config().Build.Context,
|
||||
Dockerfile: s.Config().Build.Dockerfile,
|
||||
BuildArgs: s.Config().Build.Args,
|
||||
AuthConfigs: s.authLookup.All(),
|
||||
NoCache: buildOptions.NoCache,
|
||||
ForceRemove: buildOptions.ForceRemove,
|
||||
Pull: buildOptions.Pull,
|
||||
}
|
||||
return builder.Build(ctx, s.imageName())
|
||||
}
|
||||
|
||||
func (s *Service) constructContainers(ctx context.Context, imageName string, count int) ([]*Container, error) {
|
||||
result, err := s.collectContainers(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := s.clientFactory.Create(s)
|
||||
|
||||
var namer Namer
|
||||
|
||||
if s.serviceConfig.ContainerName != "" {
|
||||
if count > 1 {
|
||||
logrus.Warnf(`The "%s" service is using the custom container name "%s". Docker requires each container to have a unique name. Remove the custom name to scale the service.`, s.name, s.serviceConfig.ContainerName)
|
||||
}
|
||||
namer = NewSingleNamer(s.serviceConfig.ContainerName)
|
||||
} else {
|
||||
namer, err = NewNamer(ctx, client, s.project.Name, s.name, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
for i := len(result); i < count; i++ {
|
||||
containerName, containerNumber := namer.Next()
|
||||
|
||||
c := NewContainer(client, containerName, containerNumber, s)
|
||||
|
||||
dockerContainer, err := c.Create(ctx, imageName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logrus.Debugf("Created container %s: %v", dockerContainer.ID, dockerContainer.Name)
|
||||
|
||||
result = append(result, NewContainer(client, containerName, containerNumber, s))
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Up implements Service.Up. It builds the image if needed, creates a container
|
||||
// and start it.
|
||||
func (s *Service) Up(ctx context.Context, options options.Up) error {
|
||||
containers, err := s.collectContainers(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var imageName = s.imageName()
|
||||
if len(containers) == 0 || !options.NoRecreate {
|
||||
imageName, err = s.ensureImageExists(ctx, options.NoBuild)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return s.up(ctx, imageName, true, options)
|
||||
}
|
||||
|
||||
// Run implements Service.Run. It runs a one of command within the service container.
|
||||
// It always create a new container.
|
||||
func (s *Service) Run(ctx context.Context, commandParts []string, options options.Run) (int, error) {
|
||||
imageName, err := s.ensureImageExists(ctx, false)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
client := s.clientFactory.Create(s)
|
||||
|
||||
namer, err := NewNamer(ctx, client, s.project.Name, s.name, true)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
containerName, containerNumber := namer.Next()
|
||||
|
||||
c := NewOneOffContainer(client, containerName, containerNumber, s)
|
||||
|
||||
configOverride := &config.ServiceConfig{Command: commandParts, Tty: true, StdinOpen: true}
|
||||
|
||||
c.CreateWithOverride(ctx, imageName, configOverride)
|
||||
|
||||
if err := s.connectContainerToNetworks(ctx, c); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if options.Detached {
|
||||
logrus.Infof("%s", c.Name())
|
||||
return 0, c.Start(ctx)
|
||||
}
|
||||
return c.Run(ctx, configOverride)
|
||||
}
|
||||
|
||||
// Info implements Service.Info. It returns an project.InfoSet with the containers
|
||||
// related to this service (can be multiple if using the scale command).
|
||||
func (s *Service) Info(ctx context.Context, qFlag bool) (project.InfoSet, error) {
|
||||
result := project.InfoSet{}
|
||||
containers, err := s.collectContainers(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, c := range containers {
|
||||
info, err := c.Info(ctx, qFlag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, info)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Start implements Service.Start. It tries to start a container without creating it.
|
||||
func (s *Service) Start(ctx context.Context) error {
|
||||
return s.collectContainersAndDo(ctx, func(c *Container) error {
|
||||
if err := s.connectContainerToNetworks(ctx, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Start(ctx)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Service) up(ctx context.Context, imageName string, create bool, options options.Up) error {
|
||||
containers, err := s.collectContainers(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logrus.Debugf("Found %d existing containers for service %s", len(containers), s.name)
|
||||
|
||||
if len(containers) == 0 && create {
|
||||
c, err := s.createOne(ctx, imageName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
containers = []*Container{c}
|
||||
}
|
||||
|
||||
return s.eachContainer(ctx, containers, func(c *Container) error {
|
||||
if create {
|
||||
if err := s.recreateIfNeeded(ctx, imageName, c, options.NoRecreate, options.ForceRecreate); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.connectContainerToNetworks(ctx, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Start(ctx)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Service) connectContainerToNetworks(ctx context.Context, c *Container) error {
|
||||
connectedNetworks, err := c.Networks(ctx)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if s.serviceConfig.Networks != nil {
|
||||
for _, network := range s.serviceConfig.Networks.Networks {
|
||||
existingNetwork, ok := connectedNetworks[network.Name]
|
||||
if ok {
|
||||
// FIXME(vdemeester) implement alias checking (to not disconnect/reconnect for nothing)
|
||||
aliasPresent := false
|
||||
for _, alias := range existingNetwork.Aliases {
|
||||
// FIXME(vdemeester) use shortID instead of ID
|
||||
ID, _ := c.ID()
|
||||
if alias == ID {
|
||||
aliasPresent = true
|
||||
}
|
||||
}
|
||||
if aliasPresent {
|
||||
continue
|
||||
}
|
||||
if err := c.NetworkDisconnect(ctx, network); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := c.NetworkConnect(ctx, network); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) recreateIfNeeded(ctx context.Context, imageName string, c *Container, noRecreate, forceRecreate bool) error {
|
||||
if noRecreate {
|
||||
return nil
|
||||
}
|
||||
outOfSync, err := c.OutOfSync(ctx, imageName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"outOfSync": outOfSync,
|
||||
"ForceRecreate": forceRecreate,
|
||||
"NoRecreate": noRecreate}).Debug("Going to decide if recreate is needed")
|
||||
|
||||
if forceRecreate || outOfSync {
|
||||
logrus.Infof("Recreating %s", s.name)
|
||||
if _, err := c.Recreate(ctx, imageName); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) collectContainersAndDo(ctx context.Context, action func(*Container) error) error {
|
||||
containers, err := s.collectContainers(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.eachContainer(ctx, containers, action)
|
||||
}
|
||||
|
||||
func (s *Service) eachContainer(ctx context.Context, containers []*Container, action func(*Container) error) error {
|
||||
|
||||
tasks := utils.InParallel{}
|
||||
for _, container := range containers {
|
||||
task := func(container *Container) func() error {
|
||||
return func() error {
|
||||
return action(container)
|
||||
}
|
||||
}(container)
|
||||
|
||||
tasks.Add(task)
|
||||
}
|
||||
|
||||
return tasks.Wait()
|
||||
}
|
||||
|
||||
// Stop implements Service.Stop. It stops any containers related to the service.
|
||||
func (s *Service) Stop(ctx context.Context, timeout int) error {
|
||||
return s.collectContainersAndDo(ctx, func(c *Container) error {
|
||||
return c.Stop(ctx, timeout)
|
||||
})
|
||||
}
|
||||
|
||||
// Restart implements Service.Restart. It restarts any containers related to the service.
|
||||
func (s *Service) Restart(ctx context.Context, timeout int) error {
|
||||
return s.collectContainersAndDo(ctx, func(c *Container) error {
|
||||
return c.Restart(ctx, timeout)
|
||||
})
|
||||
}
|
||||
|
||||
// Kill implements Service.Kill. It kills any containers related to the service.
|
||||
func (s *Service) Kill(ctx context.Context, signal string) error {
|
||||
return s.collectContainersAndDo(ctx, func(c *Container) error {
|
||||
return c.Kill(ctx, signal)
|
||||
})
|
||||
}
|
||||
|
||||
// Delete implements Service.Delete. It removes any containers related to the service.
|
||||
func (s *Service) Delete(ctx context.Context, options options.Delete) error {
|
||||
return s.collectContainersAndDo(ctx, func(c *Container) error {
|
||||
return c.Delete(ctx, options.RemoveVolume)
|
||||
})
|
||||
}
|
||||
|
||||
// Log implements Service.Log. It returns the docker logs for each container related to the service.
|
||||
func (s *Service) Log(ctx context.Context, follow bool) error {
|
||||
return s.collectContainersAndDo(ctx, func(c *Container) error {
|
||||
return c.Log(ctx, follow)
|
||||
})
|
||||
}
|
||||
|
||||
// Scale implements Service.Scale. It creates or removes containers to have the specified number
|
||||
// of related container to the service to run.
|
||||
func (s *Service) Scale(ctx context.Context, scale int, timeout int) error {
|
||||
if s.specificiesHostPort() {
|
||||
logrus.Warnf("The \"%s\" service specifies a port on the host. If multiple containers for this service are created on a single host, the port will clash.", s.Name())
|
||||
}
|
||||
|
||||
foundCount := 0
|
||||
err := s.collectContainersAndDo(ctx, func(c *Container) error {
|
||||
foundCount++
|
||||
if foundCount > scale {
|
||||
err := c.Stop(ctx, timeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// FIXME(vdemeester) remove volume in scale by default ?
|
||||
return c.Delete(ctx, false)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if foundCount != scale {
|
||||
imageName, err := s.ensureImageExists(ctx, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = s.constructContainers(ctx, imageName, scale); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return s.up(ctx, "", false, options.Up{})
|
||||
}
|
||||
|
||||
// Pull implements Service.Pull. It pulls the image of the service and skip the service that
|
||||
// would need to be built.
|
||||
func (s *Service) Pull(ctx context.Context) error {
|
||||
if s.Config().Image == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return pullImage(ctx, s.clientFactory.Create(s), s, s.Config().Image)
|
||||
}
|
||||
|
||||
// Pause implements Service.Pause. It puts into pause the container(s) related
|
||||
// to the service.
|
||||
func (s *Service) Pause(ctx context.Context) error {
|
||||
return s.collectContainersAndDo(ctx, func(c *Container) error {
|
||||
return c.Pause(ctx)
|
||||
})
|
||||
}
|
||||
|
||||
// Unpause implements Service.Pause. It brings back from pause the container(s)
|
||||
// related to the service.
|
||||
func (s *Service) Unpause(ctx context.Context) error {
|
||||
return s.collectContainersAndDo(ctx, func(c *Container) error {
|
||||
return c.Unpause(ctx)
|
||||
})
|
||||
}
|
||||
|
||||
// RemoveImage implements Service.RemoveImage. It removes images used for the service
|
||||
// depending on the specified type.
|
||||
func (s *Service) RemoveImage(ctx context.Context, imageType options.ImageType) error {
|
||||
switch imageType {
|
||||
case "local":
|
||||
if s.Config().Image != "" {
|
||||
return nil
|
||||
}
|
||||
return removeImage(ctx, s.clientFactory.Create(s), s.imageName())
|
||||
case "all":
|
||||
return removeImage(ctx, s.clientFactory.Create(s), s.imageName())
|
||||
default:
|
||||
// Don't do a thing, should be validated up-front
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var eventAttributes = []string{"image", "name"}
|
||||
|
||||
// Events implements Service.Events. It listen to all real-time events happening
|
||||
// for the service, and put them into the specified chan.
|
||||
func (s *Service) Events(ctx context.Context, evts chan events.ContainerEvent) error {
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("label", fmt.Sprintf("%s=%s", labels.PROJECT, s.project.Name))
|
||||
filter.Add("label", fmt.Sprintf("%s=%s", labels.SERVICE, s.name))
|
||||
client := s.clientFactory.Create(s)
|
||||
return <-dockerevents.Monitor(ctx, client, types.EventsOptions{
|
||||
Filters: filter,
|
||||
}, func(m eventtypes.Message) {
|
||||
service := m.Actor.Attributes[labels.SERVICE.Str()]
|
||||
attributes := map[string]string{}
|
||||
for _, attr := range eventAttributes {
|
||||
attributes[attr] = m.Actor.Attributes[attr]
|
||||
}
|
||||
e := events.ContainerEvent{
|
||||
Service: service,
|
||||
Event: m.Action,
|
||||
Type: m.Type,
|
||||
ID: m.Actor.ID,
|
||||
Time: time.Unix(m.Time, 0),
|
||||
Attributes: attributes,
|
||||
}
|
||||
evts <- e
|
||||
})
|
||||
}
|
||||
|
||||
// Containers implements Service.Containers. It returns the list of containers
|
||||
// that are related to the service.
|
||||
func (s *Service) Containers(ctx context.Context) ([]project.Container, error) {
|
||||
result := []project.Container{}
|
||||
containers, err := s.collectContainers(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, c := range containers {
|
||||
result = append(result, c)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *Service) specificiesHostPort() bool {
|
||||
_, bindings, err := nat.ParsePortSpecs(s.Config().Ports)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
for _, portBindings := range bindings {
|
||||
for _, portBinding := range portBindings {
|
||||
if portBinding.HostPort != "" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
16
integration/vendor/github.com/docker/libcompose/docker/service_factory.go
generated
vendored
Normal file
16
integration/vendor/github.com/docker/libcompose/docker/service_factory.go
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"github.com/docker/libcompose/config"
|
||||
"github.com/docker/libcompose/project"
|
||||
)
|
||||
|
||||
// ServiceFactory is an implementation of project.ServiceFactory.
|
||||
type ServiceFactory struct {
|
||||
context *Context
|
||||
}
|
||||
|
||||
// Create creates a Service based on the specified project, name and service configuration.
|
||||
func (s *ServiceFactory) Create(project *project.Project, name string, serviceConfig *config.ServiceConfig) (project.Service, error) {
|
||||
return NewService(name, serviceConfig, s.context), nil
|
||||
}
|
||||
45
integration/vendor/github.com/docker/libcompose/docker/utils.go
generated
vendored
Normal file
45
integration/vendor/github.com/docker/libcompose/docker/utils.go
generated
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"github.com/docker/engine-api/types/container"
|
||||
"github.com/docker/libcompose/project"
|
||||
)
|
||||
|
||||
// DefaultDependentServices return the dependent services (as an array of ServiceRelationship)
|
||||
// for the specified project and service. It looks for : links, volumesFrom, net and ipc configuration.
|
||||
// It uses default project implementation and append some docker specific ones.
|
||||
func DefaultDependentServices(p *project.Project, s project.Service) []project.ServiceRelationship {
|
||||
result := project.DefaultDependentServices(p, s)
|
||||
|
||||
result = appendNs(p, result, s.Config().NetworkMode, project.RelTypeNetNamespace)
|
||||
result = appendNs(p, result, s.Config().Ipc, project.RelTypeIpcNamespace)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func appendNs(p *project.Project, rels []project.ServiceRelationship, conf string, relType project.ServiceRelationshipType) []project.ServiceRelationship {
|
||||
service := GetContainerFromIpcLikeConfig(p, conf)
|
||||
if service != "" {
|
||||
rels = append(rels, project.NewServiceRelationship(service, relType))
|
||||
}
|
||||
return rels
|
||||
}
|
||||
|
||||
// GetContainerFromIpcLikeConfig returns name of the service that shares the IPC
|
||||
// namespace with the specified service.
|
||||
func GetContainerFromIpcLikeConfig(p *project.Project, conf string) string {
|
||||
ipc := container.IpcMode(conf)
|
||||
if !ipc.IsContainer() {
|
||||
return ""
|
||||
}
|
||||
|
||||
name := ipc.Container()
|
||||
if name == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
if p.ServiceConfigs.Has(name) {
|
||||
return name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
94
integration/vendor/github.com/docker/libcompose/labels/labels.go
generated
vendored
Normal file
94
integration/vendor/github.com/docker/libcompose/labels/labels.go
generated
vendored
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
package labels
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/libcompose/utils"
|
||||
)
|
||||
|
||||
// Label represents a docker label.
|
||||
type Label string
|
||||
|
||||
// Libcompose default labels.
|
||||
const (
|
||||
NUMBER = Label("com.docker.compose.container-number")
|
||||
ONEOFF = Label("com.docker.compose.oneoff")
|
||||
PROJECT = Label("com.docker.compose.project")
|
||||
SERVICE = Label("com.docker.compose.service")
|
||||
HASH = Label("com.docker.compose.config-hash")
|
||||
VERSION = Label("com.docker.compose.version")
|
||||
)
|
||||
|
||||
// EqString returns a label json string representation with the specified value.
|
||||
func (f Label) EqString(value string) string {
|
||||
return LabelFilterString(string(f), value)
|
||||
}
|
||||
|
||||
// Eq returns a label map representation with the specified value.
|
||||
func (f Label) Eq(value string) map[string][]string {
|
||||
return LabelFilter(string(f), value)
|
||||
}
|
||||
|
||||
// AndString returns a json list of labels by merging the two specified values (left and right) serialized as string.
|
||||
func AndString(left, right string) string {
|
||||
leftMap := map[string][]string{}
|
||||
rightMap := map[string][]string{}
|
||||
|
||||
// Ignore errors
|
||||
json.Unmarshal([]byte(left), &leftMap)
|
||||
json.Unmarshal([]byte(right), &rightMap)
|
||||
|
||||
for k, v := range rightMap {
|
||||
existing, ok := leftMap[k]
|
||||
if ok {
|
||||
leftMap[k] = append(existing, v...)
|
||||
} else {
|
||||
leftMap[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
result, _ := json.Marshal(leftMap)
|
||||
|
||||
return string(result)
|
||||
}
|
||||
|
||||
// And returns a map of labels by merging the two specified values (left and right).
|
||||
func And(left, right map[string][]string) map[string][]string {
|
||||
result := map[string][]string{}
|
||||
for k, v := range left {
|
||||
result[k] = v
|
||||
}
|
||||
|
||||
for k, v := range right {
|
||||
existing, ok := result[k]
|
||||
if ok {
|
||||
result[k] = append(existing, v...)
|
||||
} else {
|
||||
result[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Str returns the label name.
|
||||
func (f Label) Str() string {
|
||||
return string(f)
|
||||
}
|
||||
|
||||
// LabelFilterString returns a label json string representation of the specifed couple (key,value)
|
||||
// that is used as filter for docker.
|
||||
func LabelFilterString(key, value string) string {
|
||||
return utils.FilterString(map[string][]string{
|
||||
"label": {fmt.Sprintf("%s=%s", key, value)},
|
||||
})
|
||||
}
|
||||
|
||||
// LabelFilter returns a label map representation of the specifed couple (key,value)
|
||||
// that is used as filter for docker.
|
||||
func LabelFilter(key, value string) map[string][]string {
|
||||
return map[string][]string{
|
||||
"label": {fmt.Sprintf("%s=%s", key, value)},
|
||||
}
|
||||
}
|
||||
18
integration/vendor/github.com/docker/libcompose/logger/null.go
generated
vendored
Normal file
18
integration/vendor/github.com/docker/libcompose/logger/null.go
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
package logger
|
||||
|
||||
// NullLogger is a logger.Logger and logger.Factory implementation that does nothing.
|
||||
type NullLogger struct {
|
||||
}
|
||||
|
||||
// Out is a no-op function.
|
||||
func (n *NullLogger) Out(_ []byte) {
|
||||
}
|
||||
|
||||
// Err is a no-op function.
|
||||
func (n *NullLogger) Err(_ []byte) {
|
||||
}
|
||||
|
||||
// Create implements logger.Factory and returns a NullLogger.
|
||||
func (n *NullLogger) Create(_ string) Logger {
|
||||
return &NullLogger{}
|
||||
}
|
||||
29
integration/vendor/github.com/docker/libcompose/logger/types.go
generated
vendored
Normal file
29
integration/vendor/github.com/docker/libcompose/logger/types.go
generated
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
package logger
|
||||
|
||||
// Factory defines methods a factory should implement, to create a Logger
|
||||
// based on the specified name.
|
||||
type Factory interface {
|
||||
Create(name string) Logger
|
||||
}
|
||||
|
||||
// Logger defines methods to implement for being a logger.
|
||||
type Logger interface {
|
||||
Out(bytes []byte)
|
||||
Err(bytes []byte)
|
||||
}
|
||||
|
||||
// Wrapper is a wrapper around Logger that implements the Writer interface,
|
||||
// mainly use by docker/pkg/stdcopy functions.
|
||||
type Wrapper struct {
|
||||
Err bool
|
||||
Logger Logger
|
||||
}
|
||||
|
||||
func (l *Wrapper) Write(bytes []byte) (int, error) {
|
||||
if l.Err {
|
||||
l.Logger.Err(bytes)
|
||||
} else {
|
||||
l.Logger.Out(bytes)
|
||||
}
|
||||
return len(bytes), nil
|
||||
}
|
||||
25
integration/vendor/github.com/docker/libcompose/lookup/composable.go
generated
vendored
Normal file
25
integration/vendor/github.com/docker/libcompose/lookup/composable.go
generated
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package lookup
|
||||
|
||||
import (
|
||||
"github.com/docker/libcompose/config"
|
||||
)
|
||||
|
||||
// ComposableEnvLookup is a structure that implements the project.EnvironmentLookup interface.
|
||||
// It holds an ordered list of EnvironmentLookup to call to look for the environment value.
|
||||
type ComposableEnvLookup struct {
|
||||
Lookups []config.EnvironmentLookup
|
||||
}
|
||||
|
||||
// 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 {
|
||||
result := []string{}
|
||||
for _, lookup := range l.Lookups {
|
||||
env := lookup.Lookup(key, serviceName, config)
|
||||
if len(env) == 1 {
|
||||
result = env
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
31
integration/vendor/github.com/docker/libcompose/lookup/envfile.go
generated
vendored
Normal file
31
integration/vendor/github.com/docker/libcompose/lookup/envfile.go
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package lookup
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/runconfig/opts"
|
||||
"github.com/docker/libcompose/config"
|
||||
)
|
||||
|
||||
// EnvfileLookup is a structure that implements the project.EnvironmentLookup interface.
|
||||
// It holds the path of the file where to lookup environment values.
|
||||
type EnvfileLookup struct {
|
||||
Path string
|
||||
}
|
||||
|
||||
// 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 {
|
||||
envs, err := opts.ParseEnvFile(l.Path)
|
||||
if err != nil {
|
||||
return []string{}
|
||||
}
|
||||
for _, env := range envs {
|
||||
e := strings.Split(env, "=")
|
||||
if e[0] == key {
|
||||
return []string{env}
|
||||
}
|
||||
}
|
||||
return []string{}
|
||||
}
|
||||
66
integration/vendor/github.com/docker/libcompose/lookup/file.go
generated
vendored
Normal file
66
integration/vendor/github.com/docker/libcompose/lookup/file.go
generated
vendored
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
package lookup
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
// relativePath returns the proper relative path for the given file path. If
|
||||
// the relativeTo string equals "-", then it means that it's from the stdin,
|
||||
// and the returned path will be the current working directory. Otherwise, if
|
||||
// file is really an absolute path, then it will be returned without any
|
||||
// changes. Otherwise, the returned path will be a combination of relativeTo
|
||||
// and file.
|
||||
func relativePath(file, relativeTo string) string {
|
||||
// stdin: return the current working directory if possible.
|
||||
if relativeTo == "-" {
|
||||
if cwd, err := os.Getwd(); err == nil {
|
||||
return cwd
|
||||
}
|
||||
}
|
||||
|
||||
// If the given file is already an absolute path, just return it.
|
||||
// Otherwise, the returned path will be relative to the given relativeTo
|
||||
// path.
|
||||
if filepath.IsAbs(file) {
|
||||
return file
|
||||
}
|
||||
|
||||
abs, err := filepath.Abs(filepath.Join(path.Dir(relativeTo), file))
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get absolute directory: %s", err)
|
||||
return file
|
||||
}
|
||||
return abs
|
||||
}
|
||||
|
||||
// FileConfigLookup is a "bare" structure that implements the project.ResourceLookup interface
|
||||
type FileConfigLookup struct {
|
||||
}
|
||||
|
||||
// Lookup returns the content and the actual filename of the file that is "built" using the
|
||||
// specified file and relativeTo string. file and relativeTo are supposed to be file path.
|
||||
// If file starts with a slash ('/'), it tries to load it, otherwise it will build a
|
||||
// filename using the folder part of relativeTo joined with file.
|
||||
func (f *FileConfigLookup) Lookup(file, relativeTo string) ([]byte, string, error) {
|
||||
file = relativePath(file, relativeTo)
|
||||
logrus.Debugf("Reading file %s", file)
|
||||
bytes, err := ioutil.ReadFile(file)
|
||||
return bytes, file, err
|
||||
}
|
||||
|
||||
// ResolvePath returns the path to be used for the given path volume. This
|
||||
// function already takes care of relative paths.
|
||||
func (f *FileConfigLookup) ResolvePath(path, inFile string) string {
|
||||
vs := strings.SplitN(path, ":", 2)
|
||||
if len(vs) != 2 || filepath.IsAbs(vs[0]) {
|
||||
return path
|
||||
}
|
||||
vs[0] = relativePath(vs[0], inFile)
|
||||
return strings.Join(vs, ":")
|
||||
}
|
||||
24
integration/vendor/github.com/docker/libcompose/lookup/simple_env.go
generated
vendored
Normal file
24
integration/vendor/github.com/docker/libcompose/lookup/simple_env.go
generated
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
package lookup
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/docker/libcompose/config"
|
||||
)
|
||||
|
||||
// OsEnvLookup is a "bare" structure that implements the project.EnvironmentLookup interface
|
||||
type OsEnvLookup 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 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 {
|
||||
ret := os.Getenv(key)
|
||||
if ret == "" {
|
||||
return []string{}
|
||||
}
|
||||
return []string{fmt.Sprintf("%s=%s", key, ret)}
|
||||
}
|
||||
1
integration/vendor/github.com/docker/libcompose/package.go
generated
vendored
Normal file
1
integration/vendor/github.com/docker/libcompose/package.go
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
package libcompose
|
||||
13
integration/vendor/github.com/docker/libcompose/project/container.go
generated
vendored
Normal file
13
integration/vendor/github.com/docker/libcompose/project/container.go
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
package project
|
||||
|
||||
import (
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Container defines what a libcompose container provides.
|
||||
type Container interface {
|
||||
ID() (string, error)
|
||||
Name() string
|
||||
Port(ctx context.Context, port string) (string, error)
|
||||
IsRunning(ctx context.Context) (bool, error)
|
||||
}
|
||||
140
integration/vendor/github.com/docker/libcompose/project/context.go
generated
vendored
Normal file
140
integration/vendor/github.com/docker/libcompose/project/context.go
generated
vendored
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
package project
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libcompose/config"
|
||||
"github.com/docker/libcompose/logger"
|
||||
)
|
||||
|
||||
var projectRegexp = regexp.MustCompile("[^a-zA-Z0-9_.-]")
|
||||
|
||||
// Context holds context meta information about a libcompose project, like
|
||||
// the project name, the compose file, etc.
|
||||
type Context struct {
|
||||
ComposeFiles []string
|
||||
ComposeBytes [][]byte
|
||||
ProjectName string
|
||||
isOpen bool
|
||||
ServiceFactory ServiceFactory
|
||||
NetworksFactory NetworksFactory
|
||||
EnvironmentLookup config.EnvironmentLookup
|
||||
ResourceLookup config.ResourceLookup
|
||||
LoggerFactory logger.Factory
|
||||
IgnoreMissingConfig bool
|
||||
Project *Project
|
||||
}
|
||||
|
||||
func (c *Context) readComposeFiles() error {
|
||||
if c.ComposeBytes != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
logrus.Debugf("Opening compose files: %s", strings.Join(c.ComposeFiles, ","))
|
||||
|
||||
// Handle STDIN (`-f -`)
|
||||
if len(c.ComposeFiles) == 1 && c.ComposeFiles[0] == "-" {
|
||||
composeBytes, err := ioutil.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to read compose file from stdin: %v", err)
|
||||
return err
|
||||
}
|
||||
c.ComposeBytes = [][]byte{composeBytes}
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, composeFile := range c.ComposeFiles {
|
||||
composeBytes, err := ioutil.ReadFile(composeFile)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
logrus.Errorf("Failed to open the compose file: %s", composeFile)
|
||||
return err
|
||||
}
|
||||
if err != nil && !c.IgnoreMissingConfig {
|
||||
logrus.Errorf("Failed to find the compose file: %s", composeFile)
|
||||
return err
|
||||
}
|
||||
c.ComposeBytes = append(c.ComposeBytes, composeBytes)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Context) determineProject() error {
|
||||
name, err := c.lookupProjectName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.ProjectName = normalizeName(name)
|
||||
|
||||
if c.ProjectName == "" {
|
||||
return fmt.Errorf("Falied to determine project name")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Context) lookupProjectName() (string, error) {
|
||||
if c.ProjectName != "" {
|
||||
return c.ProjectName, nil
|
||||
}
|
||||
|
||||
if envProject := os.Getenv("COMPOSE_PROJECT_NAME"); envProject != "" {
|
||||
return envProject, nil
|
||||
}
|
||||
|
||||
file := "."
|
||||
if len(c.ComposeFiles) > 0 {
|
||||
file = c.ComposeFiles[0]
|
||||
}
|
||||
|
||||
f, err := filepath.Abs(file)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get absolute directory for: %s", file)
|
||||
return "", err
|
||||
}
|
||||
|
||||
f = toUnixPath(f)
|
||||
|
||||
parent := path.Base(path.Dir(f))
|
||||
if parent != "" && parent != "." {
|
||||
return parent, nil
|
||||
} else if wd, err := os.Getwd(); err != nil {
|
||||
return "", err
|
||||
} else {
|
||||
return path.Base(toUnixPath(wd)), nil
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeName(name string) string {
|
||||
r := regexp.MustCompile("[^a-z0-9]+")
|
||||
return r.ReplaceAllString(strings.ToLower(name), "")
|
||||
}
|
||||
|
||||
func toUnixPath(p string) string {
|
||||
return strings.Replace(p, "\\", "/", -1)
|
||||
}
|
||||
|
||||
func (c *Context) open() error {
|
||||
if c.isOpen {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := c.readComposeFiles(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.determineProject(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.isOpen = true
|
||||
return nil
|
||||
}
|
||||
122
integration/vendor/github.com/docker/libcompose/project/empty.go
generated
vendored
Normal file
122
integration/vendor/github.com/docker/libcompose/project/empty.go
generated
vendored
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
package project
|
||||
|
||||
import (
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/libcompose/config"
|
||||
"github.com/docker/libcompose/project/events"
|
||||
"github.com/docker/libcompose/project/options"
|
||||
)
|
||||
|
||||
// this ensures EmptyService implements Service
|
||||
// useful since it's easy to forget adding new functions to EmptyService
|
||||
var _ Service = &EmptyService{}
|
||||
|
||||
// EmptyService is a struct that implements Service but does nothing.
|
||||
type EmptyService struct {
|
||||
}
|
||||
|
||||
// Create implements Service.Create but does nothing.
|
||||
func (e *EmptyService) Create(ctx context.Context, options options.Create) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Build implements Service.Build but does nothing.
|
||||
func (e *EmptyService) Build(ctx context.Context, buildOptions options.Build) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Up implements Service.Up but does nothing.
|
||||
func (e *EmptyService) Up(ctx context.Context, options options.Up) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Start implements Service.Start but does nothing.
|
||||
func (e *EmptyService) Start(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop implements Service.Stop() but does nothing.
|
||||
func (e *EmptyService) Stop(ctx context.Context, timeout int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete implements Service.Delete but does nothing.
|
||||
func (e *EmptyService) Delete(ctx context.Context, options options.Delete) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Restart implements Service.Restart but does nothing.
|
||||
func (e *EmptyService) Restart(ctx context.Context, timeout int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Log implements Service.Log but does nothing.
|
||||
func (e *EmptyService) Log(ctx context.Context, follow bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Pull implements Service.Pull but does nothing.
|
||||
func (e *EmptyService) Pull(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Kill implements Service.Kill but does nothing.
|
||||
func (e *EmptyService) Kill(ctx context.Context, signal string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Containers implements Service.Containers but does nothing.
|
||||
func (e *EmptyService) Containers(ctx context.Context) ([]Container, error) {
|
||||
return []Container{}, nil
|
||||
}
|
||||
|
||||
// Scale implements Service.Scale but does nothing.
|
||||
func (e *EmptyService) Scale(ctx context.Context, count int, timeout int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Info implements Service.Info but does nothing.
|
||||
func (e *EmptyService) Info(ctx context.Context, qFlag bool) (InfoSet, error) {
|
||||
return InfoSet{}, nil
|
||||
}
|
||||
|
||||
// Pause implements Service.Pause but does nothing.
|
||||
func (e *EmptyService) Pause(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unpause implements Service.Pause but does nothing.
|
||||
func (e *EmptyService) Unpause(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run implements Service.Run but does nothing.
|
||||
func (e *EmptyService) Run(ctx context.Context, commandParts []string, options options.Run) (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// RemoveImage implements Service.RemoveImage but does nothing.
|
||||
func (e *EmptyService) RemoveImage(ctx context.Context, imageType options.ImageType) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Events implements Service.Events but does nothing.
|
||||
func (e *EmptyService) Events(ctx context.Context, events chan events.ContainerEvent) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DependentServices implements Service.DependentServices with empty slice.
|
||||
func (e *EmptyService) DependentServices() []ServiceRelationship {
|
||||
return []ServiceRelationship{}
|
||||
}
|
||||
|
||||
// Config implements Service.Config with empty config.
|
||||
func (e *EmptyService) Config() *config.ServiceConfig {
|
||||
return &config.ServiceConfig{}
|
||||
}
|
||||
|
||||
// Name implements Service.Name with empty name.
|
||||
func (e *EmptyService) Name() string {
|
||||
return ""
|
||||
}
|
||||
224
integration/vendor/github.com/docker/libcompose/project/events/events.go
generated
vendored
Normal file
224
integration/vendor/github.com/docker/libcompose/project/events/events.go
generated
vendored
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
// Package events holds event structures, methods and functions.
|
||||
package events
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Notifier defines the methods an event notifier should have.
|
||||
type Notifier interface {
|
||||
Notify(eventType EventType, serviceName string, data map[string]string)
|
||||
}
|
||||
|
||||
// Emitter defines the methods an event emitter should have.
|
||||
type Emitter interface {
|
||||
AddListener(c chan<- Event)
|
||||
}
|
||||
|
||||
// Event holds project-wide event informations.
|
||||
type Event struct {
|
||||
EventType EventType
|
||||
ServiceName string
|
||||
Data map[string]string
|
||||
}
|
||||
|
||||
// ContainerEvent holds attributes of container events.
|
||||
type ContainerEvent struct {
|
||||
Service string `json:"service"`
|
||||
Event string `json:"event"`
|
||||
ID string `json:"id"`
|
||||
Time time.Time `json:"time"`
|
||||
Attributes map[string]string `json:"attributes"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// EventType defines a type of libcompose event.
|
||||
type EventType int
|
||||
|
||||
// Definitions of libcompose events
|
||||
const (
|
||||
NoEvent = EventType(iota)
|
||||
|
||||
ContainerCreated = EventType(iota)
|
||||
ContainerStarted = EventType(iota)
|
||||
|
||||
ServiceAdd = EventType(iota)
|
||||
ServiceUpStart = EventType(iota)
|
||||
ServiceUpIgnored = EventType(iota)
|
||||
ServiceUp = EventType(iota)
|
||||
ServiceCreateStart = EventType(iota)
|
||||
ServiceCreate = EventType(iota)
|
||||
ServiceDeleteStart = EventType(iota)
|
||||
ServiceDelete = EventType(iota)
|
||||
ServiceDownStart = EventType(iota)
|
||||
ServiceDown = EventType(iota)
|
||||
ServiceRestartStart = EventType(iota)
|
||||
ServiceRestart = EventType(iota)
|
||||
ServicePullStart = EventType(iota)
|
||||
ServicePull = EventType(iota)
|
||||
ServiceKillStart = EventType(iota)
|
||||
ServiceKill = EventType(iota)
|
||||
ServiceStartStart = EventType(iota)
|
||||
ServiceStart = EventType(iota)
|
||||
ServiceBuildStart = EventType(iota)
|
||||
ServiceBuild = EventType(iota)
|
||||
ServicePauseStart = EventType(iota)
|
||||
ServicePause = EventType(iota)
|
||||
ServiceUnpauseStart = EventType(iota)
|
||||
ServiceUnpause = EventType(iota)
|
||||
ServiceStopStart = EventType(iota)
|
||||
ServiceStop = EventType(iota)
|
||||
ServiceRunStart = EventType(iota)
|
||||
ServiceRun = EventType(iota)
|
||||
|
||||
VolumeAdd = EventType(iota)
|
||||
NetworkAdd = EventType(iota)
|
||||
|
||||
ProjectDownStart = EventType(iota)
|
||||
ProjectDownDone = EventType(iota)
|
||||
ProjectCreateStart = EventType(iota)
|
||||
ProjectCreateDone = EventType(iota)
|
||||
ProjectUpStart = EventType(iota)
|
||||
ProjectUpDone = EventType(iota)
|
||||
ProjectDeleteStart = EventType(iota)
|
||||
ProjectDeleteDone = EventType(iota)
|
||||
ProjectRestartStart = EventType(iota)
|
||||
ProjectRestartDone = EventType(iota)
|
||||
ProjectReload = EventType(iota)
|
||||
ProjectReloadTrigger = EventType(iota)
|
||||
ProjectKillStart = EventType(iota)
|
||||
ProjectKillDone = EventType(iota)
|
||||
ProjectStartStart = EventType(iota)
|
||||
ProjectStartDone = EventType(iota)
|
||||
ProjectBuildStart = EventType(iota)
|
||||
ProjectBuildDone = EventType(iota)
|
||||
ProjectPauseStart = EventType(iota)
|
||||
ProjectPauseDone = EventType(iota)
|
||||
ProjectUnpauseStart = EventType(iota)
|
||||
ProjectUnpauseDone = EventType(iota)
|
||||
ProjectStopStart = EventType(iota)
|
||||
ProjectStopDone = EventType(iota)
|
||||
)
|
||||
|
||||
func (e EventType) String() string {
|
||||
var m string
|
||||
switch e {
|
||||
case ContainerCreated:
|
||||
m = "Created container"
|
||||
case ContainerStarted:
|
||||
m = "Started container"
|
||||
|
||||
case ServiceAdd:
|
||||
m = "Adding"
|
||||
case ServiceUpStart:
|
||||
m = "Starting"
|
||||
case ServiceUpIgnored:
|
||||
m = "Ignoring"
|
||||
case ServiceUp:
|
||||
m = "Started"
|
||||
case ServiceCreateStart:
|
||||
m = "Creating"
|
||||
case ServiceCreate:
|
||||
m = "Created"
|
||||
case ServiceDeleteStart:
|
||||
m = "Deleting"
|
||||
case ServiceDelete:
|
||||
m = "Deleted"
|
||||
case ServiceStopStart:
|
||||
m = "Stopping"
|
||||
case ServiceStop:
|
||||
m = "Stopped"
|
||||
case ServiceDownStart:
|
||||
m = "Stopping"
|
||||
case ServiceDown:
|
||||
m = "Stopped"
|
||||
case ServiceRestartStart:
|
||||
m = "Restarting"
|
||||
case ServiceRestart:
|
||||
m = "Restarted"
|
||||
case ServicePullStart:
|
||||
m = "Pulling"
|
||||
case ServicePull:
|
||||
m = "Pulled"
|
||||
case ServiceKillStart:
|
||||
m = "Killing"
|
||||
case ServiceKill:
|
||||
m = "Killed"
|
||||
case ServiceStartStart:
|
||||
m = "Starting"
|
||||
case ServiceStart:
|
||||
m = "Started"
|
||||
case ServiceBuildStart:
|
||||
m = "Building"
|
||||
case ServiceBuild:
|
||||
m = "Built"
|
||||
case ServiceRunStart:
|
||||
m = "Executing"
|
||||
case ServiceRun:
|
||||
m = "Executed"
|
||||
case ServicePauseStart:
|
||||
m = "Pausing"
|
||||
case ServicePause:
|
||||
m = "Paused"
|
||||
case ServiceUnpauseStart:
|
||||
m = "Unpausing"
|
||||
case ServiceUnpause:
|
||||
m = "Unpaused"
|
||||
|
||||
case ProjectDownStart:
|
||||
m = "Stopping project"
|
||||
case ProjectDownDone:
|
||||
m = "Project stopped"
|
||||
case ProjectStopStart:
|
||||
m = "Stopping project"
|
||||
case ProjectStopDone:
|
||||
m = "Project stopped"
|
||||
case ProjectCreateStart:
|
||||
m = "Creating project"
|
||||
case ProjectCreateDone:
|
||||
m = "Project created"
|
||||
case ProjectUpStart:
|
||||
m = "Starting project"
|
||||
case ProjectUpDone:
|
||||
m = "Project started"
|
||||
case ProjectDeleteStart:
|
||||
m = "Deleting project"
|
||||
case ProjectDeleteDone:
|
||||
m = "Project deleted"
|
||||
case ProjectRestartStart:
|
||||
m = "Restarting project"
|
||||
case ProjectRestartDone:
|
||||
m = "Project restarted"
|
||||
case ProjectReload:
|
||||
m = "Reloading project"
|
||||
case ProjectReloadTrigger:
|
||||
m = "Triggering project reload"
|
||||
case ProjectKillStart:
|
||||
m = "Killing project"
|
||||
case ProjectKillDone:
|
||||
m = "Project killed"
|
||||
case ProjectStartStart:
|
||||
m = "Starting project"
|
||||
case ProjectStartDone:
|
||||
m = "Project started"
|
||||
case ProjectBuildStart:
|
||||
m = "Building project"
|
||||
case ProjectBuildDone:
|
||||
m = "Project built"
|
||||
case ProjectPauseStart:
|
||||
m = "Pausing project"
|
||||
case ProjectPauseDone:
|
||||
m = "Project paused"
|
||||
case ProjectUnpauseStart:
|
||||
m = "Unpausing project"
|
||||
case ProjectUnpauseDone:
|
||||
m = "Project unpaused"
|
||||
}
|
||||
|
||||
if m == "" {
|
||||
m = fmt.Sprintf("EventType: %d", int(e))
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
53
integration/vendor/github.com/docker/libcompose/project/info.go
generated
vendored
Normal file
53
integration/vendor/github.com/docker/libcompose/project/info.go
generated
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
package project
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"text/tabwriter"
|
||||
)
|
||||
|
||||
// InfoPart holds key/value strings.
|
||||
type InfoPart struct {
|
||||
Key, Value string
|
||||
}
|
||||
|
||||
// InfoSet holds a list of Info.
|
||||
type InfoSet []Info
|
||||
|
||||
// Info holds a list of InfoPart.
|
||||
type Info []InfoPart
|
||||
|
||||
func (infos InfoSet) String(titleFlag bool) string {
|
||||
//no error checking, none of this should fail
|
||||
buffer := bytes.NewBuffer(make([]byte, 0, 1024))
|
||||
tabwriter := tabwriter.NewWriter(buffer, 4, 4, 2, ' ', 0)
|
||||
|
||||
first := true
|
||||
for _, info := range infos {
|
||||
if first && titleFlag {
|
||||
writeLine(tabwriter, true, info)
|
||||
}
|
||||
first = false
|
||||
writeLine(tabwriter, false, info)
|
||||
}
|
||||
|
||||
tabwriter.Flush()
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func writeLine(writer io.Writer, key bool, info Info) {
|
||||
first := true
|
||||
for _, part := range info {
|
||||
if !first {
|
||||
writer.Write([]byte{'\t'})
|
||||
}
|
||||
first = false
|
||||
if key {
|
||||
writer.Write([]byte(part.Key))
|
||||
} else {
|
||||
writer.Write([]byte(part.Value))
|
||||
}
|
||||
}
|
||||
|
||||
writer.Write([]byte{'\n'})
|
||||
}
|
||||
45
integration/vendor/github.com/docker/libcompose/project/interface.go
generated
vendored
Normal file
45
integration/vendor/github.com/docker/libcompose/project/interface.go
generated
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
package project
|
||||
|
||||
import (
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/libcompose/config"
|
||||
"github.com/docker/libcompose/project/events"
|
||||
"github.com/docker/libcompose/project/options"
|
||||
)
|
||||
|
||||
// APIProject defines the methods a libcompose project should implement.
|
||||
type APIProject interface {
|
||||
events.Notifier
|
||||
events.Emitter
|
||||
|
||||
Build(ctx context.Context, options options.Build, sevice ...string) error
|
||||
Create(ctx context.Context, options options.Create, services ...string) error
|
||||
Delete(ctx context.Context, options options.Delete, services ...string) error
|
||||
Down(ctx context.Context, options options.Down, services ...string) error
|
||||
Events(ctx context.Context, services ...string) (chan events.ContainerEvent, error)
|
||||
Kill(ctx context.Context, signal string, services ...string) error
|
||||
Log(ctx context.Context, follow bool, services ...string) error
|
||||
Pause(ctx context.Context, services ...string) error
|
||||
Ps(ctx context.Context, onlyID bool, services ...string) (InfoSet, error)
|
||||
// FIXME(vdemeester) we could use nat.Port instead ?
|
||||
Port(ctx context.Context, index int, protocol, serviceName, privatePort string) (string, error)
|
||||
Pull(ctx context.Context, services ...string) error
|
||||
Restart(ctx context.Context, timeout int, services ...string) error
|
||||
Run(ctx context.Context, serviceName string, commandParts []string, options options.Run) (int, error)
|
||||
Scale(ctx context.Context, timeout int, servicesScale map[string]int) error
|
||||
Start(ctx context.Context, services ...string) error
|
||||
Stop(ctx context.Context, timeout int, services ...string) error
|
||||
Unpause(ctx context.Context, services ...string) error
|
||||
Up(ctx context.Context, options options.Up, services ...string) error
|
||||
|
||||
Parse() error
|
||||
CreateService(name string) (Service, error)
|
||||
AddConfig(name string, config *config.ServiceConfig) error
|
||||
Load(bytes []byte) error
|
||||
}
|
||||
|
||||
// RuntimeProject defines runtime-specific methods for a libcompose implementation.
|
||||
type RuntimeProject interface {
|
||||
RemoveOrphans(ctx context.Context, projectName string, serviceConfigs *config.ServiceConfigs) error
|
||||
}
|
||||
81
integration/vendor/github.com/docker/libcompose/project/listener.go
generated
vendored
Normal file
81
integration/vendor/github.com/docker/libcompose/project/listener.go
generated
vendored
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
package project
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libcompose/project/events"
|
||||
)
|
||||
|
||||
var (
|
||||
infoEvents = map[events.EventType]bool{
|
||||
events.ServiceDeleteStart: true,
|
||||
events.ServiceDelete: true,
|
||||
events.ServiceDownStart: true,
|
||||
events.ServiceDown: true,
|
||||
events.ServiceStopStart: true,
|
||||
events.ServiceStop: true,
|
||||
events.ServiceKillStart: true,
|
||||
events.ServiceKill: true,
|
||||
events.ServiceCreateStart: true,
|
||||
events.ServiceCreate: true,
|
||||
events.ServiceStartStart: true,
|
||||
events.ServiceStart: true,
|
||||
events.ServiceRestartStart: true,
|
||||
events.ServiceRestart: true,
|
||||
events.ServiceUpStart: true,
|
||||
events.ServiceUp: true,
|
||||
events.ServicePauseStart: true,
|
||||
events.ServicePause: true,
|
||||
events.ServiceUnpauseStart: true,
|
||||
events.ServiceUnpause: true,
|
||||
}
|
||||
)
|
||||
|
||||
type defaultListener struct {
|
||||
project *Project
|
||||
listenChan chan events.Event
|
||||
upCount int
|
||||
}
|
||||
|
||||
// NewDefaultListener create a default listener for the specified project.
|
||||
func NewDefaultListener(p *Project) chan<- events.Event {
|
||||
l := defaultListener{
|
||||
listenChan: make(chan events.Event),
|
||||
project: p,
|
||||
}
|
||||
go l.start()
|
||||
return l.listenChan
|
||||
}
|
||||
|
||||
func (d *defaultListener) start() {
|
||||
for event := range d.listenChan {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
if event.Data != nil {
|
||||
for k, v := range event.Data {
|
||||
if buffer.Len() > 0 {
|
||||
buffer.WriteString(", ")
|
||||
}
|
||||
buffer.WriteString(k)
|
||||
buffer.WriteString("=")
|
||||
buffer.WriteString(v)
|
||||
}
|
||||
}
|
||||
|
||||
if event.EventType == events.ServiceUp {
|
||||
d.upCount++
|
||||
}
|
||||
|
||||
logf := logrus.Debugf
|
||||
|
||||
if infoEvents[event.EventType] {
|
||||
logf = logrus.Infof
|
||||
}
|
||||
|
||||
if event.ServiceName == "" {
|
||||
logf("Project [%s]: %s %s", d.project.Name, event.EventType, buffer.Bytes())
|
||||
} else {
|
||||
logf("[%d/%d] [%s]: %s %s", d.upCount, d.project.ServiceConfigs.Len(), event.ServiceName, event.EventType, buffer.Bytes())
|
||||
}
|
||||
}
|
||||
}
|
||||
19
integration/vendor/github.com/docker/libcompose/project/network.go
generated
vendored
Normal file
19
integration/vendor/github.com/docker/libcompose/project/network.go
generated
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
package project
|
||||
|
||||
import (
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/libcompose/config"
|
||||
)
|
||||
|
||||
// Networks defines the methods a libcompose network aggregate should define.
|
||||
type Networks interface {
|
||||
Initialize(ctx context.Context) error
|
||||
Remove(ctx context.Context) error
|
||||
}
|
||||
|
||||
// NetworksFactory is an interface factory to create Networks object for the specified
|
||||
// configurations (service, networks, …)
|
||||
type NetworksFactory interface {
|
||||
Create(projectName string, networkConfigs map[string]*config.NetworkConfig, serviceConfigs *config.ServiceConfigs, networkEnabled bool) (Networks, error)
|
||||
}
|
||||
52
integration/vendor/github.com/docker/libcompose/project/options/types.go
generated
vendored
Normal file
52
integration/vendor/github.com/docker/libcompose/project/options/types.go
generated
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package options
|
||||
|
||||
// Build holds options of compose build.
|
||||
type Build struct {
|
||||
NoCache bool
|
||||
ForceRemove bool
|
||||
Pull bool
|
||||
}
|
||||
|
||||
// Delete holds options of compose rm.
|
||||
type Delete struct {
|
||||
RemoveVolume bool
|
||||
BeforeDeleteCallback func([]string) bool
|
||||
}
|
||||
|
||||
// Down holds options of compose down.
|
||||
type Down struct {
|
||||
RemoveVolume bool
|
||||
RemoveImages ImageType
|
||||
RemoveOrphans bool
|
||||
}
|
||||
|
||||
// Create holds options of compose create.
|
||||
type Create struct {
|
||||
NoRecreate bool
|
||||
ForceRecreate bool
|
||||
NoBuild bool
|
||||
// ForceBuild bool
|
||||
}
|
||||
|
||||
// Run holds options of compose run.
|
||||
type Run struct {
|
||||
Detached bool
|
||||
}
|
||||
|
||||
// Up holds options of compose up.
|
||||
type Up struct {
|
||||
Create
|
||||
}
|
||||
|
||||
// ImageType defines the type of image (local, all)
|
||||
type ImageType string
|
||||
|
||||
// Valid indicates whether the image type is valid.
|
||||
func (i ImageType) Valid() bool {
|
||||
switch string(i) {
|
||||
case "", "local", "all":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
745
integration/vendor/github.com/docker/libcompose/project/project.go
generated
vendored
Normal file
745
integration/vendor/github.com/docker/libcompose/project/project.go
generated
vendored
Normal file
|
|
@ -0,0 +1,745 @@
|
|||
package project
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libcompose/config"
|
||||
"github.com/docker/libcompose/logger"
|
||||
"github.com/docker/libcompose/project/events"
|
||||
"github.com/docker/libcompose/project/options"
|
||||
"github.com/docker/libcompose/utils"
|
||||
"github.com/docker/libcompose/yaml"
|
||||
)
|
||||
|
||||
type wrapperAction func(*serviceWrapper, map[string]*serviceWrapper)
|
||||
type serviceAction func(service Service) error
|
||||
|
||||
// Project holds libcompose project information.
|
||||
type Project struct {
|
||||
Name string
|
||||
ServiceConfigs *config.ServiceConfigs
|
||||
VolumeConfigs map[string]*config.VolumeConfig
|
||||
NetworkConfigs map[string]*config.NetworkConfig
|
||||
Files []string
|
||||
ReloadCallback func() error
|
||||
ParseOptions *config.ParseOptions
|
||||
|
||||
runtime RuntimeProject
|
||||
networks Networks
|
||||
configVersion string
|
||||
context *Context
|
||||
reload []string
|
||||
upCount int
|
||||
listeners []chan<- events.Event
|
||||
hasListeners bool
|
||||
}
|
||||
|
||||
// NewProject creates a new project with the specified context.
|
||||
func NewProject(context *Context, runtime RuntimeProject, parseOptions *config.ParseOptions) *Project {
|
||||
p := &Project{
|
||||
context: context,
|
||||
runtime: runtime,
|
||||
ParseOptions: parseOptions,
|
||||
ServiceConfigs: config.NewServiceConfigs(),
|
||||
VolumeConfigs: make(map[string]*config.VolumeConfig),
|
||||
NetworkConfigs: make(map[string]*config.NetworkConfig),
|
||||
}
|
||||
|
||||
if context.LoggerFactory == nil {
|
||||
context.LoggerFactory = &logger.NullLogger{}
|
||||
}
|
||||
|
||||
context.Project = p
|
||||
|
||||
p.listeners = []chan<- events.Event{NewDefaultListener(p)}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// Parse populates project information based on its context. It sets up the name,
|
||||
// the composefile and the composebytes (the composefile content).
|
||||
func (p *Project) Parse() error {
|
||||
err := p.context.open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.Name = p.context.ProjectName
|
||||
|
||||
p.Files = p.context.ComposeFiles
|
||||
|
||||
if len(p.Files) == 1 && p.Files[0] == "-" {
|
||||
p.Files = []string{"."}
|
||||
}
|
||||
|
||||
if p.context.ComposeBytes != nil {
|
||||
for i, composeBytes := range p.context.ComposeBytes {
|
||||
file := ""
|
||||
if i < len(p.context.ComposeFiles) {
|
||||
file = p.Files[i]
|
||||
}
|
||||
if err := p.load(file, composeBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateService creates a service with the specified name based. If there
|
||||
// is no config in the project for this service, it will return an error.
|
||||
func (p *Project) CreateService(name string) (Service, error) {
|
||||
existing, ok := p.ServiceConfigs.Get(name)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Failed to find service: %s", name)
|
||||
}
|
||||
|
||||
// Copy because we are about to modify the environment
|
||||
config := *existing
|
||||
|
||||
if p.context.EnvironmentLookup != nil {
|
||||
parsedEnv := make([]string, 0, len(config.Environment))
|
||||
|
||||
for _, env := range config.Environment {
|
||||
parts := strings.SplitN(env, "=", 2)
|
||||
if len(parts) > 1 && parts[1] != "" {
|
||||
parsedEnv = append(parsedEnv, env)
|
||||
continue
|
||||
} else {
|
||||
env = parts[0]
|
||||
}
|
||||
|
||||
for _, value := range p.context.EnvironmentLookup.Lookup(env, name, &config) {
|
||||
parsedEnv = append(parsedEnv, value)
|
||||
}
|
||||
}
|
||||
|
||||
config.Environment = parsedEnv
|
||||
|
||||
// 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)
|
||||
// depending on what we get back we do different things
|
||||
switch l := len(envValue); l {
|
||||
case 0:
|
||||
delete(config.Build.Args, arg)
|
||||
case 1:
|
||||
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 p.context.ServiceFactory.Create(p, name, &config)
|
||||
}
|
||||
|
||||
// AddConfig adds the specified service config for the specified name.
|
||||
func (p *Project) AddConfig(name string, config *config.ServiceConfig) error {
|
||||
p.Notify(events.ServiceAdd, name, nil)
|
||||
|
||||
p.ServiceConfigs.Add(name, config)
|
||||
p.reload = append(p.reload, name)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddVolumeConfig adds the specified volume config for the specified name.
|
||||
func (p *Project) AddVolumeConfig(name string, config *config.VolumeConfig) error {
|
||||
p.Notify(events.VolumeAdd, name, nil)
|
||||
p.VolumeConfigs[name] = config
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddNetworkConfig adds the specified network config for the specified name.
|
||||
func (p *Project) AddNetworkConfig(name string, config *config.NetworkConfig) error {
|
||||
p.Notify(events.NetworkAdd, name, nil)
|
||||
p.NetworkConfigs[name] = config
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load loads the specified byte array (the composefile content) and adds the
|
||||
// service configuration to the project.
|
||||
// FIXME is it needed ?
|
||||
func (p *Project) Load(bytes []byte) error {
|
||||
return p.load("", bytes)
|
||||
}
|
||||
|
||||
func (p *Project) load(file string, bytes []byte) error {
|
||||
version, serviceConfigs, volumeConfigs, networkConfigs, err := config.Merge(p.ServiceConfigs, p.context.EnvironmentLookup, p.context.ResourceLookup, file, bytes, p.ParseOptions)
|
||||
if err != nil {
|
||||
log.Errorf("Could not parse config for project %s : %v", p.Name, err)
|
||||
return err
|
||||
}
|
||||
|
||||
p.configVersion = version
|
||||
|
||||
for name, config := range volumeConfigs {
|
||||
err := p.AddVolumeConfig(name, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for name, config := range networkConfigs {
|
||||
err := p.AddNetworkConfig(name, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for name, config := range serviceConfigs {
|
||||
err := p.AddConfig(name, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Update network configuration a little bit
|
||||
if p.isNetworkEnabled() {
|
||||
for _, serviceName := range p.ServiceConfigs.Keys() {
|
||||
serviceConfig, _ := p.ServiceConfigs.Get(serviceName)
|
||||
if serviceConfig.NetworkMode != "" {
|
||||
continue
|
||||
}
|
||||
if serviceConfig.Networks == nil || len(serviceConfig.Networks.Networks) == 0 {
|
||||
// Add default as network
|
||||
serviceConfig.Networks = &yaml.Networks{
|
||||
Networks: []*yaml.Network{
|
||||
{
|
||||
Name: "default",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
// Consolidate the name of the network
|
||||
// FIXME(vdemeester) probably shouldn't be there, maybe move that to interface/factory
|
||||
for _, network := range serviceConfig.Networks.Networks {
|
||||
if net, ok := p.NetworkConfigs[network.Name]; ok {
|
||||
if net.External.External {
|
||||
network.RealName = network.Name
|
||||
if net.External.Name != "" {
|
||||
network.RealName = net.External.Name
|
||||
}
|
||||
} else {
|
||||
network.RealName = p.Name + "_" + network.Name
|
||||
}
|
||||
}
|
||||
// Ignoring if we don't find the network, it will be catched later
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(vdemeester) Not sure about this..
|
||||
if p.context.NetworksFactory != nil {
|
||||
networks, err := p.context.NetworksFactory.Create(p.Name, p.NetworkConfigs, p.ServiceConfigs, p.isNetworkEnabled())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.networks = networks
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) isNetworkEnabled() bool {
|
||||
return p.configVersion == "2"
|
||||
}
|
||||
|
||||
// initialize sets up required element for project before any action (on project and service).
|
||||
// This means it's not needed to be called on Config for example.
|
||||
func (p *Project) initialize(ctx context.Context) error {
|
||||
if err := p.networks.Initialize(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO Initialize volumes
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) loadWrappers(wrappers map[string]*serviceWrapper, servicesToConstruct []string) error {
|
||||
for _, name := range servicesToConstruct {
|
||||
wrapper, err := newServiceWrapper(name, p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
wrappers[name] = wrapper
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Build builds the specified services (like docker build).
|
||||
func (p *Project) Build(ctx context.Context, buildOptions options.Build, services ...string) error {
|
||||
return p.perform(events.ProjectBuildStart, events.ProjectBuildDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
|
||||
wrapper.Do(wrappers, events.ServiceBuildStart, events.ServiceBuild, func(service Service) error {
|
||||
return service.Build(ctx, buildOptions)
|
||||
})
|
||||
}), nil)
|
||||
}
|
||||
|
||||
// Create creates the specified services (like docker create).
|
||||
func (p *Project) Create(ctx context.Context, options options.Create, services ...string) error {
|
||||
if options.NoRecreate && options.ForceRecreate {
|
||||
return fmt.Errorf("no-recreate and force-recreate cannot be combined")
|
||||
}
|
||||
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)
|
||||
})
|
||||
}), nil)
|
||||
}
|
||||
|
||||
// Stop stops the specified services (like docker stop).
|
||||
func (p *Project) Stop(ctx context.Context, timeout int, services ...string) error {
|
||||
return p.perform(events.ProjectStopStart, events.ProjectStopDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
|
||||
wrapper.Do(nil, events.ServiceStopStart, events.ServiceStop, func(service Service) error {
|
||||
return service.Stop(ctx, timeout)
|
||||
})
|
||||
}), nil)
|
||||
}
|
||||
|
||||
// Down stops the specified services and clean related containers (like docker stop + docker rm).
|
||||
func (p *Project) Down(ctx context.Context, opts options.Down, services ...string) error {
|
||||
if !opts.RemoveImages.Valid() {
|
||||
return fmt.Errorf("--rmi flag must be local, all or empty")
|
||||
}
|
||||
if err := p.Stop(ctx, 10, services...); err != nil {
|
||||
return err
|
||||
}
|
||||
if opts.RemoveOrphans {
|
||||
if err := p.runtime.RemoveOrphans(ctx, p.Name, p.ServiceConfigs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := p.Delete(ctx, options.Delete{
|
||||
RemoveVolume: opts.RemoveVolume,
|
||||
}, services...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
networks, err := p.context.NetworksFactory.Create(p.Name, p.NetworkConfigs, p.ServiceConfigs, p.isNetworkEnabled())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := networks.Remove(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return p.forEach([]string{}, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
|
||||
wrapper.Do(wrappers, events.NoEvent, events.NoEvent, func(service Service) error {
|
||||
return service.RemoveImage(ctx, opts.RemoveImages)
|
||||
})
|
||||
}), func(service Service) error {
|
||||
return service.Create(ctx, options.Create{})
|
||||
})
|
||||
}
|
||||
|
||||
// RemoveOrphans implements project.RuntimeProject.RemoveOrphans.
|
||||
// It does nothing by default as it is supposed to be overriden by specific implementation.
|
||||
func (p *Project) RemoveOrphans(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Restart restarts the specified services (like docker restart).
|
||||
func (p *Project) Restart(ctx context.Context, timeout int, services ...string) error {
|
||||
return p.perform(events.ProjectRestartStart, events.ProjectRestartDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
|
||||
wrapper.Do(wrappers, events.ServiceRestartStart, events.ServiceRestart, func(service Service) error {
|
||||
return service.Restart(ctx, timeout)
|
||||
})
|
||||
}), nil)
|
||||
}
|
||||
|
||||
// Port returns the public port for a port binding of the specified service.
|
||||
func (p *Project) Port(ctx context.Context, index int, protocol, serviceName, privatePort string) (string, error) {
|
||||
service, err := p.CreateService(serviceName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
containers, err := service.Containers(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if index < 1 || index > len(containers) {
|
||||
return "", fmt.Errorf("Invalid index %d", index)
|
||||
}
|
||||
|
||||
return containers[index-1].Port(ctx, fmt.Sprintf("%s/%s", privatePort, protocol))
|
||||
}
|
||||
|
||||
// Ps list containers for the specified services.
|
||||
func (p *Project) Ps(ctx context.Context, onlyID bool, services ...string) (InfoSet, error) {
|
||||
allInfo := InfoSet{}
|
||||
for _, name := range p.ServiceConfigs.Keys() {
|
||||
service, err := p.CreateService(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info, err := service.Info(ctx, onlyID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
allInfo = append(allInfo, info...)
|
||||
}
|
||||
return allInfo, nil
|
||||
}
|
||||
|
||||
// Start starts the specified services (like docker start).
|
||||
func (p *Project) Start(ctx context.Context, services ...string) error {
|
||||
return p.perform(events.ProjectStartStart, events.ProjectStartDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
|
||||
wrapper.Do(wrappers, events.ServiceStartStart, events.ServiceStart, func(service Service) error {
|
||||
return service.Start(ctx)
|
||||
})
|
||||
}), nil)
|
||||
}
|
||||
|
||||
// Run executes a one off command (like `docker run image command`).
|
||||
func (p *Project) Run(ctx context.Context, serviceName string, commandParts []string, opts options.Run) (int, error) {
|
||||
if !p.ServiceConfigs.Has(serviceName) {
|
||||
return 1, fmt.Errorf("%s is not defined in the template", serviceName)
|
||||
}
|
||||
|
||||
if err := p.initialize(ctx); err != nil {
|
||||
return 1, err
|
||||
}
|
||||
var exitCode int
|
||||
err := p.forEach([]string{}, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
|
||||
wrapper.Do(wrappers, events.ServiceRunStart, events.ServiceRun, func(service Service) error {
|
||||
if service.Name() == serviceName {
|
||||
code, err := service.Run(ctx, commandParts, opts)
|
||||
exitCode = code
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}), func(service Service) error {
|
||||
return service.Create(ctx, options.Create{})
|
||||
})
|
||||
return exitCode, err
|
||||
}
|
||||
|
||||
// Up creates and starts the specified services (kinda like docker run).
|
||||
func (p *Project) Up(ctx context.Context, options options.Up, services ...string) error {
|
||||
if err := p.initialize(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return p.perform(events.ProjectUpStart, events.ProjectUpDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
|
||||
wrapper.Do(wrappers, events.ServiceUpStart, events.ServiceUp, func(service Service) error {
|
||||
return service.Up(ctx, options)
|
||||
})
|
||||
}), func(service Service) error {
|
||||
return service.Create(ctx, options.Create)
|
||||
})
|
||||
}
|
||||
|
||||
// Log aggregates and prints out the logs for the specified services.
|
||||
func (p *Project) Log(ctx context.Context, follow bool, services ...string) error {
|
||||
return p.forEach(services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
|
||||
wrapper.Do(nil, events.NoEvent, events.NoEvent, func(service Service) error {
|
||||
return service.Log(ctx, follow)
|
||||
})
|
||||
}), nil)
|
||||
}
|
||||
|
||||
// Scale scales the specified services.
|
||||
func (p *Project) Scale(ctx context.Context, timeout int, servicesScale map[string]int) error {
|
||||
// This code is a bit verbose but I wanted to parse everything up front
|
||||
order := make([]string, 0, 0)
|
||||
services := make(map[string]Service)
|
||||
|
||||
for name := range servicesScale {
|
||||
if !p.ServiceConfigs.Has(name) {
|
||||
return fmt.Errorf("%s is not defined in the template", name)
|
||||
}
|
||||
|
||||
service, err := p.CreateService(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to lookup service: %s: %v", service, err)
|
||||
}
|
||||
|
||||
order = append(order, name)
|
||||
services[name] = service
|
||||
}
|
||||
|
||||
for _, name := range order {
|
||||
scale := servicesScale[name]
|
||||
log.Infof("Setting scale %s=%d...", name, scale)
|
||||
err := services[name].Scale(ctx, scale, timeout)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to set the scale %s=%d: %v", name, scale, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Pull pulls the specified services (like docker pull).
|
||||
func (p *Project) Pull(ctx context.Context, services ...string) error {
|
||||
return p.forEach(services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
|
||||
wrapper.Do(nil, events.ServicePullStart, events.ServicePull, func(service Service) error {
|
||||
return service.Pull(ctx)
|
||||
})
|
||||
}), nil)
|
||||
}
|
||||
|
||||
// listStoppedContainers lists the stopped containers for the specified services.
|
||||
func (p *Project) listStoppedContainers(ctx context.Context, services ...string) ([]string, error) {
|
||||
stoppedContainers := []string{}
|
||||
err := p.forEach(services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
|
||||
wrapper.Do(nil, events.NoEvent, events.NoEvent, func(service Service) error {
|
||||
containers, innerErr := service.Containers(ctx)
|
||||
if innerErr != nil {
|
||||
return innerErr
|
||||
}
|
||||
|
||||
for _, container := range containers {
|
||||
running, innerErr := container.IsRunning(ctx)
|
||||
if innerErr != nil {
|
||||
log.Error(innerErr)
|
||||
}
|
||||
if !running {
|
||||
containerID, innerErr := container.ID()
|
||||
if innerErr != nil {
|
||||
log.Error(innerErr)
|
||||
}
|
||||
stoppedContainers = append(stoppedContainers, containerID)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return stoppedContainers, nil
|
||||
}
|
||||
|
||||
// Delete removes the specified services (like docker rm).
|
||||
func (p *Project) Delete(ctx context.Context, options options.Delete, services ...string) error {
|
||||
stoppedContainers, err := p.listStoppedContainers(ctx, services...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(stoppedContainers) == 0 {
|
||||
p.Notify(events.ProjectDeleteDone, "", nil)
|
||||
fmt.Println("No stopped containers")
|
||||
return nil
|
||||
}
|
||||
if options.BeforeDeleteCallback != nil && !options.BeforeDeleteCallback(stoppedContainers) {
|
||||
return nil
|
||||
}
|
||||
return p.perform(events.ProjectDeleteStart, events.ProjectDeleteDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
|
||||
wrapper.Do(nil, events.ServiceDeleteStart, events.ServiceDelete, func(service Service) error {
|
||||
return service.Delete(ctx, options)
|
||||
})
|
||||
}), nil)
|
||||
}
|
||||
|
||||
// Kill kills the specified services (like docker kill).
|
||||
func (p *Project) Kill(ctx context.Context, signal string, services ...string) error {
|
||||
return p.perform(events.ProjectKillStart, events.ProjectKillDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
|
||||
wrapper.Do(nil, events.ServiceKillStart, events.ServiceKill, func(service Service) error {
|
||||
return service.Kill(ctx, signal)
|
||||
})
|
||||
}), nil)
|
||||
}
|
||||
|
||||
// Pause pauses the specified services containers (like docker pause).
|
||||
func (p *Project) Pause(ctx context.Context, services ...string) error {
|
||||
return p.perform(events.ProjectPauseStart, events.ProjectPauseDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
|
||||
wrapper.Do(nil, events.ServicePauseStart, events.ServicePause, func(service Service) error {
|
||||
return service.Pause(ctx)
|
||||
})
|
||||
}), nil)
|
||||
}
|
||||
|
||||
// Unpause pauses the specified services containers (like docker pause).
|
||||
func (p *Project) Unpause(ctx context.Context, services ...string) error {
|
||||
return p.perform(events.ProjectUnpauseStart, events.ProjectUnpauseDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
|
||||
wrapper.Do(nil, events.ServiceUnpauseStart, events.ServiceUnpause, func(service Service) error {
|
||||
return service.Unpause(ctx)
|
||||
})
|
||||
}), nil)
|
||||
}
|
||||
|
||||
func (p *Project) perform(start, done events.EventType, services []string, action wrapperAction, cycleAction serviceAction) error {
|
||||
p.Notify(start, "", nil)
|
||||
|
||||
err := p.forEach(services, action, cycleAction)
|
||||
|
||||
p.Notify(done, "", nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func isSelected(wrapper *serviceWrapper, selected map[string]bool) bool {
|
||||
return len(selected) == 0 || selected[wrapper.name]
|
||||
}
|
||||
|
||||
func (p *Project) forEach(services []string, action wrapperAction, cycleAction serviceAction) error {
|
||||
selected := make(map[string]bool)
|
||||
wrappers := make(map[string]*serviceWrapper)
|
||||
|
||||
for _, s := range services {
|
||||
selected[s] = true
|
||||
}
|
||||
|
||||
return p.traverse(true, selected, wrappers, action, cycleAction)
|
||||
}
|
||||
|
||||
func (p *Project) startService(wrappers map[string]*serviceWrapper, history []string, selected, launched map[string]bool, wrapper *serviceWrapper, action wrapperAction, cycleAction serviceAction) error {
|
||||
if launched[wrapper.name] {
|
||||
return nil
|
||||
}
|
||||
|
||||
launched[wrapper.name] = true
|
||||
history = append(history, wrapper.name)
|
||||
|
||||
for _, dep := range wrapper.service.DependentServices() {
|
||||
target := wrappers[dep.Target]
|
||||
if target == nil {
|
||||
log.Debugf("Failed to find %s", dep.Target)
|
||||
return fmt.Errorf("Service '%s' has a link to service '%s' which is undefined", wrapper.name, dep.Target)
|
||||
}
|
||||
|
||||
if utils.Contains(history, dep.Target) {
|
||||
cycle := strings.Join(append(history, dep.Target), "->")
|
||||
if dep.Optional {
|
||||
log.Debugf("Ignoring cycle for %s", cycle)
|
||||
wrapper.IgnoreDep(dep.Target)
|
||||
if cycleAction != nil {
|
||||
var err error
|
||||
log.Debugf("Running cycle action for %s", cycle)
|
||||
err = cycleAction(target.service)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("Cycle detected in path %s", cycle)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
err := p.startService(wrappers, history, selected, launched, target, action, cycleAction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if isSelected(wrapper, selected) {
|
||||
log.Debugf("Launching action for %s", wrapper.name)
|
||||
go action(wrapper, wrappers)
|
||||
} else {
|
||||
wrapper.Ignore()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) traverse(start bool, selected map[string]bool, wrappers map[string]*serviceWrapper, action wrapperAction, cycleAction serviceAction) error {
|
||||
restart := false
|
||||
wrapperList := []string{}
|
||||
|
||||
if start {
|
||||
for _, name := range p.ServiceConfigs.Keys() {
|
||||
wrapperList = append(wrapperList, name)
|
||||
}
|
||||
} else {
|
||||
for _, wrapper := range wrappers {
|
||||
if err := wrapper.Reset(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
wrapperList = p.reload
|
||||
}
|
||||
|
||||
p.loadWrappers(wrappers, wrapperList)
|
||||
p.reload = []string{}
|
||||
|
||||
// check service name
|
||||
for s := range selected {
|
||||
if wrappers[s] == nil {
|
||||
return errors.New("No such service: " + s)
|
||||
}
|
||||
}
|
||||
|
||||
launched := map[string]bool{}
|
||||
|
||||
for _, wrapper := range wrappers {
|
||||
if err := p.startService(wrappers, []string{}, selected, launched, wrapper, action, cycleAction); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var firstError error
|
||||
|
||||
for _, wrapper := range wrappers {
|
||||
if !isSelected(wrapper, selected) {
|
||||
continue
|
||||
}
|
||||
if err := wrapper.Wait(); err == ErrRestart {
|
||||
restart = true
|
||||
} else if err != nil {
|
||||
log.Errorf("Failed to start: %s : %v", wrapper.name, err)
|
||||
if firstError == nil {
|
||||
firstError = err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if restart {
|
||||
if p.ReloadCallback != nil {
|
||||
if err := p.ReloadCallback(); err != nil {
|
||||
log.Errorf("Failed calling callback: %v", err)
|
||||
}
|
||||
}
|
||||
return p.traverse(false, selected, wrappers, action, cycleAction)
|
||||
}
|
||||
return firstError
|
||||
}
|
||||
|
||||
// AddListener adds the specified listener to the project.
|
||||
// This implements implicitly events.Emitter.
|
||||
func (p *Project) AddListener(c chan<- events.Event) {
|
||||
if !p.hasListeners {
|
||||
for _, l := range p.listeners {
|
||||
close(l)
|
||||
}
|
||||
p.hasListeners = true
|
||||
p.listeners = []chan<- events.Event{c}
|
||||
} else {
|
||||
p.listeners = append(p.listeners, c)
|
||||
}
|
||||
}
|
||||
|
||||
// Notify notifies all project listener with the specified eventType, service name and datas.
|
||||
// This implements implicitly events.Notifier interface.
|
||||
func (p *Project) Notify(eventType events.EventType, serviceName string, data map[string]string) {
|
||||
if eventType == events.NoEvent {
|
||||
return
|
||||
}
|
||||
|
||||
event := events.Event{
|
||||
EventType: eventType,
|
||||
ServiceName: serviceName,
|
||||
Data: data,
|
||||
}
|
||||
|
||||
for _, l := range p.listeners {
|
||||
l <- event
|
||||
}
|
||||
}
|
||||
24
integration/vendor/github.com/docker/libcompose/project/project_events.go
generated
vendored
Normal file
24
integration/vendor/github.com/docker/libcompose/project/project_events.go
generated
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
package project
|
||||
|
||||
import (
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/libcompose/project/events"
|
||||
)
|
||||
|
||||
// Events listen for real time events from containers (of the project).
|
||||
func (p *Project) Events(ctx context.Context, services ...string) (chan events.ContainerEvent, error) {
|
||||
events := make(chan events.ContainerEvent)
|
||||
if len(services) == 0 {
|
||||
services = p.ServiceConfigs.Keys()
|
||||
}
|
||||
// FIXME(vdemeester) handle errors (chan) here
|
||||
for _, service := range services {
|
||||
s, err := p.CreateService(service)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
go s.Events(ctx, events)
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
115
integration/vendor/github.com/docker/libcompose/project/service-wrapper.go
generated
vendored
Normal file
115
integration/vendor/github.com/docker/libcompose/project/service-wrapper.go
generated
vendored
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
package project
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libcompose/project/events"
|
||||
)
|
||||
|
||||
type serviceWrapper struct {
|
||||
name string
|
||||
service Service
|
||||
done sync.WaitGroup
|
||||
state ServiceState
|
||||
err error
|
||||
project *Project
|
||||
noWait bool
|
||||
ignored map[string]bool
|
||||
}
|
||||
|
||||
func newServiceWrapper(name string, p *Project) (*serviceWrapper, error) {
|
||||
wrapper := &serviceWrapper{
|
||||
name: name,
|
||||
state: StateUnknown,
|
||||
project: p,
|
||||
ignored: map[string]bool{},
|
||||
}
|
||||
|
||||
return wrapper, wrapper.Reset()
|
||||
}
|
||||
|
||||
func (s *serviceWrapper) IgnoreDep(name string) {
|
||||
s.ignored[name] = true
|
||||
}
|
||||
|
||||
func (s *serviceWrapper) Reset() error {
|
||||
if s.state != StateExecuted {
|
||||
service, err := s.project.CreateService(s.name)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to create service for %s : %v", s.name, err)
|
||||
return err
|
||||
}
|
||||
|
||||
s.service = service
|
||||
}
|
||||
|
||||
if s.err == ErrRestart {
|
||||
s.err = nil
|
||||
}
|
||||
s.done.Add(1)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *serviceWrapper) Ignore() {
|
||||
defer s.done.Done()
|
||||
|
||||
s.state = StateExecuted
|
||||
s.project.Notify(events.ServiceUpIgnored, s.service.Name(), nil)
|
||||
}
|
||||
|
||||
func (s *serviceWrapper) waitForDeps(wrappers map[string]*serviceWrapper) bool {
|
||||
if s.noWait {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, dep := range s.service.DependentServices() {
|
||||
if s.ignored[dep.Target] {
|
||||
continue
|
||||
}
|
||||
|
||||
if wrapper, ok := wrappers[dep.Target]; ok {
|
||||
if wrapper.Wait() == ErrRestart {
|
||||
s.project.Notify(events.ProjectReload, wrapper.service.Name(), nil)
|
||||
s.err = ErrRestart
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
log.Errorf("Failed to find %s", dep.Target)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *serviceWrapper) Do(wrappers map[string]*serviceWrapper, start, done events.EventType, action func(service Service) error) {
|
||||
defer s.done.Done()
|
||||
|
||||
if s.state == StateExecuted {
|
||||
return
|
||||
}
|
||||
|
||||
if wrappers != nil && !s.waitForDeps(wrappers) {
|
||||
return
|
||||
}
|
||||
|
||||
s.state = StateExecuted
|
||||
|
||||
s.project.Notify(start, s.service.Name(), nil)
|
||||
|
||||
s.err = action(s.service)
|
||||
if s.err == ErrRestart {
|
||||
s.project.Notify(done, s.service.Name(), nil)
|
||||
s.project.Notify(events.ProjectReloadTrigger, s.service.Name(), nil)
|
||||
} else if s.err != nil {
|
||||
log.Errorf("Failed %s %s : %v", start, s.name, s.err)
|
||||
} else {
|
||||
s.project.Notify(done, s.service.Name(), nil)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *serviceWrapper) Wait() error {
|
||||
s.done.Wait()
|
||||
return s.err
|
||||
}
|
||||
97
integration/vendor/github.com/docker/libcompose/project/service.go
generated
vendored
Normal file
97
integration/vendor/github.com/docker/libcompose/project/service.go
generated
vendored
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
package project
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/libcompose/config"
|
||||
"github.com/docker/libcompose/project/events"
|
||||
"github.com/docker/libcompose/project/options"
|
||||
)
|
||||
|
||||
// Service defines what a libcompose service provides.
|
||||
type Service interface {
|
||||
Build(ctx context.Context, buildOptions options.Build) error
|
||||
Create(ctx context.Context, options options.Create) error
|
||||
Delete(ctx context.Context, options options.Delete) error
|
||||
Events(ctx context.Context, messages chan events.ContainerEvent) error
|
||||
Info(ctx context.Context, qFlag bool) (InfoSet, error)
|
||||
Log(ctx context.Context, follow bool) error
|
||||
Kill(ctx context.Context, signal string) error
|
||||
Pause(ctx context.Context) error
|
||||
Pull(ctx context.Context) error
|
||||
Restart(ctx context.Context, timeout int) error
|
||||
Run(ctx context.Context, commandParts []string, options options.Run) (int, error)
|
||||
Scale(ctx context.Context, count int, timeout int) error
|
||||
Start(ctx context.Context) error
|
||||
Stop(ctx context.Context, timeout int) error
|
||||
Unpause(ctx context.Context) error
|
||||
Up(ctx context.Context, options options.Up) error
|
||||
|
||||
RemoveImage(ctx context.Context, imageType options.ImageType) error
|
||||
Containers(ctx context.Context) ([]Container, error)
|
||||
DependentServices() []ServiceRelationship
|
||||
Config() *config.ServiceConfig
|
||||
Name() string
|
||||
}
|
||||
|
||||
// ServiceState holds the state of a service.
|
||||
type ServiceState string
|
||||
|
||||
// State definitions
|
||||
var (
|
||||
StateExecuted = ServiceState("executed")
|
||||
StateUnknown = ServiceState("unknown")
|
||||
)
|
||||
|
||||
// Error definitions
|
||||
var (
|
||||
ErrRestart = errors.New("Restart execution")
|
||||
ErrUnsupported = errors.New("UnsupportedOperation")
|
||||
)
|
||||
|
||||
// ServiceFactory is an interface factory to create Service object for the specified
|
||||
// project, with the specified name and service configuration.
|
||||
type ServiceFactory interface {
|
||||
Create(project *Project, name string, serviceConfig *config.ServiceConfig) (Service, error)
|
||||
}
|
||||
|
||||
// ServiceRelationshipType defines the type of service relationship.
|
||||
type ServiceRelationshipType string
|
||||
|
||||
// RelTypeLink means the services are linked (docker links).
|
||||
const RelTypeLink = ServiceRelationshipType("")
|
||||
|
||||
// RelTypeNetNamespace means the services share the same network namespace.
|
||||
const RelTypeNetNamespace = ServiceRelationshipType("netns")
|
||||
|
||||
// RelTypeIpcNamespace means the service share the same ipc namespace.
|
||||
const RelTypeIpcNamespace = ServiceRelationshipType("ipc")
|
||||
|
||||
// RelTypeVolumesFrom means the services share some volumes.
|
||||
const RelTypeVolumesFrom = ServiceRelationshipType("volumesFrom")
|
||||
|
||||
// RelTypeDependsOn means the dependency was explicitly set using 'depends_on'.
|
||||
const RelTypeDependsOn = ServiceRelationshipType("dependsOn")
|
||||
|
||||
// RelTypeNetworkMode means the services depends on another service on networkMode
|
||||
const RelTypeNetworkMode = ServiceRelationshipType("networkMode")
|
||||
|
||||
// ServiceRelationship holds the relationship information between two services.
|
||||
type ServiceRelationship struct {
|
||||
Target, Alias string
|
||||
Type ServiceRelationshipType
|
||||
Optional bool
|
||||
}
|
||||
|
||||
// NewServiceRelationship creates a new Relationship based on the specified alias
|
||||
// and relationship type.
|
||||
func NewServiceRelationship(nameAlias string, relType ServiceRelationshipType) ServiceRelationship {
|
||||
name, alias := NameAlias(nameAlias)
|
||||
return ServiceRelationship{
|
||||
Target: name,
|
||||
Alias: alias,
|
||||
Type: relType,
|
||||
}
|
||||
}
|
||||
47
integration/vendor/github.com/docker/libcompose/project/utils.go
generated
vendored
Normal file
47
integration/vendor/github.com/docker/libcompose/project/utils.go
generated
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
package project
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// DefaultDependentServices return the dependent services (as an array of ServiceRelationship)
|
||||
// for the specified project and service. It looks for : links, volumesFrom, net and ipc configuration.
|
||||
func DefaultDependentServices(p *Project, s Service) []ServiceRelationship {
|
||||
config := s.Config()
|
||||
if config == nil {
|
||||
return []ServiceRelationship{}
|
||||
}
|
||||
|
||||
result := []ServiceRelationship{}
|
||||
for _, link := range config.Links {
|
||||
result = append(result, NewServiceRelationship(link, RelTypeLink))
|
||||
}
|
||||
|
||||
for _, volumesFrom := range config.VolumesFrom {
|
||||
result = append(result, NewServiceRelationship(volumesFrom, RelTypeVolumesFrom))
|
||||
}
|
||||
|
||||
for _, dependsOn := range config.DependsOn {
|
||||
result = append(result, NewServiceRelationship(dependsOn, RelTypeDependsOn))
|
||||
}
|
||||
|
||||
if config.NetworkMode != "" {
|
||||
if strings.HasPrefix(config.NetworkMode, "service:") {
|
||||
serviceName := config.NetworkMode[8:]
|
||||
result = append(result, NewServiceRelationship(serviceName, RelTypeNetworkMode))
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// NameAlias returns the name and alias based on the specified string.
|
||||
// If the name contains a colon (like name:alias) it will split it, otherwise
|
||||
// it will return the specified name as name and alias.
|
||||
func NameAlias(name string) (string, string) {
|
||||
parts := strings.SplitN(name, ":", 2)
|
||||
if len(parts) == 2 {
|
||||
return parts[0], parts[1]
|
||||
}
|
||||
return parts[0], parts[0]
|
||||
}
|
||||
137
integration/vendor/github.com/docker/libcompose/utils/util.go
generated
vendored
Normal file
137
integration/vendor/github.com/docker/libcompose/utils/util.go
generated
vendored
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sync"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
|
||||
yaml "github.com/cloudfoundry-incubator/candiedyaml"
|
||||
)
|
||||
|
||||
// InParallel holds a pool and a waitgroup to execute tasks in parallel and to be able
|
||||
// to wait for completion of all tasks.
|
||||
type InParallel struct {
|
||||
wg sync.WaitGroup
|
||||
pool sync.Pool
|
||||
}
|
||||
|
||||
// Add runs the specified task in parallel and adds it to the waitGroup.
|
||||
func (i *InParallel) Add(task func() error) {
|
||||
i.wg.Add(1)
|
||||
|
||||
go func() {
|
||||
defer i.wg.Done()
|
||||
err := task()
|
||||
if err != nil {
|
||||
i.pool.Put(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Wait waits for all tasks to complete and returns the latest error encountered if any.
|
||||
func (i *InParallel) Wait() error {
|
||||
i.wg.Wait()
|
||||
obj := i.pool.Get()
|
||||
if err, ok := obj.(error); ok {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConvertByJSON converts a struct (src) to another one (target) using json marshalling/unmarshalling.
|
||||
// If the structure are not compatible, this will throw an error as the unmarshalling will fail.
|
||||
func ConvertByJSON(src, target interface{}) error {
|
||||
newBytes, err := json.Marshal(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(newBytes, target)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to unmarshall: %v\n%s", err, string(newBytes))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Convert converts a struct (src) to another one (target) using yaml marshalling/unmarshalling.
|
||||
// If the structure are not compatible, this will throw an error as the unmarshalling will fail.
|
||||
func Convert(src, target interface{}) error {
|
||||
newBytes, err := yaml.Marshal(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal(newBytes, target)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to unmarshall: %v\n%s", err, string(newBytes))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// CopySlice creates an exact copy of the provided string slice
|
||||
func CopySlice(s []string) []string {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
r := make([]string, len(s))
|
||||
copy(r, s)
|
||||
return r
|
||||
}
|
||||
|
||||
// CopyMap creates an exact copy of the provided string-to-string map
|
||||
func CopyMap(m map[string]string) map[string]string {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
r := map[string]string{}
|
||||
for k, v := range m {
|
||||
r[k] = v
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// FilterStringSet accepts a string set `s` (in the form of `map[string]bool`) and a filtering function `f`
|
||||
// and returns a string set containing only the strings `x` for which `f(x) == true`
|
||||
func FilterStringSet(s map[string]bool, f func(x string) bool) map[string]bool {
|
||||
result := map[string]bool{}
|
||||
for k := range s {
|
||||
if f(k) {
|
||||
result[k] = true
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// FilterString returns a json representation of the specified map
|
||||
// that is used as filter for docker.
|
||||
func FilterString(data map[string][]string) string {
|
||||
// I can't imagine this would ever fail
|
||||
bytes, _ := json.Marshal(data)
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
// Contains checks if the specified string (key) is present in the specified collection.
|
||||
func Contains(collection []string, key string) bool {
|
||||
for _, value := range collection {
|
||||
if value == key {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Merge performs a union of two string slices: the result is an unordered slice
|
||||
// that includes every item from either argument exactly once
|
||||
func Merge(coll1, coll2 []string) []string {
|
||||
m := map[string]struct{}{}
|
||||
for _, v := range append(coll1, coll2...) {
|
||||
m[v] = struct{}{}
|
||||
}
|
||||
r := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
r = append(r, k)
|
||||
}
|
||||
return r
|
||||
}
|
||||
21
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/LICENSE
generated
vendored
Normal file
21
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Microsoft Corporation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
188
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/constants.go
generated
vendored
Normal file
188
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/constants.go
generated
vendored
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
package ansiterm
|
||||
|
||||
const LogEnv = "DEBUG_TERMINAL"
|
||||
|
||||
// ANSI constants
|
||||
// References:
|
||||
// -- http://www.ecma-international.org/publications/standards/Ecma-048.htm
|
||||
// -- http://man7.org/linux/man-pages/man4/console_codes.4.html
|
||||
// -- http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html
|
||||
// -- http://en.wikipedia.org/wiki/ANSI_escape_code
|
||||
// -- http://vt100.net/emu/dec_ansi_parser
|
||||
// -- http://vt100.net/emu/vt500_parser.svg
|
||||
// -- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
||||
// -- http://www.inwap.com/pdp10/ansicode.txt
|
||||
const (
|
||||
// ECMA-48 Set Graphics Rendition
|
||||
// Note:
|
||||
// -- Constants leading with an underscore (e.g., _ANSI_xxx) are unsupported or reserved
|
||||
// -- Fonts could possibly be supported via SetCurrentConsoleFontEx
|
||||
// -- Windows does not expose the per-window cursor (i.e., caret) blink times
|
||||
ANSI_SGR_RESET = 0
|
||||
ANSI_SGR_BOLD = 1
|
||||
ANSI_SGR_DIM = 2
|
||||
_ANSI_SGR_ITALIC = 3
|
||||
ANSI_SGR_UNDERLINE = 4
|
||||
_ANSI_SGR_BLINKSLOW = 5
|
||||
_ANSI_SGR_BLINKFAST = 6
|
||||
ANSI_SGR_REVERSE = 7
|
||||
_ANSI_SGR_INVISIBLE = 8
|
||||
_ANSI_SGR_LINETHROUGH = 9
|
||||
_ANSI_SGR_FONT_00 = 10
|
||||
_ANSI_SGR_FONT_01 = 11
|
||||
_ANSI_SGR_FONT_02 = 12
|
||||
_ANSI_SGR_FONT_03 = 13
|
||||
_ANSI_SGR_FONT_04 = 14
|
||||
_ANSI_SGR_FONT_05 = 15
|
||||
_ANSI_SGR_FONT_06 = 16
|
||||
_ANSI_SGR_FONT_07 = 17
|
||||
_ANSI_SGR_FONT_08 = 18
|
||||
_ANSI_SGR_FONT_09 = 19
|
||||
_ANSI_SGR_FONT_10 = 20
|
||||
_ANSI_SGR_DOUBLEUNDERLINE = 21
|
||||
ANSI_SGR_BOLD_DIM_OFF = 22
|
||||
_ANSI_SGR_ITALIC_OFF = 23
|
||||
ANSI_SGR_UNDERLINE_OFF = 24
|
||||
_ANSI_SGR_BLINK_OFF = 25
|
||||
_ANSI_SGR_RESERVED_00 = 26
|
||||
ANSI_SGR_REVERSE_OFF = 27
|
||||
_ANSI_SGR_INVISIBLE_OFF = 28
|
||||
_ANSI_SGR_LINETHROUGH_OFF = 29
|
||||
ANSI_SGR_FOREGROUND_BLACK = 30
|
||||
ANSI_SGR_FOREGROUND_RED = 31
|
||||
ANSI_SGR_FOREGROUND_GREEN = 32
|
||||
ANSI_SGR_FOREGROUND_YELLOW = 33
|
||||
ANSI_SGR_FOREGROUND_BLUE = 34
|
||||
ANSI_SGR_FOREGROUND_MAGENTA = 35
|
||||
ANSI_SGR_FOREGROUND_CYAN = 36
|
||||
ANSI_SGR_FOREGROUND_WHITE = 37
|
||||
_ANSI_SGR_RESERVED_01 = 38
|
||||
ANSI_SGR_FOREGROUND_DEFAULT = 39
|
||||
ANSI_SGR_BACKGROUND_BLACK = 40
|
||||
ANSI_SGR_BACKGROUND_RED = 41
|
||||
ANSI_SGR_BACKGROUND_GREEN = 42
|
||||
ANSI_SGR_BACKGROUND_YELLOW = 43
|
||||
ANSI_SGR_BACKGROUND_BLUE = 44
|
||||
ANSI_SGR_BACKGROUND_MAGENTA = 45
|
||||
ANSI_SGR_BACKGROUND_CYAN = 46
|
||||
ANSI_SGR_BACKGROUND_WHITE = 47
|
||||
_ANSI_SGR_RESERVED_02 = 48
|
||||
ANSI_SGR_BACKGROUND_DEFAULT = 49
|
||||
// 50 - 65: Unsupported
|
||||
|
||||
ANSI_MAX_CMD_LENGTH = 4096
|
||||
|
||||
MAX_INPUT_EVENTS = 128
|
||||
DEFAULT_WIDTH = 80
|
||||
DEFAULT_HEIGHT = 24
|
||||
|
||||
ANSI_BEL = 0x07
|
||||
ANSI_BACKSPACE = 0x08
|
||||
ANSI_TAB = 0x09
|
||||
ANSI_LINE_FEED = 0x0A
|
||||
ANSI_VERTICAL_TAB = 0x0B
|
||||
ANSI_FORM_FEED = 0x0C
|
||||
ANSI_CARRIAGE_RETURN = 0x0D
|
||||
ANSI_ESCAPE_PRIMARY = 0x1B
|
||||
ANSI_ESCAPE_SECONDARY = 0x5B
|
||||
ANSI_OSC_STRING_ENTRY = 0x5D
|
||||
ANSI_COMMAND_FIRST = 0x40
|
||||
ANSI_COMMAND_LAST = 0x7E
|
||||
DCS_ENTRY = 0x90
|
||||
CSI_ENTRY = 0x9B
|
||||
OSC_STRING = 0x9D
|
||||
ANSI_PARAMETER_SEP = ";"
|
||||
ANSI_CMD_G0 = '('
|
||||
ANSI_CMD_G1 = ')'
|
||||
ANSI_CMD_G2 = '*'
|
||||
ANSI_CMD_G3 = '+'
|
||||
ANSI_CMD_DECPNM = '>'
|
||||
ANSI_CMD_DECPAM = '='
|
||||
ANSI_CMD_OSC = ']'
|
||||
ANSI_CMD_STR_TERM = '\\'
|
||||
|
||||
KEY_CONTROL_PARAM_2 = ";2"
|
||||
KEY_CONTROL_PARAM_3 = ";3"
|
||||
KEY_CONTROL_PARAM_4 = ";4"
|
||||
KEY_CONTROL_PARAM_5 = ";5"
|
||||
KEY_CONTROL_PARAM_6 = ";6"
|
||||
KEY_CONTROL_PARAM_7 = ";7"
|
||||
KEY_CONTROL_PARAM_8 = ";8"
|
||||
KEY_ESC_CSI = "\x1B["
|
||||
KEY_ESC_N = "\x1BN"
|
||||
KEY_ESC_O = "\x1BO"
|
||||
|
||||
FILL_CHARACTER = ' '
|
||||
)
|
||||
|
||||
func getByteRange(start byte, end byte) []byte {
|
||||
bytes := make([]byte, 0, 32)
|
||||
for i := start; i <= end; i++ {
|
||||
bytes = append(bytes, byte(i))
|
||||
}
|
||||
|
||||
return bytes
|
||||
}
|
||||
|
||||
var toGroundBytes = getToGroundBytes()
|
||||
var executors = getExecuteBytes()
|
||||
|
||||
// SPACE 20+A0 hex Always and everywhere a blank space
|
||||
// Intermediate 20-2F hex !"#$%&'()*+,-./
|
||||
var intermeds = getByteRange(0x20, 0x2F)
|
||||
|
||||
// Parameters 30-3F hex 0123456789:;<=>?
|
||||
// CSI Parameters 30-39, 3B hex 0123456789;
|
||||
var csiParams = getByteRange(0x30, 0x3F)
|
||||
|
||||
var csiCollectables = append(getByteRange(0x30, 0x39), getByteRange(0x3B, 0x3F)...)
|
||||
|
||||
// Uppercase 40-5F hex @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
|
||||
var upperCase = getByteRange(0x40, 0x5F)
|
||||
|
||||
// Lowercase 60-7E hex `abcdefghijlkmnopqrstuvwxyz{|}~
|
||||
var lowerCase = getByteRange(0x60, 0x7E)
|
||||
|
||||
// Alphabetics 40-7E hex (all of upper and lower case)
|
||||
var alphabetics = append(upperCase, lowerCase...)
|
||||
|
||||
var printables = getByteRange(0x20, 0x7F)
|
||||
|
||||
var escapeIntermediateToGroundBytes = getByteRange(0x30, 0x7E)
|
||||
var escapeToGroundBytes = getEscapeToGroundBytes()
|
||||
|
||||
// See http://www.vt100.net/emu/vt500_parser.png for description of the complex
|
||||
// byte ranges below
|
||||
|
||||
func getEscapeToGroundBytes() []byte {
|
||||
escapeToGroundBytes := getByteRange(0x30, 0x4F)
|
||||
escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x51, 0x57)...)
|
||||
escapeToGroundBytes = append(escapeToGroundBytes, 0x59)
|
||||
escapeToGroundBytes = append(escapeToGroundBytes, 0x5A)
|
||||
escapeToGroundBytes = append(escapeToGroundBytes, 0x5C)
|
||||
escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x60, 0x7E)...)
|
||||
return escapeToGroundBytes
|
||||
}
|
||||
|
||||
func getExecuteBytes() []byte {
|
||||
executeBytes := getByteRange(0x00, 0x17)
|
||||
executeBytes = append(executeBytes, 0x19)
|
||||
executeBytes = append(executeBytes, getByteRange(0x1C, 0x1F)...)
|
||||
return executeBytes
|
||||
}
|
||||
|
||||
func getToGroundBytes() []byte {
|
||||
groundBytes := []byte{0x18}
|
||||
groundBytes = append(groundBytes, 0x1A)
|
||||
groundBytes = append(groundBytes, getByteRange(0x80, 0x8F)...)
|
||||
groundBytes = append(groundBytes, getByteRange(0x91, 0x97)...)
|
||||
groundBytes = append(groundBytes, 0x99)
|
||||
groundBytes = append(groundBytes, 0x9A)
|
||||
groundBytes = append(groundBytes, 0x9C)
|
||||
return groundBytes
|
||||
}
|
||||
|
||||
// Delete 7F hex Always and everywhere ignored
|
||||
// C1 Control 80-9F hex 32 additional control characters
|
||||
// G1 Displayable A1-FE hex 94 additional displayable characters
|
||||
// Special A0+FF hex Same as SPACE and DELETE
|
||||
7
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/context.go
generated
vendored
Normal file
7
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/context.go
generated
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
package ansiterm
|
||||
|
||||
type ansiContext struct {
|
||||
currentChar byte
|
||||
paramBuffer []byte
|
||||
interBuffer []byte
|
||||
}
|
||||
49
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go
generated
vendored
Normal file
49
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go
generated
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
package ansiterm
|
||||
|
||||
type csiEntryState struct {
|
||||
baseState
|
||||
}
|
||||
|
||||
func (csiState csiEntryState) Handle(b byte) (s state, e error) {
|
||||
logger.Infof("CsiEntry::Handle %#x", b)
|
||||
|
||||
nextState, err := csiState.baseState.Handle(b)
|
||||
if nextState != nil || err != nil {
|
||||
return nextState, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case sliceContains(alphabetics, b):
|
||||
return csiState.parser.ground, nil
|
||||
case sliceContains(csiCollectables, b):
|
||||
return csiState.parser.csiParam, nil
|
||||
case sliceContains(executors, b):
|
||||
return csiState, csiState.parser.execute()
|
||||
}
|
||||
|
||||
return csiState, nil
|
||||
}
|
||||
|
||||
func (csiState csiEntryState) Transition(s state) error {
|
||||
logger.Infof("CsiEntry::Transition %s --> %s", csiState.Name(), s.Name())
|
||||
csiState.baseState.Transition(s)
|
||||
|
||||
switch s {
|
||||
case csiState.parser.ground:
|
||||
return csiState.parser.csiDispatch()
|
||||
case csiState.parser.csiParam:
|
||||
switch {
|
||||
case sliceContains(csiParams, csiState.parser.context.currentChar):
|
||||
csiState.parser.collectParam()
|
||||
case sliceContains(intermeds, csiState.parser.context.currentChar):
|
||||
csiState.parser.collectInter()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (csiState csiEntryState) Enter() error {
|
||||
csiState.parser.clear()
|
||||
return nil
|
||||
}
|
||||
38
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/csi_param_state.go
generated
vendored
Normal file
38
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/csi_param_state.go
generated
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
package ansiterm
|
||||
|
||||
type csiParamState struct {
|
||||
baseState
|
||||
}
|
||||
|
||||
func (csiState csiParamState) Handle(b byte) (s state, e error) {
|
||||
logger.Infof("CsiParam::Handle %#x", b)
|
||||
|
||||
nextState, err := csiState.baseState.Handle(b)
|
||||
if nextState != nil || err != nil {
|
||||
return nextState, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case sliceContains(alphabetics, b):
|
||||
return csiState.parser.ground, nil
|
||||
case sliceContains(csiCollectables, b):
|
||||
csiState.parser.collectParam()
|
||||
return csiState, nil
|
||||
case sliceContains(executors, b):
|
||||
return csiState, csiState.parser.execute()
|
||||
}
|
||||
|
||||
return csiState, nil
|
||||
}
|
||||
|
||||
func (csiState csiParamState) Transition(s state) error {
|
||||
logger.Infof("CsiParam::Transition %s --> %s", csiState.Name(), s.Name())
|
||||
csiState.baseState.Transition(s)
|
||||
|
||||
switch s {
|
||||
case csiState.parser.ground:
|
||||
return csiState.parser.csiDispatch()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
36
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go
generated
vendored
Normal file
36
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go
generated
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
package ansiterm
|
||||
|
||||
type escapeIntermediateState struct {
|
||||
baseState
|
||||
}
|
||||
|
||||
func (escState escapeIntermediateState) Handle(b byte) (s state, e error) {
|
||||
logger.Infof("escapeIntermediateState::Handle %#x", b)
|
||||
nextState, err := escState.baseState.Handle(b)
|
||||
if nextState != nil || err != nil {
|
||||
return nextState, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case sliceContains(intermeds, b):
|
||||
return escState, escState.parser.collectInter()
|
||||
case sliceContains(executors, b):
|
||||
return escState, escState.parser.execute()
|
||||
case sliceContains(escapeIntermediateToGroundBytes, b):
|
||||
return escState.parser.ground, nil
|
||||
}
|
||||
|
||||
return escState, nil
|
||||
}
|
||||
|
||||
func (escState escapeIntermediateState) Transition(s state) error {
|
||||
logger.Infof("escapeIntermediateState::Transition %s --> %s", escState.Name(), s.Name())
|
||||
escState.baseState.Transition(s)
|
||||
|
||||
switch s {
|
||||
case escState.parser.ground:
|
||||
return escState.parser.escDispatch()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
47
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/escape_state.go
generated
vendored
Normal file
47
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/escape_state.go
generated
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
package ansiterm
|
||||
|
||||
type escapeState struct {
|
||||
baseState
|
||||
}
|
||||
|
||||
func (escState escapeState) Handle(b byte) (s state, e error) {
|
||||
logger.Infof("escapeState::Handle %#x", b)
|
||||
nextState, err := escState.baseState.Handle(b)
|
||||
if nextState != nil || err != nil {
|
||||
return nextState, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case b == ANSI_ESCAPE_SECONDARY:
|
||||
return escState.parser.csiEntry, nil
|
||||
case b == ANSI_OSC_STRING_ENTRY:
|
||||
return escState.parser.oscString, nil
|
||||
case sliceContains(executors, b):
|
||||
return escState, escState.parser.execute()
|
||||
case sliceContains(escapeToGroundBytes, b):
|
||||
return escState.parser.ground, nil
|
||||
case sliceContains(intermeds, b):
|
||||
return escState.parser.escapeIntermediate, nil
|
||||
}
|
||||
|
||||
return escState, nil
|
||||
}
|
||||
|
||||
func (escState escapeState) Transition(s state) error {
|
||||
logger.Infof("Escape::Transition %s --> %s", escState.Name(), s.Name())
|
||||
escState.baseState.Transition(s)
|
||||
|
||||
switch s {
|
||||
case escState.parser.ground:
|
||||
return escState.parser.escDispatch()
|
||||
case escState.parser.escapeIntermediate:
|
||||
return escState.parser.collectInter()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (escState escapeState) Enter() error {
|
||||
escState.parser.clear()
|
||||
return nil
|
||||
}
|
||||
90
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/event_handler.go
generated
vendored
Normal file
90
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/event_handler.go
generated
vendored
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
package ansiterm
|
||||
|
||||
type AnsiEventHandler interface {
|
||||
// Print
|
||||
Print(b byte) error
|
||||
|
||||
// Execute C0 commands
|
||||
Execute(b byte) error
|
||||
|
||||
// CUrsor Up
|
||||
CUU(int) error
|
||||
|
||||
// CUrsor Down
|
||||
CUD(int) error
|
||||
|
||||
// CUrsor Forward
|
||||
CUF(int) error
|
||||
|
||||
// CUrsor Backward
|
||||
CUB(int) error
|
||||
|
||||
// Cursor to Next Line
|
||||
CNL(int) error
|
||||
|
||||
// Cursor to Previous Line
|
||||
CPL(int) error
|
||||
|
||||
// Cursor Horizontal position Absolute
|
||||
CHA(int) error
|
||||
|
||||
// Vertical line Position Absolute
|
||||
VPA(int) error
|
||||
|
||||
// CUrsor Position
|
||||
CUP(int, int) error
|
||||
|
||||
// Horizontal and Vertical Position (depends on PUM)
|
||||
HVP(int, int) error
|
||||
|
||||
// Text Cursor Enable Mode
|
||||
DECTCEM(bool) error
|
||||
|
||||
// Origin Mode
|
||||
DECOM(bool) error
|
||||
|
||||
// 132 Column Mode
|
||||
DECCOLM(bool) error
|
||||
|
||||
// Erase in Display
|
||||
ED(int) error
|
||||
|
||||
// Erase in Line
|
||||
EL(int) error
|
||||
|
||||
// Insert Line
|
||||
IL(int) error
|
||||
|
||||
// Delete Line
|
||||
DL(int) error
|
||||
|
||||
// Insert Character
|
||||
ICH(int) error
|
||||
|
||||
// Delete Character
|
||||
DCH(int) error
|
||||
|
||||
// Set Graphics Rendition
|
||||
SGR([]int) error
|
||||
|
||||
// Pan Down
|
||||
SU(int) error
|
||||
|
||||
// Pan Up
|
||||
SD(int) error
|
||||
|
||||
// Device Attributes
|
||||
DA([]string) error
|
||||
|
||||
// Set Top and Bottom Margins
|
||||
DECSTBM(int, int) error
|
||||
|
||||
// Index
|
||||
IND() error
|
||||
|
||||
// Reverse Index
|
||||
RI() error
|
||||
|
||||
// Flush updates from previous commands
|
||||
Flush() error
|
||||
}
|
||||
24
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/ground_state.go
generated
vendored
Normal file
24
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/ground_state.go
generated
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
package ansiterm
|
||||
|
||||
type groundState struct {
|
||||
baseState
|
||||
}
|
||||
|
||||
func (gs groundState) Handle(b byte) (s state, e error) {
|
||||
gs.parser.context.currentChar = b
|
||||
|
||||
nextState, err := gs.baseState.Handle(b)
|
||||
if nextState != nil || err != nil {
|
||||
return nextState, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case sliceContains(printables, b):
|
||||
return gs, gs.parser.print()
|
||||
|
||||
case sliceContains(executors, b):
|
||||
return gs, gs.parser.execute()
|
||||
}
|
||||
|
||||
return gs, nil
|
||||
}
|
||||
31
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/osc_string_state.go
generated
vendored
Normal file
31
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/osc_string_state.go
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package ansiterm
|
||||
|
||||
type oscStringState struct {
|
||||
baseState
|
||||
}
|
||||
|
||||
func (oscState oscStringState) Handle(b byte) (s state, e error) {
|
||||
logger.Infof("OscString::Handle %#x", b)
|
||||
nextState, err := oscState.baseState.Handle(b)
|
||||
if nextState != nil || err != nil {
|
||||
return nextState, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case isOscStringTerminator(b):
|
||||
return oscState.parser.ground, nil
|
||||
}
|
||||
|
||||
return oscState, nil
|
||||
}
|
||||
|
||||
// See below for OSC string terminators for linux
|
||||
// http://man7.org/linux/man-pages/man4/console_codes.4.html
|
||||
func isOscStringTerminator(b byte) bool {
|
||||
|
||||
if b == ANSI_BEL || b == 0x5C {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
136
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/parser.go
generated
vendored
Normal file
136
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/parser.go
generated
vendored
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
package ansiterm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
var logger *logrus.Logger
|
||||
|
||||
type AnsiParser struct {
|
||||
currState state
|
||||
eventHandler AnsiEventHandler
|
||||
context *ansiContext
|
||||
csiEntry state
|
||||
csiParam state
|
||||
dcsEntry state
|
||||
escape state
|
||||
escapeIntermediate state
|
||||
error state
|
||||
ground state
|
||||
oscString state
|
||||
stateMap []state
|
||||
}
|
||||
|
||||
func CreateParser(initialState string, evtHandler AnsiEventHandler) *AnsiParser {
|
||||
logFile := ioutil.Discard
|
||||
|
||||
if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" {
|
||||
logFile, _ = os.Create("ansiParser.log")
|
||||
}
|
||||
|
||||
logger = &logrus.Logger{
|
||||
Out: logFile,
|
||||
Formatter: new(logrus.TextFormatter),
|
||||
Level: logrus.InfoLevel,
|
||||
}
|
||||
|
||||
parser := &AnsiParser{
|
||||
eventHandler: evtHandler,
|
||||
context: &ansiContext{},
|
||||
}
|
||||
|
||||
parser.csiEntry = csiEntryState{baseState{name: "CsiEntry", parser: parser}}
|
||||
parser.csiParam = csiParamState{baseState{name: "CsiParam", parser: parser}}
|
||||
parser.dcsEntry = dcsEntryState{baseState{name: "DcsEntry", parser: parser}}
|
||||
parser.escape = escapeState{baseState{name: "Escape", parser: parser}}
|
||||
parser.escapeIntermediate = escapeIntermediateState{baseState{name: "EscapeIntermediate", parser: parser}}
|
||||
parser.error = errorState{baseState{name: "Error", parser: parser}}
|
||||
parser.ground = groundState{baseState{name: "Ground", parser: parser}}
|
||||
parser.oscString = oscStringState{baseState{name: "OscString", parser: parser}}
|
||||
|
||||
parser.stateMap = []state{
|
||||
parser.csiEntry,
|
||||
parser.csiParam,
|
||||
parser.dcsEntry,
|
||||
parser.escape,
|
||||
parser.escapeIntermediate,
|
||||
parser.error,
|
||||
parser.ground,
|
||||
parser.oscString,
|
||||
}
|
||||
|
||||
parser.currState = getState(initialState, parser.stateMap)
|
||||
|
||||
logger.Infof("CreateParser: parser %p", parser)
|
||||
return parser
|
||||
}
|
||||
|
||||
func getState(name string, states []state) state {
|
||||
for _, el := range states {
|
||||
if el.Name() == name {
|
||||
return el
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) Parse(bytes []byte) (int, error) {
|
||||
for i, b := range bytes {
|
||||
if err := ap.handle(b); err != nil {
|
||||
return i, err
|
||||
}
|
||||
}
|
||||
|
||||
return len(bytes), ap.eventHandler.Flush()
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) handle(b byte) error {
|
||||
ap.context.currentChar = b
|
||||
newState, err := ap.currState.Handle(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if newState == nil {
|
||||
logger.Warning("newState is nil")
|
||||
return errors.New("New state of 'nil' is invalid.")
|
||||
}
|
||||
|
||||
if newState != ap.currState {
|
||||
if err := ap.changeState(newState); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) changeState(newState state) error {
|
||||
logger.Infof("ChangeState %s --> %s", ap.currState.Name(), newState.Name())
|
||||
|
||||
// Exit old state
|
||||
if err := ap.currState.Exit(); err != nil {
|
||||
logger.Infof("Exit state '%s' failed with : '%v'", ap.currState.Name(), err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Perform transition action
|
||||
if err := ap.currState.Transition(newState); err != nil {
|
||||
logger.Infof("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Enter new state
|
||||
if err := newState.Enter(); err != nil {
|
||||
logger.Infof("Enter state '%s' failed with: '%v'", newState.Name(), err)
|
||||
return err
|
||||
}
|
||||
|
||||
ap.currState = newState
|
||||
return nil
|
||||
}
|
||||
103
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go
generated
vendored
Normal file
103
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go
generated
vendored
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
package ansiterm
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func parseParams(bytes []byte) ([]string, error) {
|
||||
paramBuff := make([]byte, 0, 0)
|
||||
params := []string{}
|
||||
|
||||
for _, v := range bytes {
|
||||
if v == ';' {
|
||||
if len(paramBuff) > 0 {
|
||||
// Completed parameter, append it to the list
|
||||
s := string(paramBuff)
|
||||
params = append(params, s)
|
||||
paramBuff = make([]byte, 0, 0)
|
||||
}
|
||||
} else {
|
||||
paramBuff = append(paramBuff, v)
|
||||
}
|
||||
}
|
||||
|
||||
// Last parameter may not be terminated with ';'
|
||||
if len(paramBuff) > 0 {
|
||||
s := string(paramBuff)
|
||||
params = append(params, s)
|
||||
}
|
||||
|
||||
logger.Infof("Parsed params: %v with length: %d", params, len(params))
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func parseCmd(context ansiContext) (string, error) {
|
||||
return string(context.currentChar), nil
|
||||
}
|
||||
|
||||
func getInt(params []string, dflt int) int {
|
||||
i := getInts(params, 1, dflt)[0]
|
||||
logger.Infof("getInt: %v", i)
|
||||
return i
|
||||
}
|
||||
|
||||
func getInts(params []string, minCount int, dflt int) []int {
|
||||
ints := []int{}
|
||||
|
||||
for _, v := range params {
|
||||
i, _ := strconv.Atoi(v)
|
||||
// Zero is mapped to the default value in VT100.
|
||||
if i == 0 {
|
||||
i = dflt
|
||||
}
|
||||
ints = append(ints, i)
|
||||
}
|
||||
|
||||
if len(ints) < minCount {
|
||||
remaining := minCount - len(ints)
|
||||
for i := 0; i < remaining; i++ {
|
||||
ints = append(ints, dflt)
|
||||
}
|
||||
}
|
||||
|
||||
logger.Infof("getInts: %v", ints)
|
||||
|
||||
return ints
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) modeDispatch(param string, set bool) error {
|
||||
switch param {
|
||||
case "?3":
|
||||
return ap.eventHandler.DECCOLM(set)
|
||||
case "?6":
|
||||
return ap.eventHandler.DECOM(set)
|
||||
case "?25":
|
||||
return ap.eventHandler.DECTCEM(set)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) hDispatch(params []string) error {
|
||||
if len(params) == 1 {
|
||||
return ap.modeDispatch(params[0], true)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) lDispatch(params []string) error {
|
||||
if len(params) == 1 {
|
||||
return ap.modeDispatch(params[0], false)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getEraseParam(params []string) int {
|
||||
param := getInt(params, 0)
|
||||
if param < 0 || 3 < param {
|
||||
param = 0
|
||||
}
|
||||
|
||||
return param
|
||||
}
|
||||
122
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/parser_actions.go
generated
vendored
Normal file
122
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/parser_actions.go
generated
vendored
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
package ansiterm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func (ap *AnsiParser) collectParam() error {
|
||||
currChar := ap.context.currentChar
|
||||
logger.Infof("collectParam %#x", currChar)
|
||||
ap.context.paramBuffer = append(ap.context.paramBuffer, currChar)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) collectInter() error {
|
||||
currChar := ap.context.currentChar
|
||||
logger.Infof("collectInter %#x", currChar)
|
||||
ap.context.paramBuffer = append(ap.context.interBuffer, currChar)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) escDispatch() error {
|
||||
cmd, _ := parseCmd(*ap.context)
|
||||
intermeds := ap.context.interBuffer
|
||||
logger.Infof("escDispatch currentChar: %#x", ap.context.currentChar)
|
||||
logger.Infof("escDispatch: %v(%v)", cmd, intermeds)
|
||||
|
||||
switch cmd {
|
||||
case "D": // IND
|
||||
return ap.eventHandler.IND()
|
||||
case "E": // NEL, equivalent to CRLF
|
||||
err := ap.eventHandler.Execute(ANSI_CARRIAGE_RETURN)
|
||||
if err == nil {
|
||||
err = ap.eventHandler.Execute(ANSI_LINE_FEED)
|
||||
}
|
||||
return err
|
||||
case "M": // RI
|
||||
return ap.eventHandler.RI()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) csiDispatch() error {
|
||||
cmd, _ := parseCmd(*ap.context)
|
||||
params, _ := parseParams(ap.context.paramBuffer)
|
||||
|
||||
logger.Infof("csiDispatch: %v(%v)", cmd, params)
|
||||
|
||||
switch cmd {
|
||||
case "@":
|
||||
return ap.eventHandler.ICH(getInt(params, 1))
|
||||
case "A":
|
||||
return ap.eventHandler.CUU(getInt(params, 1))
|
||||
case "B":
|
||||
return ap.eventHandler.CUD(getInt(params, 1))
|
||||
case "C":
|
||||
return ap.eventHandler.CUF(getInt(params, 1))
|
||||
case "D":
|
||||
return ap.eventHandler.CUB(getInt(params, 1))
|
||||
case "E":
|
||||
return ap.eventHandler.CNL(getInt(params, 1))
|
||||
case "F":
|
||||
return ap.eventHandler.CPL(getInt(params, 1))
|
||||
case "G":
|
||||
return ap.eventHandler.CHA(getInt(params, 1))
|
||||
case "H":
|
||||
ints := getInts(params, 2, 1)
|
||||
x, y := ints[0], ints[1]
|
||||
return ap.eventHandler.CUP(x, y)
|
||||
case "J":
|
||||
param := getEraseParam(params)
|
||||
return ap.eventHandler.ED(param)
|
||||
case "K":
|
||||
param := getEraseParam(params)
|
||||
return ap.eventHandler.EL(param)
|
||||
case "L":
|
||||
return ap.eventHandler.IL(getInt(params, 1))
|
||||
case "M":
|
||||
return ap.eventHandler.DL(getInt(params, 1))
|
||||
case "P":
|
||||
return ap.eventHandler.DCH(getInt(params, 1))
|
||||
case "S":
|
||||
return ap.eventHandler.SU(getInt(params, 1))
|
||||
case "T":
|
||||
return ap.eventHandler.SD(getInt(params, 1))
|
||||
case "c":
|
||||
return ap.eventHandler.DA(params)
|
||||
case "d":
|
||||
return ap.eventHandler.VPA(getInt(params, 1))
|
||||
case "f":
|
||||
ints := getInts(params, 2, 1)
|
||||
x, y := ints[0], ints[1]
|
||||
return ap.eventHandler.HVP(x, y)
|
||||
case "h":
|
||||
return ap.hDispatch(params)
|
||||
case "l":
|
||||
return ap.lDispatch(params)
|
||||
case "m":
|
||||
return ap.eventHandler.SGR(getInts(params, 1, 0))
|
||||
case "r":
|
||||
ints := getInts(params, 2, 1)
|
||||
top, bottom := ints[0], ints[1]
|
||||
return ap.eventHandler.DECSTBM(top, bottom)
|
||||
default:
|
||||
logger.Errorf(fmt.Sprintf("Unsupported CSI command: '%s', with full context: %v", cmd, ap.context))
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) print() error {
|
||||
return ap.eventHandler.Print(ap.context.currentChar)
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) clear() error {
|
||||
ap.context = &ansiContext{}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) execute() error {
|
||||
return ap.eventHandler.Execute(ap.context.currentChar)
|
||||
}
|
||||
71
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/states.go
generated
vendored
Normal file
71
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/states.go
generated
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
package ansiterm
|
||||
|
||||
type stateID int
|
||||
|
||||
type state interface {
|
||||
Enter() error
|
||||
Exit() error
|
||||
Handle(byte) (state, error)
|
||||
Name() string
|
||||
Transition(state) error
|
||||
}
|
||||
|
||||
type baseState struct {
|
||||
name string
|
||||
parser *AnsiParser
|
||||
}
|
||||
|
||||
func (base baseState) Enter() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (base baseState) Exit() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (base baseState) Handle(b byte) (s state, e error) {
|
||||
|
||||
switch {
|
||||
case b == CSI_ENTRY:
|
||||
return base.parser.csiEntry, nil
|
||||
case b == DCS_ENTRY:
|
||||
return base.parser.dcsEntry, nil
|
||||
case b == ANSI_ESCAPE_PRIMARY:
|
||||
return base.parser.escape, nil
|
||||
case b == OSC_STRING:
|
||||
return base.parser.oscString, nil
|
||||
case sliceContains(toGroundBytes, b):
|
||||
return base.parser.ground, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (base baseState) Name() string {
|
||||
return base.name
|
||||
}
|
||||
|
||||
func (base baseState) Transition(s state) error {
|
||||
if s == base.parser.ground {
|
||||
execBytes := []byte{0x18}
|
||||
execBytes = append(execBytes, 0x1A)
|
||||
execBytes = append(execBytes, getByteRange(0x80, 0x8F)...)
|
||||
execBytes = append(execBytes, getByteRange(0x91, 0x97)...)
|
||||
execBytes = append(execBytes, 0x99)
|
||||
execBytes = append(execBytes, 0x9A)
|
||||
|
||||
if sliceContains(execBytes, base.parser.context.currentChar) {
|
||||
return base.parser.execute()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type dcsEntryState struct {
|
||||
baseState
|
||||
}
|
||||
|
||||
type errorState struct {
|
||||
baseState
|
||||
}
|
||||
21
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/utilities.go
generated
vendored
Normal file
21
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/utilities.go
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
package ansiterm
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func sliceContains(bytes []byte, b byte) bool {
|
||||
for _, v := range bytes {
|
||||
if v == b {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func convertBytesToInteger(bytes []byte) int {
|
||||
s := string(bytes)
|
||||
i, _ := strconv.Atoi(s)
|
||||
return i
|
||||
}
|
||||
182
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go
generated
vendored
Normal file
182
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go
generated
vendored
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/Azure/go-ansiterm"
|
||||
)
|
||||
|
||||
// Windows keyboard constants
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx.
|
||||
const (
|
||||
VK_PRIOR = 0x21 // PAGE UP key
|
||||
VK_NEXT = 0x22 // PAGE DOWN key
|
||||
VK_END = 0x23 // END key
|
||||
VK_HOME = 0x24 // HOME key
|
||||
VK_LEFT = 0x25 // LEFT ARROW key
|
||||
VK_UP = 0x26 // UP ARROW key
|
||||
VK_RIGHT = 0x27 // RIGHT ARROW key
|
||||
VK_DOWN = 0x28 // DOWN ARROW key
|
||||
VK_SELECT = 0x29 // SELECT key
|
||||
VK_PRINT = 0x2A // PRINT key
|
||||
VK_EXECUTE = 0x2B // EXECUTE key
|
||||
VK_SNAPSHOT = 0x2C // PRINT SCREEN key
|
||||
VK_INSERT = 0x2D // INS key
|
||||
VK_DELETE = 0x2E // DEL key
|
||||
VK_HELP = 0x2F // HELP key
|
||||
VK_F1 = 0x70 // F1 key
|
||||
VK_F2 = 0x71 // F2 key
|
||||
VK_F3 = 0x72 // F3 key
|
||||
VK_F4 = 0x73 // F4 key
|
||||
VK_F5 = 0x74 // F5 key
|
||||
VK_F6 = 0x75 // F6 key
|
||||
VK_F7 = 0x76 // F7 key
|
||||
VK_F8 = 0x77 // F8 key
|
||||
VK_F9 = 0x78 // F9 key
|
||||
VK_F10 = 0x79 // F10 key
|
||||
VK_F11 = 0x7A // F11 key
|
||||
VK_F12 = 0x7B // F12 key
|
||||
|
||||
RIGHT_ALT_PRESSED = 0x0001
|
||||
LEFT_ALT_PRESSED = 0x0002
|
||||
RIGHT_CTRL_PRESSED = 0x0004
|
||||
LEFT_CTRL_PRESSED = 0x0008
|
||||
SHIFT_PRESSED = 0x0010
|
||||
NUMLOCK_ON = 0x0020
|
||||
SCROLLLOCK_ON = 0x0040
|
||||
CAPSLOCK_ON = 0x0080
|
||||
ENHANCED_KEY = 0x0100
|
||||
)
|
||||
|
||||
type ansiCommand struct {
|
||||
CommandBytes []byte
|
||||
Command string
|
||||
Parameters []string
|
||||
IsSpecial bool
|
||||
}
|
||||
|
||||
func newAnsiCommand(command []byte) *ansiCommand {
|
||||
|
||||
if isCharacterSelectionCmdChar(command[1]) {
|
||||
// Is Character Set Selection commands
|
||||
return &ansiCommand{
|
||||
CommandBytes: command,
|
||||
Command: string(command),
|
||||
IsSpecial: true,
|
||||
}
|
||||
}
|
||||
|
||||
// last char is command character
|
||||
lastCharIndex := len(command) - 1
|
||||
|
||||
ac := &ansiCommand{
|
||||
CommandBytes: command,
|
||||
Command: string(command[lastCharIndex]),
|
||||
IsSpecial: false,
|
||||
}
|
||||
|
||||
// more than a single escape
|
||||
if lastCharIndex != 0 {
|
||||
start := 1
|
||||
// skip if double char escape sequence
|
||||
if command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_ESCAPE_SECONDARY {
|
||||
start++
|
||||
}
|
||||
// convert this to GetNextParam method
|
||||
ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ansiterm.ANSI_PARAMETER_SEP)
|
||||
}
|
||||
|
||||
return ac
|
||||
}
|
||||
|
||||
func (ac *ansiCommand) paramAsSHORT(index int, defaultValue int16) int16 {
|
||||
if index < 0 || index >= len(ac.Parameters) {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
param, err := strconv.ParseInt(ac.Parameters[index], 10, 16)
|
||||
if err != nil {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
return int16(param)
|
||||
}
|
||||
|
||||
func (ac *ansiCommand) String() string {
|
||||
return fmt.Sprintf("0x%v \"%v\" (\"%v\")",
|
||||
bytesToHex(ac.CommandBytes),
|
||||
ac.Command,
|
||||
strings.Join(ac.Parameters, "\",\""))
|
||||
}
|
||||
|
||||
// isAnsiCommandChar returns true if the passed byte falls within the range of ANSI commands.
|
||||
// See http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html.
|
||||
func isAnsiCommandChar(b byte) bool {
|
||||
switch {
|
||||
case ansiterm.ANSI_COMMAND_FIRST <= b && b <= ansiterm.ANSI_COMMAND_LAST && b != ansiterm.ANSI_ESCAPE_SECONDARY:
|
||||
return true
|
||||
case b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_OSC || b == ansiterm.ANSI_CMD_DECPAM || b == ansiterm.ANSI_CMD_DECPNM:
|
||||
// non-CSI escape sequence terminator
|
||||
return true
|
||||
case b == ansiterm.ANSI_CMD_STR_TERM || b == ansiterm.ANSI_BEL:
|
||||
// String escape sequence terminator
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isXtermOscSequence(command []byte, current byte) bool {
|
||||
return (len(command) >= 2 && command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_CMD_OSC && current != ansiterm.ANSI_BEL)
|
||||
}
|
||||
|
||||
func isCharacterSelectionCmdChar(b byte) bool {
|
||||
return (b == ansiterm.ANSI_CMD_G0 || b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_G2 || b == ansiterm.ANSI_CMD_G3)
|
||||
}
|
||||
|
||||
// bytesToHex converts a slice of bytes to a human-readable string.
|
||||
func bytesToHex(b []byte) string {
|
||||
hex := make([]string, len(b))
|
||||
for i, ch := range b {
|
||||
hex[i] = fmt.Sprintf("%X", ch)
|
||||
}
|
||||
return strings.Join(hex, "")
|
||||
}
|
||||
|
||||
// ensureInRange adjusts the passed value, if necessary, to ensure it is within
|
||||
// the passed min / max range.
|
||||
func ensureInRange(n int16, min int16, max int16) int16 {
|
||||
if n < min {
|
||||
return min
|
||||
} else if n > max {
|
||||
return max
|
||||
} else {
|
||||
return n
|
||||
}
|
||||
}
|
||||
|
||||
func GetStdFile(nFile int) (*os.File, uintptr) {
|
||||
var file *os.File
|
||||
switch nFile {
|
||||
case syscall.STD_INPUT_HANDLE:
|
||||
file = os.Stdin
|
||||
case syscall.STD_OUTPUT_HANDLE:
|
||||
file = os.Stdout
|
||||
case syscall.STD_ERROR_HANDLE:
|
||||
file = os.Stderr
|
||||
default:
|
||||
panic(fmt.Errorf("Invalid standard handle identifier: %v", nFile))
|
||||
}
|
||||
|
||||
fd, err := syscall.GetStdHandle(nFile)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Invalid standard handle indentifier: %v -- %v", nFile, err))
|
||||
}
|
||||
|
||||
return file, uintptr(fd)
|
||||
}
|
||||
322
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/winterm/api.go
generated
vendored
Normal file
322
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/winterm/api.go
generated
vendored
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//===========================================================================================================
|
||||
// IMPORTANT NOTE:
|
||||
//
|
||||
// The methods below make extensive use of the "unsafe" package to obtain the required pointers.
|
||||
// Beginning in Go 1.3, the garbage collector may release local variables (e.g., incoming arguments, stack
|
||||
// variables) the pointers reference *before* the API completes.
|
||||
//
|
||||
// As a result, in those cases, the code must hint that the variables remain in active by invoking the
|
||||
// dummy method "use" (see below). Newer versions of Go are planned to change the mechanism to no longer
|
||||
// require unsafe pointers.
|
||||
//
|
||||
// If you add or modify methods, ENSURE protection of local variables through the "use" builtin to inform
|
||||
// the garbage collector the variables remain in use if:
|
||||
//
|
||||
// -- The value is not a pointer (e.g., int32, struct)
|
||||
// -- The value is not referenced by the method after passing the pointer to Windows
|
||||
//
|
||||
// See http://golang.org/doc/go1.3.
|
||||
//===========================================================================================================
|
||||
|
||||
var (
|
||||
kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
|
||||
|
||||
getConsoleCursorInfoProc = kernel32DLL.NewProc("GetConsoleCursorInfo")
|
||||
setConsoleCursorInfoProc = kernel32DLL.NewProc("SetConsoleCursorInfo")
|
||||
setConsoleCursorPositionProc = kernel32DLL.NewProc("SetConsoleCursorPosition")
|
||||
setConsoleModeProc = kernel32DLL.NewProc("SetConsoleMode")
|
||||
getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo")
|
||||
setConsoleScreenBufferSizeProc = kernel32DLL.NewProc("SetConsoleScreenBufferSize")
|
||||
scrollConsoleScreenBufferProc = kernel32DLL.NewProc("ScrollConsoleScreenBufferA")
|
||||
setConsoleTextAttributeProc = kernel32DLL.NewProc("SetConsoleTextAttribute")
|
||||
setConsoleWindowInfoProc = kernel32DLL.NewProc("SetConsoleWindowInfo")
|
||||
writeConsoleOutputProc = kernel32DLL.NewProc("WriteConsoleOutputW")
|
||||
readConsoleInputProc = kernel32DLL.NewProc("ReadConsoleInputW")
|
||||
waitForSingleObjectProc = kernel32DLL.NewProc("WaitForSingleObject")
|
||||
)
|
||||
|
||||
// Windows Console constants
|
||||
const (
|
||||
// Console modes
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
|
||||
ENABLE_PROCESSED_INPUT = 0x0001
|
||||
ENABLE_LINE_INPUT = 0x0002
|
||||
ENABLE_ECHO_INPUT = 0x0004
|
||||
ENABLE_WINDOW_INPUT = 0x0008
|
||||
ENABLE_MOUSE_INPUT = 0x0010
|
||||
ENABLE_INSERT_MODE = 0x0020
|
||||
ENABLE_QUICK_EDIT_MODE = 0x0040
|
||||
ENABLE_EXTENDED_FLAGS = 0x0080
|
||||
|
||||
ENABLE_PROCESSED_OUTPUT = 0x0001
|
||||
ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
|
||||
|
||||
// Character attributes
|
||||
// Note:
|
||||
// -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan).
|
||||
// Clearing all foreground or background colors results in black; setting all creates white.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes.
|
||||
FOREGROUND_BLUE uint16 = 0x0001
|
||||
FOREGROUND_GREEN uint16 = 0x0002
|
||||
FOREGROUND_RED uint16 = 0x0004
|
||||
FOREGROUND_INTENSITY uint16 = 0x0008
|
||||
FOREGROUND_MASK uint16 = 0x000F
|
||||
|
||||
BACKGROUND_BLUE uint16 = 0x0010
|
||||
BACKGROUND_GREEN uint16 = 0x0020
|
||||
BACKGROUND_RED uint16 = 0x0040
|
||||
BACKGROUND_INTENSITY uint16 = 0x0080
|
||||
BACKGROUND_MASK uint16 = 0x00F0
|
||||
|
||||
COMMON_LVB_MASK uint16 = 0xFF00
|
||||
COMMON_LVB_REVERSE_VIDEO uint16 = 0x4000
|
||||
COMMON_LVB_UNDERSCORE uint16 = 0x8000
|
||||
|
||||
// Input event types
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
|
||||
KEY_EVENT = 0x0001
|
||||
MOUSE_EVENT = 0x0002
|
||||
WINDOW_BUFFER_SIZE_EVENT = 0x0004
|
||||
MENU_EVENT = 0x0008
|
||||
FOCUS_EVENT = 0x0010
|
||||
|
||||
// WaitForSingleObject return codes
|
||||
WAIT_ABANDONED = 0x00000080
|
||||
WAIT_FAILED = 0xFFFFFFFF
|
||||
WAIT_SIGNALED = 0x0000000
|
||||
WAIT_TIMEOUT = 0x00000102
|
||||
|
||||
// WaitForSingleObject wait duration
|
||||
WAIT_INFINITE = 0xFFFFFFFF
|
||||
WAIT_ONE_SECOND = 1000
|
||||
WAIT_HALF_SECOND = 500
|
||||
WAIT_QUARTER_SECOND = 250
|
||||
)
|
||||
|
||||
// Windows API Console types
|
||||
// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682101(v=vs.85).aspx for Console specific types (e.g., COORD)
|
||||
// -- See https://msdn.microsoft.com/en-us/library/aa296569(v=vs.60).aspx for comments on alignment
|
||||
type (
|
||||
CHAR_INFO struct {
|
||||
UnicodeChar uint16
|
||||
Attributes uint16
|
||||
}
|
||||
|
||||
CONSOLE_CURSOR_INFO struct {
|
||||
Size uint32
|
||||
Visible int32
|
||||
}
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO struct {
|
||||
Size COORD
|
||||
CursorPosition COORD
|
||||
Attributes uint16
|
||||
Window SMALL_RECT
|
||||
MaximumWindowSize COORD
|
||||
}
|
||||
|
||||
COORD struct {
|
||||
X int16
|
||||
Y int16
|
||||
}
|
||||
|
||||
SMALL_RECT struct {
|
||||
Left int16
|
||||
Top int16
|
||||
Right int16
|
||||
Bottom int16
|
||||
}
|
||||
|
||||
// INPUT_RECORD is a C/C++ union of which KEY_EVENT_RECORD is one case, it is also the largest
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
|
||||
INPUT_RECORD struct {
|
||||
EventType uint16
|
||||
KeyEvent KEY_EVENT_RECORD
|
||||
}
|
||||
|
||||
KEY_EVENT_RECORD struct {
|
||||
KeyDown int32
|
||||
RepeatCount uint16
|
||||
VirtualKeyCode uint16
|
||||
VirtualScanCode uint16
|
||||
UnicodeChar uint16
|
||||
ControlKeyState uint32
|
||||
}
|
||||
|
||||
WINDOW_BUFFER_SIZE struct {
|
||||
Size COORD
|
||||
}
|
||||
)
|
||||
|
||||
// boolToBOOL converts a Go bool into a Windows int32.
|
||||
func boolToBOOL(f bool) int32 {
|
||||
if f {
|
||||
return int32(1)
|
||||
} else {
|
||||
return int32(0)
|
||||
}
|
||||
}
|
||||
|
||||
// GetConsoleCursorInfo retrieves information about the size and visiblity of the console cursor.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683163(v=vs.85).aspx.
|
||||
func GetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
|
||||
r1, r2, err := getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// SetConsoleCursorInfo sets the size and visiblity of the console cursor.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686019(v=vs.85).aspx.
|
||||
func SetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
|
||||
r1, r2, err := setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// SetConsoleCursorPosition location of the console cursor.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx.
|
||||
func SetConsoleCursorPosition(handle uintptr, coord COORD) error {
|
||||
r1, r2, err := setConsoleCursorPositionProc.Call(handle, coordToPointer(coord))
|
||||
use(coord)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// GetConsoleMode gets the console mode for given file descriptor
|
||||
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx.
|
||||
func GetConsoleMode(handle uintptr) (mode uint32, err error) {
|
||||
err = syscall.GetConsoleMode(syscall.Handle(handle), &mode)
|
||||
return mode, err
|
||||
}
|
||||
|
||||
// SetConsoleMode sets the console mode for given file descriptor
|
||||
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
|
||||
func SetConsoleMode(handle uintptr, mode uint32) error {
|
||||
r1, r2, err := setConsoleModeProc.Call(handle, uintptr(mode), 0)
|
||||
use(mode)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer.
|
||||
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx.
|
||||
func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) {
|
||||
info := CONSOLE_SCREEN_BUFFER_INFO{}
|
||||
err := checkError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
func ScrollConsoleScreenBuffer(handle uintptr, scrollRect SMALL_RECT, clipRect SMALL_RECT, destOrigin COORD, char CHAR_INFO) error {
|
||||
r1, r2, err := scrollConsoleScreenBufferProc.Call(handle, uintptr(unsafe.Pointer(&scrollRect)), uintptr(unsafe.Pointer(&clipRect)), coordToPointer(destOrigin), uintptr(unsafe.Pointer(&char)))
|
||||
use(scrollRect)
|
||||
use(clipRect)
|
||||
use(destOrigin)
|
||||
use(char)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// SetConsoleScreenBufferSize sets the size of the console screen buffer.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686044(v=vs.85).aspx.
|
||||
func SetConsoleScreenBufferSize(handle uintptr, coord COORD) error {
|
||||
r1, r2, err := setConsoleScreenBufferSizeProc.Call(handle, coordToPointer(coord))
|
||||
use(coord)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// SetConsoleTextAttribute sets the attributes of characters written to the
|
||||
// console screen buffer by the WriteFile or WriteConsole function.
|
||||
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx.
|
||||
func SetConsoleTextAttribute(handle uintptr, attribute uint16) error {
|
||||
r1, r2, err := setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0)
|
||||
use(attribute)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// SetConsoleWindowInfo sets the size and position of the console screen buffer's window.
|
||||
// Note that the size and location must be within and no larger than the backing console screen buffer.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686125(v=vs.85).aspx.
|
||||
func SetConsoleWindowInfo(handle uintptr, isAbsolute bool, rect SMALL_RECT) error {
|
||||
r1, r2, err := setConsoleWindowInfoProc.Call(handle, uintptr(boolToBOOL(isAbsolute)), uintptr(unsafe.Pointer(&rect)))
|
||||
use(isAbsolute)
|
||||
use(rect)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// WriteConsoleOutput writes the CHAR_INFOs from the provided buffer to the active console buffer.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687404(v=vs.85).aspx.
|
||||
func WriteConsoleOutput(handle uintptr, buffer []CHAR_INFO, bufferSize COORD, bufferCoord COORD, writeRegion *SMALL_RECT) error {
|
||||
r1, r2, err := writeConsoleOutputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), coordToPointer(bufferSize), coordToPointer(bufferCoord), uintptr(unsafe.Pointer(writeRegion)))
|
||||
use(buffer)
|
||||
use(bufferSize)
|
||||
use(bufferCoord)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// ReadConsoleInput reads (and removes) data from the console input buffer.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx.
|
||||
func ReadConsoleInput(handle uintptr, buffer []INPUT_RECORD, count *uint32) error {
|
||||
r1, r2, err := readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), uintptr(len(buffer)), uintptr(unsafe.Pointer(count)))
|
||||
use(buffer)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// WaitForSingleObject waits for the passed handle to be signaled.
|
||||
// It returns true if the handle was signaled; false otherwise.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx.
|
||||
func WaitForSingleObject(handle uintptr, msWait uint32) (bool, error) {
|
||||
r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(uint32(msWait)))
|
||||
switch r1 {
|
||||
case WAIT_ABANDONED, WAIT_TIMEOUT:
|
||||
return false, nil
|
||||
case WAIT_SIGNALED:
|
||||
return true, nil
|
||||
}
|
||||
use(msWait)
|
||||
return false, err
|
||||
}
|
||||
|
||||
// String helpers
|
||||
func (info CONSOLE_SCREEN_BUFFER_INFO) String() string {
|
||||
return fmt.Sprintf("Size(%v) Cursor(%v) Window(%v) Max(%v)", info.Size, info.CursorPosition, info.Window, info.MaximumWindowSize)
|
||||
}
|
||||
|
||||
func (coord COORD) String() string {
|
||||
return fmt.Sprintf("%v,%v", coord.X, coord.Y)
|
||||
}
|
||||
|
||||
func (rect SMALL_RECT) String() string {
|
||||
return fmt.Sprintf("(%v,%v),(%v,%v)", rect.Left, rect.Top, rect.Right, rect.Bottom)
|
||||
}
|
||||
|
||||
// checkError evaluates the results of a Windows API call and returns the error if it failed.
|
||||
func checkError(r1, r2 uintptr, err error) error {
|
||||
// Windows APIs return non-zero to indicate success
|
||||
if r1 != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Return the error if provided, otherwise default to EINVAL
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return syscall.EINVAL
|
||||
}
|
||||
|
||||
// coordToPointer converts a COORD into a uintptr (by fooling the type system).
|
||||
func coordToPointer(c COORD) uintptr {
|
||||
// Note: This code assumes the two SHORTs are correctly laid out; the "cast" to uint32 is just to get a pointer to pass.
|
||||
return uintptr(*((*uint32)(unsafe.Pointer(&c))))
|
||||
}
|
||||
|
||||
// use is a no-op, but the compiler cannot see that it is.
|
||||
// Calling use(p) ensures that p is kept live until that point.
|
||||
func use(p interface{}) {}
|
||||
100
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go
generated
vendored
Normal file
100
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go
generated
vendored
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
import "github.com/Azure/go-ansiterm"
|
||||
|
||||
const (
|
||||
FOREGROUND_COLOR_MASK = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
|
||||
BACKGROUND_COLOR_MASK = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
|
||||
)
|
||||
|
||||
// collectAnsiIntoWindowsAttributes modifies the passed Windows text mode flags to reflect the
|
||||
// request represented by the passed ANSI mode.
|
||||
func collectAnsiIntoWindowsAttributes(windowsMode uint16, inverted bool, baseMode uint16, ansiMode int16) (uint16, bool) {
|
||||
switch ansiMode {
|
||||
|
||||
// Mode styles
|
||||
case ansiterm.ANSI_SGR_BOLD:
|
||||
windowsMode = windowsMode | FOREGROUND_INTENSITY
|
||||
|
||||
case ansiterm.ANSI_SGR_DIM, ansiterm.ANSI_SGR_BOLD_DIM_OFF:
|
||||
windowsMode &^= FOREGROUND_INTENSITY
|
||||
|
||||
case ansiterm.ANSI_SGR_UNDERLINE:
|
||||
windowsMode = windowsMode | COMMON_LVB_UNDERSCORE
|
||||
|
||||
case ansiterm.ANSI_SGR_REVERSE:
|
||||
inverted = true
|
||||
|
||||
case ansiterm.ANSI_SGR_REVERSE_OFF:
|
||||
inverted = false
|
||||
|
||||
case ansiterm.ANSI_SGR_UNDERLINE_OFF:
|
||||
windowsMode &^= COMMON_LVB_UNDERSCORE
|
||||
|
||||
// Foreground colors
|
||||
case ansiterm.ANSI_SGR_FOREGROUND_DEFAULT:
|
||||
windowsMode = (windowsMode &^ FOREGROUND_MASK) | (baseMode & FOREGROUND_MASK)
|
||||
|
||||
case ansiterm.ANSI_SGR_FOREGROUND_BLACK:
|
||||
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK)
|
||||
|
||||
case ansiterm.ANSI_SGR_FOREGROUND_RED:
|
||||
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED
|
||||
|
||||
case ansiterm.ANSI_SGR_FOREGROUND_GREEN:
|
||||
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN
|
||||
|
||||
case ansiterm.ANSI_SGR_FOREGROUND_YELLOW:
|
||||
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN
|
||||
|
||||
case ansiterm.ANSI_SGR_FOREGROUND_BLUE:
|
||||
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_BLUE
|
||||
|
||||
case ansiterm.ANSI_SGR_FOREGROUND_MAGENTA:
|
||||
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_BLUE
|
||||
|
||||
case ansiterm.ANSI_SGR_FOREGROUND_CYAN:
|
||||
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE
|
||||
|
||||
case ansiterm.ANSI_SGR_FOREGROUND_WHITE:
|
||||
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
|
||||
|
||||
// Background colors
|
||||
case ansiterm.ANSI_SGR_BACKGROUND_DEFAULT:
|
||||
// Black with no intensity
|
||||
windowsMode = (windowsMode &^ BACKGROUND_MASK) | (baseMode & BACKGROUND_MASK)
|
||||
|
||||
case ansiterm.ANSI_SGR_BACKGROUND_BLACK:
|
||||
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK)
|
||||
|
||||
case ansiterm.ANSI_SGR_BACKGROUND_RED:
|
||||
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED
|
||||
|
||||
case ansiterm.ANSI_SGR_BACKGROUND_GREEN:
|
||||
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN
|
||||
|
||||
case ansiterm.ANSI_SGR_BACKGROUND_YELLOW:
|
||||
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN
|
||||
|
||||
case ansiterm.ANSI_SGR_BACKGROUND_BLUE:
|
||||
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_BLUE
|
||||
|
||||
case ansiterm.ANSI_SGR_BACKGROUND_MAGENTA:
|
||||
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_BLUE
|
||||
|
||||
case ansiterm.ANSI_SGR_BACKGROUND_CYAN:
|
||||
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE
|
||||
|
||||
case ansiterm.ANSI_SGR_BACKGROUND_WHITE:
|
||||
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
|
||||
}
|
||||
|
||||
return windowsMode, inverted
|
||||
}
|
||||
|
||||
// invertAttributes inverts the foreground and background colors of a Windows attributes value
|
||||
func invertAttributes(windowsMode uint16) uint16 {
|
||||
return (COMMON_LVB_MASK & windowsMode) | ((FOREGROUND_MASK & windowsMode) << 4) | ((BACKGROUND_MASK & windowsMode) >> 4)
|
||||
}
|
||||
101
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go
generated
vendored
Normal file
101
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go
generated
vendored
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
const (
|
||||
horizontal = iota
|
||||
vertical
|
||||
)
|
||||
|
||||
func (h *windowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_INFO) SMALL_RECT {
|
||||
if h.originMode {
|
||||
sr := h.effectiveSr(info.Window)
|
||||
return SMALL_RECT{
|
||||
Top: sr.top,
|
||||
Bottom: sr.bottom,
|
||||
Left: 0,
|
||||
Right: info.Size.X - 1,
|
||||
}
|
||||
} else {
|
||||
return SMALL_RECT{
|
||||
Top: info.Window.Top,
|
||||
Bottom: info.Window.Bottom,
|
||||
Left: 0,
|
||||
Right: info.Size.X - 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setCursorPosition sets the cursor to the specified position, bounded to the screen size
|
||||
func (h *windowsAnsiEventHandler) setCursorPosition(position COORD, window SMALL_RECT) error {
|
||||
position.X = ensureInRange(position.X, window.Left, window.Right)
|
||||
position.Y = ensureInRange(position.Y, window.Top, window.Bottom)
|
||||
err := SetConsoleCursorPosition(h.fd, position)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("Cursor position set: (%d, %d)", position.X, position.Y)
|
||||
return err
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) moveCursorVertical(param int) error {
|
||||
return h.moveCursor(vertical, param)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) moveCursorHorizontal(param int) error {
|
||||
return h.moveCursor(horizontal, param)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) moveCursor(moveMode int, param int) error {
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
position := info.CursorPosition
|
||||
switch moveMode {
|
||||
case horizontal:
|
||||
position.X += int16(param)
|
||||
case vertical:
|
||||
position.Y += int16(param)
|
||||
}
|
||||
|
||||
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) moveCursorLine(param int) error {
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
position := info.CursorPosition
|
||||
position.X = 0
|
||||
position.Y += int16(param)
|
||||
|
||||
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) moveCursorColumn(param int) error {
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
position := info.CursorPosition
|
||||
position.X = int16(param) - 1
|
||||
|
||||
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
84
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go
generated
vendored
Normal file
84
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go
generated
vendored
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
import "github.com/Azure/go-ansiterm"
|
||||
|
||||
func (h *windowsAnsiEventHandler) clearRange(attributes uint16, fromCoord COORD, toCoord COORD) error {
|
||||
// Ignore an invalid (negative area) request
|
||||
if toCoord.Y < fromCoord.Y {
|
||||
return nil
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
var coordStart = COORD{}
|
||||
var coordEnd = COORD{}
|
||||
|
||||
xCurrent, yCurrent := fromCoord.X, fromCoord.Y
|
||||
xEnd, yEnd := toCoord.X, toCoord.Y
|
||||
|
||||
// Clear any partial initial line
|
||||
if xCurrent > 0 {
|
||||
coordStart.X, coordStart.Y = xCurrent, yCurrent
|
||||
coordEnd.X, coordEnd.Y = xEnd, yCurrent
|
||||
|
||||
err = h.clearRect(attributes, coordStart, coordEnd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
xCurrent = 0
|
||||
yCurrent += 1
|
||||
}
|
||||
|
||||
// Clear intervening rectangular section
|
||||
if yCurrent < yEnd {
|
||||
coordStart.X, coordStart.Y = xCurrent, yCurrent
|
||||
coordEnd.X, coordEnd.Y = xEnd, yEnd-1
|
||||
|
||||
err = h.clearRect(attributes, coordStart, coordEnd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
xCurrent = 0
|
||||
yCurrent = yEnd
|
||||
}
|
||||
|
||||
// Clear remaining partial ending line
|
||||
coordStart.X, coordStart.Y = xCurrent, yCurrent
|
||||
coordEnd.X, coordEnd.Y = xEnd, yEnd
|
||||
|
||||
err = h.clearRect(attributes, coordStart, coordEnd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) clearRect(attributes uint16, fromCoord COORD, toCoord COORD) error {
|
||||
region := SMALL_RECT{Top: fromCoord.Y, Left: fromCoord.X, Bottom: toCoord.Y, Right: toCoord.X}
|
||||
width := toCoord.X - fromCoord.X + 1
|
||||
height := toCoord.Y - fromCoord.Y + 1
|
||||
size := uint32(width) * uint32(height)
|
||||
|
||||
if size <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
buffer := make([]CHAR_INFO, size)
|
||||
|
||||
char := CHAR_INFO{ansiterm.FILL_CHARACTER, attributes}
|
||||
for i := 0; i < int(size); i++ {
|
||||
buffer[i] = char
|
||||
}
|
||||
|
||||
err := WriteConsoleOutput(h.fd, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, ®ion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
118
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go
generated
vendored
Normal file
118
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go
generated
vendored
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
// effectiveSr gets the current effective scroll region in buffer coordinates
|
||||
func (h *windowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion {
|
||||
top := addInRange(window.Top, h.sr.top, window.Top, window.Bottom)
|
||||
bottom := addInRange(window.Top, h.sr.bottom, window.Top, window.Bottom)
|
||||
if top >= bottom {
|
||||
top = window.Top
|
||||
bottom = window.Bottom
|
||||
}
|
||||
return scrollRegion{top: top, bottom: bottom}
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) scrollUp(param int) error {
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sr := h.effectiveSr(info.Window)
|
||||
return h.scroll(param, sr, info)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) scrollDown(param int) error {
|
||||
return h.scrollUp(-param)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) deleteLines(param int) error {
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
start := info.CursorPosition.Y
|
||||
sr := h.effectiveSr(info.Window)
|
||||
// Lines cannot be inserted or deleted outside the scrolling region.
|
||||
if start >= sr.top && start <= sr.bottom {
|
||||
sr.top = start
|
||||
return h.scroll(param, sr, info)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) insertLines(param int) error {
|
||||
return h.deleteLines(-param)
|
||||
}
|
||||
|
||||
// scroll scrolls the provided scroll region by param lines. The scroll region is in buffer coordinates.
|
||||
func (h *windowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSOLE_SCREEN_BUFFER_INFO) error {
|
||||
logger.Infof("scroll: scrollTop: %d, scrollBottom: %d", sr.top, sr.bottom)
|
||||
logger.Infof("scroll: windowTop: %d, windowBottom: %d", info.Window.Top, info.Window.Bottom)
|
||||
|
||||
// Copy from and clip to the scroll region (full buffer width)
|
||||
scrollRect := SMALL_RECT{
|
||||
Top: sr.top,
|
||||
Bottom: sr.bottom,
|
||||
Left: 0,
|
||||
Right: info.Size.X - 1,
|
||||
}
|
||||
|
||||
// Origin to which area should be copied
|
||||
destOrigin := COORD{
|
||||
X: 0,
|
||||
Y: sr.top - int16(param),
|
||||
}
|
||||
|
||||
char := CHAR_INFO{
|
||||
UnicodeChar: ' ',
|
||||
Attributes: h.attributes,
|
||||
}
|
||||
|
||||
if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) deleteCharacters(param int) error {
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return h.scrollLine(param, info.CursorPosition, info)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) insertCharacters(param int) error {
|
||||
return h.deleteCharacters(-param)
|
||||
}
|
||||
|
||||
// scrollLine scrolls a line horizontally starting at the provided position by a number of columns.
|
||||
func (h *windowsAnsiEventHandler) scrollLine(columns int, position COORD, info *CONSOLE_SCREEN_BUFFER_INFO) error {
|
||||
// Copy from and clip to the scroll region (full buffer width)
|
||||
scrollRect := SMALL_RECT{
|
||||
Top: position.Y,
|
||||
Bottom: position.Y,
|
||||
Left: position.X,
|
||||
Right: info.Size.X - 1,
|
||||
}
|
||||
|
||||
// Origin to which area should be copied
|
||||
destOrigin := COORD{
|
||||
X: position.X - int16(columns),
|
||||
Y: position.Y,
|
||||
}
|
||||
|
||||
char := CHAR_INFO{
|
||||
UnicodeChar: ' ',
|
||||
Attributes: h.attributes,
|
||||
}
|
||||
|
||||
if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
9
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go
generated
vendored
Normal file
9
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go
generated
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
// AddInRange increments a value by the passed quantity while ensuring the values
|
||||
// always remain within the supplied min / max range.
|
||||
func addInRange(n int16, increment int16, min int16, max int16) int16 {
|
||||
return ensureInRange(n+increment, min, max)
|
||||
}
|
||||
726
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go
generated
vendored
Normal file
726
integration/vendor/github.com/docker/libcompose/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go
generated
vendored
Normal file
|
|
@ -0,0 +1,726 @@
|
|||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/Azure/go-ansiterm"
|
||||
"github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
var logger *logrus.Logger
|
||||
|
||||
type windowsAnsiEventHandler struct {
|
||||
fd uintptr
|
||||
file *os.File
|
||||
infoReset *CONSOLE_SCREEN_BUFFER_INFO
|
||||
sr scrollRegion
|
||||
buffer bytes.Buffer
|
||||
attributes uint16
|
||||
inverted bool
|
||||
wrapNext bool
|
||||
drewMarginByte bool
|
||||
originMode bool
|
||||
marginByte byte
|
||||
curInfo *CONSOLE_SCREEN_BUFFER_INFO
|
||||
curPos COORD
|
||||
}
|
||||
|
||||
func CreateWinEventHandler(fd uintptr, file *os.File) ansiterm.AnsiEventHandler {
|
||||
logFile := ioutil.Discard
|
||||
|
||||
if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" {
|
||||
logFile, _ = os.Create("winEventHandler.log")
|
||||
}
|
||||
|
||||
logger = &logrus.Logger{
|
||||
Out: logFile,
|
||||
Formatter: new(logrus.TextFormatter),
|
||||
Level: logrus.DebugLevel,
|
||||
}
|
||||
|
||||
infoReset, err := GetConsoleScreenBufferInfo(fd)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &windowsAnsiEventHandler{
|
||||
fd: fd,
|
||||
file: file,
|
||||
infoReset: infoReset,
|
||||
attributes: infoReset.Attributes,
|
||||
}
|
||||
}
|
||||
|
||||
type scrollRegion struct {
|
||||
top int16
|
||||
bottom int16
|
||||
}
|
||||
|
||||
// simulateLF simulates a LF or CR+LF by scrolling if necessary to handle the
|
||||
// current cursor position and scroll region settings, in which case it returns
|
||||
// true. If no special handling is necessary, then it does nothing and returns
|
||||
// false.
|
||||
//
|
||||
// In the false case, the caller should ensure that a carriage return
|
||||
// and line feed are inserted or that the text is otherwise wrapped.
|
||||
func (h *windowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) {
|
||||
if h.wrapNext {
|
||||
if err := h.Flush(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
h.clearWrap()
|
||||
}
|
||||
pos, info, err := h.getCurrentInfo()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
sr := h.effectiveSr(info.Window)
|
||||
if pos.Y == sr.bottom {
|
||||
// Scrolling is necessary. Let Windows automatically scroll if the scrolling region
|
||||
// is the full window.
|
||||
if sr.top == info.Window.Top && sr.bottom == info.Window.Bottom {
|
||||
if includeCR {
|
||||
pos.X = 0
|
||||
h.updatePos(pos)
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// A custom scroll region is active. Scroll the window manually to simulate
|
||||
// the LF.
|
||||
if err := h.Flush(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
logger.Info("Simulating LF inside scroll region")
|
||||
if err := h.scrollUp(1); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if includeCR {
|
||||
pos.X = 0
|
||||
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
|
||||
} else if pos.Y < info.Window.Bottom {
|
||||
// Let Windows handle the LF.
|
||||
pos.Y++
|
||||
if includeCR {
|
||||
pos.X = 0
|
||||
}
|
||||
h.updatePos(pos)
|
||||
return false, nil
|
||||
} else {
|
||||
// The cursor is at the bottom of the screen but outside the scroll
|
||||
// region. Skip the LF.
|
||||
logger.Info("Simulating LF outside scroll region")
|
||||
if includeCR {
|
||||
if err := h.Flush(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
pos.X = 0
|
||||
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// executeLF executes a LF without a CR.
|
||||
func (h *windowsAnsiEventHandler) executeLF() error {
|
||||
handled, err := h.simulateLF(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !handled {
|
||||
// Windows LF will reset the cursor column position. Write the LF
|
||||
// and restore the cursor position.
|
||||
pos, _, err := h.getCurrentInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
|
||||
if pos.X != 0 {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Info("Resetting cursor position for LF without CR")
|
||||
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) Print(b byte) error {
|
||||
if h.wrapNext {
|
||||
h.buffer.WriteByte(h.marginByte)
|
||||
h.clearWrap()
|
||||
if _, err := h.simulateLF(true); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
pos, info, err := h.getCurrentInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pos.X == info.Size.X-1 {
|
||||
h.wrapNext = true
|
||||
h.marginByte = b
|
||||
} else {
|
||||
pos.X++
|
||||
h.updatePos(pos)
|
||||
h.buffer.WriteByte(b)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) Execute(b byte) error {
|
||||
switch b {
|
||||
case ansiterm.ANSI_TAB:
|
||||
logger.Info("Execute(TAB)")
|
||||
// Move to the next tab stop, but preserve auto-wrap if already set.
|
||||
if !h.wrapNext {
|
||||
pos, info, err := h.getCurrentInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pos.X = (pos.X + 8) - pos.X%8
|
||||
if pos.X >= info.Size.X {
|
||||
pos.X = info.Size.X - 1
|
||||
}
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
case ansiterm.ANSI_BEL:
|
||||
h.buffer.WriteByte(ansiterm.ANSI_BEL)
|
||||
return nil
|
||||
|
||||
case ansiterm.ANSI_BACKSPACE:
|
||||
if h.wrapNext {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
h.clearWrap()
|
||||
}
|
||||
pos, _, err := h.getCurrentInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pos.X > 0 {
|
||||
pos.X--
|
||||
h.updatePos(pos)
|
||||
h.buffer.WriteByte(ansiterm.ANSI_BACKSPACE)
|
||||
}
|
||||
return nil
|
||||
|
||||
case ansiterm.ANSI_VERTICAL_TAB, ansiterm.ANSI_FORM_FEED:
|
||||
// Treat as true LF.
|
||||
return h.executeLF()
|
||||
|
||||
case ansiterm.ANSI_LINE_FEED:
|
||||
// Simulate a CR and LF for now since there is no way in go-ansiterm
|
||||
// to tell if the LF should include CR (and more things break when it's
|
||||
// missing than when it's incorrectly added).
|
||||
handled, err := h.simulateLF(true)
|
||||
if handled || err != nil {
|
||||
return err
|
||||
}
|
||||
return h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
|
||||
|
||||
case ansiterm.ANSI_CARRIAGE_RETURN:
|
||||
if h.wrapNext {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
h.clearWrap()
|
||||
}
|
||||
pos, _, err := h.getCurrentInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pos.X != 0 {
|
||||
pos.X = 0
|
||||
h.updatePos(pos)
|
||||
h.buffer.WriteByte(ansiterm.ANSI_CARRIAGE_RETURN)
|
||||
}
|
||||
return nil
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) CUU(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("CUU: [%v]", []string{strconv.Itoa(param)})
|
||||
h.clearWrap()
|
||||
return h.moveCursorVertical(-param)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) CUD(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("CUD: [%v]", []string{strconv.Itoa(param)})
|
||||
h.clearWrap()
|
||||
return h.moveCursorVertical(param)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) CUF(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("CUF: [%v]", []string{strconv.Itoa(param)})
|
||||
h.clearWrap()
|
||||
return h.moveCursorHorizontal(param)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) CUB(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("CUB: [%v]", []string{strconv.Itoa(param)})
|
||||
h.clearWrap()
|
||||
return h.moveCursorHorizontal(-param)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) CNL(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("CNL: [%v]", []string{strconv.Itoa(param)})
|
||||
h.clearWrap()
|
||||
return h.moveCursorLine(param)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) CPL(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("CPL: [%v]", []string{strconv.Itoa(param)})
|
||||
h.clearWrap()
|
||||
return h.moveCursorLine(-param)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) CHA(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("CHA: [%v]", []string{strconv.Itoa(param)})
|
||||
h.clearWrap()
|
||||
return h.moveCursorColumn(param)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) VPA(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("VPA: [[%d]]", param)
|
||||
h.clearWrap()
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
window := h.getCursorWindow(info)
|
||||
position := info.CursorPosition
|
||||
position.Y = window.Top + int16(param) - 1
|
||||
return h.setCursorPosition(position, window)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) CUP(row int, col int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("CUP: [[%d %d]]", row, col)
|
||||
h.clearWrap()
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
window := h.getCursorWindow(info)
|
||||
position := COORD{window.Left + int16(col) - 1, window.Top + int16(row) - 1}
|
||||
return h.setCursorPosition(position, window)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) HVP(row int, col int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("HVP: [[%d %d]]", row, col)
|
||||
h.clearWrap()
|
||||
return h.CUP(row, col)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) DECTCEM(visible bool) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("DECTCEM: [%v]", []string{strconv.FormatBool(visible)})
|
||||
h.clearWrap()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) DECOM(enable bool) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("DECOM: [%v]", []string{strconv.FormatBool(enable)})
|
||||
h.clearWrap()
|
||||
h.originMode = enable
|
||||
return h.CUP(1, 1)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) DECCOLM(use132 bool) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("DECCOLM: [%v]", []string{strconv.FormatBool(use132)})
|
||||
h.clearWrap()
|
||||
if err := h.ED(2); err != nil {
|
||||
return err
|
||||
}
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
targetWidth := int16(80)
|
||||
if use132 {
|
||||
targetWidth = 132
|
||||
}
|
||||
if info.Size.X < targetWidth {
|
||||
if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
|
||||
logger.Info("set buffer failed:", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
window := info.Window
|
||||
window.Left = 0
|
||||
window.Right = targetWidth - 1
|
||||
if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
|
||||
logger.Info("set window failed:", err)
|
||||
return err
|
||||
}
|
||||
if info.Size.X > targetWidth {
|
||||
if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
|
||||
logger.Info("set buffer failed:", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return SetConsoleCursorPosition(h.fd, COORD{0, 0})
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) ED(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("ED: [%v]", []string{strconv.Itoa(param)})
|
||||
h.clearWrap()
|
||||
|
||||
// [J -- Erases from the cursor to the end of the screen, including the cursor position.
|
||||
// [1J -- Erases from the beginning of the screen to the cursor, including the cursor position.
|
||||
// [2J -- Erases the complete display. The cursor does not move.
|
||||
// Notes:
|
||||
// -- Clearing the entire buffer, versus just the Window, works best for Windows Consoles
|
||||
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var start COORD
|
||||
var end COORD
|
||||
|
||||
switch param {
|
||||
case 0:
|
||||
start = info.CursorPosition
|
||||
end = COORD{info.Size.X - 1, info.Size.Y - 1}
|
||||
|
||||
case 1:
|
||||
start = COORD{0, 0}
|
||||
end = info.CursorPosition
|
||||
|
||||
case 2:
|
||||
start = COORD{0, 0}
|
||||
end = COORD{info.Size.X - 1, info.Size.Y - 1}
|
||||
}
|
||||
|
||||
err = h.clearRange(h.attributes, start, end)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If the whole buffer was cleared, move the window to the top while preserving
|
||||
// the window-relative cursor position.
|
||||
if param == 2 {
|
||||
pos := info.CursorPosition
|
||||
window := info.Window
|
||||
pos.Y -= window.Top
|
||||
window.Bottom -= window.Top
|
||||
window.Top = 0
|
||||
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) EL(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("EL: [%v]", strconv.Itoa(param))
|
||||
h.clearWrap()
|
||||
|
||||
// [K -- Erases from the cursor to the end of the line, including the cursor position.
|
||||
// [1K -- Erases from the beginning of the line to the cursor, including the cursor position.
|
||||
// [2K -- Erases the complete line.
|
||||
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var start COORD
|
||||
var end COORD
|
||||
|
||||
switch param {
|
||||
case 0:
|
||||
start = info.CursorPosition
|
||||
end = COORD{info.Size.X, info.CursorPosition.Y}
|
||||
|
||||
case 1:
|
||||
start = COORD{0, info.CursorPosition.Y}
|
||||
end = info.CursorPosition
|
||||
|
||||
case 2:
|
||||
start = COORD{0, info.CursorPosition.Y}
|
||||
end = COORD{info.Size.X, info.CursorPosition.Y}
|
||||
}
|
||||
|
||||
err = h.clearRange(h.attributes, start, end)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) IL(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("IL: [%v]", strconv.Itoa(param))
|
||||
h.clearWrap()
|
||||
return h.insertLines(param)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) DL(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("DL: [%v]", strconv.Itoa(param))
|
||||
h.clearWrap()
|
||||
return h.deleteLines(param)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) ICH(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("ICH: [%v]", strconv.Itoa(param))
|
||||
h.clearWrap()
|
||||
return h.insertCharacters(param)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) DCH(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("DCH: [%v]", strconv.Itoa(param))
|
||||
h.clearWrap()
|
||||
return h.deleteCharacters(param)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) SGR(params []int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
strings := []string{}
|
||||
for _, v := range params {
|
||||
strings = append(strings, strconv.Itoa(v))
|
||||
}
|
||||
|
||||
logger.Infof("SGR: [%v]", strings)
|
||||
|
||||
if len(params) <= 0 {
|
||||
h.attributes = h.infoReset.Attributes
|
||||
h.inverted = false
|
||||
} else {
|
||||
for _, attr := range params {
|
||||
|
||||
if attr == ansiterm.ANSI_SGR_RESET {
|
||||
h.attributes = h.infoReset.Attributes
|
||||
h.inverted = false
|
||||
continue
|
||||
}
|
||||
|
||||
h.attributes, h.inverted = collectAnsiIntoWindowsAttributes(h.attributes, h.inverted, h.infoReset.Attributes, int16(attr))
|
||||
}
|
||||
}
|
||||
|
||||
attributes := h.attributes
|
||||
if h.inverted {
|
||||
attributes = invertAttributes(attributes)
|
||||
}
|
||||
err := SetConsoleTextAttribute(h.fd, attributes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) SU(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("SU: [%v]", []string{strconv.Itoa(param)})
|
||||
h.clearWrap()
|
||||
return h.scrollUp(param)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) SD(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("SD: [%v]", []string{strconv.Itoa(param)})
|
||||
h.clearWrap()
|
||||
return h.scrollDown(param)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) DA(params []string) error {
|
||||
logger.Infof("DA: [%v]", params)
|
||||
// DA cannot be implemented because it must send data on the VT100 input stream,
|
||||
// which is not available to go-ansiterm.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) DECSTBM(top int, bottom int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("DECSTBM: [%d, %d]", top, bottom)
|
||||
|
||||
// Windows is 0 indexed, Linux is 1 indexed
|
||||
h.sr.top = int16(top - 1)
|
||||
h.sr.bottom = int16(bottom - 1)
|
||||
|
||||
// This command also moves the cursor to the origin.
|
||||
h.clearWrap()
|
||||
return h.CUP(1, 1)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) RI() error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Info("RI: []")
|
||||
h.clearWrap()
|
||||
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sr := h.effectiveSr(info.Window)
|
||||
if info.CursorPosition.Y == sr.top {
|
||||
return h.scrollDown(1)
|
||||
}
|
||||
|
||||
return h.moveCursorVertical(-1)
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) IND() error {
|
||||
logger.Info("IND: []")
|
||||
return h.executeLF()
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) Flush() error {
|
||||
h.curInfo = nil
|
||||
if h.buffer.Len() > 0 {
|
||||
logger.Infof("Flush: [%s]", h.buffer.Bytes())
|
||||
if _, err := h.buffer.WriteTo(h.file); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if h.wrapNext && !h.drewMarginByte {
|
||||
logger.Infof("Flush: drawing margin byte '%c'", h.marginByte)
|
||||
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
charInfo := []CHAR_INFO{{UnicodeChar: uint16(h.marginByte), Attributes: info.Attributes}}
|
||||
size := COORD{1, 1}
|
||||
position := COORD{0, 0}
|
||||
region := SMALL_RECT{Left: info.CursorPosition.X, Top: info.CursorPosition.Y, Right: info.CursorPosition.X, Bottom: info.CursorPosition.Y}
|
||||
if err := WriteConsoleOutput(h.fd, charInfo, size, position, ®ion); err != nil {
|
||||
return err
|
||||
}
|
||||
h.drewMarginByte = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// cacheConsoleInfo ensures that the current console screen information has been queried
|
||||
// since the last call to Flush(). It must be called before accessing h.curInfo or h.curPos.
|
||||
func (h *windowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFER_INFO, error) {
|
||||
if h.curInfo == nil {
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return COORD{}, nil, err
|
||||
}
|
||||
h.curInfo = info
|
||||
h.curPos = info.CursorPosition
|
||||
}
|
||||
return h.curPos, h.curInfo, nil
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) updatePos(pos COORD) {
|
||||
if h.curInfo == nil {
|
||||
panic("failed to call getCurrentInfo before calling updatePos")
|
||||
}
|
||||
h.curPos = pos
|
||||
}
|
||||
|
||||
// clearWrap clears the state where the cursor is in the margin
|
||||
// waiting for the next character before wrapping the line. This must
|
||||
// be done before most operations that act on the cursor.
|
||||
func (h *windowsAnsiEventHandler) clearWrap() {
|
||||
h.wrapNext = false
|
||||
h.drewMarginByte = false
|
||||
}
|
||||
22
integration/vendor/github.com/docker/libcompose/vendor/github.com/Microsoft/go-winio/LICENSE
generated
vendored
Normal file
22
integration/vendor/github.com/docker/libcompose/vendor/github.com/Microsoft/go-winio/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Microsoft
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
266
integration/vendor/github.com/docker/libcompose/vendor/github.com/Microsoft/go-winio/backup.go
generated
vendored
Normal file
266
integration/vendor/github.com/docker/libcompose/vendor/github.com/Microsoft/go-winio/backup.go
generated
vendored
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
package winio
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unicode/utf16"
|
||||
)
|
||||
|
||||
//sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
|
||||
//sys backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite
|
||||
|
||||
const (
|
||||
BackupData = uint32(iota + 1)
|
||||
BackupEaData
|
||||
BackupSecurity
|
||||
BackupAlternateData
|
||||
BackupLink
|
||||
BackupPropertyData
|
||||
BackupObjectId
|
||||
BackupReparseData
|
||||
BackupSparseBlock
|
||||
BackupTxfsData
|
||||
)
|
||||
|
||||
const (
|
||||
StreamSparseAttributes = uint32(8)
|
||||
)
|
||||
|
||||
const (
|
||||
WRITE_DAC = 0x40000
|
||||
WRITE_OWNER = 0x80000
|
||||
ACCESS_SYSTEM_SECURITY = 0x1000000
|
||||
)
|
||||
|
||||
// BackupHeader represents a backup stream of a file.
|
||||
type BackupHeader struct {
|
||||
Id uint32 // The backup stream ID
|
||||
Attributes uint32 // Stream attributes
|
||||
Size int64 // The size of the stream in bytes
|
||||
Name string // The name of the stream (for BackupAlternateData only).
|
||||
Offset int64 // The offset of the stream in the file (for BackupSparseBlock only).
|
||||
}
|
||||
|
||||
type win32StreamId struct {
|
||||
StreamId uint32
|
||||
Attributes uint32
|
||||
Size uint64
|
||||
NameSize uint32
|
||||
}
|
||||
|
||||
// BackupStreamReader reads from a stream produced by the BackupRead Win32 API and produces a series
|
||||
// of BackupHeader values.
|
||||
type BackupStreamReader struct {
|
||||
r io.Reader
|
||||
bytesLeft int64
|
||||
}
|
||||
|
||||
// NewBackupStreamReader produces a BackupStreamReader from any io.Reader.
|
||||
func NewBackupStreamReader(r io.Reader) *BackupStreamReader {
|
||||
return &BackupStreamReader{r, 0}
|
||||
}
|
||||
|
||||
// Next returns the next backup stream and prepares for calls to Write(). It skips the remainder of the current stream if
|
||||
// it was not completely read.
|
||||
func (r *BackupStreamReader) Next() (*BackupHeader, error) {
|
||||
if r.bytesLeft > 0 {
|
||||
if _, err := io.Copy(ioutil.Discard, r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var wsi win32StreamId
|
||||
if err := binary.Read(r.r, binary.LittleEndian, &wsi); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hdr := &BackupHeader{
|
||||
Id: wsi.StreamId,
|
||||
Attributes: wsi.Attributes,
|
||||
Size: int64(wsi.Size),
|
||||
}
|
||||
if wsi.NameSize != 0 {
|
||||
name := make([]uint16, int(wsi.NameSize/2))
|
||||
if err := binary.Read(r.r, binary.LittleEndian, name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hdr.Name = syscall.UTF16ToString(name)
|
||||
}
|
||||
if wsi.StreamId == BackupSparseBlock {
|
||||
if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hdr.Size -= 8
|
||||
}
|
||||
r.bytesLeft = hdr.Size
|
||||
return hdr, nil
|
||||
}
|
||||
|
||||
// Read reads from the current backup stream.
|
||||
func (r *BackupStreamReader) Read(b []byte) (int, error) {
|
||||
if r.bytesLeft == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
if int64(len(b)) > r.bytesLeft {
|
||||
b = b[:r.bytesLeft]
|
||||
}
|
||||
n, err := r.r.Read(b)
|
||||
r.bytesLeft -= int64(n)
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
} else if r.bytesLeft == 0 && err == nil {
|
||||
err = io.EOF
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
// BackupStreamWriter writes a stream compatible with the BackupWrite Win32 API.
|
||||
type BackupStreamWriter struct {
|
||||
w io.Writer
|
||||
bytesLeft int64
|
||||
}
|
||||
|
||||
// NewBackupStreamWriter produces a BackupStreamWriter on top of an io.Writer.
|
||||
func NewBackupStreamWriter(w io.Writer) *BackupStreamWriter {
|
||||
return &BackupStreamWriter{w, 0}
|
||||
}
|
||||
|
||||
// WriteHeader writes the next backup stream header and prepares for calls to Write().
|
||||
func (w *BackupStreamWriter) WriteHeader(hdr *BackupHeader) error {
|
||||
if w.bytesLeft != 0 {
|
||||
return fmt.Errorf("missing %d bytes", w.bytesLeft)
|
||||
}
|
||||
name := utf16.Encode([]rune(hdr.Name))
|
||||
wsi := win32StreamId{
|
||||
StreamId: hdr.Id,
|
||||
Attributes: hdr.Attributes,
|
||||
Size: uint64(hdr.Size),
|
||||
NameSize: uint32(len(name) * 2),
|
||||
}
|
||||
if hdr.Id == BackupSparseBlock {
|
||||
// Include space for the int64 block offset
|
||||
wsi.Size += 8
|
||||
}
|
||||
if err := binary.Write(w.w, binary.LittleEndian, &wsi); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(name) != 0 {
|
||||
if err := binary.Write(w.w, binary.LittleEndian, name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if hdr.Id == BackupSparseBlock {
|
||||
if err := binary.Write(w.w, binary.LittleEndian, hdr.Offset); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
w.bytesLeft = hdr.Size
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write writes to the current backup stream.
|
||||
func (w *BackupStreamWriter) Write(b []byte) (int, error) {
|
||||
if w.bytesLeft < int64(len(b)) {
|
||||
return 0, fmt.Errorf("too many bytes by %d", int64(len(b))-w.bytesLeft)
|
||||
}
|
||||
n, err := w.w.Write(b)
|
||||
w.bytesLeft -= int64(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// BackupFileReader provides an io.ReadCloser interface on top of the BackupRead Win32 API.
|
||||
type BackupFileReader struct {
|
||||
f *os.File
|
||||
includeSecurity bool
|
||||
ctx uintptr
|
||||
}
|
||||
|
||||
// NewBackupFileReader returns a new BackupFileReader from a file handle. If includeSecurity is true,
|
||||
// Read will attempt to read the security descriptor of the file.
|
||||
func NewBackupFileReader(f *os.File, includeSecurity bool) *BackupFileReader {
|
||||
r := &BackupFileReader{f, includeSecurity, 0}
|
||||
runtime.SetFinalizer(r, func(r *BackupFileReader) { r.Close() })
|
||||
return r
|
||||
}
|
||||
|
||||
// Read reads a backup stream from the file by calling the Win32 API BackupRead().
|
||||
func (r *BackupFileReader) Read(b []byte) (int, error) {
|
||||
var bytesRead uint32
|
||||
err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
|
||||
if err != nil {
|
||||
return 0, &os.PathError{"BackupRead", r.f.Name(), err}
|
||||
}
|
||||
if bytesRead == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
return int(bytesRead), nil
|
||||
}
|
||||
|
||||
// Close frees Win32 resources associated with the BackupFileReader. It does not close
|
||||
// the underlying file.
|
||||
func (r *BackupFileReader) Close() error {
|
||||
if r.ctx != 0 {
|
||||
backupRead(syscall.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx)
|
||||
r.ctx = 0
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BackupFileWriter provides an io.WriteCloser interface on top of the BackupWrite Win32 API.
|
||||
type BackupFileWriter struct {
|
||||
f *os.File
|
||||
includeSecurity bool
|
||||
ctx uintptr
|
||||
}
|
||||
|
||||
// NewBackupFileWrtier returns a new BackupFileWriter from a file handle. If includeSecurity is true,
|
||||
// Write() will attempt to restore the security descriptor from the stream.
|
||||
func NewBackupFileWriter(f *os.File, includeSecurity bool) *BackupFileWriter {
|
||||
w := &BackupFileWriter{f, includeSecurity, 0}
|
||||
runtime.SetFinalizer(w, func(w *BackupFileWriter) { w.Close() })
|
||||
return w
|
||||
}
|
||||
|
||||
// Write restores a portion of the file using the provided backup stream.
|
||||
func (w *BackupFileWriter) Write(b []byte) (int, error) {
|
||||
var bytesWritten uint32
|
||||
err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
|
||||
if err != nil {
|
||||
return 0, &os.PathError{"BackupWrite", w.f.Name(), err}
|
||||
}
|
||||
if int(bytesWritten) != len(b) {
|
||||
return int(bytesWritten), errors.New("not all bytes could be written")
|
||||
}
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
// Close frees Win32 resources associated with the BackupFileWriter. It does not
|
||||
// close the underlying file.
|
||||
func (w *BackupFileWriter) Close() error {
|
||||
if w.ctx != 0 {
|
||||
backupWrite(syscall.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx)
|
||||
w.ctx = 0
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// OpenForBackup opens a file or directory, potentially skipping access checks if the backup
|
||||
// or restore privileges have been acquired.
|
||||
//
|
||||
// If the file opened was a directory, it cannot be used with Readdir().
|
||||
func OpenForBackup(path string, access uint32, share uint32, createmode uint32) (*os.File, error) {
|
||||
winPath, err := syscall.UTF16FromString(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h, err := syscall.CreateFile(&winPath[0], access, share, nil, createmode, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
|
||||
if err != nil {
|
||||
err = &os.PathError{Op: "open", Path: path, Err: err}
|
||||
return nil, err
|
||||
}
|
||||
return os.NewFile(uintptr(h), path), nil
|
||||
}
|
||||
219
integration/vendor/github.com/docker/libcompose/vendor/github.com/Microsoft/go-winio/file.go
generated
vendored
Normal file
219
integration/vendor/github.com/docker/libcompose/vendor/github.com/Microsoft/go-winio/file.go
generated
vendored
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
package winio
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"runtime"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx
|
||||
//sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort
|
||||
//sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus
|
||||
//sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
|
||||
//sys timeBeginPeriod(period uint32) (n int32) = winmm.timeBeginPeriod
|
||||
|
||||
const (
|
||||
cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1
|
||||
cFILE_SKIP_SET_EVENT_ON_HANDLE = 2
|
||||
)
|
||||
|
||||
var (
|
||||
ErrFileClosed = errors.New("file has already been closed")
|
||||
ErrTimeout = &timeoutError{}
|
||||
)
|
||||
|
||||
type timeoutError struct{}
|
||||
|
||||
func (e *timeoutError) Error() string { return "i/o timeout" }
|
||||
func (e *timeoutError) Timeout() bool { return true }
|
||||
func (e *timeoutError) Temporary() bool { return true }
|
||||
|
||||
var ioInitOnce sync.Once
|
||||
var ioCompletionPort syscall.Handle
|
||||
|
||||
// ioResult contains the result of an asynchronous IO operation
|
||||
type ioResult struct {
|
||||
bytes uint32
|
||||
err error
|
||||
}
|
||||
|
||||
// ioOperation represents an outstanding asynchronous Win32 IO
|
||||
type ioOperation struct {
|
||||
o syscall.Overlapped
|
||||
ch chan ioResult
|
||||
}
|
||||
|
||||
func initIo() {
|
||||
h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ioCompletionPort = h
|
||||
go ioCompletionProcessor(h)
|
||||
}
|
||||
|
||||
// win32File implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall.
|
||||
// It takes ownership of this handle and will close it if it is garbage collected.
|
||||
type win32File struct {
|
||||
handle syscall.Handle
|
||||
wg sync.WaitGroup
|
||||
closing bool
|
||||
readDeadline time.Time
|
||||
writeDeadline time.Time
|
||||
}
|
||||
|
||||
// makeWin32File makes a new win32File from an existing file handle
|
||||
func makeWin32File(h syscall.Handle) (*win32File, error) {
|
||||
f := &win32File{handle: h}
|
||||
ioInitOnce.Do(initIo)
|
||||
_, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = setFileCompletionNotificationModes(h, cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS|cFILE_SKIP_SET_EVENT_ON_HANDLE)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
runtime.SetFinalizer(f, (*win32File).closeHandle)
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
|
||||
return makeWin32File(h)
|
||||
}
|
||||
|
||||
// closeHandle closes the resources associated with a Win32 handle
|
||||
func (f *win32File) closeHandle() {
|
||||
if !f.closing {
|
||||
// cancel all IO and wait for it to complete
|
||||
f.closing = true
|
||||
cancelIoEx(f.handle, nil)
|
||||
f.wg.Wait()
|
||||
// at this point, no new IO can start
|
||||
syscall.Close(f.handle)
|
||||
f.handle = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Close closes a win32File.
|
||||
func (f *win32File) Close() error {
|
||||
f.closeHandle()
|
||||
runtime.SetFinalizer(f, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
// prepareIo prepares for a new IO operation
|
||||
func (f *win32File) prepareIo() (*ioOperation, error) {
|
||||
f.wg.Add(1)
|
||||
if f.closing {
|
||||
return nil, ErrFileClosed
|
||||
}
|
||||
c := &ioOperation{}
|
||||
c.ch = make(chan ioResult)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// ioCompletionProcessor processes completed async IOs forever
|
||||
func ioCompletionProcessor(h syscall.Handle) {
|
||||
// Set the timer resolution to 1. This fixes a performance regression in golang 1.6.
|
||||
timeBeginPeriod(1)
|
||||
for {
|
||||
var bytes uint32
|
||||
var key uintptr
|
||||
var op *ioOperation
|
||||
err := getQueuedCompletionStatus(h, &bytes, &key, &op, syscall.INFINITE)
|
||||
if op == nil {
|
||||
panic(err)
|
||||
}
|
||||
op.ch <- ioResult{bytes, err}
|
||||
}
|
||||
}
|
||||
|
||||
// asyncIo processes the return value from ReadFile or WriteFile, blocking until
|
||||
// the operation has actually completed.
|
||||
func (f *win32File) asyncIo(c *ioOperation, deadline time.Time, bytes uint32, err error) (int, error) {
|
||||
if err != syscall.ERROR_IO_PENDING {
|
||||
f.wg.Done()
|
||||
return int(bytes), err
|
||||
} else {
|
||||
var r ioResult
|
||||
wait := true
|
||||
timedout := false
|
||||
if f.closing {
|
||||
cancelIoEx(f.handle, &c.o)
|
||||
} else if !deadline.IsZero() {
|
||||
now := time.Now()
|
||||
if !deadline.After(now) {
|
||||
timedout = true
|
||||
} else {
|
||||
timeout := time.After(deadline.Sub(now))
|
||||
select {
|
||||
case r = <-c.ch:
|
||||
wait = false
|
||||
case <-timeout:
|
||||
timedout = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if timedout {
|
||||
cancelIoEx(f.handle, &c.o)
|
||||
}
|
||||
if wait {
|
||||
r = <-c.ch
|
||||
}
|
||||
err = r.err
|
||||
if err == syscall.ERROR_OPERATION_ABORTED {
|
||||
if f.closing {
|
||||
err = ErrFileClosed
|
||||
} else if timedout {
|
||||
err = ErrTimeout
|
||||
}
|
||||
}
|
||||
f.wg.Done()
|
||||
return int(r.bytes), err
|
||||
}
|
||||
}
|
||||
|
||||
// Read reads from a file handle.
|
||||
func (f *win32File) Read(b []byte) (int, error) {
|
||||
c, err := f.prepareIo()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var bytes uint32
|
||||
err = syscall.ReadFile(f.handle, b, &bytes, &c.o)
|
||||
n, err := f.asyncIo(c, f.readDeadline, bytes, err)
|
||||
|
||||
// Handle EOF conditions.
|
||||
if err == nil && n == 0 && len(b) != 0 {
|
||||
return 0, io.EOF
|
||||
} else if err == syscall.ERROR_BROKEN_PIPE {
|
||||
return 0, io.EOF
|
||||
} else {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
|
||||
// Write writes to a file handle.
|
||||
func (f *win32File) Write(b []byte) (int, error) {
|
||||
c, err := f.prepareIo()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var bytes uint32
|
||||
err = syscall.WriteFile(f.handle, b, &bytes, &c.o)
|
||||
return f.asyncIo(c, f.writeDeadline, bytes, err)
|
||||
}
|
||||
|
||||
func (f *win32File) SetReadDeadline(t time.Time) error {
|
||||
f.readDeadline = t
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *win32File) SetWriteDeadline(t time.Time) error {
|
||||
f.writeDeadline = t
|
||||
return nil
|
||||
}
|
||||
54
integration/vendor/github.com/docker/libcompose/vendor/github.com/Microsoft/go-winio/fileinfo.go
generated
vendored
Normal file
54
integration/vendor/github.com/docker/libcompose/vendor/github.com/Microsoft/go-winio/fileinfo.go
generated
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
package winio
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//sys getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = GetFileInformationByHandleEx
|
||||
//sys setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = SetFileInformationByHandle
|
||||
|
||||
const (
|
||||
fileBasicInfo = 0
|
||||
fileIDInfo = 0x12
|
||||
)
|
||||
|
||||
// FileBasicInfo contains file access time and file attributes information.
|
||||
type FileBasicInfo struct {
|
||||
CreationTime, LastAccessTime, LastWriteTime, ChangeTime syscall.Filetime
|
||||
FileAttributes uintptr // includes padding
|
||||
}
|
||||
|
||||
// GetFileBasicInfo retrieves times and attributes for a file.
|
||||
func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
|
||||
bi := &FileBasicInfo{}
|
||||
if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
|
||||
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
|
||||
}
|
||||
return bi, nil
|
||||
}
|
||||
|
||||
// SetFileBasicInfo sets times and attributes for a file.
|
||||
func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error {
|
||||
if err := setFileInformationByHandle(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
|
||||
return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FileIDInfo contains the volume serial number and file ID for a file. This pair should be
|
||||
// unique on a system.
|
||||
type FileIDInfo struct {
|
||||
VolumeSerialNumber uint64
|
||||
FileID [16]byte
|
||||
}
|
||||
|
||||
// GetFileID retrieves the unique (volume, file ID) pair for a file.
|
||||
func GetFileID(f *os.File) (*FileIDInfo, error) {
|
||||
fileID := &FileIDInfo{}
|
||||
if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileIDInfo, (*byte)(unsafe.Pointer(fileID)), uint32(unsafe.Sizeof(*fileID))); err != nil {
|
||||
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
|
||||
}
|
||||
return fileID, nil
|
||||
}
|
||||
398
integration/vendor/github.com/docker/libcompose/vendor/github.com/Microsoft/go-winio/pipe.go
generated
vendored
Normal file
398
integration/vendor/github.com/docker/libcompose/vendor/github.com/Microsoft/go-winio/pipe.go
generated
vendored
Normal file
|
|
@ -0,0 +1,398 @@
|
|||
package winio
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
|
||||
//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *securityAttributes) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateNamedPipeW
|
||||
//sys createFile(name string, access uint32, mode uint32, sa *securityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateFileW
|
||||
//sys waitNamedPipe(name string, timeout uint32) (err error) = WaitNamedPipeW
|
||||
//sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
|
||||
//sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
|
||||
|
||||
type securityAttributes struct {
|
||||
Length uint32
|
||||
SecurityDescriptor *byte
|
||||
InheritHandle uint32
|
||||
}
|
||||
|
||||
const (
|
||||
cERROR_PIPE_BUSY = syscall.Errno(231)
|
||||
cERROR_PIPE_CONNECTED = syscall.Errno(535)
|
||||
cERROR_SEM_TIMEOUT = syscall.Errno(121)
|
||||
|
||||
cPIPE_ACCESS_DUPLEX = 0x3
|
||||
cFILE_FLAG_FIRST_PIPE_INSTANCE = 0x80000
|
||||
cSECURITY_SQOS_PRESENT = 0x100000
|
||||
cSECURITY_ANONYMOUS = 0
|
||||
|
||||
cPIPE_REJECT_REMOTE_CLIENTS = 0x8
|
||||
|
||||
cPIPE_UNLIMITED_INSTANCES = 255
|
||||
|
||||
cNMPWAIT_USE_DEFAULT_WAIT = 0
|
||||
cNMPWAIT_NOWAIT = 1
|
||||
|
||||
cPIPE_TYPE_MESSAGE = 4
|
||||
|
||||
cPIPE_READMODE_MESSAGE = 2
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed.
|
||||
// This error should match net.errClosing since docker takes a dependency on its text.
|
||||
ErrPipeListenerClosed = errors.New("use of closed network connection")
|
||||
|
||||
errPipeWriteClosed = errors.New("pipe has been closed for write")
|
||||
)
|
||||
|
||||
type win32Pipe struct {
|
||||
*win32File
|
||||
path string
|
||||
}
|
||||
|
||||
type win32MessageBytePipe struct {
|
||||
win32Pipe
|
||||
writeClosed bool
|
||||
readEOF bool
|
||||
}
|
||||
|
||||
type pipeAddress string
|
||||
|
||||
func (f *win32Pipe) LocalAddr() net.Addr {
|
||||
return pipeAddress(f.path)
|
||||
}
|
||||
|
||||
func (f *win32Pipe) RemoteAddr() net.Addr {
|
||||
return pipeAddress(f.path)
|
||||
}
|
||||
|
||||
func (f *win32Pipe) SetDeadline(t time.Time) error {
|
||||
f.SetReadDeadline(t)
|
||||
f.SetWriteDeadline(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CloseWrite closes the write side of a message pipe in byte mode.
|
||||
func (f *win32MessageBytePipe) CloseWrite() error {
|
||||
if f.writeClosed {
|
||||
return errPipeWriteClosed
|
||||
}
|
||||
_, err := f.win32File.Write(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.writeClosed = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write writes bytes to a message pipe in byte mode. Zero-byte writes are ignored, since
|
||||
// they are used to implement CloseWrite().
|
||||
func (f *win32MessageBytePipe) Write(b []byte) (int, error) {
|
||||
if f.writeClosed {
|
||||
return 0, errPipeWriteClosed
|
||||
}
|
||||
if len(b) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
return f.win32File.Write(b)
|
||||
}
|
||||
|
||||
// Read reads bytes from a message pipe in byte mode. A read of a zero-byte message on a message
|
||||
// mode pipe will return io.EOF, as will all subsequent reads.
|
||||
func (f *win32MessageBytePipe) Read(b []byte) (int, error) {
|
||||
if f.readEOF {
|
||||
return 0, io.EOF
|
||||
}
|
||||
n, err := f.win32File.Read(b)
|
||||
if err == io.EOF {
|
||||
// If this was the result of a zero-byte read, then
|
||||
// it is possible that the read was due to a zero-size
|
||||
// message. Since we are simulating CloseWrite with a
|
||||
// zero-byte message, ensure that all future Read() calls
|
||||
// also return EOF.
|
||||
f.readEOF = true
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (s pipeAddress) Network() string {
|
||||
return "pipe"
|
||||
}
|
||||
|
||||
func (s pipeAddress) String() string {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
// DialPipe connects to a named pipe by path, timing out if the connection
|
||||
// takes longer than the specified duration. If timeout is nil, then the timeout
|
||||
// is the default timeout established by the pipe server.
|
||||
func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
|
||||
var absTimeout time.Time
|
||||
if timeout != nil {
|
||||
absTimeout = time.Now().Add(*timeout)
|
||||
}
|
||||
var err error
|
||||
var h syscall.Handle
|
||||
for {
|
||||
h, err = createFile(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
|
||||
if err != cERROR_PIPE_BUSY {
|
||||
break
|
||||
}
|
||||
now := time.Now()
|
||||
var ms uint32
|
||||
if absTimeout.IsZero() {
|
||||
ms = cNMPWAIT_USE_DEFAULT_WAIT
|
||||
} else if now.After(absTimeout) {
|
||||
ms = cNMPWAIT_NOWAIT
|
||||
} else {
|
||||
ms = uint32(absTimeout.Sub(now).Nanoseconds() / 1000 / 1000)
|
||||
}
|
||||
err = waitNamedPipe(path, ms)
|
||||
if err != nil {
|
||||
if err == cERROR_SEM_TIMEOUT {
|
||||
return nil, ErrTimeout
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, &os.PathError{Op: "open", Path: path, Err: err}
|
||||
}
|
||||
|
||||
var flags uint32
|
||||
err = getNamedPipeInfo(h, &flags, nil, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var state uint32
|
||||
err = getNamedPipeHandleState(h, &state, nil, nil, nil, nil, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if state&cPIPE_READMODE_MESSAGE != 0 {
|
||||
return nil, &os.PathError{Op: "open", Path: path, Err: errors.New("message readmode pipes not supported")}
|
||||
}
|
||||
|
||||
f, err := makeWin32File(h)
|
||||
if err != nil {
|
||||
syscall.Close(h)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If the pipe is in message mode, return a message byte pipe, which
|
||||
// supports CloseWrite().
|
||||
if flags&cPIPE_TYPE_MESSAGE != 0 {
|
||||
return &win32MessageBytePipe{
|
||||
win32Pipe: win32Pipe{win32File: f, path: path},
|
||||
}, nil
|
||||
}
|
||||
return &win32Pipe{win32File: f, path: path}, nil
|
||||
}
|
||||
|
||||
type acceptResponse struct {
|
||||
f *win32File
|
||||
err error
|
||||
}
|
||||
|
||||
type win32PipeListener struct {
|
||||
firstHandle syscall.Handle
|
||||
path string
|
||||
securityDescriptor []byte
|
||||
config PipeConfig
|
||||
acceptCh chan (chan acceptResponse)
|
||||
closeCh chan int
|
||||
doneCh chan int
|
||||
}
|
||||
|
||||
func makeServerPipeHandle(path string, securityDescriptor []byte, c *PipeConfig, first bool) (syscall.Handle, error) {
|
||||
var flags uint32 = cPIPE_ACCESS_DUPLEX | syscall.FILE_FLAG_OVERLAPPED
|
||||
if first {
|
||||
flags |= cFILE_FLAG_FIRST_PIPE_INSTANCE
|
||||
}
|
||||
|
||||
var mode uint32 = cPIPE_REJECT_REMOTE_CLIENTS
|
||||
if c.MessageMode {
|
||||
mode |= cPIPE_TYPE_MESSAGE
|
||||
}
|
||||
|
||||
var sa securityAttributes
|
||||
sa.Length = uint32(unsafe.Sizeof(sa))
|
||||
if securityDescriptor != nil {
|
||||
sa.SecurityDescriptor = &securityDescriptor[0]
|
||||
}
|
||||
h, err := createNamedPipe(path, flags, mode, cPIPE_UNLIMITED_INSTANCES, uint32(c.OutputBufferSize), uint32(c.InputBufferSize), 0, &sa)
|
||||
if err != nil {
|
||||
return 0, &os.PathError{Op: "open", Path: path, Err: err}
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (l *win32PipeListener) makeServerPipe() (*win32File, error) {
|
||||
h, err := makeServerPipeHandle(l.path, l.securityDescriptor, &l.config, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, err := makeWin32File(h)
|
||||
if err != nil {
|
||||
syscall.Close(h)
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (l *win32PipeListener) listenerRoutine() {
|
||||
closed := false
|
||||
for !closed {
|
||||
select {
|
||||
case <-l.closeCh:
|
||||
closed = true
|
||||
case responseCh := <-l.acceptCh:
|
||||
p, err := l.makeServerPipe()
|
||||
if err == nil {
|
||||
// Wait for the client to connect.
|
||||
ch := make(chan error)
|
||||
go func() {
|
||||
ch <- connectPipe(p)
|
||||
}()
|
||||
select {
|
||||
case err = <-ch:
|
||||
if err != nil {
|
||||
p.Close()
|
||||
p = nil
|
||||
}
|
||||
case <-l.closeCh:
|
||||
// Abort the connect request by closing the handle.
|
||||
p.Close()
|
||||
p = nil
|
||||
err = <-ch
|
||||
if err == nil || err == ErrFileClosed {
|
||||
err = ErrPipeListenerClosed
|
||||
}
|
||||
closed = true
|
||||
}
|
||||
}
|
||||
responseCh <- acceptResponse{p, err}
|
||||
}
|
||||
}
|
||||
syscall.Close(l.firstHandle)
|
||||
l.firstHandle = 0
|
||||
// Notify Close() and Accept() callers that the handle has been closed.
|
||||
close(l.doneCh)
|
||||
}
|
||||
|
||||
// PipeConfig contain configuration for the pipe listener.
|
||||
type PipeConfig struct {
|
||||
// SecurityDescriptor contains a Windows security descriptor in SDDL format.
|
||||
SecurityDescriptor string
|
||||
|
||||
// MessageMode determines whether the pipe is in byte or message mode. In either
|
||||
// case the pipe is read in byte mode by default. The only practical difference in
|
||||
// this implementation is that CloseWrite() is only supported for message mode pipes;
|
||||
// CloseWrite() is implemented as a zero-byte write, but zero-byte writes are only
|
||||
// transferred to the reader (and returned as io.EOF in this implementation)
|
||||
// when the pipe is in message mode.
|
||||
MessageMode bool
|
||||
|
||||
// InputBufferSize specifies the size the input buffer, in bytes.
|
||||
InputBufferSize int32
|
||||
|
||||
// OutputBufferSize specifies the size the input buffer, in bytes.
|
||||
OutputBufferSize int32
|
||||
}
|
||||
|
||||
// ListenPipe creates a listener on a Windows named pipe path, e.g. \\.\pipe\mypipe.
|
||||
// The pipe must not already exist.
|
||||
func ListenPipe(path string, c *PipeConfig) (net.Listener, error) {
|
||||
var (
|
||||
sd []byte
|
||||
err error
|
||||
)
|
||||
if c == nil {
|
||||
c = &PipeConfig{}
|
||||
}
|
||||
if c.SecurityDescriptor != "" {
|
||||
sd, err = SddlToSecurityDescriptor(c.SecurityDescriptor)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
h, err := makeServerPipeHandle(path, sd, c, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Immediately open and then close a client handle so that the named pipe is
|
||||
// created but not currently accepting connections.
|
||||
h2, err := createFile(path, 0, 0, nil, syscall.OPEN_EXISTING, cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
|
||||
if err != nil {
|
||||
syscall.Close(h)
|
||||
return nil, err
|
||||
}
|
||||
syscall.Close(h2)
|
||||
l := &win32PipeListener{
|
||||
firstHandle: h,
|
||||
path: path,
|
||||
securityDescriptor: sd,
|
||||
config: *c,
|
||||
acceptCh: make(chan (chan acceptResponse)),
|
||||
closeCh: make(chan int),
|
||||
doneCh: make(chan int),
|
||||
}
|
||||
go l.listenerRoutine()
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func connectPipe(p *win32File) error {
|
||||
c, err := p.prepareIo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = connectNamedPipe(p.handle, &c.o)
|
||||
_, err = p.asyncIo(c, time.Time{}, 0, err)
|
||||
if err != nil && err != cERROR_PIPE_CONNECTED {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *win32PipeListener) Accept() (net.Conn, error) {
|
||||
ch := make(chan acceptResponse)
|
||||
select {
|
||||
case l.acceptCh <- ch:
|
||||
response := <-ch
|
||||
err := response.err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if l.config.MessageMode {
|
||||
return &win32MessageBytePipe{
|
||||
win32Pipe: win32Pipe{win32File: response.f, path: l.path},
|
||||
}, nil
|
||||
}
|
||||
return &win32Pipe{win32File: response.f, path: l.path}, nil
|
||||
case <-l.doneCh:
|
||||
return nil, ErrPipeListenerClosed
|
||||
}
|
||||
}
|
||||
|
||||
func (l *win32PipeListener) Close() error {
|
||||
select {
|
||||
case l.closeCh <- 1:
|
||||
<-l.doneCh
|
||||
case <-l.doneCh:
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *win32PipeListener) Addr() net.Addr {
|
||||
return pipeAddress(l.path)
|
||||
}
|
||||
150
integration/vendor/github.com/docker/libcompose/vendor/github.com/Microsoft/go-winio/privilege.go
generated
vendored
Normal file
150
integration/vendor/github.com/docker/libcompose/vendor/github.com/Microsoft/go-winio/privilege.go
generated
vendored
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
package winio
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unicode/utf16"
|
||||
)
|
||||
|
||||
//sys adjustTokenPrivileges(token syscall.Handle, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges
|
||||
//sys impersonateSelf(level uint32) (err error) = advapi32.ImpersonateSelf
|
||||
//sys revertToSelf() (err error) = advapi32.RevertToSelf
|
||||
//sys openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *syscall.Handle) (err error) = advapi32.OpenThreadToken
|
||||
//sys getCurrentThread() (h syscall.Handle) = GetCurrentThread
|
||||
//sys lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) = advapi32.LookupPrivilegeValueW
|
||||
//sys lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW
|
||||
//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW
|
||||
|
||||
const (
|
||||
SE_PRIVILEGE_ENABLED = 2
|
||||
|
||||
ERROR_NOT_ALL_ASSIGNED syscall.Errno = 1300
|
||||
|
||||
SeBackupPrivilege = "SeBackupPrivilege"
|
||||
SeRestorePrivilege = "SeRestorePrivilege"
|
||||
)
|
||||
|
||||
const (
|
||||
securityAnonymous = iota
|
||||
securityIdentification
|
||||
securityImpersonation
|
||||
securityDelegation
|
||||
)
|
||||
|
||||
type PrivilegeError struct {
|
||||
privileges []uint64
|
||||
}
|
||||
|
||||
func (e *PrivilegeError) Error() string {
|
||||
s := ""
|
||||
if len(e.privileges) > 1 {
|
||||
s = "Could not enable privileges "
|
||||
} else {
|
||||
s = "Could not enable privilege "
|
||||
}
|
||||
for i, p := range e.privileges {
|
||||
if i != 0 {
|
||||
s += ", "
|
||||
}
|
||||
s += `"`
|
||||
s += getPrivilegeName(p)
|
||||
s += `"`
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func RunWithPrivilege(name string, fn func() error) error {
|
||||
return RunWithPrivileges([]string{name}, fn)
|
||||
}
|
||||
|
||||
func RunWithPrivileges(names []string, fn func() error) error {
|
||||
var privileges []uint64
|
||||
for _, name := range names {
|
||||
p := uint64(0)
|
||||
err := lookupPrivilegeValue("", name, &p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
privileges = append(privileges, p)
|
||||
}
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
token, err := newThreadToken()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer releaseThreadToken(token)
|
||||
err = adjustPrivileges(token, privileges)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fn()
|
||||
}
|
||||
|
||||
func adjustPrivileges(token syscall.Handle, privileges []uint64) error {
|
||||
var b bytes.Buffer
|
||||
binary.Write(&b, binary.LittleEndian, uint32(len(privileges)))
|
||||
for _, p := range privileges {
|
||||
binary.Write(&b, binary.LittleEndian, p)
|
||||
binary.Write(&b, binary.LittleEndian, uint32(SE_PRIVILEGE_ENABLED))
|
||||
}
|
||||
prevState := make([]byte, b.Len())
|
||||
reqSize := uint32(0)
|
||||
success, err := adjustTokenPrivileges(token, false, &b.Bytes()[0], uint32(len(prevState)), &prevState[0], &reqSize)
|
||||
if !success {
|
||||
return err
|
||||
}
|
||||
if err == ERROR_NOT_ALL_ASSIGNED {
|
||||
return &PrivilegeError{privileges}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getPrivilegeName(luid uint64) string {
|
||||
var nameBuffer [256]uint16
|
||||
bufSize := uint32(len(nameBuffer))
|
||||
err := lookupPrivilegeName("", &luid, &nameBuffer[0], &bufSize)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("<unknown privilege %d>", luid)
|
||||
}
|
||||
|
||||
var displayNameBuffer [256]uint16
|
||||
displayBufSize := uint32(len(displayNameBuffer))
|
||||
var langId uint32
|
||||
err = lookupPrivilegeDisplayName("", &nameBuffer[0], &displayNameBuffer[0], &displayBufSize, &langId)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("<unknown privilege %s>", utf16.Decode(nameBuffer[:bufSize]))
|
||||
}
|
||||
|
||||
return string(utf16.Decode(displayNameBuffer[:displayBufSize]))
|
||||
}
|
||||
|
||||
func newThreadToken() (syscall.Handle, error) {
|
||||
err := impersonateSelf(securityImpersonation)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var token syscall.Handle
|
||||
err = openThreadToken(getCurrentThread(), syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, false, &token)
|
||||
if err != nil {
|
||||
rerr := revertToSelf()
|
||||
if rerr != nil {
|
||||
panic(rerr)
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func releaseThreadToken(h syscall.Handle) {
|
||||
err := revertToSelf()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
syscall.Close(h)
|
||||
}
|
||||
128
integration/vendor/github.com/docker/libcompose/vendor/github.com/Microsoft/go-winio/reparse.go
generated
vendored
Normal file
128
integration/vendor/github.com/docker/libcompose/vendor/github.com/Microsoft/go-winio/reparse.go
generated
vendored
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
package winio
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
reparseTagMountPoint = 0xA0000003
|
||||
reparseTagSymlink = 0xA000000C
|
||||
)
|
||||
|
||||
type reparseDataBuffer struct {
|
||||
ReparseTag uint32
|
||||
ReparseDataLength uint16
|
||||
Reserved uint16
|
||||
SubstituteNameOffset uint16
|
||||
SubstituteNameLength uint16
|
||||
PrintNameOffset uint16
|
||||
PrintNameLength uint16
|
||||
}
|
||||
|
||||
// ReparsePoint describes a Win32 symlink or mount point.
|
||||
type ReparsePoint struct {
|
||||
Target string
|
||||
IsMountPoint bool
|
||||
}
|
||||
|
||||
// UnsupportedReparsePointError is returned when trying to decode a non-symlink or
|
||||
// mount point reparse point.
|
||||
type UnsupportedReparsePointError struct {
|
||||
Tag uint32
|
||||
}
|
||||
|
||||
func (e *UnsupportedReparsePointError) Error() string {
|
||||
return fmt.Sprintf("unsupported reparse point %x", e.Tag)
|
||||
}
|
||||
|
||||
// DecodeReparsePoint decodes a Win32 REPARSE_DATA_BUFFER structure containing either a symlink
|
||||
// or a mount point.
|
||||
func DecodeReparsePoint(b []byte) (*ReparsePoint, error) {
|
||||
tag := binary.LittleEndian.Uint32(b[0:4])
|
||||
return DecodeReparsePointData(tag, b[8:])
|
||||
}
|
||||
|
||||
func DecodeReparsePointData(tag uint32, b []byte) (*ReparsePoint, error) {
|
||||
isMountPoint := false
|
||||
switch tag {
|
||||
case reparseTagMountPoint:
|
||||
isMountPoint = true
|
||||
case reparseTagSymlink:
|
||||
default:
|
||||
return nil, &UnsupportedReparsePointError{tag}
|
||||
}
|
||||
nameOffset := 8 + binary.LittleEndian.Uint16(b[4:6])
|
||||
if !isMountPoint {
|
||||
nameOffset += 4
|
||||
}
|
||||
nameLength := binary.LittleEndian.Uint16(b[6:8])
|
||||
name := make([]uint16, nameLength/2)
|
||||
err := binary.Read(bytes.NewReader(b[nameOffset:nameOffset+nameLength]), binary.LittleEndian, &name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ReparsePoint{string(utf16.Decode(name)), isMountPoint}, nil
|
||||
}
|
||||
|
||||
func isDriveLetter(c byte) bool {
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|
||||
}
|
||||
|
||||
// EncodeReparsePoint encodes a Win32 REPARSE_DATA_BUFFER structure describing a symlink or
|
||||
// mount point.
|
||||
func EncodeReparsePoint(rp *ReparsePoint) []byte {
|
||||
// Generate an NT path and determine if this is a relative path.
|
||||
var ntTarget string
|
||||
relative := false
|
||||
if strings.HasPrefix(rp.Target, `\\?\`) {
|
||||
ntTarget = rp.Target
|
||||
} else if strings.HasPrefix(rp.Target, `\\`) {
|
||||
ntTarget = `\??\UNC\` + rp.Target[2:]
|
||||
} else if len(rp.Target) >= 2 && isDriveLetter(rp.Target[0]) && rp.Target[1] == ':' {
|
||||
ntTarget = `\??\` + rp.Target
|
||||
} else {
|
||||
ntTarget = rp.Target
|
||||
relative = true
|
||||
}
|
||||
|
||||
// The paths must be NUL-terminated even though they are counted strings.
|
||||
target16 := utf16.Encode([]rune(rp.Target + "\x00"))
|
||||
ntTarget16 := utf16.Encode([]rune(ntTarget + "\x00"))
|
||||
|
||||
size := int(unsafe.Sizeof(reparseDataBuffer{})) - 8
|
||||
size += len(ntTarget16)*2 + len(target16)*2
|
||||
|
||||
tag := uint32(reparseTagMountPoint)
|
||||
if !rp.IsMountPoint {
|
||||
tag = reparseTagSymlink
|
||||
size += 4 // Add room for symlink flags
|
||||
}
|
||||
|
||||
data := reparseDataBuffer{
|
||||
ReparseTag: tag,
|
||||
ReparseDataLength: uint16(size),
|
||||
SubstituteNameOffset: 0,
|
||||
SubstituteNameLength: uint16((len(ntTarget16) - 1) * 2),
|
||||
PrintNameOffset: uint16(len(ntTarget16) * 2),
|
||||
PrintNameLength: uint16((len(target16) - 1) * 2),
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
binary.Write(&b, binary.LittleEndian, &data)
|
||||
if !rp.IsMountPoint {
|
||||
flags := uint32(0)
|
||||
if relative {
|
||||
flags |= 1
|
||||
}
|
||||
binary.Write(&b, binary.LittleEndian, flags)
|
||||
}
|
||||
|
||||
binary.Write(&b, binary.LittleEndian, ntTarget16)
|
||||
binary.Write(&b, binary.LittleEndian, target16)
|
||||
return b.Bytes()
|
||||
}
|
||||
96
integration/vendor/github.com/docker/libcompose/vendor/github.com/Microsoft/go-winio/sd.go
generated
vendored
Normal file
96
integration/vendor/github.com/docker/libcompose/vendor/github.com/Microsoft/go-winio/sd.go
generated
vendored
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
package winio
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW
|
||||
//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW
|
||||
//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
|
||||
//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
|
||||
//sys localFree(mem uintptr) = LocalFree
|
||||
//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength
|
||||
|
||||
const (
|
||||
cERROR_NONE_MAPPED = syscall.Errno(1332)
|
||||
)
|
||||
|
||||
type AccountLookupError struct {
|
||||
Name string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *AccountLookupError) Error() string {
|
||||
if e.Name == "" {
|
||||
return "lookup account: empty account name specified"
|
||||
}
|
||||
var s string
|
||||
switch e.Err {
|
||||
case cERROR_NONE_MAPPED:
|
||||
s = "not found"
|
||||
default:
|
||||
s = e.Err.Error()
|
||||
}
|
||||
return "lookup account " + e.Name + ": " + s
|
||||
}
|
||||
|
||||
type SddlConversionError struct {
|
||||
Sddl string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *SddlConversionError) Error() string {
|
||||
return "convert " + e.Sddl + ": " + e.Err.Error()
|
||||
}
|
||||
|
||||
// LookupSidByName looks up the SID of an account by name
|
||||
func LookupSidByName(name string) (sid string, err error) {
|
||||
if name == "" {
|
||||
return "", &AccountLookupError{name, cERROR_NONE_MAPPED}
|
||||
}
|
||||
|
||||
var sidSize, sidNameUse, refDomainSize uint32
|
||||
err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse)
|
||||
if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER {
|
||||
return "", &AccountLookupError{name, err}
|
||||
}
|
||||
sidBuffer := make([]byte, sidSize)
|
||||
refDomainBuffer := make([]uint16, refDomainSize)
|
||||
err = lookupAccountName(nil, name, &sidBuffer[0], &sidSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse)
|
||||
if err != nil {
|
||||
return "", &AccountLookupError{name, err}
|
||||
}
|
||||
var strBuffer *uint16
|
||||
err = convertSidToStringSid(&sidBuffer[0], &strBuffer)
|
||||
if err != nil {
|
||||
return "", &AccountLookupError{name, err}
|
||||
}
|
||||
sid = syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:])
|
||||
localFree(uintptr(unsafe.Pointer(strBuffer)))
|
||||
return sid, nil
|
||||
}
|
||||
|
||||
func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
|
||||
var sdBuffer uintptr
|
||||
err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil)
|
||||
if err != nil {
|
||||
return nil, &SddlConversionError{sddl, err}
|
||||
}
|
||||
defer localFree(sdBuffer)
|
||||
sd := make([]byte, getSecurityDescriptorLength(sdBuffer))
|
||||
copy(sd, (*[0xffff]byte)(unsafe.Pointer(sdBuffer))[:len(sd)])
|
||||
return sd, nil
|
||||
}
|
||||
|
||||
func SecurityDescriptorToSddl(sd []byte) (string, error) {
|
||||
var sddl *uint16
|
||||
// The returned string length seems to including an aribtrary number of terminating NULs.
|
||||
// Don't use it.
|
||||
err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer localFree(uintptr(unsafe.Pointer(sddl)))
|
||||
return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(sddl))[:]), nil
|
||||
}
|
||||
3
integration/vendor/github.com/docker/libcompose/vendor/github.com/Microsoft/go-winio/syscall.go
generated
vendored
Normal file
3
integration/vendor/github.com/docker/libcompose/vendor/github.com/Microsoft/go-winio/syscall.go
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
package winio
|
||||
|
||||
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go
|
||||
492
integration/vendor/github.com/docker/libcompose/vendor/github.com/Microsoft/go-winio/zsyscall.go
generated
vendored
Normal file
492
integration/vendor/github.com/docker/libcompose/vendor/github.com/Microsoft/go-winio/zsyscall.go
generated
vendored
Normal file
|
|
@ -0,0 +1,492 @@
|
|||
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
|
||||
|
||||
package winio
|
||||
|
||||
import "unsafe"
|
||||
import "syscall"
|
||||
|
||||
var _ unsafe.Pointer
|
||||
|
||||
var (
|
||||
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
modwinmm = syscall.NewLazyDLL("winmm.dll")
|
||||
modadvapi32 = syscall.NewLazyDLL("advapi32.dll")
|
||||
|
||||
procCancelIoEx = modkernel32.NewProc("CancelIoEx")
|
||||
procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
|
||||
procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
|
||||
procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes")
|
||||
proctimeBeginPeriod = modwinmm.NewProc("timeBeginPeriod")
|
||||
procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
|
||||
procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
|
||||
procCreateFileW = modkernel32.NewProc("CreateFileW")
|
||||
procWaitNamedPipeW = modkernel32.NewProc("WaitNamedPipeW")
|
||||
procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo")
|
||||
procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW")
|
||||
procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
|
||||
procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
|
||||
procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
|
||||
procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW")
|
||||
procLocalFree = modkernel32.NewProc("LocalFree")
|
||||
procGetSecurityDescriptorLength = modadvapi32.NewProc("GetSecurityDescriptorLength")
|
||||
procGetFileInformationByHandleEx = modkernel32.NewProc("GetFileInformationByHandleEx")
|
||||
procSetFileInformationByHandle = modkernel32.NewProc("SetFileInformationByHandle")
|
||||
procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges")
|
||||
procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
|
||||
procRevertToSelf = modadvapi32.NewProc("RevertToSelf")
|
||||
procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken")
|
||||
procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
|
||||
procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW")
|
||||
procLookupPrivilegeNameW = modadvapi32.NewProc("LookupPrivilegeNameW")
|
||||
procLookupPrivilegeDisplayNameW = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
|
||||
procBackupRead = modkernel32.NewProc("BackupRead")
|
||||
procBackupWrite = modkernel32.NewProc("BackupWrite")
|
||||
)
|
||||
|
||||
func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0)
|
||||
newport = syscall.Handle(r0)
|
||||
if newport == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func timeBeginPeriod(period uint32) (n int32) {
|
||||
r0, _, _ := syscall.Syscall(proctimeBeginPeriod.Addr(), 1, uintptr(period), 0, 0)
|
||||
n = int32(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *securityAttributes) (handle syscall.Handle, err error) {
|
||||
var _p0 *uint16
|
||||
_p0, err = syscall.UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa)
|
||||
}
|
||||
|
||||
func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *securityAttributes) (handle syscall.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0)
|
||||
handle = syscall.Handle(r0)
|
||||
if handle == syscall.InvalidHandle {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func createFile(name string, access uint32, mode uint32, sa *securityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
|
||||
var _p0 *uint16
|
||||
_p0, err = syscall.UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return _createFile(_p0, access, mode, sa, createmode, attrs, templatefile)
|
||||
}
|
||||
|
||||
func _createFile(name *uint16, access uint32, mode uint32, sa *securityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
|
||||
handle = syscall.Handle(r0)
|
||||
if handle == syscall.InvalidHandle {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func waitNamedPipe(name string, timeout uint32) (err error) {
|
||||
var _p0 *uint16
|
||||
_p0, err = syscall.UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return _waitNamedPipe(_p0, timeout)
|
||||
}
|
||||
|
||||
func _waitNamedPipe(name *uint16, timeout uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procWaitNamedPipeW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(timeout), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
|
||||
var _p0 *uint16
|
||||
_p0, err = syscall.UTF16PtrFromString(accountName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return _lookupAccountName(systemName, _p0, sid, sidSize, refDomain, refDomainSize, sidNameUse)
|
||||
}
|
||||
|
||||
func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func convertSidToStringSid(sid *byte, str **uint16) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) {
|
||||
var _p0 *uint16
|
||||
_p0, err = syscall.UTF16PtrFromString(str)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return _convertStringSecurityDescriptorToSecurityDescriptor(_p0, revision, sd, size)
|
||||
}
|
||||
|
||||
func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision uint32, sd *uintptr, size *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), 4, uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), 5, uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(secInfo), uintptr(unsafe.Pointer(sddl)), uintptr(unsafe.Pointer(sddlSize)), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func localFree(mem uintptr) {
|
||||
syscall.Syscall(procLocalFree.Addr(), 1, uintptr(mem), 0, 0)
|
||||
return
|
||||
}
|
||||
|
||||
func getSecurityDescriptorLength(sd uintptr) (len uint32) {
|
||||
r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0)
|
||||
len = uint32(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procSetFileInformationByHandle.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func adjustTokenPrivileges(token syscall.Handle, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) {
|
||||
var _p0 uint32
|
||||
if releaseAll {
|
||||
_p0 = 1
|
||||
} else {
|
||||
_p0 = 0
|
||||
}
|
||||
r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize)))
|
||||
success = r0 != 0
|
||||
if true {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func impersonateSelf(level uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(level), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func revertToSelf() (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *syscall.Handle) (err error) {
|
||||
var _p0 uint32
|
||||
if openAsSelf {
|
||||
_p0 = 1
|
||||
} else {
|
||||
_p0 = 0
|
||||
}
|
||||
r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getCurrentThread() (h syscall.Handle) {
|
||||
r0, _, _ := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0)
|
||||
h = syscall.Handle(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) {
|
||||
var _p0 *uint16
|
||||
_p0, err = syscall.UTF16PtrFromString(systemName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var _p1 *uint16
|
||||
_p1, err = syscall.UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return _lookupPrivilegeValue(_p0, _p1, luid)
|
||||
}
|
||||
|
||||
func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint64) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid)))
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) {
|
||||
var _p0 *uint16
|
||||
_p0, err = syscall.UTF16PtrFromString(systemName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return _lookupPrivilegeName(_p0, luid, buffer, size)
|
||||
}
|
||||
|
||||
func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procLookupPrivilegeNameW.Addr(), 4, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
|
||||
var _p0 *uint16
|
||||
_p0, err = syscall.UTF16PtrFromString(systemName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return _lookupPrivilegeDisplayName(_p0, name, buffer, size, languageId)
|
||||
}
|
||||
|
||||
func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procLookupPrivilegeDisplayNameW.Addr(), 5, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
|
||||
var _p0 *byte
|
||||
if len(b) > 0 {
|
||||
_p0 = &b[0]
|
||||
}
|
||||
var _p1 uint32
|
||||
if abort {
|
||||
_p1 = 1
|
||||
} else {
|
||||
_p1 = 0
|
||||
}
|
||||
var _p2 uint32
|
||||
if processSecurity {
|
||||
_p2 = 1
|
||||
} else {
|
||||
_p2 = 0
|
||||
}
|
||||
r1, _, e1 := syscall.Syscall9(procBackupRead.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
|
||||
var _p0 *byte
|
||||
if len(b) > 0 {
|
||||
_p0 = &b[0]
|
||||
}
|
||||
var _p1 uint32
|
||||
if abort {
|
||||
_p1 = 1
|
||||
} else {
|
||||
_p1 = 0
|
||||
}
|
||||
var _p2 uint32
|
||||
if processSecurity {
|
||||
_p2 = 1
|
||||
} else {
|
||||
_p2 = 0
|
||||
}
|
||||
r1, _, e1 := syscall.Syscall9(procBackupWrite.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
21
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/LICENSE
generated
vendored
Normal file
21
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Simon Eskildsen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
26
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/doc.go
generated
vendored
Normal file
26
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
Package logrus is a structured logger for Go, completely API compatible with the standard library logger.
|
||||
|
||||
|
||||
The simplest way to use Logrus is simply the package-level exported logger:
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
log "github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.WithFields(log.Fields{
|
||||
"animal": "walrus",
|
||||
"number": 1,
|
||||
"size": 10,
|
||||
}).Info("A walrus appears")
|
||||
}
|
||||
|
||||
Output:
|
||||
time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
|
||||
|
||||
For a full guide visit https://github.com/Sirupsen/logrus
|
||||
*/
|
||||
package logrus
|
||||
264
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/entry.go
generated
vendored
Normal file
264
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/entry.go
generated
vendored
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Defines the key when adding errors using WithError.
|
||||
var ErrorKey = "error"
|
||||
|
||||
// An entry is the final or intermediate Logrus logging entry. It contains all
|
||||
// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
|
||||
// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
|
||||
// passed around as much as you wish to avoid field duplication.
|
||||
type Entry struct {
|
||||
Logger *Logger
|
||||
|
||||
// Contains all the fields set by the user.
|
||||
Data Fields
|
||||
|
||||
// Time at which the log entry was created
|
||||
Time time.Time
|
||||
|
||||
// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
|
||||
Level Level
|
||||
|
||||
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
|
||||
Message string
|
||||
}
|
||||
|
||||
func NewEntry(logger *Logger) *Entry {
|
||||
return &Entry{
|
||||
Logger: logger,
|
||||
// Default is three fields, give a little extra room
|
||||
Data: make(Fields, 5),
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a reader for the entry, which is a proxy to the formatter.
|
||||
func (entry *Entry) Reader() (*bytes.Buffer, error) {
|
||||
serialized, err := entry.Logger.Formatter.Format(entry)
|
||||
return bytes.NewBuffer(serialized), err
|
||||
}
|
||||
|
||||
// Returns the string representation from the reader and ultimately the
|
||||
// formatter.
|
||||
func (entry *Entry) String() (string, error) {
|
||||
reader, err := entry.Reader()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return reader.String(), err
|
||||
}
|
||||
|
||||
// Add an error as single field (using the key defined in ErrorKey) to the Entry.
|
||||
func (entry *Entry) WithError(err error) *Entry {
|
||||
return entry.WithField(ErrorKey, err)
|
||||
}
|
||||
|
||||
// Add a single field to the Entry.
|
||||
func (entry *Entry) WithField(key string, value interface{}) *Entry {
|
||||
return entry.WithFields(Fields{key: value})
|
||||
}
|
||||
|
||||
// Add a map of fields to the Entry.
|
||||
func (entry *Entry) WithFields(fields Fields) *Entry {
|
||||
data := make(Fields, len(entry.Data)+len(fields))
|
||||
for k, v := range entry.Data {
|
||||
data[k] = v
|
||||
}
|
||||
for k, v := range fields {
|
||||
data[k] = v
|
||||
}
|
||||
return &Entry{Logger: entry.Logger, Data: data}
|
||||
}
|
||||
|
||||
// This function is not declared with a pointer value because otherwise
|
||||
// race conditions will occur when using multiple goroutines
|
||||
func (entry Entry) log(level Level, msg string) {
|
||||
entry.Time = time.Now()
|
||||
entry.Level = level
|
||||
entry.Message = msg
|
||||
|
||||
if err := entry.Logger.Hooks.Fire(level, &entry); err != nil {
|
||||
entry.Logger.mu.Lock()
|
||||
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
||||
entry.Logger.mu.Unlock()
|
||||
}
|
||||
|
||||
reader, err := entry.Reader()
|
||||
if err != nil {
|
||||
entry.Logger.mu.Lock()
|
||||
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
||||
entry.Logger.mu.Unlock()
|
||||
}
|
||||
|
||||
entry.Logger.mu.Lock()
|
||||
defer entry.Logger.mu.Unlock()
|
||||
|
||||
_, err = io.Copy(entry.Logger.Out, reader)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
|
||||
}
|
||||
|
||||
// To avoid Entry#log() returning a value that only would make sense for
|
||||
// panic() to use in Entry#Panic(), we avoid the allocation by checking
|
||||
// directly here.
|
||||
if level <= PanicLevel {
|
||||
panic(&entry)
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Debug(args ...interface{}) {
|
||||
if entry.Logger.Level >= DebugLevel {
|
||||
entry.log(DebugLevel, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Print(args ...interface{}) {
|
||||
entry.Info(args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Info(args ...interface{}) {
|
||||
if entry.Logger.Level >= InfoLevel {
|
||||
entry.log(InfoLevel, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Warn(args ...interface{}) {
|
||||
if entry.Logger.Level >= WarnLevel {
|
||||
entry.log(WarnLevel, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Warning(args ...interface{}) {
|
||||
entry.Warn(args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Error(args ...interface{}) {
|
||||
if entry.Logger.Level >= ErrorLevel {
|
||||
entry.log(ErrorLevel, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatal(args ...interface{}) {
|
||||
if entry.Logger.Level >= FatalLevel {
|
||||
entry.log(FatalLevel, fmt.Sprint(args...))
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panic(args ...interface{}) {
|
||||
if entry.Logger.Level >= PanicLevel {
|
||||
entry.log(PanicLevel, fmt.Sprint(args...))
|
||||
}
|
||||
panic(fmt.Sprint(args...))
|
||||
}
|
||||
|
||||
// Entry Printf family functions
|
||||
|
||||
func (entry *Entry) Debugf(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= DebugLevel {
|
||||
entry.Debug(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Infof(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= InfoLevel {
|
||||
entry.Info(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Printf(format string, args ...interface{}) {
|
||||
entry.Infof(format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Warnf(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= WarnLevel {
|
||||
entry.Warn(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Warningf(format string, args ...interface{}) {
|
||||
entry.Warnf(format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Errorf(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= ErrorLevel {
|
||||
entry.Error(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatalf(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= FatalLevel {
|
||||
entry.Fatal(fmt.Sprintf(format, args...))
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= PanicLevel {
|
||||
entry.Panic(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
// Entry Println family functions
|
||||
|
||||
func (entry *Entry) Debugln(args ...interface{}) {
|
||||
if entry.Logger.Level >= DebugLevel {
|
||||
entry.Debug(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Infoln(args ...interface{}) {
|
||||
if entry.Logger.Level >= InfoLevel {
|
||||
entry.Info(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Println(args ...interface{}) {
|
||||
entry.Infoln(args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Warnln(args ...interface{}) {
|
||||
if entry.Logger.Level >= WarnLevel {
|
||||
entry.Warn(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Warningln(args ...interface{}) {
|
||||
entry.Warnln(args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Errorln(args ...interface{}) {
|
||||
if entry.Logger.Level >= ErrorLevel {
|
||||
entry.Error(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatalln(args ...interface{}) {
|
||||
if entry.Logger.Level >= FatalLevel {
|
||||
entry.Fatal(entry.sprintlnn(args...))
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panicln(args ...interface{}) {
|
||||
if entry.Logger.Level >= PanicLevel {
|
||||
entry.Panic(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
// Sprintlnn => Sprint no newline. This is to get the behavior of how
|
||||
// fmt.Sprintln where spaces are always added between operands, regardless of
|
||||
// their type. Instead of vendoring the Sprintln implementation to spare a
|
||||
// string allocation, we do the simplest thing.
|
||||
func (entry *Entry) sprintlnn(args ...interface{}) string {
|
||||
msg := fmt.Sprintln(args...)
|
||||
return msg[:len(msg)-1]
|
||||
}
|
||||
193
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/exported.go
generated
vendored
Normal file
193
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/exported.go
generated
vendored
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
var (
|
||||
// std is the name of the standard logger in stdlib `log`
|
||||
std = New()
|
||||
)
|
||||
|
||||
func StandardLogger() *Logger {
|
||||
return std
|
||||
}
|
||||
|
||||
// SetOutput sets the standard logger output.
|
||||
func SetOutput(out io.Writer) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.Out = out
|
||||
}
|
||||
|
||||
// SetFormatter sets the standard logger formatter.
|
||||
func SetFormatter(formatter Formatter) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.Formatter = formatter
|
||||
}
|
||||
|
||||
// SetLevel sets the standard logger level.
|
||||
func SetLevel(level Level) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.Level = level
|
||||
}
|
||||
|
||||
// GetLevel returns the standard logger level.
|
||||
func GetLevel() Level {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
return std.Level
|
||||
}
|
||||
|
||||
// AddHook adds a hook to the standard logger hooks.
|
||||
func AddHook(hook Hook) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.Hooks.Add(hook)
|
||||
}
|
||||
|
||||
// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
|
||||
func WithError(err error) *Entry {
|
||||
return std.WithField(ErrorKey, err)
|
||||
}
|
||||
|
||||
// WithField creates an entry from the standard logger and adds a field to
|
||||
// it. If you want multiple fields, use `WithFields`.
|
||||
//
|
||||
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||
// or Panic on the Entry it returns.
|
||||
func WithField(key string, value interface{}) *Entry {
|
||||
return std.WithField(key, value)
|
||||
}
|
||||
|
||||
// WithFields creates an entry from the standard logger and adds multiple
|
||||
// fields to it. This is simply a helper for `WithField`, invoking it
|
||||
// once for each field.
|
||||
//
|
||||
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||
// or Panic on the Entry it returns.
|
||||
func WithFields(fields Fields) *Entry {
|
||||
return std.WithFields(fields)
|
||||
}
|
||||
|
||||
// Debug logs a message at level Debug on the standard logger.
|
||||
func Debug(args ...interface{}) {
|
||||
std.Debug(args...)
|
||||
}
|
||||
|
||||
// Print logs a message at level Info on the standard logger.
|
||||
func Print(args ...interface{}) {
|
||||
std.Print(args...)
|
||||
}
|
||||
|
||||
// Info logs a message at level Info on the standard logger.
|
||||
func Info(args ...interface{}) {
|
||||
std.Info(args...)
|
||||
}
|
||||
|
||||
// Warn logs a message at level Warn on the standard logger.
|
||||
func Warn(args ...interface{}) {
|
||||
std.Warn(args...)
|
||||
}
|
||||
|
||||
// Warning logs a message at level Warn on the standard logger.
|
||||
func Warning(args ...interface{}) {
|
||||
std.Warning(args...)
|
||||
}
|
||||
|
||||
// Error logs a message at level Error on the standard logger.
|
||||
func Error(args ...interface{}) {
|
||||
std.Error(args...)
|
||||
}
|
||||
|
||||
// Panic logs a message at level Panic on the standard logger.
|
||||
func Panic(args ...interface{}) {
|
||||
std.Panic(args...)
|
||||
}
|
||||
|
||||
// Fatal logs a message at level Fatal on the standard logger.
|
||||
func Fatal(args ...interface{}) {
|
||||
std.Fatal(args...)
|
||||
}
|
||||
|
||||
// Debugf logs a message at level Debug on the standard logger.
|
||||
func Debugf(format string, args ...interface{}) {
|
||||
std.Debugf(format, args...)
|
||||
}
|
||||
|
||||
// Printf logs a message at level Info on the standard logger.
|
||||
func Printf(format string, args ...interface{}) {
|
||||
std.Printf(format, args...)
|
||||
}
|
||||
|
||||
// Infof logs a message at level Info on the standard logger.
|
||||
func Infof(format string, args ...interface{}) {
|
||||
std.Infof(format, args...)
|
||||
}
|
||||
|
||||
// Warnf logs a message at level Warn on the standard logger.
|
||||
func Warnf(format string, args ...interface{}) {
|
||||
std.Warnf(format, args...)
|
||||
}
|
||||
|
||||
// Warningf logs a message at level Warn on the standard logger.
|
||||
func Warningf(format string, args ...interface{}) {
|
||||
std.Warningf(format, args...)
|
||||
}
|
||||
|
||||
// Errorf logs a message at level Error on the standard logger.
|
||||
func Errorf(format string, args ...interface{}) {
|
||||
std.Errorf(format, args...)
|
||||
}
|
||||
|
||||
// Panicf logs a message at level Panic on the standard logger.
|
||||
func Panicf(format string, args ...interface{}) {
|
||||
std.Panicf(format, args...)
|
||||
}
|
||||
|
||||
// Fatalf logs a message at level Fatal on the standard logger.
|
||||
func Fatalf(format string, args ...interface{}) {
|
||||
std.Fatalf(format, args...)
|
||||
}
|
||||
|
||||
// Debugln logs a message at level Debug on the standard logger.
|
||||
func Debugln(args ...interface{}) {
|
||||
std.Debugln(args...)
|
||||
}
|
||||
|
||||
// Println logs a message at level Info on the standard logger.
|
||||
func Println(args ...interface{}) {
|
||||
std.Println(args...)
|
||||
}
|
||||
|
||||
// Infoln logs a message at level Info on the standard logger.
|
||||
func Infoln(args ...interface{}) {
|
||||
std.Infoln(args...)
|
||||
}
|
||||
|
||||
// Warnln logs a message at level Warn on the standard logger.
|
||||
func Warnln(args ...interface{}) {
|
||||
std.Warnln(args...)
|
||||
}
|
||||
|
||||
// Warningln logs a message at level Warn on the standard logger.
|
||||
func Warningln(args ...interface{}) {
|
||||
std.Warningln(args...)
|
||||
}
|
||||
|
||||
// Errorln logs a message at level Error on the standard logger.
|
||||
func Errorln(args ...interface{}) {
|
||||
std.Errorln(args...)
|
||||
}
|
||||
|
||||
// Panicln logs a message at level Panic on the standard logger.
|
||||
func Panicln(args ...interface{}) {
|
||||
std.Panicln(args...)
|
||||
}
|
||||
|
||||
// Fatalln logs a message at level Fatal on the standard logger.
|
||||
func Fatalln(args ...interface{}) {
|
||||
std.Fatalln(args...)
|
||||
}
|
||||
48
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/formatter.go
generated
vendored
Normal file
48
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/formatter.go
generated
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
package logrus
|
||||
|
||||
import "time"
|
||||
|
||||
const DefaultTimestampFormat = time.RFC3339
|
||||
|
||||
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||
// `Entry`. It exposes all the fields, including the default ones:
|
||||
//
|
||||
// * `entry.Data["msg"]`. The message passed from Info, Warn, Error ..
|
||||
// * `entry.Data["time"]`. The timestamp.
|
||||
// * `entry.Data["level"]. The level the entry was logged at.
|
||||
//
|
||||
// Any additional fields added with `WithField` or `WithFields` are also in
|
||||
// `entry.Data`. Format is expected to return an array of bytes which are then
|
||||
// logged to `logger.Out`.
|
||||
type Formatter interface {
|
||||
Format(*Entry) ([]byte, error)
|
||||
}
|
||||
|
||||
// This is to not silently overwrite `time`, `msg` and `level` fields when
|
||||
// dumping it. If this code wasn't there doing:
|
||||
//
|
||||
// logrus.WithField("level", 1).Info("hello")
|
||||
//
|
||||
// Would just silently drop the user provided level. Instead with this code
|
||||
// it'll logged as:
|
||||
//
|
||||
// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
|
||||
//
|
||||
// It's not exported because it's still using Data in an opinionated way. It's to
|
||||
// avoid code duplication between the two default formatters.
|
||||
func prefixFieldClashes(data Fields) {
|
||||
_, ok := data["time"]
|
||||
if ok {
|
||||
data["fields.time"] = data["time"]
|
||||
}
|
||||
|
||||
_, ok = data["msg"]
|
||||
if ok {
|
||||
data["fields.msg"] = data["msg"]
|
||||
}
|
||||
|
||||
_, ok = data["level"]
|
||||
if ok {
|
||||
data["fields.level"] = data["level"]
|
||||
}
|
||||
}
|
||||
34
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/hooks.go
generated
vendored
Normal file
34
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/hooks.go
generated
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
package logrus
|
||||
|
||||
// A hook to be fired when logging on the logging levels returned from
|
||||
// `Levels()` on your implementation of the interface. Note that this is not
|
||||
// fired in a goroutine or a channel with workers, you should handle such
|
||||
// functionality yourself if your call is non-blocking and you don't wish for
|
||||
// the logging calls for levels returned from `Levels()` to block.
|
||||
type Hook interface {
|
||||
Levels() []Level
|
||||
Fire(*Entry) error
|
||||
}
|
||||
|
||||
// Internal type for storing the hooks on a logger instance.
|
||||
type LevelHooks map[Level][]Hook
|
||||
|
||||
// Add a hook to an instance of logger. This is called with
|
||||
// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface.
|
||||
func (hooks LevelHooks) Add(hook Hook) {
|
||||
for _, level := range hook.Levels() {
|
||||
hooks[level] = append(hooks[level], hook)
|
||||
}
|
||||
}
|
||||
|
||||
// Fire all the hooks for the passed level. Used by `entry.log` to fire
|
||||
// appropriate hooks for a log entry.
|
||||
func (hooks LevelHooks) Fire(level Level, entry *Entry) error {
|
||||
for _, hook := range hooks[level] {
|
||||
if err := hook.Fire(entry); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
41
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/json_formatter.go
generated
vendored
Normal file
41
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/json_formatter.go
generated
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type JSONFormatter struct {
|
||||
// TimestampFormat sets the format used for marshaling timestamps.
|
||||
TimestampFormat string
|
||||
}
|
||||
|
||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
data := make(Fields, len(entry.Data)+3)
|
||||
for k, v := range entry.Data {
|
||||
switch v := v.(type) {
|
||||
case error:
|
||||
// Otherwise errors are ignored by `encoding/json`
|
||||
// https://github.com/Sirupsen/logrus/issues/137
|
||||
data[k] = v.Error()
|
||||
default:
|
||||
data[k] = v
|
||||
}
|
||||
}
|
||||
prefixFieldClashes(data)
|
||||
|
||||
timestampFormat := f.TimestampFormat
|
||||
if timestampFormat == "" {
|
||||
timestampFormat = DefaultTimestampFormat
|
||||
}
|
||||
|
||||
data["time"] = entry.Time.Format(timestampFormat)
|
||||
data["msg"] = entry.Message
|
||||
data["level"] = entry.Level.String()
|
||||
|
||||
serialized, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
||||
}
|
||||
return append(serialized, '\n'), nil
|
||||
}
|
||||
212
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/logger.go
generated
vendored
Normal file
212
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/logger.go
generated
vendored
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Logger struct {
|
||||
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
||||
// file, or leave it default which is `os.Stderr`. You can also set this to
|
||||
// something more adventorous, such as logging to Kafka.
|
||||
Out io.Writer
|
||||
// Hooks for the logger instance. These allow firing events based on logging
|
||||
// levels and log entries. For example, to send errors to an error tracking
|
||||
// service, log to StatsD or dump the core on fatal errors.
|
||||
Hooks LevelHooks
|
||||
// All log entries pass through the formatter before logged to Out. The
|
||||
// included formatters are `TextFormatter` and `JSONFormatter` for which
|
||||
// TextFormatter is the default. In development (when a TTY is attached) it
|
||||
// logs with colors, but to a file it wouldn't. You can easily implement your
|
||||
// own that implements the `Formatter` interface, see the `README` or included
|
||||
// formatters for examples.
|
||||
Formatter Formatter
|
||||
// The logging level the logger should log at. This is typically (and defaults
|
||||
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
||||
// logged. `logrus.Debug` is useful in
|
||||
Level Level
|
||||
// Used to sync writing to the log.
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// Creates a new logger. Configuration should be set by changing `Formatter`,
|
||||
// `Out` and `Hooks` directly on the default logger instance. You can also just
|
||||
// instantiate your own:
|
||||
//
|
||||
// var log = &Logger{
|
||||
// Out: os.Stderr,
|
||||
// Formatter: new(JSONFormatter),
|
||||
// Hooks: make(LevelHooks),
|
||||
// Level: logrus.DebugLevel,
|
||||
// }
|
||||
//
|
||||
// It's recommended to make this a global instance called `log`.
|
||||
func New() *Logger {
|
||||
return &Logger{
|
||||
Out: os.Stderr,
|
||||
Formatter: new(TextFormatter),
|
||||
Hooks: make(LevelHooks),
|
||||
Level: InfoLevel,
|
||||
}
|
||||
}
|
||||
|
||||
// Adds a field to the log entry, note that you it doesn't log until you call
|
||||
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
|
||||
// If you want multiple fields, use `WithFields`.
|
||||
func (logger *Logger) WithField(key string, value interface{}) *Entry {
|
||||
return NewEntry(logger).WithField(key, value)
|
||||
}
|
||||
|
||||
// Adds a struct of fields to the log entry. All it does is call `WithField` for
|
||||
// each `Field`.
|
||||
func (logger *Logger) WithFields(fields Fields) *Entry {
|
||||
return NewEntry(logger).WithFields(fields)
|
||||
}
|
||||
|
||||
// Add an error as single field to the log entry. All it does is call
|
||||
// `WithError` for the given `error`.
|
||||
func (logger *Logger) WithError(err error) *Entry {
|
||||
return NewEntry(logger).WithError(err)
|
||||
}
|
||||
|
||||
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||
if logger.Level >= DebugLevel {
|
||||
NewEntry(logger).Debugf(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Infof(format string, args ...interface{}) {
|
||||
if logger.Level >= InfoLevel {
|
||||
NewEntry(logger).Infof(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Printf(format string, args ...interface{}) {
|
||||
NewEntry(logger).Printf(format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
||||
if logger.Level >= WarnLevel {
|
||||
NewEntry(logger).Warnf(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
||||
if logger.Level >= WarnLevel {
|
||||
NewEntry(logger).Warnf(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
||||
if logger.Level >= ErrorLevel {
|
||||
NewEntry(logger).Errorf(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
||||
if logger.Level >= FatalLevel {
|
||||
NewEntry(logger).Fatalf(format, args...)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
||||
if logger.Level >= PanicLevel {
|
||||
NewEntry(logger).Panicf(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Debug(args ...interface{}) {
|
||||
if logger.Level >= DebugLevel {
|
||||
NewEntry(logger).Debug(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Info(args ...interface{}) {
|
||||
if logger.Level >= InfoLevel {
|
||||
NewEntry(logger).Info(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Print(args ...interface{}) {
|
||||
NewEntry(logger).Info(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warn(args ...interface{}) {
|
||||
if logger.Level >= WarnLevel {
|
||||
NewEntry(logger).Warn(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Warning(args ...interface{}) {
|
||||
if logger.Level >= WarnLevel {
|
||||
NewEntry(logger).Warn(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Error(args ...interface{}) {
|
||||
if logger.Level >= ErrorLevel {
|
||||
NewEntry(logger).Error(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Fatal(args ...interface{}) {
|
||||
if logger.Level >= FatalLevel {
|
||||
NewEntry(logger).Fatal(args...)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (logger *Logger) Panic(args ...interface{}) {
|
||||
if logger.Level >= PanicLevel {
|
||||
NewEntry(logger).Panic(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Debugln(args ...interface{}) {
|
||||
if logger.Level >= DebugLevel {
|
||||
NewEntry(logger).Debugln(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Infoln(args ...interface{}) {
|
||||
if logger.Level >= InfoLevel {
|
||||
NewEntry(logger).Infoln(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Println(args ...interface{}) {
|
||||
NewEntry(logger).Println(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warnln(args ...interface{}) {
|
||||
if logger.Level >= WarnLevel {
|
||||
NewEntry(logger).Warnln(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Warningln(args ...interface{}) {
|
||||
if logger.Level >= WarnLevel {
|
||||
NewEntry(logger).Warnln(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Errorln(args ...interface{}) {
|
||||
if logger.Level >= ErrorLevel {
|
||||
NewEntry(logger).Errorln(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Fatalln(args ...interface{}) {
|
||||
if logger.Level >= FatalLevel {
|
||||
NewEntry(logger).Fatalln(args...)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (logger *Logger) Panicln(args ...interface{}) {
|
||||
if logger.Level >= PanicLevel {
|
||||
NewEntry(logger).Panicln(args...)
|
||||
}
|
||||
}
|
||||
143
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/logrus.go
generated
vendored
Normal file
143
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/logrus.go
generated
vendored
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Fields type, used to pass to `WithFields`.
|
||||
type Fields map[string]interface{}
|
||||
|
||||
// Level type
|
||||
type Level uint8
|
||||
|
||||
// Convert the Level to a string. E.g. PanicLevel becomes "panic".
|
||||
func (level Level) String() string {
|
||||
switch level {
|
||||
case DebugLevel:
|
||||
return "debug"
|
||||
case InfoLevel:
|
||||
return "info"
|
||||
case WarnLevel:
|
||||
return "warning"
|
||||
case ErrorLevel:
|
||||
return "error"
|
||||
case FatalLevel:
|
||||
return "fatal"
|
||||
case PanicLevel:
|
||||
return "panic"
|
||||
}
|
||||
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// ParseLevel takes a string level and returns the Logrus log level constant.
|
||||
func ParseLevel(lvl string) (Level, error) {
|
||||
switch strings.ToLower(lvl) {
|
||||
case "panic":
|
||||
return PanicLevel, nil
|
||||
case "fatal":
|
||||
return FatalLevel, nil
|
||||
case "error":
|
||||
return ErrorLevel, nil
|
||||
case "warn", "warning":
|
||||
return WarnLevel, nil
|
||||
case "info":
|
||||
return InfoLevel, nil
|
||||
case "debug":
|
||||
return DebugLevel, nil
|
||||
}
|
||||
|
||||
var l Level
|
||||
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
|
||||
}
|
||||
|
||||
// A constant exposing all logging levels
|
||||
var AllLevels = []Level{
|
||||
PanicLevel,
|
||||
FatalLevel,
|
||||
ErrorLevel,
|
||||
WarnLevel,
|
||||
InfoLevel,
|
||||
DebugLevel,
|
||||
}
|
||||
|
||||
// These are the different logging levels. You can set the logging level to log
|
||||
// on your instance of logger, obtained with `logrus.New()`.
|
||||
const (
|
||||
// PanicLevel level, highest level of severity. Logs and then calls panic with the
|
||||
// message passed to Debug, Info, ...
|
||||
PanicLevel Level = iota
|
||||
// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
|
||||
// logging level is set to Panic.
|
||||
FatalLevel
|
||||
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
||||
// Commonly used for hooks to send errors to an error tracking service.
|
||||
ErrorLevel
|
||||
// WarnLevel level. Non-critical entries that deserve eyes.
|
||||
WarnLevel
|
||||
// InfoLevel level. General operational entries about what's going on inside the
|
||||
// application.
|
||||
InfoLevel
|
||||
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
|
||||
DebugLevel
|
||||
)
|
||||
|
||||
// Won't compile if StdLogger can't be realized by a log.Logger
|
||||
var (
|
||||
_ StdLogger = &log.Logger{}
|
||||
_ StdLogger = &Entry{}
|
||||
_ StdLogger = &Logger{}
|
||||
)
|
||||
|
||||
// StdLogger is what your logrus-enabled library should take, that way
|
||||
// it'll accept a stdlib logger and a logrus logger. There's no standard
|
||||
// interface, this is the closest we get, unfortunately.
|
||||
type StdLogger interface {
|
||||
Print(...interface{})
|
||||
Printf(string, ...interface{})
|
||||
Println(...interface{})
|
||||
|
||||
Fatal(...interface{})
|
||||
Fatalf(string, ...interface{})
|
||||
Fatalln(...interface{})
|
||||
|
||||
Panic(...interface{})
|
||||
Panicf(string, ...interface{})
|
||||
Panicln(...interface{})
|
||||
}
|
||||
|
||||
// The FieldLogger interface generalizes the Entry and Logger types
|
||||
type FieldLogger interface {
|
||||
WithField(key string, value interface{}) *Entry
|
||||
WithFields(fields Fields) *Entry
|
||||
WithError(err error) *Entry
|
||||
|
||||
Debugf(format string, args ...interface{})
|
||||
Infof(format string, args ...interface{})
|
||||
Printf(format string, args ...interface{})
|
||||
Warnf(format string, args ...interface{})
|
||||
Warningf(format string, args ...interface{})
|
||||
Errorf(format string, args ...interface{})
|
||||
Fatalf(format string, args ...interface{})
|
||||
Panicf(format string, args ...interface{})
|
||||
|
||||
Debug(args ...interface{})
|
||||
Info(args ...interface{})
|
||||
Print(args ...interface{})
|
||||
Warn(args ...interface{})
|
||||
Warning(args ...interface{})
|
||||
Error(args ...interface{})
|
||||
Fatal(args ...interface{})
|
||||
Panic(args ...interface{})
|
||||
|
||||
Debugln(args ...interface{})
|
||||
Infoln(args ...interface{})
|
||||
Println(args ...interface{})
|
||||
Warnln(args ...interface{})
|
||||
Warningln(args ...interface{})
|
||||
Errorln(args ...interface{})
|
||||
Fatalln(args ...interface{})
|
||||
Panicln(args ...interface{})
|
||||
}
|
||||
9
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/terminal_bsd.go
generated
vendored
Normal file
9
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/terminal_bsd.go
generated
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// +build darwin freebsd openbsd netbsd dragonfly
|
||||
|
||||
package logrus
|
||||
|
||||
import "syscall"
|
||||
|
||||
const ioctlReadTermios = syscall.TIOCGETA
|
||||
|
||||
type Termios syscall.Termios
|
||||
12
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/terminal_linux.go
generated
vendored
Normal file
12
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/terminal_linux.go
generated
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// Based on ssh/terminal:
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package logrus
|
||||
|
||||
import "syscall"
|
||||
|
||||
const ioctlReadTermios = syscall.TCGETS
|
||||
|
||||
type Termios syscall.Termios
|
||||
21
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
generated
vendored
Normal file
21
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// Based on ssh/terminal:
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux darwin freebsd openbsd netbsd dragonfly
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
||||
func IsTerminal() bool {
|
||||
fd := syscall.Stderr
|
||||
var termios Termios
|
||||
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
||||
return err == 0
|
||||
}
|
||||
15
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/terminal_solaris.go
generated
vendored
Normal file
15
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/terminal_solaris.go
generated
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// +build solaris
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
func IsTerminal() bool {
|
||||
_, err := unix.IoctlGetTermios(int(os.Stdout.Fd()), unix.TCGETA)
|
||||
return err == nil
|
||||
}
|
||||
27
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/terminal_windows.go
generated
vendored
Normal file
27
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/terminal_windows.go
generated
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// Based on ssh/terminal:
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
|
||||
var (
|
||||
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
||||
)
|
||||
|
||||
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
||||
func IsTerminal() bool {
|
||||
fd := syscall.Stderr
|
||||
var st uint32
|
||||
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
||||
return r != 0 && e == 0
|
||||
}
|
||||
161
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/text_formatter.go
generated
vendored
Normal file
161
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/text_formatter.go
generated
vendored
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
nocolor = 0
|
||||
red = 31
|
||||
green = 32
|
||||
yellow = 33
|
||||
blue = 34
|
||||
gray = 37
|
||||
)
|
||||
|
||||
var (
|
||||
baseTimestamp time.Time
|
||||
isTerminal bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
baseTimestamp = time.Now()
|
||||
isTerminal = IsTerminal()
|
||||
}
|
||||
|
||||
func miniTS() int {
|
||||
return int(time.Since(baseTimestamp) / time.Second)
|
||||
}
|
||||
|
||||
type TextFormatter struct {
|
||||
// Set to true to bypass checking for a TTY before outputting colors.
|
||||
ForceColors bool
|
||||
|
||||
// Force disabling colors.
|
||||
DisableColors bool
|
||||
|
||||
// Disable timestamp logging. useful when output is redirected to logging
|
||||
// system that already adds timestamps.
|
||||
DisableTimestamp bool
|
||||
|
||||
// Enable logging the full timestamp when a TTY is attached instead of just
|
||||
// the time passed since beginning of execution.
|
||||
FullTimestamp bool
|
||||
|
||||
// TimestampFormat to use for display when a full timestamp is printed
|
||||
TimestampFormat string
|
||||
|
||||
// The fields are sorted by default for a consistent output. For applications
|
||||
// that log extremely frequently and don't use the JSON formatter this may not
|
||||
// be desired.
|
||||
DisableSorting bool
|
||||
}
|
||||
|
||||
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
var keys []string = make([]string, 0, len(entry.Data))
|
||||
for k := range entry.Data {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
if !f.DisableSorting {
|
||||
sort.Strings(keys)
|
||||
}
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
|
||||
prefixFieldClashes(entry.Data)
|
||||
|
||||
isColorTerminal := isTerminal && (runtime.GOOS != "windows")
|
||||
isColored := (f.ForceColors || isColorTerminal) && !f.DisableColors
|
||||
|
||||
timestampFormat := f.TimestampFormat
|
||||
if timestampFormat == "" {
|
||||
timestampFormat = DefaultTimestampFormat
|
||||
}
|
||||
if isColored {
|
||||
f.printColored(b, entry, keys, timestampFormat)
|
||||
} else {
|
||||
if !f.DisableTimestamp {
|
||||
f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat))
|
||||
}
|
||||
f.appendKeyValue(b, "level", entry.Level.String())
|
||||
if entry.Message != "" {
|
||||
f.appendKeyValue(b, "msg", entry.Message)
|
||||
}
|
||||
for _, key := range keys {
|
||||
f.appendKeyValue(b, key, entry.Data[key])
|
||||
}
|
||||
}
|
||||
|
||||
b.WriteByte('\n')
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
|
||||
var levelColor int
|
||||
switch entry.Level {
|
||||
case DebugLevel:
|
||||
levelColor = gray
|
||||
case WarnLevel:
|
||||
levelColor = yellow
|
||||
case ErrorLevel, FatalLevel, PanicLevel:
|
||||
levelColor = red
|
||||
default:
|
||||
levelColor = blue
|
||||
}
|
||||
|
||||
levelText := strings.ToUpper(entry.Level.String())[0:4]
|
||||
|
||||
if !f.FullTimestamp {
|
||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
|
||||
} else {
|
||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
|
||||
}
|
||||
for _, k := range keys {
|
||||
v := entry.Data[k]
|
||||
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%+v", levelColor, k, v)
|
||||
}
|
||||
}
|
||||
|
||||
func needsQuoting(text string) bool {
|
||||
for _, ch := range text {
|
||||
if !((ch >= 'a' && ch <= 'z') ||
|
||||
(ch >= 'A' && ch <= 'Z') ||
|
||||
(ch >= '0' && ch <= '9') ||
|
||||
ch == '-' || ch == '.') {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
|
||||
|
||||
b.WriteString(key)
|
||||
b.WriteByte('=')
|
||||
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
if needsQuoting(value) {
|
||||
b.WriteString(value)
|
||||
} else {
|
||||
fmt.Fprintf(b, "%q", value)
|
||||
}
|
||||
case error:
|
||||
errmsg := value.Error()
|
||||
if needsQuoting(errmsg) {
|
||||
b.WriteString(errmsg)
|
||||
} else {
|
||||
fmt.Fprintf(b, "%q", value)
|
||||
}
|
||||
default:
|
||||
fmt.Fprint(b, value)
|
||||
}
|
||||
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
31
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/writer.go
generated
vendored
Normal file
31
integration/vendor/github.com/docker/libcompose/vendor/github.com/Sirupsen/logrus/writer.go
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func (logger *Logger) Writer() *io.PipeWriter {
|
||||
reader, writer := io.Pipe()
|
||||
|
||||
go logger.writerScanner(reader)
|
||||
runtime.SetFinalizer(writer, writerFinalizer)
|
||||
|
||||
return writer
|
||||
}
|
||||
|
||||
func (logger *Logger) writerScanner(reader *io.PipeReader) {
|
||||
scanner := bufio.NewScanner(reader)
|
||||
for scanner.Scan() {
|
||||
logger.Print(scanner.Text())
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
logger.Errorf("Error while reading from Writer: %s", err)
|
||||
}
|
||||
reader.Close()
|
||||
}
|
||||
|
||||
func writerFinalizer(writer *io.PipeWriter) {
|
||||
writer.Close()
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue