1
0
Fork 0
golang-forgejo-f3-gof3/forges/filesystem/node.go
Daniel Baumann 03bfe4079e
Adding upstream version 3.10.8.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-05-18 09:37:23 +02:00

249 lines
5.7 KiB
Go

// Copyright Earl Warren <contact@earl-warren.org>
// Copyright Loïc Dachary <loic@dachary.org>
// SPDX-License-Identifier: MIT
package filesystem
import (
"context"
"fmt"
"os"
"path/filepath"
"strings"
"code.forgejo.org/f3/gof3/v3/f3"
"code.forgejo.org/f3/gof3/v3/id"
"code.forgejo.org/f3/gof3/v3/kind"
f3_tree "code.forgejo.org/f3/gof3/v3/tree/f3"
"code.forgejo.org/f3/gof3/v3/tree/generic"
"code.forgejo.org/f3/gof3/v3/util"
)
type nodeDriver struct {
generic.NullDriver
content f3.Interface
}
func newNodeDriver(content f3.Interface) generic.NodeDriverInterface {
return &nodeDriver{
content: content.Clone(),
}
}
func (o *nodeDriver) SetNative(any) {}
func (o *nodeDriver) GetNativeID() string {
return o.GetNode().GetID().String()
}
func (o *nodeDriver) getBasePath() string {
options := o.GetTreeDriver().(*treeDriver).options
return options.Directory + o.GetNode().GetCurrentPath().String()
}
func (o *nodeDriver) getTree() generic.TreeInterface {
return o.GetNode().GetTree()
}
func (o *nodeDriver) getF3Tree() f3_tree.TreeInterface {
return o.getTree().(f3_tree.TreeInterface)
}
func (o *nodeDriver) isContainer() bool {
return o.getF3Tree().IsContainer(o.getKind())
}
func (o *nodeDriver) getKind() kind.Kind {
return o.GetNode().GetKind()
}
func (o *nodeDriver) IsNull() bool { return false }
func (o *nodeDriver) GetIDFromName(ctx context.Context, name string) id.NodeID {
switch o.getKind() {
case kind.KindRoot, f3_tree.KindProjects, f3_tree.KindUsers, f3_tree.KindOrganizations, f3_tree.KindRepositories:
default:
panic(fmt.Errorf("unxpected kind %s", o.getKind()))
}
for _, child := range o.GetNode().List(ctx) {
child.Get(ctx)
if child.ToFormat().GetName() == name {
return child.GetID()
}
}
return id.NilID
}
func (o *nodeDriver) ListPage(ctx context.Context, page int) generic.ChildrenSlice {
node := o.GetNode()
node.Trace("%s '%s'", o.getKind(), node.GetID())
children := generic.NewChildrenSlice(0)
if o.getKind() == kind.KindRoot || page > 1 {
return children
}
basePath := o.getBasePath()
if !util.FileExists(basePath) {
return children
}
f3Tree := o.getF3Tree()
if !f3Tree.IsContainer(o.getKind()) {
return children
}
node.Trace("%d '%s'", page, basePath)
dirEntries, err := os.ReadDir(basePath)
if err != nil {
panic(fmt.Errorf("ReadDir %s %w", basePath, err))
}
for _, dirEntry := range dirEntries {
if !strings.HasSuffix(dirEntry.Name(), ".json") {
continue
}
node.Trace(" add %s", dirEntry.Name())
child := node.CreateChild(ctx)
i := strings.TrimSuffix(dirEntry.Name(), ".json")
childID := id.NewNodeID(i)
child.SetID(childID)
children = append(children, child)
}
return children
}
func (o *nodeDriver) Equals(context.Context, generic.NodeInterface) bool { panic("") }
func (o *nodeDriver) LookupMappedID(id id.NodeID) id.NodeID {
o.GetNode().Trace("%s", id)
return id
}
func (o *nodeDriver) hasJSON() bool {
kind := o.getKind()
if kind == f3_tree.KindForge {
return true
}
return !o.isContainer()
}
func (o *nodeDriver) Get(context.Context) bool {
o.GetNode().Trace("'%s' '%s'", o.getKind(), o.GetNode().GetID())
if !o.hasJSON() || o.GetNode().GetID() == id.NilID {
return true
}
filename := o.getBasePath() + ".json"
o.GetNode().Trace("'%s'", filename)
if !util.FileExists(filename) {
return false
}
f := o.NewFormat()
loadJSON(filename, f)
o.content = f
o.GetNode().Trace("%s %s id=%s", o.getKind(), filename, o.content.GetID())
idFilename := o.getBasePath() + ".id"
if !util.FileExists(idFilename) {
return true
}
mappedID, err := os.ReadFile(idFilename)
if err != nil {
panic(fmt.Errorf("Get %s %w", idFilename, err))
}
o.NullDriver.SetMappedID(id.NewNodeID(string(mappedID)))
return true
}
func (o *nodeDriver) SetMappedID(mapped id.NodeID) {
o.NullDriver.SetMappedID(mapped)
o.saveMappedID()
}
func (o *nodeDriver) saveMappedID() {
k := o.getKind()
switch k {
case kind.KindRoot, f3_tree.KindForge:
return
}
if o.isContainer() {
return
}
mappedID := o.GetMappedID()
if mappedID == id.NilID {
return
}
basePath := o.getBasePath()
idFilename := basePath + ".id"
o.Trace("%s", idFilename)
if err := os.WriteFile(idFilename, []byte(o.GetMappedID().String()), 0o644); err != nil {
panic(fmt.Errorf("%s %w", idFilename, err))
}
}
func (o *nodeDriver) Put(ctx context.Context) id.NodeID {
return o.upsert(ctx)
}
func (o *nodeDriver) Patch(ctx context.Context) {
o.upsert(ctx)
}
func (o *nodeDriver) upsert(context.Context) id.NodeID {
i := o.GetNode().GetID()
o.GetNode().Trace("%s %s", o.getKind(), i)
o.content.SetID(i.String())
if !o.hasJSON() || i == id.NilID {
return i
}
basePath := o.getBasePath()
dirname := filepath.Dir(basePath)
if !util.FileExists(dirname) {
if err := os.MkdirAll(dirname, 0o777); err != nil {
panic(fmt.Errorf("MakeDirAll %s %w", dirname, err))
}
}
saveJSON(basePath+".json", o.content)
o.saveMappedID()
return i
}
func (o *nodeDriver) Delete(context.Context) {
if o.isContainer() {
return
}
basePath := o.getBasePath()
if util.FileExists(basePath) {
if err := os.RemoveAll(basePath); err != nil {
panic(fmt.Errorf("RemoveAll %s %w", basePath, err))
}
}
for _, ext := range []string{".id", ".json"} {
jsonFilename := basePath + ext
if util.FileExists(jsonFilename) {
if err := os.Remove(jsonFilename); err != nil {
panic(fmt.Errorf("RemoveAll %s %w", basePath, err))
}
}
}
o.content = o.NewFormat()
}
func (o *nodeDriver) NewFormat() f3.Interface {
return o.getTree().(f3_tree.TreeInterface).NewFormat(o.getKind())
}
func (o *nodeDriver) FromFormat(content f3.Interface) {
o.content = content
}
func (o *nodeDriver) ToFormat() f3.Interface {
return o.content.Clone()
}
func (o *nodeDriver) String() string {
return o.content.GetID()
}