mirror of
https://github.com/osmarks/mycorrhiza.git
synced 2024-12-12 05:20:26 +00:00
Merge code from two branches, make it show something
This commit is contained in:
parent
c69002de7b
commit
2a3f346034
@ -9,8 +9,8 @@ type Genealogy struct {
|
||||
|
||||
func setRelations(hyphae map[string]*Hypha) {
|
||||
for name, h := range hyphae {
|
||||
if _, ok := hyphae[h.ParentName]; ok && h.ParentName != "." {
|
||||
hyphae[h.ParentName].ChildrenNames = append(hyphae[h.ParentName].ChildrenNames, name)
|
||||
if _, ok := hyphae[h.ParentName()]; ok && h.ParentName() != "." {
|
||||
hyphae[h.ParentName()].ChildrenNames = append(hyphae[h.ParentName()].ChildrenNames, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
84
hypha.go
84
hypha.go
@ -1,70 +1,52 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Hypha struct {
|
||||
// Hypha is physically located here. Most fields below are stored in <path>/mm.ini (mm for metametadata). Its revisions are physically located in <path>/<n>/ subfolders. <n> ∈ [0;∞] with 0 being latest revision, 1 the first.
|
||||
Path string
|
||||
// Every hypha was created at some point
|
||||
CreationTime int `json:"creationTime"`
|
||||
// Hypha has name but it can be changed
|
||||
Name string `json:"name"`
|
||||
// Hypha can be deleted. If it is deleted, it is not indexed by most of the software but still can be recovered at some point.
|
||||
Deleted bool `json:"deleted"`
|
||||
// Fields below are not part of m.ini and are created when traversing the file tree.
|
||||
// Hypha can be a child of any other hypha except its children. The parent hypha is stored in <path>/..
|
||||
ParentName string
|
||||
// Hypha can have any number of children which are stored as subfolders in <path>.
|
||||
FullName string
|
||||
Path string
|
||||
ViewCount int `json:"views"`
|
||||
Deleted bool `json:"deleted"`
|
||||
Revisions map[string]*Revision `json:"revisions"`
|
||||
ChildrenNames []string
|
||||
Revisions []Revision
|
||||
parentName string
|
||||
}
|
||||
|
||||
func (h Hypha) String() string {
|
||||
var revbuf string
|
||||
for _, r := range h.Revisions {
|
||||
revbuf += r.String() + "\n"
|
||||
func (h *Hypha) AddChild(childName string) {
|
||||
h.ChildrenNames = append(h.ChildrenNames, childName)
|
||||
}
|
||||
|
||||
// Used with action=zen|view
|
||||
func (h *Hypha) AsHtml(hyphae map[string]*Hypha, rev string) (string, error) {
|
||||
if "0" == rev {
|
||||
rev = h.NewestRevision()
|
||||
}
|
||||
return fmt.Sprintf("Hypha %v {\n\t"+
|
||||
"path %v\n\t"+
|
||||
"created at %v\n\t"+
|
||||
"child of %v\n\t"+
|
||||
"parent of %v\n\t"+
|
||||
"Having these revisions:\n%v"+
|
||||
"}\n", h.Name, h.Path, h.CreationTime, h.ParentName, h.ChildrenNames,
|
||||
revbuf)
|
||||
r, ok := h.Revisions[rev]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("Hypha %v has no such revision: %v", h.FullName, rev)
|
||||
}
|
||||
html, err := r.AsHtml(hyphae)
|
||||
return html, err
|
||||
}
|
||||
|
||||
func GetRevision(hyphae map[string]*Hypha, hyphaName string, rev string, w http.ResponseWriter) (Revision, bool) {
|
||||
for name, _ := range hyphae {
|
||||
if name == hyphaName {
|
||||
for _, r := range hyphae[name].Revisions {
|
||||
id, err := strconv.Atoi(rev)
|
||||
if err != nil {
|
||||
log.Println("No such revision", rev, "at hypha", hyphaName)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return Revision{}, false
|
||||
}
|
||||
if r.Id == id {
|
||||
return r, true
|
||||
}
|
||||
}
|
||||
func (h *Hypha) Name() string {
|
||||
return h.FullName
|
||||
}
|
||||
|
||||
func (h *Hypha) NewestRevision() string {
|
||||
var largest int
|
||||
for k, _ := range h.Revisions {
|
||||
rev, _ := strconv.Atoi(k)
|
||||
if rev > largest {
|
||||
largest = rev
|
||||
}
|
||||
}
|
||||
return Revision{}, false
|
||||
return strconv.Itoa(largest)
|
||||
}
|
||||
|
||||
// `rev` is the id of revision to render. If it = 0, the last one is rendered. If the revision is not found, an error is returned.
|
||||
func (h Hypha) Render(hyphae map[string]*Hypha, rev int) (ret string, err error) {
|
||||
for _, r := range h.Revisions {
|
||||
if r.Id == rev {
|
||||
return r.Render(hyphae)
|
||||
}
|
||||
}
|
||||
return "", errors.New("Revision was not found")
|
||||
func (h *Hypha) ParentName() string {
|
||||
return h.parentName
|
||||
}
|
||||
|
29
main.go
29
main.go
@ -12,6 +12,19 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func GetRevision(hyphae map[string]*Hypha, hyphaName string, rev string, w http.ResponseWriter) (Revision, bool) {
|
||||
for name, _ := range hyphae {
|
||||
if name == hyphaName {
|
||||
for id, r := range hyphae[name].Revisions {
|
||||
if rev == id {
|
||||
return *r, true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Revision{}, false
|
||||
}
|
||||
|
||||
func RevInMap(m map[string]string) string {
|
||||
if val, ok := m["rev"]; ok {
|
||||
return val
|
||||
@ -33,7 +46,7 @@ func HandlerGetBinary(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", rev.MimeType)
|
||||
w.Header().Set("Content-Type", rev.BinaryMime)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(fileContents)
|
||||
log.Println("Showing image of", rev.FullName, rev.Id)
|
||||
@ -65,7 +78,7 @@ func HandlerZen(w http.ResponseWriter, r *http.Request) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
html, err := rev.Render(hyphae)
|
||||
html, err := rev.AsHtml(hyphae)
|
||||
if err != nil {
|
||||
log.Println("Failed to render", rev.FullName)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@ -83,7 +96,7 @@ func HandlerView(w http.ResponseWriter, r *http.Request) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
html, err := rev.Render(hyphae)
|
||||
html, err := rev.AsHtml(hyphae)
|
||||
if err != nil {
|
||||
log.Println("Failed to render", rev.FullName)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@ -131,7 +144,7 @@ var hyphae map[string]*Hypha
|
||||
func hyphaeAsMap(hyphae []*Hypha) map[string]*Hypha {
|
||||
mh := make(map[string]*Hypha)
|
||||
for _, h := range hyphae {
|
||||
mh[h.Name] = h
|
||||
mh[h.Name()] = h
|
||||
}
|
||||
return mh
|
||||
}
|
||||
@ -147,8 +160,8 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
hyphae = hyphaeAsMap(recurFindHyphae(rootWikiDir))
|
||||
setRelations(hyphae)
|
||||
hyphae = recurFindHyphae(rootWikiDir)
|
||||
// setRelations(hyphae)
|
||||
|
||||
// Start server code
|
||||
r := mux.NewRouter()
|
||||
@ -197,8 +210,8 @@ func main() {
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
for _, v := range hyphae {
|
||||
log.Println("Rendering latest revision of hypha", v.Name)
|
||||
html, err := v.Render(hyphae, 0)
|
||||
log.Println("Rendering latest revision of hypha", v.Name())
|
||||
html, err := v.AsHtml(hyphae, "0")
|
||||
if err != nil {
|
||||
fmt.Fprintln(w, err)
|
||||
}
|
||||
|
126
revision.go
126
revision.go
@ -5,55 +5,39 @@ import (
|
||||
"fmt"
|
||||
"github.com/gomarkdown/markdown"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Revision struct {
|
||||
// Revision is hypha's state at some point in time. Future revisions are not really supported. Most data here is stored in m.ini.
|
||||
Id int
|
||||
// Name used at this revision
|
||||
Name string `json:"name"`
|
||||
// Name of hypha
|
||||
FullName string
|
||||
// Present in every hypha. Stored in t.txt.
|
||||
TextPath string
|
||||
// In at least one markup. Supported ones are "myco", "html", "md", "plain"
|
||||
Markup string `json:"markup"`
|
||||
// Some hyphæ have binary contents such as images. Their presence change hypha's behavior in a lot of ways (see methods' implementations). If stored, it is stored in b (filename "b")
|
||||
BinaryPath string
|
||||
BinaryRequest string
|
||||
// To tell what is meaning of binary content, mimeType for them is stored. If the hypha has no binary content, this field must be "application/x-hypha"
|
||||
MimeType string `json:"mimeType"`
|
||||
// Every revision was created at some point. This field stores the creation time of the latest revision
|
||||
RevisionTime int `json:"createdAt"`
|
||||
// Every hypha has any number of tags
|
||||
Tags []string `json:"tags"`
|
||||
// Current revision is authored by someone
|
||||
RevisionAuthor string `json:"author"`
|
||||
// and has a comment in plain text
|
||||
RevisionComment string `json:"comment"`
|
||||
Id int
|
||||
Tags []string `json:"tags"`
|
||||
FullName string `json:"name"`
|
||||
Comment string `json:"comment"`
|
||||
Author string `json:"author"`
|
||||
Time int `json:"time"`
|
||||
TextMime string `json:"text_mime"`
|
||||
BinaryMime string `json:"binary_mime"`
|
||||
TextPath string
|
||||
BinaryPath string
|
||||
}
|
||||
|
||||
func (h Revision) String() string {
|
||||
return fmt.Sprintf(`Revision %v created at %v {
|
||||
name: %v
|
||||
textPath: %v
|
||||
markup: %v
|
||||
binaryPath: %v
|
||||
mimeType: %v
|
||||
tags: %v
|
||||
revisionAuthor: %v
|
||||
revisionComment: %v
|
||||
}`, h.Id, h.RevisionTime, h.Name, h.TextPath, h.Markup, h.BinaryPath, h.MimeType, h.Tags, h.RevisionAuthor, h.RevisionComment)
|
||||
// During initialisation, it is guaranteed that r.BinaryMime is set to "" if the revision has no binary data.
|
||||
func (r *Revision) hasBinaryData() bool {
|
||||
return r.BinaryMime != ""
|
||||
}
|
||||
|
||||
// This method is meant to be called only by Hypha#Render.
|
||||
func (r Revision) Render(hyphae map[string]*Hypha) (ret string, err error) {
|
||||
func (r *Revision) urlOfBinary() string {
|
||||
return fmt.Sprintf("/%s?action=getBinary&rev=%d", r.FullName, r.Id)
|
||||
}
|
||||
|
||||
// TODO: use templates https://github.com/bouncepaw/mycorrhiza/issues/2
|
||||
func (r *Revision) AsHtml(hyphae map[string]*Hypha) (ret string, err error) {
|
||||
ret += `<article class="page">
|
||||
`
|
||||
// If it is a binary hypha (we support only images for now):
|
||||
// TODO: support things other than images.
|
||||
if r.MimeType != "application/x-hypha" {
|
||||
ret += fmt.Sprintf(`<img src="/%s" class="page__image"/>`, r.BinaryRequest)
|
||||
// TODO: support things other than images
|
||||
if r.hasBinaryData() {
|
||||
ret += fmt.Sprintf(`<img src="/%s" class="page__image"/>`, r.urlOfBinary())
|
||||
}
|
||||
|
||||
contents, err := ioutil.ReadFile(r.TextPath)
|
||||
@ -63,17 +47,71 @@ func (r Revision) Render(hyphae map[string]*Hypha) (ret string, err error) {
|
||||
|
||||
// TODO: support more markups.
|
||||
// TODO: support mycorrhiza extensions like transclusion.
|
||||
switch r.Markup {
|
||||
case "plain":
|
||||
switch r.TextMime {
|
||||
case "text/plain":
|
||||
ret += fmt.Sprintf(`<pre>%s</pre>`, contents)
|
||||
case "md":
|
||||
case "text/markdown":
|
||||
html := markdown.ToHTML(contents, nil, nil)
|
||||
ret += string(html)
|
||||
default:
|
||||
return "", errors.New("Unsupported markup: " + r.Markup)
|
||||
return "", errors.New("Unsupported mime-type: " + r.TextMime)
|
||||
}
|
||||
|
||||
ret += `
|
||||
</article>`
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (r *Revision) ActionGetBinary(w http.ResponseWriter) {
|
||||
fileContents, err := ioutil.ReadFile(r.urlOfBinary())
|
||||
if err != nil {
|
||||
log.Println("Failed to load binary data of", r.FullName, r.Id)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", r.BinaryMime)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(fileContents)
|
||||
log.Println("Serving binary data of", r.FullName, r.Id)
|
||||
}
|
||||
|
||||
func (r *Revision) ActionRaw(w http.ResponseWriter) {
|
||||
fileContents, err := ioutil.ReadFile(r.TextPath)
|
||||
if err != nil {
|
||||
log.Println("Failed to load text data of", r.FullName, r.Id)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", r.TextMime)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(fileContents)
|
||||
log.Println("Serving text data of", r.FullName, r.Id)
|
||||
}
|
||||
|
||||
func (r *Revision) ActionZen(w http.ResponseWriter, hyphae map[string]*Hypha) {
|
||||
html, err := r.AsHtml(hyphae)
|
||||
if err != nil {
|
||||
log.Println("Failed to render", r.FullName)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprint(w, html)
|
||||
}
|
||||
|
||||
func (r *Revision) ActionView(w http.ResponseWriter, hyphae map[string]*Hypha, layoutFun func(map[string]*Hypha, Revision, string) string) {
|
||||
html, err := r.AsHtml(hyphae)
|
||||
if err != nil {
|
||||
log.Println("Failed to render", r.FullName)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprint(w, layoutFun(hyphae, *r, html))
|
||||
log.Println("Rendering", r.FullName)
|
||||
}
|
||||
func (r *Revision) Name() string {
|
||||
return r.FullName
|
||||
}
|
||||
|
244
walk.go
244
walk.go
@ -2,190 +2,156 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func scanHyphaDir(fullPath string) (structureMet bool, possibleRevisionPaths []string, possibleHyphaPaths []string, reterr error) {
|
||||
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 {
|
||||
reterr = err
|
||||
return // implicit return values
|
||||
}
|
||||
|
||||
var (
|
||||
mmJsonPresent bool
|
||||
zeroDirPresent bool
|
||||
)
|
||||
|
||||
for _, node := range nodes {
|
||||
matchedHypha, _ := regexp.MatchString(hyphaPattern, node.Name())
|
||||
matchedRev, _ := regexp.MatchString(revisionPattern, node.Name())
|
||||
hyphaM, revTxtM, revBinM, metaJsonM := matchNameToEverything(node.Name())
|
||||
switch {
|
||||
case matchedRev && node.IsDir():
|
||||
if node.Name() == "0" {
|
||||
zeroDirPresent = true
|
||||
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)
|
||||
}
|
||||
possibleRevisionPaths = append(
|
||||
possibleRevisionPaths,
|
||||
filepath.Join(fullPath, node.Name()),
|
||||
)
|
||||
case (node.Name() == "mm.json") && !node.IsDir():
|
||||
mmJsonPresent = true
|
||||
case matchedHypha && node.IsDir():
|
||||
possibleHyphaPaths = append(
|
||||
possibleHyphaPaths,
|
||||
filepath.Join(fullPath, node.Name()),
|
||||
)
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
if mmJsonPresent && zeroDirPresent {
|
||||
structureMet = true
|
||||
}
|
||||
valid = hyphaDirRevsValidate(revs)
|
||||
|
||||
return // implicit return values
|
||||
}
|
||||
|
||||
func check(e error) {
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Hypha name is rootWikiDir/{here}
|
||||
func hyphaName(fullPath string) string {
|
||||
return fullPath[len(rootWikiDir)+1:]
|
||||
}
|
||||
|
||||
const (
|
||||
hyphaPattern = `[^\s\d:/?&\\][^:?&\\]*`
|
||||
revisionPattern = `[\d]+`
|
||||
hyphaUrl = "/{hypha:" + hyphaPattern + "}"
|
||||
revQuery = `{rev:[\d]+}`
|
||||
)
|
||||
|
||||
// Sends found hyphae to the `ch`. `fullPath` is tested for hyphaness, then its subdirs with hyphaesque names are tested too using goroutines for each subdir. The function is recursive.
|
||||
func recurFindHyphae(fullPath string) (hyphae []*Hypha) {
|
||||
|
||||
structureMet, possibleRevisionPaths, possibleHyphaPaths, err := scanHyphaDir(fullPath)
|
||||
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 inner hyphae
|
||||
for _, possibleHyphaPath := range possibleHyphaPaths {
|
||||
hyphae = append(hyphae, recurFindHyphae(possibleHyphaPath)...)
|
||||
// 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 !structureMet {
|
||||
if !valid {
|
||||
return hyphae
|
||||
}
|
||||
|
||||
// Template hypha struct. Other fields are default jsont values.
|
||||
// Template hypha struct. Other fields are default json values.
|
||||
h := Hypha{
|
||||
FullName: hyphaName(fullPath),
|
||||
Path: fullPath,
|
||||
Name: hyphaName(fullPath),
|
||||
ParentName: filepath.Dir(hyphaName(fullPath)),
|
||||
parentName: filepath.Dir(hyphaName(fullPath)),
|
||||
// Children names are unknown now
|
||||
}
|
||||
|
||||
// Fill in every revision
|
||||
for _, possibleRevisionPath := range possibleRevisionPaths {
|
||||
rev, err := makeRevision(possibleRevisionPath, h.Name)
|
||||
if err == nil {
|
||||
h.Revisions = append(h.Revisions, rev)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
mmJsonPath := filepath.Join(fullPath, "mm.json")
|
||||
mmJsonContents, err := ioutil.ReadFile(mmJsonPath)
|
||||
if err != nil {
|
||||
fmt.Println(fullPath, ">\tError:", err)
|
||||
return hyphae
|
||||
}
|
||||
err = json.Unmarshal(mmJsonContents, &h)
|
||||
if err != nil {
|
||||
fmt.Println(fullPath, ">\tError:", err)
|
||||
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 = append(hyphae, &h)
|
||||
hyphae[h.FullName] = &h
|
||||
return hyphae
|
||||
}
|
||||
|
||||
func makeRevision(fullPath string, fullName string) (r Revision, err error) {
|
||||
// fullPath is expected to be a path to a dir.
|
||||
// Revision directory must have at least `m.json` and `t.txt` files.
|
||||
var (
|
||||
mJsonPresent bool
|
||||
tTxtPresent bool
|
||||
bPresent bool
|
||||
)
|
||||
|
||||
nodes, err := ioutil.ReadDir(fullPath)
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
|
||||
for _, node := range nodes {
|
||||
if node.IsDir() {
|
||||
continue
|
||||
}
|
||||
switch node.Name() {
|
||||
case "m.json":
|
||||
mJsonPresent = true
|
||||
case "t.txt":
|
||||
tTxtPresent = true
|
||||
case "b":
|
||||
bPresent = true
|
||||
}
|
||||
}
|
||||
|
||||
if !(mJsonPresent && tTxtPresent) {
|
||||
return r, errors.New("makeRevision: m.json and t.txt files are not found")
|
||||
}
|
||||
|
||||
// If all the flags are true, this directory is assumed to be a revision. Gotta check further. This is template Revision struct. Other fields fall back to default init values.
|
||||
mJsonPath := filepath.Join(fullPath, "m.json")
|
||||
mJsonContents, err := ioutil.ReadFile(mJsonPath)
|
||||
if err != nil {
|
||||
fmt.Println(fullPath, ">\tError:", err)
|
||||
return r, err
|
||||
}
|
||||
|
||||
r = Revision{FullName: fullName}
|
||||
err = json.Unmarshal(mJsonContents, &r)
|
||||
if err != nil {
|
||||
fmt.Println(fullPath, ">\tError:", err)
|
||||
return r, err
|
||||
}
|
||||
|
||||
// Now, let's fill in t.txt path
|
||||
r.TextPath = filepath.Join(fullPath, "t.txt")
|
||||
|
||||
// There's sense in reading binary file only if the hypha is marked as such
|
||||
if r.MimeType != "application/x-hypha" {
|
||||
// Do not check for binary file presence, attempt to read it will fail anyway
|
||||
if bPresent {
|
||||
r.BinaryPath = filepath.Join(fullPath, "b")
|
||||
r.BinaryRequest = fmt.Sprintf("%s?rev=%d&action=getBinary", r.FullName, r.Id)
|
||||
} else {
|
||||
return r, errors.New("makeRevision: b file not present")
|
||||
}
|
||||
}
|
||||
|
||||
// So far, so good. Let's fill in id. It is guaranteed to be correct, so no error checking
|
||||
id, _ := strconv.Atoi(filepath.Base(fullPath))
|
||||
r.Id = id
|
||||
|
||||
// It is safe now to return, I guess
|
||||
return r, nil
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user