1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2025-09-13 00:06:06 +00:00

Config auto-creation, update port from arguments

This commit is contained in:
handlerug
2021-06-19 23:48:54 +07:00
parent 235fba5007
commit 317e3a2049
4 changed files with 87 additions and 52 deletions

View File

@@ -2,16 +2,18 @@
package cfg package cfg
import ( import (
"errors"
"log" "log"
"path/filepath" "os"
"strconv" "strconv"
"github.com/go-ini/ini" "github.com/go-ini/ini"
) )
// These variables represent the configuration. You are not meant to modify them after they were set. // These variables represent the configuration. You are not meant to modify
// // them after they were set.
// See https://mycorrhiza.lesarbr.es/hypha/configuration/fields for their docs. // See https://mycorrhiza.lesarbr.es/hypha/configuration/fields for the
// documentation.
var ( var (
WikiName string WikiName string
NaviTitleIcon string NaviTitleIcon string
@@ -33,60 +35,59 @@ var (
EditScripts []string EditScripts []string
) )
// These variables are set before reading the config file, they are set in main.parseCliArgs. // WikiDir is a full path to the wiki storage directory, which also must be a
var ( // git repo. This variable is set in parseCliArgs().
// WikiDir is a full path to the wiki storage directory, which also must be a git repo. var WikiDir string
WikiDir string
// ConfigFilePath is a path to the config file. Its value is used when calling ReadConfigFile.
ConfigFilePath string
)
// Config represents a Mycorrhiza wiki configuration file. This type is used only when reading configs. // Config represents a Mycorrhiza wiki configuration file. This type is used
// only when reading configs.
type Config struct { type Config struct {
WikiName string WikiName string `comment:"This name appears in the header and on various pages."`
NaviTitleIcon string NaviTitleIcon string `comment:"This icon is used in the breadcrumbs bar."`
Hyphae Hyphae
Network Network
Authorization Authorization `comment:""`
CustomScripts CustomScripts `comment:"You can specify additional scripts to load on different kinds of pages, delimited by a comma ',' sign."`
} }
// Hyphae is a section of Config which has fields related to special hyphae. // Hyphae is a section of Config which has fields related to special hyphae.
type Hyphae struct { type Hyphae struct {
HomeHypha string HomeHypha string `comment:"This hypha will be the main (index) page of your wiki, served on /."`
UserHypha string UserHypha string `comment:"This hypha is used as a prefix for user hyphae."`
HeaderLinksHypha string HeaderLinksHypha string `comment:"You can also specify a hypha to populate your own custom header links from."`
} }
// Network is a section of Config that has fields related to network stuff: HTTP and Gemini. // Network is a section of Config that has fields related to network stuff:
// HTTP and Gemini.
type Network struct { type Network struct {
HTTPPort uint64 HTTPPort uint64
URL string URL string `comment:"Set your wiki's public URL here. It's used for OpenGraph generation and syndication feeds."`
GeminiCertificatePath string GeminiCertificatePath string `comment:"Gemini requires servers to use TLS for client connections. Specify your certificate's path here."`
} }
// CustomScripts is a section with paths to JavaScript files that are loaded on specified pages. // CustomScripts is a section with paths to JavaScript files that are loaded on
// specified pages.
type CustomScripts struct { type CustomScripts struct {
// OmnipresentScripts: everywhere... // OmnipresentScripts: everywhere...
OmnipresentScripts []string `delim:","` OmnipresentScripts []string `delim:"," comment:"These scripts are loaded from anywhere."`
// ViewScripts: /hypha, /rev // ViewScripts: /hypha, /rev
ViewScripts []string `delim:","` ViewScripts []string `delim:"," comment:"These scripts are only loaded on view pages."`
// Edit: /edit // Edit: /edit
EditScripts []string `delim:","` EditScripts []string `delim:"," comment:"These scripts are only loaded on the edit page."`
} }
// Authorization is a section of Config that has fields related to authorization and authentication. // Authorization is a section of Config that has fields related to
// authorization and authentication.
type Authorization struct { type Authorization struct {
UseFixedAuth bool UseFixedAuth bool
UseRegistration bool UseRegistration bool
LimitRegistration uint64 LimitRegistration uint64 `comment:"This field controls the maximum amount of allowed registrations."`
} }
// ReadConfigFile reads a config on the given path and stores the configuration. Call it sometime during the initialization. // ReadConfigFile reads a config on the given path and stores the
// // configuration. Call it sometime during the initialization.
// Note that it may log.Fatal. // Note that it may call log.Fatal, which terminates the program.
func ReadConfigFile() { func ReadConfigFile(path string) {
cfg := &Config{ cfg := &Config{
WikiName: "Mycorrhiza Wiki", WikiName: "Mycorrhiza Wiki",
NaviTitleIcon: "🍄", NaviTitleIcon: "🍄",
@@ -102,7 +103,6 @@ func ReadConfigFile() {
}, },
Authorization: Authorization{ Authorization: Authorization{
UseFixedAuth: false, UseFixedAuth: false,
UseRegistration: false, UseRegistration: false,
LimitRegistration: 0, LimitRegistration: 0,
}, },
@@ -113,16 +113,47 @@ func ReadConfigFile() {
}, },
} }
if ConfigFilePath != "" { dirty := false
path, err := filepath.Abs(ConfigFilePath)
f, err := ini.Load(path)
if err != nil { if err != nil {
log.Fatalf("cannot expand config file path: %s", err) if errors.Is(err, os.ErrNotExist) {
f = ini.Empty()
dirty = true
} else {
log.Fatal("Failed to parse the config file:", err)
}
} }
log.Println("Loading config at", path) // Map the config file to the config struct. It'll do nothing if the file
err = ini.MapTo(cfg, path) // doesn't exist or is empty.
f.MapTo(cfg)
// Update the port if it's set externally and is different from what's in
// the config file
if HTTPPort != "" && HTTPPort != strconv.FormatUint(cfg.Network.HTTPPort, 10) {
port, err := strconv.ParseUint(HTTPPort, 10, 64)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal("Failed to parse the port from command-line arguments:", err)
}
cfg.Network.HTTPPort = port
dirty = true
}
// Save changes, if there are any
if dirty {
err = f.ReflectFrom(cfg)
if err != nil {
log.Fatal("Failed to serialize the config:", err)
}
// Disable key-value auto-aligning, but retain spaces around '=' sign
ini.PrettyFormat = false
ini.PrettyEqual = true
if err = f.SaveTo(path); err != nil {
log.Println("Failed to save the config file:", err)
} }
} }

View File

@@ -12,6 +12,7 @@ var paths struct {
gitRepo string gitRepo string
cacheDir string cacheDir string
staticFiles string staticFiles string
configPath string
tokensJSON string tokensJSON string
registrationCredentialsJSON string registrationCredentialsJSON string
fixedCredentialsJSON string fixedCredentialsJSON string
@@ -29,6 +30,9 @@ func GitRepo() string { return paths.gitRepo }
// StaticFiles returns the path to static files directory // StaticFiles returns the path to static files directory
func StaticFiles() string { return paths.staticFiles } func StaticFiles() string { return paths.staticFiles }
// ConfigPath returns the path to the config file.
func ConfigPath() string { return paths.configPath }
// TokensJSON returns the path to the JSON user tokens storage. // TokensJSON returns the path to the JSON user tokens storage.
func TokensJSON() string { return paths.tokensJSON } func TokensJSON() string { return paths.tokensJSON }
@@ -61,6 +65,8 @@ func PrepareWikiRoot() error {
return err return err
} }
paths.configPath = filepath.Join(cfg.WikiDir, "config.ini")
paths.tokensJSON = filepath.Join(paths.cacheDir, "tokens.json") paths.tokensJSON = filepath.Join(paths.cacheDir, "tokens.json")
paths.fixedCredentialsJSON = filepath.Join(cfg.WikiDir, "fixed-users.json") paths.fixedCredentialsJSON = filepath.Join(cfg.WikiDir, "fixed-users.json")
paths.registrationCredentialsJSON = filepath.Join(paths.cacheDir, "registered-users.json") paths.registrationCredentialsJSON = filepath.Join(paths.cacheDir, "registered-users.json")

View File

@@ -19,7 +19,7 @@ var defaultConfig []byte
var printExampleConfig bool var printExampleConfig bool
func init() { func init() {
flag.StringVar(&cfg.ConfigFilePath, "config-path", "", "Path to a configuration file. Leave empty if you don't want to use it.") flag.StringVar(&cfg.HTTPPort, "port", "", "Listen on another port. This option also updates the config file for your convenience.")
flag.BoolVar(&printExampleConfig, "print-example-config", false, "If true, print an example configuration file contents and exit. You can save the output to a file and base your own configuration on it.") flag.BoolVar(&printExampleConfig, "print-example-config", false, "If true, print an example configuration file contents and exit. You can save the output to a file and base your own configuration on it.")
flag.Usage = printHelp flag.Usage = printHelp
} }

View File

@@ -22,12 +22,10 @@ import (
func main() { func main() {
parseCliArgs() parseCliArgs()
// It is ok if the path is ""
cfg.ReadConfigFile()
if err := files.PrepareWikiRoot(); err != nil { if err := files.PrepareWikiRoot(); err != nil {
log.Fatal(err) log.Fatal(err)
} }
cfg.ReadConfigFile(files.ConfigPath())
log.Println("Running Mycorrhiza Wiki 1.2.0 indev") log.Println("Running Mycorrhiza Wiki 1.2.0 indev")
if err := os.Chdir(files.HyphaeDir()); err != nil { if err := os.Chdir(files.HyphaeDir()); err != nil {