dev.go
77 lines1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package commands
import (
"cmp"
"flag"
"fmt"
"log"
"net"
"os"
"os/exec"
"path/filepath"
)
const devUsage = `Start a development server
Usage:
congo dev [flags]
Flags:
--port <port> Override server port (default: 5000)
The server runs with ENV=development. Press Ctrl+C to stop.
`
func Dev() {
fs := flag.NewFlagSet("dev", flag.ExitOnError)
fs.Usage = func() { fmt.Print(devUsage) }
port := fs.String("port", "", "Override server port")
fs.Parse(os.Args[2:])
dir := findAppDir()
env := append(os.Environ(), "ENV=development")
if *port != "" {
env = append(env, "PORT="+*port)
}
listenPort := cmp.Or(*port, os.Getenv("PORT"), "5000")
// Check for port conflicts before starting.
if conn, err := net.Dial("tcp", "localhost:"+listenPort); err == nil {
conn.Close()
log.Fatalf("Port %s is already in use. Try:\n congo dev --port <other-port>", listenPort)
}
fmt.Printf("Starting development server from ./%s\n", dir)
fmt.Printf(" http://localhost:%s\n\n", listenPort)
cmd := exec.Command("go", "run", "./"+dir)
cmd.Env = env
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
if err := cmd.Run(); err != nil {
if exitErr, ok := err.(*exec.ExitError); ok && exitErr.ExitCode() == 2 {
fmt.Fprintf(os.Stderr, "\nBuild failed. Check the errors above.\n")
}
os.Exit(1)
}
}
// findAppDir locates the app directory containing main.go.
// Checks common names, then falls back to root.
func findAppDir() string {
for _, dir := range []string{"web", "app", "api", "cmd"} {
if _, err := os.Stat(filepath.Join(dir, "main.go")); err == nil {
return dir
}
}
if _, err := os.Stat("main.go"); err == nil {
return "."
}
log.Fatal("No main.go found in web/, app/, api/, cmd/, or root.\nRun 'congo init <name>' to create a project.")
return ""
}