Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
testjson.go205 linesDownload Raw Back to dist
1// Copyright 2023 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.4 5package main6 7import (8	"bytes"9	"encoding/json"10	"errors"11	"fmt"12	"io"13	"sync"14	"time"15)16 17// lockedWriter serializes Write calls to an underlying Writer.18type lockedWriter struct {19	lock sync.Mutex20	w    io.Writer21}22 23func (w *lockedWriter) Write(b []byte) (int, error) {24	w.lock.Lock()25	defer w.lock.Unlock()26	return w.w.Write(b)27}28 29// testJSONFilter is an io.Writer filter that replaces the Package field in30// test2json output.31type testJSONFilter struct {32	w       io.Writer // Underlying writer33	variant string    // Add ":variant" to Package field34 35	lineBuf bytes.Buffer // Buffer for incomplete lines36}37 38func (f *testJSONFilter) Write(b []byte) (int, error) {39	bn := len(b)40 41	// Process complete lines, and buffer any incomplete lines.42	for len(b) > 0 {43		nl := bytes.IndexByte(b, '\n')44		if nl < 0 {45			f.lineBuf.Write(b)46			break47		}48		var line []byte49		if f.lineBuf.Len() > 0 {50			// We have buffered data. Add the rest of the line from b and51			// process the complete line.52			f.lineBuf.Write(b[:nl+1])53			line = f.lineBuf.Bytes()54		} else {55			// Process a complete line from b.56			line = b[:nl+1]57		}58		b = b[nl+1:]59		f.process(line)60		f.lineBuf.Reset()61	}62 63	return bn, nil64}65 66func (f *testJSONFilter) Flush() {67	// Write any remaining partial line to the underlying writer.68	if f.lineBuf.Len() > 0 {69		f.w.Write(f.lineBuf.Bytes())70		f.lineBuf.Reset()71	}72}73 74func (f *testJSONFilter) process(line []byte) {75	if len(line) > 0 && line[0] == '{' {76		// Plausible test2json output. Parse it generically.77		//78		// We go to some effort here to preserve key order while doing this79		// generically. This will stay robust to changes in the test2json80		// struct, or other additions outside of it. If humans are ever looking81		// at the output, it's really nice to keep field order because it82		// preserves a lot of regularity in the output.83		dec := json.NewDecoder(bytes.NewBuffer(line))84		dec.UseNumber()85		val, err := decodeJSONValue(dec)86		if err == nil && val.atom == json.Delim('{') {87			// Rewrite the Package field.88			found := false89			for i := 0; i < len(val.seq); i += 2 {90				if val.seq[i].atom == "Package" {91					if pkg, ok := val.seq[i+1].atom.(string); ok {92						val.seq[i+1].atom = pkg + ":" + f.variant93						found = true94						break95					}96				}97			}98			if found {99				data, err := json.Marshal(val)100				if err != nil {101					// Should never happen.102					panic(fmt.Sprintf("failed to round-trip JSON %q: %s", line, err))103				}104				f.w.Write(data)105				// Copy any trailing text. We expect at most a "\n" here, but106				// there could be other text and we want to feed that through.107				io.Copy(f.w, dec.Buffered())108				return109			}110		}111	}112 113	// Something went wrong. Just pass the line through.114	f.w.Write(line)115}116 117type jsonValue struct {118	atom json.Token  // If json.Delim, then seq will be filled119	seq  []jsonValue // If atom == json.Delim('{'), alternating pairs120}121 122var jsonPop = errors.New("end of JSON sequence")123 124func decodeJSONValue(dec *json.Decoder) (jsonValue, error) {125	t, err := dec.Token()126	if err != nil {127		if err == io.EOF {128			err = io.ErrUnexpectedEOF129		}130		return jsonValue{}, err131	}132 133	switch t := t.(type) {134	case json.Delim:135		if t == '}' || t == ']' {136			return jsonValue{}, jsonPop137		}138 139		var seq []jsonValue140		for {141			val, err := decodeJSONValue(dec)142			if err == jsonPop {143				break144			} else if err != nil {145				return jsonValue{}, err146			}147			seq = append(seq, val)148		}149		return jsonValue{t, seq}, nil150	default:151		return jsonValue{t, nil}, nil152	}153}154 155func (v jsonValue) MarshalJSON() ([]byte, error) {156	var buf bytes.Buffer157	var marshal1 func(v jsonValue) error158	marshal1 = func(v jsonValue) error {159		if t, ok := v.atom.(json.Delim); ok {160			buf.WriteRune(rune(t))161			for i, v2 := range v.seq {162				if t == '{' && i%2 == 1 {163					buf.WriteByte(':')164				} else if i > 0 {165					buf.WriteByte(',')166				}167				if err := marshal1(v2); err != nil {168					return err169				}170			}171			if t == '{' {172				buf.WriteByte('}')173			} else {174				buf.WriteByte(']')175			}176			return nil177		}178		bytes, err := json.Marshal(v.atom)179		if err != nil {180			return err181		}182		buf.Write(bytes)183		return nil184	}185	err := marshal1(v)186	return buf.Bytes(), err187}188 189func synthesizeSkipEvent(enc *json.Encoder, pkg, msg string) {190	type event struct {191		Time    time.Time192		Action  string193		Package string194		Output  string `json:",omitempty"`195	}196	ev := event{Time: time.Now(), Package: pkg, Action: "start"}197	enc.Encode(ev)198	ev.Action = "output"199	ev.Output = msg200	enc.Encode(ev)201	ev.Action = "skip"202	ev.Output = ""203	enc.Encode(ev)204}205 
codekingpro/portable-devtools · Team Ai