Skip to content

Commit e7eb741

Browse files
authored
feat: nix dependencies! (#70)
* feat: nix dependencies! * chore: renovate groups * fix: tests * chore: new docker files
1 parent 599588c commit e7eb741

19 files changed

Lines changed: 344 additions & 63 deletions

.github/workflows/build.yml

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,30 +43,95 @@ jobs:
4343
bin/druid_rcon_web_rust
4444
.docker/entrypoint.sh
4545
.docker/druid-install-command.sh
46-
docker:
46+
docker-base:
4747
runs-on: ubuntu-latest
4848
needs: build
49+
strategy:
50+
matrix:
51+
include:
52+
- dockerfile: Dockerfile
53+
tag_suffix: ""
54+
- dockerfile: Dockerfile.steamcmd
55+
tag_suffix: "-steamcmd"
4956
steps:
5057
- uses: actions/checkout@v4
5158
with:
5259
fetch-depth: 0
60+
- name: Set up Docker Buildx
61+
uses: docker/setup-buildx-action@v3
5362
- name: Login to Docker Hub
5463
uses: docker/login-action@v3
5564
with:
5665
username: ${{ vars.DOCKERHUB_USERNAME }}
5766
password: ${{ secrets.DOCKERHUB_TOKEN }}
67+
- name: Login to Artifacts Registry
68+
uses: docker/login-action@v3
69+
with:
70+
registry: artifacts.druid.gg
71+
username: ${{ vars.DRUID_ARTIFACTS_REGISTRY_USERNAME }}
72+
password: ${{ secrets.DRUID_ARTIFACTS_REGISTRY_TOKEN }}
5873
#stable is still pretty bleeding edge at this point
5974
- name: Build and push Docker image
60-
uses: docker/build-push-action@v4
75+
uses: docker/build-push-action@v6
6176
with:
62-
file: Dockerfile
77+
context: .
78+
file: ${{ matrix.dockerfile }}
6379
tags: |
64-
highcard/druidd-base:latest
65-
highcard/druidd-base:stable
66-
highcard/druidd-base:${{ needs.build.outputs.version }}
67-
highcard/druidd-base:${{ needs.build.outputs.version_tag }}
80+
highcard/druid:latest${{ matrix.tag_suffix }}
81+
highcard/druid:stable${{ matrix.tag_suffix }}
82+
highcard/druid:${{ needs.build.outputs.version }}${{ matrix.tag_suffix }}
83+
highcard/druid:${{ needs.build.outputs.version_tag }}${{ matrix.tag_suffix }}
84+
artifacts.druid.gg/druid-team/druid:latest${{ matrix.tag_suffix }}
85+
artifacts.druid.gg/druid-team/druid:stable${{ matrix.tag_suffix }}
86+
artifacts.druid.gg/druid-team/druid:${{ needs.build.outputs.version }}${{ matrix.tag_suffix }}
87+
artifacts.druid.gg/druid-team/druid:${{ needs.build.outputs.version_tag }}${{ matrix.tag_suffix }}
6888
push: true
6989
build-args: |
7090
VERSION=${{ needs.build.outputs.version }}
7191
GIT_COMMIT=${{ github.sha }}
7292
GIT_BRANCH=${{ github.ref_name }}
93+
94+
docker-nix:
95+
runs-on: ubuntu-latest
96+
needs: [build, docker-base]
97+
strategy:
98+
matrix:
99+
include:
100+
- base_tag_suffix: ""
101+
tag_suffix: "-nix"
102+
- base_tag_suffix: "-steamcmd"
103+
tag_suffix: "-nix-steamcmd"
104+
steps:
105+
- uses: actions/checkout@v4
106+
with:
107+
fetch-depth: 0
108+
- name: Set up Docker Buildx
109+
uses: docker/setup-buildx-action@v3
110+
- name: Login to Docker Hub
111+
uses: docker/login-action@v3
112+
with:
113+
username: ${{ vars.DOCKERHUB_USERNAME }}
114+
password: ${{ secrets.DOCKERHUB_TOKEN }}
115+
- name: Login to Artifacts Registry
116+
uses: docker/login-action@v3
117+
with:
118+
registry: artifacts.druid.gg
119+
username: ${{ vars.DRUID_ARTIFACTS_REGISTRY_USERNAME }}
120+
password: ${{ secrets.DRUID_ARTIFACTS_REGISTRY_TOKEN }}
121+
- name: Build and push Nix Docker image
122+
uses: docker/build-push-action@v6
123+
with:
124+
context: .
125+
file: Dockerfile.nix
126+
tags: |
127+
highcard/druid:latest${{ matrix.tag_suffix }}
128+
highcard/druid:stable${{ matrix.tag_suffix }}
129+
highcard/druid:${{ needs.build.outputs.version }}${{ matrix.tag_suffix }}
130+
highcard/druid:${{ needs.build.outputs.version_tag }}${{ matrix.tag_suffix }}
131+
artifacts.druid.gg/druid-team/druid:latest${{ matrix.tag_suffix }}
132+
artifacts.druid.gg/druid-team/druid:stable${{ matrix.tag_suffix }}
133+
artifacts.druid.gg/druid-team/druid:${{ needs.build.outputs.version }}${{ matrix.tag_suffix }}
134+
artifacts.druid.gg/druid-team/druid:${{ needs.build.outputs.version_tag }}${{ matrix.tag_suffix }}
135+
push: true
136+
build-args: |
137+
VERSION=${{ needs.build.outputs.version }}${{ matrix.base_tag_suffix }}

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ RUN make build-plugins
1515
# The binaries are in ./bin/ directory after build
1616

1717
# Second stage: minimal runtime image
18-
FROM debian:bullseye-slim
18+
FROM ubuntu:24.04
1919

2020
RUN apt-get update && apt-get install -y \
2121
ca-certificates \

Dockerfile.nix

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
ARG VERSION=latest
2+
FROM highcard/druid:${VERSION}
3+
USER root
4+
5+
RUN apt-get update && apt-get install -y \
6+
curl xz-utils \
7+
&& rm -rf /var/lib/apt/lists/*
8+
RUN mkdir -m 0755 /nix && chown druid /nix
9+
USER druid
10+
11+
# install Nix package manager
12+
RUN bash -c "sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --no-daemon"
13+
# Make nix available in PATH for all RUN commands
14+
ENV PATH=/home/druid/.nix-profile/bin:/home/druid/.nix-profile/sbin:$PATH

Dockerfile.steamcmd

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
ARG VERSION=latest
2+
FROM highcard/druid:${VERSION} AS base
3+
FROM gameservermanagers/steamcmd:ubuntu-24.04
4+
5+
COPY --from=base /usr/bin/druid* /usr/bin/
6+
COPY --from=base /entrypoint.sh /entrypoint.sh
7+
8+
# Set up user with the same UID/GID
9+
ARG UID=1000
10+
ARG GID=1000
11+
RUN groupadd -g $GID -o druid
12+
RUN useradd -m -u $UID -g $GID -o -s /bin/bash druid
13+
14+
USER druid
15+
16+
ENTRYPOINT [ "/entrypoint.sh" ]

cmd/run.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ var RunCmd = &cobra.Command{
4040
if err != nil {
4141
return fmt.Errorf("error creating scroll service: %w", err)
4242
}
43-
processLauncher := services.NewProcedureLauncher(client, processManager, services.NewPluginManager(), consoleService, logManager, scrollService)
43+
processLauncher, err := services.NewProcedureLauncher(client, processManager, services.NewPluginManager(), consoleService, logManager, scrollService, dependencyResolution)
44+
if err != nil {
45+
return err
46+
}
4447

4548
queueManager := services.NewQueueManager(scrollService, processLauncher)
4649
snapshotService := snapshotService.NewSnapshotService()
@@ -65,4 +68,5 @@ var RunCmd = &cobra.Command{
6568

6669
func init() {
6770
RunCmd.Flags().BoolVarP(&ignoreVersionCheck, "ignore-version-check", "", false, "Ignore version check")
71+
RunCmd.Flags().StringVarP(&dependencyResolution, "dependency-resolution", "", "auto", "Dependency resolution strategy. Valid values: auto, nix, external")
6872
}

cmd/serve.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ var initSnapshotUrl string
3838
var skipArtifactDownload bool
3939
var allowPluginErrors bool
4040
var pprofBind string
41+
var dependencyResolution string
4142

4243
var ServeCommand = &cobra.Command{
4344
Use: "serve",
@@ -118,7 +119,10 @@ to interact and monitor the Scroll Application`,
118119

119120
logger.Log().Info("Scroll loaded", zap.String("Name", currentScroll.Name), zap.Any("Version", currentScroll.Version), zap.String("AppVersion", currentScroll.AppVersion), zap.Any("Ports", currentScroll.Ports))
120121

121-
processLauncher := services.NewProcedureLauncher(client, processManager, pluginManager, consoleService, logManager, scrollService)
122+
processLauncher, err := services.NewProcedureLauncher(client, processManager, pluginManager, consoleService, logManager, scrollService, dependencyResolution)
123+
if err != nil {
124+
return err
125+
}
122126

123127
queueManager := services.NewQueueManager(scrollService, processLauncher)
124128

@@ -303,6 +307,9 @@ func init() {
303307
ServeCommand.Flags().BoolVarP(&skipArtifactDownload, "skip-artifact-download", "", false, "Skip downloading the artifact on startup")
304308

305309
ServeCommand.Flags().BoolVarP(&allowPluginErrors, "allow-plugin-errors", "", false, "Ignore plugin errors on startup")
310+
311+
ServeCommand.Flags().StringVarP(&dependencyResolution, "dependency-resolution", "", "auto", "Dependency resolution strategy. Valid values: auto, nix, external")
312+
306313
}
307314

308315
func startup(scrollService *services.ScrollService, snapshotService ports.SnapshotService, processLauncher *services.ProcedureLauncher, queueManager *services.QueueManager, portSerivce *services.PortMonitor, coldStarter *services.ColdStarter, healthHandler *handler.HealthHandler, cwd string, doneChan chan error) {

examples/minecraft/.scroll/scroll.yaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,14 @@ commands:
3333
start:
3434
needs: [install]
3535
run: restart
36+
dependencies: [jdk17]
3637
procedures:
3738
- mode: exec
39+
data:
40+
- java
41+
- -version
42+
- mode: exec
43+
id: start-process
3844
data:
3945
- java
4046
- -Xmx1024M
@@ -46,7 +52,7 @@ commands:
4652
procedures:
4753
- mode: stdin
4854
data:
49-
- start.0
55+
- start-process
5056
- stop
5157
install:
5258
run: once

internal/core/domain/scroll.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,10 @@ type Procedure struct {
7878
} // @name Procedure
7979

8080
type CommandInstructionSet struct {
81-
Procedures []*Procedure `yaml:"procedures" json:"procedures"`
82-
Needs []string `yaml:"needs,omitempty" json:"needs,omitempty"`
83-
Run RunMode `yaml:"run,omitempty" json:"run,omitempty"`
81+
Dependencies []string `yaml:"dependencies,omitempty" json:"dependencies,omitempty"`
82+
Procedures []*Procedure `yaml:"procedures" json:"procedures"`
83+
Needs []string `yaml:"needs,omitempty" json:"needs,omitempty"`
84+
Run RunMode `yaml:"run,omitempty" json:"run,omitempty"`
8485
} // @name CommandInstructionSet
8586

8687
var ErrScrollDoesNotExist = fmt.Errorf("scroll does not exist")

internal/core/ports/services_ports.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ type ScrollServiceInterface interface {
4141

4242
type ProcedureLauchnerInterface interface {
4343
LaunchPlugins() error
44-
RunProcedure(*domain.Procedure, string) (string, *int, error)
44+
RunProcedure(*domain.Procedure, string, []string) (string, *int, error)
4545
Run(cmd string, runCommandCb func(cmd string) error) error
4646
GetProcedureStatuses() map[string]domain.ScrollLockStatus
4747
}
@@ -184,3 +184,8 @@ type UiDevServiceInterface interface {
184184
IsWatching() bool
185185
SetCommands(procs map[string]*domain.CommandInstructionSet)
186186
}
187+
188+
type NixDependencyServiceInterface interface {
189+
GetCommand(cmd []string, deps []string) []string
190+
EnsureNixInstalled() error
191+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package services
2+
3+
import (
4+
"fmt"
5+
"os/exec"
6+
"strings"
7+
8+
"github.com/highcard-dev/daemon/internal/core/ports"
9+
)
10+
11+
type NixDependencyService struct{}
12+
13+
func NewNixDependencyService() *NixDependencyService { return &NixDependencyService{} }
14+
15+
func (s *NixDependencyService) EnsureNixInstalled() error {
16+
if _, err := exec.LookPath("nix-shell"); err != nil {
17+
return fmt.Errorf("nix-shell not found in PATH; install Nix from https://nixos.org/download and ensure 'nix-shell' is available: %w", err)
18+
}
19+
return nil
20+
}
21+
22+
func (s *NixDependencyService) GetCommand(cmd []string, deps []string) []string {
23+
var cmds = []string{"nix-shell", "--pure"}
24+
for _, dep := range deps {
25+
cmds = append(cmds, "-p", dep)
26+
}
27+
28+
cmds = append(cmds, "--command", strings.Join(cmd, " "))
29+
30+
return cmds
31+
32+
}
33+
34+
var _ ports.NixDependencyServiceInterface = (*NixDependencyService)(nil)

0 commit comments

Comments
 (0)