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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,9 @@ pv uninstall # Complete removal with guided cleanup
│ ├── colima
│ ├── mago
│ └── composer.phar
├── pv.yml # Global settings (TLD, default PHP)
├── config/ # Server configuration
│ ├── Caddyfile
│ ├── settings.json
│ ├── sites/ # Per-project Caddyfile includes
│ └── sites-{ver}/ # Per-version site configs
├── data/ # Registry, PID file
Expand Down
8 changes: 4 additions & 4 deletions cmd/doctor.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ var doctorCmd = &cobra.Command{
}

versions, _ := phpenv.InstalledVersions()
globalPHP := settings.GlobalPHP
globalPHP := settings.Defaults.PHP

var allChecks []sectionResult

Expand Down Expand Up @@ -343,7 +343,7 @@ func runNetworkChecks(settings *config.Settings) sectionResult {
var checks []check

// DNS resolver file.
if err := setup.CheckResolverFile(settings.TLD); err == nil {
if err := setup.CheckResolverFile(settings.Defaults.TLD); err == nil {
checks = append(checks, check{Name: "DNS resolver configured", Status: true})
} else {
checks = append(checks, check{
Expand All @@ -356,7 +356,7 @@ func runNetworkChecks(settings *config.Settings) sectionResult {

// DNS responding (only if server appears to be running).
if server.IsRunning() || daemon.IsLoaded() {
if checkDNSResponding(settings.TLD) {
if checkDNSResponding(settings.Defaults.TLD) {
checks = append(checks, check{Name: "DNS responding", Status: true})
} else {
checks = append(checks, check{
Expand Down Expand Up @@ -500,7 +500,7 @@ func runProjectChecks(settings *config.Settings, reg *registry.Registry, globalP
phpV = "none"
}

domain := p.Name + "." + settings.TLD
domain := p.Name + "." + settings.Defaults.TLD

// Check project path exists.
if !dirExists(p.Path) {
Expand Down
2 changes: 1 addition & 1 deletion cmd/doctor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func TestDoctor_WithValidProject(t *testing.T) {

// Set global PHP and save settings.
settings := config.DefaultSettings()
settings.GlobalPHP = "8.4"
settings.Defaults.PHP = "8.4"
if err := settings.Save(); err != nil {
t.Fatal(err)
}
Expand Down
8 changes: 4 additions & 4 deletions cmd/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,11 @@ pv install --with="php:8.3,service[redis:7],service[mysql:8.0]"`,
if err := config.EnsureDirs(); err != nil {
return "", fmt.Errorf("cannot create directories: %w", err)
}
settings, _ := config.LoadSettings()
if settings == nil {
settings = &config.Settings{}
settings, err := config.LoadSettings()
if err != nil {
return "", fmt.Errorf("cannot load settings: %w", err)
}
settings.TLD = installTLD
settings.Defaults.TLD = installTLD
if err := settings.Save(); err != nil {
return "", fmt.Errorf("cannot save settings: %w", err)
}
Expand Down
8 changes: 4 additions & 4 deletions cmd/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ pv link --name=myapp ~/Code/myapp`,
if err != nil {
return fmt.Errorf("cannot load settings: %w", err)
}
globalPHP := settings.GlobalPHP
globalPHP := settings.Defaults.PHP

phpVersion := globalPHP
if v, err := phpenv.ResolveVersion(absPath); err == nil && v != "" {
Expand Down Expand Up @@ -95,8 +95,8 @@ pv link --name=myapp ~/Code/myapp`,
}

// Generate TLS certificate for Vite dev server auto-detection.
hostname := name + "." + settings.TLD
if err := certs.EnsureValetConfig(settings.TLD); err != nil {
hostname := name + "." + settings.Defaults.TLD
if err := certs.EnsureValetConfig(settings.Defaults.TLD); err != nil {
ui.Subtle(fmt.Sprintf("Skipped Vite TLS setup: %v", err))
} else if err := certs.GenerateSiteTLS(hostname); err != nil {
ui.Subtle(fmt.Sprintf("Vite TLS cert not generated (HTTPS HMR may need manual config): %v", err))
Expand All @@ -107,7 +107,7 @@ pv link --name=myapp ~/Code/myapp`,
typeLabel = "unknown"
}

domain := "https://" + name + "." + settings.TLD
domain := "https://" + name + "." + settings.Defaults.TLD

fmt.Fprintln(os.Stderr)
ui.Success(fmt.Sprintf("Linked %s", ui.Purple.Bold(true).Render(domain)))
Expand Down
10 changes: 3 additions & 7 deletions cmd/link_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package cmd

import (
"encoding/json"
"os"
"path/filepath"
"strings"
Expand All @@ -14,12 +13,9 @@ import (

func writeDefaultSettings(t *testing.T) {
t.Helper()
if err := config.EnsureDirs(); err != nil {
t.Fatalf("EnsureDirs() error = %v", err)
}
data, _ := json.Marshal(config.DefaultSettings())
if err := os.WriteFile(config.SettingsPath(), data, 0644); err != nil {
t.Fatalf("write settings error = %v", err)
s := config.DefaultSettings()
if err := s.Save(); err != nil {
t.Fatalf("Save settings error = %v", err)
}
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ var listCmd = &cobra.Command{
settings, _ := config.LoadSettings()
tld := "test"
if settings != nil {
tld = settings.TLD
tld = settings.Defaults.TLD
}

projects := reg.List()
Expand Down
8 changes: 4 additions & 4 deletions cmd/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ var setupCmd = &cobra.Command{
ui.Subtle(fmt.Sprintf("Warning: could not load settings: %v", err))
}
tld := "test"
if settings != nil && settings.TLD != "" {
tld = settings.TLD
if settings != nil && settings.Defaults.TLD != "" {
tld = settings.Defaults.TLD
}

// Run the tabbed setup wizard.
Expand Down Expand Up @@ -125,9 +125,9 @@ var setupCmd = &cobra.Command{
}

// Save TLD.
s := &config.Settings{TLD: tld}
s := &config.Settings{Defaults: config.Defaults{TLD: tld}}
if settings != nil {
s.GlobalPHP = settings.GlobalPHP
s.Defaults.PHP = settings.Defaults.PHP
}
if err := s.Save(); err != nil {
return fmt.Errorf("cannot save settings: %w", err)
Expand Down
2 changes: 1 addition & 1 deletion cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func startFG() error {
return fmt.Errorf("cannot load settings: %w", err)
}

return server.Start(settings.TLD)
return server.Start(settings.Defaults.TLD)
}

func startDaemon() error {
Expand Down
6 changes: 3 additions & 3 deletions cmd/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ var statusCmd = &cobra.Command{
fmt.Fprintln(os.Stderr)

// Network info.
fmt.Fprintf(os.Stderr, " %s %s\n", ui.Purple.Render("TLD"), ui.Bold.Render("."+settings.TLD))
fmt.Fprintf(os.Stderr, " %s %s\n", ui.Purple.Render("TLD"), ui.Bold.Render("."+settings.Defaults.TLD))
fmt.Fprintf(os.Stderr, " %s %s %s %s\n",
ui.Purple.Render("DNS"),
fmt.Sprintf("127.0.0.1:%d", config.DNSPort),
Expand All @@ -66,7 +66,7 @@ var statusCmd = &cobra.Command{
)

// PHP version info.
globalPHP := settings.GlobalPHP
globalPHP := settings.Defaults.PHP
versions, _ := phpenv.InstalledVersions()
if len(versions) > 0 {
var labels []string
Expand Down Expand Up @@ -112,7 +112,7 @@ var statusCmd = &cobra.Command{
typeLabel = "unknown"
}

domain := "https://" + p.Name + "." + settings.TLD
domain := "https://" + p.Name + "." + settings.Defaults.TLD
rows[i] = []string{domain, typeLabel, phpV}
}
ui.Table([]string{"Site", "Type", "PHP"}, rows)
Expand Down
2 changes: 1 addition & 1 deletion cmd/uninstall.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ var uninstallCmd = &cobra.Command{
settings, _ := config.LoadSettings()
tld := "test"
if settings != nil {
tld = settings.TLD
tld = settings.Defaults.TLD
}

// Uninstall tools (each cleans up its own binary + PATH entry).
Expand Down
4 changes: 2 additions & 2 deletions cmd/uninstall_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ func TestUninstall_SettingsLoadFallback(t *testing.T) {
if err != nil {
t.Fatalf("LoadSettings error = %v", err)
}
if settings.TLD != "test" {
t.Errorf("TLD = %q, want %q", settings.TLD, "test")
if settings.Defaults.TLD != "test" {
t.Errorf("TLD = %q, want %q", settings.Defaults.TLD, "test")
}
}
2 changes: 1 addition & 1 deletion cmd/unlink.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ pv unlink`,
settings, _ := config.LoadSettings()
tld := "test"
if settings != nil {
tld = settings.TLD
tld = settings.Defaults.TLD
}

// Remove TLS certificate for Vite dev server.
Expand Down
4 changes: 2 additions & 2 deletions internal/caddy/caddy.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ func GenerateServiceSiteConfigs(reg *registry.Registry) error {
var buf bytes.Buffer
if err := tmpl.Execute(&buf, serviceConsoleData{
Subdomain: route.Subdomain,
TLD: settings.TLD,
TLD: settings.Defaults.TLD,
Port: route.Port,
}); err != nil {
return err
Expand Down Expand Up @@ -415,7 +415,7 @@ func writeConfig(dir string, p registry.Project, settings *config.Settings, root
Name: p.Name,
Path: p.Path,
RootPath: rootPath,
TLD: settings.TLD,
TLD: settings.Defaults.TLD,
Port: port,
}); err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion internal/commands/service/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ pv service:add postgres 16`,
settings, _ := config.LoadSettings()
if settings != nil {
for _, route := range routes {
fmt.Fprintf(os.Stderr, " %s https://%s.pv.%s\n", ui.Muted.Render(route.Subdomain), route.Subdomain, settings.TLD)
fmt.Fprintf(os.Stderr, " %s https://%s.pv.%s\n", ui.Muted.Render(route.Subdomain), route.Subdomain, settings.Defaults.TLD)
}
}
} else if consolePt := svc.ConsolePort(version); consolePt > 0 {
Expand Down
3 changes: 2 additions & 1 deletion internal/config/paths.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,10 @@ func VersionsPath() string {
}

func SettingsPath() string {
return filepath.Join(ConfigDir(), "settings.json")
return filepath.Join(PvDir(), "pv.yml")
}


func CaddyfilePath() string {
return filepath.Join(ConfigDir(), "Caddyfile")
}
Expand Down
4 changes: 2 additions & 2 deletions internal/config/paths_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ func TestSettingsPath(t *testing.T) {
t.Setenv("HOME", home)

got := SettingsPath()
if !strings.HasSuffix(got, filepath.Join(".pv", "config", "settings.json")) {
t.Errorf("SettingsPath() = %q, want suffix .pv/config/settings.json", got)
if !strings.HasSuffix(got, filepath.Join(".pv", "pv.yml")) {
t.Errorf("SettingsPath() = %q, want suffix .pv/pv.yml", got)
}
}

Expand Down
27 changes: 19 additions & 8 deletions internal/config/settings.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
package config

import (
"encoding/json"
"fmt"
"os"
"regexp"

"gopkg.in/yaml.v3"
)

type Defaults struct {
PHP string `yaml:"php,omitempty"`
TLD string `yaml:"tld"`
}

type Settings struct {
TLD string `json:"tld"`
GlobalPHP string `json:"global_php,omitempty"`
Defaults Defaults `yaml:"defaults"`
}

var validTLD = regexp.MustCompile(`^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$`)

func DefaultSettings() *Settings {
return &Settings{TLD: "test"}
return &Settings{Defaults: Defaults{TLD: "test"}}
}

func LoadSettings() (*Settings, error) {
Expand All @@ -28,20 +33,26 @@ func LoadSettings() (*Settings, error) {
return nil, err
}
var s Settings
if err := json.Unmarshal(data, &s); err != nil {
if err := yaml.Unmarshal(data, &s); err != nil {
return nil, err
}
if s.TLD == "" {
s.TLD = "test"
if s.Defaults.TLD == "" {
s.Defaults.TLD = "test"
}
return &s, nil
}

func (s *Settings) Save() error {
if s.Defaults.TLD == "" {
s.Defaults.TLD = "test"
}
if err := ValidateTLD(s.Defaults.TLD); err != nil {
return err
}
if err := EnsureDirs(); err != nil {
return err
}
data, err := json.MarshalIndent(s, "", " ")
data, err := yaml.Marshal(s)
if err != nil {
return err
}
Expand Down
Loading