diff --git a/Makefile b/Makefile index 55bbbbf2..471230c3 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,9 @@ -.PHONY: clean flatbuffers generate test +.PHONY: clean flatbuffers generate test testdata .PRECIOUS: %.wasm +testdata.go.src = $(wildcard testdata/go/*.go) +testdata.go.wasm = $(testdata.go.src:.go=.wasm) + format.src.fbs = \ $(wildcard format/*/*.fbs) format.src.go = \ @@ -16,16 +19,21 @@ timecraft: go.mod $(timecraft.src.go) go build -o timecraft clean: - rm -f timecraft $(format.src.go) + rm -f timecraft $(format.src.go) $(testdata.go.wasm) generate: flatbuffers flatbuffers: go.mod $(format.src.go) go build ./format/... -test: flatbuffers +test: flatbuffers testdata go test -v ./... +testdata: $(testdata.go.wasm) + +testdata/go/%.wasm: testdata/go/%.go + GOARCH=wasm GOOS=wasip1 gotip build -o $@ $< + # We run goimports because the flatc compiler sometimes adds an unused import of # strconv. %_generated.go: %.fbs diff --git a/format/logcache/logcache.fbs b/format/logcache/logcache.fbs index 8066a3dc..551e0344 100644 --- a/format/logcache/logcache.fbs +++ b/format/logcache/logcache.fbs @@ -7,7 +7,7 @@ namespace logcache; // // The file is designed to contain one or more records. The intent is to // support grouping together caches of records that are likely to be accessed -// together (e.g. multiple stages of a transation). Bulk lookup operations +// together (e.g. multiple stages of a transaction). Bulk lookup operations // can then hit a single record set, which causes a single update of the LRU // and single access to the storage layer. table RecordSet { diff --git a/format/logsegment/logsegment.fbs b/format/logsegment/logsegment.fbs index 8215d46e..1e48874c 100644 --- a/format/logsegment/logsegment.fbs +++ b/format/logsegment/logsegment.fbs @@ -23,7 +23,7 @@ table RecordBatch { compression:types.Compression; } -// The Record table holds metdata about the recording of a single host function +// The Record table holds metadata about the recording of a single host function // call. table Record { // Monotonic timestamp relative to the process start time of the function diff --git a/format/logsnapshot/logsnapshot.fbs b/format/logsnapshot/logsnapshot.fbs index ae0341a9..088c6010 100644 --- a/format/logsnapshot/logsnapshot.fbs +++ b/format/logsnapshot/logsnapshot.fbs @@ -2,7 +2,7 @@ include "../types/types.fbs"; namespace logsnapshot; -// RecordRange represents the snapshot of mutations that occured over a +// RecordRange represents the snapshot of mutations that occurred over a // range of log records. table RecordRange { // Unique identifier of the process that the range was snapshot was generated @@ -26,10 +26,10 @@ table RecordRange { uncompressed_size:uint; // Compression algorithm used to encode the record range data sections. compression:types.Compression; - // CRC32 cheksum of the record range data section (Castagnoli). + // CRC32 checksum of the record range data section (Castagnoli). checksum:uint; // Unique identifier for the OCI layer which records the file system mutations - // that occured through the file range. + // that occurred through the file range. oci_layer:types.Hash; // List of files opened at the end the range. open_files:[OpenFile]; diff --git a/internal/cmd/help.go b/internal/cmd/help.go index c4a84657..e29b613d 100644 --- a/internal/cmd/help.go +++ b/internal/cmd/help.go @@ -23,7 +23,7 @@ For a description of each command, run 'timecraft help '.` func help(ctx context.Context, args []string) error { flagSet := newFlagSet("timecraft help", helpUsage) - flagSet.Parse(args) + parseFlags(flagSet, args) var cmd string var msg string diff --git a/internal/cmd/profile.go b/internal/cmd/profile.go index d6ca3efb..8e81670d 100644 --- a/internal/cmd/profile.go +++ b/internal/cmd/profile.go @@ -69,7 +69,7 @@ func profile(ctx context.Context, args []string) error { stringVar(flagSet, &cpuProfile, "cpuprofile") stringVar(flagSet, &memProfile, "memprofile") stringVar(flagSet, ®istryPath, "r", "registry") - flagSet.Parse(args) + parseFlags(flagSet, args) if time.Time(startTime).IsZero() { startTime = timestamp(time.Unix(0, 0)) diff --git a/internal/cmd/profile_test.go b/internal/cmd/profile_test.go new file mode 100644 index 00000000..3ae0261e --- /dev/null +++ b/internal/cmd/profile_test.go @@ -0,0 +1,39 @@ +package cmd_test + +import ( + "context" + + "github.com/stealthrocket/timecraft/internal/cmd" +) + +func ExampleRoot_profileMissingID() { + ctx := context.Background() + + FAIL(cmd.Root(ctx, "profile")) + // Output: + // ERR: timecraft profile: expected exactly one process id as argument +} + +func ExampleRoot_profileTooManyArgs() { + ctx := context.Background() + + FAIL(cmd.Root(ctx, "profile", "1", "2", "3")) + // Output: + // ERR: timecraft profile: expected exactly one process id as argument +} + +func ExampleRoot_profileInvalidID() { + ctx := context.Background() + + FAIL(cmd.Root(ctx, "profile", "1234567890")) + // Output: + // ERR: timecraft profile: malformed process id passed as argument (not a UUID) +} + +func ExampleRoot_profileUnknownID() { + ctx := context.Background() + + FAIL(cmd.Root(ctx, "profile", "b0f4dac5-9855-4cde-89fd-ebd3713c2249")) + // Output: + // ERR: timecraft profile: process has no records: b0f4dac5-9855-4cde-89fd-ebd3713c2249 +} diff --git a/internal/cmd/replay.go b/internal/cmd/replay.go index d8b0733d..a1ebf4e9 100644 --- a/internal/cmd/replay.go +++ b/internal/cmd/replay.go @@ -34,7 +34,7 @@ func replay(ctx context.Context, args []string) error { flagSet := newFlagSet("timecraft replay", replayUsage) stringVar(flagSet, ®istryPath, "r", "registry") boolVar(flagSet, &trace, "T", "trace") - flagSet.Parse(args) + parseFlags(flagSet, args) args = flagSet.Args() if len(args) != 1 { diff --git a/internal/cmd/root.go b/internal/cmd/root.go index b496c113..4804493c 100644 --- a/internal/cmd/root.go +++ b/internal/cmd/root.go @@ -66,9 +66,9 @@ func init() { } // Root is the timecraft entrypoint. -func Root(ctx context.Context, args []string) int { +func Root(ctx context.Context, args ...string) int { flagSet := newFlagSet("timecraft", helpUsage) - flagSet.Parse(args) + parseFlags(flagSet, args) if args = flagSet.Args(); len(args) == 0 { fmt.Println(rootUsage) @@ -98,7 +98,7 @@ func Root(ctx context.Context, args []string) int { case ExitCode: return int(e) default: - fmt.Fprintf(os.Stderr, "ERR: timecraft %s: %s\n", cmd, err) + fmt.Printf("ERR: timecraft %s: %s\n", cmd, err) return 1 } } @@ -175,6 +175,13 @@ func newFlagSet(cmd, usage string) *flag.FlagSet { return flagSet } +func parseFlags(f *flag.FlagSet, args []string) { + // The flag set is consutrcted with ExitOnError, it should never error. + if err := f.Parse(args); err != nil { + panic(err) + } +} + func customVar(f *flag.FlagSet, dst flag.Value, name string, alias ...string) { f.Var(dst, name, "") for _, name := range alias { diff --git a/internal/cmd/root_test.go b/internal/cmd/root_test.go new file mode 100644 index 00000000..69240d3a --- /dev/null +++ b/internal/cmd/root_test.go @@ -0,0 +1,18 @@ +package cmd_test + +import ( + "fmt" + "os" +) + +func PASS(rc int) { + if rc != 0 { + fmt.Fprintf(os.Stderr, "exit: %d\n", rc) + } +} + +func FAIL(rc int) { + if rc != 1 { + fmt.Fprintf(os.Stderr, "exit: %d\n", rc) + } +} diff --git a/internal/cmd/run.go b/internal/cmd/run.go index 499741e6..4dc87742 100644 --- a/internal/cmd/run.go +++ b/internal/cmd/run.go @@ -60,7 +60,7 @@ func run(ctx context.Context, args []string) error { boolVar(flagSet, &record, "R", "record") intVar(flagSet, &batchSize, "record-batch-size") stringVar(flagSet, &compression, "record-compression") - flagSet.Parse(args) + parseFlags(flagSet, args) envs = append(os.Environ(), envs...) args = flagSet.Args() @@ -90,13 +90,20 @@ func run(ctx context.Context, args []string) error { } defer wasmModule.Close(ctx) + // When running cmd.Root from testable examples, the standard streams are + // not set to alternative files and the fd numbers are not 0, 1, 2. + stdin := int(os.Stdin.Fd()) + stdout := int(os.Stdout.Fd()) + stderr := int(os.Stderr.Fd()) + builder := imports.NewBuilder(). WithName(wasmName). - WithArgs(args...). + WithArgs(args[1:]...). WithEnv(envs...). WithDirs("/"). WithListens(listens...). WithDials(dials...). + WithStdio(stdin, stdout, stderr). WithSocketsExtension(sockets, wasmModule). WithTracer(trace, os.Stderr) @@ -204,14 +211,16 @@ func exec(ctx context.Context, runtime wazero.Runtime, compiledModule wazero.Com <-ctx.Done() - switch err := context.Cause(ctx).(type) { - case nil: + err = context.Cause(ctx) + switch err { + case context.Canceled, context.DeadlineExceeded: + err = nil + } + + switch e := err.(type) { case *sys.ExitError: - if exitCode := err.ExitCode(); exitCode != 0 { - return ExitCode(exitCode) - } - default: - return err + return ExitCode(e.ExitCode()) } - return nil + + return err } diff --git a/internal/cmd/run_test.go b/internal/cmd/run_test.go new file mode 100644 index 00000000..6fa44031 --- /dev/null +++ b/internal/cmd/run_test.go @@ -0,0 +1,22 @@ +package cmd_test + +import ( + "context" + + "github.com/stealthrocket/timecraft/internal/cmd" +) + +func ExampleRoot_runExitZero() { + ctx := context.Background() + + PASS(cmd.Root(ctx, "run", "../../testdata/go/sleep.wasm", "10ms")) + // Output: sleeping for 10ms +} + +func ExampleRoot_runContextCanceled() { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + PASS(cmd.Root(ctx, "run", "../../testdata/go/sleep.wasm", "10s")) + // Output: +} diff --git a/internal/cmd/version.go b/internal/cmd/version.go index 2752cc95..8960d92d 100644 --- a/internal/cmd/version.go +++ b/internal/cmd/version.go @@ -15,15 +15,20 @@ Options: func version(ctx context.Context, args []string) error { flagSet := newFlagSet("timecraft version", versionUsage) - flagSet.Parse(args) + parseFlags(flagSet, args) fmt.Printf("timecraft %s\n", currentVersion()) return nil } func currentVersion() string { version := "devel" - if info, ok := debug.ReadBuildInfo(); ok && info.Main.Version != "(devel)" { - version = info.Main.Version + if info, ok := debug.ReadBuildInfo(); ok { + switch info.Main.Version { + case "": + case "(devel)": + default: + version = info.Main.Version + } } return version } diff --git a/internal/cmd/version_test.go b/internal/cmd/version_test.go new file mode 100644 index 00000000..28e49c70 --- /dev/null +++ b/internal/cmd/version_test.go @@ -0,0 +1,15 @@ +package cmd_test + +import ( + "context" + + "github.com/stealthrocket/timecraft/internal/cmd" +) + +func ExampleRoot_version() { + ctx := context.Background() + + PASS(cmd.Root(ctx, "version")) + // Output: + // timecraft devel +} diff --git a/internal/object/store.go b/internal/object/store.go index 8323b8af..267bc99f 100644 --- a/internal/object/store.go +++ b/internal/object/store.go @@ -32,7 +32,7 @@ import ( ) var ( - // ErrNotExist is an error value which may be tested aginst to determine + // ErrNotExist is an error value which may be tested against to determine // whether a method invocation from a Store instance failed due to being // called on an object which did not exist. ErrNotExist = fs.ErrNotExist diff --git a/internal/object/store_test.go b/internal/object/store_test.go index 46086fe6..6ea1be6d 100644 --- a/internal/object/store_test.go +++ b/internal/object/store_test.go @@ -36,7 +36,7 @@ func testObjectStore(t *testing.T, newStore func(*testing.T) (object.Store, func }, { - scenario: "deleting non existing objects from an emtpy store", + scenario: "deleting non existing objects from an empty store", function: testObjectStoreDeleteEmpty, }, @@ -172,7 +172,8 @@ func testObjectStoreListWhileCreate(t *testing.T, ctx context.Context, store obj assert.OK(t, store.CreateObject(ctx, "test-3", r)) }() - io.WriteString(w, "H") + _, err := io.WriteString(w, "H") + assert.OK(t, err) beforeCreateObject := readValues(t, store.ListObjects(ctx, ".")) clearCreatedAt(beforeCreateObject) @@ -183,8 +184,9 @@ func testObjectStoreListWhileCreate(t *testing.T, ctx context.Context, store obj {Name: "test-2", Size: 1}, }) - io.WriteString(w, "ello World!") - w.Close() + _, err = io.WriteString(w, "ello World!") + assert.OK(t, err) + assert.OK(t, w.Close()) <-done afterCreateObject := readValues(t, store.ListObjects(ctx, ".")) diff --git a/internal/stream/stream.go b/internal/stream/stream.go index 156b2ed9..856bde5f 100644 --- a/internal/stream/stream.go +++ b/internal/stream/stream.go @@ -8,7 +8,7 @@ import "io" // of type T. type Reader[T any] interface { // Reads values from the stream, returning the number of values read and any - // error that occured. + // error that occurred. // // The error is io.EOF when the end of the stream has been reached. Read(values []T) (int, error) @@ -62,7 +62,7 @@ func (r *nopCloser[T]) Close() error { return nil } func (r *nopCloser[T]) Read(values []T) (int, error) { return r.reader.Read(values) } // ReadAll reads all values from r and returns them as a slice, along with any -// error that occured (other than io.EOF). +// error that occurred (other than io.EOF). func ReadAll[T any](r Reader[T]) ([]T, error) { values := make([]T, 0, 1) for { diff --git a/internal/timemachine/hash.go b/internal/timemachine/hash.go index b141aa19..2347190c 100644 --- a/internal/timemachine/hash.go +++ b/internal/timemachine/hash.go @@ -4,9 +4,7 @@ import ( "fmt" "io" - flatbuffers "github.com/google/flatbuffers/go" "github.com/stealthrocket/timecraft/format" - "github.com/stealthrocket/timecraft/format/types" ) type Hash = format.Hash @@ -23,19 +21,3 @@ func UUIDv4(r io.Reader) Hash { s := fmt.Sprintf("%08x-%04x-%04x-%04x-%012x", uuid[:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]) return Hash{Algorithm: "uuidv4", Digest: s} } - -func makeHash(h *types.Hash) Hash { - return Hash{ - Algorithm: string(h.Algorithm()), - Digest: string(h.Digest()), - } -} - -func prependHash(b *flatbuffers.Builder, h Hash) flatbuffers.UOffsetT { - algorithm := b.CreateSharedString(h.Algorithm) - digest := b.CreateString(h.Digest) - types.HashStart(b) - types.HashAddAlgorithm(b, algorithm) - types.HashAddDigest(b, digest) - return types.HashEnd(b) -} diff --git a/internal/timemachine/log_test.go b/internal/timemachine/log_test.go index 6fd83155..c9988ee0 100644 --- a/internal/timemachine/log_test.go +++ b/internal/timemachine/log_test.go @@ -88,7 +88,7 @@ func TestReadRecordBatch(t *testing.T) { r := iter.Value() assert.Less(t, count, len(records)) records[count] = record{ - Timestamp: r.Timestamp(), + Timestamp: r.Time(), FunctionID: r.FunctionID(), FunctionCall: r.FunctionCall(), } diff --git a/internal/timemachine/registry.go b/internal/timemachine/registry.go index 07deb881..962e4bef 100644 --- a/internal/timemachine/registry.go +++ b/internal/timemachine/registry.go @@ -15,6 +15,12 @@ import ( "github.com/stealthrocket/timecraft/internal/stream" ) +var ( + // ErrNoRecords is an error returned when no log records could be found for + // a given process id. + ErrNoLogRecords = errors.New("process has no records") +) + type ModuleInfo struct { ID Hash Size int64 @@ -79,16 +85,12 @@ func errorCreateObject(hash format.Hash, value format.Resource, err error) error return fmt.Errorf("create object: %s: %s: %w", hash, value.ContentType(), err) } -func errorDeleteObject(hash format.Hash, err error) error { - return fmt.Errorf("delete object: %s: %w", hash, err) -} - func errorLookupObject(hash format.Hash, value format.Resource, err error) error { return fmt.Errorf("lookup object: %s: %s: %w", hash, value.ContentType(), err) } -func errorLookupDescriptor(hash format.Hash, err error) error { - return fmt.Errorf("lookup descriptor: %s: %w", hash, err) +func errorLookupDescriptor(hash format.Hash, value format.Resource, err error) error { + return fmt.Errorf("lookup descriptor: %s: %s: %w", hash, value.ContentType(), err) } func (reg *Registry) createObject(ctx context.Context, value format.ResourceMarshaler) (*format.Descriptor, error) { @@ -105,7 +107,7 @@ func (reg *Registry) createObject(ctx context.Context, value format.ResourceMars return descriptor, nil } if !errors.Is(err, object.ErrNotExist) { - return nil, errorCreateObject(hash, value, err) + return nil, errorLookupDescriptor(hash, value, err) } descriptor = &format.Descriptor{ @@ -127,16 +129,6 @@ func (reg *Registry) createObject(ctx context.Context, value format.ResourceMars return descriptor, nil } -func (reg *Registry) deleteObject(ctx context.Context, hash format.Hash) error { - if err := reg.objects.DeleteObject(ctx, reg.objectKey(hash)); err != nil { - return errorDeleteObject(hash, err) - } - if err := reg.objects.DeleteObject(ctx, reg.descriptorKey(hash)); err != nil { - return errorDeleteObject(hash, err) - } - return nil -} - func (reg *Registry) lookupDescriptor(ctx context.Context, key string) (*format.Descriptor, error) { r, err := reg.objects.ReadObject(ctx, key) if err != nil { @@ -231,6 +223,9 @@ func (reg *Registry) ListLogSegments(ctx context.Context, processID format.UUID) func (reg *Registry) LookupLogManifest(ctx context.Context, processID format.UUID) (*format.Manifest, error) { r, err := reg.objects.ReadObject(ctx, reg.manifestKey(processID)) if err != nil { + if errors.Is(err, object.ErrNotExist) { + err = fmt.Errorf("%w: %s", ErrNoLogRecords, processID) + } return nil, err } defer r.Close() @@ -246,7 +241,13 @@ func (reg *Registry) LookupLogManifest(ctx context.Context, processID format.UUI } func (reg *Registry) ReadLogSegment(ctx context.Context, processID format.UUID, segmentNumber int) (io.ReadCloser, error) { - return reg.objects.ReadObject(ctx, reg.logKey(processID, segmentNumber)) + r, err := reg.objects.ReadObject(ctx, reg.logKey(processID, segmentNumber)) + if err != nil { + if errors.Is(err, object.ErrNotExist) { + err = fmt.Errorf("%w: %s", ErrNoLogRecords, processID) + } + } + return r, err } func (reg *Registry) logKey(processID format.UUID, segmentNumber int) string { diff --git a/internal/timemachine/wasicall/codec.go b/internal/timemachine/wasicall/codec.go index 80cdc4b7..e6198407 100644 --- a/internal/timemachine/wasicall/codec.go +++ b/internal/timemachine/wasicall/codec.go @@ -36,7 +36,7 @@ func (c *Codec) DecodeArgsSizesGet(buffer []byte) (argCount, stringBytes int, er if argCount, buffer, err = decodeInt(buffer); err != nil { return } - stringBytes, buffer, err = decodeInt(buffer) + stringBytes, _, err = decodeInt(buffer) return } @@ -49,7 +49,7 @@ func (c *Codec) DecodeArgsGet(buffer []byte, args []string) (_ []string, errno E if errno, buffer, err = decodeErrno(buffer); err != nil { return } - args, buffer, err = decodeStrings(buffer, args) + args, _, err = decodeStrings(buffer, args) return args, errno, err } @@ -66,7 +66,7 @@ func (c *Codec) DecodeEnvironSizesGet(buffer []byte) (envCount, stringBytes int, if envCount, buffer, err = decodeInt(buffer); err != nil { return } - stringBytes, buffer, err = decodeInt(buffer) + stringBytes, _, err = decodeInt(buffer) return } @@ -79,7 +79,7 @@ func (c *Codec) DecodeEnvironGet(buffer []byte, env []string) (_ []string, errno if errno, buffer, err = decodeErrno(buffer); err != nil { return } - env, buffer, err = decodeStrings(buffer, env) + env, _, err = decodeStrings(buffer, env) return env, errno, err } @@ -96,7 +96,7 @@ func (c *Codec) DecodeClockResGet(buffer []byte) (id ClockID, timestamp Timestam if id, buffer, err = decodeClockID(buffer); err != nil { return } - timestamp, buffer, err = decodeTimestamp(buffer) + timestamp, _, err = decodeTimestamp(buffer) return } @@ -117,7 +117,7 @@ func (c *Codec) DecodeClockTimeGet(buffer []byte) (id ClockID, precision Timesta if precision, buffer, err = decodeTimestamp(buffer); err != nil { return } - timestamp, buffer, err = decodeTimestamp(buffer) + timestamp, _, err = decodeTimestamp(buffer) return } @@ -142,7 +142,7 @@ func (c *Codec) DecodeFDAdvise(buffer []byte) (fd FD, offset FileSize, length Fi if length, buffer, err = decodeFileSize(buffer); err != nil { return } - advice, buffer, err = decodeAdvice(buffer) + advice, _, err = decodeAdvice(buffer) return } @@ -163,7 +163,7 @@ func (c *Codec) DecodeFDAllocate(buffer []byte) (fd FD, offset FileSize, length if offset, buffer, err = decodeFileSize(buffer); err != nil { return } - length, buffer, err = decodeFileSize(buffer) + length, _, err = decodeFileSize(buffer) return } @@ -176,7 +176,7 @@ func (c *Codec) DecodeFDClose(buffer []byte) (fd FD, errno Errno, err error) { if errno, buffer, err = decodeErrno(buffer); err != nil { return } - fd, buffer, err = decodeFD(buffer) + fd, _, err = decodeFD(buffer) return } @@ -189,7 +189,7 @@ func (c *Codec) DecodeFDDataSync(buffer []byte) (fd FD, errno Errno, err error) if errno, buffer, err = decodeErrno(buffer); err != nil { return } - fd, buffer, err = decodeFD(buffer) + fd, _, err = decodeFD(buffer) return } @@ -206,7 +206,7 @@ func (c *Codec) DecodeFDStatGet(buffer []byte) (fd FD, stat FDStat, errno Errno, if fd, buffer, err = decodeFD(buffer); err != nil { return } - stat, buffer, err = decodeFDStat(buffer) + stat, _, err = decodeFDStat(buffer) return } @@ -223,7 +223,7 @@ func (c *Codec) DecodeFDStatSetFlags(buffer []byte) (fd FD, flags FDFlags, errno if fd, buffer, err = decodeFD(buffer); err != nil { return } - flags, buffer, err = decodeFDFlags(buffer) + flags, _, err = decodeFDFlags(buffer) return } @@ -244,7 +244,7 @@ func (c *Codec) DecodeFDStatSetRights(buffer []byte) (fd FD, rightsBase, rightsI if rightsBase, buffer, err = decodeRights(buffer); err != nil { return } - rightsInheriting, buffer, err = decodeRights(buffer) + rightsInheriting, _, err = decodeRights(buffer) return } @@ -261,7 +261,7 @@ func (c *Codec) DecodeFDFileStatGet(buffer []byte) (fd FD, stat FileStat, errno if fd, buffer, err = decodeFD(buffer); err != nil { return } - stat, buffer, err = decodeFileStat(buffer) + stat, _, err = decodeFileStat(buffer) return } @@ -278,7 +278,7 @@ func (c *Codec) DecodeFDFileStatSetSize(buffer []byte) (fd FD, size FileSize, er if fd, buffer, err = decodeFD(buffer); err != nil { return } - size, buffer, err = decodeFileSize(buffer) + size, _, err = decodeFileSize(buffer) return } @@ -303,7 +303,7 @@ func (c *Codec) DecodeFDFileStatSetTimes(buffer []byte) (fd FD, accessTime, modi if modifyTime, buffer, err = decodeTimestamp(buffer); err != nil { return } - flags, buffer, err = decodeFSTFlags(buffer) + flags, _, err = decodeFSTFlags(buffer) return } @@ -328,7 +328,7 @@ func (c *Codec) DecodeFDPread(buffer []byte, iovecs []IOVec) (fd FD, _ []IOVec, if offset, buffer, err = decodeFileSize(buffer); err != nil { return } - size, buffer, err = decodeSize(buffer) + size, _, err = decodeSize(buffer) return fd, iovecs, offset, size, errno, err } @@ -345,7 +345,7 @@ func (c *Codec) DecodeFDPreStatGet(buffer []byte) (fd FD, stat PreStat, errno Er if fd, buffer, err = decodeFD(buffer); err != nil { return } - stat, buffer, err = decodePreStat(buffer) + stat, _, err = decodePreStat(buffer) return } @@ -362,7 +362,7 @@ func (c *Codec) DecodeFDPreStatDirName(buffer []byte) (fd FD, name string, errno if fd, buffer, err = decodeFD(buffer); err != nil { return } - name, buffer, err = decodeString(buffer) + name, _, err = decodeString(buffer) return } @@ -387,7 +387,7 @@ func (c *Codec) DecodeFDPwrite(buffer []byte, iovecs []IOVec) (fd FD, _ []IOVec, if offset, buffer, err = decodeFileSize(buffer); err != nil { return } - size, buffer, err = decodeSize(buffer) + size, _, err = decodeSize(buffer) return fd, iovecs, offset, size, errno, err } @@ -408,7 +408,7 @@ func (c *Codec) DecodeFDRead(buffer []byte, iovecs []IOVec) (fd FD, _ []IOVec, s if iovecs, buffer, err = decodeIOVecs(buffer, iovecs); err != nil { return } - size, buffer, err = decodeSize(buffer) + size, _, err = decodeSize(buffer) return fd, iovecs, size, errno, err } @@ -437,7 +437,7 @@ func (c *Codec) DecodeFDReadDir(buffer []byte, entries []DirEntry) (fd FD, _ []D if bufferSizeBytes, buffer, err = decodeInt(buffer); err != nil { return } - count, buffer, err = decodeInt(buffer) + count, _, err = decodeInt(buffer) return fd, entries, cookie, bufferSizeBytes, count, errno, err } @@ -454,7 +454,7 @@ func (c *Codec) DecodeFDRenumber(buffer []byte) (from, to FD, errno Errno, err e if from, buffer, err = decodeFD(buffer); err != nil { return } - to, buffer, err = decodeFD(buffer) + to, _, err = decodeFD(buffer) return } @@ -479,7 +479,7 @@ func (c *Codec) DecodeFDSeek(buffer []byte) (fd FD, seekOffset FileDelta, whence if whence, buffer, err = decodeWhence(buffer); err != nil { return } - offset, buffer, err = decodeFileSize(buffer) + offset, _, err = decodeFileSize(buffer) return } @@ -492,7 +492,7 @@ func (c *Codec) DecodeFDSync(buffer []byte) (fd FD, errno Errno, err error) { if errno, buffer, err = decodeErrno(buffer); err != nil { return } - fd, buffer, err = decodeFD(buffer) + fd, _, err = decodeFD(buffer) return } @@ -509,7 +509,7 @@ func (c *Codec) DecodeFDTell(buffer []byte) (fd FD, offset FileSize, errno Errno if fd, buffer, err = decodeFD(buffer); err != nil { return } - offset, buffer, err = decodeFileSize(buffer) + offset, _, err = decodeFileSize(buffer) return } @@ -530,7 +530,7 @@ func (c *Codec) DecodeFDWrite(buffer []byte, iovecs []IOVec) (fd FD, _ []IOVec, if iovecs, buffer, err = decodeIOVecs(buffer, iovecs); err != nil { return } - size, buffer, err = decodeSize(buffer) + size, _, err = decodeSize(buffer) return fd, iovecs, size, errno, err } @@ -547,7 +547,7 @@ func (c *Codec) DecodePathCreateDirectory(buffer []byte) (fd FD, path string, er if fd, buffer, err = decodeFD(buffer); err != nil { return } - path, buffer, err = decodeString(buffer) + path, _, err = decodeString(buffer) return } @@ -572,7 +572,7 @@ func (c *Codec) DecodePathFileStatGet(buffer []byte) (fd FD, lookupFlags LookupF if path, buffer, err = decodeString(buffer); err != nil { return } - fileStat, buffer, err = decodeFileStat(buffer) + fileStat, _, err = decodeFileStat(buffer) return } @@ -605,7 +605,7 @@ func (c *Codec) DecodePathFileStatSetTimes(buffer []byte) (fd FD, lookupFlags Lo if modifyTime, buffer, err = decodeTimestamp(buffer); err != nil { return } - flags, buffer, err = decodeFSTFlags(buffer) + flags, _, err = decodeFSTFlags(buffer) return } @@ -634,7 +634,7 @@ func (c *Codec) DecodePathLink(buffer []byte) (oldFD FD, oldFlags LookupFlags, o if newFD, buffer, err = decodeFD(buffer); err != nil { return } - newPath, buffer, err = decodeString(buffer) + newPath, _, err = decodeString(buffer) return } @@ -672,7 +672,7 @@ func (c *Codec) DecodePathOpen(buffer []byte) (fd FD, dirFlags LookupFlags, path if rightsInheriting, buffer, err = decodeRights(buffer); err != nil { return } - fdFlags, buffer, err = decodeFDFlags(buffer) + fdFlags, _, err = decodeFDFlags(buffer) return } @@ -693,7 +693,7 @@ func (c *Codec) DecodePathReadLink(buffer []byte) (fd FD, path string, output [] if path, buffer, err = decodeString(buffer); err != nil { return } - output, buffer, err = decodeBytes(buffer) + output, _, err = decodeBytes(buffer) return } @@ -710,7 +710,7 @@ func (c *Codec) DecodePathRemoveDirectory(buffer []byte) (fd FD, path string, er if fd, buffer, err = decodeFD(buffer); err != nil { return } - path, buffer, err = decodeString(buffer) + path, _, err = decodeString(buffer) return } @@ -735,7 +735,7 @@ func (c *Codec) DecodePathRename(buffer []byte) (fd FD, oldPath string, newFD FD if newFD, buffer, err = decodeFD(buffer); err != nil { return } - newPath, buffer, err = decodeString(buffer) + newPath, _, err = decodeString(buffer) return } @@ -753,7 +753,7 @@ func (c *Codec) DecodePathSymlink(buffer []byte) (oldPath string, fd FD, newPath if fd, buffer, err = decodeFD(buffer); err != nil { return } - newPath, buffer, err = decodeString(buffer) + newPath, _, err = decodeString(buffer) return } @@ -770,7 +770,7 @@ func (c *Codec) DecodePathUnlinkFile(buffer []byte) (fd FD, path string, errno E if fd, buffer, err = decodeFD(buffer); err != nil { return } - path, buffer, err = decodeString(buffer) + path, _, err = decodeString(buffer) return } @@ -787,7 +787,7 @@ func (c *Codec) DecodePollOneOff(buffer []byte, subscriptions []Subscription, ev if subscriptions, buffer, err = decodeSubscriptions(buffer, subscriptions); err != nil { return } - if events, buffer, err = decodeEvents(buffer, events); err != nil { + if events, _, err = decodeEvents(buffer, events); err != nil { return } return subscriptions, events, errno, err @@ -802,7 +802,7 @@ func (c *Codec) DecodeProcExit(buffer []byte) (exitCode ExitCode, errno Errno, e if errno, buffer, err = decodeErrno(buffer); err != nil { return } - exitCode, buffer, err = decodeExitCode(buffer) + exitCode, _, err = decodeExitCode(buffer) return } @@ -815,7 +815,7 @@ func (c *Codec) DecodeProcRaise(buffer []byte) (signal Signal, errno Errno, err if errno, buffer, err = decodeErrno(buffer); err != nil { return } - signal, buffer, err = decodeSignal(buffer) + signal, _, err = decodeSignal(buffer) return } @@ -824,7 +824,7 @@ func (c *Codec) EncodeSchedYield(buffer []byte, errno Errno) []byte { } func (c *Codec) DecodeSchedYield(buffer []byte) (errno Errno, err error) { - errno, buffer, err = decodeErrno(buffer) + errno, _, err = decodeErrno(buffer) return } @@ -838,7 +838,7 @@ func (c *Codec) DecodeRandomGet(buffer []byte) (result []byte, errno Errno, err if errno, buffer, err = decodeErrno(buffer); err != nil { return } - result, buffer, err = decodeBytes(buffer) + result, _, err = decodeBytes(buffer) return } @@ -859,7 +859,7 @@ func (c *Codec) DecodeSockAccept(buffer []byte) (fd FD, flags FDFlags, newfd FD, if flags, buffer, err = decodeFDFlags(buffer); err != nil { return } - newfd, buffer, err = decodeFD(buffer) + newfd, _, err = decodeFD(buffer) return } @@ -888,7 +888,7 @@ func (c *Codec) DecodeSockRecv(buffer []byte, iovecs []IOVec) (fd FD, _ []IOVec, if size, buffer, err = decodeSize(buffer); err != nil { return } - oflags, buffer, err = decodeROFlags(buffer) + oflags, _, err = decodeROFlags(buffer) return fd, iovecs, iflags, size, oflags, errno, err } @@ -913,7 +913,7 @@ func (c *Codec) DecodeSockSend(buffer []byte) (fd FD, iovecs []IOVec, flags SIFl if flags, buffer, err = decodeSIFlags(buffer); err != nil { return } - size, buffer, err = decodeSize(buffer) + size, _, err = decodeSize(buffer) return fd, iovecs, flags, size, errno, err } @@ -930,7 +930,7 @@ func (c *Codec) DecodeSockShutdown(buffer []byte) (fd FD, flags SDFlags, errno E if fd, buffer, err = decodeFD(buffer); err != nil { return } - flags, buffer, err = decodeSDFlags(buffer) + flags, _, err = decodeSDFlags(buffer) return } @@ -963,7 +963,7 @@ func (c *Codec) DecodeSockOpen(buffer []byte) (family ProtocolFamily, socketType if rightsInheriting, buffer, err = decodeRights(buffer); err != nil { return } - fd, buffer, err = decodeFD(buffer) + fd, _, err = decodeFD(buffer) return } @@ -980,7 +980,7 @@ func (c *Codec) DecodeSockBind(buffer []byte) (fd FD, addr SocketAddress, errno if fd, buffer, err = decodeFD(buffer); err != nil { return } - addr, buffer, err = decodeAddr(buffer) + addr, _, err = decodeAddr(buffer) return } @@ -997,7 +997,7 @@ func (c *Codec) DecodeSockConnect(buffer []byte) (fd FD, addr SocketAddress, err if fd, buffer, err = decodeFD(buffer); err != nil { return } - addr, buffer, err = decodeAddr(buffer) + addr, _, err = decodeAddr(buffer) return } @@ -1014,7 +1014,7 @@ func (c *Codec) DecodeSockListen(buffer []byte) (fd FD, backlog int, errno Errno if fd, buffer, err = decodeFD(buffer); err != nil { return } - backlog, buffer, err = decodeInt(buffer) + backlog, _, err = decodeInt(buffer) return } @@ -1043,7 +1043,7 @@ func (c *Codec) DecodeSockSendTo(buffer []byte, iovecs []IOVec) (fd FD, _ []IOVe if addr, buffer, err = decodeAddr(buffer); err != nil { return } - size, buffer, err = decodeSize(buffer) + size, _, err = decodeSize(buffer) return fd, iovecs, iflags, addr, size, errno, err } @@ -1076,7 +1076,7 @@ func (c *Codec) DecodeSockRecvFrom(buffer []byte, iovecs []IOVec) (fd FD, _ []IO if oflags, buffer, err = decodeROFlags(buffer); err != nil { return } - addr, buffer, err = decodeAddr(buffer) + addr, _, err = decodeAddr(buffer) return fd, iovecs, iflags, size, oflags, addr, errno, err } @@ -1101,7 +1101,7 @@ func (c *Codec) DecodeSockGetOptInt(buffer []byte) (fd FD, level SocketOptionLev if option, buffer, err = decodeSocketOption(buffer); err != nil { return } - value, buffer, err = decodeInt(buffer) + value, _, err = decodeInt(buffer) return } @@ -1126,7 +1126,7 @@ func (c *Codec) DecodeSockSetOptInt(buffer []byte) (fd FD, level SocketOptionLev if option, buffer, err = decodeSocketOption(buffer); err != nil { return } - value, buffer, err = decodeInt(buffer) + value, _, err = decodeInt(buffer) return } @@ -1143,7 +1143,7 @@ func (c *Codec) DecodeSockLocalAddress(buffer []byte) (fd FD, addr SocketAddress if fd, buffer, err = decodeFD(buffer); err != nil { return } - addr, buffer, err = decodeAddr(buffer) + addr, _, err = decodeAddr(buffer) return } @@ -1160,7 +1160,7 @@ func (c *Codec) DecodeSockPeerAddress(buffer []byte) (fd FD, addr SocketAddress, if fd, buffer, err = decodeFD(buffer); err != nil { return } - addr, buffer, err = decodeAddr(buffer) + addr, _, err = decodeAddr(buffer) return } @@ -1628,9 +1628,7 @@ func decodePreStat(buffer []byte) (stat PreStat, _ []byte, err error) { if stat.Type, buffer, err = decodePreOpenType(buffer); err != nil { return } - if stat.PreStatDir.NameLength, buffer, err = decodeSize(buffer); err != nil { - return - } + stat.PreStatDir.NameLength, _, err = decodeSize(buffer) return } @@ -1652,9 +1650,7 @@ func decodeFDStat(buffer []byte) (stat FDStat, _ []byte, err error) { if stat.RightsBase, buffer, err = decodeRights(buffer); err != nil { return } - if stat.RightsInheriting, buffer, err = decodeRights(buffer); err != nil { - return - } + stat.RightsInheriting, _, err = decodeRights(buffer) return } @@ -1691,7 +1687,7 @@ func decodeFileStat(buffer []byte) (stat FileStat, _ []byte, err error) { if stat.ModifyTime, buffer, err = decodeTimestamp(buffer); err != nil { return } - stat.ChangeTime, buffer, err = decodeTimestamp(buffer) + stat.ChangeTime, _, err = decodeTimestamp(buffer) return } diff --git a/main.go b/main.go index 6c1dea64..c29d12c2 100644 --- a/main.go +++ b/main.go @@ -11,5 +11,5 @@ import ( func main() { ctx, _ := signal.NotifyContext(context.Background(), syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM) - os.Exit(cmd.Root(ctx, os.Args[1:])) + os.Exit(cmd.Root(ctx, os.Args[1:]...)) } diff --git a/testdata/go/sleep.go b/testdata/go/sleep.go new file mode 100644 index 00000000..e29976cd --- /dev/null +++ b/testdata/go/sleep.go @@ -0,0 +1,25 @@ +package main + +import ( + "fmt" + "os" + "time" +) + +func main() { + durations := make([]time.Duration, len(os.Args)-1) + + for i, sleep := range os.Args[1:] { + d, err := time.ParseDuration(sleep) + if err != nil { + fmt.Fprintf(os.Stderr, "ERR: %s: %s", sleep, err) + os.Exit(1) + } + durations[i] = d + } + + for _, sleep := range durations { + fmt.Printf("sleeping for %s\n", sleep) + time.Sleep(sleep) + } +}