1
0
Fork 0

Adding upstream version 3.10.8.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-05-18 09:37:23 +02:00
parent 37e9b6d587
commit 03bfe4079e
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
356 changed files with 28857 additions and 0 deletions

49
cmd/cli.go Normal file
View file

@ -0,0 +1,49 @@
// Copyright Earl Warren <contact@earl-warren.org>
// Copyright Loïc Dachary <loic@dachary.org>
// SPDX-License-Identifier: MIT
package cmd
import (
"fmt"
"sort"
filesystem_options "code.forgejo.org/f3/gof3/v3/forges/filesystem/options"
"code.forgejo.org/f3/gof3/v3/options"
"github.com/urfave/cli/v3"
)
func ForgeTypeOption(direction string) string {
return direction + "-type"
}
func GetFlagsCommon(prefix, category string) []cli.Flag {
flags := make([]cli.Flag, 0, 10)
forgeTypes := make([]string, 0, 10)
for name := range options.GetFactories() {
forgeTypes = append(forgeTypes, name)
}
sort.Strings(forgeTypes)
values := &enumType{
Enum: forgeTypes,
Default: filesystem_options.Name,
}
flags = append(flags, &cli.GenericFlag{
Name: ForgeTypeOption(prefix),
Usage: fmt.Sprintf("`TYPE` of the %s forge", prefix),
Value: values,
DefaultText: values.GetDefaultText(),
Category: prefix,
})
flags = append(flags, &cli.StringFlag{
Name: BuildForgePrefix(prefix, "path"),
Usage: "resource to mirror (e.g. /forge/users/myuser/projects/myproject)",
Category: prefix,
})
return flags
}

48
cmd/enumtype.go Normal file
View file

@ -0,0 +1,48 @@
// SPDX-License-Identifier: MIT
package cmd
import (
"fmt"
"strings"
)
type enumType struct {
Enum []string
Default string
selected string
}
func (o enumType) Join() string {
return strings.Join(o.Enum, ",")
}
func (o *enumType) Set(value string) error {
for _, enum := range o.Enum {
if strings.EqualFold(enum, value) {
o.selected = value
return nil
}
}
return fmt.Errorf("%v", o.Allowed())
}
func (o *enumType) Allowed() string {
return fmt.Sprintf("allowed values are %s", o.Join())
}
func (o *enumType) GetDefaultText() string {
return fmt.Sprintf("%s, %s", o.Default, o.Allowed())
}
func (o enumType) Get() any {
return o.String()
}
func (o enumType) String() string {
if o.selected == "" {
return o.Default
}
return o.selected
}

49
cmd/main.go Normal file
View file

@ -0,0 +1,49 @@
// Copyright Earl Warren <contact@earl-warren.org>
// Copyright Loïc Dachary <loic@dachary.org>
// SPDX-License-Identifier: MIT
package cmd
import (
"context"
"code.forgejo.org/f3/gof3/v3/logger"
"github.com/urfave/cli/v3"
)
var Version = "development"
func SetVerbosity(ctx context.Context, verbosity int) {
l := logger.ContextGetLogger(ctx)
switch verbosity {
case 0:
l.SetLevel(logger.Info)
default:
l.SetLevel(logger.Trace)
}
}
func NewApp() *cli.Command {
return &cli.Command{
Name: "F3",
Usage: "Friendly Forge Format",
Description: `Friendly Forge Format`,
Version: Version,
Before: func(ctx context.Context, c *cli.Command) (context.Context, error) {
SetVerbosity(ctx, c.Count("verbose"))
return nil, nil
},
Commands: []*cli.Command{
CreateCmdMirror(),
},
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "verbose",
Usage: "increase the verbosity level",
},
cli.VersionFlag,
},
EnableShellCompletion: true,
}
}

129
cmd/mirror.go Normal file
View file

@ -0,0 +1,129 @@
// Copyright Earl Warren <contact@earl-warren.org>
// Copyright Loïc Dachary <loic@dachary.org>
// SPDX-License-Identifier: MIT
package cmd
import (
"context"
"fmt"
"code.forgejo.org/f3/gof3/v3/logger"
"code.forgejo.org/f3/gof3/v3/options"
"code.forgejo.org/f3/gof3/v3/path"
"code.forgejo.org/f3/gof3/v3/tree/generic"
"code.forgejo.org/f3/gof3/v3/util"
"github.com/urfave/cli/v3"
)
var (
directionFrom = "from"
flagFrom = "--" + directionFrom
directionTo = "to"
flagTo = "--" + directionTo
)
func BuildForgePrefix(prefix, forge string) string {
return prefix + "-" + forge
}
func FlagsToTree(ctx context.Context, c *cli.Command, direction string) generic.TreeInterface {
forgeType := c.String(ForgeTypeOption(direction))
opts := options.GetFactory(forgeType)()
opts.(options.LoggerInterface).SetLogger(logger.ContextGetLogger(ctx))
if o, ok := opts.(options.CLIInterface); ok {
o.FromFlags(ctx, c, BuildForgePrefix(direction, forgeType))
} else {
panic("not implemented")
}
return generic.GetFactory("f3")(ctx, opts)
}
func CreateCmdMirror() *cli.Command {
flags := make([]cli.Flag, 0, 10)
for _, direction := range []string{"from", "to"} {
flags = append(flags, GetFlagsCommon(direction, "common")...)
for name, factory := range options.GetFactories() {
if opts, ok := factory().(options.CLIInterface); ok {
flags = append(flags, opts.GetFlags(BuildForgePrefix(direction, name), name)...)
}
}
}
flags = func(flags []cli.Flag) []cli.Flag {
dedup := make([]cli.Flag, 0, 10)
names := make(map[string]any, 10)
flagLoop:
for _, flag := range flags {
for _, name := range flag.Names() {
_, found := names[name]
if found {
continue flagLoop
}
}
dedup = append(dedup, flag)
for _, name := range flag.Names() {
names[name] = nil
}
}
return dedup
}(flags)
return &cli.Command{
Name: "mirror",
Usage: "Mirror",
Description: "Mirror",
Action: func(ctx context.Context, c *cli.Command) error {
return util.PanicToError(func() { runMirror(ctx, c) })
},
Flags: flags,
}
}
func runMirror(ctx context.Context, c *cli.Command) {
from := FlagsToTree(ctx, c, directionFrom)
to := FlagsToTree(ctx, c, directionTo)
fromPathString := c.String(BuildForgePrefix(directionFrom, "path"))
fromPath := generic.NewPathFromString(fromPathString)
toPathString := c.String(BuildForgePrefix(directionTo, "path"))
toPath := generic.NewPathFromString(toPathString)
log := from.GetLogger()
fromURL := "(unset)"
if url, ok := from.GetOptions().(options.URLInterface); ok {
fromURL = url.GetURL()
}
toURL := "(unset)"
if url, ok := to.GetOptions().(options.URLInterface); ok {
toURL = url.GetURL()
}
log.Info("mirror %s (%s at %s) to %s (%s at %s)",
fromPath, c.String(ForgeTypeOption(directionFrom)), fromURL,
toPath, c.String(ForgeTypeOption(directionTo)), toURL,
)
log.Debug("read %s from %T", fromPath, from)
var fromNode generic.NodeInterface
fromNode = generic.NilNode
walkAndGet := func(ctx context.Context, parent, p path.Path, node generic.NodeInterface) {
node.WalkAndGet(ctx, parent, generic.NewWalkOptions(nil))
fromNode = node
}
from.ApplyAndGet(ctx, fromPath, generic.NewApplyOptions(walkAndGet))
if fromNode == generic.NilNode {
panic(fmt.Errorf("from %s not found", fromPath))
}
from.Debug("copy %s from %T to %T", fromPath, from, to)
if toPathString == "" {
generic.TreeMirror(ctx, from, to, fromPath, generic.NewMirrorOptions())
} else {
toNode := to.FindAndGet(ctx, toPath)
if toNode == generic.NilNode {
panic(fmt.Errorf("to %s not found", toPath))
}
generic.NodeMirror(ctx, fromNode, toNode, generic.NewMirrorOptions())
}
}

139
cmd/mirror_test.go Normal file
View file

@ -0,0 +1,139 @@
// Copyright Earl Warren <contact@earl-warren.org>
// Copyright Loïc Dachary <loic@dachary.org>
// SPDX-License-Identifier: MIT
package cmd
import (
"context"
"fmt"
"testing"
filesystem_options "code.forgejo.org/f3/gof3/v3/forges/filesystem/options"
forgejo_options "code.forgejo.org/f3/gof3/v3/forges/forgejo/options"
"code.forgejo.org/f3/gof3/v3/options"
"code.forgejo.org/f3/gof3/v3/tree/generic"
f3_tests "code.forgejo.org/f3/gof3/v3/tree/tests/f3"
tests_forge "code.forgejo.org/f3/gof3/v3/tree/tests/f3/forge"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_CmdMirrorArguments(t *testing.T) {
ctx := context.Background()
output, err := runApp(ctx, "f3", "mirror", "--from-type", "garbage")
assert.ErrorContains(t, err, `allowed values are `)
assert.Contains(t, output, "Incorrect Usage:")
}
func Test_CmdMirrorIntegrationDefaultToPath(t *testing.T) {
ctx := context.Background()
fixtureOptions := tests_forge.GetFactory(filesystem_options.Name)().NewOptions(t)
fixtureTree := generic.GetFactory("f3")(ctx, fixtureOptions)
log := fixtureTree.GetLogger()
log.Trace("======= build fixture")
f3_tests.TreeBuild(t, "CmdMirrorDefault", fixtureOptions, fixtureTree)
log.Trace("======= create mirror")
mirrorOptions := tests_forge.GetFactory(filesystem_options.Name)().NewOptions(t)
mirrorTree := generic.GetFactory("f3")(ctx, mirrorOptions)
p := "/forge/users/10111"
log.Trace("======= mirror %s", p)
output, err := runApp(ctx, "f3", "--verbose", "mirror",
"--from-filesystem-directory", fixtureOptions.(options.URLInterface).GetURL(),
"--from-path", p,
"--to-filesystem-directory", mirrorOptions.(options.URLInterface).GetURL(),
)
log.Trace("======= assert")
assert.NoError(t, err)
require.Contains(t, output, fmt.Sprintf("mirror %s (filesystem", p))
mirrorTree.WalkAndGet(ctx, generic.NewWalkOptions(nil))
found := mirrorTree.Find(generic.NewPathFromString(p))
require.NotEqualValues(t, found, generic.NilNode)
assert.EqualValues(t, p, found.GetCurrentPath().String())
}
func Test_CmdMirrorIntegrationSpecificToPath(t *testing.T) {
ctx := context.Background()
mirrorOptions := tests_forge.GetFactory(forgejo_options.Name)().NewOptions(t)
mirrorTree := generic.GetFactory("f3")(ctx, mirrorOptions)
fixtureOptions := tests_forge.GetFactory(filesystem_options.Name)().NewOptions(t)
fixtureTree := generic.GetFactory("f3")(ctx, fixtureOptions)
log := fixtureTree.GetLogger()
creator := f3_tests.NewCreator(t, "CmdMirrorSpecific", log)
log.Trace("======= build fixture")
var fromPath string
{
fixtureUserID := "userID01"
fixtureProjectID := "projectID01"
userFormat := creator.GenerateUser()
userFormat.SetID(fixtureUserID)
users := fixtureTree.MustFind(generic.NewPathFromString("/forge/users"))
user := users.CreateChild(ctx)
user.FromFormat(userFormat)
user.Upsert(ctx)
require.EqualValues(t, user.GetID(), users.GetIDFromName(ctx, userFormat.UserName))
projectFormat := creator.GenerateProject()
projectFormat.SetID(fixtureProjectID)
projects := user.MustFind(generic.NewPathFromString("projects"))
project := projects.CreateChild(ctx)
project.FromFormat(projectFormat)
project.Upsert(ctx)
require.EqualValues(t, project.GetID(), projects.GetIDFromName(ctx, projectFormat.Name))
fromPath = fmt.Sprintf("/forge/users/%s/projects/%s", userFormat.UserName, projectFormat.Name)
}
log.Trace("======= create mirror")
var toPath string
var projects generic.NodeInterface
{
userFormat := creator.GenerateUser()
users := mirrorTree.MustFind(generic.NewPathFromString("/forge/users"))
user := users.CreateChild(ctx)
user.FromFormat(userFormat)
user.Upsert(ctx)
require.EqualValues(t, user.GetID(), users.GetIDFromName(ctx, userFormat.UserName))
projectFormat := creator.GenerateProject()
projects = user.MustFind(generic.NewPathFromString("projects"))
project := projects.CreateChild(ctx)
project.FromFormat(projectFormat)
project.Upsert(ctx)
require.EqualValues(t, project.GetID(), projects.GetIDFromName(ctx, projectFormat.Name))
toPath = fmt.Sprintf("/forge/users/%s/projects/%s", userFormat.UserName, projectFormat.Name)
}
log.Trace("======= mirror %s", fromPath)
output, err := runApp(ctx, "f3", "--verbose", "mirror",
"--from-type", filesystem_options.Name,
"--from-path", fromPath,
"--from-filesystem-directory", fixtureOptions.(options.URLInterface).GetURL(),
"--to-type", forgejo_options.Name,
"--to-path", toPath,
"--to-forgejo-user", mirrorOptions.(options.AuthInterface).GetUsername(),
"--to-forgejo-password", mirrorOptions.(options.AuthInterface).GetPassword(),
"--to-forgejo-url", mirrorOptions.(options.URLInterface).GetURL(),
)
assert.NoError(t, err)
log.Trace("======= assert")
require.Contains(t, output, fmt.Sprintf("mirror %s", fromPath))
projects.List(ctx)
require.NotEmpty(t, projects.GetChildren())
log.Trace("======= project %s", projects.GetChildren()[0])
}

33
cmd/signal.go Normal file
View file

@ -0,0 +1,33 @@
// Copyright Earl Warren <contact@earl-warren.org>
// Copyright Loïc Dachary <loic@dachary.org>
// SPDX-License-Identifier: MIT
package cmd
import (
"context"
"os"
"os/signal"
"syscall"
)
func InstallSignals() (context.Context, context.CancelFunc) {
ctx, cancel := context.WithCancel(context.Background())
go func() {
signalChannel := make(chan os.Signal, 1)
signal.Notify(
signalChannel,
syscall.SIGINT,
syscall.SIGTERM,
)
select {
case <-signalChannel:
case <-ctx.Done():
}
cancel()
signal.Reset()
}()
return ctx, cancel
}

38
cmd/testhelpers.go Normal file
View file

@ -0,0 +1,38 @@
// Copyright Earl Warren <contact@earl-warren.org>
// Copyright Loïc Dachary <loic@dachary.org>
// SPDX-License-Identifier: MIT
package cmd
import (
"context"
"fmt"
"code.forgejo.org/f3/gof3/v3/logger"
// allow forges to register
_ "code.forgejo.org/f3/gof3/v3/forges/filesystem"
_ "code.forgejo.org/f3/gof3/v3/forges/forgejo"
)
func runApp(ctx context.Context, args ...string) (string, error) {
l := logger.NewCaptureLogger()
ctx = logger.ContextSetLogger(ctx, l)
app := NewApp()
app.Writer = l.GetBuffer()
app.ErrWriter = l.GetBuffer()
defer func() {
if r := recover(); r != nil {
fmt.Println(l.String())
panic(r)
}
}()
err := app.Run(ctx, args)
fmt.Println(l.String())
return l.String(), err
}