diff --git a/opts/opts.go b/opts/opts.go new file mode 100644 index 0000000..a1b8752 --- /dev/null +++ b/opts/opts.go @@ -0,0 +1,148 @@ +package opts + +import ( + "fmt" + "github.com/dotcloud/docker/utils" + "os" + "path/filepath" + "regexp" + "strings" +) + +// ListOpts type +type ListOpts struct { + values []string + validator ValidatorFctType +} + +func NewListOpts(validator ValidatorFctType) ListOpts { + return ListOpts{ + validator: validator, + } +} + +func (opts *ListOpts) String() string { + return fmt.Sprintf("%v", []string(opts.values)) +} + +// Set validates if needed the input value and add it to the +// internal slice. +func (opts *ListOpts) Set(value string) error { + if opts.validator != nil { + v, err := opts.validator(value) + if err != nil { + return err + } + value = v + } + opts.values = append(opts.values, value) + return nil +} + +// Delete remove the given element from the slice. +func (opts *ListOpts) Delete(key string) { + for i, k := range opts.values { + if k == key { + opts.values = append(opts.values[:i], opts.values[i+1:]...) + return + } + } +} + +// GetMap returns the content of values in a map in order to avoid +// duplicates. +// FIXME: can we remove this? +func (opts *ListOpts) GetMap() map[string]struct{} { + ret := make(map[string]struct{}) + for _, k := range opts.values { + ret[k] = struct{}{} + } + return ret +} + +// GetAll returns the values' slice. +// FIXME: Can we remove this? +func (opts *ListOpts) GetAll() []string { + return opts.values +} + +// Get checks the existence of the given key. +func (opts *ListOpts) Get(key string) bool { + for _, k := range opts.values { + if k == key { + return true + } + } + return false +} + +// Len returns the amount of element in the slice. +func (opts *ListOpts) Len() int { + return len(opts.values) +} + +// Validators +type ValidatorFctType func(val string) (string, error) + +func ValidateAttach(val string) (string, error) { + if val != "stdin" && val != "stdout" && val != "stderr" { + return val, fmt.Errorf("Unsupported stream name: %s", val) + } + return val, nil +} + +func ValidateLink(val string) (string, error) { + if _, err := parseLink(val); err != nil { + return val, err + } + return val, nil +} + +// FIXME: this is a duplicate of docker.utils.parseLink. +// it can't be moved to a separate links/ package because +// links depends on Container which is defined in the core. +// +// Links come in the format of +// name:alias +func parseLink(rawLink string) (map[string]string, error) { + return utils.PartParser("name:alias", rawLink) +} + +func ValidatePath(val string) (string, error) { + var containerPath string + + if strings.Count(val, ":") > 2 { + return val, fmt.Errorf("bad format for volumes: %s", val) + } + + splited := strings.SplitN(val, ":", 2) + if len(splited) == 1 { + containerPath = splited[0] + val = filepath.Clean(splited[0]) + } else { + containerPath = splited[1] + val = fmt.Sprintf("%s:%s", splited[0], filepath.Clean(splited[1])) + } + + if !filepath.IsAbs(containerPath) { + return val, fmt.Errorf("%s is not an absolute path", containerPath) + } + return val, nil +} + +func ValidateEnv(val string) (string, error) { + arr := strings.Split(val, "=") + if len(arr) > 1 { + return val, nil + } + return fmt.Sprintf("%s=%s", val, os.Getenv(val)), nil +} + +func ValidateIp4Address(val string) (string, error) { + re := regexp.MustCompile(`^(([0-9]+\.){3}([0-9]+))\s*$`) + var ns = re.FindSubmatch([]byte(val)) + if len(ns) > 0 { + return string(ns[1]), nil + } + return "", fmt.Errorf("%s is not an ip4 address", val) +} diff --git a/opts/opts_test.go b/opts/opts_test.go new file mode 100644 index 0000000..a5c1fac --- /dev/null +++ b/opts/opts_test.go @@ -0,0 +1,24 @@ +package opts + +import ( + "testing" +) + +func TestValidateIP4(t *testing.T) { + if ret, err := ValidateIp4Address(`1.2.3.4`); err != nil || ret == "" { + t.Fatalf("ValidateIp4Address(`1.2.3.4`) got %s %s", ret, err) + } + + if ret, err := ValidateIp4Address(`127.0.0.1`); err != nil || ret == "" { + t.Fatalf("ValidateIp4Address(`127.0.0.1`) got %s %s", ret, err) + } + + if ret, err := ValidateIp4Address(`127`); err == nil || ret != "" { + t.Fatalf("ValidateIp4Address(`127`) got %s %s", ret, err) + } + + if ret, err := ValidateIp4Address(`random invalid string`); err == nil || ret != "" { + t.Fatalf("ValidateIp4Address(`random invalid string`) got %s %s", ret, err) + } + +}