Initial DDC release
This commit is contained in:
commit
434f6441da
57 files changed
+4606
No files matched your search
Executable
+125
@@ -0,0 +1,125 @@
|
||||
package jobs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"ddc/internal/files"
|
||||
"ddc/internal/libraries"
|
||||
)
|
||||
|
||||
type MoveRequest struct {
|
||||
Paths []string `json:"paths"`
|
||||
Destination string `json:"destination"`
|
||||
Subfolder string `json:"subfolder"`
|
||||
Cleanup bool `json:"cleanup"`
|
||||
}
|
||||
|
||||
func (manager *Manager) Move(id string, request MoveRequest) error {
|
||||
job, err := manager.lookup(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if job.currentStatus() != StatusReady {
|
||||
return ErrJobBusy
|
||||
}
|
||||
if len(request.Paths) == 0 {
|
||||
return invalid(errors.New("select at least one file or folder"))
|
||||
}
|
||||
|
||||
library, err := libraries.Resolve(manager.settings.LibraryRoots, request.Destination)
|
||||
if err != nil {
|
||||
return invalid(err)
|
||||
}
|
||||
subfolder, err := files.SanitizeSubfolder(request.Subfolder)
|
||||
if err != nil {
|
||||
return invalid(err)
|
||||
}
|
||||
sources, err := resolveSources(job.directory, request.Paths)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
destination, err := files.EnsureSubdirectory(library.Path, subfolder)
|
||||
if err != nil {
|
||||
return invalid(err)
|
||||
}
|
||||
if err := checkTargets(sources, destination); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !job.begin(StatusReady, StatusMoving) {
|
||||
return ErrJobBusy
|
||||
}
|
||||
go func() {
|
||||
defer job.workers.Done()
|
||||
manager.moveFiles(job, library, sources, destination, request.Cleanup)
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func resolveSources(root string, relativePaths []string) ([]string, error) {
|
||||
sources := make([]string, 0, len(relativePaths))
|
||||
seenNames := make(map[string]bool)
|
||||
|
||||
for _, relative := range relativePaths {
|
||||
source, err := files.ResolveInside(root, relative)
|
||||
if err != nil {
|
||||
return nil, invalid(err)
|
||||
}
|
||||
name := filepath.Base(source)
|
||||
if seenNames[name] {
|
||||
return nil, invalid(fmt.Errorf("more than one selected item is named %q", name))
|
||||
}
|
||||
seenNames[name] = true
|
||||
sources = append(sources, source)
|
||||
}
|
||||
|
||||
for _, outer := range sources {
|
||||
for _, inner := range sources {
|
||||
if files.IsWithin(outer, inner) {
|
||||
return nil, invalid(errors.New("selection contains a folder and items inside it"))
|
||||
}
|
||||
}
|
||||
}
|
||||
return sources, nil
|
||||
}
|
||||
|
||||
func checkTargets(sources []string, destination string) error {
|
||||
for _, source := range sources {
|
||||
name := filepath.Base(source)
|
||||
if _, err := os.Lstat(filepath.Join(destination, name)); err == nil {
|
||||
return fmt.Errorf("%w: %s", files.ErrDestinationExists, name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (manager *Manager) moveFiles(job *Job, library libraries.Destination, sources []string, destination string, cleanup bool) {
|
||||
job.resetProgress()
|
||||
var totalBytes int64
|
||||
for _, source := range sources {
|
||||
if size, err := files.TreeSize(source); err == nil {
|
||||
totalBytes += size
|
||||
}
|
||||
}
|
||||
job.SetTotal(totalBytes)
|
||||
|
||||
for _, source := range sources {
|
||||
if err := files.MoveInto(source, destination, manager.reservedBytes(), job.Add); err != nil {
|
||||
job.setStatus(StatusReady, "Move failed: "+err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
message := fmt.Sprintf("Moved %d item(s) to %s", len(sources), library.Path)
|
||||
if !cleanup {
|
||||
job.setStatus(StatusReady, message)
|
||||
return
|
||||
}
|
||||
if err := os.RemoveAll(job.directory); err != nil {
|
||||
message += ", cleanup failed: " + err.Error()
|
||||
}
|
||||
job.setStatus(StatusCompleted, message)
|
||||
}
|
||||
Reference in new issue
Block a user