-
Notifications
You must be signed in to change notification settings - Fork 0
/
gofs.go
83 lines (67 loc) · 1.76 KB
/
gofs.go
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
72
73
74
75
76
77
78
79
80
81
82
83
package gofs
import (
"bytes"
"encoding/json"
"fmt"
"io"
fslib "io/fs"
"os"
"os/exec"
"path"
)
type gofs struct {
pkgdir, workdir string
}
type FS interface {
fslib.FS
WorkDir() string
Done() error
}
func New(pkg string) (FS, error) {
wrkdir, err := os.MkdirTemp("", "*")
if err != nil {
return nil, fmt.Errorf("failed to initialize working directory: %w", err)
}
newCmd := func(name string, args ...string) *exec.Cmd {
cmd := exec.Command(name, args...)
cmd.Dir = wrkdir
// cmd.Stderr = os.Stderr
return cmd
}
if err = newCmd("go", "mod", "init", "temp").Run(); err != nil {
return nil, fmt.Errorf("failed to init go module in working directory: %w", err)
}
if err = newCmd("go", "get", pkg).Run(); err != nil {
return nil, fmt.Errorf("failed to go get '%s': %w", pkg, err)
}
golist := newCmd("go", "list", "-json", pkg)
stdOut, stdErr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)
golist.Stdout, golist.Stderr = stdOut, stdErr
if err = golist.Run(); err != nil {
return nil, fmt.Errorf("failed to go list '%s': %w", pkg, err)
}
errBytes, err := io.ReadAll(stdErr)
if err != nil {
return nil, fmt.Errorf("failed to read 'go list' error: %w", err)
}
if len(errBytes) > 0 {
return nil, fmt.Errorf("'go list' failed to run successfully: %s", string(errBytes))
}
golistResp := new(struct{ Dir string })
if err := json.NewDecoder(stdOut).Decode(golistResp); err != nil {
return nil, fmt.Errorf("failed to read 'go list' output: %w", err)
}
return &gofs{
workdir: wrkdir,
pkgdir: golistResp.Dir,
}, nil
}
func (fs *gofs) Open(fname string) (fslib.File, error) {
return os.Open(path.Join(fs.pkgdir, fname))
}
func (fs *gofs) WorkDir() string {
return fs.workdir
}
func (fs *gofs) Done() error {
return os.RemoveAll(fs.workdir)
}