2020-06-12 16:22:02 +00:00
package main
import (
"encoding/json"
"io/ioutil"
2020-06-16 18:35:52 +00:00
"log"
2020-06-12 16:22:02 +00:00
"path/filepath"
"regexp"
)
2020-06-16 18:35:52 +00:00
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 )
2020-06-12 16:22:02 +00:00
nodes , err := ioutil . ReadDir ( fullPath )
if err != nil {
return // implicit return values
}
for _ , node := range nodes {
2020-06-16 18:35:52 +00:00
hyphaM , revTxtM , revBinM , metaJsonM := matchNameToEverything ( node . Name ( ) )
2020-06-12 16:22:02 +00:00
switch {
2020-06-16 18:35:52 +00:00
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 )
2020-06-12 16:22:02 +00:00
}
2020-06-16 18:35:52 +00:00
revs [ revId ] [ "bin" ] = filepath . Join ( fullPath , node . Name ( ) )
case metaJsonM && ! node . IsDir ( ) :
metaJsonPath = filepath . Join ( fullPath , "meta.json" )
2020-06-12 16:22:02 +00:00
// Other nodes are ignored. It is not promised they will be ignored in future versions
}
}
2020-06-16 18:35:52 +00:00
valid = hyphaDirRevsValidate ( revs )
2020-06-12 16:22:02 +00:00
return // implicit return values
}
// Hypha name is rootWikiDir/{here}
func hyphaName ( fullPath string ) string {
return fullPath [ len ( rootWikiDir ) + 1 : ]
}
2020-06-16 18:35:52 +00:00
func recurFindHyphae ( fullPath string ) map [ string ] * Hypha {
hyphae := make ( map [ string ] * Hypha )
valid , revs , possibleSubhyphae , metaJsonPath , err := scanHyphaDir ( fullPath )
2020-06-12 16:22:02 +00:00
if err != nil {
return hyphae
}
2020-06-16 18:35:52 +00:00
// First, let's process subhyphae
for _ , possibleSubhypha := range possibleSubhyphae {
for k , v := range recurFindHyphae ( possibleSubhypha ) {
hyphae [ k ] = v
}
2020-06-12 16:22:02 +00:00
}
// This folder is not a hypha itself, nothing to do here
2020-06-16 18:35:52 +00:00
if ! valid {
2020-06-12 16:22:02 +00:00
return hyphae
}
2020-06-16 18:35:52 +00:00
// Template hypha struct. Other fields are default json values.
2020-06-12 16:22:02 +00:00
h := Hypha {
2020-06-16 18:35:52 +00:00
FullName : hyphaName ( fullPath ) ,
2020-06-12 16:22:02 +00:00
Path : fullPath ,
2020-06-16 18:35:52 +00:00
parentName : filepath . Dir ( hyphaName ( fullPath ) ) ,
2020-06-12 16:22:02 +00:00
// Children names are unknown now
}
2020-06-16 18:35:52 +00:00
metaJsonContents , err := ioutil . ReadFile ( metaJsonPath )
2020-06-12 16:22:02 +00:00
if err != nil {
2020-06-16 18:35:52 +00:00
log . Printf ( "Error when reading `%s`; skipping" , metaJsonPath )
2020-06-12 16:22:02 +00:00
return hyphae
}
2020-06-16 18:35:52 +00:00
err = json . Unmarshal ( metaJsonContents , & h )
2020-06-12 16:22:02 +00:00
if err != nil {
2020-06-16 18:35:52 +00:00
log . Printf ( "Error when unmarshaling `%s`; skipping" , metaJsonPath )
2020-06-12 16:22:02 +00:00
return hyphae
}
2020-06-16 18:35:52 +00:00
// 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
}
}
2020-06-12 16:22:02 +00:00
} else {
2020-06-16 18:35:52 +00:00
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 )
2020-06-12 16:22:02 +00:00
}
}
2020-06-16 18:35:52 +00:00
// Now the hypha should be ok, gotta send structs
hyphae [ h . FullName ] = & h
return hyphae
2020-06-12 16:22:02 +00:00
}