diff options
Diffstat (limited to 'internal/templates')
| -rw-r--r-- | internal/templates/templates.go | 358 |
1 files changed, 0 insertions, 358 deletions
diff --git a/internal/templates/templates.go b/internal/templates/templates.go deleted file mode 100644 index 2163f47..0000000 --- a/internal/templates/templates.go +++ /dev/null | |||
| @@ -1,358 +0,0 @@ | |||
| 1 | package templates | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "bytes" | ||
| 5 | "text/template" | ||
| 6 | ) | ||
| 7 | |||
| 8 | var serviceTemplate = `[Unit] | ||
| 9 | Description={{.Name}} | ||
| 10 | After=network.target | ||
| 11 | |||
| 12 | [Service] | ||
| 13 | Type=simple | ||
| 14 | User={{.User}} | ||
| 15 | WorkingDirectory={{.WorkDir}} | ||
| 16 | EnvironmentFile={{.EnvFile}} | ||
| 17 | ExecStart={{.BinaryPath}} {{.Args}} | ||
| 18 | Restart=always | ||
| 19 | RestartSec=5s | ||
| 20 | NoNewPrivileges=true | ||
| 21 | PrivateTmp=true | ||
| 22 | {{- if .Memory}} | ||
| 23 | MemoryMax={{.Memory}} | ||
| 24 | {{- end}} | ||
| 25 | {{- if .CPU}} | ||
| 26 | CPUQuota={{.CPU}} | ||
| 27 | {{- end}} | ||
| 28 | |||
| 29 | [Install] | ||
| 30 | WantedBy=multi-user.target | ||
| 31 | ` | ||
| 32 | |||
| 33 | var appCaddyTemplate = `{{.Domain}} { | ||
| 34 | reverse_proxy 127.0.0.1:{{.Port}} | ||
| 35 | } | ||
| 36 | ` | ||
| 37 | |||
| 38 | var staticCaddyTemplate = `{{.Domain}} { | ||
| 39 | root * {{.RootDir}} | ||
| 40 | file_server | ||
| 41 | encode gzip | ||
| 42 | } | ||
| 43 | ` | ||
| 44 | |||
| 45 | // SystemdService generates a systemd service unit file | ||
| 46 | func SystemdService(data map[string]string) (string, error) { | ||
| 47 | tmpl, err := template.New("service").Parse(serviceTemplate) | ||
| 48 | if err != nil { | ||
| 49 | return "", err | ||
| 50 | } | ||
| 51 | |||
| 52 | var buf bytes.Buffer | ||
| 53 | if err := tmpl.Execute(&buf, data); err != nil { | ||
| 54 | return "", err | ||
| 55 | } | ||
| 56 | |||
| 57 | return buf.String(), nil | ||
| 58 | } | ||
| 59 | |||
| 60 | // AppCaddy generates a Caddy config for a Go app | ||
| 61 | func AppCaddy(data map[string]string) (string, error) { | ||
| 62 | tmpl, err := template.New("caddy").Parse(appCaddyTemplate) | ||
| 63 | if err != nil { | ||
| 64 | return "", err | ||
| 65 | } | ||
| 66 | |||
| 67 | var buf bytes.Buffer | ||
| 68 | if err := tmpl.Execute(&buf, data); err != nil { | ||
| 69 | return "", err | ||
| 70 | } | ||
| 71 | |||
| 72 | return buf.String(), nil | ||
| 73 | } | ||
| 74 | |||
| 75 | // StaticCaddy generates a Caddy config for a static site | ||
| 76 | func StaticCaddy(data map[string]string) (string, error) { | ||
| 77 | tmpl, err := template.New("caddy").Parse(staticCaddyTemplate) | ||
| 78 | if err != nil { | ||
| 79 | return "", err | ||
| 80 | } | ||
| 81 | |||
| 82 | var buf bytes.Buffer | ||
| 83 | if err := tmpl.Execute(&buf, data); err != nil { | ||
| 84 | return "", err | ||
| 85 | } | ||
| 86 | |||
| 87 | return buf.String(), nil | ||
| 88 | } | ||
| 89 | |||
| 90 | var postReceiveHookTemplate = `#!/bin/bash | ||
| 91 | set -euo pipefail | ||
| 92 | |||
| 93 | REPO=/srv/git/{{.Name}}.git | ||
| 94 | SRC=/var/lib/{{.Name}}/src | ||
| 95 | NAME={{.Name}} | ||
| 96 | |||
| 97 | while read oldrev newrev refname; do | ||
| 98 | branch=$(git rev-parse --symbolic --abbrev-ref "$refname") | ||
| 99 | [ "$branch" = "main" ] || { echo "Pushed to $branch, skipping deploy."; exit 0; } | ||
| 100 | done | ||
| 101 | |||
| 102 | # Ensure checkout directory exists | ||
| 103 | sudo /bin/mkdir -p "$SRC" | ||
| 104 | sudo /bin/chown -R git:git "/var/lib/${NAME}" | ||
| 105 | |||
| 106 | echo "==> Checking out code..." | ||
| 107 | git --work-tree="$SRC" --git-dir="$REPO" checkout -f main | ||
| 108 | |||
| 109 | cd "$SRC" | ||
| 110 | |||
| 111 | # If no Dockerfile, nothing to deploy | ||
| 112 | if [ ! -f Dockerfile ]; then | ||
| 113 | echo "No Dockerfile found, skipping deploy." | ||
| 114 | exit 0 | ||
| 115 | fi | ||
| 116 | |||
| 117 | # Install deployment config from repo (using full paths for sudoers) | ||
| 118 | if [ -f "$SRC/.ship/service" ]; then | ||
| 119 | echo "==> Installing systemd unit..." | ||
| 120 | sudo /bin/cp "$SRC/.ship/service" "/etc/systemd/system/${NAME}.service" | ||
| 121 | sudo systemctl daemon-reload | ||
| 122 | fi | ||
| 123 | if [ -f "$SRC/.ship/Caddyfile" ]; then | ||
| 124 | echo "==> Installing Caddy config..." | ||
| 125 | sudo /bin/cp "$SRC/.ship/Caddyfile" "/etc/caddy/sites-enabled/${NAME}.caddy" | ||
| 126 | sudo systemctl reload caddy | ||
| 127 | fi | ||
| 128 | |||
| 129 | # Ensure data directory exists | ||
| 130 | sudo /bin/mkdir -p "/var/lib/${NAME}/data" | ||
| 131 | sudo /bin/chown -R git:git "/var/lib/${NAME}/data" | ||
| 132 | |||
| 133 | echo "==> Building Docker image..." | ||
| 134 | docker build -t ${NAME}:latest . | ||
| 135 | |||
| 136 | echo "==> Restarting service..." | ||
| 137 | sudo systemctl restart ${NAME} | ||
| 138 | |||
| 139 | echo "==> Deploy complete!" | ||
| 140 | ` | ||
| 141 | |||
| 142 | var postReceiveHookStaticTemplate = `#!/bin/bash | ||
| 143 | set -euo pipefail | ||
| 144 | |||
| 145 | REPO=/srv/git/{{.Name}}.git | ||
| 146 | WEBROOT=/var/www/{{.Name}} | ||
| 147 | NAME={{.Name}} | ||
| 148 | |||
| 149 | while read oldrev newrev refname; do | ||
| 150 | branch=$(git rev-parse --symbolic --abbrev-ref "$refname") | ||
| 151 | [ "$branch" = "main" ] || { echo "Pushed to $branch, skipping deploy."; exit 0; } | ||
| 152 | done | ||
| 153 | |||
| 154 | echo "==> Deploying static site..." | ||
| 155 | git --work-tree="$WEBROOT" --git-dir="$REPO" checkout -f main | ||
| 156 | |||
| 157 | if [ -f "$WEBROOT/.ship/Caddyfile" ]; then | ||
| 158 | echo "==> Installing Caddy config..." | ||
| 159 | sudo /bin/cp "$WEBROOT/.ship/Caddyfile" "/etc/caddy/sites-enabled/${NAME}.caddy" | ||
| 160 | sudo systemctl reload caddy | ||
| 161 | fi | ||
| 162 | |||
| 163 | echo "==> Deploy complete!" | ||
| 164 | ` | ||
| 165 | |||
| 166 | var codeCaddyTemplate = `{{.BaseDomain}} { | ||
| 167 | @goget query go-get=1 | ||
| 168 | handle @goget { | ||
| 169 | root * /opt/ship/vanity | ||
| 170 | templates | ||
| 171 | rewrite * /index.html | ||
| 172 | file_server | ||
| 173 | } | ||
| 174 | |||
| 175 | @git path_regexp "^.*/(HEAD|info/refs|objects/info/[^/]+|git-upload-pack|git-receive-pack)$" | ||
| 176 | handle @git { | ||
| 177 | reverse_proxy unix//run/fcgiwrap.socket { | ||
| 178 | transport fastcgi { | ||
| 179 | env SCRIPT_FILENAME /usr/lib/git-core/git-http-backend | ||
| 180 | env GIT_PROJECT_ROOT /srv/git | ||
| 181 | env REQUEST_METHOD {method} | ||
| 182 | env QUERY_STRING {query} | ||
| 183 | env PATH_INFO {path} | ||
| 184 | } | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | @cgitassets path /cgit/* | ||
| 189 | handle @cgitassets { | ||
| 190 | root * /usr/share/cgit | ||
| 191 | uri strip_prefix /cgit | ||
| 192 | file_server | ||
| 193 | } | ||
| 194 | |||
| 195 | handle { | ||
| 196 | reverse_proxy unix//run/fcgiwrap.socket { | ||
| 197 | transport fastcgi { | ||
| 198 | env SCRIPT_FILENAME /usr/lib/cgit/cgit.cgi | ||
| 199 | env QUERY_STRING {query} | ||
| 200 | env REQUEST_METHOD {method} | ||
| 201 | env PATH_INFO {path} | ||
| 202 | env HTTP_HOST {host} | ||
| 203 | env SERVER_NAME {host} | ||
| 204 | } | ||
| 205 | } | ||
| 206 | } | ||
| 207 | } | ||
| 208 | ` | ||
| 209 | |||
| 210 | var dockerServiceTemplate = `[Unit] | ||
| 211 | Description={{.Name}} | ||
| 212 | After=network.target docker.service | ||
| 213 | Requires=docker.service | ||
| 214 | |||
| 215 | [Service] | ||
| 216 | Type=simple | ||
| 217 | ExecStartPre=-/usr/bin/docker rm -f {{.Name}} | ||
| 218 | ExecStart=/usr/bin/docker run --rm --name {{.Name}} \ | ||
| 219 | -p 127.0.0.1:{{.Port}}:{{.ContainerPort}} \ | ||
| 220 | --env-file /etc/ship/env/{{.Name}}.env \ | ||
| 221 | -v /var/lib/{{.Name}}/data:/data \ | ||
| 222 | {{.Name}}:latest | ||
| 223 | ExecStop=/usr/bin/docker stop -t 10 {{.Name}} | ||
| 224 | Restart=always | ||
| 225 | RestartSec=5s | ||
| 226 | |||
| 227 | [Install] | ||
| 228 | WantedBy=multi-user.target | ||
| 229 | ` | ||
| 230 | |||
| 231 | var defaultAppCaddyTemplate = `{{.Domain}} { | ||
| 232 | reverse_proxy 127.0.0.1:{{.Port}} | ||
| 233 | } | ||
| 234 | ` | ||
| 235 | |||
| 236 | var defaultStaticCaddyTemplate = `{{.Domain}} { | ||
| 237 | root * /var/www/{{.Name}} | ||
| 238 | file_server | ||
| 239 | encode gzip | ||
| 240 | } | ||
| 241 | ` | ||
| 242 | |||
| 243 | // PostReceiveHook generates a post-receive hook for git-app repos | ||
| 244 | func PostReceiveHook(data map[string]string) (string, error) { | ||
| 245 | return renderTemplate("post-receive", postReceiveHookTemplate, data) | ||
| 246 | } | ||
| 247 | |||
| 248 | // PostReceiveHookStatic generates a post-receive hook for git-static repos | ||
| 249 | func PostReceiveHookStatic(data map[string]string) (string, error) { | ||
| 250 | return renderTemplate("post-receive-static", postReceiveHookStaticTemplate, data) | ||
| 251 | } | ||
| 252 | |||
| 253 | // CodeCaddy generates the base domain Caddy config for vanity imports + git HTTP | ||
| 254 | func CodeCaddy(data map[string]string) (string, error) { | ||
| 255 | return renderTemplate("code-caddy", codeCaddyTemplate, data) | ||
| 256 | } | ||
| 257 | |||
| 258 | var cgitrcTemplate = `virtual-root=/ | ||
| 259 | css=/cgit/cgit.css | ||
| 260 | logo=/cgit/cgit.png | ||
| 261 | header=/opt/ship/cgit-header.html | ||
| 262 | scan-path=/srv/git/ | ||
| 263 | export-ok=git-daemon-export-ok | ||
| 264 | enable-http-clone=0 | ||
| 265 | clone-url=https://{{.BaseDomain}}/$CGIT_REPO_URL | ||
| 266 | root-title={{.BaseDomain}} | ||
| 267 | root-desc= | ||
| 268 | remove-suffix=.git | ||
| 269 | ` | ||
| 270 | |||
| 271 | var cgitHeaderTemplate = `<style> | ||
| 272 | body, table, td, th, div#cgit { background: #1a1a2e; color: #ccc; } | ||
| 273 | a { color: #7aa2f7; } | ||
| 274 | a:hover { color: #9ecbff; } | ||
| 275 | table.list tr:hover td { background: #222244; } | ||
| 276 | table.list td, table.list th { border-bottom: 1px solid #333; } | ||
| 277 | th { background: #16213e; } | ||
| 278 | td.commitgraph .column1 { color: #7aa2f7; } | ||
| 279 | td.commitgraph .column2 { color: #9ece6a; } | ||
| 280 | td.logheader { background: #16213e; } | ||
| 281 | div#header { background: #16213e; border-bottom: 1px solid #333; } | ||
| 282 | div#header .sub { color: #888; } | ||
| 283 | table.tabs { border-bottom: 1px solid #333; } | ||
| 284 | table.tabs td a { color: #ccc; } | ||
| 285 | table.tabs td a.active { color: #fff; background: #1a1a2e; border: 1px solid #333; border-bottom: 1px solid #1a1a2e; } | ||
| 286 | div.footer { color: #555; } | ||
| 287 | div.footer a { color: #555; } | ||
| 288 | div.diffstat-header { background: #16213e; } | ||
| 289 | table.diffstat { border-bottom: 1px solid #333; } | ||
| 290 | table.diffstat td.graph span.graph-moreremoved { background: #f7768e; } | ||
| 291 | table.diffstat td.graph span.graph-moreadded { background: #9ece6a; } | ||
| 292 | table.diffstat td.graph span.graph-removed { background: #f7768e; } | ||
| 293 | table.diffstat td.graph span.graph-added { background: #9ece6a; } | ||
| 294 | table.diff { background: #131320; border: 1px solid #333; } | ||
| 295 | div.diff td { font-family: monospace; } | ||
| 296 | div.head { color: #ccc; background: #16213e; padding: 2px 4px; } | ||
| 297 | div.hunk { color: #7aa2f7; background: #1a1a3e; padding: 2px 4px; } | ||
| 298 | div.add { color: #9ece6a; background: #1a2e1a; padding: 2px 4px; } | ||
| 299 | div.del { color: #f7768e; background: #2e1a1a; padding: 2px 4px; } | ||
| 300 | table.diff td.add { color: #9ece6a; background: #1a2e1a; } | ||
| 301 | table.diff td.del { color: #f7768e; background: #2e1a1a; } | ||
| 302 | table.diff td.hunk { color: #7aa2f7; background: #1a1a3e; } | ||
| 303 | table.diff td { border: none; background: #1a1a2e; } | ||
| 304 | table.blob td.lines { color: #ccc; } | ||
| 305 | table.blob td.linenumbers { background: #16213e; } | ||
| 306 | table.blob td.linenumbers a { color: #555; } | ||
| 307 | table.blob td.linenumbers a:hover { color: #7aa2f7; } | ||
| 308 | table.ssdiff td.add { color: #9ece6a; background: #1a2e1a; } | ||
| 309 | table.ssdiff td.del { color: #f7768e; background: #2e1a1a; } | ||
| 310 | table.ssdiff td { border-right: 1px solid #333; } | ||
| 311 | table.ssdiff td.hunk { color: #7aa2f7; background: #1a1a3e; } | ||
| 312 | table.ssdiff td.head { background: #16213e; border-bottom: 1px solid #333; } | ||
| 313 | table.ssdiff td.foot { background: #16213e; border-top: 1px solid #333; } | ||
| 314 | table.ssdiff td.lineno { background: #16213e; color: #555; } | ||
| 315 | pre { color: #ccc; } | ||
| 316 | input, textarea, select { background: #222; color: #ccc; border: 1px solid #444; } | ||
| 317 | img#logo { display: none; } | ||
| 318 | </style> | ||
| 319 | ` | ||
| 320 | |||
| 321 | // CgitRC generates the /etc/cgitrc config file | ||
| 322 | func CgitRC(data map[string]string) (string, error) { | ||
| 323 | return renderTemplate("cgitrc", cgitrcTemplate, data) | ||
| 324 | } | ||
| 325 | |||
| 326 | // CgitHeader generates the cgit header HTML file (dark theme) | ||
| 327 | func CgitHeader() string { | ||
| 328 | return cgitHeaderTemplate | ||
| 329 | } | ||
| 330 | |||
| 331 | // DockerService generates a systemd unit for a Docker-based app | ||
| 332 | func DockerService(data map[string]string) (string, error) { | ||
| 333 | return renderTemplate("docker-service", dockerServiceTemplate, data) | ||
| 334 | } | ||
| 335 | |||
| 336 | // DefaultAppCaddy generates a default Caddyfile for a git-app | ||
| 337 | func DefaultAppCaddy(data map[string]string) (string, error) { | ||
| 338 | return renderTemplate("default-app-caddy", defaultAppCaddyTemplate, data) | ||
| 339 | } | ||
| 340 | |||
| 341 | // DefaultStaticCaddy generates a default Caddyfile for a git-static site | ||
| 342 | func DefaultStaticCaddy(data map[string]string) (string, error) { | ||
| 343 | return renderTemplate("default-static-caddy", defaultStaticCaddyTemplate, data) | ||
| 344 | } | ||
| 345 | |||
| 346 | func renderTemplate(name, tmplStr string, data map[string]string) (string, error) { | ||
| 347 | tmpl, err := template.New(name).Parse(tmplStr) | ||
| 348 | if err != nil { | ||
| 349 | return "", err | ||
| 350 | } | ||
| 351 | |||
| 352 | var buf bytes.Buffer | ||
| 353 | if err := tmpl.Execute(&buf, data); err != nil { | ||
| 354 | return "", err | ||
| 355 | } | ||
| 356 | |||
| 357 | return buf.String(), nil | ||
| 358 | } | ||
