diff --git a/main.go b/main.go index cc86dab..4f1b94f 100644 --- a/main.go +++ b/main.go @@ -1,9 +1,12 @@ package main import ( + "archive/zip" "encoding/json" "fmt" + "io" "os" + "path/filepath" ) type Command struct { @@ -28,24 +31,39 @@ var commands = []Command{ return "", fmt.Errorf("expected game name") } - var modsToInstall = arguments[1:] - var installedMods = []string{} + var archivePaths = arguments[1:] + var processed = 0 if gameError := WithGame(arguments[0], func(game *Game) error { - var installed, installError = game.InstallMods(modsToInstall) + for i := range archivePaths { + var archivePath = archivePaths[i] + var extension = filepath.Ext(archivePath) - if installError != nil { - return installError + if len(extension) == 0 { + continue + } else { + extension = extension[1:] + } + + var extractor, extractorExists = extractors[extension] + + if !(extractorExists) { + continue + } + + if game.InstallMod(extractor, archivePath) != nil { + continue + } + + processed += 1 } - installedMods = installed - return nil }); gameError != nil { return "", gameError } - return fmt.Sprint(len(installedMods), " of ", len(modsToInstall), " installed"), nil + return fmt.Sprint(processed, " of ", len(archivePaths), " installed"), nil }, }, @@ -161,6 +179,74 @@ var commands = []Command{ }, } +var extractors = map[string]Extractor{ + "zip": func(archivePath string, destinationPath string) error { + var zipReader, openReaderError = zip.OpenReader(archivePath) + + if openReaderError != nil { + return openReaderError + } + + defer func() { + if closeError := zipReader.Close(); closeError != nil { + panic(closeError.Error()) + } + }() + + if mkdirError := os.MkdirAll(destinationPath, 0755); mkdirError != nil { + return mkdirError + } + + for i := range zipReader.File { + var file = zipReader.File[i] + var fileReader, fileOpenError = file.Open() + + if fileOpenError != nil { + return fileOpenError + } + + defer func() { + if closeError := fileReader.Close(); closeError != nil { + panic(closeError.Error()) + } + }() + + var path = filepath.Join(destinationPath, file.Name) + + if file.FileInfo().IsDir() { + if mkdirError := os.MkdirAll(path, file.Mode()); mkdirError != nil { + return mkdirError + } + } else { + if mkdirError := os.MkdirAll(filepath.Dir(path), file.Mode()); mkdirError != nil { + return mkdirError + } + + var extractedFile, fileOpenError = os.OpenFile(path, + os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode()) + + if fileOpenError != nil { + return fileOpenError + } + + defer func() { + if fileOpenError := extractedFile.Close(); fileOpenError != nil { + panic(fileOpenError) + } + }() + + var _, copyError = io.Copy(extractedFile, fileReader) + + if copyError != nil { + return copyError + } + } + } + + return nil + }, +} + var formatters = map[string]func(any) ([]byte, error){ "json": func(data any) ([]byte, error) { var marshalledJson, marshalError = json.Marshal(data) diff --git a/manager.go b/manager.go index f6fba97..c3ad695 100644 --- a/manager.go +++ b/manager.go @@ -1,10 +1,8 @@ package main import ( - "archive/zip" "encoding/csv" "fmt" - "io" "os" "path/filepath" "strings" @@ -14,53 +12,37 @@ type App struct { ConfigDirPath string } +type Extractor func(string, string) error + type Game struct { ID string Mods map[string]Mod HasUpdated bool } -func (game *Game) InstallMods(archivePaths []string) ([]string, error) { - var processed = 0 +func (game *Game) InstallMod(extractor Extractor, archivePath string) error { + var gamePath, pathError = game.Path() - for i := range archivePaths { - var archivePath = archivePaths[i] - var suffixIndex = strings.LastIndex(archivePath, ".") - - if suffixIndex < 0 { - return nil, fmt.Errorf("cannot determine file type of `%s`", archivePath) - } - - var extension = archivePath[suffixIndex+1:] - var extractor = extractors[extension] - - if extractor == nil { - return nil, fmt.Errorf("unsupported file type `%s`", extension) - } - - var gamePath, pathError = game.Path() - - if pathError != nil { - return nil, pathError - } - - var modName = filepath.Base(archivePath[:suffixIndex]) - - if extractError := extractor(archivePath, filepath.Join( - gamePath, "mods", modName)); extractError != nil { - - return nil, extractError - } - - game.Mods[modName] = Mod{ - IsEnabled: false, - } - - game.HasUpdated = true - processed += 1 + if pathError != nil { + return pathError } - return archivePaths[0:processed], nil + var baseName = filepath.Base(archivePath) + var modName = strings.TrimSuffix(baseName, filepath.Ext(baseName)) + + if extractError := extractor(archivePath, filepath.Join( + gamePath, "mods", modName)); extractError != nil { + + return extractError + } + + game.Mods[modName] = Mod{ + IsEnabled: false, + } + + game.HasUpdated = true + + return nil } type Mod struct { @@ -220,71 +202,3 @@ func (game *Game) RenameMod(modName string, newName string) error { return nil } - -var extractors = map[string]func(string, string) error{ - "zip": func(archivePath string, destinationPath string) error { - var zipReader, openReaderError = zip.OpenReader(archivePath) - - if openReaderError != nil { - return openReaderError - } - - defer func() { - if closeError := zipReader.Close(); closeError != nil { - panic(closeError.Error()) - } - }() - - if mkdirError := os.MkdirAll(destinationPath, 0755); mkdirError != nil { - return mkdirError - } - - for i := range zipReader.File { - var file = zipReader.File[i] - var fileReader, fileOpenError = file.Open() - - if fileOpenError != nil { - return fileOpenError - } - - defer func() { - if closeError := fileReader.Close(); closeError != nil { - panic(closeError.Error()) - } - }() - - var path = filepath.Join(destinationPath, file.Name) - - if file.FileInfo().IsDir() { - if mkdirError := os.MkdirAll(path, file.Mode()); mkdirError != nil { - return mkdirError - } - } else { - if mkdirError := os.MkdirAll(filepath.Dir(path), file.Mode()); mkdirError != nil { - return mkdirError - } - - var extractedFile, fileOpenError = os.OpenFile(path, - os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode()) - - if fileOpenError != nil { - return fileOpenError - } - - defer func() { - if fileOpenError := extractedFile.Close(); fileOpenError != nil { - panic(fileOpenError) - } - }() - - var _, copyError = io.Copy(extractedFile, fileReader) - - if copyError != nil { - return copyError - } - } - } - - return nil - }, -}