blob: 58f85ec39689286ee62b164718a07379e0b1b15e [file] [log] [blame]
// Copyright 2020 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.
// Command experiment is used for modifying data in the experiments table.
package main
import (
"context"
"flag"
"fmt"
"log"
"os"
"golang.org/x/pkgsite/internal"
"golang.org/x/pkgsite/internal/config"
"golang.org/x/pkgsite/internal/database"
"golang.org/x/pkgsite/internal/postgres"
)
const usage = `
List experiments:
experiments [flags...] ls
Create a new experiment:
experiments [flags...] create <name>
Update an experiment:
experiments [flags...] update <name>
Remove an experiment:
experiments [flags...] rm <name>
`
var rollout = flag.Uint("rollout", 100, "experiment rollout percentage")
func exitUsage() {
flag.Usage()
os.Exit(2)
}
func main() {
flag.Usage = func() {
fmt.Fprint(flag.CommandLine.Output(), usage)
fmt.Fprintln(flag.CommandLine.Output())
fmt.Fprintln(flag.CommandLine.Output(), "Flags:")
flag.PrintDefaults()
}
flag.Parse()
if flag.NArg() < 1 {
exitUsage()
}
ctx := context.Background()
cfg, err := config.Init(ctx)
if err != nil {
log.Fatal(ctx, err)
}
cfg.Dump(os.Stderr)
ddb, err := database.Open("postgres", cfg.DBConnInfo(), cfg.InstanceID)
if err != nil {
log.Fatal(ctx, err)
}
defer ddb.Close()
db := postgres.New(ddb)
switch flag.Arg(0) {
case "ls", "list":
if err := listExperiments(ctx, db); err != nil {
log.Fatalf("listing experiments: %v", err)
}
case "create":
if flag.NArg() < 2 {
fmt.Println(flag.NArg())
exitUsage()
}
if err := createExperiment(ctx, db, flag.Arg(1), *rollout); err != nil {
log.Fatalf("creating experiment: %v", err)
}
case "update":
if flag.NArg() < 2 {
exitUsage()
}
if err := updateExperiment(ctx, db, flag.Arg(1), *rollout); err != nil {
log.Fatalf("updating experiment: %v", err)
}
case "rm", "remove":
if flag.NArg() < 1 {
exitUsage()
}
if err := removeExperiment(ctx, db, flag.Arg(1)); err != nil {
log.Fatalf("removing experiment: %v", err)
}
default:
exitUsage()
}
}
func listExperiments(ctx context.Context, db *postgres.DB) error {
exps, err := db.GetExperiments(ctx)
if err != nil {
return err
}
fmt.Printf("%30s %12s %-40s\n", "NAME", "ROLLOUT", "DESCRIPTION")
for _, exp := range exps {
fmt.Printf("%30s %12d %-40s\n", exp.Name, exp.Rollout, exp.Description)
}
return nil
}
func createExperiment(ctx context.Context, db *postgres.DB, name string, rollout uint) error {
exp := &internal.Experiment{
Name: name,
Description: description(name),
Rollout: rollout,
}
if err := db.InsertExperiment(ctx, exp); err != nil {
return err
}
fmt.Printf("\nCreated experiment %q with rollout=%d.\n", name, rollout)
return nil
}
func updateExperiment(ctx context.Context, db *postgres.DB, name string, rollout uint) error {
exp := &internal.Experiment{
Name: name,
Description: description(name),
Rollout: rollout,
}
if err := db.UpdateExperiment(ctx, exp); err != nil {
return err
}
fmt.Printf("\nUpdated experiment %q; rollout=%d.\n", name, rollout)
return nil
}
func removeExperiment(ctx context.Context, db *postgres.DB, name string) error {
if err := db.RemoveExperiment(ctx, name); err != nil {
return err
}
fmt.Printf("\nRemoved experiment %q.\n", name)
return nil
}
func description(name string) string {
d, ok := internal.Experiments[name]
if !ok {
log.Fatalf("Experiment %q does not exist.", name)
}
return d
}