1package services
2
3import (
4	"fmt"
5	"regexp"
6	"strings"
7
8	"github.com/docker/distribution/reference"
9)
10
11type Service struct {
12	Service   string
13	Version   string
14	ImageName string
15	Aliases   []string
16}
17
18var referenceRegexpNoPort = regexp.MustCompile(`^(.*?)(|:[0-9]+)(|/.*)$`)
19
20const imageVersionLatest = "latest"
21
22// SplitNameAndVersion parses Docker registry image urls and constructs a struct with correct
23// image url, name, version and aliases
24func SplitNameAndVersion(serviceDescription string) Service {
25	// Try to find matches in e.g. subdomain.domain.tld:8080/namespace/service:version
26	matches := reference.ReferenceRegexp.FindStringSubmatch(serviceDescription)
27	if len(matches) == 0 {
28		return Service{
29			ImageName: serviceDescription,
30			Version:   imageVersionLatest,
31		}
32	}
33
34	// -> subdomain.domain.tld:8080/namespace/service
35	imageWithoutVersion := matches[1]
36	// -> version
37	imageVersion := matches[2]
38
39	registryMatches := referenceRegexpNoPort.FindStringSubmatch(imageWithoutVersion)
40	// -> subdomain.domain.tld
41	registry := registryMatches[1]
42	// -> /namespace/service
43	imageName := registryMatches[3]
44
45	service := Service{}
46	service.Service = registry + imageName
47
48	if len(imageVersion) > 0 {
49		service.ImageName = serviceDescription
50		service.Version = imageVersion
51	} else {
52		service.ImageName = fmt.Sprintf("%s:%s", imageWithoutVersion, imageVersionLatest)
53		service.Version = imageVersionLatest
54	}
55
56	alias := strings.ReplaceAll(service.Service, "/", "__")
57	service.Aliases = append(service.Aliases, alias)
58
59	// Create alternative link name according to RFC 1123
60	// Where you can use only `a-zA-Z0-9-`
61	alternativeName := strings.ReplaceAll(service.Service, "/", "-")
62	if alias != alternativeName {
63		service.Aliases = append(service.Aliases, alternativeName)
64	}
65
66	return service
67}
68