Skip to content
This repository has been archived by the owner on Feb 17, 2024. It is now read-only.

timecraft: use human types #28

Merged
merged 5 commits into from
May 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ flatbuffers: go.mod $(format.src.go)
$(GO) build ./format/...

test: flatbuffers testdata
$(GO) test -v ./...
$(GO) test ./...

testdata: $(testdata.go.wasm)

Expand Down
4 changes: 2 additions & 2 deletions internal/cmd/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,12 @@ func get(ctx context.Context, args []string) error {
var (
timeRange = timemachine.Since(time.Unix(0, 0))
output = outputFormat("text")
registryPath = "~/.timecraft"
registryPath = human.Path("~/.timecraft")
)

flagSet := newFlagSet("timecraft get", getUsage)
customVar(flagSet, &output, "o", "output")
stringVar(flagSet, &registryPath, "r", "registry")
customVar(flagSet, &registryPath, "r", "registry")
parseFlags(flagSet, args)

args = flagSet.Args()
Expand Down
35 changes: 18 additions & 17 deletions internal/cmd/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
pprof "github.com/google/pprof/profile"
"github.com/google/uuid"

"github.com/stealthrocket/timecraft/internal/print/human"
"github.com/stealthrocket/timecraft/internal/stream"
"github.com/stealthrocket/timecraft/internal/timemachine"
"github.com/stealthrocket/timecraft/internal/timemachine/wasicall"
Expand Down Expand Up @@ -54,28 +55,28 @@ Options:

func profile(ctx context.Context, args []string) error {
var (
startTime timestamp
duration time.Duration
sampleRate = 1.0
cpuProfile = "cpu.out"
memProfile = "mem.out"
registryPath = "~/.timecraft"
startTime = human.Time{}
duration = human.Duration(0)
sampleRate = human.Rate(1.0)
cpuProfile = human.Path("cpu.out")
memProfile = human.Path("mem.out")
registryPath = human.Path("~/.timecraft")
)

flagSet := newFlagSet("timecraft profile", profileUsage)
customVar(flagSet, &startTime, "start-time")
durationVar(flagSet, &duration, "duration")
float64Var(flagSet, &sampleRate, "sample-rate")
stringVar(flagSet, &cpuProfile, "cpuprofile")
stringVar(flagSet, &memProfile, "memprofile")
stringVar(flagSet, &registryPath, "r", "registry")
customVar(flagSet, &duration, "duration")
customVar(flagSet, &sampleRate, "sample-rate")
customVar(flagSet, &cpuProfile, "cpuprofile")
customVar(flagSet, &memProfile, "memprofile")
customVar(flagSet, &registryPath, "r", "registry")
parseFlags(flagSet, args)

if time.Time(startTime).IsZero() {
startTime = timestamp(time.Unix(0, 0))
startTime = human.Time(time.Unix(0, 0))
}
if duration == 0 {
duration = time.Duration(math.MaxInt64)
duration = human.Duration(math.MaxInt64)
}

args = flagSet.Args()
Expand Down Expand Up @@ -122,16 +123,16 @@ func profile(ctx context.Context, args []string) error {
records := &recordProfiler{
records: timemachine.NewLogRecordReader(logReader),
startTime: time.Time(startTime),
endTime: time.Time(startTime).Add(duration),
sampleRate: sampleRate,
endTime: time.Time(startTime).Add(time.Duration(duration)),
sampleRate: float64(sampleRate),
}

records.cpu = wzprof.NewCPUProfiler(wzprof.TimeFunc(records.now))
records.mem = wzprof.NewMemoryProfiler()
defer func() {
records.stop()
writeProfile("cpu", cpuProfile, records.cpuProfile)
writeProfile("memory", memProfile, records.memProfile)
writeProfile("cpu", string(cpuProfile), records.cpuProfile)
writeProfile("memory", string(memProfile), records.memProfile)
}()

ctx = context.WithValue(ctx,
Expand Down
5 changes: 3 additions & 2 deletions internal/cmd/replay.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/google/uuid"
"github.com/stealthrocket/wasi-go"

"github.com/stealthrocket/timecraft/internal/print/human"
"github.com/stealthrocket/timecraft/internal/timemachine"
"github.com/stealthrocket/timecraft/internal/timemachine/wasicall"
"github.com/stealthrocket/wasi-go/imports/wasi_snapshot_preview1"
Expand All @@ -27,12 +28,12 @@ Options:

func replay(ctx context.Context, args []string) error {
var (
registryPath = "~/.timecraft"
registryPath = human.Path("~/.timecraft")
trace = false
)

flagSet := newFlagSet("timecraft replay", replayUsage)
stringVar(flagSet, &registryPath, "r", "registry")
customVar(flagSet, &registryPath, "r", "registry")
boolVar(flagSet, &trace, "T", "trace")
parseFlags(flagSet, args)

Expand Down
108 changes: 40 additions & 68 deletions internal/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,10 @@ import (
"log"
_ "net/http/pprof"
"os"
"os/user"
"path/filepath"
"strings"
"time"

"github.com/stealthrocket/timecraft/internal/object"
"github.com/stealthrocket/timecraft/internal/print/human"
"github.com/stealthrocket/timecraft/internal/timemachine"
)

Expand Down Expand Up @@ -105,23 +103,34 @@ func Root(ctx context.Context, args ...string) int {
}
}

type timestamp time.Time

func (ts timestamp) String() string {
t := time.Time(ts)
if t.IsZero() {
return "start"
func setEnum[T ~string](enum *T, typ string, value string, options ...string) error {
for _, option := range options {
if option == value {
*enum = T(option)
return nil
}
}
return t.Format(time.RFC3339)
return fmt.Errorf("unsupported %s: %q (not one of %s)", typ, value, strings.Join(options, ", "))
}

func (ts *timestamp) Set(value string) error {
t, err := time.Parse(time.RFC3339, value)
if err != nil {
return err
}
*ts = timestamp(t)
return nil
type compression string

func (c compression) String() string {
return string(c)
}

func (c *compression) Set(value string) error {
return setEnum(c, "compression type", value, "snappy", "zstd", "none")
}

type sockets string

func (s sockets) String() string {
return string(s)
}

func (s *sockets) Set(value string) error {
return setEnum(s, "sockets extension", value, "none", "auto", "path_open", "wasmedgev1", "wasmedgev2")
}

type outputFormat string
Expand All @@ -131,13 +140,7 @@ func (o outputFormat) String() string {
}

func (o *outputFormat) Set(value string) error {
switch value {
case "text", "json", "yaml":
*o = outputFormat(value)
return nil
default:
return fmt.Errorf("unsupported output format: %q", value)
}
return setEnum(o, "output format", value, "text", "json", "yaml")
}

type stringList []string
Expand All @@ -151,25 +154,25 @@ func (s *stringList) Set(value string) error {
return nil
}

func createRegistry(path string) (*timemachine.Registry, error) {
path, err := resolvePath(path)
func createRegistry(path human.Path) (*timemachine.Registry, error) {
p, err := path.Resolve()
if err != nil {
return nil, err
}
if err := os.Mkdir(path, 0777); err != nil {
if err := os.Mkdir(p, 0777); err != nil {
if !errors.Is(err, fs.ErrExist) {
return nil, err
}
}
return openRegistry(path)
return openRegistry(human.Path(p))
}

func openRegistry(path string) (*timemachine.Registry, error) {
path, err := resolvePath(path)
func openRegistry(path human.Path) (*timemachine.Registry, error) {
p, err := path.Resolve()
if err != nil {
return nil, err
}
store, err := object.DirStore(path)
store, err := object.DirStore(p)
if err != nil {
return nil, err
}
Expand All @@ -179,17 +182,6 @@ func openRegistry(path string) (*timemachine.Registry, error) {
return registry, nil
}

func resolvePath(path string) (string, error) {
if strings.HasPrefix(path, "~") {
u, err := user.Current()
if err != nil {
return "", err
}
path = filepath.Join(u.HomeDir, path[1:])
}
return path, nil
}

func newFlagSet(cmd, usage string) *flag.FlagSet {
flagSet := flag.NewFlagSet(cmd, flag.ExitOnError)
flagSet.Usage = func() { fmt.Println(usage) }
Expand All @@ -203,36 +195,16 @@ func parseFlags(f *flag.FlagSet, args []string) {
}
}

func customVar(f *flag.FlagSet, dst flag.Value, name string, alias ...string) {
f.Var(dst, name, "")
func boolVar(f *flag.FlagSet, dst *bool, name string, alias ...string) {
f.BoolVar(dst, name, *dst, "")
for _, name := range alias {
f.Var(dst, name, "")
f.BoolVar(dst, name, *dst, "")
}
}

func durationVar(f *flag.FlagSet, dst *time.Duration, name string, alias ...string) {
setFlagVar(f.DurationVar, dst, name, alias)
}

func stringVar(f *flag.FlagSet, dst *string, name string, alias ...string) {
setFlagVar(f.StringVar, dst, name, alias)
}

func boolVar(f *flag.FlagSet, dst *bool, name string, alias ...string) {
setFlagVar(f.BoolVar, dst, name, alias)
}

func intVar(f *flag.FlagSet, dst *int, name string, alias ...string) {
setFlagVar(f.IntVar, dst, name, alias)
}

func float64Var(f *flag.FlagSet, dst *float64, name string, alias ...string) {
setFlagVar(f.Float64Var, dst, name, alias)
}

func setFlagVar[T any](set func(*T, string, T, string), dst *T, name string, alias []string) {
set(dst, name, *dst, "")
func customVar(f *flag.FlagSet, dst flag.Value, name string, alias ...string) {
f.Var(dst, name, "")
for _, name := range alias {
set(dst, name, *dst, "")
f.Var(dst, name, "")
}
}
24 changes: 12 additions & 12 deletions internal/cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"time"

"github.com/google/uuid"

"github.com/stealthrocket/timecraft/format"
"github.com/stealthrocket/timecraft/internal/object"
"github.com/stealthrocket/timecraft/internal/print/human"
"github.com/stealthrocket/timecraft/internal/timemachine"
"github.com/stealthrocket/timecraft/internal/timemachine/wasicall"
"github.com/stealthrocket/wasi-go"
Expand Down Expand Up @@ -43,10 +43,10 @@ func run(ctx context.Context, args []string) error {
envs stringList
listens stringList
dials stringList
batchSize = 4096
compression = "zstd"
sockets = "auto"
registryPath = "~/.timecraft"
batchSize = human.Count(4096)
compression = compression("zstd")
sockets = sockets("auto")
registryPath = human.Path("~/.timecraft")
record = false
trace = false
)
Expand All @@ -55,12 +55,12 @@ func run(ctx context.Context, args []string) error {
customVar(flagSet, &envs, "e", "env")
customVar(flagSet, &listens, "L", "listen")
customVar(flagSet, &dials, "D", "dial")
stringVar(flagSet, &sockets, "S", "sockets")
stringVar(flagSet, &registryPath, "r", "registry")
customVar(flagSet, &sockets, "S", "sockets")
customVar(flagSet, &registryPath, "r", "registry")
boolVar(flagSet, &trace, "T", "trace")
boolVar(flagSet, &record, "R", "record")
intVar(flagSet, &batchSize, "record-batch-size")
stringVar(flagSet, &compression, "record-compression")
customVar(flagSet, &batchSize, "record-batch-size")
customVar(flagSet, &compression, "record-compression")
parseFlags(flagSet, args)

envs = append(os.Environ(), envs...)
Expand Down Expand Up @@ -105,12 +105,12 @@ func run(ctx context.Context, args []string) error {
WithListens(listens...).
WithDials(dials...).
WithStdio(stdin, stdout, stderr).
WithSocketsExtension(sockets, wasmModule).
WithSocketsExtension(string(sockets), wasmModule).
WithTracer(trace, os.Stderr)

if record {
var c timemachine.Compression
switch strings.ToLower(compression) {
switch compression {
case "snappy":
c = timemachine.Snappy
case "zstd":
Expand Down Expand Up @@ -174,7 +174,7 @@ func run(ctx context.Context, args []string) error {
defer logSegment.Close()
logWriter := timemachine.NewLogWriter(logSegment)

recordWriter := timemachine.NewLogRecordWriter(logWriter, batchSize, c)
recordWriter := timemachine.NewLogRecordWriter(logWriter, int(batchSize), c)
defer recordWriter.Flush()

builder = builder.WithWrappers(func(s wasi.System) wasi.System {
Expand Down
Loading
Loading