435c0d9fc8
This PR switches the Nomad repository from using govendor to Go modules for managing dependencies. Aspects of the Nomad workflow remain pretty much the same. The usual Makefile targets should continue to work as they always did. The API submodule simply defers to the parent Nomad version on the repository, keeping the semantics of API versioning that currently exists.
104 lines
2.9 KiB
Go
104 lines
2.9 KiB
Go
// Copyright 2016 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package buildutil
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"fmt"
|
|
"go/build"
|
|
"io"
|
|
"io/ioutil"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// OverlayContext overlays a build.Context with additional files from
|
|
// a map. Files in the map take precedence over other files.
|
|
//
|
|
// In addition to plain string comparison, two file names are
|
|
// considered equal if their base names match and their directory
|
|
// components point at the same directory on the file system. That is,
|
|
// symbolic links are followed for directories, but not files.
|
|
//
|
|
// A common use case for OverlayContext is to allow editors to pass in
|
|
// a set of unsaved, modified files.
|
|
//
|
|
// Currently, only the Context.OpenFile function will respect the
|
|
// overlay. This may change in the future.
|
|
func OverlayContext(orig *build.Context, overlay map[string][]byte) *build.Context {
|
|
// TODO(dominikh): Implement IsDir, HasSubdir and ReadDir
|
|
|
|
rc := func(data []byte) (io.ReadCloser, error) {
|
|
return ioutil.NopCloser(bytes.NewBuffer(data)), nil
|
|
}
|
|
|
|
copy := *orig // make a copy
|
|
ctxt := ©
|
|
ctxt.OpenFile = func(path string) (io.ReadCloser, error) {
|
|
// Fast path: names match exactly.
|
|
if content, ok := overlay[path]; ok {
|
|
return rc(content)
|
|
}
|
|
|
|
// Slow path: check for same file under a different
|
|
// alias, perhaps due to a symbolic link.
|
|
for filename, content := range overlay {
|
|
if sameFile(path, filename) {
|
|
return rc(content)
|
|
}
|
|
}
|
|
|
|
return OpenFile(orig, path)
|
|
}
|
|
return ctxt
|
|
}
|
|
|
|
// ParseOverlayArchive parses an archive containing Go files and their
|
|
// contents. The result is intended to be used with OverlayContext.
|
|
//
|
|
//
|
|
// Archive format
|
|
//
|
|
// The archive consists of a series of files. Each file consists of a
|
|
// name, a decimal file size and the file contents, separated by
|
|
// newlines. No newline follows after the file contents.
|
|
func ParseOverlayArchive(archive io.Reader) (map[string][]byte, error) {
|
|
overlay := make(map[string][]byte)
|
|
r := bufio.NewReader(archive)
|
|
for {
|
|
// Read file name.
|
|
filename, err := r.ReadString('\n')
|
|
if err != nil {
|
|
if err == io.EOF {
|
|
break // OK
|
|
}
|
|
return nil, fmt.Errorf("reading archive file name: %v", err)
|
|
}
|
|
filename = filepath.Clean(strings.TrimSpace(filename))
|
|
|
|
// Read file size.
|
|
sz, err := r.ReadString('\n')
|
|
if err != nil {
|
|
return nil, fmt.Errorf("reading size of archive file %s: %v", filename, err)
|
|
}
|
|
sz = strings.TrimSpace(sz)
|
|
size, err := strconv.ParseUint(sz, 10, 32)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("parsing size of archive file %s: %v", filename, err)
|
|
}
|
|
|
|
// Read file content.
|
|
content := make([]byte, size)
|
|
if _, err := io.ReadFull(r, content); err != nil {
|
|
return nil, fmt.Errorf("reading archive file %s: %v", filename, err)
|
|
}
|
|
overlay[filename] = content
|
|
}
|
|
|
|
return overlay, nil
|
|
}
|