From 971cc396e1d01f53f65a86278fd0ac4490565335 Mon Sep 17 00:00:00 2001 From: Mitch Riedstra Date: Fri, 20 Nov 2020 19:56:29 -0500 Subject: Reorganize. Update to use go modules. --- Build.sh | 15 ++-- archive/archive.go | 104 +++++++++++++++++++++++ archive/unarchive.go | 85 +++++++++++++++++++ cli.go | 195 ------------------------------------------ cmd/cli/main.go | 196 +++++++++++++++++++++++++++++++++++++++++++ config/config.go | 89 ++++++++++++++++++++ config/config_unix.go | 21 +++++ config/config_windows.go | 22 +++++ go.mod | 5 ++ go.sum | 3 + lib/archive/archive.go | 104 ----------------------- lib/archive/unarchive.go | 85 ------------------- lib/config/config.go | 89 -------------------- lib/config/config_unix.go | 21 ----- lib/config/config_windows.go | 22 ----- lib/steam/package.go | 96 --------------------- lib/steam/steam.go | 123 --------------------------- lib/steam/unix.go | 10 --- lib/steam/windows.go | 5 -- steam/package.go | 96 +++++++++++++++++++++ steam/steam.go | 123 +++++++++++++++++++++++++++ steam/unix.go | 10 +++ steam/windows.go | 5 ++ 23 files changed, 768 insertions(+), 756 deletions(-) create mode 100644 archive/archive.go create mode 100644 archive/unarchive.go delete mode 100644 cli.go create mode 100644 cmd/cli/main.go create mode 100644 config/config.go create mode 100644 config/config_unix.go create mode 100644 config/config_windows.go create mode 100644 go.mod create mode 100644 go.sum delete mode 100644 lib/archive/archive.go delete mode 100644 lib/archive/unarchive.go delete mode 100644 lib/config/config.go delete mode 100644 lib/config/config_unix.go delete mode 100644 lib/config/config_windows.go delete mode 100644 lib/steam/package.go delete mode 100644 lib/steam/steam.go delete mode 100644 lib/steam/unix.go delete mode 100644 lib/steam/windows.go create mode 100644 steam/package.go create mode 100644 steam/steam.go create mode 100644 steam/unix.go create mode 100644 steam/windows.go diff --git a/Build.sh b/Build.sh index 8a31e2c..57b1c16 100755 --- a/Build.sh +++ b/Build.sh @@ -1,22 +1,25 @@ #!/bin/sh - +set -e +set -x if ! [ -d bin ] ; then mkdir bin fi -go build -o bin/steam-export . +commands=cli + +for cmd in $commands ; do export GOOS=windows export GOARCH="386" -go build -o bin/steam-export-$GOOS-$GOARCH.exe . +go build -o bin/steam-export-$GOOS-$GOARCH.exe ./cmd/$cmd export GOOS=windows export GOARCH=amd64 -go build -o bin/steam-export-$GOOS-$GOARCH.exe . +go build -o bin/steam-export-$GOOS-$GOARCH.exe ./cmd/$cmd export GOOS=linux export GOARCH=amd64 -go build -o bin/steam-export-$GOOS-$GOARCH . +go build -o bin/steam-export-$GOOS-$GOARCH ./cmd/$cmd -cp bin/* /Fishtank/Mitch/SteamDrive/scripts/ +done diff --git a/archive/archive.go b/archive/archive.go new file mode 100644 index 0000000..639a864 --- /dev/null +++ b/archive/archive.go @@ -0,0 +1,104 @@ +package archive + +import ( + "archive/tar" + "path/filepath" + + "compress/gzip" + + "io" + "os" + + "strings" +) + +type Archive struct { + Output string + Input []string + file *os.File +} + +func (a *Archive) Tar(compressionType string) error { + var err error + if a.file, err = os.Create(a.Output); err != nil { + return err + } + + defer a.file.Close() + + var twriter *tar.Writer + + // Set the compression type... if any + switch compressionType { + case "gz": + gzwriter, err := gzip.NewWriterLevel(a.file, gzip.BestSpeed) + if err != nil { + return err + } + defer gzwriter.Close() + // Write to the gzip writer + twriter = tar.NewWriter(gzwriter) + default: + // Write directly to the file + twriter = tar.NewWriter(a.file) + } + + // Close off the tar writer when we're done + defer twriter.Close() + + for _, v := range a.Input { + if err := filepath.Walk(v, tarWalkfn(twriter)); err != nil { + return err + } + } + + return nil + +} + +func tarWalkfn(writer *tar.Writer) filepath.WalkFunc { + // This is an interesting trick to get around scoping issues + return func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if info.IsDir() { + return nil + } + + f, err := os.Open(path) + if err != nil { + return err + } + defer f.Close() + + // Convert Windows paths to Unix paths + path = strings.Replace(path, "\\", "/", -1) + + // TODO; See if tar.FileInfoheader() could be used instead + // without the pathing issues I encountered + h := &tar.Header{ + Name: path, + Size: info.Size(), + // I don't like it... but it helps with platform compatibility + Mode: 0664, + ModTime: info.ModTime(), + } + + err = writer.WriteHeader(h) + if err != nil { + return err + } + + _, err = io.Copy(writer, f) + if err != nil { + // TODO: Figure out how to add more useful information to + // These errors + // fmt.Fprintln(os.Stderr, f.Name()) + return err + } + + return nil + } +} diff --git a/archive/unarchive.go b/archive/unarchive.go new file mode 100644 index 0000000..8a5617e --- /dev/null +++ b/archive/unarchive.go @@ -0,0 +1,85 @@ +package archive + +import ( + "archive/tar" + fp "path/filepath" + + "compress/gzip" + + "io" + "os" + + "strings" +) + +type Unarchive struct { + Input string + tarReader *tar.Reader +} + +// Extracts a tar arcive to the current working directory +// This will overwrite everything. So be careful +func (u *Unarchive) UnTar(compressionType string) error { + f, err := os.Open(u.Input) + if err != nil { + return err + } + defer f.Close() + + var treader *tar.Reader + + switch compressionType { + case "gz": + gzreader, err := gzip.NewReader(f) + if err != nil { + return err + } + // Read from the gzip reader instead of the file + treader = tar.NewReader(gzreader) + default: + // Read from the file directly + treader = tar.NewReader(f) + } + + for { + hdr, err := treader.Next() + if err == io.EOF { + // We've reached the end! Whoee + break + } + if err != nil { + return err + } + + // Fix windows slashes... + fileName := strings.Replace(hdr.Name, "\\", "/", -1) + + info := hdr.FileInfo() + if info.IsDir() { + // I don't like hard-coded permissions but it + // it helps with overall platform compatibility + if err = os.MkdirAll(fileName, 0775); err != nil { + return err + } + continue + } + + if err = os.MkdirAll(fp.Dir(fileName), 0775); err != nil { + return err + } + + // Create a file handle to work with + // f, err := os.Create(fileName) + f, err := os.OpenFile(fileName, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0664) + if err != nil { + return err + } + defer f.Close() + if _, err := io.Copy(f, treader); err != nil { + return err + } + + } + + return nil +} diff --git a/cli.go b/cli.go deleted file mode 100644 index af0654d..0000000 --- a/cli.go +++ /dev/null @@ -1,195 +0,0 @@ -package main - -import ( - "errors" - "flag" - "fmt" - "os" - - "git.riedstra.us/mitch/steam-export/lib/config" - "git.riedstra.us/mitch/steam-export/lib/steam" -) - -var ( - errorHandling flag.ErrorHandling = flag.ExitOnError - - steamLib *steam.Library = &steam.Library{} -) - -func parseArgs(args []string) error { - if len(args) < 2 { - return errors.New("Not enough arguments") - } - aa := args[2:] - switch a := args[1]; a { - case "list": - return listGames(aa) - case "package": - return packageGame(aa) - case "extract": - return extractGame(aa) - case "delete": - return deleteGame(aa) - case "edit-config": - return editConfig(aa) - default: - printHelp() - } - - return nil -} - -func printHelp() { - fmt.Printf(`--- -Program usage: -steam-export-cli $subcommand $options -Subcommands: - list - package - extract - delete - server - edit-config - -Type in a subcommand -h or -help for more information -`) - -} - -func editConfig(args []string) error { - fl := flag.NewFlagSet("edit-config", errorHandling) - e := fl.String("e", "", "Editor to invoke") - if err := fl.Parse(args); err != nil { - return err - } - return config.EditDefaultConfig(*e) -} - -func listGames(args []string) error { - fl := flag.NewFlagSet("list", errorHandling) - lib := fl.String("l", steam.DefaultLib, - "Path to library in question. All the way to the 'steamapps' folder") - - l := steam.DefaultLib - fl.Parse(args) - if fl.Parsed() { - l = string(*lib) - } - - if err := steamLib.ProcessLibrary(l); err != nil { - return err - } - - fmt.Println(steamLib) - - return nil -} - -func packageGame(args []string) error { - fl := flag.NewFlagSet("package", errorHandling) - lib := fl.String("l", steam.DefaultLib, - "Path to library in question. All the way to the 'steamapps' folder") - fileName := fl.String("f", "export", - "Name of the archive file to be created. Please do not include the file extension") - game := fl.Int("g", -1, - "Index of the game to be exported. Please see `list` for the index") - compress := fl.String("z", "gz", - "Compression type. Default 'gz' '' is no compression") - - var g int - l := steam.DefaultLib - fl.Parse(args) - if fl.Parsed() { - l = string(*lib) - g = int(*game) - } - - if err := steamLib.ProcessLibrary(l); err != nil { - return err - } - - if len(steamLib.Games) < g || g == -1 { - return errors.New("Cannot find game for index provided or no index provided") - } - - if *fileName == "export" { - fileName = &steamLib.Games[g] - } - - switch *compress { - case "gz": - return steamLib.PackageGameToFile(g, *fileName+".tar.gz", *compress) - default: - return steamLib.PackageGameToFile(g, *fileName+".tar", *compress) - } - -} - -func extractGame(args []string) error { - fl := flag.NewFlagSet("extract", errorHandling) - lib := fl.String("l", steam.DefaultLib, - "Path to library in question. All the way to the 'steamapps' folder") - fileName := fl.String("f", "", - "Name of the archive file to be extracted. Please include the file extension") - compress := fl.String("z", "gz", - "Compression type. Default 'gz' '' is no compression") - - l := steam.DefaultLib - fl.Parse(args) - if fl.Parsed() { - l = string(*lib) - } - - if err := steamLib.ProcessLibrary(l); err != nil { - return err - } - - if *fileName == "" { - return errors.New("No filename provided") - } - - return steamLib.ExtractGameFromFile(*fileName, *compress) - -} - -func deleteGame(args []string) error { - fl := flag.NewFlagSet("delete", errorHandling) - lib := fl.String("l", steam.DefaultLib, - "Path to library in question. All the way to the 'steamapps' folder") - game := fl.Int("g", -1, - "Index of the game to be deleted. Please see `list` for the index") - - var g int - l := steam.DefaultLib - fl.Parse(args) - if fl.Parsed() { - l = string(*lib) - g = int(*game) - } - - if err := steamLib.ProcessLibrary(l); err != nil { - return err - } - - if len(steamLib.Games) < g || g == -1 { - return errors.New("Cannot find game for index provided or no index provided") - } - - return steamLib.DeleteGame(g) -} - -func main() { - config, err := config.LoadConfig() - if err != nil { - fmt.Println(err) - } else { - if config.DefaultRepository != "" { - steam.DefaultLib = config.DefaultRepository - } - } - - if err := parseArgs(os.Args); err != nil { - fmt.Fprintln(os.Stderr, err) - printHelp() - } -} diff --git a/cmd/cli/main.go b/cmd/cli/main.go new file mode 100644 index 0000000..3292d30 --- /dev/null +++ b/cmd/cli/main.go @@ -0,0 +1,196 @@ +package main + +import ( + "errors" + "flag" + "fmt" + "os" + + "riedstra.dev/mitch/steam-export/config" + "riedstra.dev/mitch/steam-export/steam" +) + +var ( + errorHandling flag.ErrorHandling = flag.ExitOnError + + steamLib *steam.Library = &steam.Library{} +) + +func parseArgs(args []string) error { + if len(args) < 2 { + return errors.New("Not enough arguments") + } + aa := args[2:] + switch a := args[1]; a { + case "list": + return listGames(aa) + case "package": + return packageGame(aa) + case "extract": + return extractGame(aa) + case "delete": + return deleteGame(aa) + case "edit-config": + return editConfig(aa) + default: + printHelp() + } + + return nil +} + +func printHelp() { + fmt.Printf(`--- +Program usage: +steam-export-cli $subcommand $options +Subcommands: + list + package + extract + delete + server + edit-config + +Type in a subcommand -h or -help for more information +`) + +} + +func editConfig(args []string) error { + fl := flag.NewFlagSet("edit-config", errorHandling) + e := fl.String("e", "", "Editor to invoke") + if err := fl.Parse(args); err != nil { + return err + } + return config.EditDefaultConfig(*e) +} + +func listGames(args []string) error { + fl := flag.NewFlagSet("list", errorHandling) + lib := fl.String("l", steam.DefaultLib, + "Path to library in question. All the way to the 'steamapps' folder") + + l := steam.DefaultLib + fl.Parse(args) + if fl.Parsed() { + l = string(*lib) + } + + if err := steamLib.ProcessLibrary(l); err != nil { + return err + } + + fmt.Println(steamLib) + + return nil +} + +func packageGame(args []string) error { + fl := flag.NewFlagSet("package", errorHandling) + lib := fl.String("l", steam.DefaultLib, + "Path to library in question. All the way to the 'steamapps' folder") + fileName := fl.String("f", "export", + "Name of the archive file to be created. Please do not include the file extension") + game := fl.Int("g", -1, + "Index of the game to be exported. Please see `list` for the index") + compress := fl.String("z", "gz", + "Compression type. Default 'gz' '' is no compression") + + var g int + l := steam.DefaultLib + fl.Parse(args) + if fl.Parsed() { + l = string(*lib) + g = int(*game) + } + + if err := steamLib.ProcessLibrary(l); err != nil { + return err + } + + if len(steamLib.Games) < g || g == -1 { + return errors.New("Cannot find game for index provided or no index provided") + } + + if *fileName == "export" { + fileName = &steamLib.Games[g] + } + + switch *compress { + case "gz": + return steamLib.PackageGameToFile(g, *fileName+".tar.gz", *compress) + default: + return steamLib.PackageGameToFile(g, *fileName+".tar", *compress) + } + +} + +func extractGame(args []string) error { + fl := flag.NewFlagSet("extract", errorHandling) + lib := fl.String("l", steam.DefaultLib, + "Path to library in question. All the way to the 'steamapps' folder") + fileName := fl.String("f", "", + "Name of the archive file to be extracted. Please include the file extension") + compress := fl.String("z", "gz", + "Compression type. Default 'gz' '' is no compression") + + l := steam.DefaultLib + fl.Parse(args) + if fl.Parsed() { + l = string(*lib) + } + + if err := steamLib.ProcessLibrary(l); err != nil { + return err + } + + if *fileName == "" { + return errors.New("No filename provided") + } + + return steamLib.ExtractGameFromFile(*fileName, *compress) + +} + +func deleteGame(args []string) error { + fl := flag.NewFlagSet("delete", errorHandling) + lib := fl.String("l", steam.DefaultLib, + "Path to library in question. All the way to the 'steamapps' folder") + game := fl.Int("g", -1, + "Index of the game to be deleted. Please see `list` for the index") + + var g int + l := steam.DefaultLib + fl.Parse(args) + if fl.Parsed() { + l = string(*lib) + g = int(*game) + } + + if err := steamLib.ProcessLibrary(l); err != nil { + return err + } + + if len(steamLib.Games) < g || g == -1 { + return errors.New("Cannot find game for index provided or no index provided") + } + + return steamLib.DeleteGame(g) +} + +func main() { + config, err := config.LoadConfig() + if err != nil { + fmt.Println(err) + } else { + if config.DefaultRepository != "" { + steam.DefaultLib = config.DefaultRepository + } + } + + if err := parseArgs(os.Args); err != nil { + fmt.Fprintln(os.Stderr, err) + printHelp() + } +} + diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..839acbf --- /dev/null +++ b/config/config.go @@ -0,0 +1,89 @@ +// Used to define and load this application's specific configuration +package config + +import ( + "gopkg.in/yaml.v2" + "io/ioutil" + "os" + "os/exec" +) + +type Config struct { + SteamRepositories []string `yaml:"SteamRepositories"` + DefaultRepository string `yaml:"DefaultRepository"` + Listen string +} + +var configFilename string = "steam-export.yml" + +// By default it reads 'config.yml' in the current directory +func LoadConfig() (*Config, error) { + c := &Config{} + err := c.ReadDefaultConfig() + return c, err +} + +func (c *Config) ReadConfig(cfg string) error { + contents, err := ioutil.ReadFile(cfg) + if err != nil { + return err + } + return yaml.Unmarshal([]byte(contents), c) +} + +func checkConfigFile(cf string) error { + // Check if our config file exists, or create it + if _, err := os.Stat(cf); err != nil { + if f, err := os.Create(cf); err != nil { + return err + } else { + f.WriteString(` +--- +listen: 0.0.0.0:9413 +# Repositories that you want to expose on the web server +SteamRepositories: + # We're ideally looking for the full path to the steamapps folder + # On windows you're going to escape the slashes + - "C:\\Program Files (x86)\\Steam\\steamapps" + # - "/usr/mitch/SteamGames/steamapps" + +# This defaults to: +# Only change this if your default Steam library is different than the Steam default +# DefaultRepository: "/usr/mitch/SteamGames/steamapps" +# DefaultRepository: "Z:\\SteamGames\\steamapps" +`) + f.Close() + } + } + return nil +} + +func (c *Config) ReadDefaultConfig() error { + if err := c.ReadConfig(configFilename); err != nil { + if err = checkConfigFile(fn); err != nil { + return err + } + return c.ReadConfig(fn) + } + return nil +} + +func EditDefaultConfig(e string) error { + if e != "" { + editor = e + } + + if _, err := os.Stat(configFilename); err != nil { + if _, err := os.Stat(fn); err != nil { + return err + } + c := exec.Command(editor, fn) + c.Stdout = os.Stdout + c.Stdin = os.Stdin + c.Stderr = os.Stderr + return c.Run() + } + cmd := exec.Command(editor, configFilename) + return cmd.Run() + +} diff --git a/config/config_unix.go b/config/config_unix.go new file mode 100644 index 0000000..8be1967 --- /dev/null +++ b/config/config_unix.go @@ -0,0 +1,21 @@ +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris + +package config + +import ( + "os" + "path/filepath" +) + +var ( + editor string = setEditor() + fn string = filepath.Join(os.Getenv("HOME"), "."+configFilename) +) + +func setEditor() string { + e := os.Getenv("EDITOR") + if e == "" { + return "vi" + } + return e +} diff --git a/config/config_windows.go b/config/config_windows.go new file mode 100644 index 0000000..39b6b6c --- /dev/null +++ b/config/config_windows.go @@ -0,0 +1,22 @@ +// +build windows + +package config + +import ( + "os" + // "os/exec" + "path/filepath" +) + +var ( + editor string = setEditor() + fn string = filepath.Join(os.Getenv("LOCALAPPDATA"), configFilename) +) + +func setEditor() string { + e := os.Getenv("EDITOR") + if e == "" { + return `C:\Program Files\Windows NT\Accessories\wordpad.exe` + } + return e +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..3f4cfa5 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module riedstra.dev/mitch/steam-export + +go 1.15 + +require gopkg.in/yaml.v2 v2.3.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..8fabe8d --- /dev/null +++ b/go.sum @@ -0,0 +1,3 @@ +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/lib/archive/archive.go b/lib/archive/archive.go deleted file mode 100644 index 639a864..0000000 --- a/lib/archive/archive.go +++ /dev/null @@ -1,104 +0,0 @@ -package archive - -import ( - "archive/tar" - "path/filepath" - - "compress/gzip" - - "io" - "os" - - "strings" -) - -type Archive struct { - Output string - Input []string - file *os.File -} - -func (a *Archive) Tar(compressionType string) error { - var err error - if a.file, err = os.Create(a.Output); err != nil { - return err - } - - defer a.file.Close() - - var twriter *tar.Writer - - // Set the compression type... if any - switch compressionType { - case "gz": - gzwriter, err := gzip.NewWriterLevel(a.file, gzip.BestSpeed) - if err != nil { - return err - } - defer gzwriter.Close() - // Write to the gzip writer - twriter = tar.NewWriter(gzwriter) - default: - // Write directly to the file - twriter = tar.NewWriter(a.file) - } - - // Close off the tar writer when we're done - defer twriter.Close() - - for _, v := range a.Input { - if err := filepath.Walk(v, tarWalkfn(twriter)); err != nil { - return err - } - } - - return nil - -} - -func tarWalkfn(writer *tar.Writer) filepath.WalkFunc { - // This is an interesting trick to get around scoping issues - return func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - if info.IsDir() { - return nil - } - - f, err := os.Open(path) - if err != nil { - return err - } - defer f.Close() - - // Convert Windows paths to Unix paths - path = strings.Replace(path, "\\", "/", -1) - - // TODO; See if tar.FileInfoheader() could be used instead - // without the pathing issues I encountered - h := &tar.Header{ - Name: path, - Size: info.Size(), - // I don't like it... but it helps with platform compatibility - Mode: 0664, - ModTime: info.ModTime(), - } - - err = writer.WriteHeader(h) - if err != nil { - return err - } - - _, err = io.Copy(writer, f) - if err != nil { - // TODO: Figure out how to add more useful information to - // These errors - // fmt.Fprintln(os.Stderr, f.Name()) - return err - } - - return nil - } -} diff --git a/lib/archive/unarchive.go b/lib/archive/unarchive.go deleted file mode 100644 index 8a5617e..0000000 --- a/lib/archive/unarchive.go +++ /dev/null @@ -1,85 +0,0 @@ -package archive - -import ( - "archive/tar" - fp "path/filepath" - - "compress/gzip" - - "io" - "os" - - "strings" -) - -type Unarchive struct { - Input string - tarReader *tar.Reader -} - -// Extracts a tar arcive to the current working directory -// This will overwrite everything. So be careful -func (u *Unarchive) UnTar(compressionType string) error { - f, err := os.Open(u.Input) - if err != nil { - return err - } - defer f.Close() - - var treader *tar.Reader - - switch compressionType { - case "gz": - gzreader, err := gzip.NewReader(f) - if err != nil { - return err - } - // Read from the gzip reader instead of the file - treader = tar.NewReader(gzreader) - default: - // Read from the file directly - treader = tar.NewReader(f) - } - - for { - hdr, err := treader.Next() - if err == io.EOF { - // We've reached the end! Whoee - break - } - if err != nil { - return err - } - - // Fix windows slashes... - fileName := strings.Replace(hdr.Name, "\\", "/", -1) - - info := hdr.FileInfo() - if info.IsDir() { - // I don't like hard-coded permissions but it - // it helps with overall platform compatibility - if err = os.MkdirAll(fileName, 0775); err != nil { - return err - } - continue - } - - if err = os.MkdirAll(fp.Dir(fileName), 0775); err != nil { - return err - } - - // Create a file handle to work with - // f, err := os.Create(fileName) - f, err := os.OpenFile(fileName, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0664) - if err != nil { - return err - } - defer f.Close() - if _, err := io.Copy(f, treader); err != nil { - return err - } - - } - - return nil -} diff --git a/lib/config/config.go b/lib/config/config.go deleted file mode 100644 index 839acbf..0000000 --- a/lib/config/config.go +++ /dev/null @@ -1,89 +0,0 @@ -// Used to define and load this application's specific configuration -package config - -import ( - "gopkg.in/yaml.v2" - "io/ioutil" - "os" - "os/exec" -) - -type Config struct { - SteamRepositories []string `yaml:"SteamRepositories"` - DefaultRepository string `yaml:"DefaultRepository"` - Listen string -} - -var configFilename string = "steam-export.yml" - -// By default it reads 'config.yml' in the current directory -func LoadConfig() (*Config, error) { - c := &Config{} - err := c.ReadDefaultConfig() - return c, err -} - -func (c *Config) ReadConfig(cfg string) error { - contents, err := ioutil.ReadFile(cfg) - if err != nil { - return err - } - return yaml.Unmarshal([]byte(contents), c) -} - -func checkConfigFile(cf string) error { - // Check if our config file exists, or create it - if _, err := os.Stat(cf); err != nil { - if f, err := os.Create(cf); err != nil { - return err - } else { - f.WriteString(` ---- -listen: 0.0.0.0:9413 -# Repositories that you want to expose on the web server -SteamRepositories: - # We're ideally looking for the full path to the steamapps folder - # On windows you're going to escape the slashes - - "C:\\Program Files (x86)\\Steam\\steamapps" - # - "/usr/mitch/SteamGames/steamapps" - -# This defaults to: -# Only change this if your default Steam library is different than the Steam default -# DefaultRepository: "/usr/mitch/SteamGames/steamapps" -# DefaultRepository: "Z:\\SteamGames\\steamapps" -`) - f.Close() - } - } - return nil -} - -func (c *Config) ReadDefaultConfig() error { - if err := c.ReadConfig(configFilename); err != nil { - if err = checkConfigFile(fn); err != nil { - return err - } - return c.ReadConfig(fn) - } - return nil -} - -func EditDefaultConfig(e string) error { - if e != "" { - editor = e - } - - if _, err := os.Stat(configFilename); err != nil { - if _, err := os.Stat(fn); err != nil { - return err - } - c := exec.Command(editor, fn) - c.Stdout = os.Stdout - c.Stdin = os.Stdin - c.Stderr = os.Stderr - return c.Run() - } - cmd := exec.Command(editor, configFilename) - return cmd.Run() - -} diff --git a/lib/config/config_unix.go b/lib/config/config_unix.go deleted file mode 100644 index 8be1967..0000000 --- a/lib/config/config_unix.go +++ /dev/null @@ -1,21 +0,0 @@ -// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris - -package config - -import ( - "os" - "path/filepath" -) - -var ( - editor string = setEditor() - fn string = filepath.Join(os.Getenv("HOME"), "."+configFilename) -) - -func setEditor() string { - e := os.Getenv("EDITOR") - if e == "" { - return "vi" - } - return e -} diff --git a/lib/config/config_windows.go b/lib/config/config_windows.go deleted file mode 100644 index 39b6b6c..0000000 --- a/lib/config/config_windows.go +++ /dev/null @@ -1,22 +0,0 @@ -// +build windows - -package config - -import ( - "os" - // "os/exec" - "path/filepath" -) - -var ( - editor string = setEditor() - fn string = filepath.Join(os.Getenv("LOCALAPPDATA"), configFilename) -) - -func setEditor() string { - e := os.Getenv("EDITOR") - if e == "" { - return `C:\Program Files\Windows NT\Accessories\wordpad.exe` - } - return e -} diff --git a/lib/steam/package.go b/lib/steam/package.go deleted file mode 100644 index 2e25994..0000000 --- a/lib/steam/package.go +++ /dev/null @@ -1,96 +0,0 @@ -package steam - -import ( - // "fmt" - "git.riedstra.us/mitch/steam-export/lib/archive" - "os" - "path/filepath" -) - -func (l *Library) PackageGameToFile(index int, file, compress string) error { - g := l.Games[index] - - working_dir, err := os.Getwd() - if err != nil { - return err - } - // output := working_dir + "/" + g + ".tar" - output, err := filepath.Abs(file) - if err != nil { - return err - } - - os.Chdir(l.Folder) - acf, err := l.FindACF(g) - if err != nil { - return err - } - input := []string{"common/" + g, acf} - a := archive.Archive{Output: output, Input: input} - err = a.Tar(compress) - if err != nil { - return err - } - - os.Chdir(working_dir) - - return nil -} - -func (l *Library) ExtractGameFromFile(f, compress string) error { - working_dir, err := os.Getwd() - if err != nil { - return err - } - - f, err = filepath.Abs(f) - if err != nil { - return err - } - - if err = os.Chdir(l.Folder); err != nil { - return err - } - u := &archive.Unarchive{ - Input: f, - } - if err := u.UnTar(compress); err != nil { - return err - } - - if err = os.Chdir(working_dir); err != nil { - return err - } - return nil -} - -func (l *Library) DeleteGame(i int) error { - g := l.Games[i] - - working_dir, err := os.Getwd() - if err != nil { - return err - } - - if err = os.Chdir(l.Folder); err != nil { - return err - } - - acf, err := l.FindACF(g) - if err != nil { - return err - } - // fmt.Fprintf(os.Stderr, "Removing %q %q\n", acf, "common/"+g) - if err := os.Remove(acf); err != nil { - return err - } - if err := os.RemoveAll("common/" + g); err != nil { - return err - } - - if err = os.Chdir(working_dir); err != nil { - return err - } - - return nil -} diff --git a/lib/steam/steam.go b/lib/steam/steam.go deleted file mode 100644 index ea27e5a..0000000 --- a/lib/steam/steam.go +++ /dev/null @@ -1,123 +0,0 @@ -// This is designed to be a rather simplistic library to help pull information -// from a local steam library -package steam - -import ( - "fmt" - "io/ioutil" - - "errors" - - "bufio" - "os" - "path/filepath" - "strings" - // "log" -) - -type Library struct { - Folder string - Games []string -} - -func ProcessMultipleLibraries(r []string) ([]*Library, error) { - var libs []*Library - for _, i := range r { - lib := &Library{} - err := lib.ProcessLibrary(i) - if err != nil { - return nil, err - } - libs = append(libs, lib) - } - return libs, nil -} - -// Populate the "Folder" and "Games" fields based on the provided directory -func (s *Library) ProcessLibrary(r string) error { - if hasCommon(r) { - dirs, err := ioutil.ReadDir(r + "/common") - if err != nil { - return err - } - s.Folder = r - for _, f := range dirs { - if f.IsDir() { - s.Games = append(s.Games, f.Name()) - } - } - } else { - return errors.New(fmt.Sprintf("No common directory in: %s", r)) - } - return nil -} - -// Find the ACF files related to this video game -func (l *Library) FindACF(g string) (string, error) { - working_dir, err := os.Getwd() - if err != nil { - return "", err - } - if err = os.Chdir(l.Folder); err != nil { - return "", err - } - files, err := filepath.Glob("*.acf") - if err != nil { - return "", err - } - for _, fn := range files { - info, err := os.Lstat(fn) - if err != nil { - return "", err - } - // We don't want it if it's a directory - if info.IsDir() { - continue - } - - // Open up the file - f, err := os.Open(fn) - defer f.Close() - if err != nil { - return "", err - } - scanner := bufio.NewScanner(f) - for scanner.Scan() { - // Finally check and see if the file has the video game name - if strings.Contains(scanner.Text(), g) { - os.Chdir(working_dir) - return fn, nil - // fmt.Printf("%s/%s:%d: %s\n", root, path, i, scanner.Text()) - } - } - - } - str := "Couldn't find ACF file related to Game: %s" - return "", errors.New(fmt.Sprintf(str, g)) -} - -// This is automatically called to print out the contents of the struct -// when things like fmt.Println are used -func (s *Library) String() (str string) { - str = fmt.Sprintln("\n----") - str = str + fmt.Sprintln(s.Folder) - str = str + "\n----\n" - for k, v := range s.Games { - str = str + fmt.Sprintf("%d: %s\n", k, v) - //str = str + fmt.Sprintln(v) - } - return -} - -func hasCommon(d string) bool { - dirs, err := ioutil.ReadDir(d) - if err != nil { - return false - } - for _, f := range dirs { - if f.Name() == "common" && f.IsDir() { - return true - } - } - return false -} diff --git a/lib/steam/unix.go b/lib/steam/unix.go deleted file mode 100644 index caa4b43..0000000 --- a/lib/steam/unix.go +++ /dev/null @@ -1,10 +0,0 @@ -// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris - -package steam - -import ( - "os" - "path/filepath" -) - -var DefaultLib string = filepath.Join(os.Getenv("HOME"), ".steam/steam/steamapps") diff --git a/lib/steam/windows.go b/lib/steam/windows.go deleted file mode 100644 index 17fe62c..0000000 --- a/lib/steam/windows.go +++ /dev/null @@ -1,5 +0,0 @@ -// +build windows - -package steam - -var DefaultLib string = `C:\Program Files (x86)\Steam\steamapps` diff --git a/steam/package.go b/steam/package.go new file mode 100644 index 0000000..a73a6bc --- /dev/null +++ b/steam/package.go @@ -0,0 +1,96 @@ +package steam + +import ( + // "fmt" + "riedstra.dev/mitch/steam-export/archive" + "os" + "path/filepath" +) + +func (l *Library) PackageGameToFile(index int, file, compress string) error { + g := l.Games[index] + + working_dir, err := os.Getwd() + if err != nil { + return err + } + // output := working_dir + "/" + g + ".tar" + output, err := filepath.Abs(file) + if err != nil { + return err + } + + os.Chdir(l.Folder) + acf, err := l.FindACF(g) + if err != nil { + return err + } + input := []string{"common/" + g, acf} + a := archive.Archive{Output: output, Input: input} + err = a.Tar(compress) + if err != nil { + return err + } + + os.Chdir(working_dir) + + return nil +} + +func (l *Library) ExtractGameFromFile(f, compress string) error { + working_dir, err := os.Getwd() + if err != nil { + return err + } + + f, err = filepath.Abs(f) + if err != nil { + return err + } + + if err = os.Chdir(l.Folder); err != nil { + return err + } + u := &archive.Unarchive{ + Input: f, + } + if err := u.UnTar(compress); err != nil { + return err + } + + if err = os.Chdir(working_dir); err != nil { + return err + } + return nil +} + +func (l *Library) DeleteGame(i int) error { + g := l.Games[i] + + working_dir, err := os.Getwd() + if err != nil { + return err + } + + if err = os.Chdir(l.Folder); err != nil { + return err + } + + acf, err := l.FindACF(g) + if err != nil { + return err + } + // fmt.Fprintf(os.Stderr, "Removing %q %q\n", acf, "common/"+g) + if err := os.Remove(acf); err != nil { + return err + } + if err := os.RemoveAll("common/" + g); err != nil { + return err + } + + if err = os.Chdir(working_dir); err != nil { + return err + } + + return nil +} diff --git a/steam/steam.go b/steam/steam.go new file mode 100644 index 0000000..ea27e5a --- /dev/null +++ b/steam/steam.go @@ -0,0 +1,123 @@ +// This is designed to be a rather simplistic library to help pull information +// from a local steam library +package steam + +import ( + "fmt" + "io/ioutil" + + "errors" + + "bufio" + "os" + "path/filepath" + "strings" + // "log" +) + +type Library struct { + Folder string + Games []string +} + +func ProcessMultipleLibraries(r []string) ([]*Library, error) { + var libs []*Library + for _, i := range r { + lib := &Library{} + err := lib.ProcessLibrary(i) + if err != nil { + return nil, err + } + libs = append(libs, lib) + } + return libs, nil +} + +// Populate the "Folder" and "Games" fields based on the provided directory +func (s *Library) ProcessLibrary(r string) error { + if hasCommon(r) { + dirs, err := ioutil.ReadDir(r + "/common") + if err != nil { + return err + } + s.Folder = r + for _, f := range dirs { + if f.IsDir() { + s.Games = append(s.Games, f.Name()) + } + } + } else { + return errors.New(fmt.Sprintf("No common directory in: %s", r)) + } + return nil +} + +// Find the ACF files related to this video game +func (l *Library) FindACF(g string) (string, error) { + working_dir, err := os.Getwd() + if err != nil { + return "", err + } + if err = os.Chdir(l.Folder); err != nil { + return "", err + } + files, err := filepath.Glob("*.acf") + if err != nil { + return "", err + } + for _, fn := range files { + info, err := os.Lstat(fn) + if err != nil { + return "", err + } + // We don't want it if it's a directory + if info.IsDir() { + continue + } + + // Open up the file + f, err := os.Open(fn) + defer f.Close() + if err != nil { + return "", err + } + scanner := bufio.NewScanner(f) + for scanner.Scan() { + // Finally check and see if the file has the video game name + if strings.Contains(scanner.Text(), g) { + os.Chdir(working_dir) + return fn, nil + // fmt.Printf("%s/%s:%d: %s\n", root, path, i, scanner.Text()) + } + } + + } + str := "Couldn't find ACF file related to Game: %s" + return "", errors.New(fmt.Sprintf(str, g)) +} + +// This is automatically called to print out the contents of the struct +// when things like fmt.Println are used +func (s *Library) String() (str string) { + str = fmt.Sprintln("\n----") + str = str + fmt.Sprintln(s.Folder) + str = str + "\n----\n" + for k, v := range s.Games { + str = str + fmt.Sprintf("%d: %s\n", k, v) + //str = str + fmt.Sprintln(v) + } + return +} + +func hasCommon(d string) bool { + dirs, err := ioutil.ReadDir(d) + if err != nil { + return false + } + for _, f := range dirs { + if f.Name() == "common" && f.IsDir() { + return true + } + } + return false +} diff --git a/steam/unix.go b/steam/unix.go new file mode 100644 index 0000000..caa4b43 --- /dev/null +++ b/steam/unix.go @@ -0,0 +1,10 @@ +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris + +package steam + +import ( + "os" + "path/filepath" +) + +var DefaultLib string = filepath.Join(os.Getenv("HOME"), ".steam/steam/steamapps") diff --git a/steam/windows.go b/steam/windows.go new file mode 100644 index 0000000..17fe62c --- /dev/null +++ b/steam/windows.go @@ -0,0 +1,5 @@ +// +build windows + +package steam + +var DefaultLib string = `C:\Program Files (x86)\Steam\steamapps` -- cgit v1.2.3