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

macOS #51

Merged
merged 1 commit into from
Apr 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions codeserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ package main
import (
"context"
"io"
"net"
"net/http"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"time"

"go.coder.com/flog"
Expand Down Expand Up @@ -85,13 +89,36 @@ func codeServerPort(cntName string) (string, error) {
)

for ctx.Err() == nil {
port, err = codeserver.Port(cntName)
if err == nil {
return port, nil
if runtime.GOOS == "darwin" {
// macOS uses port forwarding instead of host networking so netstat stuff below will not work
// as it will find the port inside the container, which we already know is 8443.
cmd := exec.CommandContext(ctx, "docker", "port", cntName, "8443")
var out []byte
out, err = cmd.CombinedOutput()
if err != nil {
continue
}

addr := strings.TrimSpace(string(out))
_, port, err = net.SplitHostPort(addr)
if err != nil {
return "", xerrors.Errorf("invalid address from docker port: %q", string(out))
}
} else {
port, err = codeserver.Port(cntName)
if xerrors.Is(err, codeserver.PortNotFoundError) {
continue
}
if err != nil {
return "", err
}
}

if !xerrors.Is(err, codeserver.PortNotFoundError) {
return "", err
var resp *http.Response
resp, err = http.Get("http://localhost:" + port)
if err == nil {
resp.Body.Close()
return port, nil
}

time.Sleep(time.Millisecond * 100)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/Microsoft/go-winio v0.4.12 // indirect
github.com/docker/distribution v2.7.1+incompatible // indirect
github.com/docker/docker v0.7.3-0.20190416080540-ad9362bb1567
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-connections v0.4.0
github.com/docker/go-units v0.3.3 // indirect
github.com/fatih/color v1.7.0
github.com/gogo/protobuf v1.2.1 // indirect
Expand Down
3 changes: 1 addition & 2 deletions project.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package main
import (
"context"
"fmt"
"net"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -244,7 +243,7 @@ func (p *project) open() error {
return err
}

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

flog.Info("opening %v", u)
return browserapp.Open(u)
Expand Down
39 changes: 33 additions & 6 deletions runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package main
import (
"context"
"fmt"
"github.com/docker/go-connections/nat"
"os"
"path/filepath"
"runtime"
"strings"
"time"

Expand Down Expand Up @@ -67,15 +69,24 @@ func (r *runner) runContainer(image string) error {
return err
}

containerAddr := "localhost"
containerPort := r.port
if runtime.GOOS == "darwin" {
// See justification below.
containerPort = "8443"
containerAddr = "0.0.0.0"
}

// We want the code-server logs to be available inside the container for easy
// access during development, but also going to stdout so `docker logs` can be used
// to debug a failed code-server startup.
cmd := "cd " + projectDir +
"; code-server --host 127.0.0.1" +
" --port " + r.port +
" --data-dir ~/.config/Code --extensions-dir ~/.vscode/extensions --allow-http --no-auth 2>&1 | tee " + containerLogPath
cmd := fmt.Sprintf(`set -euxo pipefail || exit 1
cd %v
code-server --host %v --port %v \
--data-dir ~/.config/Code --extensions-dir ~/.vscode/extensions --allow-http --no-auth 2>&1 | tee %v
`, projectDir, containerAddr, containerPort, containerLogPath)
if r.testCmd != "" {
cmd = r.testCmd + "; exit 1"
cmd = r.testCmd + "\n exit 1"
}

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

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

// macOS does not support host networking.
// See https://github.com/docker/for-mac/issues/2716
if runtime.GOOS == "darwin" {
portSpec := fmt.Sprintf("127.0.0.1:%v:%v/tcp", r.port, "8443")
hostConfig.NetworkMode = ""
exposed, bindings, err := nat.ParsePortSpecs([]string{portSpec})
if err != nil {
return xerrors.Errorf("failed to parse port spec: %w", err)
}
containerConfig.ExposedPorts = exposed
hostConfig.PortBindings = bindings
}

_, err = cli.ContainerCreate(ctx, containerConfig, hostConfig, nil, r.cntName)
if err != nil {
return xerrors.Errorf("failed to create container: %w", err)
Expand Down