1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2025-04-09 20:26:47 +00:00

Implement the rocket link migration algorithm

This commit is contained in:
Timur Ismagilov 2022-01-31 02:34:52 +05:00
parent 3281fadfc5
commit 86d1a00bfc
7 changed files with 142 additions and 7 deletions

View File

@ -38,6 +38,9 @@ func TokensJSON() string { return paths.tokensJSON }
// UserCredentialsJSON returns the path to the JSON user credentials storage.
func UserCredentialsJSON() string { return paths.userCredentialsJSON }
// FileInRoot returns full path for the given filename if it was placed in the root of the wiki structure.
func FileInRoot(filename string) string { return filepath.Join(cfg.WikiDir, filename) }
// PrepareWikiRoot ensures all needed directories and files exist and have
// correct permissions.
func PrepareWikiRoot() error {

View File

@ -31,6 +31,8 @@ const (
TypeRenameHypha
// TypeUnattachHypha represents a hypha attachment deletion
TypeUnattachHypha
// TypeMarkupMigration represents a wikimind-powered automatic markup migration procedure
TypeMarkupMigration
)
// Op is an object representing a history operation.
@ -65,15 +67,15 @@ func (hop *Op) gitop(args ...string) *Op {
return hop
}
// WithErr appends the `err` to the list of errors.
func (hop *Op) WithErr(err error) *Op {
// withErr appends the `err` to the list of errors.
func (hop *Op) withErr(err error) *Op {
hop.Errs = append(hop.Errs, err)
return hop
}
// WithErrAbort appends the `err` to the list of errors and immediately aborts the operation.
func (hop *Op) WithErrAbort(err error) *Op {
return hop.WithErr(err).Abort()
return hop.withErr(err).Abort()
}
// WithFilesRemoved git-rm-s all passed `paths`. Paths can be rooted or not. Paths that are empty strings are ignored.
@ -110,7 +112,7 @@ func (hop *Op) WithFiles(paths ...string) *Op {
return hop.gitop(append([]string{"add"}, paths...)...)
}
// Apply applies history operation by doing the commit.
// Apply applies history operation by doing the commit. You do not need to call Abort afterwards.
func (hop *Op) Apply() *Op {
hop.gitop(
"commit",

View File

@ -41,7 +41,7 @@ var backlinkIndex = make(map[string]linkSet)
// IndexBacklinks traverses all text hyphae, extracts links from them and forms an initial index. Call it when indexing and reindexing hyphae.
func IndexBacklinks() {
// It is safe to ignore the mutex, because there is only one worker.
for h := range hyphae.FilterTextHyphae(hyphae.YieldExistingHyphae()) {
for h := range hyphae.FilterHyphaeWithText(hyphae.YieldExistingHyphae()) {
foundLinks := extractHyphaLinksFromContent(h.Name, fetchText(h))
for _, link := range foundLinks {
if _, exists := backlinkIndex[link]; !exists {

View File

@ -21,8 +21,9 @@ func YieldExistingHyphae() chan *Hypha {
return ch
}
// FilterTextHyphae filters the source channel and yields only those hyphae than have text parts.
func FilterTextHyphae(src chan *Hypha) chan *Hypha {
// FilterHyphaeWithText filters the source channel and yields only those hyphae than have text parts.
func FilterHyphaeWithText(src chan *Hypha) chan *Hypha {
// TODO: reimplement as a function with a callback?
sink := make(chan *Hypha)
go func() {
for h := range src {

View File

@ -5,6 +5,7 @@
package main
import (
"github.com/bouncepaw/mycorrhiza/migration"
"log"
"os"
@ -45,6 +46,7 @@ func main() {
user.InitUserDatabase()
history.Start()
history.InitGitRepo()
migration.MigrateRocketsMaybe()
shroom.SetHeaderLinks()
// Static files:

117
migration/rockets.go Normal file
View File

@ -0,0 +1,117 @@
// Package migration holds the utilities for migrating from older incompatible Mycomarkup versions.
//
// As of, there is rocket link migration only. Migrations are meant to be removed couple of versions after being introduced.
package migration
import (
"github.com/bouncepaw/mycomarkup/v3/tools"
"io"
"io/ioutil"
"log"
"os"
"strings"
"github.com/bouncepaw/mycorrhiza/files"
"github.com/bouncepaw/mycorrhiza/history"
"github.com/bouncepaw/mycorrhiza/hyphae"
"github.com/bouncepaw/mycorrhiza/user"
)
// TODO: add heading migration too.
var rocketMarkerPath string
// MigrateRocketsMaybe checks if the rocket link migration marker exists. If it exists, nothing is done. If it does not, the migration takes place.
//
// This function writes logs and might terminate the program. Tons of side-effects, stay safe.
func MigrateRocketsMaybe() {
rocketMarkerPath = files.FileInRoot(".mycomarkup-rocket-link-migration-marker.txt")
if !shouldMigrateRockets() {
return
}
var (
hop = history.
Operation(history.TypeMarkupMigration).
WithMsg("Migrate rocket links to the new syntax").
WithUser(user.WikimindUser())
mycoFiles = []string{}
)
for hypha := range hyphae.FilterHyphaeWithText(hyphae.YieldExistingHyphae()) {
/// Open file, read from file, modify file. If anything goes wrong, scream and shout.
file, err := os.OpenFile(hypha.TextPartPath(), os.O_RDWR, 0766)
if err != nil {
hop.WithErrAbort(err)
log.Fatal("Something went wrong when opening ", hypha.TextPartPath(), ": ", err.Error())
}
var buf strings.Builder
_, err = io.Copy(&buf, file)
if err != nil {
hop.WithErrAbort(err)
_ = file.Close()
log.Fatal("Something went wrong when reading ", hypha.TextPartPath(), ": ", err.Error())
}
var (
oldText = buf.String()
newText = tools.MigrateRocketLinks(oldText)
)
if oldText != newText { // This file right here is being migrated for real.
mycoFiles = append(mycoFiles, hypha.TextPartPath())
err = file.Truncate(0)
if err != nil {
hop.WithErrAbort(err)
_ = file.Close()
log.Fatal("Something went wrong when truncating ", hypha.TextPartPath(), ": ", err.Error())
}
_, err = file.Seek(0, 0)
if err != nil {
hop.WithErrAbort(err)
_ = file.Close()
log.Fatal("Something went wrong when seeking in ", hypha.TextPartPath(), ": ", err.Error())
}
_, err = file.WriteString(newText)
if err != nil {
hop.WithErrAbort(err)
_ = file.Close()
log.Fatal("Something went wrong when writing to ", hypha.TextPartPath(), ": ", err.Error())
}
}
_ = file.Close()
}
if hop.WithFiles(mycoFiles...).Apply().HasErrors() {
log.Fatal("Something went wrong when commiting rocket link migration: ", hop.FirstErrorText())
}
log.Println("Migrated", len(mycoFiles), "Mycomarkup documents")
createRocketLinkMarker()
}
func shouldMigrateRockets() bool {
file, err := os.Open(rocketMarkerPath)
if os.IsNotExist(err) {
return true
}
if err != nil {
log.Fatalln("When checking if rocket migration is needed:", err.Error())
}
_ = file.Close()
return false
}
func createRocketLinkMarker() {
err := ioutil.WriteFile(
rocketMarkerPath,
[]byte(`This file is used to mark that the rocket link migration was made successfully. If this file is deleted, the migration might happen again depending on the version. You should probably not touch this file at all and let it be.`),
0766,
)
if err != nil {
log.Fatalln(err)
}
}

View File

@ -88,6 +88,16 @@ func EmptyUser() *User {
}
}
// WikimindUser constructs the wikimind user, which is to be used for automated wiki edits and has admin privileges.
func WikimindUser() *User {
return &User{
Name: "wikimind",
Group: "admin",
Password: "",
Source: "local",
}
}
// CanProceed checks whether user has rights to visit the provided path (and perform an action).
func (user *User) CanProceed(route string) bool {
if !cfg.UseAuth {