github.com/pankona/gometalinter@v2.0.11+incompatible/_linters/src/golang.org/x/tools/go/buildutil/overlay.go (about) 1 // Copyright 2016 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package buildutil 6 7 import ( 8 "bufio" 9 "bytes" 10 "fmt" 11 "go/build" 12 "io" 13 "io/ioutil" 14 "path/filepath" 15 "strconv" 16 "strings" 17 ) 18 19 // OverlayContext overlays a build.Context with additional files from 20 // a map. Files in the map take precedence over other files. 21 // 22 // In addition to plain string comparison, two file names are 23 // considered equal if their base names match and their directory 24 // components point at the same directory on the file system. That is, 25 // symbolic links are followed for directories, but not files. 26 // 27 // A common use case for OverlayContext is to allow editors to pass in 28 // a set of unsaved, modified files. 29 // 30 // Currently, only the Context.OpenFile function will respect the 31 // overlay. This may change in the future. 32 func OverlayContext(orig *build.Context, overlay map[string][]byte) *build.Context { 33 // TODO(dominikh): Implement IsDir, HasSubdir and ReadDir 34 35 rc := func(data []byte) (io.ReadCloser, error) { 36 return ioutil.NopCloser(bytes.NewBuffer(data)), nil 37 } 38 39 copy := *orig // make a copy 40 ctxt := © 41 ctxt.OpenFile = func(path string) (io.ReadCloser, error) { 42 // Fast path: names match exactly. 43 if content, ok := overlay[path]; ok { 44 return rc(content) 45 } 46 47 // Slow path: check for same file under a different 48 // alias, perhaps due to a symbolic link. 49 for filename, content := range overlay { 50 if sameFile(path, filename) { 51 return rc(content) 52 } 53 } 54 55 return OpenFile(orig, path) 56 } 57 return ctxt 58 } 59 60 // ParseOverlayArchive parses an archive containing Go files and their 61 // contents. The result is intended to be used with OverlayContext. 62 // 63 // 64 // Archive format 65 // 66 // The archive consists of a series of files. Each file consists of a 67 // name, a decimal file size and the file contents, separated by 68 // newlinews. No newline follows after the file contents. 69 func ParseOverlayArchive(archive io.Reader) (map[string][]byte, error) { 70 overlay := make(map[string][]byte) 71 r := bufio.NewReader(archive) 72 for { 73 // Read file name. 74 filename, err := r.ReadString('\n') 75 if err != nil { 76 if err == io.EOF { 77 break // OK 78 } 79 return nil, fmt.Errorf("reading archive file name: %v", err) 80 } 81 filename = filepath.Clean(strings.TrimSpace(filename)) 82 83 // Read file size. 84 sz, err := r.ReadString('\n') 85 if err != nil { 86 return nil, fmt.Errorf("reading size of archive file %s: %v", filename, err) 87 } 88 sz = strings.TrimSpace(sz) 89 size, err := strconv.ParseUint(sz, 10, 32) 90 if err != nil { 91 return nil, fmt.Errorf("parsing size of archive file %s: %v", filename, err) 92 } 93 94 // Read file content. 95 content := make([]byte, size) 96 if _, err := io.ReadFull(r, content); err != nil { 97 return nil, fmt.Errorf("reading archive file %s: %v", filename, err) 98 } 99 overlay[filename] = content 100 } 101 102 return overlay, nil 103 }