@@ -196,6 +196,24 @@ USER wttr
# ---------------------------------------------------------------------------
+# full: games plus DOSBox for DOS doors (bbs.dosbox, type: dos). DOSBox
+# runs headless on SDL's dummy video driver, so no X server is needed, and
+# only while someone plays. The doors and the FOSSIL driver are the
+# operator's: put them under /app/doors (a volume).
+# ---------------------------------------------------------------------------
+FROM games AS full
+
+USER root
+RUN set -eux; \
+ apt-get update; \
+ apt-get install -y --no-install-recommends dosbox; \
+ rm -rf /var/lib/apt/lists/*; \
+ mkdir -p /app/doors; \
+ chown wttr:wttr /app/doors
+
+USER wttr
+
+# ---------------------------------------------------------------------------
# A plain `docker build` still produces the runtime image, without games.
# ---------------------------------------------------------------------------
FROM runtime AS default
@@ -34,13 +34,14 @@ // dosSettings is a resolved DOSBox setup.
type dosSettings struct {
program string
- xvfb string // xvfb-run, when there is no display to draw on
+ headless bool // no display: SDL's dummy video driver, no window at all
fossilDir string
fossilCmd string
}
-// resolveDOSBox finds DOSBox, and xvfb-run when there is no display. It
-// returns "" (DOS doors off) when either is missing.
+// resolveDOSBox finds DOSBox. It returns "" (DOS doors off) when it is
+// missing. Without a display DOSBox draws to SDL's dummy video driver, so
+// no X server (and no Xvfb) is needed.
func resolveDOSBox(c *DOSBoxConfig) string {
s := resolveDOSSettings(c)
if s == nil {
@@ -67,13 +68,7 @@ return nil
}
s := &dosSettings{program: path, fossilDir: c.FossilDir, fossilCmd: c.FossilCommand}
- if os.Getenv("DISPLAY") == "" {
- if s.xvfb = findProgram("xvfb-run", ""); s.xvfb == "" {
- log.Printf("bbs: DOS doors off: no display and no xvfb-run")
-
- return nil
- }
- }
+ s.headless = os.Getenv("DISPLAY") == ""
dosConfigs.Store(path, s)
return s
@@ -149,11 +144,11 @@ }
args := []string{"-conf", confPath, "-noconsole", "-exit"}
cmd := exec.Command(ds.program, args...)
- if ds.xvfb != "" {
- cmd = exec.Command(ds.xvfb, append([]string{"-a", ds.program}, args...)...)
- }
cmd.Dir = tmp
cmd.Env = append(door.Env(filepath.Join(tmp, "DOOR.SYS"), tmp), "SDL_AUDIODRIVER=dummy")
+ if ds.headless {
+ cmd.Env = append(cmd.Env, "SDL_VIDEODRIVER=dummy")
+ }
cmd.Stdout = io.Discard
cmd.Stderr = io.Discard
if err := cmd.Start(); err != nil {
@@ -28,9 +28,6 @@ func TestDOSDoorThroughDOSBox(t *testing.T) { if _, err := exec.LookPath("dosbox"); err != nil {
t.Skip("dosbox not installed")
}
- if _, err := exec.LookPath("xvfb-run"); err != nil {
- t.Skip("xvfb-run not installed")
- }
srv := testServer(t, &Config{
DOSBox: &DOSBoxConfig{},
Doors: []DoorConfig{{Name: "Echo", Type: DoorDOS, Dir: t.TempDir(), Exe: "ECHO DOS SAYS HELLO>COM1", Nodes: 1}},