Parial work on clean and deploy
This commit is contained in:
parent
3b92ee1421
commit
56d80c4883
162
main.go
162
main.go
|
@ -12,11 +12,13 @@ import (
|
||||||
type Command struct {
|
type Command struct {
|
||||||
Name string
|
Name string
|
||||||
Description string
|
Description string
|
||||||
Action func([]string) (string, error)
|
Action CommandAction
|
||||||
Arguments []string
|
Arguments []string
|
||||||
IsVarargs bool
|
IsVarargs bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CommandAction func([]string, []string) (string, error)
|
||||||
|
|
||||||
var commands = []Command{
|
var commands = []Command{
|
||||||
{
|
{
|
||||||
Name: "install",
|
Name: "install",
|
||||||
|
@ -24,38 +26,35 @@ var commands = []Command{
|
||||||
Arguments: []string{"game name", "archive path"},
|
Arguments: []string{"game name", "archive path"},
|
||||||
IsVarargs: true,
|
IsVarargs: true,
|
||||||
|
|
||||||
Action: func(arguments []string) (string, error) {
|
Action: func(requiredArguments []string, providedArguments []string) (string, error) {
|
||||||
var argumentCount = len(arguments)
|
var argumentCount = len(providedArguments)
|
||||||
|
|
||||||
if argumentCount == 0 {
|
if argumentCount < len(requiredArguments) {
|
||||||
return "", fmt.Errorf("expected game name")
|
return "", fmt.Errorf("expected game name folowed by at least one archive path")
|
||||||
}
|
}
|
||||||
|
|
||||||
var archivePaths = arguments[1:]
|
var archivePaths = providedArguments[1:]
|
||||||
var processed = 0
|
|
||||||
|
|
||||||
if gameError := WithGame(arguments[0], func(game *Game) error {
|
if gameError := WithGame(providedArguments[0], func(game *Game) error {
|
||||||
for i := range archivePaths {
|
for i := range archivePaths {
|
||||||
var archivePath = archivePaths[i]
|
var archivePath = archivePaths[i]
|
||||||
var extension = filepath.Ext(archivePath)
|
var extension = filepath.Ext(archivePath)
|
||||||
|
|
||||||
if len(extension) == 0 {
|
if len(extension) == 0 {
|
||||||
continue
|
return fmt.Errorf("missing file extension: `%s`", archivePath)
|
||||||
} else {
|
|
||||||
extension = extension[1:]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var extractor, extractorExists = extractors[extension]
|
var extractor, extractorExists = extractors[extension[1:]]
|
||||||
|
|
||||||
if !(extractorExists) {
|
if !(extractorExists) {
|
||||||
continue
|
return fmt.Errorf("unsupported file format: `%s`", archivePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
if game.InstallMod(extractor, archivePath) != nil {
|
if installError := game.InstallMod(
|
||||||
continue
|
extractor, archivePath); installError != nil {
|
||||||
}
|
|
||||||
|
|
||||||
processed += 1
|
return installError
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -63,7 +62,7 @@ var commands = []Command{
|
||||||
return "", gameError
|
return "", gameError
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprint(processed, " of ", len(archivePaths), " installed"), nil
|
return "mods installed", nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -73,31 +72,19 @@ var commands = []Command{
|
||||||
Arguments: []string{"game name", "mod name"},
|
Arguments: []string{"game name", "mod name"},
|
||||||
IsVarargs: true,
|
IsVarargs: true,
|
||||||
|
|
||||||
Action: func(arguments []string) (string, error) {
|
Action: func(requiredArguments []string, providedArguments []string) (string, error) {
|
||||||
var argumentCount = len(arguments)
|
if len(providedArguments) < len(requiredArguments) {
|
||||||
|
return "", fmt.Errorf("expected %s followed by one or more %ss",
|
||||||
if argumentCount == 0 {
|
requiredArguments[0], requiredArguments[1])
|
||||||
return "", fmt.Errorf("expected game name")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var modsToRemove = arguments[1:]
|
if gameError := WithGame(providedArguments[0], func(game *Game) error {
|
||||||
var removedMods = []string{}
|
return game.RemoveMods(providedArguments[1:])
|
||||||
|
|
||||||
if gameError := WithGame(arguments[0], func(game *Game) error {
|
|
||||||
var removed, removeError = game.RemoveMods(modsToRemove)
|
|
||||||
|
|
||||||
if removeError != nil {
|
|
||||||
return removeError
|
|
||||||
}
|
|
||||||
|
|
||||||
removedMods = removed
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}); gameError != nil {
|
}); gameError != nil {
|
||||||
return "", gameError
|
return "", gameError
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprint(len(removedMods), " of ", len(removedMods), " removed"), nil
|
return "removed mods", nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -107,13 +94,16 @@ var commands = []Command{
|
||||||
Arguments: []string{"game name", "mod name", "new name"},
|
Arguments: []string{"game name", "mod name", "new name"},
|
||||||
IsVarargs: false,
|
IsVarargs: false,
|
||||||
|
|
||||||
Action: func(arguments []string) (string, error) {
|
Action: func(requiredArguments []string, providedArguments []string) (string, error) {
|
||||||
if len(arguments) != 3 {
|
if len(providedArguments) != len(requiredArguments) {
|
||||||
return "", fmt.Errorf("expected game name followed by mod name and new name")
|
return "", fmt.Errorf("expected %s followed by %s and %s",
|
||||||
|
requiredArguments[0], requiredArguments[1], requiredArguments[2])
|
||||||
}
|
}
|
||||||
|
|
||||||
if gameError := WithGame(arguments[0], func(game *Game) error {
|
if gameError := WithGame(providedArguments[0], func(game *Game) error {
|
||||||
if removeError := game.RenameMod(arguments[1], arguments[2]); removeError != nil {
|
if removeError := game.RenameMod(providedArguments[1],
|
||||||
|
providedArguments[2]); removeError != nil {
|
||||||
|
|
||||||
return removeError
|
return removeError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,22 +122,23 @@ var commands = []Command{
|
||||||
Arguments: []string{"game name", "format"},
|
Arguments: []string{"game name", "format"},
|
||||||
IsVarargs: false,
|
IsVarargs: false,
|
||||||
|
|
||||||
Action: func(arguments []string) (string, error) {
|
Action: func(requiredArguments []string, providedArguments []string) (string, error) {
|
||||||
if len(arguments) != 2 {
|
if len(providedArguments) != len(requiredArguments) {
|
||||||
return "", fmt.Errorf("expected game name followed by format")
|
return "", fmt.Errorf("expected %s followed by %s",
|
||||||
|
requiredArguments[0], requiredArguments[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
var modManifest = ""
|
var modManifest = ""
|
||||||
|
|
||||||
if gameError := WithGame(arguments[0], func(game *Game) error {
|
if gameError := WithGame(providedArguments[0], func(game *Game) error {
|
||||||
var format = arguments[1]
|
var format = providedArguments[1]
|
||||||
var formatter, formatterExists = formatters[format]
|
var formatter, formatterExists = formatters[format]
|
||||||
|
|
||||||
if !(formatterExists) {
|
if !(formatterExists) {
|
||||||
return fmt.Errorf("unsupported format: `%s`", format)
|
return fmt.Errorf("unsupported format: `%s`", format)
|
||||||
}
|
}
|
||||||
|
|
||||||
var formattedManifest, formatError = formatter(game.Mods)
|
var formattedManifest, formatError = formatter(game.ModOrder)
|
||||||
|
|
||||||
if formatError != nil {
|
if formatError != nil {
|
||||||
return formatError
|
return formatError
|
||||||
|
@ -172,9 +163,76 @@ var commands = []Command{
|
||||||
Arguments: []string{"game name"},
|
Arguments: []string{"game name"},
|
||||||
IsVarargs: false,
|
IsVarargs: false,
|
||||||
|
|
||||||
Action: func(arguments []string) (string, error) {
|
Action: func(requiredArguments []string, arguments []string) (string, error) {
|
||||||
// TODO: Implement.
|
if len(arguments) != len(requiredArguments) {
|
||||||
return "", fmt.Errorf("not implemented")
|
return "", fmt.Errorf("expected %s", requiredArguments[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
if gameError := WithGame(arguments[0], func(game *Game) error {
|
||||||
|
var deployError = game.Deploy()
|
||||||
|
|
||||||
|
if deployError != nil {
|
||||||
|
return deployError
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}); gameError != nil {
|
||||||
|
return "", gameError
|
||||||
|
}
|
||||||
|
|
||||||
|
return "deployed", nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Name: "disable",
|
||||||
|
Description: "Disable one or more installed mods",
|
||||||
|
Arguments: []string{"game name", "mod name"},
|
||||||
|
IsVarargs: true,
|
||||||
|
|
||||||
|
Action: func(requiredArguments []string, arguments []string) (string, error) {
|
||||||
|
if len(arguments) < len(requiredArguments) {
|
||||||
|
return "", fmt.Errorf("expected %s followed by one or more %ss",
|
||||||
|
requiredArguments[0], requiredArguments[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
if gameError := WithGame(arguments[0], func(game *Game) error {
|
||||||
|
if enableError := game.SwitchMods(false, arguments[1:]); enableError != nil {
|
||||||
|
return enableError
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}); gameError != nil {
|
||||||
|
return "", gameError
|
||||||
|
}
|
||||||
|
|
||||||
|
return "enabled", nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Name: "enable",
|
||||||
|
Description: "Enable one or more installed mods",
|
||||||
|
Arguments: []string{"game name", "mod name"},
|
||||||
|
IsVarargs: true,
|
||||||
|
|
||||||
|
Action: func(requiredArguments []string, arguments []string) (string, error) {
|
||||||
|
if len(arguments) < len(requiredArguments) {
|
||||||
|
return "", fmt.Errorf("expected %s followed by one or more %ss",
|
||||||
|
requiredArguments[0], requiredArguments[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
if gameError := WithGame(arguments[0], func(game *Game) error {
|
||||||
|
if enableError := game.SwitchMods(true, arguments[1:]); enableError != nil {
|
||||||
|
return enableError
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}); gameError != nil {
|
||||||
|
return "", gameError
|
||||||
|
}
|
||||||
|
|
||||||
|
return "enabled", nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -291,7 +349,7 @@ func main() {
|
||||||
var command = commands[i]
|
var command = commands[i]
|
||||||
|
|
||||||
if command.Name == commandName {
|
if command.Name == commandName {
|
||||||
var response, actionError = command.Action(os.Args[2:])
|
var response, actionError = command.Action(command.Arguments, os.Args[2:])
|
||||||
|
|
||||||
if actionError != nil {
|
if actionError != nil {
|
||||||
fmt.Fprintln(os.Stderr, actionError.Error())
|
fmt.Fprintln(os.Stderr, actionError.Error())
|
||||||
|
|
311
manager.go
311
manager.go
|
@ -1,8 +1,11 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"encoding/csv"
|
"encoding/csv"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -12,33 +15,193 @@ type App struct {
|
||||||
ConfigDirPath string
|
ConfigDirPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (game *Game) CachePath() (string, error) {
|
||||||
|
var path, pathError = os.UserCacheDir()
|
||||||
|
|
||||||
|
if pathError != nil {
|
||||||
|
return "", pathError
|
||||||
|
}
|
||||||
|
|
||||||
|
path = filepath.Join(path, "modman", game.ID)
|
||||||
|
|
||||||
|
if mkdirError := os.MkdirAll(path, 0755); mkdirError != nil {
|
||||||
|
return "", mkdirError
|
||||||
|
}
|
||||||
|
|
||||||
|
return path, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (game *Game) Clean() error {
|
||||||
|
var cachePath, cachePathError = game.CachePath()
|
||||||
|
|
||||||
|
if cachePathError != nil {
|
||||||
|
return cachePathError
|
||||||
|
}
|
||||||
|
|
||||||
|
var deployedListPath = filepath.Join(cachePath, "backup", "deployed.txt")
|
||||||
|
|
||||||
|
if backupFile, openError := os.Open(deployedListPath); !(os.IsNotExist(openError)) {
|
||||||
|
defer backupFile.Close()
|
||||||
|
|
||||||
|
var scanner = bufio.NewScanner(backupFile)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
var
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (game *Game) ConfigPath() (string, error) {
|
||||||
|
var path, pathError = os.UserConfigDir()
|
||||||
|
|
||||||
|
if pathError != nil {
|
||||||
|
return "", pathError
|
||||||
|
}
|
||||||
|
|
||||||
|
path = filepath.Join(path, "modman", game.ID)
|
||||||
|
|
||||||
|
if mkdirError := os.MkdirAll(path, 0755); mkdirError != nil {
|
||||||
|
return "", mkdirError
|
||||||
|
}
|
||||||
|
|
||||||
|
return path, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (game *Game) Deploy() error {
|
||||||
|
var cachePath, cachePathError = game.CachePath()
|
||||||
|
|
||||||
|
if cachePathError != nil {
|
||||||
|
return cachePathError
|
||||||
|
}
|
||||||
|
|
||||||
|
var configPath, configPathError = game.ConfigPath()
|
||||||
|
|
||||||
|
if configPathError != nil {
|
||||||
|
return configPathError
|
||||||
|
}
|
||||||
|
|
||||||
|
var backupPath = filepath.Join(cachePath, "backup")
|
||||||
|
var deployedListPath = filepath.Join(backupPath, "deployed.txt")
|
||||||
|
|
||||||
|
if backupFile, openError := os.Open(deployedListPath); !(os.IsNotExist(openError)) {
|
||||||
|
defer backupFile.Close()
|
||||||
|
|
||||||
|
var scanner = bufio.NewScanner(backupFile)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
var
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var modsPath = filepath.Join(configPath, "mods")
|
||||||
|
|
||||||
|
for i := range game.ModOrder {
|
||||||
|
var mod = game.ModOrder[i]
|
||||||
|
|
||||||
|
if mod.IsEnabled {
|
||||||
|
var modPath = filepath.Join(modsPath, mod.Name)
|
||||||
|
|
||||||
|
if walkError := filepath.WalkDir(modPath, func(
|
||||||
|
path string, dirEntry fs.DirEntry, dirError error) error {
|
||||||
|
|
||||||
|
if dirError != nil {
|
||||||
|
return dirError
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileMode = dirEntry.Type()
|
||||||
|
|
||||||
|
if !(fileMode.IsDir()) {
|
||||||
|
var localPath, relativeError = filepath.Rel(modPath, path)
|
||||||
|
|
||||||
|
if relativeError != nil {
|
||||||
|
return relativeError
|
||||||
|
}
|
||||||
|
|
||||||
|
var linkPath = filepath.Join(game.Path, localPath)
|
||||||
|
|
||||||
|
if pathError := os.MkdirAll(filepath.Dir(linkPath),
|
||||||
|
fileMode.Perm()); pathError != nil {
|
||||||
|
|
||||||
|
return pathError
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, statError := os.Stat(linkPath); !(os.IsNotExist(statError)) {
|
||||||
|
var sourceFile, sourceOpenError = os.Open(linkPath)
|
||||||
|
|
||||||
|
if sourceOpenError != nil {
|
||||||
|
return sourceOpenError
|
||||||
|
}
|
||||||
|
|
||||||
|
defer sourceFile.Close()
|
||||||
|
|
||||||
|
var targetFile, targetOpenError = os.Create(backupPath)
|
||||||
|
|
||||||
|
if targetOpenError != nil {
|
||||||
|
return targetOpenError
|
||||||
|
}
|
||||||
|
|
||||||
|
defer targetFile.Close()
|
||||||
|
|
||||||
|
var _, copyError = io.Copy(targetFile, sourceFile)
|
||||||
|
|
||||||
|
if copyError != nil {
|
||||||
|
return copyError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if linkError := os.Link(path, linkPath); linkError != nil {
|
||||||
|
return linkError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}); walkError != nil {
|
||||||
|
return walkError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type Extractor func(string, string) error
|
type Extractor func(string, string) error
|
||||||
|
|
||||||
type Game struct {
|
type Game struct {
|
||||||
ID string
|
ID string
|
||||||
Mods map[string]Mod
|
ModOrder []Mod
|
||||||
|
ModNames map[string]int
|
||||||
|
Path string
|
||||||
HasUpdated bool
|
HasUpdated bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (game *Game) InstallMod(extractor Extractor, archivePath string) error {
|
func (game *Game) InstallMod(extractor Extractor, archivePath string) error {
|
||||||
var gamePath, pathError = game.Path()
|
var baseName = filepath.Base(archivePath)
|
||||||
|
var modName = strings.TrimSuffix(baseName, filepath.Ext(baseName))
|
||||||
|
|
||||||
|
if _, exists := game.ModNames[modName]; exists {
|
||||||
|
return fmt.Errorf("mod with name already exists: `%s`", modName)
|
||||||
|
}
|
||||||
|
|
||||||
|
var configPath, pathError = game.ConfigPath()
|
||||||
|
|
||||||
if pathError != nil {
|
if pathError != nil {
|
||||||
return pathError
|
return pathError
|
||||||
}
|
}
|
||||||
|
|
||||||
var baseName = filepath.Base(archivePath)
|
|
||||||
var modName = strings.TrimSuffix(baseName, filepath.Ext(baseName))
|
|
||||||
|
|
||||||
if extractError := extractor(archivePath, filepath.Join(
|
if extractError := extractor(archivePath, filepath.Join(
|
||||||
gamePath, "mods", modName)); extractError != nil {
|
configPath, "mods", modName)); extractError != nil {
|
||||||
|
|
||||||
return extractError
|
return extractError
|
||||||
}
|
}
|
||||||
|
|
||||||
game.Mods[modName] = Mod{
|
game.ModNames[modName] = len(game.ModOrder)
|
||||||
|
|
||||||
|
game.ModOrder = append(game.ModOrder, Mod{
|
||||||
IsEnabled: false,
|
IsEnabled: false,
|
||||||
}
|
Name: modName,
|
||||||
|
})
|
||||||
|
|
||||||
game.HasUpdated = true
|
game.HasUpdated = true
|
||||||
|
|
||||||
|
@ -47,6 +210,30 @@ func (game *Game) InstallMod(extractor Extractor, archivePath string) error {
|
||||||
|
|
||||||
type Mod struct {
|
type Mod struct {
|
||||||
IsEnabled bool
|
IsEnabled bool
|
||||||
|
Name string
|
||||||
|
Source string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (game *Game) SwitchMods(isEnabled bool, names []string) error {
|
||||||
|
if len(names) != 0 {
|
||||||
|
for i := range names {
|
||||||
|
var name = names[i]
|
||||||
|
var index, exists = game.ModNames[name]
|
||||||
|
|
||||||
|
if !(exists) {
|
||||||
|
return fmt.Errorf("mod does not exist: `%s`", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
var mod = game.ModOrder[index]
|
||||||
|
|
||||||
|
mod.IsEnabled = isEnabled
|
||||||
|
game.ModOrder[index] = mod
|
||||||
|
}
|
||||||
|
|
||||||
|
game.HasUpdated = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithGame(gameName string, action func(*Game) error) error {
|
func WithGame(gameName string, action func(*Game) error) error {
|
||||||
|
@ -58,17 +245,19 @@ func WithGame(gameName string, action func(*Game) error) error {
|
||||||
if gameName == supportedGame {
|
if gameName == supportedGame {
|
||||||
var game = Game{
|
var game = Game{
|
||||||
ID: supportedGame,
|
ID: supportedGame,
|
||||||
Mods: make(map[string]Mod),
|
ModOrder: make([]Mod, 0, 512),
|
||||||
|
ModNames: make(map[string]int),
|
||||||
HasUpdated: false,
|
HasUpdated: false,
|
||||||
|
Path: "/home/kayomn/.steam/steam/steamapps/common/Fallout 4/Data",
|
||||||
}
|
}
|
||||||
|
|
||||||
var gamePath, pathError = game.Path()
|
var configPath, pathError = game.ConfigPath()
|
||||||
|
|
||||||
if pathError != nil {
|
if pathError != nil {
|
||||||
return pathError
|
return pathError
|
||||||
}
|
}
|
||||||
|
|
||||||
var manifestPath = filepath.Join(gamePath, "mods.csv")
|
var manifestPath = filepath.Join(configPath, "mods.csv")
|
||||||
|
|
||||||
// Load manifest from disk.
|
// Load manifest from disk.
|
||||||
{
|
{
|
||||||
|
@ -92,9 +281,13 @@ func WithGame(gameName string, action func(*Game) error) error {
|
||||||
var status = recordValues[0]
|
var status = recordValues[0]
|
||||||
var name = recordValues[1]
|
var name = recordValues[1]
|
||||||
|
|
||||||
game.Mods[name] = Mod{
|
game.ModNames[name] = len(game.ModOrder)
|
||||||
|
|
||||||
|
game.ModOrder = append(game.ModOrder, Mod{
|
||||||
IsEnabled: status == "*",
|
IsEnabled: status == "*",
|
||||||
}
|
Name: name,
|
||||||
|
Source: "",
|
||||||
|
})
|
||||||
|
|
||||||
recordValues, recordError = manifestReader.Read()
|
recordValues, recordError = manifestReader.Read()
|
||||||
}
|
}
|
||||||
|
@ -107,8 +300,7 @@ func WithGame(gameName string, action func(*Game) error) error {
|
||||||
|
|
||||||
// Save manifest back to disk.
|
// Save manifest back to disk.
|
||||||
if game.HasUpdated {
|
if game.HasUpdated {
|
||||||
var manifestFile, openError = os.OpenFile(manifestPath,
|
var manifestFile, openError = os.Create(manifestPath)
|
||||||
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
|
||||||
|
|
||||||
if openError != nil {
|
if openError != nil {
|
||||||
return openError
|
return openError
|
||||||
|
@ -118,14 +310,15 @@ func WithGame(gameName string, action func(*Game) error) error {
|
||||||
|
|
||||||
var manifestWriter = csv.NewWriter(manifestFile)
|
var manifestWriter = csv.NewWriter(manifestFile)
|
||||||
|
|
||||||
for name, mod := range game.Mods {
|
for i := range game.ModOrder {
|
||||||
|
var mod = game.ModOrder[i]
|
||||||
var status = ""
|
var status = ""
|
||||||
|
|
||||||
if mod.IsEnabled {
|
if mod.IsEnabled {
|
||||||
status = "*"
|
status = "*"
|
||||||
}
|
}
|
||||||
|
|
||||||
manifestWriter.Write([]string{status, name})
|
manifestWriter.Write([]string{status, mod.Name, mod.Source})
|
||||||
}
|
}
|
||||||
|
|
||||||
manifestWriter.Flush()
|
manifestWriter.Flush()
|
||||||
|
@ -138,65 +331,63 @@ func WithGame(gameName string, action func(*Game) error) error {
|
||||||
return fmt.Errorf("%s: game not supported", gameName)
|
return fmt.Errorf("%s: game not supported", gameName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (game Game) Path() (string, error) {
|
func (game *Game) RemoveMods(names []string) error {
|
||||||
var configDirPath, configError = os.UserConfigDir()
|
var configPath, pathError = game.ConfigPath()
|
||||||
|
|
||||||
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 {
|
if pathError != nil {
|
||||||
return pathError
|
return pathError
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, exists := game.Mods[modName]; !(exists) {
|
if len(names) != 0 {
|
||||||
|
game.HasUpdated = true
|
||||||
|
|
||||||
|
for i := range names {
|
||||||
|
var name = names[i]
|
||||||
|
var index, exists = game.ModNames[name]
|
||||||
|
|
||||||
|
if !(exists) {
|
||||||
|
return fmt.Errorf("unknown mod: `%s`", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if removeError := os.RemoveAll(filepath.Join(configPath, name)); removeError != nil {
|
||||||
|
return removeError
|
||||||
|
}
|
||||||
|
|
||||||
|
game.ModOrder = append(game.ModOrder[:index], game.ModOrder[index+1:]...)
|
||||||
|
|
||||||
|
delete(game.ModNames, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (game *Game) RenameMod(modName string, newName string) error {
|
||||||
|
var configPath, pathError = game.ConfigPath()
|
||||||
|
|
||||||
|
if pathError != nil {
|
||||||
|
return pathError
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, exists := game.ModNames[modName]; !(exists) {
|
||||||
return fmt.Errorf("no mod with that name exists")
|
return fmt.Errorf("no mod with that name exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, exists := game.Mods[newName]; exists {
|
if _, nameTaken := game.ModNames[newName]; nameTaken {
|
||||||
return fmt.Errorf("a mod with the new name already exists")
|
return fmt.Errorf("a mod with the new name already exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
if renameError := os.Rename(filepath.Join(gamePath, modName),
|
var modsPath = filepath.Join(configPath, "mods")
|
||||||
filepath.Join(gamePath, newName)); renameError != nil {
|
|
||||||
|
if renameError := os.Rename(filepath.Join(modsPath, modName),
|
||||||
|
filepath.Join(modsPath, newName)); renameError != nil {
|
||||||
|
|
||||||
return renameError
|
return renameError
|
||||||
}
|
}
|
||||||
|
|
||||||
game.Mods[newName] = game.Mods[modName]
|
game.ModNames[newName] = game.ModNames[modName]
|
||||||
|
|
||||||
delete(game.Mods, modName)
|
delete(game.ModNames, modName)
|
||||||
|
|
||||||
game.HasUpdated = true
|
game.HasUpdated = true
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue