From 6524310770649b6aa9786711edd2f6eeab4ba61a Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 17 Apr 2014 11:47:12 -0700 Subject: [PATCH] cmd/pack: handle very long lines in pkgdef LGTM=rsc, bradfitz R=golang-codereviews, rsc, bradfitz CC=golang-codereviews https://golang.org/cl/88170049 --- src/cmd/pack/pack.go | 20 ++++---- src/cmd/pack/pack_test.go | 102 ++++++++++++++++++++++++++++++++------ 2 files changed, 98 insertions(+), 24 deletions(-) diff --git a/src/cmd/pack/pack.go b/src/cmd/pack/pack.go index 468104deb6..594433712d 100644 --- a/src/cmd/pack/pack.go +++ b/src/cmd/pack/pack.go @@ -406,20 +406,22 @@ func readPkgdef(file string) (data []byte, err error) { // Read from file, collecting header for __.PKGDEF. // The header is from the beginning of the file until a line // containing just "!". The first line must begin with "go object ". - var buf bytes.Buffer - scan := bufio.NewScanner(f) - for scan.Scan() { - line := scan.Text() - if buf.Len() == 0 && !strings.HasPrefix(line, "go object ") { + rbuf := bufio.NewReader(f) + var wbuf bytes.Buffer + for { + line, err := rbuf.ReadBytes('\n') + if err != nil { + return nil, err + } + if wbuf.Len() == 0 && !bytes.HasPrefix(line, []byte("go object ")) { return nil, errors.New("not a Go object file") } - if line == "!" { + if bytes.Equal(line, []byte("!\n")) { break } - buf.WriteString(line) - buf.WriteString("\n") + wbuf.Write(line) } - return buf.Bytes(), nil + return wbuf.Bytes(), nil } // exactly16Bytes truncates the string if necessary so it is at most 16 bytes long, diff --git a/src/cmd/pack/pack_test.go b/src/cmd/pack/pack_test.go index 9389349187..bd4b224aff 100644 --- a/src/cmd/pack/pack_test.go +++ b/src/cmd/pack/pack_test.go @@ -198,17 +198,97 @@ func TestHello(t *testing.T) { t.Fatal(err) } + char := findChar(t, dir) + run := func(args ...string) string { - cmd := exec.Command(args[0], args[1:]...) - cmd.Dir = dir - out, err := cmd.CombinedOutput() + return doRun(t, dir, args...) + } + + run("go", "build", "cmd/pack") // writes pack binary to dir + run("go", "tool", char+"g", "hello.go") + run("./pack", "grc", "hello.a", "hello."+char) + run("go", "tool", char+"l", "-o", "a.out", "hello.a") + out := run("./a.out") + if out != "hello world\n" { + t.Fatal("incorrect output: %q, want %q", out, "hello world\n") + } +} + +// Test that pack works with very long lines in PKGDEF. +func TestLargeDefs(t *testing.T) { + dir := tmpDir(t) + defer os.RemoveAll(dir) + large := filepath.Join(dir, "large.go") + f, err := os.Create(large) + if err != nil { + t.Fatal(err) + } + + printf := func(format string, args ...interface{}) { + _, err := fmt.Fprintf(f, format, args...) if err != nil { - t.Fatalf("%v: %v\n%s", args, err, string(out)) + t.Fatalf("Writing to %s: %v", large, err) } - return string(out) } - out := run("go", "env") + printf("package large\n\ntype T struct {\n") + for i := 0; i < 10000; i++ { + printf("f%d int `tag:\"", i) + for j := 0; j < 100; j++ { + printf("t%d=%d,", j, j) + } + printf("\"`\n") + } + printf("}\n") + if err = f.Close(); err != nil { + t.Fatal(err) + } + + main := filepath.Join(dir, "main.go") + prog := ` + package main + import "./large" + var V large.T + func main() { + println("ok") + } + ` + err = ioutil.WriteFile(main, []byte(prog), 0666) + if err != nil { + t.Fatal(err) + } + + char := findChar(t, dir) + + run := func(args ...string) string { + return doRun(t, dir, args...) + } + + run("go", "build", "cmd/pack") // writes pack binary to dir + run("go", "tool", char+"g", "large.go") + run("./pack", "grc", "large.a", "large."+char) + run("go", "tool", char+"g", "main.go") + run("go", "tool", char+"l", "-o", "a.out", "main."+char) + out := run("./a.out") + if out != "ok\n" { + t.Fatal("incorrect output: %q, want %q", out, "ok\n") + } +} + +// doRun runs a program in a directory and returns the output. +func doRun(t *testing.T, dir string, args ...string) string { + cmd := exec.Command(args[0], args[1:]...) + cmd.Dir = dir + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("%v: %v\n%s", args, err, string(out)) + } + return string(out) +} + +// findChar returns the architecture character for the go command. +func findChar(t *testing.T, dir string) string { + out := doRun(t, dir, "go", "env") re, err := regexp.Compile(`\s*GOCHAR=['"]?(\w)['"]?`) if err != nil { t.Fatal(err) @@ -217,15 +297,7 @@ func TestHello(t *testing.T) { if fields == nil { t.Fatal("cannot find GOCHAR in 'go env' output:\n", out) } - char := fields[1] - run("go", "build", "cmd/pack") // writes pack binary to dir - run("go", "tool", char+"g", "hello.go") - run("./pack", "grc", "hello.a", "hello."+char) - run("go", "tool", char+"l", "-o", "a.out", "hello.a") - out = run("./a.out") - if out != "hello world\n" { - t.Fatal("incorrect output: %q, want %q", out, "hello world\n") - } + return fields[1] } // Fake implementation of files. -- 2.48.1