-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathremoteuri.go
More file actions
127 lines (108 loc) · 3.61 KB
/
remoteuri.go
File metadata and controls
127 lines (108 loc) · 3.61 KB
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package devcontainers
import (
"encoding/hex"
"fmt"
"os"
"path/filepath"
"regexp"
"github.com/stuartleeks/devcontainer-cli/internal/pkg/git"
"github.com/stuartleeks/devcontainer-cli/internal/pkg/wsl"
)
// GetDevContainerURI gets the devcontainer URI for a folder to launch using the VS Code --folder-uri switch
// If subFolder is specified, it is appended to the workspaceMountPath
func GetDevContainerURI(folderPath string, subFolder string) (string, error) {
absPath, err := filepath.Abs(folderPath)
if err != nil {
return "", fmt.Errorf("error handling path %q: %s", folderPath, err)
}
launchPath := absPath
if wsl.IsWsl() {
var err error
launchPath, err = wsl.ConvertWslPathToWindowsPath(launchPath)
if err != nil {
return "", err
}
}
launchPathHex := convertToHexString(launchPath)
workspaceMountPath, err := GetWorkspaceMountPath(absPath)
if err != nil {
return "", err
}
if subFolder != "" {
workspaceMountPath = filepath.Join(workspaceMountPath, subFolder)
}
uri := fmt.Sprintf("vscode-remote://dev-container+%s%s", launchPathHex, workspaceMountPath)
return uri, nil
}
func convertToHexString(input string) string {
return hex.EncodeToString([]byte(input))
}
// GetWorkspaceMountPath returns the devcontainer mount path for the devcontainer in the specified folder
func GetWorkspaceMountPath(folderPath string) (string, error) {
// TODO - consider how to support repository-containers (https://github.com/microsoft/vscode-remote-release/issues/3218)
// If we're called from WSL we want a WSL Path but will also handle a Windows Path
if wsl.IsWsl() {
if wsl.HasWslPathPrefix(folderPath) {
convertedPath, err := wsl.ConvertWindowsPathToWslPath(folderPath)
if err != nil {
return "", err
}
folderPath = convertedPath
}
}
devcontainerDefinitionPath, err := getDevContainerJsonPath(folderPath)
if err != nil {
return "", fmt.Errorf("error getting devcontainer definition path: %s", err)
}
buf, err := os.ReadFile(devcontainerDefinitionPath)
if err != nil {
return "", fmt.Errorf("error loading devcontainer definition: %s", err)
}
workspaceMountPath, err := getWorkspaceMountPathFromDevcontainerDefinition(buf)
if err != nil {
return "", fmt.Errorf("error parsing devcontainer definition: %s", err)
}
if workspaceMountPath != "" {
return workspaceMountPath, nil
}
// No `workspaceFolder` found in devcontainer.json - use default
devcontainerPath, err := getDefaultWorkspaceFolderForPath(folderPath)
if err != nil {
return "", fmt.Errorf("error getting default workspace path: %s", err)
}
return fmt.Sprintf("/workspaces/%s", devcontainerPath), nil
}
// TODO: add tests (and implementation) to handle JSON parsing with comments
// Current implementation doesn't handle
// - block comments
// - the value split on a new line from the property name
func getWorkspaceMountPathFromDevcontainerDefinition(definition []byte) (string, error) {
r, err := regexp.Compile("(?m)^\\s*\"workspaceFolder\"\\s*:\\s*\"(.*)\"")
if err != nil {
return "", fmt.Errorf("error compiling regex: %s", err)
}
matches := r.FindSubmatch(definition)
if len(matches) == 2 {
return string(matches[1]), nil
}
return "", nil
}
func getDefaultWorkspaceFolderForPath(path string) (string, error) {
// get the git repo-root
rootPath, err := git.GetTopLevelPath(path)
if err != nil {
return "", err
}
if rootPath == "" {
// not a git repo, default to path
rootPath = path
}
// get parent to root
rootParent, _ := filepath.Split(rootPath)
// return path relative to rootParent
relativePath, err := filepath.Rel(rootParent, path)
if err != nil {
return "", err
}
return relativePath, nil
}