1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2024-12-12 05:20:26 +00:00
mycorrhiza/walk.go
2020-06-16 23:35:52 +05:00

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
}