1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2024-12-13 22:00:27 +00:00

Implement backlinks updating

This commit is contained in:
Mikhail Chekan 2021-09-01 03:28:12 +08:00 committed by Timur Ismagilov
parent 820de6a0aa
commit 7c41403eee
5 changed files with 91 additions and 22 deletions

View File

@ -15,6 +15,25 @@ import (
// Using set here seems like the most appropriate solution // Using set here seems like the most appropriate solution
type linkSet map[string]struct{} type linkSet map[string]struct{}
func toLinkSet(xs []string) linkSet {
result := make(linkSet)
for _, x := range xs {
result[x] = struct{}{}
}
return result
}
func fetchText(h *Hypha) string {
if h.TextPath == "" {
return ""
}
text, err := os.ReadFile(h.TextPath)
if err == nil {
return string(text)
}
return ""
}
var backlinkIndex = make(map[string]linkSet) var backlinkIndex = make(map[string]linkSet)
var backlinkIndexMutex = sync.Mutex{} var backlinkIndexMutex = sync.Mutex{}
@ -23,41 +42,85 @@ func IndexBacklinks() {
// It is safe to ignore the mutex, because there is only one worker. // It is safe to ignore the mutex, because there is only one worker.
src := FilterTextHyphae(YieldExistingHyphae()) src := FilterTextHyphae(YieldExistingHyphae())
for h := range src { for h := range src {
fileContentsT, errT := os.ReadFile(h.TextPath) links := ExtractHyphaLinksFromContent(h.Name, fetchText(h))
if errT == nil { for _, link := range links {
links := ExtractHyphaLinksFromContent(h.Name, string(fileContentsT)) if _, exists := backlinkIndex[link]; !exists {
for _, link := range links { backlinkIndex[link] = make(linkSet)
if _, exists := backlinkIndex[link]; !exists {
backlinkIndex[link] = make(linkSet)
}
backlinkIndex[link][h.Name] = struct{}{}
} }
backlinkIndex[link][h.Name] = struct{}{}
} }
} }
} }
func BacklinksOnEdit(h *Hypha, oldText string) {
backlinkIndexMutex.Lock()
newLinks := toLinkSet(ExtractHyphaLinks(h))
oldLinks := toLinkSet(ExtractHyphaLinksFromContent(h.Name, oldText))
for link := range oldLinks {
if _, exists := newLinks[link]; !exists {
delete(backlinkIndex[link], h.Name)
}
}
for link := range newLinks {
if _, exists := oldLinks[link]; !exists {
if _, exists := backlinkIndex[link]; !exists {
backlinkIndex[link] = make(linkSet)
}
backlinkIndex[link][h.Name] = struct{}{}
}
}
backlinkIndexMutex.Unlock()
}
func BacklinksOnDelete(h *Hypha, oldText string) {
backlinkIndexMutex.Lock()
oldLinks := ExtractHyphaLinksFromContent(h.Name, oldText)
for _, link := range oldLinks {
if lSet, exists := backlinkIndex[link]; exists {
delete(lSet, h.Name)
}
}
backlinkIndexMutex.Unlock()
}
func BacklinksOnRename(h *Hypha, oldName string) {
backlinkIndexMutex.Lock()
actualLinks := ExtractHyphaLinks(h)
for _, link := range actualLinks {
if lSet, exists := backlinkIndex[link]; exists {
delete(lSet, oldName)
backlinkIndex[link][h.Name] = struct{}{}
}
}
backlinkIndexMutex.Unlock()
}
// YieldHyphaBacklinks gets backlinks for a desired hypha, sorts and iterates over them
func YieldHyphaBacklinks(query string) <-chan string { func YieldHyphaBacklinks(query string) <-chan string {
hyphaName := util.CanonicalName(query) hyphaName := util.CanonicalName(query)
out := make(chan string) out := make(chan string)
sorted := PathographicSort(out) sorted := PathographicSort(out)
go func() { go func() {
links := backlinkIndex[hyphaName] links, exists := backlinkIndex[hyphaName]
for link := range links { if exists {
out <- link for link := range links {
out <- link
}
} }
close(out) close(out)
}() }()
return sorted return sorted
} }
// YieldHyphaLinks extracts hypha links from a desired hypha and iterates over them // YieldHyphaLinks extracts hypha links from a desired hypha, sorts and iterates over them
func YieldHyphaLinks(query string) <-chan string { func YieldHyphaLinks(query string) <-chan string {
// That is merely a debug function, but it could be useful. // That is merely a debug function, but it could be useful.
// Should we extract them into link-specific subfile? -- chekoopa // Should we extract them into link-specific subfile? -- chekoopa
hyphaName := util.CanonicalName(query) hyphaName := util.CanonicalName(query)
out := make(chan string) out := make(chan string)
go func() { go func() {
links := ExtractHyphaLinks(hyphaName) var h = ByName(hyphaName)
links := ExtractHyphaLinks(h)
for _, link := range links { for _, link := range links {
out <- link out <- link
} }
@ -67,15 +130,8 @@ func YieldHyphaLinks(query string) <-chan string {
} }
// ExtractHyphaLinks extracts hypha links from a desired hypha // ExtractHyphaLinks extracts hypha links from a desired hypha
func ExtractHyphaLinks(hyphaName string) []string { func ExtractHyphaLinks(h *Hypha) []string {
var h = ByName(hyphaName) return ExtractHyphaLinksFromContent(h.Name, fetchText(h))
if h.Exists {
fileContentsT, errT := os.ReadFile(h.TextPath)
if errT == nil {
return ExtractHyphaLinksFromContent(hyphaName, string(fileContentsT))
}
}
return make([]string, 0)
} }
// ExtractHyphaLinksFromContent extracts hypha links from a provided text // ExtractHyphaLinksFromContent extracts hypha links from a provided text

View File

@ -17,12 +17,14 @@ func DeleteHypha(u *user.User, h *hyphae.Hypha) (hop *history.HistoryOp, errtitl
return hop, errtitle return hop, errtitle
} }
originalText, _ := FetchTextPart(h)
hop. hop.
WithFilesRemoved(h.TextPath, h.BinaryPath). WithFilesRemoved(h.TextPath, h.BinaryPath).
WithMsg(fmt.Sprintf("Delete %s", h.Name)). WithMsg(fmt.Sprintf("Delete %s", h.Name)).
WithUser(u). WithUser(u).
Apply() Apply()
if !hop.HasErrors() { if !hop.HasErrors() {
hyphae.BacklinksOnDelete(h, originalText)
h.Delete() h.Delete()
} }
return hop, "" return hop, ""

View File

@ -67,11 +67,13 @@ func RenameHypha(h *hyphae.Hypha, newHypha *hyphae.Hypha, recursive bool, u *use
Apply() Apply()
if len(hop.Errs) == 0 { if len(hop.Errs) == 0 {
for _, h := range hyphaeToRename { for _, h := range hyphaeToRename {
oldName := h.Name
h.RenameTo(replaceName(h.Name)) h.RenameTo(replaceName(h.Name))
h.Lock() h.Lock()
h.TextPath = replaceName(h.TextPath) h.TextPath = replaceName(h.TextPath)
h.BinaryPath = replaceName(h.BinaryPath) h.BinaryPath = replaceName(h.BinaryPath)
h.Unlock() h.Unlock()
hyphae.BacklinksOnRename(h, oldName)
} }
} }
return hop, "" return hop, ""

View File

@ -7,6 +7,7 @@ import (
"github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/util"
) )
// YieldHyphaNamesContainingString picks hyphae with have a string in their title, sorts and iterates over them.
func YieldHyphaNamesContainingString(query string) <-chan string { func YieldHyphaNamesContainingString(query string) <-chan string {
query = util.CanonicalName(query) query = util.CanonicalName(query)
out := make(chan string) out := make(chan string)

View File

@ -66,6 +66,7 @@ func uploadHelp(h *hyphae.Hypha, hop *history.HistoryOp, ext string, data []byte
var ( var (
fullPath = filepath.Join(files.HyphaeDir(), h.Name+ext) fullPath = filepath.Join(files.HyphaeDir(), h.Name+ext)
originalFullPath = &h.TextPath originalFullPath = &h.TextPath
originalText = "" // for backlink update
) )
// Reject if the path is outside the hyphae dir // Reject if the path is outside the hyphae dir
if !strings.HasPrefix(fullPath, files.HyphaeDir()) { if !strings.HasPrefix(fullPath, files.HyphaeDir()) {
@ -80,6 +81,10 @@ func uploadHelp(h *hyphae.Hypha, hop *history.HistoryOp, ext string, data []byte
return hop.WithErrAbort(err), err.Error() return hop.WithErrAbort(err), err.Error()
} }
if hop.Type == history.TypeEditText {
originalText, _ = FetchTextPart(h)
}
if err := os.WriteFile(fullPath, data, 0666); err != nil { if err := os.WriteFile(fullPath, data, 0666); err != nil {
return hop.WithErrAbort(err), err.Error() return hop.WithErrAbort(err), err.Error()
} }
@ -96,5 +101,8 @@ func uploadHelp(h *hyphae.Hypha, hop *history.HistoryOp, ext string, data []byte
return hop.Abort(), "No changes" return hop.Abort(), "No changes"
} }
*originalFullPath = fullPath *originalFullPath = fullPath
if hop.Type == history.TypeEditText {
hyphae.BacklinksOnEdit(h, originalText)
}
return hop.WithFiles(fullPath).WithUser(u).Apply(), "" return hop.WithFiles(fullPath).WithUser(u).Apply(), ""
} }