Skip to content

Commit ce5d968

Browse files
committed
feat: enhance ScrollService with template rendering and configuration management
- Added functionality to ensure scroll-config.yml is generated from scroll-config.yml.scroll_template if it doesn't exist. - Introduced tests for rendering templates and preserving user edits in configuration files. - Updated launch configurations for debugging and serving Minecraft and registry push operations.
1 parent 8f6db7d commit ce5d968

5 files changed

Lines changed: 164 additions & 11 deletions

File tree

.vscode/launch.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,21 @@
1616
"-p", "9190"
1717
]
1818
},
19+
{
20+
"name": "Serve (minecraft)",
21+
"type": "go",
22+
"request": "launch",
23+
"mode": "debug",
24+
"console": "integratedTerminal",
25+
"program": "${workspaceFolder}/main.go",
26+
"args": [
27+
"serve",
28+
"--cwd", "${workspaceFolder}/examples/minecraft",
29+
"--additional-endpoints", "annotations",
30+
"--allow-plugin-errors",
31+
"-p", "9190"
32+
]
33+
},
1934
{
2035
"name": "Run (scroll-cwd)",
2136
"type": "go",
@@ -40,6 +55,16 @@
4055
"--cwd", "${workspaceFolder}/examples/scroll-cwd"
4156
]
4257
},
58+
{
59+
"name": "Registry Push (arg) ",
60+
"type": "go",
61+
"request": "launch",
62+
"mode": "debug",
63+
"program": "${workspaceFolder}/main.go",
64+
"args": [
65+
"registry", "push","examples/scroll-cwd"
66+
]
67+
},
4368
{
4469
"name": "Registry Pull (scroll-cwd-pull)",
4570
"type": "go",

internal/core/domain/scroll.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -210,12 +210,18 @@ func (sc *Scroll) GetColdStartPorts() []Port {
210210
return sc.Ports
211211
}
212212

213+
const ScrollConfigFile = "scroll-config.yml"
214+
const ScrollConfigTemplate = ScrollConfigFile + ".scroll_template"
215+
213216
var ScrollFiles = map[string]ArtifactType{
214-
"update": ArtifactTypeScrollFs,
215-
"scroll.yaml": ArtifactTypeScrollFs,
216-
"packet_handler": ArtifactTypeScrollFs,
217-
"public": ArtifactTypeScrollFs,
218-
"private": ArtifactTypeScrollFs,
219-
"data": ArtifactTypeScrollData,
220-
".meta": ArtifactTypeScrollMeta,
217+
"update": ArtifactTypeScrollFs,
218+
"scroll.yaml": ArtifactTypeScrollFs,
219+
"packet_handler": ArtifactTypeScrollFs,
220+
"public": ArtifactTypeScrollFs,
221+
"private": ArtifactTypeScrollFs,
222+
"scroll-config.yml.scroll_template": ArtifactTypeScrollFs,
223+
"data": ArtifactTypeScrollData,
224+
"scroll-lock.json": ArtifactTypeScrollData,
225+
"scroll-config.yml": ArtifactTypeScrollData,
226+
".meta": ArtifactTypeScrollMeta,
221227
}

internal/core/services/registry/oci.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ func (c *OciClient) PullSelective(dir string, artifact string, includeData bool,
133133
// ORAS appends +gzip to the media type for directories.
134134
baseType := strings.TrimSuffix(s.MediaType, "+gzip")
135135
if baseType == string(domain.ArtifactTypeScrollData) {
136-
logger.Log().Debug("Skipping data layer", zap.String("digest", s.Digest.String()))
136+
path := s.Annotations["org.opencontainers.image.path"]
137+
logger.Log().Debug("Skipping data layer", zap.String("digest", s.Digest.String()), zap.String("path", path))
137138
continue
138139
}
139140
filtered = append(filtered, s)

internal/core/services/scroll_service.go

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,35 @@ func (s ScrollService) ScrollExists() bool {
127127
return b && err == nil
128128
}
129129

130+
func isScrollConfigTemplate(path string) bool {
131+
return filepath.Base(path) == domain.ScrollConfigTemplate
132+
}
133+
134+
// ensureScrollConfigFromTemplate renders scroll-config.yml.scroll_template to
135+
// produce scroll-config.yml when the config file does not yet exist. This is a
136+
// one-shot bootstrap: once the file is present it is never overwritten, so
137+
// user edits and non-deterministic template output (e.g. randAlphaNum) are
138+
// preserved across restarts.
139+
func (s ScrollService) ensureScrollConfigFromTemplate() error {
140+
configPath := filepath.Join(s.scrollDir, domain.ScrollConfigFile)
141+
if exists, _ := utils.FileExists(configPath); exists {
142+
return nil
143+
}
144+
145+
templatePath := filepath.Join(s.scrollDir, domain.ScrollConfigTemplate)
146+
if ok, _ := utils.FileExists(templatePath); !ok {
147+
return nil
148+
}
149+
150+
config := TemplateData{}
151+
return s.templateRenderer.RenderScrollTemplateFiles("", []string{templatePath}, config, "")
152+
}
153+
130154
func (s ScrollService) RenderCwdTemplates() error {
155+
if err := s.ensureScrollConfigFromTemplate(); err != nil {
156+
return err
157+
}
158+
131159
cwd := s.scrollDir
132160

133161
libRegEx, err := regexp.Compile(`^.+\.(scroll_template)$`)
@@ -140,8 +168,10 @@ func (s ScrollService) RenderCwdTemplates() error {
140168
if !libRegEx.MatchString(path) {
141169
return nil
142170
}
171+
if isScrollConfigTemplate(path) {
172+
return nil
173+
}
143174
files = append(files, path)
144-
145175
return nil
146176
})
147177

@@ -152,7 +182,6 @@ func (s ScrollService) RenderCwdTemplates() error {
152182
config := TemplateData{Config: s.GetScrollConfig()}
153183

154184
return s.templateRenderer.RenderScrollTemplateFiles("", files, config, "")
155-
156185
}
157186

158187
func (s ScrollService) GetScrollConfig() interface{} {
@@ -172,7 +201,7 @@ func (s ScrollService) GetScrollConfig() interface{} {
172201
}
173202

174203
func (s ScrollService) GetScrollConfigRawYaml() []byte {
175-
path := s.scrollDir + "/.scroll_config.yml"
204+
path := filepath.Join(s.scrollDir, domain.ScrollConfigFile)
176205

177206
content, err := os.ReadFile(path)
178207

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package services_test
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"testing"
7+
8+
"github.com/highcard-dev/daemon/internal/core/services"
9+
)
10+
11+
const minimalScrollYaml = `name: test-scroll
12+
version: 0.0.1
13+
commands: {}
14+
`
15+
16+
func writeFile(t *testing.T, path, content string) {
17+
t.Helper()
18+
if err := os.WriteFile(path, []byte(content), 0644); err != nil {
19+
t.Fatalf("failed to write %s: %v", path, err)
20+
}
21+
}
22+
23+
func TestRenderCwdTemplates_BootstrapsScrollConfig(t *testing.T) {
24+
dir := t.TempDir()
25+
writeFile(t, filepath.Join(dir, "scroll.yaml"), minimalScrollYaml)
26+
writeFile(t, filepath.Join(dir, "scroll-config.yml.scroll_template"), "key: generated-value\n")
27+
28+
svc, err := services.NewScrollService(dir)
29+
if err != nil {
30+
t.Fatalf("NewScrollService: %v", err)
31+
}
32+
33+
if err := svc.RenderCwdTemplates(); err != nil {
34+
t.Fatalf("RenderCwdTemplates: %v", err)
35+
}
36+
37+
content, err := os.ReadFile(filepath.Join(dir, "scroll-config.yml"))
38+
if err != nil {
39+
t.Fatalf("scroll-config.yml should exist after bootstrap: %v", err)
40+
}
41+
if string(content) != "key: generated-value\n" {
42+
t.Errorf("unexpected config content: %q", string(content))
43+
}
44+
}
45+
46+
func TestRenderCwdTemplates_DoesNotOverwriteExistingConfig(t *testing.T) {
47+
dir := t.TempDir()
48+
writeFile(t, filepath.Join(dir, "scroll.yaml"), minimalScrollYaml)
49+
writeFile(t, filepath.Join(dir, "scroll-config.yml"), "key: user-edited\n")
50+
writeFile(t, filepath.Join(dir, "scroll-config.yml.scroll_template"), "key: {{ randAlphaNum 50 }}\n")
51+
52+
svc, err := services.NewScrollService(dir)
53+
if err != nil {
54+
t.Fatalf("NewScrollService: %v", err)
55+
}
56+
57+
if err := svc.RenderCwdTemplates(); err != nil {
58+
t.Fatalf("RenderCwdTemplates: %v", err)
59+
}
60+
61+
content, err := os.ReadFile(filepath.Join(dir, "scroll-config.yml"))
62+
if err != nil {
63+
t.Fatalf("reading config: %v", err)
64+
}
65+
if string(content) != "key: user-edited\n" {
66+
t.Errorf("existing config was overwritten: %q", string(content))
67+
}
68+
}
69+
70+
func TestRenderCwdTemplates_OtherTemplatesReceiveBootstrappedConfig(t *testing.T) {
71+
dir := t.TempDir()
72+
writeFile(t, filepath.Join(dir, "scroll.yaml"), minimalScrollYaml)
73+
writeFile(t, filepath.Join(dir, "scroll-config.yml.scroll_template"), "greeting: hello\n")
74+
writeFile(t, filepath.Join(dir, "app.conf.scroll_template"), "value: {{ .Config.greeting }}\n")
75+
76+
svc, err := services.NewScrollService(dir)
77+
if err != nil {
78+
t.Fatalf("NewScrollService: %v", err)
79+
}
80+
81+
if err := svc.RenderCwdTemplates(); err != nil {
82+
t.Fatalf("RenderCwdTemplates: %v", err)
83+
}
84+
85+
content, err := os.ReadFile(filepath.Join(dir, "app.conf"))
86+
if err != nil {
87+
t.Fatalf("app.conf should exist: %v", err)
88+
}
89+
if string(content) != "value: hello\n" {
90+
t.Errorf("other template did not see bootstrapped config: %q", string(content))
91+
}
92+
}

0 commit comments

Comments
 (0)