mirror of
https://github.com/osmarks/mycorrhiza.git
synced 2024-12-12 05:20:26 +00:00
158 lines
3.9 KiB
Go
158 lines
3.9 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io/ioutil"
|
|
"log"
|
|
"path/filepath"
|
|
"regexp"
|
|
)
|
|
|
|
const (
|
|
hyphaPattern = `[^\s\d:/?&\\][^:?&\\]*`
|
|
hyphaUrl = `/{hypha:` + hyphaPattern + `}`
|
|
revisionPattern = `[\d]+`
|
|
revQuery = `{rev:` + revisionPattern + `}`
|
|
revTxtPattern = revisionPattern + `\.txt`
|
|
revBinPattern = revisionPattern + `\.bin`
|
|
metaJsonPattern = `meta\.json`
|
|
)
|
|
|
|
var (
|
|
leadingInt = regexp.MustCompile(`^[-+]?\d+`)
|
|
)
|
|
|
|
func matchNameToEverything(name string) (hyphaM bool, revTxtM bool, revBinM bool, metaJsonM bool) {
|
|
simpleMatch := func(s string, p string) bool {
|
|
m, _ := regexp.MatchString(p, s)
|
|
return m
|
|
}
|
|
switch {
|
|
case simpleMatch(name, revTxtPattern):
|
|
revTxtM = true
|
|
case simpleMatch(name, revBinPattern):
|
|
revBinM = true
|
|
case simpleMatch(name, metaJsonPattern):
|
|
metaJsonM = true
|
|
case simpleMatch(name, hyphaPattern):
|
|
hyphaM = true
|
|
}
|
|
return
|
|
}
|
|
|
|
func stripLeadingInt(s string) string {
|
|
return leadingInt.FindString(s)
|
|
}
|
|
|
|
func hyphaDirRevsValidate(dto map[string]map[string]string) (res bool) {
|
|
for k, _ := range dto {
|
|
switch k {
|
|
case "0":
|
|
delete(dto, "0")
|
|
default:
|
|
res = true
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
func scanHyphaDir(fullPath string) (valid bool, revs map[string]map[string]string, possibleSubhyphae []string, metaJsonPath string, err error) {
|
|
revs = make(map[string]map[string]string)
|
|
nodes, err := ioutil.ReadDir(fullPath)
|
|
if err != nil {
|
|
return // implicit return values
|
|
}
|
|
|
|
for _, node := range nodes {
|
|
hyphaM, revTxtM, revBinM, metaJsonM := matchNameToEverything(node.Name())
|
|
switch {
|
|
case hyphaM && node.IsDir():
|
|
possibleSubhyphae = append(possibleSubhyphae, filepath.Join(fullPath, node.Name()))
|
|
case revTxtM && !node.IsDir():
|
|
revId := stripLeadingInt(node.Name())
|
|
if _, ok := revs[revId]; !ok {
|
|
revs[revId] = make(map[string]string)
|
|
}
|
|
revs[revId]["txt"] = filepath.Join(fullPath, node.Name())
|
|
case revBinM && !node.IsDir():
|
|
revId := stripLeadingInt(node.Name())
|
|
if _, ok := revs[revId]; !ok {
|
|
revs[revId] = make(map[string]string)
|
|
}
|
|
revs[revId]["bin"] = filepath.Join(fullPath, node.Name())
|
|
case metaJsonM && !node.IsDir():
|
|
metaJsonPath = filepath.Join(fullPath, "meta.json")
|
|
// Other nodes are ignored. It is not promised they will be ignored in future versions
|
|
}
|
|
}
|
|
|
|
valid = hyphaDirRevsValidate(revs)
|
|
|
|
return // implicit return values
|
|
}
|
|
|
|
// Hypha name is rootWikiDir/{here}
|
|
func hyphaName(fullPath string) string {
|
|
return fullPath[len(rootWikiDir)+1:]
|
|
}
|
|
|
|
func recurFindHyphae(fullPath string) map[string]*Hypha {
|
|
hyphae := make(map[string]*Hypha)
|
|
valid, revs, possibleSubhyphae, metaJsonPath, err := scanHyphaDir(fullPath)
|
|
if err != nil {
|
|
return hyphae
|
|
}
|
|
|
|
// First, let's process subhyphae
|
|
for _, possibleSubhypha := range possibleSubhyphae {
|
|
for k, v := range recurFindHyphae(possibleSubhypha) {
|
|
hyphae[k] = v
|
|
}
|
|
}
|
|
|
|
// This folder is not a hypha itself, nothing to do here
|
|
if !valid {
|
|
return hyphae
|
|
}
|
|
|
|
// Template hypha struct. Other fields are default json values.
|
|
h := Hypha{
|
|
FullName: hyphaName(fullPath),
|
|
Path: fullPath,
|
|
parentName: filepath.Dir(hyphaName(fullPath)),
|
|
// Children names are unknown now
|
|
}
|
|
|
|
metaJsonContents, err := ioutil.ReadFile(metaJsonPath)
|
|
if err != nil {
|
|
log.Printf("Error when reading `%s`; skipping", metaJsonPath)
|
|
return hyphae
|
|
}
|
|
err = json.Unmarshal(metaJsonContents, &h)
|
|
if err != nil {
|
|
log.Printf("Error when unmarshaling `%s`; skipping", metaJsonPath)
|
|
return hyphae
|
|
}
|
|
|
|
// Fill in every revision paths
|
|
for id, paths := range revs {
|
|
if r, ok := h.Revisions[id]; ok {
|
|
for fType, fPath := range paths {
|
|
switch fType {
|
|
case "bin":
|
|
r.BinaryPath = fPath
|
|
case "txt":
|
|
r.TextPath = fPath
|
|
}
|
|
}
|
|
} else {
|
|
log.Printf("Error when reading hyphae from disk: hypha `%s`'s meta.json provided no information about revision `%s`, but files %s are provided; skipping\n", h.FullName, id, paths)
|
|
}
|
|
}
|
|
|
|
// Now the hypha should be ok, gotta send structs
|
|
hyphae[h.FullName] = &h
|
|
return hyphae
|
|
|
|
}
|