diff --git a/admin/admin.go b/admin/admin.go
index 738e530..f5426a3 100644
--- a/admin/admin.go
+++ b/admin/admin.go
@@ -30,7 +30,7 @@ func AdminHandler(w http.ResponseWriter, r *http.Request) {
API Log
System Log
Env Vars
- Deploy
+ Server
`
html := app.RenderHTMLForRequest("Admin", "Admin Dashboard", content, r)
diff --git a/admin/deploy.go b/admin/deploy.go
index f1497f8..b8a8122 100644
--- a/admin/deploy.go
+++ b/admin/deploy.go
@@ -39,8 +39,8 @@ func sourceDir() string {
return filepath.Join(home, "src", "mu")
}
-// DeployHandler shows the deploy page and handles deploy requests
-func DeployHandler(w http.ResponseWriter, r *http.Request) {
+// UpdateHandler shows the update/restart page and handles requests
+func UpdateHandler(w http.ResponseWriter, r *http.Request) {
_, _, err := auth.RequireAdmin(r)
if err != nil {
app.Forbidden(w, r, "Admin access required")
@@ -52,27 +52,32 @@ func DeployHandler(w http.ResponseWriter, r *http.Request) {
return
}
- // GET — render deploy page
+ // GET — render server page
content := `
← Admin
- Deploy
- Pull latest code, build, and restart the service.
+ Server
Source: ` + sourceDir() + `
-
+
+
`
- html := app.RenderHTMLForRequest("Admin", "Deploy", content, r)
+ html := app.RenderHTMLForRequest("Admin", "Server", content, r)
w.Write([]byte(html))
}
@@ -111,7 +121,7 @@ func handleDeploy(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{
"success": false,
- "logs": []deployLogEntry{{Step: "lock", Output: "Deploy already in progress", Success: false}},
+ "logs": []deployLogEntry{{Step: "lock", Output: "Already in progress", Success: false}},
})
return
}
@@ -124,22 +134,37 @@ func handleDeploy(w http.ResponseWriter, r *http.Request) {
deployMu.Unlock()
}()
+ var req struct {
+ Action string `json:"action"`
+ }
+ json.NewDecoder(r.Body).Decode(&req)
+
dir := sourceDir()
var logs []deployLogEntry
success := true
- steps := []struct {
+ type step struct {
name string
cmd string
args []string
- }{
- {"git pull", "git", []string{"pull", "origin", "main"}},
- {"go install", "go", []string{"install"}},
- {"restart service", "sudo", []string{"-n", "systemctl", "restart", "mu"}},
}
- for _, step := range steps {
- entry := runStep(dir, step.name, step.cmd, step.args)
+ var steps []step
+ switch req.Action {
+ case "restart":
+ steps = []step{
+ {"restart service", "sudo", []string{"-n", "systemctl", "restart", "mu"}},
+ }
+ default: // "update"
+ steps = []step{
+ {"git pull", "git", []string{"pull", "origin", "main"}},
+ {"go install", "go", []string{"install"}},
+ {"restart service", "sudo", []string{"-n", "systemctl", "restart", "mu"}},
+ }
+ }
+
+ for _, s := range steps {
+ entry := runStep(dir, s.name, s.cmd, s.args)
logs = append(logs, entry)
if !entry.Success {
success = false
@@ -163,8 +188,18 @@ func runStep(dir, name, cmdName string, args []string) deployLogEntry {
cmd := exec.Command(cmdName, args...)
cmd.Dir = dir
- // Inherit env so go build picks up GOPATH etc
- cmd.Env = append(os.Environ(), "HOME="+os.Getenv("HOME"))
+ // Inherit env and ensure Go/snap paths are available
+ home := os.Getenv("HOME")
+ path := os.Getenv("PATH")
+ goPath := filepath.Join(home, "go", "bin")
+ goRoot := "/usr/local/go/bin"
+ if !strings.Contains(path, goPath) {
+ path = goPath + ":" + path
+ }
+ if !strings.Contains(path, goRoot) {
+ path = goRoot + ":" + path
+ }
+ cmd.Env = append(os.Environ(), "HOME="+home, "PATH="+path)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
diff --git a/main.go b/main.go
index e4818d9..4e8f2d2 100644
--- a/main.go
+++ b/main.go
@@ -209,7 +209,7 @@ func main() {
"/admin/api": true,
"/admin/log": true,
"/admin/env": true,
- "/admin/deploy": true,
+ "/admin/server": true,
"/plans": false, // Public - shows pricing options
"/donate": false,
"/wallet": false, // Public - shows wallet info; auth checked in handler
@@ -281,8 +281,8 @@ func main() {
// environment variables status
http.HandleFunc("/admin/env", admin.EnvHandler)
- // deploy
- http.HandleFunc("/admin/deploy", admin.DeployHandler)
+ // server update and restart
+ http.HandleFunc("/admin/server", admin.UpdateHandler)
// plans page (public - overview of options)
http.HandleFunc("/plans", app.Plans)