z_mirror/fmm

git clone https://git.raiguard.me/z_mirror/fmm

Caleb HeuerInitial WIP811753c

updating
4.2 KiB185 linesraw
1package cli
2
3import (
4	"cmp"
5	"errors"
6	"fmt"
7	"io"
8	"os"
9	"path/filepath"
10	"slices"
11	"strings"
12
13	fmm "github.com/raiguard/fmm/lib"
14)
15
16const usageStr string = `usage: fmm <command> [args...]
17commands:
18	add     [args...]   Download and enable the given mods and their dependencies
19	disable [args...]   Disable the given mods, or all mods if none are given
20	enable  [args...]   Enable the given mods and their dependencies
21	help                Show usage information
22	list    [files...]  List all mods in the mods directory, or in the given save files
23	sync    [args...]   Disable all mods, then download and enable the given mods and their dependencies
24	upload  [files...]  Upload the given mod zip files to the mod portal`
25
26func Run(args []string) {
27	if len(args) == 0 {
28		printUsage("no operation was specified")
29	}
30
31	var task func(*fmm.Manager, []string)
32	switch args[0] {
33	case "add", "a":
34		task = add
35	case "disable", "d":
36		task = disable
37	case "enable", "e":
38		task = enable
39	case "help", "h", "-h", "--help", "-help":
40		printUsage()
41	case "list", "ls":
42		task = list
43	case "sync", "s":
44		task = sync
45	case "update", "u":
46		task = update
47	case "upload", "ul":
48		task = upload
49	default:
50		printUsage("unrecognized operation", args[0])
51	}
52	args = args[1:]
53
54	manager, err := fmm.NewManager(".", filepath.Join(".", "mods"))
55	if err != nil {
56		if !errors.Is(err, fmm.ErrInvalidGameDirectory) {
57			abort(err)
58		}
59		gamePath := os.Getenv("FACTORIO_PATH")
60		modsPath := os.Getenv("FACTORIO_MODS_PATH")
61		if modsPath == "" {
62			modsPath = filepath.Join(gamePath, "mods")
63		}
64		manager, err = fmm.NewManager(gamePath, modsPath)
65		if err != nil {
66			abort(err)
67		}
68	}
69
70	if !manager.HasPlayerData() {
71		manager.SetPlayerData(fmm.PlayerData{
72			Token:    os.Getenv("FACTORIO_TOKEN"),
73			Username: os.Getenv("FACTORIO_USERNAME"),
74		})
75	}
76
77	manager.SetApiKey(os.Getenv("FACTORIO_API_KEY"))
78
79	stdinStat, _ := os.Stdin.Stat()
80	if stdinStat.Mode()&os.ModeNamedPipe > 0 {
81		bytes, err := io.ReadAll(os.Stdin)
82		if err == nil {
83			args = append(args, strings.Split(strings.TrimSpace(string(bytes)), "\n")...)
84		}
85	}
86
87	task(manager, args)
88
89	if err := manager.Save(); err != nil {
90		errorln(errors.Join(errors.New("unable to save modifications"), err))
91	}
92}
93
94func add(manager *fmm.Manager, args []string) {
95	for _, mod := range manager.ExpandDependencies(getMods(args), true) {
96		ver, err := manager.Add(mod)
97		if err != nil {
98			errorf("failed to add %s\n", mod.ToString())
99			errorln(err)
100		} else if ver != nil {
101			fmt.Println("enabled", mod.Name, ver.ToString(false))
102		}
103	}
104}
105
106func disable(manager *fmm.Manager, args []string) {
107	if len(args) == 0 {
108		manager.DisableAll()
109		fmt.Println("disabled all mods")
110		return
111	}
112
113	for _, mod := range getMods(args) {
114		if err := manager.Disable(mod.Name); err != nil {
115			errorf("failed to disable %s\n", mod.ToString())
116			errorln(err)
117		} else {
118			fmt.Println("disabled", mod.Name)
119		}
120	}
121}
122
123func enable(manager *fmm.Manager, args []string) {
124	for _, mod := range manager.ExpandDependencies(getMods(args), false) {
125		ver, err := manager.Enable(mod)
126		if err != nil {
127			errorf("failed to enable %s\n", mod.ToString())
128			errorln(err)
129		} else if ver != nil {
130			fmt.Println("enabled", mod.Name, ver.ToString(false))
131		}
132	}
133}
134
135func list(manager *fmm.Manager, args []string) {
136	mods := []fmm.ModIdent{}
137	if len(args) == 0 {
138		mods = manager.GetMods()
139	} else {
140		for _, filepath := range args {
141			fileMods, err := fmm.ParseSaveFile(filepath)
142			if err != nil {
143				fmt.Println(err)
144			}
145			mods = append(mods, fileMods...)
146		}
147	}
148	slices.SortFunc(mods, func(a fmm.ModIdent, b fmm.ModIdent) int {
149		if a.Name != b.Name {
150			return cmp.Compare(a.Name, b.Name)
151		}
152		switch a.Version.Cmp(b.Version) {
153		case fmm.VersionLt:
154			return -1
155		case fmm.VersionGt:
156			return 1
157		case fmm.VersionEq:
158			return 0
159		// Should be unreachable
160		default:
161			return 0
162		}
163	})
164	for _, mod := range mods {
165		fmt.Println(mod.ToString())
166	}
167}
168
169func sync(manager *fmm.Manager, args []string) {
170	manager.DisableAll()
171	fmt.Println("disabled all mods")
172	add(manager, args)
173}
174
175func update(manager *fmm.Manager, args []string) {
176	manager.CheckDownloadUpdates(getMods(args))
177}
178
179func upload(manager *fmm.Manager, files []string) {
180	for _, file := range files {
181		if err := manager.Portal.UploadMod(file); err != nil {
182			fmt.Println(err)
183		}
184	}
185}