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