esp-modman/manager.go

205 lines
3.9 KiB
Go
Raw Normal View History

2022-12-03 18:56:36 +01:00
package main
import (
"encoding/csv"
"fmt"
"os"
"path/filepath"
"strings"
)
type App struct {
ConfigDirPath string
}
2022-12-03 19:27:53 +01:00
type Extractor func(string, string) error
2022-12-03 18:56:36 +01:00
type Game struct {
ID string
Mods map[string]Mod
HasUpdated bool
}
2022-12-03 19:27:53 +01:00
func (game *Game) InstallMod(extractor Extractor, archivePath string) error {
var gamePath, pathError = game.Path()
2022-12-03 18:56:36 +01:00
2022-12-03 19:27:53 +01:00
if pathError != nil {
return pathError
}
2022-12-03 18:56:36 +01:00
2022-12-03 19:27:53 +01:00
var baseName = filepath.Base(archivePath)
var modName = strings.TrimSuffix(baseName, filepath.Ext(baseName))
2022-12-03 18:56:36 +01:00
2022-12-03 19:27:53 +01:00
if extractError := extractor(archivePath, filepath.Join(
gamePath, "mods", modName)); extractError != nil {
2022-12-03 18:56:36 +01:00
2022-12-03 19:27:53 +01:00
return extractError
}
2022-12-03 18:56:36 +01:00
2022-12-03 19:27:53 +01:00
game.Mods[modName] = Mod{
IsEnabled: false,
2022-12-03 18:56:36 +01:00
}
2022-12-03 19:27:53 +01:00
game.HasUpdated = true
return nil
2022-12-03 18:56:36 +01:00
}
type Mod struct {
IsEnabled bool
}
func WithGame(gameName string, action func(*Game) error) error {
var supportedGames = []string{"fallout4", "falloutnv", "skyrim"}
for i := range supportedGames {
var supportedGame = supportedGames[i]
if gameName == supportedGame {
var game = Game{
ID: supportedGame,
Mods: make(map[string]Mod),
HasUpdated: false,
}
var gamePath, pathError = game.Path()
if pathError != nil {
return pathError
}
var manifestPath = filepath.Join(gamePath, "mods.csv")
// Load manifest from disk.
{
var manifestFile, openError = os.Open(manifestPath)
if openError == nil {
defer manifestFile.Close()
var manifestReader = csv.NewReader(manifestFile)
var recordValues, recordError = manifestReader.Read()
for recordValues != nil {
if recordError != nil {
return recordError
}
if len(recordValues) < 2 {
return fmt.Errorf("could not read mod manifest data - may be corrupt")
}
var status = recordValues[0]
var name = recordValues[1]
game.Mods[name] = Mod{
IsEnabled: status == "*",
}
recordValues, recordError = manifestReader.Read()
}
}
}
if actionError := action(&game); actionError != nil {
return actionError
}
// Save manifest back to disk.
if game.HasUpdated {
var manifestFile, openError = os.OpenFile(manifestPath,
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if openError != nil {
return openError
}
defer manifestFile.Close()
var manifestWriter = csv.NewWriter(manifestFile)
for name, mod := range game.Mods {
var status = ""
if mod.IsEnabled {
status = "*"
}
manifestWriter.Write([]string{status, name})
}
manifestWriter.Flush()
}
return nil
}
}
return fmt.Errorf("%s: game not supported", gameName)
}
func (game Game) Path() (string, error) {
var configDirPath, configError = os.UserConfigDir()
if configError != nil {
return "", configError
}
return filepath.Join(configDirPath, "modman", game.ID), nil
}
func (game *Game) RemoveMods(modNames []string) ([]string, error) {
var gamePath, pathError = game.Path()
if pathError != nil {
return nil, pathError
}
var processed = 0
for i := range modNames {
var modName = modNames[i]
if removeError := os.RemoveAll(filepath.Join(gamePath, modName)); removeError != nil {
return nil, removeError
}
delete(game.Mods, modName)
game.HasUpdated = true
processed += 1
}
return modNames[0:processed], nil
}
func (game *Game) RenameMod(modName string, newName string) error {
var gamePath, pathError = game.Path()
if pathError != nil {
return pathError
}
if _, exists := game.Mods[modName]; !(exists) {
return fmt.Errorf("no mod with that name exists")
}
if _, exists := game.Mods[newName]; exists {
return fmt.Errorf("a mod with the new name already exists")
}
if renameError := os.Rename(filepath.Join(gamePath, modName),
filepath.Join(gamePath, newName)); renameError != nil {
return renameError
}
game.Mods[newName] = game.Mods[modName]
delete(game.Mods, modName)
game.HasUpdated = true
return nil
}