github.com/apptainer/singularity@v3.1.1+incompatible/internal/pkg/util/uri/uri.go (about) 1 // Copyright (c) 2018, Sylabs Inc. All rights reserved. 2 // This software is licensed under a 3-clause BSD license. Please consult the 3 // LICENSE.md file distributed with the sources of this project regarding your 4 // rights to use or distribute this software. 5 6 package uri 7 8 import ( 9 "fmt" 10 "strings" 11 ) 12 13 const ( 14 // Library is the keyword for a library ref 15 Library = "library" 16 // Shub is the keyword for a shub ref 17 Shub = "shub" 18 // HTTP is the keyword for http ref 19 HTTP = "http" 20 // HTTPS is the keyword for https ref 21 HTTPS = "https" 22 ) 23 24 // validURIs contains a list of known uris 25 var validURIs = map[string]bool{ 26 "library": true, 27 "shub": true, 28 "docker": true, 29 "docker-archive": true, 30 "docker-daemon": true, 31 "oci": true, 32 "oci-archive": true, 33 "http": true, 34 "https": true, 35 } 36 37 // IsValid returns whether or not the given source is valid 38 func IsValid(source string) (valid bool, err error) { 39 40 u := strings.SplitN(source, ":", 2) 41 42 if len(u) != 2 { 43 return false, fmt.Errorf("Invalid URI %s", source) 44 } 45 46 if _, ok := validURIs[u[0]]; ok { 47 return true, nil 48 } 49 50 return false, fmt.Errorf("Invalid URI %s", source) 51 } 52 53 // GetName turns a transport:ref URI into a name containing the top-level identifier 54 // of the image. For example, docker://godlovedc/lolcow returns lolcow 55 // 56 // Returns "" when not in transport:ref format 57 func GetName(uri string) string { 58 transport, ref := Split(uri) 59 if transport == "" { 60 return "" 61 } 62 63 ref = strings.TrimLeft(ref, "/") // Trim leading "/" characters 64 refSplit := strings.Split(ref, "/") // Split ref into parts 65 66 if transport == HTTP || transport == HTTPS { 67 imageName := refSplit[len(refSplit)-1] 68 return imageName 69 } 70 71 // Default tag is latest 72 tags := []string{"latest"} 73 container := refSplit[len(refSplit)-1] 74 75 if strings.Contains(container, ":") { 76 imageParts := strings.Split(container, ":") 77 container = imageParts[0] 78 tags = []string{imageParts[1]} 79 if strings.Contains(tags[0], ",") { 80 tags = strings.Split(tags[0], ",") 81 } 82 } 83 84 return fmt.Sprintf("%s_%s.sif", container, tags[0]) 85 } 86 87 // Split splits a URI into it's components which can be used directly through containers/image 88 // 89 // This can be tricky if there is no type but a file name contains a colon. 90 // 91 // Examples: 92 // docker://ubuntu -> docker, //ubuntu 93 // docker://ubuntu:18.04 -> docker, //ubuntu:18.04 94 // oci-archive:path/to/archive -> oci-archive, path/to/archive 95 // ubuntu -> "", ubuntu 96 // ubuntu:18.04.img -> "", ubuntu:18.04.img 97 func Split(uri string) (transport string, ref string) { 98 uriSplit := strings.SplitN(uri, ":", 2) 99 if len(uriSplit) == 1 { 100 // no colon 101 return "", uri 102 } 103 104 if uriSplit[1][0:1] == "//" { 105 // the format was ://, so try it whether or not valid URI 106 return uriSplit[0], uriSplit[1] 107 } 108 109 if ok, err := IsValid(uri); ok && err == nil { 110 // also accept recognized URIs 111 return uriSplit[0], uriSplit[1] 112 } 113 114 return "", uri 115 }