github.com/seh/gb@v0.4.4-0.20160724065125-065d2b2b1ba1/internal/importer/build.go (about)

     1  // Copyright 2011 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 importer
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"go/token"
    11  	"path/filepath"
    12  	"strings"
    13  )
    14  
    15  // importer is a private interface defined here so public *Importer
    16  // types can be embedded in *Package with exposing them to the caller.
    17  type importer interface {
    18  	matchFile(path string, allTags map[string]bool) (match bool, data []byte, err error)
    19  	match(name string, allTags map[string]bool) bool
    20  }
    21  
    22  // A Package describes the Go package found in a directory.
    23  type Package struct {
    24  	importer               // the importer context that loaded this package
    25  	Dir           string   // directory containing package sources
    26  	Name          string   // package name
    27  	ImportPath    string   // import path of package ("" if unknown)
    28  	Root          string   // root of Go tree where this package lives
    29  	SrcRoot       string   // package source root directory ("" if unknown)
    30  	PkgTargetRoot string   // architecture dependent install root directory ("" if unknown)
    31  	Standard      bool     // package found in GOROOT
    32  	AllTags       []string // tags that can influence file selection in this directory
    33  	ConflictDir   string   // this directory shadows Dir in $GOPATH
    34  
    35  	// Source files
    36  	GoFiles        []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
    37  	CgoFiles       []string // .go source files that import "C"
    38  	IgnoredGoFiles []string // .go source files ignored for this build
    39  	CFiles         []string // .c source files
    40  	CXXFiles       []string // .cc, .cpp and .cxx source files
    41  	MFiles         []string // .m (Objective-C) source files
    42  	HFiles         []string // .h, .hh, .hpp and .hxx source files
    43  	SFiles         []string // .s source files
    44  	SwigFiles      []string // .swig files
    45  	SwigCXXFiles   []string // .swigcxx files
    46  	SysoFiles      []string // .syso system object files to add to archive
    47  
    48  	// Cgo directives
    49  	CgoCFLAGS    []string // Cgo CFLAGS directives
    50  	CgoCPPFLAGS  []string // Cgo CPPFLAGS directives
    51  	CgoCXXFLAGS  []string // Cgo CXXFLAGS directives
    52  	CgoLDFLAGS   []string // Cgo LDFLAGS directives
    53  	CgoPkgConfig []string // Cgo pkg-config directives
    54  
    55  	// Dependency information
    56  	Imports   []string                    // imports from GoFiles, CgoFiles
    57  	ImportPos map[string][]token.Position // line information for Imports
    58  
    59  	// Test information
    60  	TestGoFiles    []string                    // _test.go files in package
    61  	TestImports    []string                    // imports from TestGoFiles
    62  	TestImportPos  map[string][]token.Position // line information for TestImports
    63  	XTestGoFiles   []string                    // _test.go files outside package
    64  	XTestImports   []string                    // imports from XTestGoFiles
    65  	XTestImportPos map[string][]token.Position // line information for XTestImports
    66  }
    67  
    68  // NoGoError is the error used by Import to describe a directory
    69  // containing no buildable Go source files. (It may still contain
    70  // test files, files hidden by build tags, and so on.)
    71  type NoGoError struct {
    72  	Dir string
    73  }
    74  
    75  func (e *NoGoError) Error() string {
    76  	return "no buildable Go source files in " + e.Dir
    77  }
    78  
    79  // MultiplePackageError describes a directory containing
    80  // multiple buildable Go source files for multiple packages.
    81  type MultiplePackageError struct {
    82  	Dir      string   // directory containing files
    83  	Packages []string // package names found
    84  	Files    []string // corresponding files: Files[i] declares package Packages[i]
    85  }
    86  
    87  func (e *MultiplePackageError) Error() string {
    88  	// Error string limited to two entries for compatibility.
    89  	return fmt.Sprintf("found packages %s (%s) and %s (%s) in %s", e.Packages[0], e.Files[0], e.Packages[1], e.Files[1], e.Dir)
    90  }
    91  
    92  // expandSrcDir expands any occurrence of ${SRCDIR}, making sure
    93  // the result is safe for the shell.
    94  func expandSrcDir(str string, srcdir string) (string, bool) {
    95  	// "\" delimited paths cause safeCgoName to fail
    96  	// so convert native paths with a different delimeter
    97  	// to "/" before starting (eg: on windows).
    98  	srcdir = filepath.ToSlash(srcdir)
    99  
   100  	// Spaces are tolerated in ${SRCDIR}, but not anywhere else.
   101  	chunks := strings.Split(str, "${SRCDIR}")
   102  	if len(chunks) < 2 {
   103  		return str, safeCgoName(str, false)
   104  	}
   105  	ok := true
   106  	for _, chunk := range chunks {
   107  		ok = ok && (chunk == "" || safeCgoName(chunk, false))
   108  	}
   109  	ok = ok && (srcdir == "" || safeCgoName(srcdir, true))
   110  	res := strings.Join(chunks, srcdir)
   111  	return res, ok && res != ""
   112  }
   113  
   114  // NOTE: $ is not safe for the shell, but it is allowed here because of linker options like -Wl,$ORIGIN.
   115  // We never pass these arguments to a shell (just to programs we construct argv for), so this should be okay.
   116  // See golang.org/issue/6038.
   117  const safeString = "+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$"
   118  const safeSpaces = " "
   119  
   120  var safeBytes = []byte(safeSpaces + safeString)
   121  
   122  func safeCgoName(s string, spaces bool) bool {
   123  	if s == "" {
   124  		return false
   125  	}
   126  	safe := safeBytes
   127  	if !spaces {
   128  		safe = safe[len(safeSpaces):]
   129  	}
   130  	for i := 0; i < len(s); i++ {
   131  		if c := s[i]; c < 0x80 && bytes.IndexByte(safe, c) < 0 {
   132  			return false
   133  		}
   134  	}
   135  	return true
   136  }