summaryrefslogtreecommitdiffstats
path: root/internal/state/state.go
diff options
context:
space:
mode:
authorClawd <ai@clawd.bot>2026-02-17 07:54:26 -0800
committerClawd <ai@clawd.bot>2026-02-17 07:54:26 -0800
commit6b2c04728cd914f27ae62c1df0bf5df24ac9a628 (patch)
tree8a103ac79194a05fae438b0da105589aaa6b78d9 /internal/state/state.go
parent5e5de4ea1aa98f75d470e4a61644d4b9f100c4b0 (diff)
Remove v1 code, simplify state to just base_domain
- Delete all v1 commands (deploy, init, list, status, remove, etc.) - Delete v1 env/ and host/ subcommand directories - Simplify state.go: remove NextPort, Apps, AllocatePort, etc. - Local state now only tracks default_host + base_domain per host - Ports and deploys are tracked on the server (/etc/ship/ports/) - host init now creates minimal state.json
Diffstat (limited to 'internal/state/state.go')
-rw-r--r--internal/state/state.go83
1 files changed, 6 insertions, 77 deletions
diff --git a/internal/state/state.go b/internal/state/state.go
index c9aa21d..9b06179 100644
--- a/internal/state/state.go
+++ b/internal/state/state.go
@@ -8,38 +8,18 @@ import (
8 "regexp" 8 "regexp"
9) 9)
10 10
11// State represents the entire local deployment state 11// State represents the local ship configuration
12type State struct { 12type State struct {
13 DefaultHost string `json:"default_host,omitempty"` 13 DefaultHost string `json:"default_host,omitempty"`
14 Hosts map[string]*Host `json:"hosts"` 14 Hosts map[string]*Host `json:"hosts"`
15} 15}
16 16
17// Host represents deployment state for a single VPS 17// Host represents configuration for a single VPS
18type Host struct { 18type Host struct {
19 NextPort int `json:"next_port"` 19 BaseDomain string `json:"base_domain,omitempty"`
20 BaseDomain string `json:"base_domain,omitempty"` 20 GitSetup bool `json:"git_setup,omitempty"`
21 GitSetup bool `json:"git_setup,omitempty"`
22 Apps map[string]*App `json:"apps"`
23} 21}
24 22
25// App represents a deployed application or static site
26type App struct {
27 Type string `json:"type"` // "app", "static", "git-app", or "git-static"
28 Domain string `json:"domain"`
29 Port int `json:"port,omitempty"` // only for type="app" or "git-app"
30 Repo string `json:"repo,omitempty"` // only for git types, e.g. "/srv/git/foo.git"
31 Public bool `json:"public,omitempty"` // only for git types, enables HTTP clone access
32 Env map[string]string `json:"env,omitempty"` // only for type="app" or "git-app"
33 Args string `json:"args,omitempty"` // only for type="app"
34 Files []string `json:"files,omitempty"` // only for type="app"
35 Memory string `json:"memory,omitempty"` // only for type="app"
36 CPU string `json:"cpu,omitempty"` // only for type="app"
37}
38
39const (
40 startPort = 8001
41)
42
43var validName = regexp.MustCompile(`^[a-z][a-z0-9-]{0,62}$`) 23var validName = regexp.MustCompile(`^[a-z][a-z0-9-]{0,62}$`)
44 24
45// ValidateName checks that a name is safe for use in shell commands, 25// ValidateName checks that a name is safe for use in shell commands,
@@ -55,7 +35,6 @@ func ValidateName(name string) error {
55func Load() (*State, error) { 35func Load() (*State, error) {
56 path := statePath() 36 path := statePath()
57 37
58 // If file doesn't exist, return empty state
59 if _, err := os.Stat(path); os.IsNotExist(err) { 38 if _, err := os.Stat(path); os.IsNotExist(err) {
60 return &State{ 39 return &State{
61 Hosts: make(map[string]*Host), 40 Hosts: make(map[string]*Host),
@@ -72,7 +51,6 @@ func Load() (*State, error) {
72 return nil, fmt.Errorf("failed to parse state file: %w", err) 51 return nil, fmt.Errorf("failed to parse state file: %w", err)
73 } 52 }
74 53
75 // Initialize maps if nil
76 if state.Hosts == nil { 54 if state.Hosts == nil {
77 state.Hosts = make(map[string]*Host) 55 state.Hosts = make(map[string]*Host)
78 } 56 }
@@ -84,7 +62,6 @@ func Load() (*State, error) {
84func (s *State) Save() error { 62func (s *State) Save() error {
85 path := statePath() 63 path := statePath()
86 64
87 // Ensure directory exists
88 dir := filepath.Dir(path) 65 dir := filepath.Dir(path)
89 if err := os.MkdirAll(dir, 0755); err != nil { 66 if err := os.MkdirAll(dir, 0755); err != nil {
90 return fmt.Errorf("failed to create config directory: %w", err) 67 return fmt.Errorf("failed to create config directory: %w", err)
@@ -102,60 +79,14 @@ func (s *State) Save() error {
102 return nil 79 return nil
103} 80}
104 81
105// GetHost returns the host state, creating it if it doesn't exist 82// GetHost returns the host config, creating it if it doesn't exist
106func (s *State) GetHost(host string) *Host { 83func (s *State) GetHost(host string) *Host {
107 if s.Hosts[host] == nil { 84 if s.Hosts[host] == nil {
108 s.Hosts[host] = &Host{ 85 s.Hosts[host] = &Host{}
109 NextPort: startPort,
110 Apps: make(map[string]*App),
111 }
112 }
113 if s.Hosts[host].Apps == nil {
114 s.Hosts[host].Apps = make(map[string]*App)
115 } 86 }
116 return s.Hosts[host] 87 return s.Hosts[host]
117} 88}
118 89
119// AllocatePort returns the next available port for a host
120func (s *State) AllocatePort(host string) int {
121 h := s.GetHost(host)
122 port := h.NextPort
123 h.NextPort++
124 return port
125}
126
127// AddApp adds or updates an app in the state
128func (s *State) AddApp(host, name string, app *App) {
129 h := s.GetHost(host)
130 h.Apps[name] = app
131}
132
133// RemoveApp removes an app from the state
134func (s *State) RemoveApp(host, name string) error {
135 h := s.GetHost(host)
136 if _, exists := h.Apps[name]; !exists {
137 return fmt.Errorf("app %s not found", name)
138 }
139 delete(h.Apps, name)
140 return nil
141}
142
143// GetApp returns an app from the state
144func (s *State) GetApp(host, name string) (*App, error) {
145 h := s.GetHost(host)
146 app, exists := h.Apps[name]
147 if !exists {
148 return nil, fmt.Errorf("app %s not found", name)
149 }
150 return app, nil
151}
152
153// ListApps returns all apps for a host
154func (s *State) ListApps(host string) map[string]*App {
155 h := s.GetHost(host)
156 return h.Apps
157}
158
159// GetDefaultHost returns the default host, or empty string if not set 90// GetDefaultHost returns the default host, or empty string if not set
160func (s *State) GetDefaultHost() string { 91func (s *State) GetDefaultHost() string {
161 return s.DefaultHost 92 return s.DefaultHost
@@ -166,11 +97,9 @@ func (s *State) SetDefaultHost(host string) {
166 s.DefaultHost = host 97 s.DefaultHost = host
167} 98}
168 99
169// statePath returns the path to the state file
170func statePath() string { 100func statePath() string {
171 home, err := os.UserHomeDir() 101 home, err := os.UserHomeDir()
172 if err != nil { 102 if err != nil {
173 // Fallback to current directory (should rarely happen)
174 return ".ship-state.json" 103 return ".ship-state.json"
175 } 104 }
176 return filepath.Join(home, ".config", "ship", "state.json") 105 return filepath.Join(home, ".config", "ship", "state.json")