large changes
This commit is contained in:
@@ -1,9 +0,0 @@
|
|||||||
FROM alpine:3.20
|
|
||||||
|
|
||||||
ARG SITE
|
|
||||||
|
|
||||||
RUN echo "https://git.vxserver.dev/api/packages/fSD/alpine/main/fports" >> /etc/apk/repositories
|
|
||||||
&& apk update \
|
|
||||||
&& apk add --no-cache fes
|
|
||||||
|
|
||||||
ENTRYPOINT ["fes", "run", ${SITE}]
|
|
||||||
19
Makefile
Normal file
19
Makefile
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
GO ?= go
|
||||||
|
|
||||||
|
.PHONY: build deps lint install
|
||||||
|
|
||||||
|
all: build
|
||||||
|
|
||||||
|
deps:
|
||||||
|
$(GO) mod download
|
||||||
|
|
||||||
|
build: deps
|
||||||
|
$(GO) build -ldflags "-X fes/modules/version.gitCommit=$(shell git rev-parse --short HEAD)" -o fes
|
||||||
|
@echo "Fes is now built to ./fes"
|
||||||
|
|
||||||
|
lint:
|
||||||
|
$(GO) vet ./...
|
||||||
|
$(GO) fmt ./...
|
||||||
|
|
||||||
|
install:
|
||||||
|
$(GO) install fes
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
local std = require("core.std")
|
local std = require("lib.std")
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
M.__index = M
|
M.__index = M
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
local std = require("core.std")
|
local std = require("lib.std")
|
||||||
local symbol = require("core.symbol")
|
local symbol = require("lib.symbol")
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
24
main.go
24
main.go
@@ -9,15 +9,15 @@ import (
|
|||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
|
|
||||||
"fes/src/config"
|
"fes/modules/config"
|
||||||
"fes/src/doc"
|
"fes/modules/doc"
|
||||||
"fes/src/new"
|
"fes/modules/new"
|
||||||
"fes/src/server"
|
"fes/modules/server"
|
||||||
"fes/src/version"
|
"fes/modules/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed core/*
|
//go:embed lib/*
|
||||||
var core embed.FS
|
var lib embed.FS
|
||||||
|
|
||||||
//go:embed index.html
|
//go:embed index.html
|
||||||
var documentation string
|
var documentation string
|
||||||
@@ -25,7 +25,8 @@ var documentation string
|
|||||||
func init() {
|
func init() {
|
||||||
config.Port = flag.Int("p", 3000, "Set the server port")
|
config.Port = flag.Int("p", 3000, "Set the server port")
|
||||||
config.Color = flag.Bool("no-color", false, "Disable color output")
|
config.Color = flag.Bool("no-color", false, "Disable color output")
|
||||||
config.Core = core
|
config.Static = flag.Bool("static", false, "Render and save all pages.")
|
||||||
|
config.Lib = lib
|
||||||
config.Doc = documentation
|
config.Doc = documentation
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,15 +39,22 @@ func main() {
|
|||||||
fmt.Println(" run <project_dir> Start the server")
|
fmt.Println(" run <project_dir> Start the server")
|
||||||
fmt.Println("Options:")
|
fmt.Println("Options:")
|
||||||
flag.PrintDefaults()
|
flag.PrintDefaults()
|
||||||
|
fmt.Println("For bug reports, contact a developer and describe the issue. Provide the output of the `-V1` flag.")
|
||||||
}
|
}
|
||||||
|
|
||||||
showVersion := flag.Bool("version", false, "Show version and exit")
|
showVersion := flag.Bool("version", false, "Show version and exit")
|
||||||
|
showFullVersion := flag.Bool("V1", false, "Show extended version information and exit")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if *showVersion {
|
if *showVersion {
|
||||||
version.Version()
|
version.Version()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *showFullVersion {
|
||||||
|
version.FullVersion()
|
||||||
|
}
|
||||||
|
|
||||||
if *config.Color {
|
if *config.Color {
|
||||||
color.NoColor = true
|
color.NoColor = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,13 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Core embed.FS
|
var Lib embed.FS
|
||||||
var Doc string
|
var Doc string
|
||||||
var Port *int
|
var Port *int
|
||||||
var Color *bool
|
var Color *bool
|
||||||
|
var Static *bool
|
||||||
|
|
||||||
type MyConfig struct {
|
type AppConfig struct {
|
||||||
App struct {
|
App struct {
|
||||||
Name string `toml:"name"`
|
Name string `toml:"name"`
|
||||||
Version string `toml:"version"`
|
Version string `toml:"version"`
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package doc
|
package doc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fes/src/config"
|
"fes/modules/config"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -1,26 +1,20 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fes/modules/config"
|
||||||
|
"fes/modules/ui"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/pelletier/go-toml/v2"
|
||||||
|
lua "github.com/yuin/gopher-lua"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"fes/src/config"
|
|
||||||
"fes/src/ui"
|
|
||||||
|
|
||||||
"github.com/gomarkdown/markdown"
|
|
||||||
"github.com/gomarkdown/markdown/html"
|
|
||||||
"github.com/gomarkdown/markdown/parser"
|
|
||||||
"github.com/pelletier/go-toml/v2"
|
|
||||||
lua "github.com/yuin/gopher-lua"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type reqData struct {
|
type reqData struct {
|
||||||
@@ -28,42 +22,6 @@ type reqData struct {
|
|||||||
params map[string]string
|
params map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func joinBase(base, name string) string {
|
|
||||||
if base == "" {
|
|
||||||
return "/" + name
|
|
||||||
}
|
|
||||||
return base + "/" + name
|
|
||||||
}
|
|
||||||
|
|
||||||
func basePath(base string) string {
|
|
||||||
if base == "" || base == "." {
|
|
||||||
return "/"
|
|
||||||
}
|
|
||||||
return base
|
|
||||||
}
|
|
||||||
|
|
||||||
func fixMalformedToml(content string) string {
|
|
||||||
re := regexp.MustCompile(`(?m)^(\s*\w+\s*=\s*)$`)
|
|
||||||
return re.ReplaceAllStringFunc(content, func(match string) string {
|
|
||||||
parts := strings.Split(strings.TrimSpace(match), "=")
|
|
||||||
if len(parts) == 2 && strings.TrimSpace(parts[1]) == "" {
|
|
||||||
key := strings.TrimSpace(parts[0])
|
|
||||||
return key + " = \"\""
|
|
||||||
}
|
|
||||||
return match
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func markdownToHTML(mdText string) string {
|
|
||||||
extensions := parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock
|
|
||||||
p := parser.NewWithExtensions(extensions)
|
|
||||||
doc := p.Parse([]byte(mdText))
|
|
||||||
htmlFlags := html.CommonFlags | html.HrefTargetBlank
|
|
||||||
opts := html.RendererOptions{Flags: htmlFlags}
|
|
||||||
renderer := html.NewRenderer(opts)
|
|
||||||
return string(markdown.Render(doc, renderer))
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleDir(entries []os.DirEntry, dir string, routes map[string]string, base string, isStatic bool) error {
|
func handleDir(entries []os.DirEntry, dir string, routes map[string]string, base string, isStatic bool) error {
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
path := filepath.Join(dir, entry.Name())
|
path := filepath.Join(dir, entry.Name())
|
||||||
@@ -136,18 +94,18 @@ func loadIncludeModules(L *lua.LState, includeDir string) *lua.LTable {
|
|||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadLua(entry string, cfg *config.MyConfig, requestData reqData) ([]byte, error) {
|
func loadLua(entry string, cfg *config.AppConfig, requestData reqData) ([]byte, error) {
|
||||||
L := lua.NewState()
|
L := lua.NewState()
|
||||||
defer L.Close()
|
defer L.Close()
|
||||||
|
|
||||||
coreFiles, err := fs.ReadDir(config.Core, "core")
|
libFiles, err := fs.ReadDir(config.Lib, "lib")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for _, de := range coreFiles {
|
for _, de := range libFiles {
|
||||||
if de.IsDir() || !strings.HasSuffix(de.Name(), ".lua") {
|
if de.IsDir() || !strings.HasSuffix(de.Name(), ".lua") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
path := filepath.Join("core", de.Name())
|
path := filepath.Join("lib", de.Name())
|
||||||
fileData, err := config.Core.ReadFile(path)
|
fileData, err := config.Lib.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -157,7 +115,7 @@ func loadLua(entry string, cfg *config.MyConfig, requestData reqData) ([]byte, e
|
|||||||
|
|
||||||
preloadLuaModule := func(name, path string) {
|
preloadLuaModule := func(name, path string) {
|
||||||
L.PreloadModule(name, func(L *lua.LState) int {
|
L.PreloadModule(name, func(L *lua.LState) int {
|
||||||
fileData, err := config.Core.ReadFile(path)
|
fileData, err := config.Lib.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -169,24 +127,24 @@ func loadLua(entry string, cfg *config.MyConfig, requestData reqData) ([]byte, e
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
preloadLuaModule("core.std", "core/std.lua")
|
preloadLuaModule("lib.std", "lib/std.lua")
|
||||||
preloadLuaModule("core.symbol", "core/symbol.lua")
|
preloadLuaModule("lib.symbol", "lib/symbol.lua")
|
||||||
preloadLuaModule("core.util", "core/util.lua")
|
preloadLuaModule("lib.util", "lib/util.lua")
|
||||||
|
|
||||||
L.PreloadModule("fes", func(L *lua.LState) int {
|
L.PreloadModule("fes", func(L *lua.LState) int {
|
||||||
mod := L.NewTable()
|
mod := L.NewTable()
|
||||||
coreModules := []string{}
|
libModules := []string{}
|
||||||
if ents, err := fs.ReadDir(config.Core, "core"); err == nil {
|
if ents, err := fs.ReadDir(config.Lib, "lib"); err == nil {
|
||||||
for _, e := range ents {
|
for _, e := range ents {
|
||||||
if e.IsDir() || !strings.HasSuffix(e.Name(), ".lua") {
|
if e.IsDir() || !strings.HasSuffix(e.Name(), ".lua") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
coreModules = append(coreModules, strings.TrimSuffix(e.Name(), ".lua"))
|
libModules = append(libModules, strings.TrimSuffix(e.Name(), ".lua"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, modName := range coreModules {
|
for _, modName := range libModules {
|
||||||
path := filepath.Join("core", modName+".lua")
|
path := filepath.Join("lib", modName+".lua")
|
||||||
fileData, err := config.Core.ReadFile(path)
|
fileData, err := config.Lib.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -199,7 +157,7 @@ func loadLua(entry string, cfg *config.MyConfig, requestData reqData) ([]byte, e
|
|||||||
if !ok || tbl == nil {
|
if !ok || tbl == nil {
|
||||||
tbl = L.NewTable()
|
tbl = L.NewTable()
|
||||||
}
|
}
|
||||||
if modName == "builtin" {
|
if modName == "fes" {
|
||||||
tbl.ForEach(func(k, v lua.LValue) { mod.RawSet(k, v) })
|
tbl.ForEach(func(k, v lua.LValue) { mod.RawSet(k, v) })
|
||||||
} else {
|
} else {
|
||||||
mod.RawSetString(modName, tbl)
|
mod.RawSetString(modName, tbl)
|
||||||
@@ -351,7 +309,7 @@ func generateArchiveIndex(fsPath string, urlPath string) (string, error) {
|
|||||||
return b.String(), nil
|
return b.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateNotFoundData(cfg *config.MyConfig) []byte {
|
func generateNotFoundData(cfg *config.AppConfig) []byte {
|
||||||
notFoundData := []byte(`
|
notFoundData := []byte(`
|
||||||
<html>
|
<html>
|
||||||
<head><title>404 Not Found</title></head>
|
<head><title>404 Not Found</title></head>
|
||||||
@@ -397,14 +355,14 @@ func loadDirs() map[string]string {
|
|||||||
return routes
|
return routes
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseConfig() config.MyConfig {
|
func parseConfig() config.AppConfig {
|
||||||
tomlDocument, err := os.ReadFile("Fes.toml")
|
tomlDocument, err := os.ReadFile("Fes.toml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ui.Error("failed to read Fes.toml", err)
|
ui.Error("failed to read Fes.toml", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
docStr := fixMalformedToml(string(tomlDocument))
|
docStr := fixMalformedToml(string(tomlDocument))
|
||||||
var cfg config.MyConfig
|
var cfg config.AppConfig
|
||||||
if err := toml.Unmarshal([]byte(docStr), &cfg); err != nil {
|
if err := toml.Unmarshal([]byte(docStr), &cfg); err != nil {
|
||||||
ui.Warning("failed to parse Fes.toml", err)
|
ui.Warning("failed to parse Fes.toml", err)
|
||||||
cfg.App.Authors = []string{"unknown"}
|
cfg.App.Authors = []string{"unknown"}
|
||||||
45
modules/server/util.go
Normal file
45
modules/server/util.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gomarkdown/markdown"
|
||||||
|
"github.com/gomarkdown/markdown/html"
|
||||||
|
"github.com/gomarkdown/markdown/parser"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func joinBase(base, name string) string {
|
||||||
|
if base == "" {
|
||||||
|
return "/" + name
|
||||||
|
}
|
||||||
|
return base + "/" + name
|
||||||
|
}
|
||||||
|
|
||||||
|
func basePath(base string) string {
|
||||||
|
if base == "" || base == "." {
|
||||||
|
return "/"
|
||||||
|
}
|
||||||
|
return base
|
||||||
|
}
|
||||||
|
|
||||||
|
func fixMalformedToml(content string) string {
|
||||||
|
re := regexp.MustCompile(`(?m)^(\s*\w+\s*=\s*)$`)
|
||||||
|
return re.ReplaceAllStringFunc(content, func(match string) string {
|
||||||
|
parts := strings.Split(strings.TrimSpace(match), "=")
|
||||||
|
if len(parts) == 2 && strings.TrimSpace(parts[1]) == "" {
|
||||||
|
key := strings.TrimSpace(parts[0])
|
||||||
|
return key + " = \"\""
|
||||||
|
}
|
||||||
|
return match
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func markdownToHTML(mdText string) string {
|
||||||
|
extensions := parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock
|
||||||
|
p := parser.NewWithExtensions(extensions)
|
||||||
|
doc := p.Parse([]byte(mdText))
|
||||||
|
htmlFlags := html.CommonFlags | html.HrefTargetBlank
|
||||||
|
opts := html.RendererOptions{Flags: htmlFlags}
|
||||||
|
renderer := html.NewRenderer(opts)
|
||||||
|
return string(markdown.Render(doc, renderer))
|
||||||
|
}
|
||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"fes/src/config"
|
"fes/modules/config"
|
||||||
"fes/src/version"
|
"fes/modules/version"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
)
|
)
|
||||||
@@ -5,6 +5,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var gitCommit string = "devel"
|
||||||
|
|
||||||
const PROGRAM_NAME string = "fes"
|
const PROGRAM_NAME string = "fes"
|
||||||
const PROGRAM_NAME_LONG string = "fes/fSD"
|
const PROGRAM_NAME_LONG string = "fes/fSD"
|
||||||
const VERSION string = "beta"
|
const VERSION string = "beta"
|
||||||
@@ -13,3 +15,8 @@ func Version() {
|
|||||||
fmt.Printf("%s version %s\n", PROGRAM_NAME_LONG, VERSION)
|
fmt.Printf("%s version %s\n", PROGRAM_NAME_LONG, VERSION)
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FullVersion() {
|
||||||
|
fmt.Printf("%s+%s\n", VERSION, gitCommit)
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user