github.com/sc0rp1us/gb@v0.4.1-0.20160319180011-4ba8cf1baa5a/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 "errors" 10 "fmt" 11 "go/token" 12 "path/filepath" 13 "strings" 14 "unicode" 15 ) 16 17 // importer is a private interface defined here so public *Importer 18 // types can be embedded in *Package with exposing them to the caller. 19 type importer interface { 20 matchFile(path string, allTags map[string]bool) (match bool, data []byte, err error) 21 match(name string, allTags map[string]bool) bool 22 } 23 24 // A Package describes the Go package found in a directory. 25 type Package struct { 26 importer // the importer context that loaded this package 27 Dir string // directory containing package sources 28 Name string // package name 29 ImportPath string // import path of package ("" if unknown) 30 Root string // root of Go tree where this package lives 31 SrcRoot string // package source root directory ("" if unknown) 32 PkgTargetRoot string // architecture dependent install root directory ("" if unknown) 33 Standard bool // package found in GOROOT 34 AllTags []string // tags that can influence file selection in this directory 35 ConflictDir string // this directory shadows Dir in $GOPATH 36 37 // Source files 38 GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) 39 CgoFiles []string // .go source files that import "C" 40 IgnoredGoFiles []string // .go source files ignored for this build 41 CFiles []string // .c source files 42 CXXFiles []string // .cc, .cpp and .cxx source files 43 MFiles []string // .m (Objective-C) source files 44 HFiles []string // .h, .hh, .hpp and .hxx source files 45 SFiles []string // .s source files 46 SwigFiles []string // .swig files 47 SwigCXXFiles []string // .swigcxx files 48 SysoFiles []string // .syso system object files to add to archive 49 50 // Cgo directives 51 CgoCFLAGS []string // Cgo CFLAGS directives 52 CgoCPPFLAGS []string // Cgo CPPFLAGS directives 53 CgoCXXFLAGS []string // Cgo CXXFLAGS directives 54 CgoLDFLAGS []string // Cgo LDFLAGS directives 55 CgoPkgConfig []string // Cgo pkg-config directives 56 57 // Dependency information 58 Imports []string // imports from GoFiles, CgoFiles 59 ImportPos map[string][]token.Position // line information for Imports 60 61 // Test information 62 TestGoFiles []string // _test.go files in package 63 TestImports []string // imports from TestGoFiles 64 TestImportPos map[string][]token.Position // line information for TestImports 65 XTestGoFiles []string // _test.go files outside package 66 XTestImports []string // imports from XTestGoFiles 67 XTestImportPos map[string][]token.Position // line information for XTestImports 68 } 69 70 // NoGoError is the error used by Import to describe a directory 71 // containing no buildable Go source files. (It may still contain 72 // test files, files hidden by build tags, and so on.) 73 type NoGoError struct { 74 Dir string 75 } 76 77 func (e *NoGoError) Error() string { 78 return "no buildable Go source files in " + e.Dir 79 } 80 81 // MultiplePackageError describes a directory containing 82 // multiple buildable Go source files for multiple packages. 83 type MultiplePackageError struct { 84 Dir string // directory containing files 85 Packages []string // package names found 86 Files []string // corresponding files: Files[i] declares package Packages[i] 87 } 88 89 func (e *MultiplePackageError) Error() string { 90 // Error string limited to two entries for compatibility. 91 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) 92 } 93 94 // expandSrcDir expands any occurrence of ${SRCDIR}, making sure 95 // the result is safe for the shell. 96 func expandSrcDir(str string, srcdir string) (string, bool) { 97 // "\" delimited paths cause safeCgoName to fail 98 // so convert native paths with a different delimeter 99 // to "/" before starting (eg: on windows). 100 srcdir = filepath.ToSlash(srcdir) 101 102 // Spaces are tolerated in ${SRCDIR}, but not anywhere else. 103 chunks := strings.Split(str, "${SRCDIR}") 104 if len(chunks) < 2 { 105 return str, safeCgoName(str, false) 106 } 107 ok := true 108 for _, chunk := range chunks { 109 ok = ok && (chunk == "" || safeCgoName(chunk, false)) 110 } 111 ok = ok && (srcdir == "" || safeCgoName(srcdir, true)) 112 res := strings.Join(chunks, srcdir) 113 return res, ok && res != "" 114 } 115 116 // NOTE: $ is not safe for the shell, but it is allowed here because of linker options like -Wl,$ORIGIN. 117 // We never pass these arguments to a shell (just to programs we construct argv for), so this should be okay. 118 // See golang.org/issue/6038. 119 const safeString = "+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$" 120 const safeSpaces = " " 121 122 var safeBytes = []byte(safeSpaces + safeString) 123 124 func safeCgoName(s string, spaces bool) bool { 125 if s == "" { 126 return false 127 } 128 safe := safeBytes 129 if !spaces { 130 safe = safe[len(safeSpaces):] 131 } 132 for i := 0; i < len(s); i++ { 133 if c := s[i]; c < 0x80 && bytes.IndexByte(safe, c) < 0 { 134 return false 135 } 136 } 137 return true 138 } 139 140 // splitQuoted splits the string s around each instance of one or more consecutive 141 // white space characters while taking into account quotes and escaping, and 142 // returns an array of substrings of s or an empty list if s contains only white space. 143 // Single quotes and double quotes are recognized to prevent splitting within the 144 // quoted region, and are removed from the resulting substrings. If a quote in s 145 // isn't closed err will be set and r will have the unclosed argument as the 146 // last element. The backslash is used for escaping. 147 // 148 // For example, the following string: 149 // 150 // a b:"c d" 'e''f' "g\"" 151 // 152 // Would be parsed as: 153 // 154 // []string{"a", "b:c d", "ef", `g"`} 155 // 156 func splitQuoted(s string) (r []string, err error) { 157 var args []string 158 arg := make([]rune, len(s)) 159 escaped := false 160 quoted := false 161 quote := '\x00' 162 i := 0 163 for _, rune := range s { 164 switch { 165 case escaped: 166 escaped = false 167 case rune == '\\': 168 escaped = true 169 continue 170 case quote != '\x00': 171 if rune == quote { 172 quote = '\x00' 173 continue 174 } 175 case rune == '"' || rune == '\'': 176 quoted = true 177 quote = rune 178 continue 179 case unicode.IsSpace(rune): 180 if quoted || i > 0 { 181 quoted = false 182 args = append(args, string(arg[:i])) 183 i = 0 184 } 185 continue 186 } 187 arg[i] = rune 188 i++ 189 } 190 if quoted || i > 0 { 191 args = append(args, string(arg[:i])) 192 } 193 if quote != 0 { 194 err = errors.New("unclosed quote") 195 } else if escaped { 196 err = errors.New("unfinished escaping") 197 } 198 return args, err 199 }