-
Notifications
You must be signed in to change notification settings - Fork 2
/
devcontainer.go
101 lines (81 loc) · 2.05 KB
/
devcontainer.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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package devcontainer
import (
"bytes"
"encoding/json"
"errors"
"os"
"os/exec"
"path/filepath"
"strings"
)
func NewEnvironment(cliPath string) *Environment {
return &Environment{cliPath: cliPath}
}
type Environment struct {
cliPath string
containerID string
mounts []mountInfo
}
type mountInfo struct {
Type string
Source string
Destination string
}
func (environment *Environment) GetContainerID() (string, error) {
if environment.containerID != "" {
return environment.containerID, nil
}
content, err := os.ReadFile("/proc/1/cpuset")
if err != nil {
return "", err
}
// TODO: not in container...
environment.containerID = filepath.Base(string(bytes.TrimSpace(content)))
return environment.containerID, nil
}
func (environment *Environment) GetHostPath(path string) (string, error) {
if environment.mounts == nil {
containerID, err := environment.GetContainerID()
if err != nil {
return "", err
}
mounts, err := listMountInfos(environment.cliPath, containerID)
if err != nil {
return "", err
}
environment.mounts = mounts
}
for _, mount := range environment.mounts {
out, err := exec.Command("realpath", "-m", "--relative-base="+mount.Destination, path).Output()
if err != nil {
return "", err
}
path = strings.TrimSpace(string(out))
if !strings.HasPrefix(path, "/") {
return filepath.Join(mount.Source, path), nil
}
}
return "", errors.New("path is not in host filesystem: " + path)
}
func listMountInfos(cliPath string, containerID string) ([]mountInfo, error) {
cmd := exec.Command(cliPath, "container", "inspect", containerID)
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, err
}
stderr := bytes.NewBuffer(nil)
cmd.Stderr = stderr
if err := cmd.Start(); err != nil {
return nil, err
}
inspect := []struct {
Mounts []mountInfo
}{}
if err := json.NewDecoder(stdout).Decode(&inspect); err != nil {
return nil, err
}
if err := cmd.Wait(); err != nil {
return nil, errors.New(string(bytes.TrimSpace(stderr.Bytes())))
}
return inspect[0].Mounts, nil
}