github.com/amanya/packer@v0.12.1-0.20161117214323-902ac5ab2eb6/common/config.go (about)

     1  package common
     2  
     3  import (
     4  	"fmt"
     5  	"net/url"
     6  	"os"
     7  	"path/filepath"
     8  	"runtime"
     9  	"strings"
    10  )
    11  
    12  // ScrubConfig is a helper that returns a string representation of
    13  // any struct with the given values stripped out.
    14  func ScrubConfig(target interface{}, values ...string) string {
    15  	conf := fmt.Sprintf("Config: %+v", target)
    16  	for _, value := range values {
    17  		if value == "" {
    18  			continue
    19  		}
    20  		conf = strings.Replace(conf, value, "<Filtered>", -1)
    21  	}
    22  	return conf
    23  }
    24  
    25  // ChooseString returns the first non-empty value.
    26  func ChooseString(vals ...string) string {
    27  	for _, el := range vals {
    28  		if el != "" {
    29  			return el
    30  		}
    31  	}
    32  
    33  	return ""
    34  }
    35  
    36  // DownloadableURL processes a URL that may also be a file path and returns
    37  // a completely valid URL. For example, the original URL might be "local/file.iso"
    38  // which isn't a valid URL. DownloadableURL will return "file:///local/file.iso"
    39  func DownloadableURL(original string) (string, error) {
    40  	if runtime.GOOS == "windows" {
    41  		// If the distance to the first ":" is just one character, assume
    42  		// we're dealing with a drive letter and thus a file path.
    43  		idx := strings.Index(original, ":")
    44  		if idx == 1 {
    45  			original = "file:///" + original
    46  		}
    47  	}
    48  
    49  	url, err := url.Parse(original)
    50  	if err != nil {
    51  		return "", err
    52  	}
    53  
    54  	if url.Scheme == "" {
    55  		url.Scheme = "file"
    56  	}
    57  
    58  	if url.Scheme == "file" {
    59  		// Windows file handling is all sorts of tricky...
    60  		if runtime.GOOS == "windows" {
    61  			// If the path is using Windows-style slashes, URL parses
    62  			// it into the host field.
    63  			if url.Path == "" && strings.Contains(url.Host, `\`) {
    64  				url.Path = url.Host
    65  				url.Host = ""
    66  			}
    67  
    68  			// For Windows absolute file paths, remove leading / prior to processing
    69  			// since net/url turns "C:/" into "/C:/"
    70  			if len(url.Path) > 0 && url.Path[0] == '/' {
    71  				url.Path = url.Path[1:len(url.Path)]
    72  			}
    73  		}
    74  
    75  		// Only do the filepath transformations if the file appears
    76  		// to actually exist.
    77  		if _, err := os.Stat(url.Path); err == nil {
    78  			url.Path, err = filepath.Abs(url.Path)
    79  			if err != nil {
    80  				return "", err
    81  			}
    82  
    83  			url.Path, err = filepath.EvalSymlinks(url.Path)
    84  			if err != nil {
    85  				return "", err
    86  			}
    87  
    88  			url.Path = filepath.Clean(url.Path)
    89  		}
    90  
    91  		if runtime.GOOS == "windows" {
    92  			// Also replace all backslashes with forwardslashes since Windows
    93  			// users are likely to do this but the URL should actually only
    94  			// contain forward slashes.
    95  			url.Path = strings.Replace(url.Path, `\`, `/`, -1)
    96  		}
    97  	}
    98  
    99  	// Make sure it is lowercased
   100  	url.Scheme = strings.ToLower(url.Scheme)
   101  
   102  	// This is to work around issue #5927. This can safely be removed once
   103  	// we distribute with a version of Go that fixes that bug.
   104  	//
   105  	// See: https://code.google.com/p/go/issues/detail?id=5927
   106  	if url.Path != "" && url.Path[0] != '/' {
   107  		url.Path = "/" + url.Path
   108  	}
   109  
   110  	// Verify that the scheme is something we support in our common downloader.
   111  	supported := []string{"file", "http", "https"}
   112  	found := false
   113  	for _, s := range supported {
   114  		if url.Scheme == s {
   115  			found = true
   116  			break
   117  		}
   118  	}
   119  
   120  	if !found {
   121  		return "", fmt.Errorf("Unsupported URL scheme: %s", url.Scheme)
   122  	}
   123  
   124  	return url.String(), nil
   125  }