File: mirror.go

package info (click to toggle)
golang-code.forgejo-f3-gof3 3.11.0-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 1,952 kB
  • sloc: sh: 100; makefile: 65
file content (129 lines) | stat: -rw-r--r-- 3,713 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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())
	}
}