impr: modular sandbox configs

This commit is contained in:
Anton
2023-12-05 00:53:50 +05:00
parent 07b523cd4d
commit cfe8970ebf
9 changed files with 113 additions and 62 deletions

View File

@@ -1,14 +0,0 @@
{
"sh": {
"run": {
"engine": "docker",
"entry": "main.sh",
"steps": [
{
"box": "alpine",
"command": ["sh", "main.sh"]
}
]
}
}
}

12
configs/commands/sh.json Normal file
View File

@@ -0,0 +1,12 @@
{
"run": {
"engine": "docker",
"entry": "main.sh",
"steps": [
{
"box": "alpine",
"command": ["sh", "main.sh"]
}
]
}
}

View File

@@ -4,12 +4,15 @@ import (
"encoding/json" "encoding/json"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"github.com/nalgeon/codapi/internal/fileio"
) )
const ( const (
configFilename = "config.json" configFilename = "config.json"
boxesFilename = "boxes.json" boxesFilename = "boxes.json"
commandsFilename = "commands.json" commandsDirname = "commands"
) )
// Read reads application config from JSON files. // Read reads application config from JSON files.
@@ -24,7 +27,7 @@ func Read(path string) (*Config, error) {
return nil, err return nil, err
} }
cfg, err = ReadCommands(cfg, filepath.Join(path, commandsFilename)) cfg, err = ReadCommands(cfg, filepath.Join(path, commandsDirname))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -71,31 +74,36 @@ func ReadBoxes(cfg *Config, path string) (*Config, error) {
// ReadCommands reads commands config from a JSON file. // ReadCommands reads commands config from a JSON file.
func ReadCommands(cfg *Config, path string) (*Config, error) { func ReadCommands(cfg *Config, path string) (*Config, error) {
data, err := os.ReadFile(path) fnames, err := filepath.Glob(filepath.Join(path, "*.json"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
commands := make(map[string]SandboxCommands) cfg.Commands = make(map[string]SandboxCommands, len(fnames))
err = json.Unmarshal(data, &commands) for _, fname := range fnames {
if err != nil { sandbox := strings.TrimSuffix(filepath.Base(fname), ".json")
return nil, err commands, err := fileio.ReadJson[SandboxCommands](fname)
} if err != nil {
break
for _, playCmds := range commands {
for _, cmd := range playCmds {
if cmd.Before != nil {
setStepDefaults(cmd.Before, cfg.Step)
}
for _, step := range cmd.Steps {
setStepDefaults(step, cfg.Step)
}
if cmd.After != nil {
setStepDefaults(cmd.After, cfg.Step)
}
} }
setCommandDefaults(commands, cfg)
cfg.Commands[sandbox] = commands
} }
cfg.Commands = commands
return cfg, err return cfg, err
} }
// setCommandDefaults applies global defaults to sandbox commands.
func setCommandDefaults(commands SandboxCommands, cfg *Config) {
for _, cmd := range commands {
if cmd.Before != nil {
setStepDefaults(cmd.Before, cfg.Step)
}
for _, step := range cmd.Steps {
setStepDefaults(step, cfg.Step)
}
if cmd.After != nil {
setStepDefaults(cmd.After, cfg.Step)
}
}
}

View File

@@ -1,25 +0,0 @@
{
"python": {
"run": {
"engine": "docker",
"entry": "main.py",
"steps": [
{
"box": "python",
"command": ["python", "main.py"]
}
]
},
"test": {
"engine": "docker",
"entry": "test_main.py",
"steps": [
{
"box": "python",
"command": ["python", "-m", "unittest"],
"noutput": 8192
}
]
}
}
}

View File

@@ -0,0 +1,23 @@
{
"run": {
"engine": "docker",
"entry": "main.py",
"steps": [
{
"box": "python",
"command": ["python", "main.py"]
}
]
},
"test": {
"engine": "docker",
"entry": "test_main.py",
"steps": [
{
"box": "python",
"command": ["python", "-m", "unittest"],
"noutput": 8192
}
]
}
}

View File

@@ -2,6 +2,7 @@
package fileio package fileio
import ( import (
"encoding/json"
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
@@ -37,3 +38,17 @@ func CopyFiles(pattern string, dstDir string) error {
return nil return nil
} }
// ReadJson reads the file and decodes it from JSON.
func ReadJson[T any](path string) (T, error) {
var obj T
data, err := os.ReadFile(path)
if err != nil {
return obj, err
}
err = json.Unmarshal(data, &obj)
if err != nil {
return obj, err
}
return obj, err
}

View File

@@ -3,6 +3,7 @@ package fileio
import ( import (
"os" "os"
"path/filepath" "path/filepath"
"reflect"
"testing" "testing"
) )
@@ -54,3 +55,30 @@ func TestCopyFiles(t *testing.T) {
t.Errorf("unexpected file content: got %q, want %q", data, expected) t.Errorf("unexpected file content: got %q, want %q", data, expected)
} }
} }
func TestReadJson(t *testing.T) {
type Person struct{ Name string }
t.Run("valid", func(t *testing.T) {
got, err := ReadJson[Person](filepath.Join("testdata", "valid.json"))
if err != nil {
t.Fatalf("unexpected error %v", err)
}
want := Person{"alice"}
if !reflect.DeepEqual(got, want) {
t.Errorf("expected %v, got %v", want, got)
}
})
t.Run("invalid", func(t *testing.T) {
_, err := ReadJson[Person](filepath.Join("testdata", "invalid.json"))
if err == nil {
t.Fatal("expected error, got nil")
}
})
t.Run("does not exist", func(t *testing.T) {
_, err := ReadJson[Person](filepath.Join("testdata", "missing.json"))
if err == nil {
t.Fatal("expected error, got nil")
}
})
}

1
internal/fileio/testdata/invalid.json vendored Normal file
View File

@@ -0,0 +1 @@
name: alice

3
internal/fileio/testdata/valid.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"name": "alice"
}