forked from itchio/butler
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cp.go
98 lines (77 loc) · 2.22 KB
/
cp.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package main
import (
"io"
"os"
"path/filepath"
"time"
humanize "github.com/dustin/go-humanize"
"github.com/itchio/butler/comm"
"github.com/itchio/wharf/counter"
"github.com/itchio/wharf/eos"
)
func cp(src string, dest string, resume bool) {
must(doCp(src, dest, resume))
}
func doCp(srcPath string, destPath string, resume bool) error {
src, err := eos.Open(srcPath)
if err != nil {
return err
}
defer src.Close()
dir := filepath.Dir(destPath)
err = os.MkdirAll(dir, 0755)
if err != nil {
return err
}
flags := os.O_CREATE | os.O_WRONLY
dest, err := os.OpenFile(destPath, flags, 0644)
if err != nil {
return err
}
defer dest.Close()
stats, err := src.Stat()
if err != nil {
return err
}
totalBytes := int64(stats.Size())
startOffset := int64(0)
if resume {
startOffset, err = dest.Seek(0, os.SEEK_END)
if err != nil {
return err
}
if startOffset == 0 {
comm.Logf("Downloading %s", humanize.IBytes(uint64(totalBytes)))
} else if startOffset > totalBytes {
comm.Logf("Existing data too big (%s > %s), starting over", humanize.IBytes(uint64(startOffset)), humanize.IBytes(uint64(totalBytes)))
} else if startOffset == totalBytes {
comm.Logf("All %s already there", humanize.IBytes(uint64(totalBytes)))
return nil
}
comm.Logf("Resuming at %s / %s", humanize.IBytes(uint64(startOffset)), humanize.IBytes(uint64(totalBytes)))
_, err = src.Seek(startOffset, os.SEEK_SET)
if err != nil {
return err
}
} else {
comm.Logf("Downloading %s", humanize.IBytes(uint64(totalBytes)))
}
start := time.Now()
comm.Progress(float64(startOffset) / float64(totalBytes))
comm.StartProgressWithTotalBytes(totalBytes)
cw := counter.NewWriterCallback(func(count int64) {
alpha := float64(startOffset+count) / float64(totalBytes)
comm.Progress(alpha)
}, dest)
copiedBytes, err := io.Copy(cw, src)
if err != nil {
return err
}
comm.EndProgress()
totalDuration := time.Since(start)
prettyStartOffset := humanize.IBytes(uint64(startOffset))
prettySize := humanize.IBytes(uint64(copiedBytes))
perSecond := humanize.IBytes(uint64(float64(totalBytes-startOffset) / totalDuration.Seconds()))
comm.Statf("%s + %s copied @ %s/s\n", prettyStartOffset, prettySize, perSecond)
return nil
}