Adding upstream version 3.10.8.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
37e9b6d587
commit
03bfe4079e
356 changed files with 28857 additions and 0 deletions
124
tree/f3/f3.go
Normal file
124
tree/f3/f3.go
Normal file
|
@ -0,0 +1,124 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package f3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/f3"
|
||||
"code.forgejo.org/f3/gof3/v3/kind"
|
||||
"code.forgejo.org/f3/gof3/v3/options"
|
||||
"code.forgejo.org/f3/gof3/v3/path"
|
||||
objects_helper "code.forgejo.org/f3/gof3/v3/tree/f3/objects"
|
||||
"code.forgejo.org/f3/gof3/v3/tree/generic"
|
||||
)
|
||||
|
||||
type treeF3 struct {
|
||||
generic.Tree
|
||||
|
||||
options options.Interface
|
||||
objectsHelper objects_helper.Interface
|
||||
}
|
||||
|
||||
type setFunc func(parent path.Path, node generic.NodeInterface)
|
||||
|
||||
type TreeInterface interface {
|
||||
generic.TreeInterface
|
||||
|
||||
IsContainer(kind.Kind) bool
|
||||
NewFormat(kind kind.Kind) f3.Interface
|
||||
CreateChild(ctx context.Context, pathString string, set setFunc)
|
||||
GetObjectsHelper() objects_helper.Interface
|
||||
}
|
||||
|
||||
func (o *treeF3) GetChildrenKind(parentKind kind.Kind) kind.Kind {
|
||||
if childrenKind, ok := childrenKind[parentKind]; ok {
|
||||
return childrenKind
|
||||
}
|
||||
panic(fmt.Errorf("unexpected kind %s", parentKind))
|
||||
}
|
||||
|
||||
func (o *treeF3) IsContainer(kind kind.Kind) bool {
|
||||
if isContainer, ok := isContainer[kind]; ok {
|
||||
return isContainer
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (o *treeF3) NewFormat(kind kind.Kind) f3.Interface {
|
||||
return f3.New(string(kind))
|
||||
}
|
||||
|
||||
func (o *treeF3) GetObjectsHelper() objects_helper.Interface {
|
||||
return o.objectsHelper
|
||||
}
|
||||
|
||||
func (o *treeF3) CreateChild(ctx context.Context, pathString string, set setFunc) {
|
||||
p := generic.NewPathFromString(pathString)
|
||||
o.Apply(ctx, p, generic.NewApplyOptions(func(ctx context.Context, parent, p path.Path, node generic.NodeInterface) {
|
||||
o.Trace("%s %s | %T %s", parent.String(), node.GetID(), node, node.GetKind())
|
||||
child := o.Factory(ctx, o.GetChildrenKind(node.GetKind()))
|
||||
child.SetParent(node)
|
||||
childParentPath := parent.Append(node)
|
||||
if set != nil {
|
||||
set(childParentPath, child)
|
||||
}
|
||||
child.Upsert(ctx)
|
||||
child.List(ctx)
|
||||
}))
|
||||
}
|
||||
|
||||
func newTreeF3(ctx context.Context, opts options.Interface) generic.TreeInterface {
|
||||
tree := &treeF3{}
|
||||
tree.Init(tree, opts)
|
||||
|
||||
tree.objectsHelper = objects_helper.NewObjectsHelper()
|
||||
|
||||
tree.SetDriver(GetForgeFactory(opts.GetName())(tree, opts))
|
||||
|
||||
tree.Register(kind.KindRoot, func(ctx context.Context, k kind.Kind) generic.NodeInterface {
|
||||
return newFixedChildrenNode(ctx, tree, []kind.Kind{KindForge})
|
||||
})
|
||||
tree.Register(KindForge, func(ctx context.Context, k kind.Kind) generic.NodeInterface {
|
||||
return newFixedChildrenNode(ctx, tree, []kind.Kind{KindTopics, KindUsers, KindOrganizations})
|
||||
})
|
||||
tree.Register(KindUser, func(ctx context.Context, k kind.Kind) generic.NodeInterface {
|
||||
return newFixedChildrenNode(ctx, tree, []kind.Kind{KindProjects})
|
||||
})
|
||||
tree.Register(KindOrganization, func(ctx context.Context, k kind.Kind) generic.NodeInterface {
|
||||
return newFixedChildrenNode(ctx, tree, []kind.Kind{KindProjects})
|
||||
})
|
||||
tree.Register(KindProject, func(ctx context.Context, k kind.Kind) generic.NodeInterface {
|
||||
return newFixedChildrenNode(ctx, tree, []kind.Kind{KindRepositories, KindLabels, KindMilestones, KindIssues, KindPullRequests, KindReleases})
|
||||
})
|
||||
tree.Register(KindIssue, func(ctx context.Context, k kind.Kind) generic.NodeInterface {
|
||||
return newFixedChildrenNode(ctx, tree, []kind.Kind{KindComments, KindReactions})
|
||||
})
|
||||
tree.Register(KindRepository, func(ctx context.Context, k kind.Kind) generic.NodeInterface {
|
||||
return newRepositoryNode(ctx, tree)
|
||||
})
|
||||
tree.Register(KindPullRequest, func(ctx context.Context, k kind.Kind) generic.NodeInterface {
|
||||
return newFixedChildrenNode(ctx, tree, []kind.Kind{KindComments, KindReactions, KindReviews})
|
||||
})
|
||||
tree.Register(KindReview, func(ctx context.Context, k kind.Kind) generic.NodeInterface {
|
||||
return newFixedChildrenNode(ctx, tree, []kind.Kind{KindReviewComments, KindReactions})
|
||||
})
|
||||
tree.Register(KindComment, func(ctx context.Context, k kind.Kind) generic.NodeInterface {
|
||||
return newFixedChildrenNode(ctx, tree, []kind.Kind{KindReactions})
|
||||
})
|
||||
tree.Register(KindRelease, func(ctx context.Context, k kind.Kind) generic.NodeInterface {
|
||||
return newFixedChildrenNode(ctx, tree, []kind.Kind{KindAssets})
|
||||
})
|
||||
|
||||
root := tree.Factory(ctx, kind.KindRoot)
|
||||
tree.SetRoot(root)
|
||||
|
||||
return tree
|
||||
}
|
||||
|
||||
func init() {
|
||||
generic.RegisterFactory("f3", newTreeF3)
|
||||
}
|
49
tree/f3/fixed_children.go
Normal file
49
tree/f3/fixed_children.go
Normal file
|
@ -0,0 +1,49 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package f3
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/id"
|
||||
"code.forgejo.org/f3/gof3/v3/kind"
|
||||
"code.forgejo.org/f3/gof3/v3/tree/generic"
|
||||
)
|
||||
|
||||
type fixedChildrenNode struct {
|
||||
generic.Node
|
||||
|
||||
kinds []kind.Kind
|
||||
}
|
||||
|
||||
func (o *fixedChildrenNode) GetChildren() generic.ChildrenSlice {
|
||||
children := generic.NewChildrenSlice(len(o.kinds))
|
||||
for _, kind := range o.kinds {
|
||||
child := o.GetChild(id.NewNodeID(kind))
|
||||
children = append(children, child)
|
||||
}
|
||||
return children
|
||||
}
|
||||
|
||||
func (o *fixedChildrenNode) ListPage(ctx context.Context, page int) generic.ChildrenSlice {
|
||||
if page > 1 {
|
||||
return generic.NewChildrenSlice(0)
|
||||
}
|
||||
return o.GetChildren()
|
||||
}
|
||||
|
||||
func newFixedChildrenNode(ctx context.Context, tree generic.TreeInterface, kinds []kind.Kind) generic.NodeInterface {
|
||||
node := &fixedChildrenNode{}
|
||||
node.Init(node)
|
||||
node.kinds = kinds
|
||||
for _, kind := range kinds {
|
||||
id := id.NewNodeID(kind)
|
||||
child := tree.Factory(ctx, kind)
|
||||
child.SetID(id)
|
||||
child.SetParent(node)
|
||||
node.SetChild(child)
|
||||
}
|
||||
return node
|
||||
}
|
30
tree/f3/forge_factory.go
Normal file
30
tree/f3/forge_factory.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package f3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/tree/generic"
|
||||
)
|
||||
|
||||
var forgeFactories = make(map[string]ForgeFactory, 10)
|
||||
|
||||
type ForgeFactory func(tree generic.TreeInterface, options any) generic.TreeDriverInterface
|
||||
|
||||
func RegisterForgeFactory(name string, factory ForgeFactory) {
|
||||
name = strings.ToLower(name)
|
||||
forgeFactories[name] = factory
|
||||
}
|
||||
|
||||
func GetForgeFactory(name string) ForgeFactory {
|
||||
name = strings.ToLower(name)
|
||||
factory, ok := forgeFactories[name]
|
||||
if !ok {
|
||||
panic(fmt.Errorf("no forge registered for %s", name))
|
||||
}
|
||||
return factory
|
||||
}
|
181
tree/f3/helpers.go
Normal file
181
tree/f3/helpers.go
Normal file
|
@ -0,0 +1,181 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package f3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/f3"
|
||||
"code.forgejo.org/f3/gof3/v3/id"
|
||||
"code.forgejo.org/f3/gof3/v3/kind"
|
||||
"code.forgejo.org/f3/gof3/v3/path"
|
||||
"code.forgejo.org/f3/gof3/v3/tree/generic"
|
||||
"code.forgejo.org/f3/gof3/v3/util"
|
||||
)
|
||||
|
||||
type ForgeDriverInterface interface {
|
||||
SetNative(native any)
|
||||
GetNativeID() string
|
||||
GetHelper() any
|
||||
}
|
||||
|
||||
func ConvertToAny[T any](s ...T) []any {
|
||||
a := make([]any, 0, len(s))
|
||||
for _, e := range s {
|
||||
a = append(a, e)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func ConvertNativeChild(ctx context.Context, tree generic.TreeInterface, parent generic.NodeInterface, kind kind.Kind, nativeChild any) generic.NodeInterface {
|
||||
child := tree.Factory(ctx, kind)
|
||||
child.SetParent(parent)
|
||||
childDriver := child.GetDriver().(ForgeDriverInterface)
|
||||
childDriver.SetNative(nativeChild)
|
||||
child.SetID(id.NewNodeID(childDriver.GetNativeID()))
|
||||
return child
|
||||
}
|
||||
|
||||
func ConvertListed(ctx context.Context, node generic.NodeInterface, nativeChildren ...any) generic.ChildrenSlice {
|
||||
children := generic.NewChildrenSlice(len(nativeChildren))
|
||||
|
||||
tree := node.GetTree()
|
||||
f3Tree := tree.(TreeInterface)
|
||||
kind := f3Tree.GetChildrenKind(node.GetKind())
|
||||
|
||||
for _, nativeChild := range nativeChildren {
|
||||
children = append(children, ConvertNativeChild(ctx, tree, node, kind, nativeChild))
|
||||
}
|
||||
return children
|
||||
}
|
||||
|
||||
func GetFirstNodeKind(node generic.NodeInterface, kind ...kind.Kind) generic.NodeInterface {
|
||||
if slices.Contains(kind, node.GetKind()) {
|
||||
return node
|
||||
}
|
||||
parent := node.GetParent()
|
||||
if parent == generic.NilNode {
|
||||
return generic.NilNode
|
||||
}
|
||||
return GetFirstNodeKind(parent, kind...)
|
||||
}
|
||||
|
||||
func GetFirstFormat[T f3.Interface](node generic.NodeInterface) T {
|
||||
f := node.NewFormat()
|
||||
switch f.(type) {
|
||||
case T:
|
||||
return node.ToFormat().(T)
|
||||
}
|
||||
parent := node.GetParent()
|
||||
if parent == generic.NilNode {
|
||||
panic(fmt.Errorf("no parent of the desired type"))
|
||||
}
|
||||
return GetFirstFormat[T](parent)
|
||||
}
|
||||
|
||||
func GetProject(node generic.NodeInterface) generic.NodeInterface {
|
||||
return GetFirstNodeKind(node, KindProject)
|
||||
}
|
||||
|
||||
func GetProjectID(node generic.NodeInterface) int64 {
|
||||
return util.ParseInt(GetProject(node).GetID().String())
|
||||
}
|
||||
|
||||
func GetProjectName(node generic.NodeInterface) string {
|
||||
return GetProject(node).ToFormat().(*f3.Project).Name
|
||||
}
|
||||
|
||||
func GetOwner(node generic.NodeInterface) generic.NodeInterface {
|
||||
return GetFirstNodeKind(node, KindUser, KindOrganization)
|
||||
}
|
||||
|
||||
func GetOwnerID(node generic.NodeInterface) int64 {
|
||||
return GetOwner(node).GetID().Int64()
|
||||
}
|
||||
|
||||
func GetReactionable(node generic.NodeInterface) generic.NodeInterface {
|
||||
return GetFirstNodeKind(node, KindComment, KindIssue, KindPullRequest)
|
||||
}
|
||||
|
||||
func GetReactionableID(node generic.NodeInterface) int64 {
|
||||
return GetReactionable(node).GetID().Int64()
|
||||
}
|
||||
|
||||
func GetCommentable(node generic.NodeInterface) generic.NodeInterface {
|
||||
return GetFirstNodeKind(node, KindIssue, KindPullRequest)
|
||||
}
|
||||
|
||||
func GetCommentableID(node generic.NodeInterface) int64 {
|
||||
return GetCommentable(node).GetID().Int64()
|
||||
}
|
||||
|
||||
func GetComment(node generic.NodeInterface) generic.NodeInterface {
|
||||
return GetFirstNodeKind(node, KindComment, KindReviewComment)
|
||||
}
|
||||
|
||||
func GetCommentID(node generic.NodeInterface) int64 {
|
||||
return GetComment(node).GetID().Int64()
|
||||
}
|
||||
|
||||
func GetRelease(node generic.NodeInterface) generic.NodeInterface {
|
||||
return GetFirstNodeKind(node, KindRelease)
|
||||
}
|
||||
|
||||
func GetReleaseID(node generic.NodeInterface) int64 {
|
||||
return GetRelease(node).GetID().Int64()
|
||||
}
|
||||
|
||||
func GetPullRequest(node generic.NodeInterface) generic.NodeInterface {
|
||||
return GetFirstNodeKind(node, KindPullRequest)
|
||||
}
|
||||
|
||||
func GetPullRequestID(node generic.NodeInterface) int64 {
|
||||
return GetPullRequest(node).GetID().Int64()
|
||||
}
|
||||
|
||||
func GetReview(node generic.NodeInterface) generic.NodeInterface {
|
||||
return GetFirstNodeKind(node, KindReview)
|
||||
}
|
||||
|
||||
func GetReviewID(node generic.NodeInterface) int64 {
|
||||
return GetReview(node).GetID().Int64()
|
||||
}
|
||||
|
||||
func GetReviewComment(node generic.NodeInterface) generic.NodeInterface {
|
||||
return GetFirstNodeKind(node, KindReviewComment)
|
||||
}
|
||||
|
||||
func GetReviewCommentID(node generic.NodeInterface) int64 {
|
||||
return GetReviewComment(node).GetID().Int64()
|
||||
}
|
||||
|
||||
func GetOwnerName(node generic.NodeInterface) string {
|
||||
owner := GetOwner(node)
|
||||
if owner == generic.NilNode {
|
||||
panic(fmt.Errorf("no user or organization parent for %s", node))
|
||||
}
|
||||
switch f := owner.ToFormat().(type) {
|
||||
case *f3.User:
|
||||
return f.UserName
|
||||
case *f3.Organization:
|
||||
return f.Name
|
||||
default:
|
||||
panic(fmt.Errorf("unexpected type %T", owner.ToFormat()))
|
||||
}
|
||||
}
|
||||
|
||||
func GetUsernameFromID(ctx context.Context, tree TreeInterface, id int64) string {
|
||||
var name string
|
||||
getName := func(ctx context.Context, parent, p path.Path, node generic.NodeInterface) {
|
||||
name = node.ToFormat().(*f3.User).UserName
|
||||
}
|
||||
p := NewUserPath(id)
|
||||
if !tree.ApplyAndGet(ctx, p, generic.NewApplyOptions(getName)) {
|
||||
panic(fmt.Errorf("%s not found", p))
|
||||
}
|
||||
return name
|
||||
}
|
102
tree/f3/kind.go
Normal file
102
tree/f3/kind.go
Normal file
|
@ -0,0 +1,102 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package f3
|
||||
|
||||
import (
|
||||
"code.forgejo.org/f3/gof3/v3/f3"
|
||||
"code.forgejo.org/f3/gof3/v3/kind"
|
||||
)
|
||||
|
||||
const (
|
||||
KindAsset = f3.ResourceAsset
|
||||
KindAssets = f3.ResourceAssets
|
||||
KindComment = f3.ResourceComment
|
||||
KindComments = f3.ResourceComments
|
||||
KindForge = f3.ResourceForge
|
||||
KindIssue = f3.ResourceIssue
|
||||
KindIssues = f3.ResourceIssues
|
||||
KindLabel = f3.ResourceLabel
|
||||
KindLabels = f3.ResourceLabels
|
||||
KindMilestone = f3.ResourceMilestone
|
||||
KindMilestones = f3.ResourceMilestones
|
||||
KindOrganization = f3.ResourceOrganization
|
||||
KindOrganizations = f3.ResourceOrganizations
|
||||
KindProject = f3.ResourceProject
|
||||
KindProjects = f3.ResourceProjects
|
||||
KindPullRequest = f3.ResourcePullRequest
|
||||
KindPullRequests = f3.ResourcePullRequests
|
||||
KindReaction = f3.ResourceReaction
|
||||
KindReactions = f3.ResourceReactions
|
||||
KindRelease = f3.ResourceRelease
|
||||
KindReleases = f3.ResourceReleases
|
||||
KindRepository = f3.ResourceRepository
|
||||
KindRepositories = f3.ResourceRepositories
|
||||
KindReview = f3.ResourceReview
|
||||
KindReviews = f3.ResourceReviews
|
||||
KindReviewComment = f3.ResourceReviewComment
|
||||
KindReviewComments = f3.ResourceReviewComments
|
||||
KindTopic = f3.ResourceTopic
|
||||
KindTopics = f3.ResourceTopics
|
||||
KindUser = f3.ResourceUser
|
||||
KindUsers = f3.ResourceUsers
|
||||
)
|
||||
|
||||
var isContainer = map[kind.Kind]bool{
|
||||
kind.KindRoot: true,
|
||||
KindAssets: true,
|
||||
KindComments: true,
|
||||
KindIssues: true,
|
||||
KindLabels: true,
|
||||
KindMilestones: true,
|
||||
KindOrganizations: true,
|
||||
KindProjects: true,
|
||||
KindPullRequests: true,
|
||||
KindReactions: true,
|
||||
KindReleases: true,
|
||||
KindRepositories: true,
|
||||
KindReviews: true,
|
||||
KindReviewComments: true,
|
||||
KindTopics: true,
|
||||
KindUsers: true,
|
||||
}
|
||||
|
||||
var childrenKind = map[kind.Kind]kind.Kind{
|
||||
kind.KindRoot: KindForge,
|
||||
KindAssets: KindAsset,
|
||||
KindComments: KindComment,
|
||||
KindIssues: KindIssue,
|
||||
KindLabels: KindLabel,
|
||||
KindMilestones: KindMilestone,
|
||||
KindOrganizations: KindOrganization,
|
||||
KindProjects: KindProject,
|
||||
KindPullRequests: KindPullRequest,
|
||||
KindReactions: KindReaction,
|
||||
KindReleases: KindRelease,
|
||||
KindRepositories: KindRepository,
|
||||
KindReviews: KindReview,
|
||||
KindReviewComments: KindReviewComment,
|
||||
KindTopics: KindTopic,
|
||||
KindUsers: KindUser,
|
||||
}
|
||||
|
||||
var containerChildFixedID = map[kind.Kind]bool{
|
||||
kind.KindRoot: true,
|
||||
KindAssets: false,
|
||||
KindComments: false,
|
||||
KindForge: true,
|
||||
KindIssues: false,
|
||||
KindLabels: false,
|
||||
KindMilestones: false,
|
||||
KindOrganizations: false,
|
||||
KindProjects: false,
|
||||
KindPullRequests: false,
|
||||
KindReactions: false,
|
||||
KindReleases: false,
|
||||
KindRepositories: false,
|
||||
KindReviewComments: false,
|
||||
KindReviews: false,
|
||||
KindTopics: false,
|
||||
KindUsers: false,
|
||||
}
|
27
tree/f3/label.go
Normal file
27
tree/f3/label.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package f3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/f3"
|
||||
)
|
||||
|
||||
func NewLabelPathString[T any](projectPath string, id T) string {
|
||||
return fmt.Sprintf("%s/labels/%v", projectPath, id)
|
||||
}
|
||||
|
||||
func NewLabelReference[T any](projectPath string, id T) *f3.Reference {
|
||||
return f3.NewReference(NewLabelPathString(projectPath, id))
|
||||
}
|
||||
|
||||
func NewIssueLabelReference[T any](id T) *f3.Reference {
|
||||
return f3.NewReference(NewLabelPathString("../..", id))
|
||||
}
|
||||
|
||||
func NewPullRequestLabelReference[T any](id T) *f3.Reference {
|
||||
return f3.NewReference(NewLabelPathString("../..", id))
|
||||
}
|
23
tree/f3/milestone.go
Normal file
23
tree/f3/milestone.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package f3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/f3"
|
||||
)
|
||||
|
||||
func NewMilestonePathString[T any](projectPath string, id T) string {
|
||||
return fmt.Sprintf("%s/milestones/%v", projectPath, id)
|
||||
}
|
||||
|
||||
func NewMilestoneReference[T any](projectPath string, id T) *f3.Reference {
|
||||
return f3.NewReference(NewMilestonePathString(projectPath, id))
|
||||
}
|
||||
|
||||
func NewIssueMilestoneReference[T any](id T) *f3.Reference {
|
||||
return f3.NewReference(NewMilestonePathString("../..", id))
|
||||
}
|
99
tree/f3/objects/objects.go
Normal file
99
tree/f3/objects/objects.go
Normal file
|
@ -0,0 +1,99 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package objects
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
Save(rc io.ReadCloser) (string, string)
|
||||
}
|
||||
|
||||
type helper struct {
|
||||
dir *string
|
||||
}
|
||||
|
||||
func (o *helper) getDir() string {
|
||||
if o.dir == nil {
|
||||
dir, err := os.MkdirTemp("", "objectHelper")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
runtime.SetFinalizer(o, func(o *helper) {
|
||||
err := os.RemoveAll(dir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
o.dir = &dir
|
||||
}
|
||||
return *o.dir
|
||||
}
|
||||
|
||||
func (o *helper) getPath(sha string) string {
|
||||
return filepath.Join(o.getDir(), sha[0:2], sha[2:4], sha)
|
||||
}
|
||||
|
||||
func (o *helper) Save(rc io.ReadCloser) (string, string) {
|
||||
tempFile, err := os.CreateTemp("", "object")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
tempRemoved := false
|
||||
defer func() {
|
||||
if !tempRemoved {
|
||||
_ = os.Remove(tempFile.Name())
|
||||
}
|
||||
}()
|
||||
|
||||
// reader
|
||||
defer rc.Close()
|
||||
|
||||
// writer to file
|
||||
f, err := os.OpenFile(tempFile.Name(), os.O_CREATE|os.O_RDWR, 0o644)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// writer to sha256
|
||||
h := sha256.New()
|
||||
|
||||
// copy reader to file & sha256
|
||||
w := io.MultiWriter(f, h)
|
||||
if _, err := io.Copy(w, rc); err != nil {
|
||||
panic(fmt.Errorf("while copying object: %w", err))
|
||||
}
|
||||
|
||||
// finalize writer to sha256
|
||||
sha := hex.EncodeToString(h.Sum(nil))
|
||||
|
||||
// finalize writer to file
|
||||
if err := tempFile.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
path := o.getPath(sha)
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := os.Rename(tempFile.Name(), path); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
tempRemoved = true
|
||||
|
||||
return sha, path
|
||||
}
|
||||
|
||||
func NewObjectsHelper() Interface {
|
||||
return &helper{}
|
||||
}
|
68
tree/f3/objects/sha.go
Normal file
68
tree/f3/objects/sha.go
Normal file
|
@ -0,0 +1,68 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package objects
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
options_http "code.forgejo.org/f3/gof3/v3/options/http"
|
||||
)
|
||||
|
||||
type SHASetter interface {
|
||||
SetSHA(sha string)
|
||||
}
|
||||
|
||||
func FuncReadURLAndSetSHA(newHTTPClient options_http.NewMigrationHTTPClientFun, url string, sha SHASetter) func() io.ReadCloser {
|
||||
return func() io.ReadCloser {
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
httpClient := newHTTPClient()
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("while downloading %s %w", url, err))
|
||||
}
|
||||
|
||||
return FuncReadAndSetSHA(resp.Body, sha)()
|
||||
}
|
||||
}
|
||||
|
||||
type readAndSetSHA struct {
|
||||
reader io.Reader
|
||||
closer io.Closer
|
||||
sha SHASetter
|
||||
hasher hash.Hash
|
||||
}
|
||||
|
||||
func (o *readAndSetSHA) Read(b []byte) (n int, err error) {
|
||||
return o.reader.Read(b)
|
||||
}
|
||||
|
||||
func (o *readAndSetSHA) Close() error {
|
||||
o.sha.SetSHA(hex.EncodeToString(o.hasher.Sum(nil)))
|
||||
return o.closer.Close()
|
||||
}
|
||||
|
||||
func newReadAndSetSHA(reader io.ReadCloser, sha SHASetter) *readAndSetSHA {
|
||||
hasher := sha256.New()
|
||||
return &readAndSetSHA{
|
||||
reader: io.TeeReader(reader, hasher),
|
||||
closer: reader,
|
||||
sha: sha,
|
||||
hasher: hasher,
|
||||
}
|
||||
}
|
||||
|
||||
func FuncReadAndSetSHA(reader io.ReadCloser, sha SHASetter) func() io.ReadCloser {
|
||||
return func() io.ReadCloser {
|
||||
return newReadAndSetSHA(reader, sha)
|
||||
}
|
||||
}
|
35
tree/f3/objects/sha_test.go
Normal file
35
tree/f3/objects/sha_test.go
Normal file
|
@ -0,0 +1,35 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package objects
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type sha string
|
||||
|
||||
func (o *sha) SetSHA(s string) {
|
||||
*o = sha(s)
|
||||
}
|
||||
|
||||
func (o *sha) GetSHA() string {
|
||||
return string(*o)
|
||||
}
|
||||
|
||||
func Test_FuncReadAndSetSHA(t *testing.T) {
|
||||
content := "CONTENT"
|
||||
r := strings.NewReader(content)
|
||||
s := new(sha)
|
||||
f := FuncReadAndSetSHA(io.NopCloser(r), s)()
|
||||
c, err := io.ReadAll(f)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, f.Close())
|
||||
require.Equal(t, "65f23e22a9bfedda96929b3cfcb8b6d2fdd34a2e877ddb81f45d79ab05710e12", s.GetSHA())
|
||||
require.Equal(t, content, string(c))
|
||||
}
|
11
tree/f3/organizations.go
Normal file
11
tree/f3/organizations.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package f3
|
||||
|
||||
import (
|
||||
"code.forgejo.org/f3/gof3/v3/tree/generic"
|
||||
)
|
||||
|
||||
var OrganizationsPath = generic.NewPathFromString("/forge/organizations")
|
188
tree/f3/path.go
Normal file
188
tree/f3/path.go
Normal file
|
@ -0,0 +1,188 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package f3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/id"
|
||||
"code.forgejo.org/f3/gof3/v3/kind"
|
||||
generic_path "code.forgejo.org/f3/gof3/v3/path"
|
||||
"code.forgejo.org/f3/gof3/v3/tree/generic"
|
||||
)
|
||||
|
||||
type Path interface {
|
||||
NodeIDs() []id.NodeID
|
||||
OwnerAndProjectID() (owner, project int64)
|
||||
|
||||
AppendID(id string) Path
|
||||
Ignore() Path
|
||||
|
||||
generic_path.Path
|
||||
Root() Path
|
||||
|
||||
Forge() Path
|
||||
SetForge() Path
|
||||
|
||||
Assets() Path
|
||||
SetAssets() Path
|
||||
|
||||
Comments() Path
|
||||
SetComments() Path
|
||||
|
||||
Issues() Path
|
||||
SetIssues() Path
|
||||
|
||||
Labels() Path
|
||||
SetLabels() Path
|
||||
|
||||
Milestones() Path
|
||||
SetMilestones() Path
|
||||
|
||||
Owners() Path
|
||||
SetOwners(owners kind.Kind) Path
|
||||
|
||||
Organizations() Path
|
||||
SetOrganizations() Path
|
||||
|
||||
Projects() Path
|
||||
SetProjects() Path
|
||||
|
||||
PullRequests() Path
|
||||
SetPullRequests() Path
|
||||
|
||||
Reactions() Path
|
||||
SetReactions() Path
|
||||
|
||||
Releases() Path
|
||||
SetReleases() Path
|
||||
|
||||
Repositories() Path
|
||||
SetRepositories() Path
|
||||
|
||||
Reviews() Path
|
||||
SetReviews() Path
|
||||
|
||||
ReviewComments() Path
|
||||
SetReviewComments() Path
|
||||
|
||||
Topics() Path
|
||||
SetTopics() Path
|
||||
|
||||
Users() Path
|
||||
SetUsers() Path
|
||||
}
|
||||
|
||||
type f3path struct {
|
||||
generic_path.Implementation
|
||||
}
|
||||
|
||||
func (o f3path) popKind(k ...kind.Kind) Path {
|
||||
firstKind := kind.Kind(o.First().(generic.NodeInterface).GetID().String())
|
||||
if !slices.Contains(k, firstKind) {
|
||||
panic(fmt.Errorf("%s expected one of %s got %s", o, k, firstKind))
|
||||
}
|
||||
return ToPath(o.RemoveFirst())
|
||||
}
|
||||
|
||||
func (o f3path) NodeIDs() []id.NodeID {
|
||||
nodeIDs := make([]id.NodeID, 0, o.Length())
|
||||
collectID := false
|
||||
for _, node := range o.Root().All() {
|
||||
if collectID {
|
||||
nodeIDs = append(nodeIDs, node.(generic.NodeInterface).GetID())
|
||||
collectID = false
|
||||
continue
|
||||
}
|
||||
kind := kind.Kind(node.(generic.NodeInterface).GetID().String())
|
||||
fixedID, ok := containerChildFixedID[kind]
|
||||
if !ok {
|
||||
panic(fmt.Errorf("%s unexpected kind %s", o.All(), kind))
|
||||
}
|
||||
if !fixedID {
|
||||
collectID = true
|
||||
}
|
||||
}
|
||||
return nodeIDs
|
||||
}
|
||||
|
||||
func (o f3path) OwnerAndProjectID() (owner, project int64) {
|
||||
nodeIDs := o.NodeIDs()
|
||||
return nodeIDs[0].Int64(), nodeIDs[1].Int64()
|
||||
}
|
||||
|
||||
func (o f3path) Root() Path { return o.popKind(kind.Kind("")) }
|
||||
|
||||
func (o f3path) Forge() Path { return o.popKind(KindForge) }
|
||||
func (o f3path) SetForge() Path { return o.appendKind(KindForge) }
|
||||
|
||||
func (o f3path) Assets() Path { return o.popKind(KindAssets) }
|
||||
func (o f3path) SetAssets() Path { return o.appendKind(KindAssets) }
|
||||
|
||||
func (o f3path) Comments() Path { return o.popKind(KindComments) }
|
||||
func (o f3path) SetComments() Path { return o.appendKind(KindComments) }
|
||||
|
||||
func (o f3path) Issues() Path { return o.popKind(KindIssues) }
|
||||
func (o f3path) SetIssues() Path { return o.appendKind(KindIssues) }
|
||||
|
||||
func (o f3path) Labels() Path { return o.popKind(KindLabels) }
|
||||
func (o f3path) SetLabels() Path { return o.appendKind(KindLabels) }
|
||||
|
||||
func (o f3path) Milestones() Path { return o.popKind(KindMilestones) }
|
||||
func (o f3path) SetMilestones() Path { return o.appendKind(KindMilestones) }
|
||||
|
||||
func (o f3path) Organizations() Path { return o.popKind(KindOrganizations) }
|
||||
func (o f3path) SetOrganizations() Path { return o.appendKind(KindOrganizations) }
|
||||
|
||||
func (o f3path) Projects() Path { return o.popKind(KindProjects) }
|
||||
func (o f3path) SetProjects() Path { return o.appendKind(KindProjects) }
|
||||
|
||||
func (o f3path) PullRequests() Path { return o.popKind(KindPullRequests) }
|
||||
func (o f3path) SetPullRequests() Path { return o.appendKind(KindPullRequests) }
|
||||
|
||||
func (o f3path) Reactions() Path { return o.popKind(KindReactions) }
|
||||
func (o f3path) SetReactions() Path { return o.appendKind(KindReactions) }
|
||||
|
||||
func (o f3path) Releases() Path { return o.popKind(KindReleases) }
|
||||
func (o f3path) SetReleases() Path { return o.appendKind(KindReleases) }
|
||||
|
||||
func (o f3path) Repositories() Path { return o.popKind(KindRepositories) }
|
||||
func (o f3path) SetRepositories() Path { return o.appendKind(KindRepositories) }
|
||||
|
||||
func (o f3path) Reviews() Path { return o.popKind(KindReviews) }
|
||||
func (o f3path) SetReviews() Path { return o.appendKind(KindReviews) }
|
||||
|
||||
func (o f3path) ReviewComments() Path { return o.popKind(KindReviewComments) }
|
||||
func (o f3path) SetReviewComments() Path { return o.appendKind(KindReviewComments) }
|
||||
|
||||
func (o f3path) Topics() Path { return o.popKind(KindTopics) }
|
||||
func (o f3path) SetTopics() Path { return o.appendKind(KindTopics) }
|
||||
|
||||
func (o f3path) Users() Path { return o.popKind(KindUsers) }
|
||||
func (o f3path) SetUsers() Path { return o.appendKind(KindUsers) }
|
||||
|
||||
func (o f3path) Owners() Path { return o.popKind(KindUsers, KindOrganizations) }
|
||||
func (o f3path) SetOwners(owners kind.Kind) Path { return o.appendKind(owners) }
|
||||
|
||||
func (o f3path) AppendID(id string) Path {
|
||||
return ToPath(o.Append(generic.NewNodeFromID(id)))
|
||||
}
|
||||
|
||||
func (o f3path) appendKind(kind kind.Kind) Path {
|
||||
return o.AppendID(string(kind))
|
||||
}
|
||||
|
||||
func (o f3path) Ignore() Path {
|
||||
return ToPath(o.RemoveFirst())
|
||||
}
|
||||
|
||||
func ToPath(other generic_path.Path) Path {
|
||||
return f3path{other.(generic_path.Implementation)}
|
||||
}
|
||||
|
||||
func NewPathFromString(pathString string) Path {
|
||||
return ToPath(generic.NewPathFromString(pathString))
|
||||
}
|
181
tree/f3/path_test.go
Normal file
181
tree/f3/path_test.go
Normal file
|
@ -0,0 +1,181 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package f3
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/id"
|
||||
"code.forgejo.org/f3/gof3/v3/tree/generic"
|
||||
"code.forgejo.org/f3/gof3/v3/util"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestF3Path(t *testing.T) {
|
||||
p := NewPathFromString("/")
|
||||
p = p.SetForge()
|
||||
{
|
||||
p.Root().Forge()
|
||||
}
|
||||
nodeIDs := make([]id.NodeID, 0, 10)
|
||||
{
|
||||
p := p.SetOwners(KindUsers)
|
||||
i := "1"
|
||||
ownerID := util.ParseInt(i)
|
||||
nodeIDs := append(nodeIDs, id.NewNodeID(i))
|
||||
p = p.AppendID(i)
|
||||
assert.EqualValues(t, id.NewNodeID(i), p.Root().Forge().Users().First().(generic.NodeInterface).GetID())
|
||||
assert.EqualValues(t, nodeIDs, p.NodeIDs())
|
||||
|
||||
{
|
||||
p := p.SetProjects()
|
||||
i := "2"
|
||||
projectID := util.ParseInt(i)
|
||||
nodeIDs := append(nodeIDs, id.NewNodeID(i))
|
||||
p = p.AppendID(i)
|
||||
assert.EqualValues(t, id.NewNodeID(i), p.Root().Forge().Users().Ignore().Projects().First().(generic.NodeInterface).GetID())
|
||||
assert.EqualValues(t, nodeIDs, p.NodeIDs())
|
||||
owner, project := p.OwnerAndProjectID()
|
||||
assert.EqualValues(t, ownerID, owner)
|
||||
assert.EqualValues(t, projectID, project)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
p := p.SetAssets()
|
||||
i := "something"
|
||||
nodeIDs := append(nodeIDs, id.NewNodeID(i))
|
||||
p = p.AppendID(i)
|
||||
assert.EqualValues(t, id.NewNodeID(i), p.Root().Forge().Assets().First().(generic.NodeInterface).GetID())
|
||||
assert.EqualValues(t, nodeIDs, p.NodeIDs())
|
||||
}
|
||||
|
||||
{
|
||||
p := p.SetComments()
|
||||
i := "something"
|
||||
nodeIDs := append(nodeIDs, id.NewNodeID(i))
|
||||
p = p.AppendID(i)
|
||||
assert.EqualValues(t, id.NewNodeID(i), p.Root().Forge().Comments().First().(generic.NodeInterface).GetID())
|
||||
assert.EqualValues(t, nodeIDs, p.NodeIDs())
|
||||
}
|
||||
|
||||
{
|
||||
p := p.SetIssues()
|
||||
i := "something"
|
||||
nodeIDs := append(nodeIDs, id.NewNodeID(i))
|
||||
p = p.AppendID(i)
|
||||
assert.EqualValues(t, id.NewNodeID(i), p.Root().Forge().Issues().First().(generic.NodeInterface).GetID())
|
||||
assert.EqualValues(t, nodeIDs, p.NodeIDs())
|
||||
}
|
||||
|
||||
{
|
||||
p := p.SetLabels()
|
||||
i := "something"
|
||||
nodeIDs := append(nodeIDs, id.NewNodeID(i))
|
||||
p = p.AppendID(i)
|
||||
assert.EqualValues(t, id.NewNodeID(i), p.Root().Forge().Labels().First().(generic.NodeInterface).GetID())
|
||||
assert.EqualValues(t, nodeIDs, p.NodeIDs())
|
||||
}
|
||||
|
||||
{
|
||||
p := p.SetMilestones()
|
||||
i := "something"
|
||||
nodeIDs := append(nodeIDs, id.NewNodeID(i))
|
||||
p = p.AppendID(i)
|
||||
assert.EqualValues(t, id.NewNodeID(i), p.Root().Forge().Milestones().First().(generic.NodeInterface).GetID())
|
||||
assert.EqualValues(t, nodeIDs, p.NodeIDs())
|
||||
}
|
||||
|
||||
{
|
||||
p := p.SetOrganizations()
|
||||
i := "something"
|
||||
nodeIDs := append(nodeIDs, id.NewNodeID(i))
|
||||
p = p.AppendID(i)
|
||||
assert.EqualValues(t, id.NewNodeID(i), p.Root().Forge().Organizations().First().(generic.NodeInterface).GetID())
|
||||
assert.EqualValues(t, nodeIDs, p.NodeIDs())
|
||||
}
|
||||
|
||||
{
|
||||
p := p.SetProjects()
|
||||
i := "something"
|
||||
nodeIDs := append(nodeIDs, id.NewNodeID(i))
|
||||
p = p.AppendID(i)
|
||||
assert.EqualValues(t, id.NewNodeID(i), p.Root().Forge().Projects().First().(generic.NodeInterface).GetID())
|
||||
assert.EqualValues(t, nodeIDs, p.NodeIDs())
|
||||
}
|
||||
|
||||
{
|
||||
p := p.SetPullRequests()
|
||||
i := "something"
|
||||
nodeIDs := append(nodeIDs, id.NewNodeID(i))
|
||||
p = p.AppendID(i)
|
||||
assert.EqualValues(t, id.NewNodeID(i), p.Root().Forge().PullRequests().First().(generic.NodeInterface).GetID())
|
||||
assert.EqualValues(t, nodeIDs, p.NodeIDs())
|
||||
}
|
||||
|
||||
{
|
||||
p := p.SetReactions()
|
||||
i := "something"
|
||||
nodeIDs := append(nodeIDs, id.NewNodeID(i))
|
||||
p = p.AppendID(i)
|
||||
assert.EqualValues(t, id.NewNodeID(i), p.Root().Forge().Reactions().First().(generic.NodeInterface).GetID())
|
||||
assert.EqualValues(t, nodeIDs, p.NodeIDs())
|
||||
}
|
||||
|
||||
{
|
||||
p := p.SetReleases()
|
||||
i := "something"
|
||||
nodeIDs := append(nodeIDs, id.NewNodeID(i))
|
||||
p = p.AppendID(i)
|
||||
assert.EqualValues(t, id.NewNodeID(i), p.Root().Forge().Releases().First().(generic.NodeInterface).GetID())
|
||||
assert.EqualValues(t, nodeIDs, p.NodeIDs())
|
||||
}
|
||||
|
||||
{
|
||||
p := p.SetRepositories()
|
||||
i := "something"
|
||||
nodeIDs := append(nodeIDs, id.NewNodeID(i))
|
||||
p = p.AppendID(i)
|
||||
assert.EqualValues(t, id.NewNodeID(i), p.Root().Forge().Repositories().First().(generic.NodeInterface).GetID())
|
||||
assert.EqualValues(t, nodeIDs, p.NodeIDs())
|
||||
}
|
||||
|
||||
{
|
||||
p := p.SetReviews()
|
||||
i := "something"
|
||||
nodeIDs := append(nodeIDs, id.NewNodeID(i))
|
||||
p = p.AppendID(i)
|
||||
assert.EqualValues(t, id.NewNodeID(i), p.Root().Forge().Reviews().First().(generic.NodeInterface).GetID())
|
||||
assert.EqualValues(t, nodeIDs, p.NodeIDs())
|
||||
}
|
||||
|
||||
{
|
||||
p := p.SetReviewComments()
|
||||
i := "something"
|
||||
nodeIDs := append(nodeIDs, id.NewNodeID(i))
|
||||
p = p.AppendID(i)
|
||||
assert.EqualValues(t, id.NewNodeID(i), p.Root().Forge().ReviewComments().First().(generic.NodeInterface).GetID())
|
||||
assert.EqualValues(t, nodeIDs, p.NodeIDs())
|
||||
}
|
||||
|
||||
{
|
||||
p := p.SetTopics()
|
||||
i := "something"
|
||||
nodeIDs := append(nodeIDs, id.NewNodeID(i))
|
||||
p = p.AppendID(i)
|
||||
assert.EqualValues(t, id.NewNodeID(i), p.Root().Forge().Topics().First().(generic.NodeInterface).GetID())
|
||||
assert.EqualValues(t, nodeIDs, p.NodeIDs())
|
||||
}
|
||||
|
||||
{
|
||||
p := p.SetUsers()
|
||||
i := "something"
|
||||
nodeIDs := append(nodeIDs, id.NewNodeID(i))
|
||||
p = p.AppendID(i)
|
||||
assert.EqualValues(t, id.NewNodeID(i), p.Root().Forge().Users().First().(generic.NodeInterface).GetID())
|
||||
assert.EqualValues(t, nodeIDs, p.NodeIDs())
|
||||
}
|
||||
}
|
29
tree/f3/project.go
Normal file
29
tree/f3/project.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package f3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/f3"
|
||||
"code.forgejo.org/f3/gof3/v3/tree/generic"
|
||||
)
|
||||
|
||||
func NewProjectPathString[U, P any](owners string, user U, project P) string {
|
||||
return fmt.Sprintf("/forge/%s/%v/projects/%v", owners, user, project)
|
||||
}
|
||||
|
||||
func NewProjectReference[U, P any](owners string, user U, project P) *f3.Reference {
|
||||
return f3.NewReference(NewProjectPathString(owners, user, project))
|
||||
}
|
||||
|
||||
func ResolveProjectReference(ctx context.Context, tree generic.TreeInterface, r *f3.Reference) (string, string) {
|
||||
project := tree.Find(generic.NewPathFromString(r.Get()))
|
||||
if project == generic.NilNode {
|
||||
panic(fmt.Errorf("%s not found", r.Get()))
|
||||
}
|
||||
return GetOwnerName(project), GetProjectName(project)
|
||||
}
|
47
tree/f3/pullrequest.go
Normal file
47
tree/f3/pullrequest.go
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package f3
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/tree/generic"
|
||||
)
|
||||
|
||||
type PullRequestDriverInterface interface {
|
||||
GetPullRequestHead() string
|
||||
GetPullRequestRef() string
|
||||
GetPullRequestPushRefs() []string
|
||||
}
|
||||
|
||||
type PullRequestNodeDriverProxyInterface interface {
|
||||
PullRequestDriverInterface
|
||||
}
|
||||
|
||||
type PullRequestNodeInterface interface {
|
||||
generic.NodeInterface
|
||||
PullRequestNodeDriverProxyInterface
|
||||
}
|
||||
|
||||
type pullRequestNode struct {
|
||||
generic.Node
|
||||
}
|
||||
|
||||
func (o *pullRequestNode) GetPullRequestHead() string {
|
||||
return o.GetDriver().(PullRequestDriverInterface).GetPullRequestHead()
|
||||
}
|
||||
|
||||
func (o *pullRequestNode) GetPullRequestRef() string {
|
||||
return o.GetDriver().(PullRequestDriverInterface).GetPullRequestRef()
|
||||
}
|
||||
|
||||
func (o *pullRequestNode) GetPullRequestPushRefs() []string {
|
||||
return o.GetDriver().(PullRequestDriverInterface).GetPullRequestPushRefs()
|
||||
}
|
||||
|
||||
func newPullRequestNode(ctx context.Context, tree generic.TreeInterface) generic.NodeInterface {
|
||||
node := &pullRequestNode{}
|
||||
return node.Init(node)
|
||||
}
|
66
tree/f3/repository.go
Normal file
66
tree/f3/repository.go
Normal file
|
@ -0,0 +1,66 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package f3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/f3"
|
||||
"code.forgejo.org/f3/gof3/v3/path"
|
||||
"code.forgejo.org/f3/gof3/v3/tree/generic"
|
||||
)
|
||||
|
||||
type RepositoryDriverInterface interface {
|
||||
GetRepositoryURL() string
|
||||
GetRepositoryPushURL() string
|
||||
GetRepositoryInternalRefs() []string
|
||||
}
|
||||
|
||||
type RepositoryNodeDriverProxyInterface interface {
|
||||
RepositoryDriverInterface
|
||||
}
|
||||
|
||||
type RepositoryNodeInterface interface {
|
||||
generic.NodeInterface
|
||||
RepositoryNodeDriverProxyInterface
|
||||
}
|
||||
|
||||
type repositoryNode struct {
|
||||
generic.Node
|
||||
}
|
||||
|
||||
func (o *repositoryNode) GetRepositoryURL() string {
|
||||
return o.GetDriver().(RepositoryDriverInterface).GetRepositoryURL()
|
||||
}
|
||||
|
||||
func (o *repositoryNode) GetRepositoryPushURL() string {
|
||||
return o.GetDriver().(RepositoryDriverInterface).GetRepositoryPushURL()
|
||||
}
|
||||
|
||||
func (o *repositoryNode) GetRepositoryInternalRefs() []string {
|
||||
return o.GetDriver().(RepositoryDriverInterface).GetRepositoryInternalRefs()
|
||||
}
|
||||
|
||||
func newRepositoryNode(ctx context.Context, tree generic.TreeInterface) generic.NodeInterface {
|
||||
node := &repositoryNode{}
|
||||
return node.Init(node)
|
||||
}
|
||||
|
||||
func NewRepositoryPath[T, U any](owners string, owner T, project U) path.Path {
|
||||
return generic.NewPathFromString(NewRepositoryPathString(owners, owner, project))
|
||||
}
|
||||
|
||||
func NewRepositoryPathString[T, U any](owners string, owner T, project U) string {
|
||||
return fmt.Sprintf("%s/%v/projects/%v/repositories/vcs", owners, owner, project)
|
||||
}
|
||||
|
||||
func NewRepositoryReference[T, U any](owners string, owner T, project U) *f3.Reference {
|
||||
return f3.NewReference(NewRepositoryPathString(owners, owner, project))
|
||||
}
|
||||
|
||||
func NewPullRequestSameRepositoryReference() *f3.Reference {
|
||||
return f3.NewReference("../../repositories/vcs")
|
||||
}
|
23
tree/f3/topic.go
Normal file
23
tree/f3/topic.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package f3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/f3"
|
||||
)
|
||||
|
||||
func NewTopicPath[T any](id T) Path {
|
||||
return NewPathFromString(NewTopicPathString(id))
|
||||
}
|
||||
|
||||
func NewTopicPathString[T any](id T) string {
|
||||
return fmt.Sprintf("/forge/topics/%v", id)
|
||||
}
|
||||
|
||||
func NewTopicReference[T any](id T) *f3.Reference {
|
||||
return f3.NewReference(NewTopicPathString(id))
|
||||
}
|
11
tree/f3/topics.go
Normal file
11
tree/f3/topics.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package f3
|
||||
|
||||
import (
|
||||
"code.forgejo.org/f3/gof3/v3/tree/generic"
|
||||
)
|
||||
|
||||
var TopicsPath = generic.NewPathFromString("/forge/topics")
|
23
tree/f3/user.go
Normal file
23
tree/f3/user.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package f3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/f3"
|
||||
)
|
||||
|
||||
func NewUserPath[T any](id T) Path {
|
||||
return NewPathFromString(NewUserPathString(id))
|
||||
}
|
||||
|
||||
func NewUserPathString[T any](id T) string {
|
||||
return fmt.Sprintf("/forge/users/%v", id)
|
||||
}
|
||||
|
||||
func NewUserReference[T any](id T) *f3.Reference {
|
||||
return f3.NewReference(NewUserPathString(id))
|
||||
}
|
11
tree/f3/users.go
Normal file
11
tree/f3/users.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package f3
|
||||
|
||||
import (
|
||||
"code.forgejo.org/f3/gof3/v3/tree/generic"
|
||||
)
|
||||
|
||||
var UsersPath = generic.NewPathFromString("/forge/users")
|
Loading…
Add table
Add a link
Reference in a new issue