Skip to content

Commit

Permalink
cmd/go: split out cmd/go/internal/str
Browse files Browse the repository at this point in the history
This is one CL in a long sequence of changes to break up the
go command from one package into a plausible group of packages.

This sequence is concerned only with moving code, not changing
or cleaning up code. There will still be more cleanup after this sequence.

The entire sequence will be submitted together: it is not a goal
for the tree to build at every step.

For #18653.

Change-Id: I63f578f5ac99c707b599ac5659293c46b275567d
Reviewed-on: https://go-review.googlesource.com/36190
Reviewed-by: David Crawshaw <[email protected]>
  • Loading branch information
rsc committed Feb 3, 2017
1 parent d9e6835 commit 762eb40
Show file tree
Hide file tree
Showing 11 changed files with 154 additions and 126 deletions.
35 changes: 18 additions & 17 deletions src/cmd/go/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package main
import (
"bufio"
"bytes"
"cmd/go/internal/str"
"container/heap"
"debug/elf"
"errors"
Expand Down Expand Up @@ -2091,7 +2092,7 @@ func (b *builder) run(dir string, desc string, env []string, cmdargs ...interfac
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 {
Expand Down Expand Up @@ -2121,7 +2122,7 @@ func (b *builder) processOutput(out []byte) string {
// 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 {
Expand Down Expand Up @@ -2450,7 +2451,7 @@ func toolVerify(b *builder, p *Package, newTool string, ofile string, args []int
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
Expand All @@ -2477,7 +2478,7 @@ func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s
}

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 {
Expand Down Expand Up @@ -2692,7 +2693,7 @@ func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmh
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))
}
Expand Down Expand Up @@ -2913,7 +2914,7 @@ func (tools gccgoToolchain) link(b *builder, root *action, out string, allaction
ldflags = append(ldflags, root.p.CgoLDFLAGS...)
}

ldflags = stringList("-Wl,-(", ldflags, "-Wl,-)")
ldflags = str.StringList("-Wl,-(", ldflags, "-Wl,-)")

for _, shlib := range shlibs {
ldflags = append(
Expand Down Expand Up @@ -3244,11 +3245,11 @@ func envList(key, def string) []string {
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
}

Expand Down Expand Up @@ -3354,7 +3355,7 @@ func (b *builder) cgo(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofil
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 {
Expand All @@ -3372,7 +3373,7 @@ func (b *builder) cgo(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofil
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"
Expand All @@ -3391,7 +3392,7 @@ func (b *builder) cgo(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofil
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"
Expand Down Expand Up @@ -3440,7 +3441,7 @@ func (b *builder) dynimport(p *Package, obj, importGo, cgoExe string, cflags, cg
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
Expand Down Expand Up @@ -3672,9 +3673,9 @@ func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx b
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"
Expand Down
4 changes: 3 additions & 1 deletion src/cmd/go/fix.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

package main

import "cmd/go/internal/str"

var cmdFix = &Command{
Run: runFix,
UsageLine: "fix [packages]",
Expand All @@ -25,6 +27,6 @@ func runFix(cmd *Command, args []string) {
// 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)))
}
}
3 changes: 2 additions & 1 deletion src/cmd/go/fmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package main

import (
"cmd/go/internal/str"
"os"
"path/filepath"
)
Expand Down Expand Up @@ -39,7 +40,7 @@ func runFmt(cmd *Command, args []string) {
// 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)))
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/cmd/go/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package main

import (
"cmd/go/internal/str"
"fmt"
"go/build"
"os"
Expand Down Expand Up @@ -302,7 +303,7 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
// 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)
Expand All @@ -324,7 +325,7 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
// 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" {
Expand Down
97 changes: 97 additions & 0 deletions src/cmd/go/internal/str/str.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// 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
}
77 changes: 2 additions & 75 deletions src/cmd/go/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package main
import (
"bufio"
"bytes"
"cmd/go/internal/str"
"flag"
"fmt"
"go/build"
Expand Down Expand Up @@ -453,7 +454,7 @@ func exitIfErrors() {
}

func run(cmdargs ...interface{}) {
cmdline := stringList(cmdargs...)
cmdline := str.StringList(cmdargs...)
if buildN || buildX {
fmt.Printf("%s\n", strings.Join(cmdline, " "))
if buildN {
Expand Down Expand Up @@ -730,77 +731,3 @@ func matchPackagesInFS(pattern string) []string {
})
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 "", ""
}
Loading

0 comments on commit 762eb40

Please sign in to comment.