github.com/sudharsh/packer@v0.4.1/common/config.go (about) 1 package common 2 3 import ( 4 "fmt" 5 "github.com/mitchellh/mapstructure" 6 "github.com/mitchellh/packer/packer" 7 "net/url" 8 "os" 9 "path/filepath" 10 "runtime" 11 "sort" 12 "strings" 13 ) 14 15 // ScrubConfig is a helper that returns a string representation of 16 // any struct with the given values stripped out. 17 func ScrubConfig(target interface{}, values ...string) string { 18 conf := fmt.Sprintf("Config: %+v", target) 19 for _, value := range values { 20 conf = strings.Replace(conf, value, "<Filtered>", -1) 21 } 22 return conf 23 } 24 25 // CheckUnusedConfig is a helper that makes sure that the there are no 26 // unused configuration keys, properly ignoring keys that don't matter. 27 func CheckUnusedConfig(md *mapstructure.Metadata) *packer.MultiError { 28 errs := make([]error, 0) 29 30 if md.Unused != nil && len(md.Unused) > 0 { 31 sort.Strings(md.Unused) 32 for _, unused := range md.Unused { 33 if unused != "type" && !strings.HasPrefix(unused, "packer_") { 34 errs = append( 35 errs, fmt.Errorf("Unknown configuration key: %s", unused)) 36 } 37 } 38 } 39 40 if len(errs) > 0 { 41 return &packer.MultiError{errs} 42 } 43 44 return nil 45 } 46 47 // DecodeConfig is a helper that handles decoding raw configuration using 48 // mapstructure. It returns the metadata and any errors that may happen. 49 // If you need extra configuration for mapstructure, you should configure 50 // it manually and not use this helper function. 51 func DecodeConfig(target interface{}, raws ...interface{}) (*mapstructure.Metadata, error) { 52 var md mapstructure.Metadata 53 decoderConfig := &mapstructure.DecoderConfig{ 54 Metadata: &md, 55 Result: target, 56 WeaklyTypedInput: true, 57 } 58 59 decoder, err := mapstructure.NewDecoder(decoderConfig) 60 if err != nil { 61 return nil, err 62 } 63 64 for _, raw := range raws { 65 err := decoder.Decode(raw) 66 if err != nil { 67 return nil, err 68 } 69 } 70 71 return &md, nil 72 } 73 74 // DownloadableURL processes a URL that may also be a file path and returns 75 // a completely valid URL. For example, the original URL might be "local/file.iso" 76 // which isn't a valid URL. DownloadableURL will return "file:///local/file.iso" 77 func DownloadableURL(original string) (string, error) { 78 if runtime.GOOS == "windows" { 79 // If the distance to the first ":" is just one character, assume 80 // we're dealing with a drive letter and thus a file path. 81 idx := strings.Index(original, ":") 82 if idx == 1 { 83 original = "file:///" + original 84 } 85 } 86 87 url, err := url.Parse(original) 88 if err != nil { 89 return "", err 90 } 91 92 if url.Scheme == "" { 93 url.Scheme = "file" 94 } 95 96 if url.Scheme == "file" { 97 // For Windows absolute file paths, remove leading / prior to processing 98 // since net/url turns "C:/" into "/C:/" 99 if runtime.GOOS == "windows" && url.Path[0] == '/' { 100 url.Path = url.Path[1:len(url.Path)] 101 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 // Only do the filepath transformations if the file appears 109 // to actually exist. 110 if _, err := os.Stat(url.Path); err == nil { 111 url.Path, err = filepath.Abs(url.Path) 112 if err != nil { 113 return "", err 114 } 115 116 url.Path, err = filepath.EvalSymlinks(url.Path) 117 if err != nil { 118 return "", err 119 } 120 121 url.Path = filepath.Clean(url.Path) 122 } 123 } 124 125 // Make sure it is lowercased 126 url.Scheme = strings.ToLower(url.Scheme) 127 128 // This is to work around issue #5927. This can safely be removed once 129 // we distribute with a version of Go that fixes that bug. 130 // 131 // See: https://code.google.com/p/go/issues/detail?id=5927 132 if url.Path != "" && url.Path[0] != '/' { 133 url.Path = "/" + url.Path 134 } 135 136 // Verify that the scheme is something we support in our common downloader. 137 supported := []string{"file", "http", "https"} 138 found := false 139 for _, s := range supported { 140 if url.Scheme == s { 141 found = true 142 break 143 } 144 } 145 146 if !found { 147 return "", fmt.Errorf("Unsupported URL scheme: %s", url.Scheme) 148 } 149 150 return url.String(), nil 151 }