github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/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 }