cmd/benchsave: add header flag for specifying common keys
This allows easily adding additional information when uploading
existing files. Example usage:
benchsave -header <(echo goarch: arm; echo goos: linux) *.log
Change-Id: I46afafd39d8314d9c06c209f868b71cd5e58c63a
Reviewed-on: https://go-review.googlesource.com/35350
Reviewed-by: Russ Cox <rsc@golang.org>
diff --git a/cmd/benchsave/benchsave.go b/cmd/benchsave/benchsave.go
index 3649c53..5913e41 100644
--- a/cmd/benchsave/benchsave.go
+++ b/cmd/benchsave/benchsave.go
@@ -6,21 +6,23 @@
//
// Usage:
//
-// benchsave [-server https://server.org] a.txt [b.txt ...]
+// benchsave [-v] [-header file] [-server url] file...
//
// Each input file should contain the output from one or more runs of
// ``go test -bench'', or another tool which uses the same format.
//
-// benchsave will upload the input files to the specified server and
+// Benchsave will upload the input files to the specified server and
// print a URL where they can be viewed.
package main
import (
+ "bytes"
"context"
"encoding/json"
"flag"
"fmt"
"io"
+ "io/ioutil"
"log"
"mime/multipart"
"os"
@@ -31,8 +33,9 @@
)
var (
- server = flag.String("server", "https://perfdata.golang.org", "perfdata server to upload benchmarks to")
- verbose = flag.Bool("v", false, "verbose")
+ server = flag.String("server", "https://perfdata.golang.org", "upload benchmarks to server at `url`")
+ verbose = flag.Bool("v", false, "print verbose log messages")
+ header = flag.String("header", "", "insert `file` at the beginning of each uploaded file")
)
type uploadStatus struct {
@@ -45,25 +48,26 @@
}
// writeOneFile reads name and writes it to mpw.
-func writeOneFile(mpw *multipart.Writer, name string) {
+func writeOneFile(mpw *multipart.Writer, name string, header []byte) error {
w, err := mpw.CreateFormFile("file", filepath.Base(name))
if err != nil {
- fmt.Fprintf(os.Stderr, "Writing upload failed: %v\n", err)
- os.Exit(1)
+ return err
+ }
+ if len(header) > 0 {
+ if _, err := w.Write(header); err != nil {
+ return err
+ }
}
f, err := os.Open(name)
if err != nil {
- fmt.Fprint(os.Stderr, err)
- mpw.WriteField("abort", "1")
- // TODO(quentin): Wait until the abort field is written before exiting.
- os.Exit(1)
+ return err
}
defer f.Close()
if _, err := io.Copy(w, f); err != nil {
- fmt.Fprintf(os.Stderr, "Writing upload failed: %v", err)
- os.Exit(1)
+ return err
}
+ return nil
}
func usage() {
@@ -85,6 +89,16 @@
log.Fatal("no files to upload")
}
+ var headerData []byte
+ if *header != "" {
+ var err error
+ headerData, err = ioutil.ReadFile(*header)
+ if err != nil {
+ log.Fatal(err)
+ }
+ headerData = append(bytes.TrimRight(headerData, "\n"), '\n', '\n')
+ }
+
// TODO(quentin): Some servers might not need authentication.
// We should somehow detect this and not force the user to get a token.
// Or they might need non-Google authentication.
@@ -98,8 +112,16 @@
defer mpw.Close()
for _, name := range files {
- writeOneFile(mpw, name)
+ if err := writeOneFile(mpw, name, headerData); err != nil {
+ log.Print(err)
+ mpw.WriteField("abort", "1")
+ // Writing the 'abort' field will cause the server to send back an error response,
+ // which will cause the main goroutine to below.
+ return
+ }
}
+
+ mpw.WriteField("commit", "1")
}()
start := time.Now()
diff --git a/storage/app/upload.go b/storage/app/upload.go
index d66de6c..475ffca 100644
--- a/storage/app/upload.go
+++ b/storage/app/upload.go
@@ -93,6 +93,9 @@
}
name := p.FormName()
+ if name == "commit" {
+ continue
+ }
if name != "file" {
return nil, fmt.Errorf("unexpected field %q", name)
}