support deployments

This commit is contained in:
Iris Lightshard 2023-10-20 22:46:37 -06:00
parent 8f600b21fb
commit e4ae62ad7b
Signed by: nilix
GPG key ID: F54E0D40695271D4
9 changed files with 140 additions and 15 deletions

View file

@ -37,8 +37,9 @@ Initially the user will be presented with the login screen; upon successful logi
- `Pages`: the default page, shows a list of existing pages - clicking one enables editing that page; a button is also presented for adding a new page. Each `Adapter` will provide different formatting help and can allow editable slugs/URLs or not (eg, the `EurekaAdapter` builds slugs/URLs directly from the page title).
- `Files`: provides an interface for managing statically hosted files. Files and directories can be added, moved, and deleted.
- `Build`: a simple form to build the site - build options configurable by `Adapter` are present under an accordion.
- `Configuration`: interface to the configuration for the `Adapter`. Each `Adapter` provides its own configuration interface with associated data types (currently supported: `int`, `float`, `string`, and `multilinestring`)
- `Build`: a simple form to build the site - build options configurable by `Adapter` are present under an accordion.
- `Deploy`: a _very_ simple form to either deploy the site or revert the current state to the deployed state
- `Logout`: logs the user out and returns to the login screen
## adapter interface
@ -61,6 +62,8 @@ The `Adapter` interface and associated data types can be found in the [adapter.g
- `SavePage(oldSlug, newSlug, title, content string) error`: given all the proper arguments, save a page to the backing store (eg filesystem, db)
- `DeletePage(slug string) error`: given a slug, delete the corresponding page source and possibly its generated HTML, depending on the `Adapter`
- `Build(buildOptions map[string][]string) BuildStatus`: takes a map of build option names to their values and builds the site, returning a `BuildStatus` object containing the success or failure as a boolean and the detailed status (eg, the console ouptut of the build process)
- `Deploy() DeployStatus`: executes the deployment script and returns a `DeployStatus` object, analagous to a `BuildStatus`
- `Revert() RevertStatus`: executes the reversion script and returns a `RevertStatus` object, analagous to a `BuildStatus`
## license

View file

@ -9,6 +9,9 @@ type BuildStatus struct {
Message string
}
type DeployStatus BuildStatus
type RevertStatus BuildStatus
type Page struct {
Title string
Content string
@ -38,4 +41,6 @@ type Adapter interface {
SavePage(oldSlug, newSlug, title, content string) error
DeletePage(slug string) error
Build(buildOptions map[BuildOption]string) BuildStatus
Deploy() DeployStatus
Revert() RevertStatus
}

View file

@ -29,7 +29,7 @@ func (self *EurekaAdapter) Init(cfg *Config) {
err = self.readCfg()
if err != nil {
fmt.Printf(err.Error())
fmt.Printf(err.Error())
panic("config.h is malformed!")
}
}
@ -302,6 +302,28 @@ func (self *EurekaAdapter) Build(buildOptions map[BuildOption]string) BuildStatu
}
}
func (self *EurekaAdapter) Deploy() DeployStatus {
cmd := exec.Command("./deploy.sh")
cmd.Dir = self.Root
out, err := cmd.CombinedOutput()
return DeployStatus{
Success: err == nil,
Message: string(out),
}
}
func (self *EurekaAdapter) Revert() RevertStatus {
cmd := exec.Command("./deploy.sh", "--resync")
cmd.Dir = self.Root
out, err := cmd.CombinedOutput()
return RevertStatus{
Success: err == nil,
Message: string(out),
}
}
func (self *EurekaAdapter) readCfg() error {
configPath := filepath.Join(self.Root, "config.h")
_, err := os.Stat(filepath.Join(self.Root, "config.h"))
@ -315,9 +337,9 @@ func (self *EurekaAdapter) readCfg() error {
}
fileData := strings.Replace(
strings.Replace(
string(f[:]), "/* clang-format on */", "", -1),
"/* clang-format off */", "", -1)
strings.Replace(
string(f[:]), "/* clang-format on */", "", -1),
"/* clang-format off */", "", -1)
macros := strings.Split(fileData, "#define ")[1:]
for _, macro := range macros {
@ -370,8 +392,8 @@ func (self *EurekaAdapter) readCfg() error {
}
cfgType := "int"
if strings.HasPrefix(k, "IS_") {
cfgType = "bool"
}
cfgType = "bool"
}
self.Config[ConfigOption{
Name: k,
Type: cfgType,
@ -389,11 +411,11 @@ func (self *EurekaAdapter) writeCfg() error {
defer f.Close()
f.WriteString("/* clang-format off */\n");
f.WriteString("/* clang-format off */\n")
for k, v := range self.Config {
switch k.Type {
case "int":
fallthrough
fallthrough
case "bool":
_, err := strconv.ParseInt(v, 10, 64)
if err != nil {
@ -417,7 +439,7 @@ func (self *EurekaAdapter) writeCfg() error {
fmt.Println("Unsupported config value type: " + k.Type)
}
}
f.WriteString("/* clang-format on */\n");
f.WriteString("/* clang-format on */\n")
return nil
}

View file

@ -2,8 +2,8 @@ package lfo
import (
"context"
"net/http"
core "hacklab.nilfm.cc/nirvash/archetype"
"net/http"
"strings"
)

View file

@ -1,14 +1,14 @@
package main
import (
"html/template"
"net/http"
core "hacklab.nilfm.cc/nirvash/archetype"
. "hacklab.nilfm.cc/nirvash/lfo"
"hacklab.nilfm.cc/quartzgun/indentalUserDB"
. "hacklab.nilfm.cc/quartzgun/middleware"
"hacklab.nilfm.cc/quartzgun/renderer"
"hacklab.nilfm.cc/quartzgun/router"
"html/template"
"net/http"
"os"
"path/filepath"
)
@ -161,6 +161,50 @@ func main() {
udb,
"/"))
rtr.Get(
`/deploy`,
Fortify(
Protected(
WithAdapter(
renderer.Template(
pathConcat(templateRoot, "deploy.html"),
pathConcat(templateRoot, "header.html"),
pathConcat(templateRoot, "footer.html")),
cfg.Adapter),
http.MethodGet,
udb,
"/login")))
rtr.Post(
`/deploy`,
Defend(
Protected(
WithAdapter(
renderer.Template(
pathConcat(templateRoot, "deployed.html"),
pathConcat(templateRoot, "header.html"),
pathConcat(templateRoot, "footer.html")),
cfg.Adapter),
http.MethodGet,
udb,
"/login"),
udb,
"/"))
rtr.Post(
`/revert`,
Defend(
Protected(
WithAdapter(
renderer.Template(
pathConcat(templateRoot, "reverted.html"),
pathConcat(templateRoot, "header.html"),
pathConcat(templateRoot, "footer.html")),
cfg.Adapter),
http.MethodGet,
udb,
"/login"),
udb,
"/"))
rtr.Post(
`/delete/(?P<Slug>\S+)`,
Defend(

16
templates/deploy.html Normal file
View file

@ -0,0 +1,16 @@
{{ $csrfToken := (.Context).Value "csrfToken" }}
{{ template "header" . }}
<h2>Deployment</h2>
<form class="build" method="POST" action="/deploy">
<input hidden name="csrfToken" value="{{$csrfToken}}"/>
<input type="submit" value="Deploy"/>
</form>
<form class="build" method="POST" action="/revert">
<input hidden name="csrfToken" value="{{$csrfToken}}"/>
<input type="submit" value="Revert"/>
</form>
{{ template "footer" . }}

17
templates/deployed.html Normal file
View file

@ -0,0 +1,17 @@
{{ $status := ((.Context).Value "adapter").Deploy }}
{{ template "header" . }}
{{ if ne ($status).Success true }}
<h2>Deployment Error</h2>
<span class="adapter-error"><pre>{{($status).Message}}</pre></span>
{{ else }}
<h2>Deployment Successful</h2>
<span class="adapter-success"><pre>{{($status).Message}}</pre></span>
{{ end }}
{{ template "footer" . }}

View file

@ -14,8 +14,9 @@
<ul>
<li><a href="/">Pages</a></li>
<li><a href="/file-mgr">Files</a></li>
<li><a href="/build">Build</a></li>
<li><a href="/config">Configuration</a></li>
<li><a href="/build">Build</a></li>
<li><a href="/deploy">Deployment</a></li>
<li><a href="/logout">Logout</a></li>
</ul>
</nav>

17
templates/reverted.html Normal file
View file

@ -0,0 +1,17 @@
{{ $status := ((.Context).Value "adapter").Revert }}
{{ template "header" . }}
{{ if ne ($status).Success true }}
<h2>Revert Error</h2>
<span class="adapter-error"><pre>{{($status).Message}}</pre></span>
{{ else }}
<h2>Revert Successful</h2>
<span class="adapter-success"><pre>{{($status).Message}}</pre></span>
{{ end }}
{{ template "footer" . }}