{{ . }}
++ The hypha you are trying to access does not exist yet. Why not create it? +
+diff --git a/README.md b/README.md index 7a7d6d8..d96bdff 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,6 @@ # mycorrhiza wiki -Simple wiki engine inspired by fungi. +A wiki engine inspired by fungi. + +Current version: 0.5. + +Not production-ready. diff --git a/cfg/config.go b/cfg/config.go index 348d8d9..88ea94a 100644 --- a/cfg/config.go +++ b/cfg/config.go @@ -8,17 +8,23 @@ import ( "path/filepath" ) +type MyceliumConfig struct { + Names []string `json:"names"` + Type string `json:"type"` +} + const ( HyphaPattern = `[^\s\d:/?&\\][^:?&\\]*` HyphaUrl = `/{hypha:` + HyphaPattern + `}` RevisionPattern = `[\d]+` RevQuery = `{rev:` + RevisionPattern + `}` + MyceliumPattern = `:` + HyphaPattern + MyceliumUrl = `/{mycelium:` + MyceliumPattern + `}` ) var ( DescribeHyphaHerePattern = "Describe %s here" WikiDir string - TemplatesDir string configJsonPath string // Default values that can be overriden in config.json @@ -28,13 +34,16 @@ var ( GenericErrorMsg = `Sorry, something went wrong` SiteTitle = `MycorrhizaWiki` Theme = `default-light` + Mycelia = []MyceliumConfig{ + {[]string{"main"}, "main"}, + {[]string{"sys", "system"}, "system"}, + } ) func InitConfig(wd string) bool { log.Println("WikiDir is", wd) WikiDir = wd - TemplatesDir = "Templates" - configJsonPath = filepath.Join(filepath.Dir(WikiDir), "config.json") + configJsonPath = filepath.Join(WikiDir, "config.json") if _, err := os.Stat(configJsonPath); os.IsNotExist(err) { log.Println("config.json not found, using default values") @@ -52,9 +61,10 @@ func readConfig() bool { } cfg := struct { - Address string `json:"address"` - Theme string `json:"theme"` - SiteTitle string `json:"site-title"` + Address string `json:"address"` + Theme string `json:"theme"` + SiteTitle string `json:"site-title"` + Mycelia []MyceliumConfig `json:"mycelia"` TitleTemplates struct { EditHypha string `json:"edit-hypha"` ViewHypha string `json:"view-hypha"` @@ -72,6 +82,7 @@ func readConfig() bool { SiteTitle = cfg.SiteTitle TitleEditTemplate = cfg.TitleTemplates.EditHypha TitleTemplate = cfg.TitleTemplates.ViewHypha + Mycelia = cfg.Mycelia return true } diff --git a/fs/data.go b/fs/data.go index 5c88f4a..58b7264 100644 --- a/fs/data.go +++ b/fs/data.go @@ -17,8 +17,12 @@ func (h *Hypha) MetaJsonPath() string { return filepath.Join(h.Path(), "meta.json") } +func (h *Hypha) CanonicalName() string { + return util.UrlToCanonical(h.FullName) +} + func (h *Hypha) Path() string { - return filepath.Join(cfg.WikiDir, util.UrlToCanonical(h.FullName)) + return filepath.Join(cfg.WikiDir, h.CanonicalName()) } func (h *Hypha) TextPath() string { diff --git a/fs/hypha.go b/fs/hypha.go index 20f0255..762955a 100644 --- a/fs/hypha.go +++ b/fs/hypha.go @@ -12,7 +12,6 @@ import ( "strings" "time" - "github.com/bouncepaw/mycorrhiza/cfg" "github.com/bouncepaw/mycorrhiza/util" ) @@ -23,8 +22,8 @@ type Hypha struct { Deleted bool `json:"deleted"` Revisions map[string]*Revision `json:"revisions"` actual *Revision `json:"-"` - Invalid bool - Err error + Invalid bool `json:"-"` + Err error `json:"-"` } func (h *Hypha) Invalidate(err error) *Hypha { @@ -183,7 +182,7 @@ func (h *Hypha) CreateDirIfNeeded() *Hypha { return h } // os.MkdirAll created dir if it is not there. Basically, checks it for us. - err := os.MkdirAll(filepath.Join(cfg.WikiDir, h.FullName), os.ModePerm) + err := os.MkdirAll(h.Path(), os.ModePerm) if err != nil { h.Invalidate(err) } @@ -315,7 +314,7 @@ func (h *Hypha) SaveJson() *Hypha { // Store adds `h` to the `Hs` if it is not already there func (h *Hypha) Store() *Hypha { if !h.Invalid { - Hs.paths[h.FullName] = h.Path() + Hs.paths[h.CanonicalName()] = h.Path() } return h } diff --git a/fs/mycelium.go b/fs/mycelium.go new file mode 100644 index 0000000..7f87960 --- /dev/null +++ b/fs/mycelium.go @@ -0,0 +1,56 @@ +package fs + +import ( + "io/ioutil" + "log" + + "github.com/bouncepaw/mycorrhiza/cfg" +) + +var ( + MainMycelium string + SystemMycelium string +) + +func gatherDirNames(path string) map[string]struct{} { + res := make(map[string]struct{}) + nodes, err := ioutil.ReadDir(path) + if err != nil { + log.Fatal(err) + } + for _, node := range nodes { + if node.IsDir() { + res[node.Name()] = struct{}{} + } + } + return res +} + +func VerifyMycelia() { + var ( + dirs = gatherDirNames(cfg.WikiDir) + mainPresent bool + systemPresent bool + ) + for _, mycelium := range cfg.Mycelia { + switch mycelium.Type { + case "main": + mainPresent = true + MainMycelium = mycelium.Names[0] + case "system": + systemPresent = true + SystemMycelium = mycelium.Names[0] + } + // Check if there is a dir corresponding to the mycelium + if _, ok := dirs[mycelium.Names[0]]; !ok { + log.Fatal("No directory found for mycelium " + mycelium.Names[0]) + } + } + if !mainPresent { + log.Fatal("No `main` mycelium given in config.json") + } + if !systemPresent { + log.Fatal("No `system` mycelium given in config.json") + } + log.Println("Mycelial dirs are present") +} diff --git a/main.go b/main.go index 215646c..baf04d9 100644 --- a/main.go +++ b/main.go @@ -22,6 +22,25 @@ func RevInMap(m map[string]string) string { return "0" } +func IdempotentRouterBoiler(router *mux.Router, action string, handler func(w http.ResponseWriter, rq *http.Request)) { + router. + Queries("action", action, "rev", cfg.RevQuery). + Path(cfg.MyceliumUrl + cfg.HyphaUrl). + HandlerFunc(handler) + router. + Queries("action", action). + Path(cfg.MyceliumUrl + cfg.HyphaUrl). + HandlerFunc(handler) + router. + Queries("action", action, "rev", cfg.RevQuery). + Path(cfg.HyphaUrl). + HandlerFunc(handler) + router. + Queries("action", action). + Path(cfg.HyphaUrl). + HandlerFunc(handler) +} + func main() { if len(os.Args) == 1 { panic("Expected a root wiki pages directory") @@ -34,6 +53,7 @@ func main() { log.Println("Welcome to MycorrhizaWiki α") cfg.InitConfig(wikiDir) log.Println("Indexing hyphae...") + fs.VerifyMycelia() fs.InitStorage() // Start server code. See handlers.go for handlers' implementations. @@ -43,31 +63,20 @@ func main() { http.ServeFile(w, rq, filepath.Join(filepath.Dir(cfg.WikiDir), "favicon.ico")) }) - r.Queries("action", "binary", "rev", cfg.RevQuery).Path(cfg.HyphaUrl). - HandlerFunc(HandlerBinary) - r.Queries("action", "binary").Path(cfg.HyphaUrl). - HandlerFunc(HandlerBinary) - - r.Queries("action", "raw", "rev", cfg.RevQuery).Path(cfg.HyphaUrl). - HandlerFunc(HandlerRaw) - r.Queries("action", "raw").Path(cfg.HyphaUrl). - HandlerFunc(HandlerRaw) - - r.Queries("action", "zen", "rev", cfg.RevQuery).Path(cfg.HyphaUrl). - HandlerFunc(HandlerZen) - r.Queries("action", "zen").Path(cfg.HyphaUrl). - HandlerFunc(HandlerZen) - - r.Queries("action", "view", "rev", cfg.RevQuery).Path(cfg.HyphaUrl). - HandlerFunc(HandlerView) - r.Queries("action", "view").Path(cfg.HyphaUrl). - HandlerFunc(HandlerView) + IdempotentRouterBoiler(r, "binary", HandlerBinary) + IdempotentRouterBoiler(r, "raw", HandlerRaw) + IdempotentRouterBoiler(r, "zen", HandlerZen) + IdempotentRouterBoiler(r, "view", HandlerView) + r.Queries("action", "edit").Path(cfg.MyceliumUrl + cfg.HyphaUrl). + HandlerFunc(HandlerEdit) r.Queries("action", "edit").Path(cfg.HyphaUrl). HandlerFunc(HandlerEdit) - r.Queries("action", "update").Path(cfg.HyphaUrl).Methods("POST"). - HandlerFunc(HandlerUpdate) + r.Queries("action", "update").Path(cfg.MyceliumUrl + cfg.HyphaUrl). + Methods("POST").HandlerFunc(HandlerUpdate) + r.Queries("action", "update").Path(cfg.HyphaUrl). + Methods("POST").HandlerFunc(HandlerUpdate) r.HandleFunc(cfg.HyphaUrl, HandlerView) diff --git a/render/render.go b/render/render.go index 3ae982c..4e33f38 100644 --- a/render/render.go +++ b/render/render.go @@ -85,7 +85,7 @@ type Layout struct { } func layout(name string) *Layout { - h := fs.Hs.Open(path.Join(cfg.TemplatesDir, cfg.Theme, name+".html")).OnRevision("0") + h := fs.Hs.Open(path.Join(fs.SystemMycelium, "theme", cfg.Theme, name+".html")).OnRevision("0") if h.Invalid { return &Layout{nil, nil, true, h.Err} } diff --git a/w/config.json b/w/config.json deleted file mode 100644 index 409bcd2..0000000 --- a/w/config.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "address": "127.0.0.1:1737", - "theme": "default-light", - "site-title": "🍄 MycorrhizaWiki", - "title-templates": { - "edit-hypha": "Edit %s at MycorrhizaWiki", - "view-hypha": "%s at MycorrhizaWiki" - } -} diff --git a/w/m/templates/default-light/view/404.html/1.html b/w/m/templates/default-light/view/404.html/1.html deleted file mode 100644 index e7a14c5..0000000 --- a/w/m/templates/default-light/view/404.html/1.html +++ /dev/null @@ -1,4 +0,0 @@ -
-The hypha you are trying to access does not exist yet. Why not create it? -
diff --git a/w/README.md b/wiki/README.md similarity index 100% rename from w/README.md rename to wiki/README.md diff --git a/wiki/config.json b/wiki/config.json new file mode 100644 index 0000000..2f2abee --- /dev/null +++ b/wiki/config.json @@ -0,0 +1,31 @@ +{ + "address": "127.0.0.1:1737", + "theme": "default-light", + "site-title": "🍄 MycorrhizaWiki", + "title-templates": { + "edit-hypha": "Edit %s at MycorrhizaWiki", + "view-hypha": "%s at MycorrhizaWiki" + }, + "mycelia": [ + { + "names": ["main"], + "type": "main" + }, + { + "names": ["sys", "system"], + "type": "system" + }, + { + "names": ["spec", "special"], + "type": "special" + }, + { + "names": ["user","u"], + "type": "user" + }, + { + "names": ["tag", "t"], + "type": "tag" + } + ] +} diff --git a/w/favicon.ico b/wiki/favicon.ico similarity index 100% rename from w/favicon.ico rename to wiki/favicon.ico diff --git a/w/m/README.md b/wiki/main/README.md similarity index 100% rename from w/m/README.md rename to wiki/main/README.md diff --git a/w/m/fruit/1.md b/wiki/main/fruit/1.md similarity index 100% rename from w/m/fruit/1.md rename to wiki/main/fruit/1.md diff --git a/w/m/fruit/2.md b/wiki/main/fruit/2.md similarity index 100% rename from w/m/fruit/2.md rename to wiki/main/fruit/2.md diff --git a/w/m/fruit/3.markdown b/wiki/main/fruit/3.markdown similarity index 100% rename from w/m/fruit/3.markdown rename to wiki/main/fruit/3.markdown diff --git a/w/m/fruit/4.markdown b/wiki/main/fruit/4.markdown similarity index 100% rename from w/m/fruit/4.markdown rename to wiki/main/fruit/4.markdown diff --git a/w/m/fruit/5.markdown b/wiki/main/fruit/5.markdown similarity index 100% rename from w/m/fruit/5.markdown rename to wiki/main/fruit/5.markdown diff --git a/w/m/fruit/apple/1.jpg b/wiki/main/fruit/apple/1.jpg similarity index 100% rename from w/m/fruit/apple/1.jpg rename to wiki/main/fruit/apple/1.jpg diff --git a/w/m/fruit/apple/1.txt b/wiki/main/fruit/apple/1.txt similarity index 100% rename from w/m/fruit/apple/1.txt rename to wiki/main/fruit/apple/1.txt diff --git a/w/m/fruit/apple/2.jpg b/wiki/main/fruit/apple/2.jpg similarity index 100% rename from w/m/fruit/apple/2.jpg rename to wiki/main/fruit/apple/2.jpg diff --git a/w/m/fruit/apple/2.txt b/wiki/main/fruit/apple/2.txt similarity index 100% rename from w/m/fruit/apple/2.txt rename to wiki/main/fruit/apple/2.txt diff --git a/w/m/fruit/apple/3.txt b/wiki/main/fruit/apple/3.txt similarity index 100% rename from w/m/fruit/apple/3.txt rename to wiki/main/fruit/apple/3.txt diff --git a/w/m/fruit/apple/4.jpg b/wiki/main/fruit/apple/4.jpg similarity index 100% rename from w/m/fruit/apple/4.jpg rename to wiki/main/fruit/apple/4.jpg diff --git a/w/m/fruit/apple/4.txt b/wiki/main/fruit/apple/4.txt similarity index 100% rename from w/m/fruit/apple/4.txt rename to wiki/main/fruit/apple/4.txt diff --git a/w/m/fruit/apple/meta.json b/wiki/main/fruit/apple/meta.json similarity index 100% rename from w/m/fruit/apple/meta.json rename to wiki/main/fruit/apple/meta.json diff --git a/w/m/fruit/meta.json b/wiki/main/fruit/meta.json similarity index 100% rename from w/m/fruit/meta.json rename to wiki/main/fruit/meta.json diff --git a/w/m/fruit/pear/1.markdown b/wiki/main/fruit/pear/1.markdown similarity index 100% rename from w/m/fruit/pear/1.markdown rename to wiki/main/fruit/pear/1.markdown diff --git a/w/m/fruit/pear/meta.json b/wiki/main/fruit/pear/meta.json similarity index 100% rename from w/m/fruit/pear/meta.json rename to wiki/main/fruit/pear/meta.json diff --git a/w/m/fruit/pineapple/1.html b/wiki/main/fruit/pineapple/1.html similarity index 100% rename from w/m/fruit/pineapple/1.html rename to wiki/main/fruit/pineapple/1.html diff --git a/w/m/fruit/pineapple/meta.json b/wiki/main/fruit/pineapple/meta.json similarity index 100% rename from w/m/fruit/pineapple/meta.json rename to wiki/main/fruit/pineapple/meta.json diff --git a/w/m/fungus/1.markdown b/wiki/main/fungus/1.markdown similarity index 100% rename from w/m/fungus/1.markdown rename to wiki/main/fungus/1.markdown diff --git a/w/m/fungus/amanita_muscaria/1.markdown b/wiki/main/fungus/amanita_muscaria/1.markdown similarity index 100% rename from w/m/fungus/amanita_muscaria/1.markdown rename to wiki/main/fungus/amanita_muscaria/1.markdown diff --git a/w/m/fungus/amanita_muscaria/2.markdown b/wiki/main/fungus/amanita_muscaria/2.markdown similarity index 100% rename from w/m/fungus/amanita_muscaria/2.markdown rename to wiki/main/fungus/amanita_muscaria/2.markdown diff --git a/w/m/fungus/amanita_muscaria/3.markdown b/wiki/main/fungus/amanita_muscaria/3.markdown similarity index 100% rename from w/m/fungus/amanita_muscaria/3.markdown rename to wiki/main/fungus/amanita_muscaria/3.markdown diff --git a/w/m/fungus/amanita_muscaria/4.markdown b/wiki/main/fungus/amanita_muscaria/4.markdown similarity index 100% rename from w/m/fungus/amanita_muscaria/4.markdown rename to wiki/main/fungus/amanita_muscaria/4.markdown diff --git a/w/m/fungus/amanita_muscaria/meta.json b/wiki/main/fungus/amanita_muscaria/meta.json similarity index 100% rename from w/m/fungus/amanita_muscaria/meta.json rename to wiki/main/fungus/amanita_muscaria/meta.json diff --git a/w/m/fungus/amanita_regalis/1.jpeg b/wiki/main/fungus/amanita_regalis/1.jpeg similarity index 100% rename from w/m/fungus/amanita_regalis/1.jpeg rename to wiki/main/fungus/amanita_regalis/1.jpeg diff --git a/w/m/fungus/amanita_regalis/1.markdown b/wiki/main/fungus/amanita_regalis/1.markdown similarity index 100% rename from w/m/fungus/amanita_regalis/1.markdown rename to wiki/main/fungus/amanita_regalis/1.markdown diff --git a/w/m/fungus/amanita_regalis/meta.json b/wiki/main/fungus/amanita_regalis/meta.json similarity index 100% rename from w/m/fungus/amanita_regalis/meta.json rename to wiki/main/fungus/amanita_regalis/meta.json diff --git a/w/m/fungus/meta.json b/wiki/main/fungus/meta.json similarity index 100% rename from w/m/fungus/meta.json rename to wiki/main/fungus/meta.json diff --git a/w/m/help/1.markdown b/wiki/main/help/1.markdown similarity index 100% rename from w/m/help/1.markdown rename to wiki/main/help/1.markdown diff --git a/w/m/help/meta.json b/wiki/main/help/meta.json similarity index 100% rename from w/m/help/meta.json rename to wiki/main/help/meta.json diff --git a/wiki/main/help/mycelia/1.markdown b/wiki/main/help/mycelia/1.markdown new file mode 100644 index 0000000..b86210e --- /dev/null +++ b/wiki/main/help/mycelia/1.markdown @@ -0,0 +1,85 @@ +In MycorrhizaWiki **mycelia** are used to organize [hyphae](hyphae) in related namespaces. + +## Mycelium traits +- Every mycelium has any number (0..∞) of hyphae. +- Every hypha is part of one mycelium. +- Every mycelium has one canonical name and any number of synonyms. +- Every wiki has one main mycelium. +- They are named by the same scheme as hyphae but they have a colon prefix. + +## Mycelium URL +- Address a hypha in a particular mycelium: `/:sys/about`. +- Address subpage of the hypha above: `/:sys/about/more` +- Address a hypha in the main mycelium: `/How/does it work`. +- Address a hypha in the main mycelium explicitly: `/:main/How/does it work`. + +## Mycelium configuration +In your `config.json`, in `"mycelia"` field there is an array of objects. + +``` +{ + ... + "mycelia": [ + { + "names": ["main"], + "type": "main" + }, + { + "names": ["sys", "system"], + "type": "system" + }, + { + "names": ["spec", "special"], + "type": "special" + }, + { + "names": ["user","u"], + "type": "user" + }, + { + "names": ["tag", "t"], + "type": "tag" + } + ] + ... +} +``` + +Each object reprents a mycelium. You can set all their names there. First name in each `"names"` array is a canonical name for the mycelium. + +Field `"type"` sets the mycelium's type. There are such types: + +| **Type** | **Description** | +| `main` | The main mycelium. There must be exactly one such mycelium in a wiki. | +| `system` | Things like scripts, styles and templates go here. There must be exactly one such mycelium in a wiki. | +| `special` | Things like utility hyphae and plugin pages go here. It is optional because there are no hyphae or plugins now. | +| `user` | Userpages. It is optional because there are no users now. | +| `tag` | Pages describing tags. It is optional because there are no tags now. | +| `other` | Mycelia without any additional meaning added by the engine. There can be any number of them. | + +## How are they stored in the filesystem. +For example, `wiki` is your wiki directory and you have configured the mycelia like in the example above. You should have structure like that: + +``` +wiki/ + config.json ← your configuration + favicon.ico ← your site icon + main/ ← :main,+ The hypha you are trying to access does not exist yet. Why not create it? +
+