...

Source file src/golang.org/x/tools/go/buildutil/overlay.go

Documentation: golang.org/x/tools/go/buildutil

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

View as plain text