Commit e03b4ae0 authored by Quentin Smith's avatar Quentin Smith

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/35350Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent 6f1afaec
...@@ -6,21 +6,23 @@ ...@@ -6,21 +6,23 @@
// //
// Usage: // 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 // Each input file should contain the output from one or more runs of
// ``go test -bench'', or another tool which uses the same format. // ``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. // print a URL where they can be viewed.
package main package main
import ( import (
"bytes"
"context" "context"
"encoding/json" "encoding/json"
"flag" "flag"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"log" "log"
"mime/multipart" "mime/multipart"
"os" "os"
...@@ -31,8 +33,9 @@ import ( ...@@ -31,8 +33,9 @@ import (
) )
var ( var (
server = flag.String("server", "https://perfdata.golang.org", "perfdata server to upload benchmarks to") server = flag.String("server", "https://perfdata.golang.org", "upload benchmarks to server at `url`")
verbose = flag.Bool("v", false, "verbose") 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 { type uploadStatus struct {
...@@ -45,25 +48,26 @@ type uploadStatus struct { ...@@ -45,25 +48,26 @@ type uploadStatus struct {
} }
// writeOneFile reads name and writes it to mpw. // 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)) w, err := mpw.CreateFormFile("file", filepath.Base(name))
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Writing upload failed: %v\n", err) return err
os.Exit(1) }
if len(header) > 0 {
if _, err := w.Write(header); err != nil {
return err
}
} }
f, err := os.Open(name) f, err := os.Open(name)
if err != nil { if err != nil {
fmt.Fprint(os.Stderr, err) return err
mpw.WriteField("abort", "1")
// TODO(quentin): Wait until the abort field is written before exiting.
os.Exit(1)
} }
defer f.Close() defer f.Close()
if _, err := io.Copy(w, f); err != nil { if _, err := io.Copy(w, f); err != nil {
fmt.Fprintf(os.Stderr, "Writing upload failed: %v", err) return err
os.Exit(1)
} }
return nil
} }
func usage() { func usage() {
...@@ -85,6 +89,16 @@ func main() { ...@@ -85,6 +89,16 @@ func main() {
log.Fatal("no files to upload") 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. // TODO(quentin): Some servers might not need authentication.
// We should somehow detect this and not force the user to get a token. // We should somehow detect this and not force the user to get a token.
// Or they might need non-Google authentication. // Or they might need non-Google authentication.
...@@ -98,8 +112,16 @@ func main() { ...@@ -98,8 +112,16 @@ func main() {
defer mpw.Close() defer mpw.Close()
for _, name := range files { 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() start := time.Now()
......
...@@ -93,6 +93,9 @@ func (a *App) processUpload(ctx context.Context, user string, mr *multipart.Read ...@@ -93,6 +93,9 @@ func (a *App) processUpload(ctx context.Context, user string, mr *multipart.Read
} }
name := p.FormName() name := p.FormName()
if name == "commit" {
continue
}
if name != "file" { if name != "file" {
return nil, fmt.Errorf("unexpected field %q", name) return nil, fmt.Errorf("unexpected field %q", name)
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment