diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/archive/archive.go | 104 | ||||
| -rw-r--r-- | lib/archive/unarchive.go | 85 | ||||
| -rw-r--r-- | lib/config/config.go | 89 | ||||
| -rw-r--r-- | lib/config/config_unix.go | 21 | ||||
| -rw-r--r-- | lib/config/config_windows.go | 22 | ||||
| -rw-r--r-- | lib/steam/package.go | 96 | ||||
| -rw-r--r-- | lib/steam/steam.go | 123 | ||||
| -rw-r--r-- | lib/steam/unix.go | 10 | ||||
| -rw-r--r-- | lib/steam/windows.go | 5 |
9 files changed, 555 insertions, 0 deletions
diff --git a/lib/archive/archive.go b/lib/archive/archive.go new file mode 100644 index 0000000..639a864 --- /dev/null +++ b/lib/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/lib/archive/unarchive.go b/lib/archive/unarchive.go new file mode 100644 index 0000000..8a5617e --- /dev/null +++ b/lib/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/lib/config/config.go b/lib/config/config.go new file mode 100644 index 0000000..839acbf --- /dev/null +++ b/lib/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/lib/config/config_unix.go b/lib/config/config_unix.go new file mode 100644 index 0000000..8be1967 --- /dev/null +++ b/lib/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/lib/config/config_windows.go b/lib/config/config_windows.go new file mode 100644 index 0000000..39b6b6c --- /dev/null +++ b/lib/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/lib/steam/package.go b/lib/steam/package.go new file mode 100644 index 0000000..2e25994 --- /dev/null +++ b/lib/steam/package.go @@ -0,0 +1,96 @@ +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 new file mode 100644 index 0000000..ea27e5a --- /dev/null +++ b/lib/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/lib/steam/unix.go b/lib/steam/unix.go new file mode 100644 index 0000000..caa4b43 --- /dev/null +++ b/lib/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/lib/steam/windows.go b/lib/steam/windows.go new file mode 100644 index 0000000..17fe62c --- /dev/null +++ b/lib/steam/windows.go @@ -0,0 +1,5 @@ +// +build windows + +package steam + +var DefaultLib string = `C:\Program Files (x86)\Steam\steamapps` |
