Skip to content
This repository was archived by the owner on Apr 28, 2020. It is now read-only.

Commit f87fa20

Browse files
committed
Add macOS support
Updates #52 Still no good support for multi user linux systems.
1 parent bc0801f commit f87fa20

File tree

4 files changed

+67
-14
lines changed

4 files changed

+67
-14
lines changed

codeserver.go

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ package main
33
import (
44
"context"
55
"io"
6+
"net"
67
"net/http"
78
"os"
9+
"os/exec"
810
"path/filepath"
11+
"runtime"
12+
"strings"
913
"time"
1014

1115
"go.coder.com/flog"
@@ -85,13 +89,36 @@ func codeServerPort(cntName string) (string, error) {
8589
)
8690

8791
for ctx.Err() == nil {
88-
port, err = codeserver.Port(cntName)
89-
if err == nil {
90-
return port, nil
92+
if runtime.GOOS == "darwin" {
93+
// macOS uses port forwarding instead of host networking so netstat stuff below will not work
94+
// as it will find the port inside the container, which we already know is 8443.
95+
cmd := exec.CommandContext(ctx, "docker", "port", cntName, "8443")
96+
var out []byte
97+
out, err = cmd.CombinedOutput()
98+
if err != nil {
99+
continue
100+
}
101+
102+
addr := strings.TrimSpace(string(out))
103+
_, port, err = net.SplitHostPort(addr)
104+
if err != nil {
105+
return "", xerrors.Errorf("invalid address from docker port: %q", string(out))
106+
}
107+
} else {
108+
port, err = codeserver.Port(cntName)
109+
if xerrors.Is(err, codeserver.PortNotFoundError) {
110+
continue
111+
}
112+
if err != nil {
113+
return "", err
114+
}
91115
}
92116

93-
if !xerrors.Is(err, codeserver.PortNotFoundError) {
94-
return "", err
117+
var resp *http.Response
118+
resp, err = http.Get("http://localhost:" + port)
119+
if err == nil {
120+
resp.Body.Close()
121+
return port, nil
95122
}
96123

97124
time.Sleep(time.Millisecond * 100)

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ require (
88
github.com/Microsoft/go-winio v0.4.12 // indirect
99
github.com/docker/distribution v2.7.1+incompatible // indirect
1010
github.com/docker/docker v0.7.3-0.20190416080540-ad9362bb1567
11-
github.com/docker/go-connections v0.4.0 // indirect
11+
github.com/docker/go-connections v0.4.0
1212
github.com/docker/go-units v0.3.3 // indirect
1313
github.com/fatih/color v1.7.0
1414
github.com/gogo/protobuf v1.2.1 // indirect

project.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package main
33
import (
44
"context"
55
"fmt"
6-
"net"
76
"os"
87
"path/filepath"
98
"strings"
@@ -244,7 +243,7 @@ func (p *project) open() error {
244243
return err
245244
}
246245

247-
u := "http://" + net.JoinHostPort("127.0.0.1", port)
246+
u := "http://localhost:" + port
248247

249248
flog.Info("opening %v", u)
250249
return browserapp.Open(u)

runner.go

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ package main
33
import (
44
"context"
55
"fmt"
6+
"github.com/docker/go-connections/nat"
67
"os"
78
"path/filepath"
9+
"runtime"
810
"strings"
911
"time"
1012

@@ -67,15 +69,24 @@ func (r *runner) runContainer(image string) error {
6769
return err
6870
}
6971

72+
containerAddr := "localhost"
73+
containerPort := r.port
74+
if runtime.GOOS == "darwin" {
75+
// See justification below.
76+
containerPort = "8443"
77+
containerAddr = "0.0.0.0"
78+
}
79+
7080
// We want the code-server logs to be available inside the container for easy
7181
// access during development, but also going to stdout so `docker logs` can be used
7282
// to debug a failed code-server startup.
73-
cmd := "cd " + projectDir +
74-
"; code-server --host 127.0.0.1" +
75-
" --port " + r.port +
76-
" --data-dir ~/.config/Code --extensions-dir ~/.vscode/extensions --allow-http --no-auth 2>&1 | tee " + containerLogPath
83+
cmd := fmt.Sprintf(`set -euxo pipefail || exit 1
84+
cd %v
85+
code-server --host %v --port %v \
86+
--data-dir ~/.config/Code --extensions-dir ~/.vscode/extensions --allow-http --no-auth 2>&1 | tee %v
87+
`, projectDir, containerAddr, containerPort, containerLogPath)
7788
if r.testCmd != "" {
78-
cmd = r.testCmd + "; exit 1"
89+
cmd = r.testCmd + "\n exit 1"
7990
}
8091

8192
var envs []string
@@ -98,7 +109,10 @@ func (r *runner) runContainer(image string) error {
98109
projectLocalDirLabel: r.projectLocalDir,
99110
projectNameLabel: r.projectName,
100111
},
101-
User: r.hostUser + ":user",
112+
// The user inside has uid 1000. This works even on macOS where the default user has uid 501.
113+
// See https://stackoverflow.com/questions/43097341/docker-on-macosx-does-not-translate-file-ownership-correctly-in-volumes
114+
// The docker image runs it as uid 1000 so we don't need to set anything.
115+
User: "",
102116
}
103117

104118
err = r.addImageDefinedLabels(image, containerConfig.Labels)
@@ -123,6 +137,19 @@ func (r *runner) runContainer(image string) error {
123137
},
124138
}
125139

140+
// macOS does not support host networking.
141+
// See https://github.com/docker/for-mac/issues/2716
142+
if runtime.GOOS == "darwin" {
143+
portSpec := fmt.Sprintf("127.0.0.1:%v:%v/tcp", r.port, "8443")
144+
hostConfig.NetworkMode = ""
145+
exposed, bindings, err := nat.ParsePortSpecs([]string{portSpec})
146+
if err != nil {
147+
return xerrors.Errorf("failed to parse port spec: %w", err)
148+
}
149+
containerConfig.ExposedPorts = exposed
150+
hostConfig.PortBindings = bindings
151+
}
152+
126153
_, err = cli.ContainerCreate(ctx, containerConfig, hostConfig, nil, r.cntName)
127154
if err != nil {
128155
return xerrors.Errorf("failed to create container: %w", err)

0 commit comments

Comments
 (0)