Files
acp/acp.go
2022-09-14 12:19:32 +08:00

146 lines
2.6 KiB
Go

package acp
import (
"context"
"os"
"sync"
"github.com/schollz/progressbar/v3"
"github.com/sirupsen/logrus"
)
const (
StageIndex = iota
StageCopy
StageFinished
)
type Copyer struct {
*option
createFlag int
stage int64
copyedBytes int64
totalBytes int64
copyedFiles int64
totalFiles int64
updateProgressBar func(func(bar *progressbar.ProgressBar))
updateCopying func(func(set map[int64]struct{}))
logf func(l logrus.Level, format string, args ...any)
jobsLock sync.Mutex
jobs []*baseJob
noSpaceSource []*source
errsLock sync.Mutex
errors []*Error
badDstsLock sync.Mutex
badDsts map[string]error
readingFiles chan struct{}
writePipe chan *writeJob
postPipe chan *baseJob
running sync.WaitGroup
}
func New(ctx context.Context, opts ...Option) (*Copyer, error) {
opt := newOption()
for _, o := range opts {
if o == nil {
continue
}
opt = o(opt)
}
if err := opt.check(); err != nil {
return nil, err
}
c := &Copyer{
option: opt,
stage: StageIndex,
updateProgressBar: func(f func(bar *progressbar.ProgressBar)) {},
updateCopying: func(f func(set map[int64]struct{})) {},
logf: func(l logrus.Level, format string, args ...any) {
logrus.StandardLogger().Logf(l, format, args...)
},
badDsts: make(map[string]error),
writePipe: make(chan *writeJob, 32),
postPipe: make(chan *baseJob, 8),
}
c.createFlag = os.O_WRONLY | os.O_CREATE
if c.overwrite {
c.createFlag |= os.O_TRUNC
} else {
c.createFlag |= os.O_EXCL
}
if c.fromDevice.linear {
c.readingFiles = make(chan struct{}, 1)
}
c.running.Add(1)
go wrap(ctx, func() { c.run(ctx) })
return c, nil
}
func (c *Copyer) Wait() *Report {
c.running.Wait()
return c.Report()
}
func (c *Copyer) run(ctx context.Context) {
defer c.running.Done()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
if c.withProgressBar {
c.startProgressBar(ctx)
}
c.index(ctx)
if !c.checkJobs() {
return
}
if err := c.applyAutoFillLimit(); err != nil {
c.reportError("_autofill", err)
return
}
c.copy(ctx)
}
func (c *Copyer) reportError(file string, err error) {
e := &Error{Path: file, Err: err}
c.logf(logrus.ErrorLevel, e.Error())
c.errsLock.Lock()
defer c.errsLock.Unlock()
c.errors = append(c.errors, e)
}
func (c *Copyer) getErrors() []*Error {
c.errsLock.Lock()
defer c.errsLock.Unlock()
return c.errors
}
func (c *Copyer) addBadDsts(dst string, err error) {
c.badDstsLock.Lock()
defer c.badDstsLock.Unlock()
c.badDsts[dst] = err
}
func (c *Copyer) getBadDsts() map[string]error {
c.errsLock.Lock()
defer c.errsLock.Unlock()
return c.badDsts
}