diff --git a/livelog/copy.go b/livelog/copy.go index 70b92e5..6e787bc 100644 --- a/livelog/copy.go +++ b/livelog/copy.go @@ -6,29 +6,15 @@ package livelog import ( "bufio" - "encoding/base64" "io" - "io/ioutil" - "regexp" ) -var re = regexp.MustCompile("#((.*?)#)") - // Copy copies from src to dst and removes until either EOF // is reached on src or an error occurs. func Copy(dst io.Writer, src io.ReadCloser) error { r := bufio.NewReader(src) for { bytes, err := r.ReadBytes('\n') - // check logs for card data - card := re.FindStringSubmatch(string(bytes)) - if card != nil { - data, err := base64.StdEncoding.DecodeString(card[len(card)-1:][0]) - if err == nil { - _ = ioutil.WriteFile("/tmp/card.json", data, 0644) - } - continue - } if _, err := dst.Write(bytes); err != nil { return err } diff --git a/livelog/extractor/writer.go b/livelog/extractor/writer.go new file mode 100644 index 0000000..a7d2211 --- /dev/null +++ b/livelog/extractor/writer.go @@ -0,0 +1,40 @@ +package extractor + +import ( + "encoding/base64" + "io" + "regexp" +) + +var re = regexp.MustCompile("#((.*?)#)") + +type Writer struct { + base io.Writer + file []byte +} + +func New(w io.Writer) *Writer { + return &Writer{w, nil} +} + +func (e *Writer) Write(p []byte) (n int, err error) { + card := re.FindStringSubmatch(string(p)) + if card == nil { + return e.base.Write(p) + } + + data, err := base64.StdEncoding.DecodeString(card[len(card)-1:][0]) + if err == nil { + e.file = data + } + // remove encoded string for logs + return e.base.Write([]byte("")) +} + +func (e *Writer) File() ([]byte, bool) { + if len(e.file) > 0 { + return e.file, true + } else { + return nil, false + } +} diff --git a/pipeline/runtime/execer.go b/pipeline/runtime/execer.go index 4b3d28d..bcd5092 100644 --- a/pipeline/runtime/execer.go +++ b/pipeline/runtime/execer.go @@ -8,6 +8,8 @@ import ( "context" "sync" + "github.com/drone/runner-go/livelog/extractor" + "github.com/drone/drone-go/drone" "github.com/drone/runner-go/environ" "github.com/drone/runner-go/logger" @@ -235,17 +237,20 @@ func (e *Execer) exec(ctx context.Context, state *pipeline.State, spec Spec, ste wc := e.streamer.Stream(noContext, state, step.GetName()) wc = newReplacer(wc, secretSlice(step)) + // wrap writer in extrator + ext := extractor.New(wc) + // if the step is configured as a daemon, it is detached // from the main process and executed separately. if step.IsDetached() { go func() { - e.engine.Run(ctx, spec, copy, wc) + e.engine.Run(ctx, spec, copy, ext) wc.Close() }() return nil } - exited, err := e.engine.Run(ctx, spec, copy, wc) + exited, err := e.engine.Run(ctx, spec, copy, ext) // close the stream. If the session is a remote session, the // full log buffer is uploaded to the remote server. @@ -253,14 +258,15 @@ func (e *Execer) exec(ctx context.Context, state *pipeline.State, spec Spec, ste result = multierror.Append(result, err) } - // stream card data to server if exists - file, _ := e.engine.StreamFile(ctx, spec, copy, "/tmp/card.json") - if file != nil { - err = e.uploader.UploadCard(ctx, file, state, step.GetName()) + // upload card if exists + card, ok := ext.File() + if ok { + err = e.uploader.UploadCard(ctx, card, state, step.GetName()) if err != nil { return nil } } + // if the context was cancelled and returns a Canceled or // DeadlineExceeded error this indicates the pipeline was // cancelled. diff --git a/pipeline/runtime/type.go b/pipeline/runtime/type.go index 8ded0fa..38fa4de 100644 --- a/pipeline/runtime/type.go +++ b/pipeline/runtime/type.go @@ -84,9 +84,6 @@ type ( // Run runs the pipeline step. Run(context.Context, Spec, Step, io.Writer) (*State, error) - - // StreamFile copies a file to the server - StreamFile(context.Context, Spec, Step, string) (io.ReadCloser, error) } // Spec is an interface that must be implemented by all diff --git a/pipeline/uploader.go b/pipeline/uploader.go index d2a5df4..f80dc7c 100644 --- a/pipeline/uploader.go +++ b/pipeline/uploader.go @@ -2,11 +2,10 @@ package pipeline import ( "context" - "io" ) type Uploader interface { - UploadCard(context.Context, io.ReadCloser, *State, string) error + UploadCard(context.Context, []byte, *State, string) error } func NopUploader() Uploader { @@ -15,4 +14,4 @@ func NopUploader() Uploader { type nopUploader struct{} -func (*nopUploader) UploadCard(context.Context, io.ReadCloser, *State, string) error { return nil } +func (*nopUploader) UploadCard(context.Context, []byte, *State, string) error { return nil } diff --git a/pipeline/uploader/upload.go b/pipeline/uploader/upload.go index 3d1628e..55b69e4 100644 --- a/pipeline/uploader/upload.go +++ b/pipeline/uploader/upload.go @@ -3,7 +3,6 @@ package uploader import ( "context" "encoding/json" - "io" "github.com/drone/drone-go/drone" "github.com/drone/runner-go/client" @@ -23,14 +22,10 @@ func New(client client.Client) *Upload { } } -func (s *Upload) UploadCard(ctx context.Context, r io.ReadCloser, state *pipeline.State, stepName string) error { +func (s *Upload) UploadCard(ctx context.Context, bytes []byte, state *pipeline.State, stepName string) error { src := state.Find(stepName) - bytes, err := io.ReadAll(r) - if err != nil { - return err - } card := drone.CardInput{} - err = json.Unmarshal(bytes, &card) + err := json.Unmarshal(bytes, &card) if err != nil { return err }