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

Commit

Permalink
Merge pull request #28 from stealthrocket/human-types
Browse files Browse the repository at this point in the history
timecraft: use human types
  • Loading branch information
achille-roussel committed May 29, 2023
2 parents 8de3b88 + c7b21b8 commit 6ae087e
Show file tree
Hide file tree
Showing 24 changed files with 279 additions and 181 deletions.
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

0 comments on commit 6ae087e

Please sign in to comment.