249 lines
5.7 KiB
Go
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()
|
|
}
|