github.com/cvmfs/docker-graphdriver@v0.0.0-20181206110523-155ec6df0521/repository-manager/lib/parse.go (about)

     1  package lib
     2  
     3  import (
     4  	"fmt"
     5  	"net/url"
     6  	"strings"
     7  )
     8  
     9  func ParseImage(image string) (img Image, err error) {
    10  	url, err := url.Parse(image)
    11  	if err != nil {
    12  		return Image{}, err
    13  	}
    14  	if url.Host == "" {
    15  		return Image{}, fmt.Errorf("Impossible to identify the registry of the image: %s", image)
    16  	}
    17  	if url.Path == "" {
    18  		return Image{}, fmt.Errorf("Impossible to identify the repository of the image: %s", image)
    19  	}
    20  	colonPathSplitted := strings.Split(url.Path, ":")
    21  	if len(colonPathSplitted) == 0 {
    22  		return Image{}, fmt.Errorf("Impossible to identify the path of the image: %s", image)
    23  	}
    24  	// no split happened, hence we don't have neither a tag nor a digest, but only a path
    25  	if len(colonPathSplitted) == 1 {
    26  
    27  		// we remove the first  and the trailing `/`
    28  		repository := strings.TrimLeft(colonPathSplitted[0], "/")
    29  		repository = strings.TrimRight(repository, "/")
    30  		if repository == "" {
    31  			return Image{}, fmt.Errorf("Impossible to find the repository for: %s", image)
    32  		}
    33  		return Image{
    34  			Scheme:     url.Scheme,
    35  			Registry:   url.Host,
    36  			Repository: repository,
    37  		}, nil
    38  
    39  	}
    40  	if len(colonPathSplitted) > 3 {
    41  		fmt.Println(colonPathSplitted)
    42  		return Image{}, fmt.Errorf("Impossible to parse the string into an image, too many `:` in : %s", image)
    43  	}
    44  	// the colon `:` is used also as separator in the digest between sha256
    45  	// and the actuall digest, a len(pathSplitted) == 2 could either means
    46  	// a repository and a tag or a repository and an hash, in the case of
    47  	// the hash however the split will be more complex.  Now we split for
    48  	// the at `@` which separate the digest from everything else. If this
    49  	// split produce only one result we have a repository and maybe a tag,
    50  	// if it produce two we have a repository, maybe a tag and definitely a
    51  	// digest, if it produce more than two we have an error.
    52  	atPathSplitted := strings.Split(url.Path, "@")
    53  	if len(atPathSplitted) > 2 {
    54  		return Image{}, fmt.Errorf("To many `@` in the image name: %s", image)
    55  	}
    56  	var repoTag, digest string
    57  	if len(atPathSplitted) == 2 {
    58  		digest = atPathSplitted[1]
    59  		repoTag = atPathSplitted[0]
    60  	}
    61  	if len(atPathSplitted) == 1 {
    62  		repoTag = atPathSplitted[0]
    63  	}
    64  	// finally we break up also the repoTag to find out if we have also a
    65  	// tag or just a repository name
    66  	colonRepoTagSplitted := strings.Split(repoTag, ":")
    67  
    68  	// only the repository, without the tag
    69  	if len(colonRepoTagSplitted) == 1 {
    70  		repository := strings.TrimLeft(colonRepoTagSplitted[0], "/")
    71  		repository = strings.TrimRight(repository, "/")
    72  		if repository == "" {
    73  			return Image{}, fmt.Errorf("Impossible to find the repository for: %s", image)
    74  		}
    75  		return Image{
    76  			Scheme:     url.Scheme,
    77  			Registry:   url.Host,
    78  			Repository: repository,
    79  			Digest:     digest,
    80  		}, nil
    81  	}
    82  
    83  	// both repository and tag
    84  	if len(colonRepoTagSplitted) == 2 {
    85  		repository := strings.TrimLeft(colonRepoTagSplitted[0], "/")
    86  		repository = strings.TrimRight(repository, "/")
    87  		if repository == "" {
    88  			return Image{}, fmt.Errorf("Impossible to find the repository for: %s", image)
    89  		}
    90  		return Image{
    91  			Scheme:     url.Scheme,
    92  			Registry:   url.Host,
    93  			Repository: repository,
    94  			Tag:        colonRepoTagSplitted[1],
    95  			Digest:     digest,
    96  		}, nil
    97  	}
    98  	return Image{}, fmt.Errorf("Impossible to parse the image: %s", image)
    99  }