1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
|
package debuginfod
import (
"bufio"
"bytes"
"context"
"os"
"os/exec"
"strings"
"time"
)
const debuginfodFind = "debuginfod-find"
const notificationThrottle time.Duration = 1 * time.Second
func execFind(ctx context.Context, notify func(string), args ...string) (string, error) {
if _, err := exec.LookPath(debuginfodFind); err != nil {
return "", err
}
if ctx == nil {
ctx = context.Background()
}
cmd := exec.CommandContext(ctx, debuginfodFind, args...)
if notify != nil {
cmd.Env = append(os.Environ(), "DEBUGINFOD_PROGRESS=yes")
stderr, err := cmd.StderrPipe()
if err != nil {
return "", err
}
s := bufio.NewScanner(stderr)
s.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF && len(data) == 0 {
return 0, nil, nil
}
if i := bytes.IndexAny(data, "\n\r"); i >= 0 {
return i + 1, dropCR(data[0:i]), nil
}
if atEOF {
return len(data), dropCR(data), nil
}
return 0, nil, nil
})
go func() {
var tlast time.Time
for s.Scan() {
if time.Since(tlast) > notificationThrottle {
tlast = time.Now()
notify(string(s.Text()))
}
}
}()
}
out, err := cmd.Output() // ignore stderr
if err != nil {
return "", err
}
return strings.TrimSpace(string(out)), err
}
func dropCR(data []byte) []byte {
r, _ := bytes.CutSuffix(data, []byte{'\r'})
return r
}
func GetSource(buildid, filename string) (string, error) {
return execFind(context.Background(), nil, "source", buildid, filename)
}
func GetDebuginfo(ctx context.Context, notify func(string), buildid string) (string, error) {
return execFind(ctx, notify, "debuginfo", buildid)
}
|