github.com/docker-library/go-dockerlibrary@v0.0.0-20200821205225-669fbe5c1d52/manifest/fetch.go (about)

     1  package manifest
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"net/url"
     7  	"os"
     8  	"path/filepath"
     9  	"strings"
    10  )
    11  
    12  func validateTagName(man *Manifest2822, repoName, tagName string) error {
    13  	if tagName != "" && (man.GetTag(tagName) == nil && len(man.GetSharedTag(tagName)) == 0) {
    14  		return fmt.Errorf("tag not found in manifest for %q: %q", repoName, tagName)
    15  	}
    16  	return nil
    17  }
    18  
    19  // "library" is the default "library directory"
    20  // returns the parsed version of (in order):
    21  //   if "repo" is a URL, the remote contents of that URL
    22  //   if "repo" is a relative path like "./repo", that file
    23  //   the file "library/repo"
    24  // (repoName, tagName, man, err)
    25  func Fetch(library, repo string) (string, string, *Manifest2822, error) {
    26  	repoName := filepath.Base(repo)
    27  	tagName := ""
    28  	if tagIndex := strings.IndexRune(repoName, ':'); tagIndex > 0 {
    29  		tagName = repoName[tagIndex+1:]
    30  		repoName = repoName[:tagIndex]
    31  		repo = strings.TrimSuffix(repo, ":"+tagName)
    32  	}
    33  
    34  	u, err := url.Parse(repo)
    35  	if err == nil && u.IsAbs() && (u.Scheme == "http" || u.Scheme == "https") {
    36  		// must be remote URL!
    37  		resp, err := http.Get(repo)
    38  		if err != nil {
    39  			return repoName, tagName, nil, err
    40  		}
    41  		defer resp.Body.Close()
    42  		man, err := Parse(resp.Body)
    43  		if err != nil {
    44  			return repoName, tagName, man, err
    45  		}
    46  		return repoName, tagName, man, validateTagName(man, repoName, tagName)
    47  	}
    48  
    49  	// try file paths
    50  	filePaths := []string{}
    51  	if filepath.IsAbs(repo) || strings.IndexRune(repo, filepath.Separator) >= 0 || strings.IndexRune(repo, '/') >= 0 {
    52  		filePaths = append(filePaths, repo)
    53  	}
    54  	if !filepath.IsAbs(repo) {
    55  		filePaths = append(filePaths, filepath.Join(library, repo))
    56  	}
    57  	for _, fileName := range filePaths {
    58  		f, err := os.Open(fileName)
    59  		if err != nil && !os.IsNotExist(err) {
    60  			return repoName, tagName, nil, err
    61  		}
    62  		if err == nil {
    63  			defer f.Close()
    64  			man, err := Parse(f)
    65  			if err != nil {
    66  				return repoName, tagName, man, err
    67  			}
    68  			return repoName, tagName, man, validateTagName(man, repoName, tagName)
    69  		}
    70  	}
    71  
    72  	return repoName, tagName, nil, fmt.Errorf("unable to find a manifest named %q (in %q or as a remote URL)", repo, library)
    73  }