aboutsummaryrefslogtreecommitdiff
path: root/steam/package.go
diff options
context:
space:
mode:
authorMitchell Riedstra <mitch@riedstra.dev>2021-08-04 20:06:07 -0400
committerMitchell Riedstra <mitch@riedstra.dev>2021-08-04 20:06:07 -0400
commit742938b00222c7ad57ad11eb24850d9202c2503d (patch)
treee0d1d033027d5dd553c213ed41bb8ae201d6a285 /steam/package.go
parenta5a49ff08056a67cc57435f219aa157342a0d9a0 (diff)
downloadsteam-export-742938b00222c7ad57ad11eb24850d9202c2503d.tar.gz
steam-export-742938b00222c7ad57ad11eb24850d9202c2503d.tar.xz
Pretty large structural changes. Non-building development snapshot
Diffstat (limited to 'steam/package.go')
-rw-r--r--steam/package.go148
1 files changed, 105 insertions, 43 deletions
diff --git a/steam/package.go b/steam/package.go
index bd5bfb5..df6f1e8 100644
--- a/steam/package.go
+++ b/steam/package.go
@@ -8,39 +8,79 @@ import (
"strings"
)
-// Package writes the package, returning bytes written and an error if any
-func (g *Game) Package(wr io.WriteCloser) error {
- acf, err := FindACF(g.LibraryPath, g.Name)
+const (
+ defaultDirectoryMode = 0775
+ defaultFileMode = 0644
+)
+
+// Package writes the package to wr, returning errors if any
+func (l *Library) Package(game string, wr io.WriteCloser) error {
+ g, ok := l.games[game]
+ if !ok {
+ return E_GameDoesNotExist
+ }
+
+ j := newJob("package", g)
+ defer j.done()
+
+ l.status.addJob(j)
+
+ acf, err := FindACF(l.folder, g.Name)
if err != nil {
+ j.addError(err)
return err
}
twriter := tar.NewWriter(wr)
paths := []string{
- filepath.Join(g.LibraryPath, "common", g.Name),
+ filepath.Join(l.folder, "common", g.Name),
acf,
}
for _, pth := range paths {
- err := filepath.Walk(pth, tarWalkfn(twriter, g.LibraryPath))
+ err := filepath.Walk(pth, tarWalkfn(twriter, l.folder))
if err != nil {
+ j.addError(err)
return err
}
}
err = twriter.Flush()
if err != nil {
+ j.addError(err)
return err
}
err = twriter.Close()
+ if err != nil {
+ j.addError(err)
+ return err
+ }
- return wr.Close()
+ err = wr.Close()
+ if err != nil {
+ j.addError(err)
+ }
+ return err
}
// Extract will read a tarball from the io.Reader and install the game into
-// the current library path
-func (l *Library) Extract(r io.Reader) error {
+// the current library path. This offers no visibility into the progress,
+// as it does not update the job status on the progress, though it will
+// populate errors.
+//
+// Most callers will want to use ExtractHTTP or ExtractFile instead
+func (l *Library) Extract(r io.Reader) (*Game, error) {
+ g := &Game{LibraryPath: l.folder}
+ j := newJob("extract", g)
+ defer j.done()
+
+ l.status.addJob(j)
+
+ return l.extractPrimitive(j, g, r)
+}
+
+func (l *Library) extractPrimitive(j *Job, g *Game, r io.Reader) (*Game, error) {
treader := tar.NewReader(r)
for {
@@ -50,78 +90,100 @@ func (l *Library) Extract(r io.Reader) error {
break
}
if err != nil {
- return err
+ j.addError(err)
+ return nil, err
}
- // Fix windows slashes...
- fileName := strings.Replace(hdr.Name, "\\", "/", -1)
+ fileName := filepath.ToSlash(hdr.Name)
+
+ if g.Name == "" {
+ s := strings.Split(fileName, "/")
+ if len(s) >= 2 {
+ g.Name = s[1]
+ }
+ }
- fileName = filepath.Join(l.Folder, fileName)
+ fileName = filepath.Join(l.folder, fileName)
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
+ err = os.MkdirAll(fileName, defaultDirectoryMode)
+ if err != nil {
+ j.addError(err)
+ return nil, err
}
+
continue
}
- if err = os.MkdirAll(filepath.Dir(fileName), 0775); err != nil {
- return err
+ err = os.MkdirAll(filepath.Dir(fileName), defaultDirectoryMode)
+ if err != nil {
+ j.addError(err)
+ return nil, err
}
// Create a file handle to work with
- f, err := os.OpenFile(fileName, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0664)
+ f, err := os.OpenFile(fileName, os.O_CREATE|os.O_TRUNC|os.O_WRONLY,
+ defaultFileMode)
if err != nil {
- return err
+ j.addError(err)
+ return nil, err
}
if _, err := io.Copy(f, treader); err != nil {
+ j.addError(err)
f.Close()
- return err
+ return nil, err
}
f.Close()
}
- return nil
+ err := g.SetSizeInfo()
+ if err != nil {
+ j.addError(err)
+ return nil, err
+ }
+
+ l.m.Lock()
+ l.games[g.Name] = g
+ l.m.Unlock()
+
+ return g, nil
}
// Delete removes all of the game files and the ACF
-func (g *Game) Delete() error {
- acf, err := FindACF(g.LibraryPath, g.Name)
+func (l *Library) Delete(game string) error {
+ g, ok := l.games[game]
+ if !ok {
+ return E_GameDoesNotExist
+ }
+
+ j := newJob("delete", g)
+ defer j.done()
+
+ l.status.addJob(j)
+
+ acf, err := FindACF(l.folder, game)
if err != nil {
+ j.addError(err)
return err
}
if err := os.Remove(acf); err != nil {
+ j.addError(err)
return err
}
- err = os.RemoveAll(filepath.Join(g.LibraryPath, "common", g.Name))
+ err = os.RemoveAll(filepath.Join(l.folder, "common", g.Name))
if err != nil {
+ j.addError(err)
return err
}
- return nil
-}
-
-// GetSize returns the size of a game in a pretty format
-func (g Game) GetSize() string {
- return formatBytes(g.Size)
-}
-
-func (g *Game) setSizeInfo() error {
- pth := filepath.Join(g.LibraryPath, "common", g.Name)
- return filepath.Walk(pth, func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
+ l.m.Lock()
+ delete(l.games, game)
+ l.m.Unlock()
- if info.Mode().IsRegular() {
- g.Size += info.Size()
- }
-
- return nil
- })
+ return nil
}