func ParseRepositoryInfo(reposName string) (*RepositoryInfo, error) {
	return emptyServiceConfig.NewRepositoryInfo(reposName)
}
ParseRepositoryInfo performs the breakdown of a repository name into a RepositoryInfo, but
lacks registry configuration.
package registry
import (
	"encoding/json"
	"errors"
	"fmt"
	"net"
	"net/url"
	"regexp"
	"strings"
	"github.com/docker/docker/opts"
	flag "github.com/docker/docker/pkg/mflag"
	"github.com/docker/docker/utils"
)
type Options struct {
	Mirrors            opts.ListOpts
	InsecureRegistries opts.ListOpts
}
const (
	INDEXSERVER    = "https://index.docker.io/v1/"
	REGISTRYSERVER = "https://registry-1.docker.io/v2/"
	INDEXNAME      = "docker.io"
)
var (
	ErrInvalidRepositoryName = errors.New("Invalid repository name (ex: \"registry.domain.tld/myrepos\")")
	emptyServiceConfig       = NewServiceConfig(nil)
	validNamespaceChars      = regexp.MustCompile(`^([a-z0-9-_]*)$`)
	validRepo                = regexp.MustCompile(`^([a-z0-9-_.]+)$`)
)
func IndexServerAddress() string {
	return INDEXSERVER
}
func IndexServerName() string {
	return INDEXNAME
}
func (options *Options) InstallFlags() {
	options.Mirrors = opts.NewListOpts(ValidateMirror)
	flag.Var(&options.Mirrors, []string{"-registry-mirror"}, "Specify a preferred Docker registry mirror")
	options.InsecureRegistries = opts.NewListOpts(ValidateIndexName)
	flag.Var(&options.InsecureRegistries, []string{"-insecure-registry"}, "Enable insecure communication with specified registries (no certificate verification for HTTPS and enable HTTP fallback) (e.g., localhost:5000 or 10.20.0.0/16)")
}
type netIPNet net.IPNet
func (ipnet *netIPNet) MarshalJSON() ([]byte, error) {
	return json.Marshal((*net.IPNet)(ipnet).String())
}
func (ipnet *netIPNet) UnmarshalJSON(b []byte) (err error) {
	var ipnet_str string
	if err = json.Unmarshal(b, &ipnet_str); err == nil {
		var cidr *net.IPNet
		if _, cidr, err = net.ParseCIDR(ipnet_str); err == nil {
			*ipnet = netIPNet(*cidr)
		}
	}
	return
}
type ServiceConfig struct {
	InsecureRegistryCIDRs []*netIPNet           `json:"InsecureRegistryCIDRs"`
	IndexConfigs          map[string]*IndexInfo `json:"IndexConfigs"`
}
func NewServiceConfig(options *Options) *ServiceConfig {
	if options == nil {
		options = &Options{
			Mirrors:            opts.NewListOpts(nil),
			InsecureRegistries: opts.NewListOpts(nil),
		}
	}
	options.InsecureRegistries.Set("127.0.0.0/8")
	config := &ServiceConfig{
		InsecureRegistryCIDRs: make([]*netIPNet, 0),
		IndexConfigs:          make(map[string]*IndexInfo, 0),
	}
	for _, r := range options.InsecureRegistries.GetAll() {
		_, ipnet, err := net.ParseCIDR(r)
		if err == nil {
			config.InsecureRegistryCIDRs = append(config.InsecureRegistryCIDRs, (*netIPNet)(ipnet))
		} else {
			config.IndexConfigs[r] = &IndexInfo{
				Name:     r,
				Mirrors:  make([]string, 0),
				Secure:   false,
				Official: false,
			}
		}
	}
	config.IndexConfigs[IndexServerName()] = &IndexInfo{
		Name:     IndexServerName(),
		Mirrors:  options.Mirrors.GetAll(),
		Secure:   true,
		Official: true,
	}
	return config
}
func (config *ServiceConfig) isSecureIndex(indexName string) bool {
	if index, ok := config.IndexConfigs[indexName]; ok {
		return index.Secure
	}
	host, _, err := net.SplitHostPort(indexName)
	if err != nil {
		host = indexName
	}
	addrs, err := lookupIP(host)
	if err != nil {
		ip := net.ParseIP(host)
		if ip != nil {
			addrs = []net.IP{ip}
		}
	}
	for _, addr := range addrs {
		for _, ipnet := range config.InsecureRegistryCIDRs {
			if (*net.IPNet)(ipnet).Contains(addr) {
				return false
			}
		}
	}
	return true
}
func ValidateMirror(val string) (string, error) {
	uri, err := url.Parse(val)
	if err != nil {
		return "", fmt.Errorf("%s is not a valid URI", val)
	}
	if uri.Scheme != "http" && uri.Scheme != "https" {
		return "", fmt.Errorf("Unsupported scheme %s", uri.Scheme)
	}
	if uri.Path != "" || uri.RawQuery != "" || uri.Fragment != "" {
		return "", fmt.Errorf("Unsupported path/query/fragment at end of the URI")
	}
	return fmt.Sprintf("%s://%s/v1/", uri.Scheme, uri.Host), nil
}
func ValidateIndexName(val string) (string, error) {
	if val == "index."+IndexServerName() {
		val = IndexServerName()
	}
	return val, nil
}
func validateRemoteName(remoteName string) error {
	var (
		namespace string
		name      string
	)
	nameParts := strings.SplitN(remoteName, "/", 2)
	if len(nameParts) < 2 {
		namespace = "library"
		name = nameParts[0]
		if err := utils.ValidateID(name); err == nil {
			return fmt.Errorf("Invalid repository name (%s), cannot specify 64-byte hexadecimal strings", name)
		}
	} else {
		namespace = nameParts[0]
		name = nameParts[1]
	}
	if !validNamespaceChars.MatchString(namespace) {
		return fmt.Errorf("Invalid namespace name (%s). Only [a-z0-9-_] are allowed.", namespace)
	}
	if len(namespace) < 4 || len(namespace) > 30 {
		return fmt.Errorf("Invalid namespace name (%s). Cannot be fewer than 4 or more than 30 characters.", namespace)
	}
	if strings.HasPrefix(namespace, "-") || strings.HasSuffix(namespace, "-") {
		return fmt.Errorf("Invalid namespace name (%s). Cannot begin or end with a hyphen.", namespace)
	}
	if strings.Contains(namespace, "--") {
		return fmt.Errorf("Invalid namespace name (%s). Cannot contain consecutive hyphens.", namespace)
	}
	if !validRepo.MatchString(name) {
		return fmt.Errorf("Invalid repository name (%s), only [a-z0-9-_.] are allowed", name)
	}
	return nil
}
func validateNoSchema(reposName string) error {
	if strings.Contains(reposName, "://") {
		return ErrInvalidRepositoryName
	}
	return nil
}
func ValidateRepositoryName(reposName string) error {
	var err error
	if err = validateNoSchema(reposName); err != nil {
		return err
	}
	indexName, remoteName := splitReposName(reposName)
	if _, err = ValidateIndexName(indexName); err != nil {
		return err
	}
	return validateRemoteName(remoteName)
}
func (config *ServiceConfig) NewIndexInfo(indexName string) (*IndexInfo, error) {
	var err error
	indexName, err = ValidateIndexName(indexName)
	if err != nil {
		return nil, err
	}
	if index, ok := config.IndexConfigs[indexName]; ok {
		return index, nil
	}
	index := &IndexInfo{
		Name:     indexName,
		Mirrors:  make([]string, 0),
		Official: false,
	}
	index.Secure = config.isSecureIndex(indexName)
	return index, nil
}
func (index *IndexInfo) GetAuthConfigKey() string {
	if index.Official {
		return IndexServerAddress()
	}
	return index.Name
}
func splitReposName(reposName string) (string, string) {
	nameParts := strings.SplitN(reposName, "/", 2)
	var indexName, remoteName string
	if len(nameParts) == 1 || (!strings.Contains(nameParts[0], ".") &&
		!strings.Contains(nameParts[0], ":") && nameParts[0] != "localhost") {
		indexName = IndexServerName()
		remoteName = reposName
	} else {
		indexName = nameParts[0]
		remoteName = nameParts[1]
	}
	return indexName, remoteName
}
func (config *ServiceConfig) NewRepositoryInfo(reposName string) (*RepositoryInfo, error) {
	if err := validateNoSchema(reposName); err != nil {
		return nil, err
	}
	indexName, remoteName := splitReposName(reposName)
	if err := validateRemoteName(remoteName); err != nil {
		return nil, err
	}
	repoInfo := &RepositoryInfo{
		RemoteName: remoteName,
	}
	var err error
	repoInfo.Index, err = config.NewIndexInfo(indexName)
	if err != nil {
		return nil, err
	}
	if repoInfo.Index.Official {
		normalizedName := repoInfo.RemoteName
		if strings.HasPrefix(normalizedName, "library/") {
			normalizedName = strings.SplitN(normalizedName, "/", 2)[1]
		}
		repoInfo.LocalName = normalizedName
		repoInfo.RemoteName = normalizedName
		if strings.IndexRune(normalizedName, '/') == -1 {
			repoInfo.Official = true
			repoInfo.RemoteName = "library/" + normalizedName
		}
		repoInfo.CanonicalName = repoInfo.LocalName
	} else {
		repoInfo.LocalName = repoInfo.Index.Name + "/" + repoInfo.RemoteName
		repoInfo.CanonicalName = repoInfo.LocalName
	}
	return repoInfo, nil
}
func (repoInfo *RepositoryInfo) GetSearchTerm() string {
	if repoInfo.Index.Official {
		return repoInfo.LocalName
	}
	return repoInfo.RemoteName
}