Skip to content
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
19 changes: 15 additions & 4 deletions cmd/devenv/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"time"

"github.com/nauticalab/devenv-engine/internal/config"
Expand Down Expand Up @@ -309,11 +310,21 @@ func printConfigSummary(cfg *config.DevEnvConfig) {
fmt.Printf(" Git: %s <%s>\n", cfg.Git.Name, cfg.Git.Email)
}

if cfg.Resources.CPU != nil || cfg.Resources.Memory != "" {
cpuStr := formatCPU(cfg.Resources.CPU)
fmt.Printf(" Resources: CPU=%s, Memory=%s, GPU=%d\n",
cpuStr, cfg.Resources.Memory, cfg.Resources.GPU)
cpuStr := cfg.CPU() // e.g., "4000m" or "0"
memStr := cfg.Memory() // e.g., "16Gi" or ""

hasCPU := cpuStr != "0"
hasMem := memStr != ""

if hasCPU || hasMem {
var parts []string
if hasCPU {
parts = append(parts, fmt.Sprintf("CPU=%s", cpuStr))
}
if hasMem {
parts = append(parts, fmt.Sprintf("Memory=%s", memStr))
}
fmt.Printf(" Resources: %s\n", strings.Join(parts, ", "))
}

if len(cfg.Volumes) > 0 {
Expand Down
8 changes: 4 additions & 4 deletions internal/config/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func ExampleLoadDeveloperConfig() {

// Output:
// Developer: testuser
// CPU: 4
// CPU: 4000m
// Memory: 16Gi
// User ID: 2000
// SSH Keys: 1 configured
Expand All @@ -45,7 +45,7 @@ func ExampleDevEnvConfig_CPU() {
Name: "alice",
BaseConfig: config.BaseConfig{
Resources: config.ResourceConfig{
CPU: "8", // String value
CPU: 8, // String value
},
},
}
Expand All @@ -70,8 +70,8 @@ func ExampleDevEnvConfig_CPU() {
fmt.Printf("Default CPU: %s\n", cfg3.CPU())

// Output:
// String CPU: 8
// Integer CPU: 4
// String CPU: 8000m
// Integer CPU: 4000m
// Default CPU: 0
}

Expand Down
56 changes: 56 additions & 0 deletions internal/config/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"os"
"path/filepath"
"strings"

"gopkg.in/yaml.v3"
)
Expand Down Expand Up @@ -216,3 +217,58 @@ func mergeVolumes(global, user []VolumeMount) []VolumeMount {

return result
}

// normalizeSSHKeys converts the flexible SSH key field to a string slice
// Handles both single string and string array formats from YAML
func normalizeSSHKeys(sshKeyField any) ([]string, error) {
if sshKeyField == nil {
return []string{}, nil
}

switch keys := sshKeyField.(type) {
case string:
s := strings.TrimSpace(keys)
// Single SSH key
if s == "" {
return []string{}, fmt.Errorf("SSH key cannot be empty string")
}
return []string{s}, nil

case []string:
// Direct string slice
if len(keys) == 0 {
return nil, fmt.Errorf("SSH key array cannot be empty")
}
out := make([]string, len(keys))
for i, k := range keys {
s := strings.TrimSpace(k)
if s == "" {
return nil, fmt.Errorf("SSH key at index %d cannot be empty", i)
}
out[i] = s
}
return out, nil

case []any: // alias of []interface{}
if len(keys) == 0 {
return nil, fmt.Errorf("SSH key array cannot be empty")
}
out := make([]string, len(keys))
// Array of SSH keys (from YAML)
for i, e := range keys {
s, ok := e.(string)
if !ok {
return nil, fmt.Errorf("SSH key at index %d is not a string", i)
}
s = strings.TrimSpace(s)
if s == "" {
return nil, fmt.Errorf("SSH key at index %d cannot be empty", i)
}
out[i] = s
}
return out, nil

default:
return nil, fmt.Errorf("SSH key field must be string or array of strings, got %T", sshKeyField)
}
}
Loading