forked from mirror/oddmu
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
faf9198edd |
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
This software is Copyright (c) 2015–2026 by Alex Schroeder.
|
||||
This software is Copyright (c) 2015–2024 by Alex Schroeder.
|
||||
|
||||
This is free software, licensed under:
|
||||
|
||||
|
||||
13
Makefile
13
Makefile
@@ -1,8 +1,7 @@
|
||||
SHELL=/bin/bash
|
||||
PREFIX=${HOME}/.local
|
||||
BINARIES=oddmu-linux-amd64.tar.gz oddmu-linux-arm64.tar.gz oddmu-darwin-amd64.tar.gz oddmu-windows-amd64.tar.gz
|
||||
|
||||
.PHONY: help build test run upload docs install priv clean dist dist-upload
|
||||
.PHONY: help build test run upload docs install priv
|
||||
|
||||
help:
|
||||
@echo Help for Oddmu
|
||||
@@ -39,13 +38,10 @@ test:
|
||||
rm -rf testdata/*
|
||||
go test -shuffle on .
|
||||
|
||||
# go install golang.org/x/lint/golint@latest
|
||||
# go install github.com/go-critic/go-critic/cmd/go-critic@latest
|
||||
check:
|
||||
golint
|
||||
go-critic check
|
||||
gocritic check
|
||||
|
||||
# go install golang.org/x/tools/cmd/goimports@latest
|
||||
fix:
|
||||
goimports -w *.go
|
||||
|
||||
@@ -69,10 +65,7 @@ clean:
|
||||
rm --force oddmu oddmu.exe oddmu-{linux,darwin,windows}-{amd64,arm64}{,.tar.gz}
|
||||
cd man && make clean
|
||||
|
||||
dist-upload: $(BINARIES)
|
||||
rsync -ai $^ sibirocobombus:alexschroeder.ch/wiki/oddmu/
|
||||
|
||||
dist: $(BINARIES)
|
||||
dist: oddmu-linux-amd64.tar.gz oddmu-linux-arm64.tar.gz oddmu-darwin-amd64.tar.gz oddmu-windows-amd64.tar.gz
|
||||
|
||||
oddmu-linux-amd64: *.go
|
||||
GOOS=linux GOARCH=amd64 go build -o $@
|
||||
|
||||
12
README.md
12
README.md
@@ -65,11 +65,6 @@ changes.
|
||||
This man page documents the "version" subcommand which you can use to
|
||||
get the installed Oddmu version.
|
||||
|
||||
[oddmu-man(1)](https://alexschroeder.ch/view/oddmu/oddmu-man.1): Oddmu
|
||||
comes with a "man" subcommand to print the manual pages. This man page
|
||||
documents the subcommand, but I guess if you can read the man page,
|
||||
you don't need the "man" subcommand.
|
||||
|
||||
Working locally:
|
||||
|
||||
[oddmu-links(1)](https://alexschroeder.ch/view/oddmu/oddmu-links.1):
|
||||
@@ -225,13 +220,6 @@ into `$HOME/.local/share/man/`.
|
||||
make install
|
||||
```
|
||||
|
||||
This installs `oddmu` into `/usr/local/bin` and the manual pages into
|
||||
`/usr/local/share/man`:
|
||||
|
||||
```sh
|
||||
sudo make install PREFIX=/usr/local
|
||||
```
|
||||
|
||||
Here's an example using [GNU Stow](https://www.gnu.org/software/stow/)
|
||||
to install it into `/usr/local/stow` in a way that allows you to
|
||||
uninstall it later:
|
||||
|
||||
16
RELEASE
16
RELEASE
@@ -1,22 +1,22 @@
|
||||
When preparing a new release
|
||||
----------------------------
|
||||
|
||||
1. run tests
|
||||
1. Run tests
|
||||
|
||||
2. update man/oddmu-releases.7.txt
|
||||
2. Update man/oddmu-releases.7.txt
|
||||
- add missing items
|
||||
- change "(unreleased)"
|
||||
|
||||
3. check copyright year in LICENSE
|
||||
3. make docs
|
||||
|
||||
4. make docs
|
||||
4. Make sure all files are checked in
|
||||
|
||||
5. make sure all files are checked in
|
||||
5. Tag the release and push the tag to all remotes
|
||||
|
||||
6. tag the release and push the tag to the remote
|
||||
6. cd man && make upload
|
||||
|
||||
7. make dist
|
||||
|
||||
8. make dist-upload
|
||||
8. create a new release at https://github.com/kensanata/oddmu/releases
|
||||
|
||||
9. cd man && make upload
|
||||
9. upload the four .tar.gz binaries to the GitHub release
|
||||
|
||||
11
feed.go
11
feed.go
@@ -16,9 +16,7 @@ import (
|
||||
type dateSource int
|
||||
|
||||
const (
|
||||
// ModTime means that the feed item date is based on the page file's last modification date.
|
||||
ModTime dateSource = iota
|
||||
// URL means that the feed item date is based on the ISO date contained in the page name.
|
||||
URL
|
||||
)
|
||||
|
||||
@@ -69,12 +67,11 @@ func feed(p *Page, ti time.Time, from, n int, source dateSource) *Feed {
|
||||
feed.Date = ti.Format(time.RFC1123Z)
|
||||
feed.From = from
|
||||
feed.N = n
|
||||
switch {
|
||||
case n == 0:
|
||||
if n == 0 {
|
||||
feed.Complete = true
|
||||
case from > n:
|
||||
} else if from > n {
|
||||
feed.Prev = from - n
|
||||
default:
|
||||
} else {
|
||||
year, err := p.BlogYear()
|
||||
if err == nil && p.ArchiveExists(year+1) {
|
||||
feed.PrevYear = year + 1
|
||||
@@ -153,7 +150,7 @@ func (p *Page) Date(source dateSource) (time.Time, error) {
|
||||
return p.ModTime()
|
||||
}
|
||||
|
||||
// BlogYear returns the current year if the page name is "index". If the page name is a number such as "2026" then
|
||||
// BLogYear returns the current year if the page name is "index". If the page name is a number such as "2026" then
|
||||
// this is parsed as an integer and returned.
|
||||
func (p *Page) BlogYear() (int, error) {
|
||||
name := path.Base(p.Name)
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
<atom:link href="https://example.org/view/{{.Dir}}{{.PrevYear}}.rss?n={{.N}}" rel="previous" type="application/rss+xml"/>{{end}}{{if .Next}}
|
||||
<atom:link href="https://example.org/view/{{.Path}}.rss?from={{.Next}}&n={{.N}}" rel="next" type="application/rss+xml"/>{{end}}{{if .NextYear}}
|
||||
<atom:link href="https://example.org/view/{{.Dir}}{{.NextYear}}.rss?n={{.N}}" rel="next" type="application/rss+xml"/>{{end}}{{if .Complete}}
|
||||
<generator>Oddμ https://src.alexschroeder.ch/oddmu.git/</generator>
|
||||
<fh:complete/>{{end}}
|
||||
<description>This is the digital garden of Your Name.</description>
|
||||
<image>
|
||||
|
||||
@@ -78,7 +78,7 @@ func (p *Page) printFeed(w io.Writer, ti time.Time) subcommands.ExitStatus {
|
||||
fmt.Fprintf(os.Stderr, "Cannot write prefix: %s\n", err)
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
initTemplates()
|
||||
loadTemplates()
|
||||
templates.RLock()
|
||||
defer templates.RUnlock()
|
||||
err = templates.template["feed.html"].Execute(w, f)
|
||||
|
||||
41
go.mod
41
go.mod
@@ -1,40 +1,41 @@
|
||||
module src.alexschroeder.ch/oddmu
|
||||
|
||||
go 1.25
|
||||
go 1.22
|
||||
|
||||
toolchain go1.22.3
|
||||
|
||||
require (
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/edwvee/exiffix v0.0.0-20240229113213-0dbb146775be
|
||||
github.com/fsnotify/fsnotify v1.9.0
|
||||
github.com/gabriel-vasile/mimetype v1.4.13
|
||||
github.com/gen2brain/heic v0.4.9
|
||||
github.com/gen2brain/webp v0.5.5
|
||||
github.com/gomarkdown/markdown v0.0.0-20250810172220-2e2c11897d1a
|
||||
github.com/edwvee/exiffix v0.0.0-20210922235313-0f6cbda5e58f
|
||||
github.com/fsnotify/fsnotify v1.7.0
|
||||
github.com/gabriel-vasile/mimetype v1.4.3
|
||||
github.com/gen2brain/heic v0.3.1
|
||||
github.com/gen2brain/webp v0.5.2
|
||||
github.com/gomarkdown/markdown v0.0.0-20250207164621-7a1f277a159e
|
||||
github.com/google/subcommands v1.2.0
|
||||
github.com/hexops/gotextdiff v1.0.3
|
||||
github.com/microcosm-cc/bluemonday v1.0.27
|
||||
github.com/microcosm-cc/bluemonday v1.0.26
|
||||
github.com/muesli/reflow v0.3.0
|
||||
github.com/pemistahl/lingua-go v1.4.0
|
||||
github.com/sergi/go-diff v1.4.0
|
||||
github.com/sergi/go-diff v1.3.1
|
||||
github.com/stretchr/testify v1.8.4
|
||||
golang.org/x/exp v0.0.0-20260112195511-716be5621a96
|
||||
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/aymerick/douceur v0.2.0 // indirect
|
||||
github.com/clipperhouse/stringish v0.1.1 // indirect
|
||||
github.com/clipperhouse/uax29/v2 v2.5.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/ebitengine/purego v0.9.1 // indirect
|
||||
github.com/ebitengine/purego v0.8.1 // indirect
|
||||
github.com/gorilla/css v1.0.1 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.19 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/rivo/uniseg v0.4.6 // indirect
|
||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/tetratelabs/wazero v1.11.0 // indirect
|
||||
golang.org/x/image v0.35.0 // indirect
|
||||
golang.org/x/net v0.49.0 // indirect
|
||||
golang.org/x/sys v0.40.0 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
github.com/tetratelabs/wazero v1.8.1 // indirect
|
||||
golang.org/x/image v0.15.0 // indirect
|
||||
golang.org/x/net v0.20.0 // indirect
|
||||
golang.org/x/sys v0.21.0 // indirect
|
||||
google.golang.org/protobuf v1.32.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
78
go.sum
78
go.sum
@@ -1,30 +1,26 @@
|
||||
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
||||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||
github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs=
|
||||
github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA=
|
||||
github.com/clipperhouse/uax29/v2 v2.5.0 h1:x7T0T4eTHDONxFJsL94uKNKPHrclyFI0lm7+w94cO8U=
|
||||
github.com/clipperhouse/uax29/v2 v2.5.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A=
|
||||
github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/edwvee/exiffix v0.0.0-20240229113213-0dbb146775be h1:FNPYI8/ifKGW7kdBdlogyGGaPXZmOXBbV1uz4Amr3s0=
|
||||
github.com/edwvee/exiffix v0.0.0-20240229113213-0dbb146775be/go.mod h1:G3dK5MziX9e4jUa8PWjowCOPCcyQwxsZ5a0oYA73280=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/gen2brain/heic v0.4.9 h1:sHM7kjMV2+AlrSfYNsJiD0NrqAJqIMWAOqMSZ0HXrU8=
|
||||
github.com/gen2brain/heic v0.4.9/go.mod h1:0/0SrVQnUhOA3ekFY5/lApZYniF/DsgS3g9COWe83dM=
|
||||
github.com/gen2brain/webp v0.5.5 h1:MvQR75yIPU/9nSqYT5h13k4URaJK3gf9tgz/ksRbyEg=
|
||||
github.com/gen2brain/webp v0.5.5/go.mod h1:xOSMzp4aROt2KFW++9qcK/RBTOVC2S9tJG66ip/9Oc0=
|
||||
github.com/gomarkdown/markdown v0.0.0-20250810172220-2e2c11897d1a h1:l7A0loSszR5zHd/qK53ZIHMO8b3bBSmENnQ6eKnUT0A=
|
||||
github.com/gomarkdown/markdown v0.0.0-20250810172220-2e2c11897d1a/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/ebitengine/purego v0.8.1 h1:sdRKd6plj7KYW33EH5As6YKfe8m9zbN9JMrOjNVF/BE=
|
||||
github.com/ebitengine/purego v0.8.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/edwvee/exiffix v0.0.0-20210922235313-0f6cbda5e58f h1:RMnUwTnNR070mFAEIoqMYjNirHj8i0h79VXTYyBCyVA=
|
||||
github.com/edwvee/exiffix v0.0.0-20210922235313-0f6cbda5e58f/go.mod h1:KoE3Ti1qbQXCb3s/XGj0yApHnbnNnn1bXTtB5Auq/Vc=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||
github.com/gen2brain/heic v0.3.1 h1:ClY5YTdXdIanw7pe9ZVUM9XcsqH6CCCa5CZBlm58qOs=
|
||||
github.com/gen2brain/heic v0.3.1/go.mod h1:m2sVIf02O7wfO8mJm+PvE91lnq4QYJy2hseUon7So10=
|
||||
github.com/gen2brain/webp v0.5.2 h1:aYdjbU/2L98m+bqUdkYMOIY93YC+EN3HuZLMaqgMD9U=
|
||||
github.com/gen2brain/webp v0.5.2/go.mod h1:Nb3xO5sy6MeUAHhru9H3GT7nlOQO5dKRNNlE92CZrJw=
|
||||
github.com/gomarkdown/markdown v0.0.0-20250207164621-7a1f277a159e h1:ESHlT0RVZphh4JGBz49I5R6nTdC8Qyc08vU25GQHzzQ=
|
||||
github.com/gomarkdown/markdown v0.0.0-20250207164621-7a1f277a159e/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=
|
||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
|
||||
@@ -37,10 +33,10 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
|
||||
github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
|
||||
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
|
||||
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58=
|
||||
github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs=
|
||||
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
|
||||
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
|
||||
github.com/pemistahl/lingua-go v1.4.0 h1:ifYhthrlW7iO4icdubwlduYnmwU37V1sbNrwhKBR4rM=
|
||||
@@ -49,30 +45,32 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.6 h1:Sovz9sDSwbOz9tgUy8JpT+KgCkPYJEN/oYzlJiYTNLg=
|
||||
github.com/rivo/uniseg v0.4.6/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc=
|
||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
|
||||
github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
|
||||
github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
|
||||
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
||||
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/tetratelabs/wazero v1.11.0 h1:+gKemEuKCTevU4d7ZTzlsvgd1uaToIDtlQlmNbwqYhA=
|
||||
github.com/tetratelabs/wazero v1.11.0/go.mod h1:eV28rsN8Q+xwjogd7f4/Pp4xFxO7uOGbLcD/LzB1wiU=
|
||||
golang.org/x/exp v0.0.0-20260112195511-716be5621a96 h1:Z/6YuSHTLOHfNFdb8zVZomZr7cqNgTJvA8+Qz75D8gU=
|
||||
golang.org/x/exp v0.0.0-20260112195511-716be5621a96/go.mod h1:nzimsREAkjBCIEFtHiYkrJyT+2uy9YZJB7H1k68CXZU=
|
||||
github.com/tetratelabs/wazero v1.8.1 h1:NrcgVbWfkWvVc4UtT4LRLDf91PsOzDzefMdwhLfA550=
|
||||
github.com/tetratelabs/wazero v1.8.1/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs=
|
||||
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
|
||||
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.35.0 h1:LKjiHdgMtO8z7Fh18nGY6KDcoEtVfsgLDPeLyguqb7I=
|
||||
golang.org/x/image v0.35.0/go.mod h1:MwPLTVgvxSASsxdLzKrl8BRFuyqMyGhLwmC+TO1Sybk=
|
||||
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
|
||||
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
|
||||
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
|
||||
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
|
||||
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
|
||||
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.nh
|
||||
.ad l
|
||||
.\" Begin generated content:
|
||||
.TH "ODDMU-APACHE" "5" "2026-01-29"
|
||||
.TH "ODDMU-APACHE" "5" "2025-07-16"
|
||||
.PP
|
||||
.SH NAME
|
||||
.PP
|
||||
@@ -48,7 +48,7 @@ ServerAdmin alex@alexschroeder\&.ch
|
||||
<VirtualHost *:443>
|
||||
ServerName transjovian\&.org
|
||||
SSLEngine on
|
||||
ProxyPassMatch "^/((view|preview|diff|edit|save|add|append|upload|drop|search|archive)/(\&.*)|sitemap.xml)?$"
|
||||
ProxyPassMatch "^/((view|preview|diff|edit|save|add|append|upload|drop|search|archive)/(\&.*))?$"
|
||||
"http://localhost:8080/$1"
|
||||
</VirtualHost>
|
||||
.fi
|
||||
@@ -126,13 +126,13 @@ ServerAdmin alex@alexschroeder\&.ch
|
||||
ServerName transjovian\&.org
|
||||
ProxyPassMatch "^/((view|diff|search|archive)/(\&.*))?$"
|
||||
"http://localhost:8080/$1"
|
||||
RedirectMatch "^/((edit|save|add|append|upload|drop)/(\&.*)|sitemap.xml)?$"
|
||||
RedirectMatch "^/((edit|save|add|append|upload|drop)/(\&.*))?$"
|
||||
"https://transjovian\&.org/$1"
|
||||
</VirtualHost>
|
||||
<VirtualHost *:443>
|
||||
ServerName transjovian\&.org
|
||||
SSLEngine on
|
||||
ProxyPassMatch "^/((view|preview|diff|edit|save|add|append|upload|drop|search|archive)/(\&.*)|sitemap.xml)?$"
|
||||
ProxyPassMatch "^/((view|preview|diff|edit|save|add|append|upload|drop|search|archive)/(\&.*))?$"
|
||||
"http://localhost:8080/$1"
|
||||
</VirtualHost>
|
||||
.fi
|
||||
@@ -170,7 +170,7 @@ In that case, you need to use the ProxyPassMatch directive.\&
|
||||
.PP
|
||||
.nf
|
||||
.RS 4
|
||||
ProxyPassMatch "^/((view|preview|diff|edit|save|add|append|upload|drop|search|archive)/(\&.*)|sitemap.xml)?$"
|
||||
ProxyPassMatch "^/((view|preview|diff|edit|save|add|append|upload|drop|search|archive)/(\&.*))?$"
|
||||
"unix:/run/oddmu/oddmu\&.sock|http://localhost/$1"
|
||||
.fi
|
||||
.RE
|
||||
@@ -189,7 +189,7 @@ A workaround is to add the redirect manually and drop the question-mark:
|
||||
.nf
|
||||
.RS 4
|
||||
RedirectMatch "^/$" "/view/index"
|
||||
ProxyPassMatch "^/((view|preview|diff|edit|save|add|append|upload|drop|search|archive)/(\&.*)|sitemap.xml)$"
|
||||
ProxyPassMatch "^/((view|preview|diff|edit|save|add|append|upload|drop|search|archive)/(\&.*))$"
|
||||
"unix:/run/oddmu/oddmu\&.sock|http://localhost/$1"
|
||||
.fi
|
||||
.RE
|
||||
@@ -248,74 +248,12 @@ to your "<VirtualHost *:443>" section:
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
.SS Actual usernames and passwords for authentication
|
||||
.PP
|
||||
On a community server where the users have accounts, wiki editing can be limited
|
||||
to the system'\&s users.\&
|
||||
.PP
|
||||
In order to do this, install the \fBmod-authnz-external\fR module for Apache and the
|
||||
\fBpwauth\fR binary.\& The module allows the password checking normally done inside
|
||||
Apache to be done by an separate external program running outside of Apache.\&
|
||||
.PP
|
||||
Here'\&s an example configuration:
|
||||
.PP
|
||||
.nf
|
||||
.RS 4
|
||||
AddExternalAuth pwauth /usr/sbin/pwauth
|
||||
SetExternalAuthMethod pwauth pipe
|
||||
|
||||
<LocationMatch "^/(edit|save|add|append|upload|drop)/">
|
||||
AuthType Basic
|
||||
AuthName "Password Required"
|
||||
AuthBasicProvider external
|
||||
AuthExternal pwauth
|
||||
Require valid-user
|
||||
</LocationMatch>
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
.SS Different logins for different access rights
|
||||
.PP
|
||||
What if you have a site with various subdirectories and each subdirectory is for
|
||||
a different group of friends?\& You can set this up using your webserver.\& One way
|
||||
to do this is to require specific usernames (which must have a password in the
|
||||
password file mentioned above.\&
|
||||
.PP
|
||||
This requires a valid login by the user "alex" or "berta":
|
||||
.PP
|
||||
.nf
|
||||
.RS 4
|
||||
<LocationMatch "^/(edit|save|add|append|upload|drop)/intetebi/">
|
||||
Require user alex berta
|
||||
</LocationMatch>
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
.SS Private wikis
|
||||
.PP
|
||||
Based on the above, you can prevent people from \fIreading\fR the wiki.\& The location
|
||||
must cover all the URLs in order to protect everything.\&
|
||||
.PP
|
||||
.nf
|
||||
.RS 4
|
||||
<Location />
|
||||
AuthType Basic
|
||||
AuthName "Password Required"
|
||||
AuthUserFile /home/oddmu/\&.htpasswd
|
||||
Require valid-user
|
||||
</Location>
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
.SS Subdirectories as separate sites
|
||||
.PP
|
||||
The way Oddmu handles subdirectories is that all files and directories are
|
||||
visible, except for "hidden" files and directories (whose name starts with a
|
||||
period).\& Specifically, do not rely on Apache to hide locations in subdirectories
|
||||
from public view.\& Search reveals the existence of these pages and produces an
|
||||
extract, even if users cannot follow the links.\& The Sitemap lists all pages,
|
||||
including subdirectories.\& Archive links pack all the subdirectories, including
|
||||
locations you may have hidden from view using Apache.\&
|
||||
extract, even if users cannot follow the links.\& Archive links pack all the
|
||||
subdirectories, including locations you may have hidden from view using Apache.\&
|
||||
.PP
|
||||
If you to treat subdirectories as separate sites, you need to set the
|
||||
environment variable ODDMU_FILTER to a regular expression matching the those
|
||||
@@ -400,13 +338,46 @@ In this case, "/css/oddmu-2023.\&css" would be the name of your stylesheet.\& If
|
||||
your document root is "/home/oddmu", then the filename of your stylesheet would
|
||||
have to be "/home/oddmu/css/oddmu-2023.\&css" for this to work.\&
|
||||
.PP
|
||||
.SS Different logins for different access rights
|
||||
.PP
|
||||
What if you have a site with various subdirectories and each subdirectory is for
|
||||
a different group of friends?\& You can set this up using your webserver.\& One way
|
||||
to do this is to require specific usernames (which must have a password in the
|
||||
password file mentioned above.\&
|
||||
.PP
|
||||
This requires a valid login by the user "alex" or "berta":
|
||||
.PP
|
||||
.nf
|
||||
.RS 4
|
||||
<LocationMatch "^/(edit|save|add|append|upload|drop)/intetebi/">
|
||||
Require user alex berta
|
||||
</LocationMatch>
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
.SS Private wikis
|
||||
.PP
|
||||
Based on the above, you can prevent people from \fIreading\fR the wiki.\& The location
|
||||
must cover all the URLs in order to protect everything.\&
|
||||
.PP
|
||||
.nf
|
||||
.RS 4
|
||||
<Location />
|
||||
AuthType Basic
|
||||
AuthName "Password Required"
|
||||
AuthUserFile /home/oddmu/\&.htpasswd
|
||||
Require valid-user
|
||||
</Location>
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
.SS Virtual hosting
|
||||
.PP
|
||||
Virtual hosting in this context means that the program serves two different
|
||||
sites for two different domains from the same machine.\& Oddmu doesn'\&t support
|
||||
that, but your webserver does.\& Therefore, start an Oddmu instance for every
|
||||
domain name, each listening on a different port.\& Then set up your web server
|
||||
such that every domain proxies for a different Oddmu instance.\&
|
||||
such that ever domain acts as a reverse proxy to a different Oddmu instance.\&
|
||||
.PP
|
||||
.SH SEE ALSO
|
||||
.PP
|
||||
|
||||
@@ -209,61 +209,6 @@ to your "<VirtualHost \*:443>" section:
|
||||
</LocationMatch>
|
||||
```
|
||||
|
||||
## Actual usernames and passwords for authentication
|
||||
|
||||
On a community server where the users have accounts, wiki editing can be limited
|
||||
to the system's users.
|
||||
|
||||
In order to do this, install the *mod-authnz-external* module for Apache and the
|
||||
*pwauth* binary. The module allows the password checking normally done inside
|
||||
Apache to be done by an separate external program running outside of Apache.
|
||||
|
||||
Here's an example configuration:
|
||||
|
||||
```
|
||||
AddExternalAuth pwauth /usr/sbin/pwauth
|
||||
SetExternalAuthMethod pwauth pipe
|
||||
|
||||
<LocationMatch "^/(edit|save|add|append|upload|drop)/">
|
||||
AuthType Basic
|
||||
AuthName "Password Required"
|
||||
AuthBasicProvider external
|
||||
AuthExternal pwauth
|
||||
Require valid-user
|
||||
</LocationMatch>
|
||||
```
|
||||
|
||||
## Different logins for different access rights
|
||||
|
||||
What if you have a site with various subdirectories and each subdirectory is for
|
||||
a different group of friends? You can set this up using your webserver. One way
|
||||
to do this is to require specific usernames (which must have a password in the
|
||||
password file mentioned above.
|
||||
|
||||
This requires a valid login by the user "alex" or "berta":
|
||||
|
||||
```
|
||||
<LocationMatch "^/(edit|save|add|append|upload|drop)/intetebi/">
|
||||
Require user alex berta
|
||||
</LocationMatch>
|
||||
```
|
||||
|
||||
## Private wikis
|
||||
|
||||
Based on the above, you can prevent people from _reading_ the wiki. The location
|
||||
must cover all the URLs in order to protect everything.
|
||||
|
||||
```
|
||||
<Location />
|
||||
AuthType Basic
|
||||
AuthName "Password Required"
|
||||
AuthUserFile /home/oddmu/.htpasswd
|
||||
Require valid-user
|
||||
</Location>
|
||||
```
|
||||
|
||||
## Subdirectories as separate sites
|
||||
|
||||
The way Oddmu handles subdirectories is that all files and directories are
|
||||
visible, except for "hidden" files and directories (whose name starts with a
|
||||
period). Specifically, do not rely on Apache to hide locations in subdirectories
|
||||
@@ -347,13 +292,42 @@ In this case, "/css/oddmu-2023.css" would be the name of your stylesheet. If
|
||||
your document root is "/home/oddmu", then the filename of your stylesheet would
|
||||
have to be "/home/oddmu/css/oddmu-2023.css" for this to work.
|
||||
|
||||
## Different logins for different access rights
|
||||
|
||||
What if you have a site with various subdirectories and each subdirectory is for
|
||||
a different group of friends? You can set this up using your webserver. One way
|
||||
to do this is to require specific usernames (which must have a password in the
|
||||
password file mentioned above.
|
||||
|
||||
This requires a valid login by the user "alex" or "berta":
|
||||
|
||||
```
|
||||
<LocationMatch "^/(edit|save|add|append|upload|drop)/intetebi/">
|
||||
Require user alex berta
|
||||
</LocationMatch>
|
||||
```
|
||||
|
||||
## Private wikis
|
||||
|
||||
Based on the above, you can prevent people from _reading_ the wiki. The location
|
||||
must cover all the URLs in order to protect everything.
|
||||
|
||||
```
|
||||
<Location />
|
||||
AuthType Basic
|
||||
AuthName "Password Required"
|
||||
AuthUserFile /home/oddmu/.htpasswd
|
||||
Require valid-user
|
||||
</Location>
|
||||
```
|
||||
|
||||
## Virtual hosting
|
||||
|
||||
Virtual hosting in this context means that the program serves two different
|
||||
sites for two different domains from the same machine. Oddmu doesn't support
|
||||
that, but your webserver does. Therefore, start an Oddmu instance for every
|
||||
domain name, each listening on a different port. Then set up your web server
|
||||
such that every domain proxies for a different Oddmu instance.
|
||||
such that ever domain acts as a reverse proxy to a different Oddmu instance.
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.nh
|
||||
.ad l
|
||||
.\" Begin generated content:
|
||||
.TH "ODDMU-EXPORT" "1" "2026-01-03"
|
||||
.TH "ODDMU-EXPORT" "1" "2025-08-31"
|
||||
.PP
|
||||
.SH NAME
|
||||
.PP
|
||||
@@ -31,8 +31,7 @@ XML preamble is printed and appropriate escaping rules are used.\&
|
||||
.PP
|
||||
.SH FILES
|
||||
.PP
|
||||
By default, the export uses the feed template ("feed.\&html") in the current
|
||||
directory.\&
|
||||
By default, the export uses the \fB\fRfeed.\&html\fB\fR template in the current directory.\&
|
||||
.PP
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
|
||||
@@ -24,8 +24,7 @@ XML preamble is printed and appropriate escaping rules are used.
|
||||
|
||||
# FILES
|
||||
|
||||
By default, the export uses the feed template ("feed.html") in the current
|
||||
directory.
|
||||
By default, the export uses the **feed.html** template in the current directory.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.nh
|
||||
.ad l
|
||||
.\" Begin generated content:
|
||||
.TH "ODDMU-FILTER" "7" "2026-01-03"
|
||||
.TH "ODDMU-FILTER" "7" "2024-09-30"
|
||||
.PP
|
||||
.SH NAME
|
||||
.PP
|
||||
@@ -13,13 +13,13 @@ oddmu-filter - keeping subdirectories separate
|
||||
.PP
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
There are actions such as producing the sitemap, searching and archiving that
|
||||
act on multiple pages, not just a single page.\& These actions walk the directory
|
||||
tree, including all subdirectories.\& In some cases, this is not desirable.\&
|
||||
There are actions such as searching and archiving that act on multiple pages,
|
||||
not just a single page.\& These actions walk the directory tree, including all
|
||||
subdirectories.\& In some cases, this is not desirable.\&
|
||||
.PP
|
||||
Sometimes, subdirectories are separate sites, like the sites of other projects
|
||||
or different people.\& Depending on how you think about it, you might not want to
|
||||
include those "sites" in searches, sitemaps or archives of the whole site.\&
|
||||
include those "sites" in searches or archives of the whole site.\&
|
||||
.PP
|
||||
Since directory tree actions always start in the directory the visitor is
|
||||
currently looking at, directory tree actions starting in a "separate site"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.nh
|
||||
.ad l
|
||||
.\" Begin generated content:
|
||||
.TH "ODDMU-HTML" "1" "2026-01-03"
|
||||
.TH "ODDMU-HTML" "1" "2025-04-05"
|
||||
.PP
|
||||
.SH NAME
|
||||
.PP
|
||||
@@ -13,7 +13,7 @@ oddmu-html - render Oddmu page HTML
|
||||
.PP
|
||||
.SH SYNOPSIS
|
||||
.PP
|
||||
\fBoddmu html\fR [\fB-template\fR \fItemplate-name\fR] \fIpage-name\fR
|
||||
\fBoddmu html\fR [\fB\fR-template\fB\fR \fItemplate-name\fR] \fIpage-name\fR
|
||||
.PP
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
@@ -23,7 +23,7 @@ name if you want to read Markdown from \fBstdin\fR.\&
|
||||
.PP
|
||||
.SH OPTIONS
|
||||
.PP
|
||||
\fB-template\fR \fItemplate-name\fR
|
||||
\fB\fR-template\fB\fR \fItemplate-name\fR
|
||||
.RS 4
|
||||
Use the given template to render the page.\& Without this, the HTML lacks
|
||||
html and body tags.\& The only two options that make sense are "view.\&html"
|
||||
|
||||
@@ -6,7 +6,7 @@ oddmu-html - render Oddmu page HTML
|
||||
|
||||
# SYNOPSIS
|
||||
|
||||
*oddmu html* [*-template* _template-name_] _page-name_
|
||||
*oddmu html* [**-template** _template-name_] _page-name_
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
@@ -16,7 +16,7 @@ name if you want to read Markdown from *stdin*.
|
||||
|
||||
# OPTIONS
|
||||
|
||||
*-template* _template-name_
|
||||
**-template** _template-name_
|
||||
Use the given template to render the page. Without this, the HTML lacks
|
||||
html and body tags. The only two options that make sense are "view.html"
|
||||
and "static.html".
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
.\" Generated by scdoc 1.11.3
|
||||
.\" Complete documentation for this program is not available as a GNU info page
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.nh
|
||||
.ad l
|
||||
.\" Begin generated content:
|
||||
.TH "ODDMU-MAN" "1" "2026-02-11"
|
||||
.PP
|
||||
.SH NAME
|
||||
.PP
|
||||
oddmu-man - print the manual pages
|
||||
.PP
|
||||
.SH SYNOPSIS
|
||||
.PP
|
||||
\fBoddmu man\fR
|
||||
.PP
|
||||
\fBoddmu man\fR \fItopic\fR
|
||||
.PP
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
The "man" subcommand lists the topics available or prints the manual page for
|
||||
the given topic.\&
|
||||
.PP
|
||||
Example:
|
||||
.PP
|
||||
.nf
|
||||
.RS 4
|
||||
oddmu man apache
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
.SH SEE ALSO
|
||||
.PP
|
||||
\fIoddmu\fR(1)
|
||||
.PP
|
||||
.SH AUTHORS
|
||||
.PP
|
||||
Maintained by Alex Schroeder <alex@gnu.\&org>.\&
|
||||
@@ -1,30 +0,0 @@
|
||||
ODDMU-MAN(1)
|
||||
|
||||
# NAME
|
||||
|
||||
oddmu-man - print the manual pages
|
||||
|
||||
# SYNOPSIS
|
||||
|
||||
*oddmu man*
|
||||
|
||||
*oddmu man* _topic_
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The "man" subcommand lists the topics available or prints the manual page for
|
||||
the given topic.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
oddmu man apache
|
||||
```
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
_oddmu_(1)
|
||||
|
||||
# AUTHORS
|
||||
|
||||
Maintained by Alex Schroeder <alex@gnu.org>.
|
||||
@@ -5,7 +5,7 @@
|
||||
.nh
|
||||
.ad l
|
||||
.\" Begin generated content:
|
||||
.TH "ODDMU-NGINX" "5" "2026-01-03"
|
||||
.TH "ODDMU-NGINX" "5" "2025-07-16"
|
||||
.PP
|
||||
.SH NAME
|
||||
.PP
|
||||
@@ -27,7 +27,7 @@ section.\& Add a new \fIlocation\fR section after the existing \fIlocation\fR se
|
||||
.PP
|
||||
.nf
|
||||
.RS 4
|
||||
location ~ ^/(view|preview|diff|edit|save|add|append|upload|drop|search|sitemap|archive)/ {
|
||||
location ~ ^/(view|preview|diff|edit|save|add|append|upload|drop|search|archive)/ {
|
||||
proxy_pass http://localhost:8080;
|
||||
}
|
||||
.fi
|
||||
@@ -97,7 +97,7 @@ server configuration.\& On a Debian system, that'\&d be in
|
||||
.PP
|
||||
.nf
|
||||
.RS 4
|
||||
location ~ ^/(view|preview|diff|edit|save|add|append|upload|drop|search|sitemap|archive)/ {
|
||||
location ~ ^/(view|preview|diff|edit|save|add|append|upload|drop|search|archive)/ {
|
||||
proxy_pass http://unix:/run/oddmu/oddmu\&.sock:;
|
||||
}
|
||||
.fi
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
.\" Generated by scdoc 1.11.3
|
||||
.\" Generated by scdoc 1.11.4
|
||||
.\" Complete documentation for this program is not available as a GNU info page
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.nh
|
||||
.ad l
|
||||
.\" Begin generated content:
|
||||
.TH "ODDMU-RELEASES" "7" "2026-02-11"
|
||||
.TH "ODDMU-RELEASES" "7" "2026-01-01"
|
||||
.PP
|
||||
.SH NAME
|
||||
.PP
|
||||
@@ -15,18 +15,9 @@ oddmu-releases - what'\&s new?\&
|
||||
.PP
|
||||
This page lists user-visible features and template changes to consider.\&
|
||||
.PP
|
||||
.SS 1.21 (unreleased)
|
||||
.SS 1.20 (unreleased)
|
||||
.PP
|
||||
Write any missing templates when Oddmu starts up.\&
|
||||
.PP
|
||||
Add man subcommand to print manual pages.\&
|
||||
.PP
|
||||
Both of these features make it possible to distribute just the binary.\&
|
||||
.PP
|
||||
.SS 1.20 (2026)
|
||||
.PP
|
||||
Add -shrink and -glob options to the \fIstatic\fR subcommand.\& See \fIoddmu-static\fR(1)
|
||||
for more.\&
|
||||
Add -shrink and -glob options to the \fIstatic\fR subcommand.\&
|
||||
.PP
|
||||
Some tools were used to check the code (goimports, golint, gocritic).\&
|
||||
Unfortunately, the resulting changes necessitates a change in the templates
|
||||
@@ -49,8 +40,8 @@ faster than any of the feeds for hashtag pages, presumably, an extra features
|
||||
was added: on the first and on the last page of the feed, a link to the next or
|
||||
the previous year is added, if such a page exists.\& This works if at beginning of
|
||||
every year, you move all the entries on to a dedicated year page.\& You need to
|
||||
add the necessary links to the "feed.\&html" template.\& See \fIoddmu-templates\fR(5)
|
||||
for more.\&
|
||||
add the necessary links to the feed template ("feed.\&html").\& See
|
||||
\fIoddmu-templates\fR(5) for more.\&
|
||||
.PP
|
||||
Example:
|
||||
.PP
|
||||
@@ -71,11 +62,6 @@ Example:
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
Add \fIsitemap\fR subcommand and handler.\& See \fIoddmu-sitemap\fR(1) for more.\& If you
|
||||
want to make it available for search engines and the like, you most likely have
|
||||
to add it to your proxy configuration.\& See \fIoddmu-apache\fR(5) or \fIoddmu-nginx\fR(5)
|
||||
for more.\&
|
||||
.PP
|
||||
.SS 1.19 (2025)
|
||||
.PP
|
||||
Add \fIfeed\fR subcommand.\& This produces a "complete" feed.\&
|
||||
@@ -85,8 +71,8 @@ Add feed pagination for the \fIfeed\fR action.\& This produces a "paginated" fee
|
||||
See RFC 5005 for more information.\&
|
||||
.PP
|
||||
If you like the idea of feed pagination (not a given since that also helps bots
|
||||
scrape your site!\&) you need to add the necessary links to the "feed.\&html"
|
||||
template.\& See \fIoddmu-templates\fR(5) for more.\&
|
||||
scrape your site!\&) you need to add the necessary links to the feed template
|
||||
("feed.\&html").\& See \fIoddmu-templates\fR(5) for more.\&
|
||||
.PP
|
||||
Example, adding the feed history namespace:
|
||||
.PP
|
||||
@@ -118,15 +104,16 @@ In an effort to remove features that can be handled by the web server, the
|
||||
for a better solution.\&
|
||||
.PP
|
||||
You probably need to remove a sentence linking to the list action from the
|
||||
"upload.\&html" template.\&
|
||||
upload template ("upload.\&html").\&
|
||||
.PP
|
||||
.SS 1.17 (2025)
|
||||
.PP
|
||||
You need to update the "upload.\&html" template.\& Many things have changed!\& See
|
||||
\fIoddmu-templates\fR(5) for more.\&
|
||||
You need to update the upload template ("upload.\&html").\& Many things have
|
||||
changed!\& See \fIoddmu-templates\fR(5) for more.\&
|
||||
.PP
|
||||
You probably want to ensure that the upload link on the "view.\&html" template and
|
||||
others, if you added it, has a \fIfilename\fR and \fIpagename\fR parameters.\&
|
||||
You probably want to ensure that the upload link on the view template
|
||||
("view.\&html") and others, if you added it, has a \fIfilename\fR and \fIpagename\fR
|
||||
parameters.\&
|
||||
.PP
|
||||
Example:
|
||||
.PP
|
||||
@@ -136,8 +123,8 @@ Example:
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
You need to change {{.\&Name}} to {{.\&Path}} when it is used in URLs, in the
|
||||
"list.\&html" template.\& If you don'\&t do this, file deleting and rename may not
|
||||
You need to change {{.\&Name}} to {{.\&Path}} when it is used in URLs, in the list
|
||||
template ("list.\&html").\& If you don'\&t do this, file deleting and rename may not
|
||||
work on files containing a comma, a semicolon, a questionmark or a hash
|
||||
character.\& This fix was necessary because URLs for files containing a
|
||||
questionmark or a hash character would end the path at this character and treat
|
||||
@@ -192,7 +179,7 @@ together with appropriate permission checks.\&
|
||||
See \fIoddmu-apache\fR(5) or \fIoddmu-nginx\fR(5) for example.\&
|
||||
.PP
|
||||
In addition to that, you might want a link to the \fIlist\fR action from one of the
|
||||
existing templates.\& For example, from the "upload.\&html" template:
|
||||
existing templates.\& For example, from upload.\&html:
|
||||
.PP
|
||||
.nf
|
||||
.RS 4
|
||||
@@ -229,9 +216,10 @@ These are the quotation marks currently supported: '\&foo'\& "foo" ‘foo’ ‚
|
||||
“foo” „foo“ ”foo” «foo» »foo« ‹foo› ›foo‹ 「foo」 「foo」 『foo』 – any such
|
||||
quoted text is searched as-is, including whitespace.\&
|
||||
.PP
|
||||
Add loading="lazy" for images in the search template.\& If you want to take
|
||||
advantage of this, you'\&ll need to adapt your "search.\&html" template accordingly.\&
|
||||
Use like this, for example:
|
||||
Add loading="lazy" for images in search.\&html
|
||||
.PP
|
||||
If you want to take advantage of this, you'\&ll need to adapt your "search.\&html"
|
||||
template accordingly.\& Use like this, for example:
|
||||
.PP
|
||||
.nf
|
||||
.RS 4
|
||||
@@ -291,10 +279,10 @@ If you want to take advantage of this, you'\&ll need to adapt your templates
|
||||
accordingly.\& The "preview.\&html" template is a mix of "view.\&html" and
|
||||
"edit.\&html".\&
|
||||
.PP
|
||||
There is an optional change to make to copies of the "upload.\&html" template if
|
||||
you upload multiple images at a time.\& Instead of showing just the link to the
|
||||
last upload, you can now show the link (and the images or links, if you want to)
|
||||
to all the files uploaded.\& Use like this, for example:
|
||||
There is an optional change to make to copies of \fIupload.\&html\fR if you upload
|
||||
multiple images at a time.\& Instead of showing just the link to the last upload,
|
||||
you can now show the link (and the images or links, if you want to) to all the
|
||||
files uploaded.\& Use like this, for example:
|
||||
.PP
|
||||
.nf
|
||||
.RS 4
|
||||
@@ -304,9 +292,9 @@ Links:<tt>{{range \&.Actual}}<br>{{end}}</tt>
|
||||
.PP
|
||||
.SS 1.9 (2024)
|
||||
.PP
|
||||
There is a change to make to copies of the "upload.\&html" template if
|
||||
subdirectories are being used.\& The \fILast\fR property no longer contains the
|
||||
directory.\& It has to be added to the template as follows:
|
||||
There is a change to make to copies of \fIupload.\&html\fR if subdirectories are being
|
||||
used.\& The \fILast\fR property no longer contains the directory.\& It has to be added
|
||||
to the template as follows:
|
||||
.PP
|
||||
.nf
|
||||
.RS 4
|
||||
@@ -334,7 +322,7 @@ The upload template can use the \fIToday\fR property.\&
|
||||
The upload template comes with JavaScript that allows users to paste images or
|
||||
drag and drop files.\&
|
||||
.PP
|
||||
The upload template changed the id for the filename field from "text" to "name".\&
|
||||
The upload template changed the id for the filename field from `text` to `name`.\&
|
||||
.PP
|
||||
The source repository now comes with example templates.\&
|
||||
.PP
|
||||
@@ -344,7 +332,7 @@ No user-visible changes.\& Documentation and code comments got better.\&
|
||||
.PP
|
||||
.SS 1.7 (2024)
|
||||
.PP
|
||||
Allow upload of multiple files.\& This requires an update to the "upload.\&html"
|
||||
Allow upload of multiple files.\& This requires an update to the \fIupload.\&html\fR
|
||||
template: Add the \fImultiple\fR attribute to the file input element and change the
|
||||
label from "file" to "files".\&
|
||||
.PP
|
||||
|
||||
@@ -8,18 +8,9 @@ oddmu-releases - what's new?
|
||||
|
||||
This page lists user-visible features and template changes to consider.
|
||||
|
||||
## 1.21 (unreleased)
|
||||
## 1.20 (unreleased)
|
||||
|
||||
Write any missing templates when Oddmu starts up.
|
||||
|
||||
Add man subcommand to print manual pages.
|
||||
|
||||
Both of these features make it possible to distribute just the binary.
|
||||
|
||||
## 1.20 (2026)
|
||||
|
||||
Add -shrink and -glob options to the _static_ subcommand. See _oddmu-static_(1)
|
||||
for more.
|
||||
Add -shrink and -glob options to the _static_ subcommand.
|
||||
|
||||
Some tools were used to check the code (goimports, golint, gocritic).
|
||||
Unfortunately, the resulting changes necessitates a change in the templates
|
||||
@@ -40,8 +31,8 @@ faster than any of the feeds for hashtag pages, presumably, an extra features
|
||||
was added: on the first and on the last page of the feed, a link to the next or
|
||||
the previous year is added, if such a page exists. This works if at beginning of
|
||||
every year, you move all the entries on to a dedicated year page. You need to
|
||||
add the necessary links to the "feed.html" template. See _oddmu-templates_(5)
|
||||
for more.
|
||||
add the necessary links to the feed template ("feed.html"). See
|
||||
_oddmu-templates_(5) for more.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -60,11 +51,6 @@ Example:
|
||||
…
|
||||
```
|
||||
|
||||
Add _sitemap_ subcommand and handler. See _oddmu-sitemap_(1) for more. If you
|
||||
want to make it available for search engines and the like, you most likely have
|
||||
to add it to your proxy configuration. See _oddmu-apache_(5) or _oddmu-nginx_(5)
|
||||
for more.
|
||||
|
||||
## 1.19 (2025)
|
||||
|
||||
Add _feed_ subcommand. This produces a "complete" feed.
|
||||
@@ -74,8 +60,8 @@ Add feed pagination for the _feed_ action. This produces a "paginated" feed.
|
||||
See RFC 5005 for more information.
|
||||
|
||||
If you like the idea of feed pagination (not a given since that also helps bots
|
||||
scrape your site!) you need to add the necessary links to the "feed.html"
|
||||
template. See _oddmu-templates_(5) for more.
|
||||
scrape your site!) you need to add the necessary links to the feed template
|
||||
("feed.html"). See _oddmu-templates_(5) for more.
|
||||
|
||||
Example, adding the feed history namespace:
|
||||
|
||||
@@ -105,15 +91,16 @@ _list_, _delete_ and _rename_ actions were removed again. See _oddmu-webdav_(5)
|
||||
for a better solution.
|
||||
|
||||
You probably need to remove a sentence linking to the list action from the
|
||||
"upload.html" template.
|
||||
upload template ("upload.html").
|
||||
|
||||
## 1.17 (2025)
|
||||
|
||||
You need to update the "upload.html" template. Many things have changed! See
|
||||
_oddmu-templates_(5) for more.
|
||||
You need to update the upload template ("upload.html"). Many things have
|
||||
changed! See _oddmu-templates_(5) for more.
|
||||
|
||||
You probably want to ensure that the upload link on the "view.html" template and
|
||||
others, if you added it, has a _filename_ and _pagename_ parameters.
|
||||
You probably want to ensure that the upload link on the view template
|
||||
("view.html") and others, if you added it, has a _filename_ and _pagename_
|
||||
parameters.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -121,8 +108,8 @@ Example:
|
||||
<a href="/upload/{{.Dir}}?filename={{.Base}}-1.jpg&pagename={{.Base}}">Upload</a>
|
||||
```
|
||||
|
||||
You need to change {{.Name}} to {{.Path}} when it is used in URLs, in the
|
||||
"list.html" template. If you don't do this, file deleting and rename may not
|
||||
You need to change {{.Name}} to {{.Path}} when it is used in URLs, in the list
|
||||
template ("list.html"). If you don't do this, file deleting and rename may not
|
||||
work on files containing a comma, a semicolon, a questionmark or a hash
|
||||
character. This fix was necessary because URLs for files containing a
|
||||
questionmark or a hash character would end the path at this character and treat
|
||||
@@ -177,7 +164,7 @@ together with appropriate permission checks.
|
||||
See _oddmu-apache_(5) or _oddmu-nginx_(5) for example.
|
||||
|
||||
In addition to that, you might want a link to the _list_ action from one of the
|
||||
existing templates. For example, from the "upload.html" template:
|
||||
existing templates. For example, from upload.html:
|
||||
|
||||
```
|
||||
<p>You can rename and delete files <a href="/list/{{.Dir}}">from the file list</a>.
|
||||
@@ -210,9 +197,10 @@ These are the quotation marks currently supported: 'foo' "foo" ‘foo’ ‚foo
|
||||
“foo” „foo“ ”foo” «foo» »foo« ‹foo› ›foo‹ 「foo」 「foo」 『foo』 – any such
|
||||
quoted text is searched as-is, including whitespace.
|
||||
|
||||
Add loading="lazy" for images in the search template. If you want to take
|
||||
advantage of this, you'll need to adapt your "search.html" template accordingly.
|
||||
Use like this, for example:
|
||||
Add loading="lazy" for images in search.html
|
||||
|
||||
If you want to take advantage of this, you'll need to adapt your "search.html"
|
||||
template accordingly. Use like this, for example:
|
||||
|
||||
```
|
||||
{{range .Items}}
|
||||
@@ -264,10 +252,10 @@ If you want to take advantage of this, you'll need to adapt your templates
|
||||
accordingly. The "preview.html" template is a mix of "view.html" and
|
||||
"edit.html".
|
||||
|
||||
There is an optional change to make to copies of the "upload.html" template if
|
||||
you upload multiple images at a time. Instead of showing just the link to the
|
||||
last upload, you can now show the link (and the images or links, if you want to)
|
||||
to all the files uploaded. Use like this, for example:
|
||||
There is an optional change to make to copies of _upload.html_ if you upload
|
||||
multiple images at a time. Instead of showing just the link to the last upload,
|
||||
you can now show the link (and the images or links, if you want to) to all the
|
||||
files uploaded. Use like this, for example:
|
||||
|
||||
```
|
||||
Links:<tt>{{range .Actual}}<br>{{end}}</tt>
|
||||
@@ -275,9 +263,9 @@ Links:<tt>{{range .Actual}}<br>{{end}}</tt>
|
||||
|
||||
## 1.9 (2024)
|
||||
|
||||
There is a change to make to copies of the "upload.html" template if
|
||||
subdirectories are being used. The _Last_ property no longer contains the
|
||||
directory. It has to be added to the template as follows:
|
||||
There is a change to make to copies of _upload.html_ if subdirectories are being
|
||||
used. The _Last_ property no longer contains the directory. It has to be added
|
||||
to the template as follows:
|
||||
|
||||
```
|
||||
{{if ne .Last ""}}
|
||||
@@ -301,7 +289,7 @@ The upload template can use the _Today_ property.
|
||||
The upload template comes with JavaScript that allows users to paste images or
|
||||
drag and drop files.
|
||||
|
||||
The upload template changed the id for the filename field from "text" to "name".
|
||||
The upload template changed the id for the filename field from `text` to `name`.
|
||||
|
||||
The source repository now comes with example templates.
|
||||
|
||||
@@ -311,7 +299,7 @@ No user-visible changes. Documentation and code comments got better.
|
||||
|
||||
## 1.7 (2024)
|
||||
|
||||
Allow upload of multiple files. This requires an update to the "upload.html"
|
||||
Allow upload of multiple files. This requires an update to the _upload.html_
|
||||
template: Add the _multiple_ attribute to the file input element and change the
|
||||
label from "file" to "files".
|
||||
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
.\" Generated by scdoc 1.11.3
|
||||
.\" Complete documentation for this program is not available as a GNU info page
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.nh
|
||||
.ad l
|
||||
.\" Begin generated content:
|
||||
.TH "ODDMU-SITEMAP" "1" "2026-01-03"
|
||||
.PP
|
||||
.SH NAME
|
||||
.PP
|
||||
oddmu-sitemap - print static sitemap.\&xml
|
||||
.PP
|
||||
.SH SYNOPSIS
|
||||
.PP
|
||||
\fBoddmu sitemap\fR [\fB-base\fR \fIURL\fR] [\fB-filter\fR \fIregexp\fR]
|
||||
.PP
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
The "sitemap" subcommand prints the list of all pages in Sitemap format.\& Oddmu
|
||||
already serves the sitemap at the URL "/sitemap.\&xml" but if you'\&d prefer to
|
||||
provide a static file, use this command and redirect the output to a file called
|
||||
"sitemap.\&xml" in your document root at regular intervals.\&
|
||||
.PP
|
||||
If you do this, don'\&t proxy the "/sitemap" URL in the web server configuration.\&
|
||||
.PP
|
||||
Your "robots.\&txt" file, if you have one, should point at the sitemap you
|
||||
provide.\&
|
||||
.PP
|
||||
.SH OPTIONS
|
||||
.PP
|
||||
\fB-base\fR \fIURL\fR
|
||||
.RS 4
|
||||
The base URL is something like "https://example.\&org/view/".\&
|
||||
.RE
|
||||
\fB-filter\fR \fIregexp\fR
|
||||
.RS 4
|
||||
A regular expression matching the pages to exclude from the sitemap.\&
|
||||
This emulates the effect of the ODDMU_FILTER environment variable.\&
|
||||
.PP
|
||||
.RE
|
||||
.SH SEE ALSO
|
||||
.PP
|
||||
\fIoddmu\fR(1), \fIoddmu-filter\fR(7), \fIoddmu-apache\fR(1), \fIoddmu-nginx\fR(1),
|
||||
https://www.\&sitemaps.\&org/
|
||||
.PP
|
||||
.SH AUTHORS
|
||||
.PP
|
||||
Maintained by Alex Schroeder <alex@gnu.\&org>.\&
|
||||
@@ -6,7 +6,7 @@ oddmu-sitemap - print static sitemap.xml
|
||||
|
||||
# SYNOPSIS
|
||||
|
||||
*oddmu sitemap* [*-base* _URL_] [*-filter* _regexp_]
|
||||
*oddmu sitemap* [-base URL]
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
.\" Generated by scdoc 1.11.3
|
||||
.\" Generated by scdoc 1.11.4
|
||||
.\" Complete documentation for this program is not available as a GNU info page
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.nh
|
||||
.ad l
|
||||
.\" Begin generated content:
|
||||
.TH "ODDMU-STATIC" "1" "2026-02-06"
|
||||
.TH "ODDMU-STATIC" "1" "2025-12-05"
|
||||
.PP
|
||||
.SH NAME
|
||||
.PP
|
||||
@@ -13,7 +13,7 @@ oddmu-static - create a static copy of the site
|
||||
.PP
|
||||
.SH SYNOPSIS
|
||||
.PP
|
||||
\fBoddmu static\fR [\fB-jobs\fR \fIn\fR] [\fB-glob\fR \fIpattern\fR] [\fB-shrink\fR] \fIdir-name\fR
|
||||
\fBoddmu static\fR [\fB\fR-jobs\fB\fR \fIn\fR] [\fB\fR-glob\fB\fR \fIpattern\fR] [\fB\fR-shrink\fB\fR] \fIdir-name\fR
|
||||
.PP
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
@@ -32,7 +32,7 @@ no feed items are found, no feed is written.\& The feed is limited to the ten mo
|
||||
recent items.\&
|
||||
.PP
|
||||
Hidden files and directories (starting with a ".\&") and backup files (ending with
|
||||
a "~") are skipped.\&
|
||||
a "\(ti") are skipped.\&
|
||||
.PP
|
||||
All other files are \fIhard linked\fR.\& This is done to save space: on a typical blog
|
||||
the images take a lot more space than the text.\& On my blog in 2023 I had 2.\&62
|
||||
@@ -53,18 +53,18 @@ original, too.\&
|
||||
.PP
|
||||
.SH OPTIONS
|
||||
.PP
|
||||
\fB-jobs\fR \fIn\fR
|
||||
\fB\fR-jobs\fB\fR \fIn\fR
|
||||
.RS 4
|
||||
By default, two jobs are used to process the files.\& If your machine has
|
||||
more cores, you can increase the number of jobs.\&
|
||||
.PP
|
||||
.RE
|
||||
\fB-glob\fR \fIpattern\fR
|
||||
\fB\fR-glob\fB\fR \fIpattern\fR
|
||||
.RS 4
|
||||
By default, all files are used for the static export.\& You can limit the
|
||||
files used by providing a shell file name pattern.\& A "*" matches any
|
||||
number of characters; a "?\&" matches exactly one character; "[a-z]"
|
||||
matches a character listed, including ranges; "[^a-z]" matches a
|
||||
matches a character listed, including ranges; "[\(haa-z]" matches a
|
||||
character not listed, including ranges; "\e" a backslash escapes the
|
||||
following character.\& You must use quotes around the pattern if you are
|
||||
using a shell as the shell would otherwise expand the pattern, resulting
|
||||
@@ -72,12 +72,12 @@ in the error "Exactly one target directory is required".\&
|
||||
.PP
|
||||
.PP
|
||||
.RE
|
||||
\fB-shrink\fR
|
||||
\fB\fR-shrink\fB\fR
|
||||
.RS 4
|
||||
By default, images are linked or copied.\& With this option, JPEG, PNG and
|
||||
WebP files are scaled down if more than 800 pixels wide and the quality
|
||||
is set to 30% for JPEG and WebP files.\& This is \fIbad quality\fR but the
|
||||
result is that these image files are very small.\&
|
||||
is set to 10% for JPEG and WebP files.\& This is \fIvery bad quality\fR but
|
||||
the result is that these image files are very small.\&
|
||||
.PP
|
||||
.RE
|
||||
.SH EXAMPLES
|
||||
|
||||
@@ -6,7 +6,7 @@ oddmu-static - create a static copy of the site
|
||||
|
||||
# SYNOPSIS
|
||||
|
||||
*oddmu static* [*-jobs* _n_] [*-glob* _pattern_] [*-shrink*] _dir-name_
|
||||
*oddmu static* [**-jobs** _n_] [**-glob** _pattern_] [**-shrink**] _dir-name_
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
@@ -46,11 +46,11 @@ original, too.
|
||||
|
||||
# OPTIONS
|
||||
|
||||
*-jobs* _n_
|
||||
**-jobs** _n_
|
||||
By default, two jobs are used to process the files. If your machine has
|
||||
more cores, you can increase the number of jobs.
|
||||
|
||||
*-glob* _pattern_
|
||||
**-glob** _pattern_
|
||||
By default, all files are used for the static export. You can limit the
|
||||
files used by providing a shell file name pattern. A "\*" matches any
|
||||
number of characters; a "?" matches exactly one character; "[a-z]"
|
||||
@@ -61,11 +61,11 @@ original, too.
|
||||
in the error "Exactly one target directory is required".
|
||||
|
||||
|
||||
*-shrink*
|
||||
**-shrink**
|
||||
By default, images are linked or copied. With this option, JPEG, PNG and
|
||||
WebP files are scaled down if more than 800 pixels wide and the quality
|
||||
is set to 30% for JPEG and WebP files. This is _bad quality_ but the
|
||||
result is that these image files are very small.
|
||||
is set to 10% for JPEG and WebP files. This is _very bad quality_ but
|
||||
the result is that these image files are very small.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
.\" Generated by scdoc 1.11.3
|
||||
.\" Generated by scdoc 1.11.4
|
||||
.\" Complete documentation for this program is not available as a GNU info page
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.nh
|
||||
.ad l
|
||||
.\" Begin generated content:
|
||||
.TH "ODDMU-TEMPLATES" "5" "2026-01-03" "File Formats Manual"
|
||||
.TH "ODDMU-TEMPLATES" "5" "2026-01-01" "File Formats Manual"
|
||||
.PP
|
||||
.SH NAME
|
||||
.PP
|
||||
@@ -31,12 +31,12 @@ placeholders.\&
|
||||
.IP \(bu 4
|
||||
\fIfeed.\&html\fR uses a \fIfeed\fR
|
||||
.IP \(bu 4
|
||||
\fIlist.\&html\fR uses a \fIlist\fR
|
||||
.IP \(bu 4
|
||||
\fIpreview.\&html\fR uses a \fIpage\fR
|
||||
.IP \(bu 4
|
||||
\fIsearch.\&html\fR uses a \fIsearch\fR
|
||||
.IP \(bu 4
|
||||
\fIsitemap.\&html\fR uses a \fIsitemap\fR
|
||||
.IP \(bu 4
|
||||
\fIstatic.\&html\fR uses a \fIpage\fR
|
||||
.IP \(bu 4
|
||||
\fIupload.\&html\fR uses an \fIupload\fR
|
||||
@@ -172,6 +172,32 @@ explanation.\& The next year is one lower than the year currently shown (if on a
|
||||
year page) or the current year (if looking at the index).\& If it isn'\&t set, it'\&s
|
||||
value is 0.\&
|
||||
.PP
|
||||
.SS List
|
||||
.PP
|
||||
The list contains a directory name and an array of files.\&
|
||||
.PP
|
||||
\fI{{.\&Dir}}\fR is the directory name that is being listed, percent-encoded.\&
|
||||
.PP
|
||||
\fI{{.\&Files}}\fR is the array of files.\& To refer to them, you need to use a \fI{{range
|
||||
Files}}\fR … \fI{{end}}\fR construct.\&
|
||||
.PP
|
||||
Each file has the following attributes:
|
||||
.PP
|
||||
\fI{{.\&Name}}\fR is the filename.\& The ".\&md" suffix for Markdown files is part of the
|
||||
name (unlike page names).\&
|
||||
.PP
|
||||
\fI{{.\&Path}}\fR is the page name, percent-encoded.\&
|
||||
.PP
|
||||
\fI{{.\&Title}}\fR is the page title, if the file in question is a Markdown file.\&
|
||||
.PP
|
||||
\fI{{.\&IsDir}}\fR is a boolean used to indicate that this file is a directory.\&
|
||||
.PP
|
||||
\fI{{.\&IsUp}}\fR is a boolean used to indicate the entry for the parent directory
|
||||
(the first file in the array, unless the directory being listed is the top
|
||||
directory).\& The filename of this file is ".\&.\&".\&
|
||||
.PP
|
||||
\fI{{.\&Date}}\fR is the last modification date of the file.\&
|
||||
.PP
|
||||
.SS Search
|
||||
.PP
|
||||
\fI{{.\&Query}}\fR is the query string.\&
|
||||
@@ -210,16 +236,6 @@ are only listed if a search term matches.\&
|
||||
\fI{{.\&Html}}\fR the image alt-text with a bold tag used to highlight the first
|
||||
search term that matched.\&
|
||||
.PP
|
||||
.SS Sitemap
|
||||
.PP
|
||||
The sitemap contains a list of URLs, each with its location:
|
||||
.PP
|
||||
\fI{{.\&URL}}\fR is the list of URLs.\&
|
||||
.PP
|
||||
Each URL has the following attributes:
|
||||
.PP
|
||||
\fI{{.\&Loc}}\fR with the actual page URL.\&
|
||||
.PP
|
||||
.SS Upload
|
||||
.PP
|
||||
\fI{{.\&Dir}}\fR is the directory where the uploaded file ends up, based on the URL
|
||||
|
||||
443
man/oddmu.1
443
man/oddmu.1
@@ -1,443 +0,0 @@
|
||||
.\" Generated by scdoc 1.11.3
|
||||
.\" Complete documentation for this program is not available as a GNU info page
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.nh
|
||||
.ad l
|
||||
.\" Begin generated content:
|
||||
.TH "ODDMU" "1" "2026-02-11"
|
||||
.PP
|
||||
.SH NAME
|
||||
.PP
|
||||
oddmu - a wiki server
|
||||
.PP
|
||||
Oddmu is sometimes written Oddμ because μ is the letter mu.\&
|
||||
.PP
|
||||
.SH SYNOPSIS
|
||||
.PP
|
||||
\fBoddmu\fR
|
||||
.PP
|
||||
\fBoddmu\fR \fIsubcommand\fR [\fIarguments\fR.\&.\&.\&]
|
||||
.PP
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
Oddmu can be used as a static site generator, turning Markdown files into HTML
|
||||
files, or it can be used as a public or a private wiki server.\& If it runs as a
|
||||
public wiki server, a regular webserver should be used as reverse proxy.\&
|
||||
.PP
|
||||
Run Oddmu without any arguments to serve the current working directory as a wiki
|
||||
on port 8080.\& Point your browser to http://localhost:8080/ to use it.\& This
|
||||
redirects you to http://localhost:8080/view/index – the first page you'\&ll
|
||||
create, most likely.\&
|
||||
.PP
|
||||
See \fIoddmu\fR(5) for details about the page formatting.\&
|
||||
.PP
|
||||
If you request a file that exists, like "index.\&md", Oddmu serves it as-is.\& If
|
||||
you request a file that doesn'\&t exist, like "index", Oddmu checks if a matching
|
||||
Markdown file exists by appending the extension ".\&md".\& If such a file is found,
|
||||
it is turned into HTML and shown.\& If no such file exists, Oddmu offers you to
|
||||
create the page.\&
|
||||
.PP
|
||||
If your files don'\&t provide their own title ("# title"), the file name (without
|
||||
".\&md") is used for the page title.\&
|
||||
.PP
|
||||
Every file can be viewed as feed by using the extension ".\&rss".\& The
|
||||
feed items are based on links in bullet lists using the asterix
|
||||
("*").\&
|
||||
.PP
|
||||
Subdirectories are created as necessary.\&
|
||||
.PP
|
||||
The wiki knows the following actions for a given page name and (optional)
|
||||
directory:
|
||||
.PP
|
||||
.PD 0
|
||||
.IP \(bu 4
|
||||
\fI/\fR redirects to /view/index
|
||||
.IP \(bu 4
|
||||
\fI/view/dir/\fR redirects to /view/dir/index
|
||||
.IP \(bu 4
|
||||
\fI/view/dir/name\fR shows a page
|
||||
.IP \(bu 4
|
||||
\fI/view/dir/name.\&md\fR shows the source text of a page
|
||||
.IP \(bu 4
|
||||
\fI/view/dir/name.\&rss\fR shows the RSS feed for the pages linked
|
||||
.IP \(bu 4
|
||||
\fI/diff/dir/name\fR shows the last change to a page
|
||||
.IP \(bu 4
|
||||
\fI/edit/dir/name\fR shows a form to edit a page
|
||||
.IP \(bu 4
|
||||
\fI/preview/dir/name\fR shows a preview of a page edit and the form to edit it
|
||||
.IP \(bu 4
|
||||
\fI/save/dir/name\fR saves an edit
|
||||
.IP \(bu 4
|
||||
\fI/add/dir/name\fR shows a form to add to a page
|
||||
.IP \(bu 4
|
||||
\fI/append/dir/name\fR appends an addition to a page
|
||||
.IP \(bu 4
|
||||
\fI/upload/dir/name\fR shows a form to upload a file
|
||||
.IP \(bu 4
|
||||
\fI/drop/dir/name\fR saves an upload
|
||||
.IP \(bu 4
|
||||
\fI/search/dir/?\&q=term\fR to search for a term
|
||||
.IP \(bu 4
|
||||
\fI/sitemap.\&xml\fR to list the links to all the pages
|
||||
.IP \(bu 4
|
||||
\fI/archive/dir/name.\&zip\fR to download a zip file of a directory
|
||||
.PD
|
||||
.PP
|
||||
When calling the \fIsave\fR and \fIappend\fR action, the page name is taken from the URL
|
||||
path and the page content is taken from the \fIbody\fR form parameter.\& To
|
||||
illustrate, here'\&s how to edit the "welcome" page using \fIcurl\fR:
|
||||
.PP
|
||||
.nf
|
||||
.RS 4
|
||||
curl --form body="Did you bring a towel?"
|
||||
http://localhost:8080/save/welcome
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
When calling the \fIdrop\fR action, the query parameters used are \fIname\fR for the
|
||||
target filename and \fIfile\fR for the file to upload.\& If the query parameter
|
||||
\fImaxwidth\fR is set, an attempt is made to decode and resize the image.\& JPG, PNG,
|
||||
WEBP and HEIC files can be decoded.\& Only JPG, PNG and WEBP files can be encoded,
|
||||
however.\& If the target name ends in \fI.\&jpg\fR or \fI.\&png\fR, the \fIquality\fR query
|
||||
parameter is also taken into account.\& To upload some thumbnails:
|
||||
.PP
|
||||
.nf
|
||||
.RS 4
|
||||
for f in *\&.jpg; do
|
||||
curl --form name="$f" --form file=@"$f" --form maxwidth=100
|
||||
http://localhost:8080/drop/
|
||||
done
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
When calling the \fIsearch\fR action, the search terms are taken from the query
|
||||
parameter \fIq\fR.\&
|
||||
.PP
|
||||
.nf
|
||||
.RS 4
|
||||
curl \&'http://localhost:8080/search/?q=towel\&'
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
The page name to act upon is optionally taken from the query parameter \fIid\fR.\& In
|
||||
this case, the directory must still be part of the path and may not be part of
|
||||
the \fIid\fR.\& This is enforced so that the path can be used by a webserver for
|
||||
access control.\&
|
||||
.PP
|
||||
.nf
|
||||
.RS 4
|
||||
curl \&'http://localhost:8080/view/man/?id=oddmu\&.1\&.txt\&'
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
The base name for the \fIarchive\fR action is used by the browser to save the
|
||||
downloaded file.\& For Oddmu, only the directory is important.\& The following zips
|
||||
the \fIman\fR directory and saves it as \fIman.\&zip\fR.\&
|
||||
.PP
|
||||
.nf
|
||||
.RS 4
|
||||
curl --remote-name \&'http://localhost:8080/archive/man/man\&.zip
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
.SH CONFIGURATION
|
||||
.PP
|
||||
The template files are the HTML files in the working directory.\& If they are
|
||||
missing, the default files are written to disk as soon as they are required.\&
|
||||
Please change these templates!\&
|
||||
.PP
|
||||
The first change you should make is to replace the name and email address in the
|
||||
footer of \fIview.\&html\fR.\& Look for "Your Name" and "example.\&org".\&
|
||||
.PP
|
||||
The second change you should make is to replace the name, email address and
|
||||
domain name in "feed.\&html".\& Look for "Your Name" and "example.\&org".\&
|
||||
.PP
|
||||
See \fIoddmu-templates\fR(5) for more.\&
|
||||
.PP
|
||||
.SH ENVIRONMENT
|
||||
.PP
|
||||
You can change the port served by setting the ODDMU_PORT environment variable.\&
|
||||
.PP
|
||||
You can change the address served by setting the ODDMU_ADDRESS environment
|
||||
variable to either an IPv4 address or an IPv6 address.\& If ODDMU_ADDRESS is
|
||||
unset, then the program listens on all available unicast addresses, both IPv4
|
||||
and IPv6.\& Here are a few example addresses:
|
||||
.PP
|
||||
.nf
|
||||
.RS 4
|
||||
ODDMU_ADDRESS=127\&.0\&.0\&.1 # The loopback IPv4 address\&.
|
||||
ODDMU_ADDRESS=2001:db8::3:1 # An IPv6 address\&.
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
See the Socket Activation section for an alternative method of listening which
|
||||
supports Unix-domain sockets.\&
|
||||
.PP
|
||||
In order to limit language-detection to the languages you actually use, set the
|
||||
environment variable ODDMU_LANGUAGES to a comma-separated list of ISO 639-1
|
||||
codes, e.\&g.\& "en" or "en,de,fr,pt".\&
|
||||
.PP
|
||||
You can enable webfinger to link fediverse accounts to their correct profile
|
||||
pages by setting ODDMU_WEBFINGER to "1".\& See \fIoddmu\fR(5).\&
|
||||
.PP
|
||||
If you use secret subdirectories, you cannot rely on the web server to hide
|
||||
those pages because some actions such as searching and archiving include
|
||||
subdirectories.\& They act upon a whole tree of pages, not just a single page.\& The
|
||||
ODDMU_FILTER can be used to exclude subdirectories from such tree actions.\& See
|
||||
\fIoddmu-filter\fR(7) and \fIoddmu-apache\fR(5).\&
|
||||
.PP
|
||||
.SH Socket Activation
|
||||
.PP
|
||||
Instead of specifying ODDMU_ADDRESS or ODDMU_PORT, you can start the service
|
||||
through socket activation.\& The advantage of this method is that you can use a
|
||||
Unix-domain socket instead of a TCP socket, and the permissions and ownership of
|
||||
the socket are set before the program starts.\& See \fIoddmu.\&service\fR(5),
|
||||
\fIoddmu-apache\fR(5) and \fIoddmu-nginx\fR(5) for an example of how to use socket
|
||||
activation with a Unix-domain socket under systemd and Apache.\&
|
||||
.PP
|
||||
.SH SECURITY
|
||||
.PP
|
||||
If the machine you are running Oddmu on is accessible from the Internet, you
|
||||
must secure your installation.\& The best way to do this is use a regular web
|
||||
server as a reverse proxy.\& See \fIoddmu-apache\fR(5) and \fIoddmu-nginx\fR(5) for
|
||||
example configurations.\&
|
||||
.PP
|
||||
Oddmu assumes that all the users that can edit pages or upload files are trusted
|
||||
users and therefore their content is trusted.\& Oddmu does not perform HTML
|
||||
sanitization!\&
|
||||
.PP
|
||||
For an extra dose of security, consider using a Unix-domain socket.\&
|
||||
.PP
|
||||
.SH OPTIONS
|
||||
.PP
|
||||
Oddmu can be run on the command-line using various subcommands.\&
|
||||
.PP
|
||||
.PD 0
|
||||
.IP \(bu 4
|
||||
to generate the HTML for a single page, see \fIoddmu-html\fR(1)
|
||||
.IP \(bu 4
|
||||
to generate the HTML for the entire site, using Oddmu as a static site
|
||||
generator, see \fIoddmu-static\fR(1)
|
||||
.IP \(bu 4
|
||||
to export the HTML for the entire site in one big feed, see \fIoddmu-export\fR(1)
|
||||
.IP \(bu 4
|
||||
to emulate a search of the files, see \fIoddmu-search\fR(1); to understand how the
|
||||
search engine indexes pages and how it sorts and scores results, see
|
||||
\fIoddmu-search\fR(7)
|
||||
.IP \(bu 4
|
||||
to search a regular expression and replace it across all files, see
|
||||
\fIoddmu-replace\fR(1)
|
||||
.IP \(bu 4
|
||||
to learn what the most popular hashtags are, see \fIoddmu-hashtags\fR(1)
|
||||
.IP \(bu 4
|
||||
to print a table of contents (TOC) for a page, see \fIoddmu-toc\fR(1)
|
||||
.IP \(bu 4
|
||||
to list the outgoing links for a page, see \fIoddmu-links\fR(1)
|
||||
.IP \(bu 4
|
||||
to find missing pages (local links that go nowhere), see \fIoddmu-missing\fR(1)
|
||||
.IP \(bu 4
|
||||
to list all the pages with name and title, see \fIoddmu-list\fR(1)
|
||||
.IP \(bu 4
|
||||
to add links to changes, index and hashtag pages to pages you created locally,
|
||||
see \fIoddmu-notify\fR(1)
|
||||
.IP \(bu 4
|
||||
to display build information, see \fIoddmu-version\fR(1)
|
||||
.PD
|
||||
.PP
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
When saving a page, the page name is take from the URL and the page content is
|
||||
taken from the "body" form parameter.\& To illustrate, here'\&s how to edit a page
|
||||
using \fIcurl\fR(1):
|
||||
.PP
|
||||
.nf
|
||||
.RS 4
|
||||
curl --form body="Did you bring a towel?"
|
||||
http://localhost:8080/save/welcome
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
To compute the space used by your setup, use regular tools:
|
||||
.PP
|
||||
.nf
|
||||
.RS 4
|
||||
du --exclude=\&'*/.*\&' --exclude \&'*~\&' --block-size=M
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
.SH DESIGN
|
||||
.PP
|
||||
This is a minimal wiki.\& There is no version history.\& It'\&s well suited as a
|
||||
\fIsecondary\fR medium: collaboration and conversation happens elsewhere, in chat,
|
||||
on social media.\& The wiki serves as the text repository that results from these
|
||||
discussions.\&
|
||||
.PP
|
||||
The idea is that the webserver handles as many tasks as possible.\& It logs
|
||||
requests, does rate limiting, handles encryption, gets the certificates, and so
|
||||
on.\& The web server acts as a reverse proxy and the wiki ends up being a content
|
||||
management system with almost no structure – or endless malleability, depending
|
||||
on your point of view.\& See \fIoddmu-apache\fR(5).\&
|
||||
.PP
|
||||
.SH NOTES
|
||||
.PP
|
||||
Page names are filenames with ".\&md" appended.\& If your filesystem cannot handle
|
||||
it, it can'\&t be a page name.\& Filenames can contain slashes and Oddmu creates
|
||||
subdirectories as necessary.\&
|
||||
.PP
|
||||
Files may not end with a tilde ('\&~'\&) – these are backup files.\& When saving pages
|
||||
and file uploads, the old file is renamed to the backup file unless the backup
|
||||
file is less than an hour old, thus collapsing all edits made in an hour into a
|
||||
single diff when comparing backup and current version.\& The backup also gets an
|
||||
updated timestamp so that subsequent edits don'\&t immediately overwrite it.\&
|
||||
.PP
|
||||
The \fBindex\fR page is the default page.\& People visiting the "root" of the site are
|
||||
redirected to "/view/index".\&
|
||||
.PP
|
||||
The \fBchanges\fR page is where links to new and changed files are added.\& As an
|
||||
author, you can prevent this from happening by deselecting the checkbox "Add
|
||||
link to the list of changes.\&" The changes page can be edited like every other
|
||||
page, so it'\&s easy to undo mistakes.\&
|
||||
.PP
|
||||
Links on the changes page are grouped by date.\& When new links are added, the
|
||||
current date of the machine Oddmu is running on is used.\& If a link already
|
||||
exists on the changes page, it is moved up to the current date.\& If that leaves
|
||||
an old date without any links, that date heading is removed.\&
|
||||
.PP
|
||||
A page whose name starts with an ISO date (YYYY-MM-DD, e.\&g.\& "2023-10-28") is
|
||||
called a \fBblog\fR page.\& When creating or editing blog pages, links to it are added
|
||||
from other pages as follows:
|
||||
.PP
|
||||
.PD 0
|
||||
.IP \(bu 4
|
||||
If the blog page name starts with the current year, a link is created from the
|
||||
index page back to the blog page being created or edited.\& Again, you can
|
||||
prevent this from happening by deselecting the checkbox "Add link to the list
|
||||
of changes.\&" The index page can be edited like every other page, so it'\&s easy
|
||||
to undo mistakes.\&
|
||||
.PD
|
||||
.PP
|
||||
.PD 0
|
||||
.IP \(bu 4
|
||||
For every \fBhashtag\fR used, another link might be created.\& If a page named like
|
||||
the hashtag exists, a backlink is added to it, linking to the new or edited
|
||||
blog page.\&
|
||||
.PD
|
||||
.PP
|
||||
.PD 0
|
||||
.IP \(bu 4
|
||||
If a link to the new or edited blog page already exists but it'\&s title is no
|
||||
longer correct, it is updated.\&
|
||||
.PD
|
||||
.PP
|
||||
New links added for blog pages are added at the top of the first unnumbered list
|
||||
using the asterisk ('\&*'\&).\& If no such list exists, a new one is started at the
|
||||
bottom of the page.\& This allows you to have a different unnumbered list further
|
||||
up on the page, as long as it uses the minus for items ('\&-'\&).\&
|
||||
.PP
|
||||
Changes made locally to the source files (using an editor) do not create any
|
||||
links on the changes page, the index page or on any hashtag pages.\& See
|
||||
\fIoddmu-notify\fR(1) for a way to add the necessary links to the changes page and
|
||||
possibly to the index and hashtag pages.\&
|
||||
.PP
|
||||
A hashtag consists of a number sign ('\&#'\&) followed by Unicode letters, numbers
|
||||
or the underscore ('\&_'\&).\& Thus, a hashtag ends with punctuation or whitespace.\&
|
||||
.PP
|
||||
The page names, titles and hashtags are loaded into memory when the server
|
||||
starts.\& If you have a lot of pages, this takes a lot of memory.\& Oddmu watches
|
||||
the working directory and any subdirectories for changes made to page files and
|
||||
updates this cache when necessary.\&
|
||||
.PP
|
||||
Uploaded files cannot be edited unless they end with ".\&md".\& If you upload a file
|
||||
called "hello.\&txt" and attempt to edit it by using "/edit/hello.\&txt" you create
|
||||
a page with the name "hello.\&txt.\&md" instead.\&
|
||||
.PP
|
||||
In order to delete uploaded files via the web, create an empty file and upload
|
||||
it.\& In order to delete a wiki page, save an empty page.\&
|
||||
.PP
|
||||
Note that some HTML file names are special: they act as templates.\& See
|
||||
\fIoddmu-templates\fR(5) for their names and their use.\& Oddmu watches the working
|
||||
directory and any subdirectories for changes made to template files and reloads
|
||||
them.\& There is no need to restart the server after making changes to the
|
||||
templates.\&
|
||||
.PP
|
||||
.SH SEE ALSO
|
||||
.PP
|
||||
.PD 0
|
||||
.IP \(bu 4
|
||||
\fIoddmu\fR(5), about the markup syntax and how feeds are generated based on link
|
||||
lists
|
||||
.IP \(bu 4
|
||||
\fIoddmu-releases\fR(7), on what features are part of the latest release
|
||||
.IP \(bu 4
|
||||
\fIoddmu-filter\fR(7), on how to treat subdirectories as separate sites
|
||||
.IP \(bu 4
|
||||
\fIoddmu-search\fR(7), on how search works
|
||||
.IP \(bu 4
|
||||
\fIoddmu-templates\fR(5), on how to write the HTML templates
|
||||
.PD
|
||||
.PP
|
||||
If you run Oddmu as a web server:
|
||||
.PP
|
||||
.PD 0
|
||||
.IP \(bu 4
|
||||
\fIoddmu-apache\fR(5), on how to set up Apache as a reverse proxy
|
||||
.IP \(bu 4
|
||||
\fIoddmu-nginx\fR(5), on how to set up freenginx as a reverse proxy
|
||||
.IP \(bu 4
|
||||
\fIoddmu-webdav\fR(5), on how to set up Apache as a Web-DAV server
|
||||
.IP \(bu 4
|
||||
\fIoddmu.\&service\fR(5), on how to run the service under systemd
|
||||
.PD
|
||||
.PP
|
||||
If you run Oddmu as a static site generator or pages offline and sync them with
|
||||
Oddmu running as a webserver:
|
||||
.PP
|
||||
.PD 0
|
||||
.IP \(bu 4
|
||||
\fIoddmu-hashtags\fR(1), on working with hashtags
|
||||
.IP \(bu 4
|
||||
\fIoddmu-html\fR(1), on how to render a page
|
||||
.IP \(bu 4
|
||||
\fIoddmu-feed\fR(1), on how to render a feed
|
||||
.IP \(bu 4
|
||||
\fIoddmu-list\fR(1), on how to list pages and titles
|
||||
.IP \(bu 4
|
||||
\fIoddmu-links\fR(1), on how to list the outgoing links for a page
|
||||
.IP \(bu 4
|
||||
\fIoddmu-missing\fR(1), on how to find broken local links
|
||||
.IP \(bu 4
|
||||
\fIoddmu-notify\fR(1), on updating index, changes and hashtag pages
|
||||
.IP \(bu 4
|
||||
\fIoddmu-replace\fR(1), on how to search and replace text
|
||||
.IP \(bu 4
|
||||
\fIoddmu-search\fR(1), on how to run a search
|
||||
.IP \(bu 4
|
||||
\fIoddmu-sitemap\fR(1), on generating a static sitemap.\&xml
|
||||
.IP \(bu 4
|
||||
\fIoddmu-static\fR(1), on generating a static site
|
||||
.IP \(bu 4
|
||||
\fIoddmu-toc\fR(1), on how to list the table of contents (toc) a page
|
||||
.IP \(bu 4
|
||||
\fIoddmu-version\fR(1), on how to get all the build information from the binary
|
||||
.PD
|
||||
.PP
|
||||
If you want to stop using Oddmu:
|
||||
.PP
|
||||
.PD 0
|
||||
.IP \(bu 4
|
||||
\fIoddmu-export\fR(1), on how to export all the files as one big RSS file
|
||||
.PD
|
||||
.PP
|
||||
And finally, if you don'\&t have the man pages, you can still read the original
|
||||
documents:
|
||||
.PP
|
||||
.PD 0
|
||||
.IP \(bu 4
|
||||
\fIoddmu-man\fR(1), to get help even if you don'\&t have the man pages installed
|
||||
.PD
|
||||
.PP
|
||||
.SH AUTHORS
|
||||
.PP
|
||||
Maintained by Alex Schroeder <alex@gnu.\&org>.\&
|
||||
|
||||
@@ -25,11 +25,10 @@ create, most likely.
|
||||
|
||||
See _oddmu_(5) for details about the page formatting.
|
||||
|
||||
If you request a file that exists, like "index.md", Oddmu serves it as-is. If
|
||||
you request a file that doesn't exist, like "index", Oddmu checks if a matching
|
||||
Markdown file exists by appending the extension ".md". If such a file is found,
|
||||
it is turned into HTML and shown. If no such file exists, Oddmu offers you to
|
||||
create the page.
|
||||
If you request a page that doesn't exist, Oddmu tries to find a matching
|
||||
Markdown file by appending the extension ".md" to the page name. In the example
|
||||
above, the page name requested is "index" and the file name Oddmu tries to read
|
||||
is "index.md". If no such file exists, Oddmu offers you to create the page.
|
||||
|
||||
If your files don't provide their own title ("# title"), the file name (without
|
||||
".md") is used for the page title.
|
||||
@@ -72,9 +71,9 @@ curl --form body="Did you bring a towel?" \
|
||||
When calling the _drop_ action, the query parameters used are _name_ for the
|
||||
target filename and _file_ for the file to upload. If the query parameter
|
||||
_maxwidth_ is set, an attempt is made to decode and resize the image. JPG, PNG,
|
||||
WEBP and HEIC files can be decoded. Only JPG, PNG and WEBP files can be encoded,
|
||||
however. If the target name ends in _.jpg_ or _.png_, the _quality_ query
|
||||
parameter is also taken into account. To upload some thumbnails:
|
||||
WEBP and HEIC files can be decoded. Only JPG and PNG files can be encoded,
|
||||
however. If the target name ends in _.jpg_, the _quality_ query parameter is
|
||||
also taken into account. To upload some thumbnails:
|
||||
|
||||
```
|
||||
for f in *.jpg; do
|
||||
@@ -91,12 +90,11 @@ curl 'http://localhost:8080/search/?q=towel'
|
||||
```
|
||||
|
||||
The page name to act upon is optionally taken from the query parameter _id_. In
|
||||
this case, the directory must still be part of the path and may not be part of
|
||||
the _id_. This is enforced so that the path can be used by a webserver for
|
||||
access control.
|
||||
this case, the directory must also be part of the query parameter and not of the
|
||||
URL path.
|
||||
|
||||
```
|
||||
curl 'http://localhost:8080/view/man/?id=oddmu.1.txt'
|
||||
curl 'http://localhost:8080/view/?id=man/oddmu.1.txt'
|
||||
```
|
||||
|
||||
The base name for the _archive_ action is used by the browser to save the
|
||||
@@ -109,9 +107,8 @@ curl --remote-name 'http://localhost:8080/archive/man/man.zip
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
The template files are the HTML files in the working directory. If they are
|
||||
missing, the default files are written to disk as soon as they are required.
|
||||
Please change these templates!
|
||||
The template files are the HTML files in the working directory. Please change
|
||||
these templates!
|
||||
|
||||
The first change you should make is to replace the name and email address in the
|
||||
footer of _view.html_. Look for "Your Name" and "example.org".
|
||||
@@ -250,53 +247,55 @@ current date of the machine Oddmu is running on is used. If a link already
|
||||
exists on the changes page, it is moved up to the current date. If that leaves
|
||||
an old date without any links, that date heading is removed.
|
||||
|
||||
If you want to link to the changes page, you need to do this yourself. Add a
|
||||
link from the index, for example. The "view.html" template currently doesn't do
|
||||
it. See _oddmu-templates_(5) if you want to add the link to the template.
|
||||
|
||||
A page whose name starts with an ISO date (YYYY-MM-DD, e.g. "2023-10-28") is
|
||||
called a *blog* page. When creating or editing blog pages, links to it are added
|
||||
from other pages as follows:
|
||||
from other pages.
|
||||
|
||||
- If the blog page name starts with the current year, a link is created from the
|
||||
index page back to the blog page being created or edited. Again, you can
|
||||
prevent this from happening by deselecting the checkbox "Add link to the list
|
||||
of changes." The index page can be edited like every other page, so it's easy
|
||||
to undo mistakes.
|
||||
If the blog page name starts with the current year, a link is created from the
|
||||
index page back to the blog page being created or edited. Again, you can prevent
|
||||
this from happening by deselecting the checkbox "Add link to the list of
|
||||
changes." The index page can be edited like every other page, so it's easy to
|
||||
undo mistakes.
|
||||
|
||||
- For every *hashtag* used, another link might be created. If a page named like
|
||||
the hashtag exists, a backlink is added to it, linking to the new or edited
|
||||
blog page.
|
||||
For every *hashtag* used, another link might be created. If a page named like
|
||||
the hashtag exists, a backlink is added to it, linking to the new or edited blog
|
||||
page.
|
||||
|
||||
- If a link to the new or edited blog page already exists but it's title is no
|
||||
longer correct, it is updated.
|
||||
If a link to the new or edited blog page already exists but it's title is no
|
||||
longer correct, it is updated.
|
||||
|
||||
New links added for blog pages are added at the top of the first unnumbered list
|
||||
using the asterisk ('\*'). If no such list exists, a new one is started at the
|
||||
bottom of the page. This allows you to have a different unnumbered list further
|
||||
up on the page, as long as it uses the minus for items ('-').
|
||||
|
||||
Changes made locally to the source files (using an editor) do not create any
|
||||
links on the changes page, the index page or on any hashtag pages. See
|
||||
_oddmu-notify_(1) for a way to add the necessary links to the changes page and
|
||||
possibly to the index and hashtag pages.
|
||||
Changes made locally do not create any links on the changes page, the index page
|
||||
or on any hashtag pages. See _oddmu-notify_(1) for a way to add the necessary
|
||||
links to the changes page and possibly to the index and hashtag pages.
|
||||
|
||||
A hashtag consists of a number sign ('#') followed by Unicode letters, numbers
|
||||
or the underscore ('\_'). Thus, a hashtag ends with punctuation or whitespace.
|
||||
|
||||
The page names, titles and hashtags are loaded into memory when the server
|
||||
starts. If you have a lot of pages, this takes a lot of memory. Oddmu watches
|
||||
the working directory and any subdirectories for changes made to page files and
|
||||
updates this cache when necessary.
|
||||
starts. If you have a lot of pages, this takes a lot of memory.
|
||||
|
||||
Uploaded files cannot be edited unless they end with ".md". If you upload a file
|
||||
called "hello.txt" and attempt to edit it by using "/edit/hello.txt" you create
|
||||
a page with the name "hello.txt.md" instead.
|
||||
Oddmu watches the working directory and any subdirectories for changes made
|
||||
directly. Thus, in theory, it's not necessary to restart it after making such
|
||||
changes.
|
||||
|
||||
You cannot edit uploaded files. If you upload a file called "hello.txt" and
|
||||
attempt to edit it by using "/edit/hello.txt" you create a page with the name
|
||||
"hello.txt.md" instead.
|
||||
|
||||
In order to delete uploaded files via the web, create an empty file and upload
|
||||
it. In order to delete a wiki page, save an empty page.
|
||||
|
||||
Note that some HTML file names are special: they act as templates. See
|
||||
_oddmu-templates_(5) for their names and their use. Oddmu watches the working
|
||||
directory and any subdirectories for changes made to template files and reloads
|
||||
them. There is no need to restart the server after making changes to the
|
||||
templates.
|
||||
_oddmu-templates_(5) for their names and their use.
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
@@ -335,11 +334,6 @@ If you want to stop using Oddmu:
|
||||
|
||||
- _oddmu-export_(1), on how to export all the files as one big RSS file
|
||||
|
||||
And finally, if you don't have the man pages, you can still read the original
|
||||
documents:
|
||||
|
||||
- _oddmu-man_(1), to get help even if you don't have the man pages installed
|
||||
|
||||
# AUTHORS
|
||||
|
||||
Maintained by Alex Schroeder <alex@gnu.org>.
|
||||
|
||||
81
man_cmd.go
81
man_cmd.go
@@ -1,81 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"embed"
|
||||
"fmt"
|
||||
"flag"
|
||||
"io"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/google/subcommands"
|
||||
)
|
||||
|
||||
type manCmd struct {
|
||||
}
|
||||
|
||||
func (cmd *manCmd) SetFlags(f *flag.FlagSet) {
|
||||
}
|
||||
|
||||
func (*manCmd) Name() string { return "man" }
|
||||
func (*manCmd) Synopsis() string { return "show a manual page" }
|
||||
func (*manCmd) Usage() string {
|
||||
return `man <topic>:
|
||||
Print a manual page on a topic. If no topic is given, the
|
||||
available topics are listed. Substrings are possible.
|
||||
`
|
||||
}
|
||||
|
||||
// A filesystem with a read-only copy of the man pages at build time.
|
||||
//
|
||||
//go:embed man/*.txt
|
||||
var manFiles embed.FS
|
||||
|
||||
func (cmd *manCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
|
||||
topic := strings.Join(f.Args(), " ")
|
||||
return manCli(os.Stdout, topic)
|
||||
}
|
||||
|
||||
func manCli(w io.Writer, topic string) subcommands.ExitStatus {
|
||||
entries, err := manFiles.ReadDir("man")
|
||||
if err != nil {
|
||||
fmt.Println("An error in the build resulted in unreadable manual pages:", err)
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
if (topic == "") {
|
||||
fmt.Println("Topics:")
|
||||
names := []string{}
|
||||
for _, entry := range entries {
|
||||
names = append(names, entry.Name())
|
||||
}
|
||||
slices.Sort(names)
|
||||
for _, name := range names {
|
||||
fmt.Println(name)
|
||||
}
|
||||
return subcommands.ExitSuccess
|
||||
}
|
||||
var candidate string
|
||||
for _, entry := range entries {
|
||||
name := entry.Name()
|
||||
if strings.Contains(name, topic) {
|
||||
if candidate != "" {
|
||||
fmt.Printf("The topic '%s' matches both %s and %s, maybe more.\n", topic, candidate, name)
|
||||
fmt.Println("Please be more specific.")
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
candidate = name
|
||||
}
|
||||
}
|
||||
if candidate == "" {
|
||||
fmt.Printf("No manual page matching topic '%s' found\n", topic)
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
b, err := manFiles.ReadFile("man/" + candidate)
|
||||
if err != nil {
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
os.Stdout.Write(b)
|
||||
return subcommands.ExitSuccess
|
||||
}
|
||||
27
man_test.go
27
man_test.go
@@ -61,8 +61,8 @@ func TestManTemplates(t *testing.T) {
|
||||
assert.Greater(t, count, 0, "no templates were found")
|
||||
}
|
||||
|
||||
// Does oddmu-templates(5) mention all the template attributes?
|
||||
func TestManTemplateAttributes(t *testing.T) {
|
||||
// Does oddmu-templates(5) mention all the templates?
|
||||
func TestManTemplateAttributess(t *testing.T) {
|
||||
mfp := "man/oddmu-templates.5.txt"
|
||||
b, err := os.ReadFile(mfp)
|
||||
man := string(b)
|
||||
@@ -106,7 +106,7 @@ func TestManActions(t *testing.T) {
|
||||
wiki := string(b)
|
||||
count := 0
|
||||
// this doesn't match the root handler
|
||||
re := regexp.MustCompile(`mux\.HandleFunc\("(/[a-z]+/)", makeHandler\([a-z]+Handler, (true|false)(, http\.Method(Get|Post))+\)\)`)
|
||||
re := regexp.MustCompile(`\.HandleFunc\("(/[a-z]+/)", makeHandler\([a-z]+Handler, (true|false)(, http\.Method(Get|Post))+\)\)`)
|
||||
for _, match := range re.FindAllStringSubmatch(wiki, -1) {
|
||||
count++
|
||||
var path string
|
||||
@@ -122,27 +122,6 @@ func TestManActions(t *testing.T) {
|
||||
assert.Contains(t, main, "\n- _/_", "root")
|
||||
}
|
||||
|
||||
// Does oddmu(1) mention all the commands?
|
||||
func TestManCommands(t *testing.T) {
|
||||
b, err := os.ReadFile("man/oddmu.1.txt")
|
||||
assert.NoError(t, err)
|
||||
main := string(b)
|
||||
b, err = os.ReadFile("wiki.go")
|
||||
assert.NoError(t, err)
|
||||
wiki := string(b)
|
||||
count := 0
|
||||
re := regexp.MustCompile(`subcommands\.Register\(&([a-z]+)Cmd`)
|
||||
for _, match := range re.FindAllStringSubmatch(wiki, -1) {
|
||||
count++
|
||||
command := match[1]
|
||||
ref := "_oddmu-" + command + "_(1)"
|
||||
assert.Contains(t, main, ref, "link to the '%s' command", command)
|
||||
}
|
||||
assert.Greater(t, count, 0, "no commands were found")
|
||||
// root handler is manual
|
||||
assert.Contains(t, main, "\n- _/_", "root")
|
||||
}
|
||||
|
||||
// Does the README link to all the man pages and all the Go source files,
|
||||
// excluding the command and test files?
|
||||
func TestReadme(t *testing.T) {
|
||||
|
||||
@@ -77,7 +77,7 @@ func searchCli(w io.Writer, cmd *searchCmd, args []string) subcommands.ExitStatu
|
||||
case cmd.files:
|
||||
for _, p := range items {
|
||||
name := filepath.FromSlash(p.Name) + ".md\n"
|
||||
fmt.Fprint(w, name)
|
||||
fmt.Fprintf(w, name)
|
||||
}
|
||||
default:
|
||||
for _, p := range items {
|
||||
|
||||
14
sitemap.go
14
sitemap.go
@@ -1,20 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// SitemapURL is a URL of the sitemap.
|
||||
type SitemapURL struct {
|
||||
// Loc is the actual location.
|
||||
Loc string
|
||||
}
|
||||
|
||||
// Sitemap is the sitemap itself, containing a list of URLs.
|
||||
type Sitemap struct {
|
||||
URL []*SitemapURL
|
||||
}
|
||||
@@ -25,12 +21,8 @@ func sitemapHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/sitemap.xml" {
|
||||
http.NotFound(w, r)
|
||||
} else {
|
||||
w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>` + "\n"))
|
||||
scheme := "http"
|
||||
if r.TLS != nil {
|
||||
scheme += "s"
|
||||
}
|
||||
base := fmt.Sprintf("%s://%s/view/", scheme, r.Host)
|
||||
w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>`))
|
||||
base := r.URL.Scheme + "://" + r.URL.Host + "/view/"
|
||||
filter := os.Getenv("ODDMU_FILTER")
|
||||
renderTemplate(w, ".", "sitemap", sitemap(&index, base, filter))
|
||||
}
|
||||
@@ -48,7 +40,7 @@ func sitemap(idx *indexStore, base, filter string) Sitemap {
|
||||
idx.RLock()
|
||||
defer idx.RUnlock()
|
||||
for name := range idx.titles {
|
||||
if filter == "" || !re.MatchString(name) {
|
||||
if !re.MatchString(name) {
|
||||
url = append(url, &SitemapURL{Loc: base + name})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"flag"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
type sitemapCmd struct {
|
||||
base string
|
||||
base string
|
||||
filter string
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ func (cmd *sitemapCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interfac
|
||||
// is important so that test code can ensure no other test running in parallel can interfere with the list of known
|
||||
// pages (by adding or deleting pages).
|
||||
func sitemapCli(w io.Writer, idx *indexStore, base, filter string) subcommands.ExitStatus {
|
||||
initTemplates()
|
||||
loadTemplates()
|
||||
template := "sitemap.html"
|
||||
t := templates.template[template]
|
||||
if t == nil {
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<meta name="generator" content="Oddμ <https://src.alexschroeder.ch/oddmu.git/>"/>
|
||||
<title>{{.Title}}</title>
|
||||
<style>
|
||||
html { max-width: 65ch; padding: 1ch; margin: auto; color: #111; background-color: #ffe }
|
||||
|
||||
@@ -24,9 +24,6 @@ import (
|
||||
"github.com/google/subcommands"
|
||||
)
|
||||
|
||||
var shrinkWidth = 800
|
||||
var shrinkQuality = 30
|
||||
|
||||
type staticCmd struct {
|
||||
jobs int
|
||||
shrink bool
|
||||
@@ -72,7 +69,7 @@ func staticCli(source, target string, jobs int, glob string, shrink, verbose, qu
|
||||
index.RLock()
|
||||
defer index.RUnlock()
|
||||
loadLanguages()
|
||||
initTemplates()
|
||||
loadTemplates()
|
||||
tasks := make(chan args, 10000)
|
||||
results := make(chan error, jobs)
|
||||
done := make(chan bool, jobs)
|
||||
@@ -262,6 +259,9 @@ func staticFile(source, target string, info fs.FileInfo, shrink bool) error {
|
||||
return err
|
||||
}
|
||||
|
||||
var shrinkWidth = 800
|
||||
var shrinkQuality = 10
|
||||
|
||||
// shrink Image shrinks images down and reduces the quality dramatically.
|
||||
func shrinkImage(source, target string, info fs.FileInfo) error {
|
||||
file, err := os.Open(source)
|
||||
|
||||
61
templates.go
61
templates.go
@@ -1,80 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"html/template"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// A filesystem with a read-only copy of the templates at build time.
|
||||
//
|
||||
//go:embed *.html
|
||||
var templateDefaults embed.FS
|
||||
|
||||
// templateFiles are the various HTML template files used. These files must exist in the root directory for Oddmu
|
||||
// to be able to generate HTML output. This always requires a template.
|
||||
var templateFiles = []string{}
|
||||
var templateFiles = []string{"edit.html", "add.html", "view.html", "preview.html",
|
||||
"diff.html", "search.html", "static.html", "upload.html", "feed.html",
|
||||
"sitemap.html"}
|
||||
|
||||
// templateStore controls access to the map of parsed HTML templates. Make sure to lock and unlock as appropriate.
|
||||
// See renderTemplate and loadTemplates.
|
||||
// templateStore controls access to map of parsed HTML templates. Make sure to lock and unlock as appropriate. See
|
||||
// renderTemplate and loadTemplates.
|
||||
type templateStore struct {
|
||||
sync.RWMutex
|
||||
|
||||
// template is a map of parsed HTML templates. The key is their filepath name. By default, the map only
|
||||
// contains top-level templates like "view.html". Subdirectories may contain their own templates which
|
||||
// override the templates in the root directory. If so, they are filepaths like "dir/view.html". This is a
|
||||
// map because we need to add and remove templates as time passes.
|
||||
// template is a map of parsed HTML templates. The key is their filepath name. By default, the map only contains
|
||||
// top-level templates like "view.html". Subdirectories may contain their own templates which override the
|
||||
// templates in the root directory. If so, they are filepaths like "dir/view.html".
|
||||
template map[string]*template.Template
|
||||
}
|
||||
|
||||
var templates templateStore
|
||||
|
||||
// initTemplates loads the templates and writes them to disk if they are missing. If templates have already been
|
||||
// loaded, return immediately.
|
||||
func initTemplates() {
|
||||
// loadTemplates loads the templates. If templates have already been loaded, return immediately.
|
||||
func loadTemplates() {
|
||||
if templates.template != nil {
|
||||
return
|
||||
}
|
||||
templates.Lock()
|
||||
defer templates.Unlock()
|
||||
templates.template = make(map[string]*template.Template)
|
||||
// load the defaults and make a list of the default names
|
||||
entries, err := templateDefaults.ReadDir(".")
|
||||
if err != nil {
|
||||
log.Println("An error in the build resulted in unreadable default templates:", err)
|
||||
}
|
||||
// if loading or parsing fails, continue as perhaps the files exist in the file-system
|
||||
for _, entry := range entries {
|
||||
name := entry.Name()
|
||||
templateFiles = append(templateFiles, name)
|
||||
b, err := fs.ReadFile(templateDefaults, name)
|
||||
if err != nil {
|
||||
log.Printf("Cannot read built-in default template %s: %s\n", name, err)
|
||||
continue
|
||||
}
|
||||
t := template.New(name)
|
||||
templates.template[name], err = t.Parse(string(b))
|
||||
if err != nil {
|
||||
log.Printf("Cannot parse built-in default template %s: %s\n", name, err)
|
||||
}
|
||||
_, err = os.Stat(name)
|
||||
if err != nil {
|
||||
err = os.WriteFile(name, b, 0644)
|
||||
if err == nil {
|
||||
log.Printf("Wrote built-in default template %s\n", name)
|
||||
} else {
|
||||
log.Printf("Cannot write built-in default template %s: %s\n", name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
// walk the directory, load templates and add directories
|
||||
templates.template = make(map[string]*template.Template)
|
||||
filepath.Walk(".", loadTemplate)
|
||||
log.Println(len(templates.template), "templates loaded")
|
||||
}
|
||||
@@ -90,6 +54,7 @@ func loadTemplate(fp string, info fs.FileInfo, err error) error {
|
||||
t, err := template.ParseFiles(fp)
|
||||
if err != nil {
|
||||
log.Println("Cannot parse template:", fp, err)
|
||||
// ignore error
|
||||
} else {
|
||||
templates.template[fp] = t
|
||||
}
|
||||
@@ -127,7 +92,7 @@ func removeTemplate(fp string) {
|
||||
// renderTemplate is the helper that is used to render the templates with data.
|
||||
// A template in the same directory is preferred, if it exists.
|
||||
func renderTemplate(w http.ResponseWriter, dir, tmpl string, data any) {
|
||||
initTemplates()
|
||||
loadTemplates()
|
||||
base := tmpl + ".html"
|
||||
templates.RLock()
|
||||
defer templates.RUnlock()
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
|
||||
<meta name="generator" content="Oddμ <https://src.alexschroeder.ch/oddmu.git/>"/>
|
||||
<title>{{.Title}}</title>
|
||||
<style>
|
||||
html { max-width: 70ch; padding: 1ch; margin: auto; color: #111; background-color: #ffe }
|
||||
|
||||
3
wiki.go
3
wiki.go
@@ -208,7 +208,7 @@ func serve() {
|
||||
mux.HandleFunc("/upload/", makeHandler(uploadHandler, false, http.MethodGet))
|
||||
mux.HandleFunc("/drop/", makeHandler(dropHandler, false, http.MethodPost))
|
||||
mux.HandleFunc("/search/", makeHandler(searchHandler, false, http.MethodGet, http.MethodPost))
|
||||
mux.HandleFunc("/sitemap.xml", sitemapHandler)
|
||||
mux.HandleFunc("/sitemap", sitemapHandler)
|
||||
srv := &http.Server{
|
||||
ReadTimeout: 2 * time.Minute,
|
||||
WriteTimeout: 5 * time.Minute,
|
||||
@@ -230,7 +230,6 @@ func commands() {
|
||||
subcommands.Register(&exportCmd{}, "")
|
||||
subcommands.Register(&hashtagsCmd{}, "")
|
||||
subcommands.Register(&feedCmd{}, "")
|
||||
subcommands.Register(&manCmd{}, "")
|
||||
subcommands.Register(&htmlCmd{}, "")
|
||||
subcommands.Register(&listCmd{}, "")
|
||||
subcommands.Register(&linksCmd{}, "")
|
||||
|
||||
Reference in New Issue
Block a user