%PDF- %PDF-
| Direktori : /home/waritko/go/src/github.com/odeke-em/drive/src/ |
| Current File : //home/waritko/go/src/github.com/odeke-em/drive/src/trash.go |
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package drive
import (
"fmt"
// "path/filepath"
)
type trashOpt struct {
permanent bool
toTrash bool
byId bool
}
func (g *Commands) Trash(byId bool) (err error) {
opt := trashOpt{
toTrash: true,
permanent: false,
byId: byId,
}
return g.reduceForTrash(g.opts.Sources, &opt)
}
func (g *Commands) Delete(byId bool) (err error) {
opt := trashOpt{
toTrash: true,
permanent: true,
byId: byId,
}
return g.reduceForTrash(g.opts.Sources, &opt)
}
func (g *Commands) Untrash(byId bool) (err error) {
opt := trashOpt{
toTrash: false,
permanent: false,
byId: byId,
}
return g.reduceForTrash(g.opts.Sources, &opt)
}
func (g *Commands) EmptyTrash() error {
rootFile, err := g.rem.FindByPath("/")
if err != nil {
return err
}
spin := g.playabler()
spin.play()
defer spin.stop()
if g.opts.canPrompt() {
travSt := traversalSt{
depth: -1,
file: rootFile,
headPath: "/",
inTrash: true,
mask: g.opts.TypeMask,
explicitNoPrompt: true,
}
if !g.breadthFirst(travSt, spin) {
return nil
}
g.log.Logln("This operation is irreversible. Empty trash! ")
if status := promptForChanges(); !accepted(status) {
g.log.Logln("Aborted emptying trash")
return status.Error()
}
}
err = g.rem.EmptyTrash()
if err == nil {
g.log.Logln("Successfully emptied trash")
}
return err
}
func (g *Commands) trasher(relToRoot string, opt *trashOpt) (*Change, error) {
var file *File
if relToRoot == "/" && opt.toTrash {
return nil, immutableAttemptErr(fmt.Errorf("Will not try to trash root."))
}
resolver := g.rem.FindByPathTrashed
if opt.byId {
resolver = g.rem.FindById
} else if opt.toTrash {
resolver = g.rem.FindByPath
}
file, err := resolver(relToRoot)
if err != nil {
return nil, err
}
if opt.byId {
if file.Labels != nil {
if file.Labels.Trashed == opt.toTrash {
return nil, illogicalStateErr(fmt.Errorf("toTrash=%v set yet already file.Trash=%v", opt.toTrash, file.Labels.Trashed))
}
}
relToRoot = fmt.Sprintf("%s (%s)", relToRoot, file.Name)
}
change := &Change{Path: relToRoot, g: g}
if opt.toTrash {
change.Dest = file
} else {
change.Src = file
}
return change, nil
}
func (g *Commands) trashByMatch(inTrash, permanent bool) error {
mq := matchQuery{
dirPath: g.opts.Path,
inTrash: false,
titleSearches: []fuzzyStringsValuePair{
{fuzzyLevel: Like, values: g.opts.Sources, inTrash: inTrash},
},
}
var cl []*Change
p := g.opts.Path
if p == "/" {
p = ""
}
pagePair := g.rem.FindMatches(&mq)
errsChan := pagePair.errsChan
matches := pagePair.filesChan
working := true
for working {
select {
case err := <-errsChan:
if err != nil {
return err
}
case match, stillHasContent := <-matches:
if !stillHasContent {
working = false
break
}
if match == nil {
continue
}
ch := &Change{Path: p + "/" + match.Name, g: g}
if inTrash {
ch.Src = match
} else {
ch.Dest = match
}
cl = append(cl, ch)
}
}
if len(cl) < 1 {
return noMatchesFoundErr(fmt.Errorf("no matches found!"))
}
clArg := changeListArg{
logy: g.log,
changes: cl,
noClobber: false,
noPrompt: !g.opts.canPrompt(),
canPreview: g.opts.canPreview(),
}
status, _ := printChangeList(&clArg)
if !accepted(status) {
return status.Error()
}
toTrash := !inTrash
opt := trashOpt{
toTrash: toTrash,
permanent: permanent,
}
return g.playTrashChangeList(cl, &opt)
}
func (g *Commands) TrashByMatch() error {
return g.trashByMatch(false, false)
}
func (g *Commands) UntrashByMatch() error {
return g.trashByMatch(true, false)
}
func (g *Commands) DeleteByMatch() error {
return g.trashByMatch(false, true)
}
func (g *Commands) reduceForTrash(args []string, opt *trashOpt) error {
var cl []*Change
for i, relToRoot := range args {
c, cErr := g.trasher(relToRoot, opt)
g.DebugPrintf("[reduceForTrash] #%d: relToRoot: %s\n", i, relToRoot)
if cErr != nil {
g.log.LogErrf("\033[91m'%s': %v\033[00m\n", relToRoot, cErr)
} else if c != nil {
cl = append(cl, c)
}
}
clArg := changeListArg{
logy: g.log,
changes: cl,
noClobber: false,
canPreview: g.opts.canPreview(),
noPrompt: !g.opts.canPrompt(),
}
status, _ := printChangeList(&clArg)
if !accepted(status) {
return status.Error()
}
if opt.permanent && g.opts.canPrompt() {
status := promptForChanges("This operation is irreversible. Continue [Y/N] ")
if !accepted(status) {
return status.Error()
}
}
return g.playTrashChangeList(cl, opt)
}
func (g *Commands) playTrashChangeList(cl []*Change, opt *trashOpt) (err error) {
trashSize, unTrashSize := reduceToSize(cl, SelectDest|SelectSrc)
g.taskStart(trashSize + unTrashSize)
var fn func(*Change) error
if opt.permanent {
fn = g.remoteDelete
g.DebugPrintf("[playTrashChangeList] isPermanentOp. Selecting remoteDelete\n")
} else {
fn = g.remoteUntrash
if opt.toTrash {
fn = g.remoteTrash
}
g.DebugPrintf("[playTrashChangeList/nonPermanentOp]: toTrash: %v\n", opt.toTrash)
}
for i, c := range cl {
op := c.Op()
g.DebugPrintf("[playTrashChangeList] #%d op: %v change: %#v\n", i, op, c)
if c.Op() == OpNone {
continue
}
cErr := fn(c)
if cErr != nil {
g.log.LogErrln(cErr)
}
}
g.taskFinish()
return err
}