all repos — nirvash @ e4ae62ad7b35eb5c0065ee470908e643b064eec2

modular CMS using the quartzgun library

support deployments
Iris Lightshard nilix@nilfm.cc
PGP Signature
-----BEGIN PGP SIGNATURE-----

iHUEABYKAB0WIQR2zYvweXfSPsSU6pP1Tg1AaVJx1AUCZTNXrQAKCRD1Tg1AaVJx
1GghAP9Qa5EPs/j5OwS/M677ZkxBQIoh65utVnZ5xX/L7htilQD+Itj/QxOtId9q
VEVKR8D+u2aIG2Q2kxTdqQ52oSTTDQk=
=bnjd
-----END PGP SIGNATURE-----
commit

e4ae62ad7b35eb5c0065ee470908e643b064eec2

parent

8f600b21fbbc9885e1c09301785e63714504a99e

M README.mdREADME.md

@@ -37,8 +37,9 @@ Initially the user will be presented with the login screen; upon successful login, the application presents the navbar with these options:

- `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. +- `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. -- `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`) +- `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 @@ - `CreatePage(slug, title, content string) error`: given all the proper arguments, create a new page in the backing store (eg filesystem, db)

- `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
M archetype/adapter.goarchetype/adapter.go

@@ -9,6 +9,9 @@ Success bool

Message string } +type DeployStatus BuildStatus +type RevertStatus BuildStatus + type Page struct { Title string Content string

@@ -38,4 +41,6 @@ CreatePage(slug, title, content string) error

SavePage(oldSlug, newSlug, title, content string) error DeletePage(slug string) error Build(buildOptions map[BuildOption]string) BuildStatus + Deploy() DeployStatus + Revert() RevertStatus }
M archetype/eureka.goarchetype/eureka.go

@@ -29,7 +29,7 @@ self.Config = make(map[ConfigOption]string)

err = self.readCfg() if err != nil { - fmt.Printf(err.Error()) + fmt.Printf(err.Error()) panic("config.h is malformed!") } }

@@ -302,6 +302,28 @@ Message: string(out),

} } +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 @@ return err

} 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 @@ return err

} cfgType := "int" if strings.HasPrefix(k, "IS_") { - cfgType = "bool" - } + cfgType = "bool" + } self.Config[ConfigOption{ Name: k, Type: cfgType,

@@ -389,11 +411,11 @@ }

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 @@ default:

fmt.Println("Unsupported config value type: " + k.Type) } } - - f.WriteString("/* clang-format on */\n"); + + f.WriteString("/* clang-format on */\n") return nil }
M lfo/middleware.golfo/middleware.go

@@ -2,8 +2,8 @@ package lfo

import ( "context" - "net/http" core "hacklab.nilfm.cc/nirvash/archetype" + "net/http" "strings" )
M nirvash.gonirvash.go

@@ -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 @@ "/login"),

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(
A templates/deploy.html

@@ -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" . }}
A templates/deployed.html

@@ -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" . }}
M templates/header.htmltemplates/header.html

@@ -14,8 +14,9 @@ <nav>

<ul> <li><a href="/">Pages</a></li> <li><a href="/file-mgr">Files</a></li> + <li><a href="/config">Configuration</a></li> <li><a href="/build">Build</a></li> - <li><a href="/config">Configuration</a></li> + <li><a href="/deploy">Deployment</a></li> <li><a href="/logout">Logout</a></li> </ul> </nav>
A templates/reverted.html

@@ -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" . }}