import (
"bufio"
"bytes"
+ "cmd/go/internal/str"
"container/heap"
"debug/elf"
"errors"
out, err := b.runOut(dir, desc, env, cmdargs...)
if len(out) > 0 {
if desc == "" {
- desc = b.fmtcmd(dir, "%s", strings.Join(stringList(cmdargs...), " "))
+ desc = b.fmtcmd(dir, "%s", strings.Join(str.StringList(cmdargs...), " "))
}
b.showOutput(dir, desc, b.processOutput(out))
if err != nil {
// runOut runs the command given by cmdline in the directory dir.
// It returns the command output and any errors that occurred.
func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...interface{}) ([]byte, error) {
- cmdline := stringList(cmdargs...)
+ cmdline := str.StringList(cmdargs...)
if buildN || buildX {
var envcmdline string
for i := range env {
return err
}
if !bytes.Equal(data1, data2) {
- return fmt.Errorf("%s and %s produced different output files:\n%s\n%s", filepath.Base(args[1].(string)), newTool, strings.Join(stringList(args...), " "), strings.Join(stringList(newArgs...), " "))
+ return fmt.Errorf("%s and %s produced different output files:\n%s\n%s", filepath.Base(args[1].(string)), newTool, strings.Join(str.StringList(args...), " "), strings.Join(str.StringList(newArgs...), " "))
}
os.Remove(ofile + ".new")
return nil
}
if buildN || buildX {
- cmdline := stringList("pack", "r", absAfile, absOfiles)
+ cmdline := str.StringList("pack", "r", absAfile, absOfiles)
b.showcmd(p.Dir, "%s # internal", joinUnambiguously(cmdline))
}
if buildN {
if p.localPrefix != "" {
gcargs = append(gcargs, "-fgo-relative-import-path="+p.localPrefix)
}
- args := stringList(tools.compiler(), importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags)
+ args := str.StringList(tools.compiler(), importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags)
for _, f := range gofiles {
args = append(args, mkAbs(p.Dir, f))
}
ldflags = append(ldflags, root.p.CgoLDFLAGS...)
}
- ldflags = stringList("-Wl,-(", ldflags, "-Wl,-)")
+ ldflags = str.StringList("-Wl,-(", ldflags, "-Wl,-)")
for _, shlib := range shlibs {
ldflags = append(
func (b *builder) cflags(p *Package) (cppflags, cflags, cxxflags, fflags, ldflags []string) {
defaults := "-g -O2"
- cppflags = stringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS)
- cflags = stringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS)
- cxxflags = stringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS)
- fflags = stringList(envList("CGO_FFLAGS", defaults), p.CgoFFLAGS)
- ldflags = stringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS)
+ cppflags = str.StringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS)
+ cflags = str.StringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS)
+ cxxflags = str.StringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS)
+ fflags = str.StringList(envList("CGO_FFLAGS", defaults), p.CgoFFLAGS)
+ ldflags = str.StringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS)
return
}
outGo = append(outGo, gofiles...)
// gcc
- cflags := stringList(cgoCPPFLAGS, cgoCFLAGS)
+ cflags := str.StringList(cgoCPPFLAGS, cgoCFLAGS)
for _, cfile := range cfiles {
ofile := obj + cfile[:len(cfile)-1] + "o"
if err := b.gcc(p, ofile, cflags, obj+cfile); err != nil {
outObj = append(outObj, ofile)
}
- cxxflags := stringList(cgoCPPFLAGS, cgoCXXFLAGS)
+ cxxflags := str.StringList(cgoCPPFLAGS, cgoCXXFLAGS)
for _, file := range gxxfiles {
// Append .o to the file, just in case the pkg has file.c and file.cpp
ofile := obj + cgoRe.ReplaceAllString(filepath.Base(file), "_") + ".o"
outObj = append(outObj, ofile)
}
- fflags := stringList(cgoCPPFLAGS, cgoFFLAGS)
+ fflags := str.StringList(cgoCPPFLAGS, cgoFFLAGS)
for _, file := range ffiles {
// Append .o to the file, just in case the pkg has file.c and file.f
ofile := obj + cgoRe.ReplaceAllString(filepath.Base(file), "_") + ".o"
return err
}
- linkobj := stringList(ofile, outObj, p.SysoFiles)
+ linkobj := str.StringList(ofile, outObj, p.SysoFiles)
dynobj := obj + "_cgo_.o"
// we need to use -pie for Linux/ARM to get accurate imported sym
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _ := b.cflags(p)
var cflags []string
if cxx {
- cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS)
+ cflags = str.StringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS)
} else {
- cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCFLAGS)
+ cflags = str.StringList(cgoCPPFLAGS, pcCFLAGS, cgoCFLAGS)
}
n := 5 // length of ".swig"
package main
+import "cmd/go/internal/str"
+
var cmdFix = &Command{
Run: runFix,
UsageLine: "fix [packages]",
// Use pkg.gofiles instead of pkg.Dir so that
// the command only applies to this package,
// not to packages in subdirectories.
- run(stringList(buildToolExec, tool("fix"), relPaths(pkg.allgofiles)))
+ run(str.StringList(buildToolExec, tool("fix"), relPaths(pkg.allgofiles)))
}
}
package main
import (
+ "cmd/go/internal/str"
"os"
"path/filepath"
)
// Use pkg.gofiles instead of pkg.Dir so that
// the command only applies to this package,
// not to packages in subdirectories.
- run(stringList(gofmt, "-l", "-w", relPaths(pkg.allgofiles)))
+ run(str.StringList(gofmt, "-l", "-w", relPaths(pkg.allgofiles)))
}
}
package main
import (
+ "cmd/go/internal/str"
"fmt"
"go/build"
"os"
// due to wildcard expansion.
for _, p := range pkgs {
if *getFix {
- run(buildToolExec, stringList(tool("fix"), relPaths(p.allgofiles)))
+ run(buildToolExec, str.StringList(tool("fix"), relPaths(p.allgofiles)))
// The imports might have changed, so reload again.
p = reloadPackage(arg, stk)
// Process test dependencies when -t is specified.
// (But don't get test dependencies for test dependencies:
// we always pass mode 0 to the recursive calls below.)
- imports = stringList(imports, p.TestImports, p.XTestImports)
+ imports = str.StringList(imports, p.TestImports, p.XTestImports)
}
for i, path := range imports {
if path == "C" {
--- /dev/null
+// Copyright 2017 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 str provides string manipulation utilities.
+package str
+
+import (
+ "bytes"
+ "fmt"
+ "unicode"
+ "unicode/utf8"
+)
+
+// StringList flattens its arguments into a single []string.
+// Each argument in args must have type string or []string.
+func StringList(args ...interface{}) []string {
+ var x []string
+ for _, arg := range args {
+ switch arg := arg.(type) {
+ case []string:
+ x = append(x, arg...)
+ case string:
+ x = append(x, arg)
+ default:
+ panic("stringList: invalid argument of type " + fmt.Sprintf("%T", arg))
+ }
+ }
+ return x
+}
+
+// toFold returns a string with the property that
+// strings.EqualFold(s, t) iff toFold(s) == toFold(t)
+// This lets us test a large set of strings for fold-equivalent
+// duplicates without making a quadratic number of calls
+// to EqualFold. Note that strings.ToUpper and strings.ToLower
+// do not have the desired property in some corner cases.
+func toFold(s string) string {
+ // Fast path: all ASCII, no upper case.
+ // Most paths look like this already.
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ if c >= utf8.RuneSelf || 'A' <= c && c <= 'Z' {
+ goto Slow
+ }
+ }
+ return s
+
+Slow:
+ var buf bytes.Buffer
+ for _, r := range s {
+ // SimpleFold(x) cycles to the next equivalent rune > x
+ // or wraps around to smaller values. Iterate until it wraps,
+ // and we've found the minimum value.
+ for {
+ r0 := r
+ r = unicode.SimpleFold(r0)
+ if r <= r0 {
+ break
+ }
+ }
+ // Exception to allow fast path above: A-Z => a-z
+ if 'A' <= r && r <= 'Z' {
+ r += 'a' - 'A'
+ }
+ buf.WriteRune(r)
+ }
+ return buf.String()
+}
+
+// FoldDup reports a pair of strings from the list that are
+// equal according to strings.EqualFold.
+// It returns "", "" if there are no such strings.
+func FoldDup(list []string) (string, string) {
+ clash := map[string]string{}
+ for _, s := range list {
+ fold := toFold(s)
+ if t := clash[fold]; t != "" {
+ if s > t {
+ s, t = t, s
+ }
+ return s, t
+ }
+ clash[fold] = s
+ }
+ return "", ""
+}
+
+// Contains reports whether x contains s.
+func Contains(x []string, s string) bool {
+ for _, t := range x {
+ if t == s {
+ return true
+ }
+ }
+ return false
+}
import (
"bufio"
"bytes"
+ "cmd/go/internal/str"
"flag"
"fmt"
"go/build"
}
func run(cmdargs ...interface{}) {
- cmdline := stringList(cmdargs...)
+ cmdline := str.StringList(cmdargs...)
if buildN || buildX {
fmt.Printf("%s\n", strings.Join(cmdline, " "))
if buildN {
})
return pkgs
}
-
-// stringList's arguments should be a sequence of string or []string values.
-// stringList flattens them into a single []string.
-func stringList(args ...interface{}) []string {
- var x []string
- for _, arg := range args {
- switch arg := arg.(type) {
- case []string:
- x = append(x, arg...)
- case string:
- x = append(x, arg)
- default:
- panic("stringList: invalid argument of type " + fmt.Sprintf("%T", arg))
- }
- }
- return x
-}
-
-// toFold returns a string with the property that
-// strings.EqualFold(s, t) iff toFold(s) == toFold(t)
-// This lets us test a large set of strings for fold-equivalent
-// duplicates without making a quadratic number of calls
-// to EqualFold. Note that strings.ToUpper and strings.ToLower
-// have the desired property in some corner cases.
-func toFold(s string) string {
- // Fast path: all ASCII, no upper case.
- // Most paths look like this already.
- for i := 0; i < len(s); i++ {
- c := s[i]
- if c >= utf8.RuneSelf || 'A' <= c && c <= 'Z' {
- goto Slow
- }
- }
- return s
-
-Slow:
- var buf bytes.Buffer
- for _, r := range s {
- // SimpleFold(x) cycles to the next equivalent rune > x
- // or wraps around to smaller values. Iterate until it wraps,
- // and we've found the minimum value.
- for {
- r0 := r
- r = unicode.SimpleFold(r0)
- if r <= r0 {
- break
- }
- }
- // Exception to allow fast path above: A-Z => a-z
- if 'A' <= r && r <= 'Z' {
- r += 'a' - 'A'
- }
- buf.WriteRune(r)
- }
- return buf.String()
-}
-
-// foldDup reports a pair of strings from the list that are
-// equal according to strings.EqualFold.
-// It returns "", "" if there are no such strings.
-func foldDup(list []string) (string, string) {
- clash := map[string]string{}
- for _, s := range list {
- fold := toFold(s)
- if t := clash[fold]; t != "" {
- if s > t {
- s, t = t, s
- }
- return s, t
- }
- clash[fold] = s
- }
- return "", ""
-}
import (
"bytes"
+ "cmd/go/internal/str"
"crypto/sha1"
"errors"
"fmt"
// Build list of full paths to all Go files in the package,
// for use by commands like go fmt.
- p.gofiles = stringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles)
+ p.gofiles = str.StringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles)
for i := range p.gofiles {
p.gofiles[i] = filepath.Join(p.Dir, p.gofiles[i])
}
sort.Strings(p.gofiles)
- p.sfiles = stringList(p.SFiles)
+ p.sfiles = str.StringList(p.SFiles)
for i := range p.sfiles {
p.sfiles[i] = filepath.Join(p.Dir, p.sfiles[i])
}
sort.Strings(p.sfiles)
- p.allgofiles = stringList(p.IgnoredGoFiles)
+ p.allgofiles = str.StringList(p.IgnoredGoFiles)
for i := range p.allgofiles {
p.allgofiles[i] = filepath.Join(p.Dir, p.allgofiles[i])
}
// To avoid problems on case-insensitive files, we reject any package
// where two different input files have equal names under a case-insensitive
// comparison.
- f1, f2 := foldDup(stringList(
+ f1, f2 := str.FoldDup(str.StringList(
p.GoFiles,
p.CgoFiles,
p.IgnoredGoFiles,
// In the absence of errors lower in the dependency tree,
// check for case-insensitive collisions of import paths.
if len(p.DepsErrors) == 0 {
- dep1, dep2 := foldDup(p.Deps)
+ dep1, dep2 := str.FoldDup(p.Deps)
if dep1 != "" {
p.Error = &PackageError{
ImportStack: stk.copy(),
// to test for write access, and then skip GOPATH roots we don't have write
// access to. But hopefully we can just use the mtimes always.
- srcs := stringList(p.GoFiles, p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.FFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles)
+ srcs := str.StringList(p.GoFiles, p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.FFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles)
for _, src := range srcs {
if olderThan(filepath.Join(p.Dir, src)) {
return true, "newer source file"
// Include the list of files compiled as part of the package.
// This lets us detect removed files. See issue 3895.
- inputFiles := stringList(
+ inputFiles := str.StringList(
p.GoFiles,
p.CgoFiles,
p.CFiles,
package main
import (
+ "cmd/go/internal/str"
"io/ioutil"
"os"
"path/filepath"
list []string
f1, f2 string
}{
- {stringList("math/rand", "math/big"), "", ""},
- {stringList("math", "strings"), "", ""},
- {stringList("strings"), "", ""},
- {stringList("strings", "strings"), "strings", "strings"},
- {stringList("Rand", "rand", "math", "math/rand", "math/Rand"), "Rand", "rand"},
+ {str.StringList("math/rand", "math/big"), "", ""},
+ {str.StringList("math", "strings"), "", ""},
+ {str.StringList("strings"), "", ""},
+ {str.StringList("strings", "strings"), "strings", "strings"},
+ {str.StringList("Rand", "rand", "math", "math/rand", "math/Rand"), "Rand", "rand"},
}
func TestFoldDup(t *testing.T) {
for _, tt := range foldDupTests {
- f1, f2 := foldDup(tt.list)
+ f1, f2 := str.FoldDup(tt.list)
if f1 != tt.f1 || f2 != tt.f2 {
t.Errorf("foldDup(%q) = %q, %q, want %q, %q", tt.list, f1, f2, tt.f1, tt.f2)
}
package main
import (
+ "cmd/go/internal/str"
"fmt"
"os"
"os/exec"
// runProgram is the action for running a binary that has already
// been compiled. We ignore exit status.
func (b *builder) runProgram(a *action) error {
- cmdline := stringList(findExecCmd(), a.deps[0].target, a.args)
+ cmdline := str.StringList(findExecCmd(), a.deps[0].target, a.args)
if buildN || buildX {
b.showcmd("", "%s", strings.Join(cmdline, " "))
if buildN {
import (
"bytes"
+ "cmd/go/internal/str"
"errors"
"fmt"
"go/ast"
b.do(root)
}
-func contains(x []string, s string) bool {
- for _, t := range x {
- if t == s {
- return true
- }
- }
- return false
-}
-
var windowsBadWords = []string{
"install",
"patch",
err.Pos = "" // show full import stack
return nil, nil, nil, err
}
- if contains(p1.Deps, p.ImportPath) || p1.ImportPath == p.ImportPath {
+ if str.Contains(p1.Deps, p.ImportPath) || p1.ImportPath == p.ImportPath {
// Same error that loadPackage returns (via reusePackage) in pkg.go.
// Can't change that code, because that code is only for loading the
// non-test copy of a package.
ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
ptest.target = ""
- ptest.Imports = stringList(p.Imports, p.TestImports)
+ ptest.Imports = str.StringList(p.Imports, p.TestImports)
ptest.imports = append(append([]*Package{}, p.imports...), imports...)
ptest.pkgdir = testDir
ptest.fake = true
Search:
for p.ImportPath != target {
for _, p1 := range p.imports {
- if p1.ImportPath == target || contains(p1.Deps, target) {
+ if p1.ImportPath == target || str.Contains(p1.Deps, target) {
stk = append(stk, p1.ImportPath)
p = p1
continue Search
// builderRunTest is the action for running a test binary.
func builderRunTest(b *builder, a *action) error {
- args := stringList(findExecCmd(), a.deps[0].target, testArgs)
+ args := str.StringList(findExecCmd(), a.deps[0].target, testArgs)
a.testOutput = new(bytes.Buffer)
if buildN || buildX {
package main
-import "path/filepath"
+import (
+ "path/filepath"
+
+ "cmd/go/internal/str"
+)
func init() {
addBuildFlags(cmdVet)
// Vet expects to be given a set of files all from the same package.
// Run once for package p and once for package p_test.
if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles) > 0 {
- runVetFiles(p, stringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.SFiles))
+ runVetFiles(p, str.StringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.SFiles))
}
if len(p.XTestGoFiles) > 0 {
- runVetFiles(p, stringList(p.XTestGoFiles))
+ runVetFiles(p, str.StringList(p.XTestGoFiles))
}
}
}