Skip to content

Commit

Permalink
Configurable list properties + type masking ie list -f, -d
Browse files Browse the repository at this point in the history
+ Allowing for search only of directories or files or a combo
  for those nostalgic for find -type f or find -type d
+ Allowing custom page sizes for list
  • Loading branch information
Emmanuel Odeke committed Jan 7, 2015
1 parent 7e0e52b commit 29157c1
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 36 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ Use `drive help` for further reference.
$ drive diff [path1 path2 ...] # outputs diffs of multiple paths.
$ drive pub [path1 path2 ...] # publishes the files, outputs URL.
$ drive unpub [path1 path2 ...] # revokes public access to the specified files.
$ drive list [-d 2 -a -no-prompt path1 path2 path3 ...] # list contents of paths on remote to a recursion depth of 2 even listing hidden files and not needing to prompt for pagination.
$ drive list [-f -m 2 -a -no-prompt path1 path2 path3 ...] # list only files that are children of paths on remote to a recursion depth of 2 even listing hidden files and not needing to prompt for pagination.
$ drive list [-d -m -1 -a -no-prompt path1 path2 path3 ...] # list all the directories that are sub children of paths on remote to a recursion depth of even listing hidden files and not needing to prompt for pagination.

# Note using the no-clobber option for push or pull ensures that only ADDITIONS are made
# any modifications or deletions are ignored and those files are safe.
Expand Down
37 changes: 27 additions & 10 deletions cmd/drive/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,18 +107,23 @@ func (cmd *quotaCmd) Run(args []string) {
}

type listCmd struct {
hidden *bool
pageCount *int
recursive *bool
depth *int
noPrompt *bool
inTrash *bool
hidden *bool
pageCount *int
recursive *bool
files *bool
directories *bool
depth *int
pageSize *int64
noPrompt *bool
inTrash *bool
}

func (cmd *listCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.depth = fs.Int("d", 1, "maximum recursion depth")
cmd.hidden = fs.Bool("a", false, "list all paths even hidden ones")
cmd.pageCount = fs.Int("p", -1, "number of results per pagination")
cmd.depth = fs.Int("m", 1, "maximum recursion depth")
cmd.hidden = fs.Bool("hidden", false, "list all paths even hidden ones")
cmd.files = fs.Bool("f", false, "list only files")
cmd.directories = fs.Bool("d", false, "list all directories")
cmd.pageSize = fs.Int64("p", 100, "number of results per pagination")
cmd.inTrash = fs.Bool("trashed", false, "list content in the trash")
cmd.noPrompt = fs.Bool("no-prompt", false, "shows no prompt before pagination")
cmd.recursive = fs.Bool("r", false, "recursively list subdirectories")
Expand All @@ -135,15 +140,27 @@ func (cmd *listCmd) Run(args []string) {
if len(uniqArgv) < 1 {
uniqArgv = append(uniqArgv, "")
}
typeMask := 0
if *cmd.directories {
typeMask |= drive.Folder
}
if *cmd.files {
typeMask |= drive.NonFolder
}
if *cmd.inTrash {
typeMask |= drive.InTrash
}

exitWithError(drive.New(context, &drive.Options{
Depth: *cmd.depth,
Hidden: *cmd.hidden,
InTrash: *cmd.inTrash,
PageSize: *cmd.pageSize,
Path: path,
NoPrompt: *cmd.noPrompt,
Recursive: *cmd.recursive,
Sources: uniqArgv,
InTrash: *cmd.inTrash,
TypeMask: typeMask,
}).List())
}

Expand Down
10 changes: 8 additions & 2 deletions commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,18 @@ type Options struct {
Mounts []*config.MountPoint
// NoClobber when set prevents overwriting of stale content
NoClobber bool
NoPrompt bool
Path string
// NoPrompt overwrites any prompt pauses
NoPrompt bool
Path string
// PageSize determines the number of results returned per API call
PageSize int64
Recursive bool
// Sources is a of list all paths that are
// within the scope/path of the current gd context
Sources []string
// TypeMask contains the result of setting different type bits e.g
// Folder to search only for folders etc.
TypeMask int
}

type Commands struct {
Expand Down
74 changes: 53 additions & 21 deletions list.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,26 @@
package drive

import (
drive "github.com/google/google-api-go-client/drive/v2"
"fmt"
drive "github.com/google/google-api-go-client/drive/v2"
"path/filepath"
"strings"
)


var BytesPerKB = float64(1024)

const (
InTrash = 1 << iota
Folder
NonFolder
)

type attribute struct {
human bool
minimal bool
parent string
}

type byteDescription func(b int64) string

func memoizeBytes() byteDescription {
Expand Down Expand Up @@ -89,7 +100,7 @@ func (g *Commands) List() (err error) {
}

for _, r := range remotes {
if !g.breadthFirst(r.Id, "", r.Name, g.opts.Depth, false) {
if !g.breadthFirst(r.Id, "", r.Name, g.opts.Depth, g.opts.TypeMask, false) {
break
}
}
Expand All @@ -114,12 +125,6 @@ func (g *Commands) List() (err error) {
return
}

type attribute struct {
human bool
minimal bool
parent string
}

func (f *File) pretty(opt attribute) {
if opt.minimal {
fmt.Printf("%s/%s\n", opt.parent, f.Name)
Expand All @@ -144,34 +149,53 @@ func (f *File) pretty(opt attribute) {
fmt.Println()
}

func (g *Commands) breadthFirst(parentId, parent, child string, depth int, inTrash bool) bool {
func buildExpression(parentId string, typeMask int, inTrash bool) string {
var exprBuilder []string

if inTrash || (typeMask&InTrash) != 0 {
exprBuilder = append(exprBuilder, "trashed=true")
} else {
exprBuilder = append(exprBuilder, fmt.Sprintf("'%s' in parents", parentId), "trashed=false")
}

// Folder and NonFolder are mutually exclusive.
if (typeMask & Folder) != 0 {
exprBuilder = append(exprBuilder, "mimeType = 'application/vnd.google-apps.folder'")
}
return strings.Join(exprBuilder, " and ")
}

func (g *Commands) breadthFirst(parentId, parent,
child string, depth, typeMask int, inTrash bool) bool {

// A depth of < 0 means traverse as deep as you can
if depth == 0 {
return false
}
if depth > 0 {
depth -= 1
}
pageToken := ""

req := g.rem.service.Files.List()
var expr string
if inTrash || g.opts.InTrash {
expr = "trashed=true"
} else {
expr = fmt.Sprintf("'%s' in parents and trashed=false", parentId)
}
headPath := ""
if parent != "" {
headPath = parent
}
if child != "" {
headPath = headPath + "/" + child
}

pageToken := ""
expr := "trashed=true"

if !inTrash {
expr = buildExpression(parentId, typeMask, g.opts.InTrash)
}

req := g.rem.service.Files.List()
req.Q(expr)

// TODO: Get pageSize from g.opts
req.MaxResults(50)
req.MaxResults(g.opts.PageSize)

var children []*drive.File

Expand All @@ -196,8 +220,16 @@ func (g *Commands) breadthFirst(parentId, parent, child string, depth int, inTra
if isHidden(file.Title, g.opts.Hidden) {
continue
}
rem.pretty(opt)
children = append(children, file)

// The case in which only directories wanted is covered by the buildExpression clause
// reason being that only folder are allowed to be roots, including the only files clause
// would result in incorrect traversal since non-folders don't have children.
// Just don't print it, however, the folder will still be explored.
if (typeMask&NonFolder) != 0 && rem.IsDir {
continue
}
rem.pretty(opt)
}

pageToken = res.NextPageToken
Expand All @@ -211,7 +243,7 @@ func (g *Commands) breadthFirst(parentId, parent, child string, depth int, inTra

if !inTrash && !g.opts.InTrash {
for _, file := range children {
if !g.breadthFirst(file.Id, headPath, file.Title, depth, inTrash) {
if !g.breadthFirst(file.Id, headPath, file.Title, depth, typeMask, inTrash) {
return false
}
}
Expand Down
7 changes: 5 additions & 2 deletions trash.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func (g *Commands) Untrash() (err error) {
}

func (g *Commands) EmptyTrash() error {
if !g.breadthFirst("", "", "", -1, true) {
if !g.breadthFirst("", "", "", -1, 0, true) {
return nil
}

Expand All @@ -55,6 +55,9 @@ func (g *Commands) EmptyTrash() error {

func (g *Commands) trasher(relToRoot string, toTrash bool) (change *Change, err error) {
var file *File
if relToRoot == "/" && toTrash {
return nil, fmt.Errorf("Will not try to trash root.")
}
if toTrash {
file, err = g.rem.FindByPath(relToRoot)
} else {
Expand All @@ -79,7 +82,7 @@ func (g *Commands) reduce(args []string, toTrash bool) error {
for _, relToRoot := range args {
c, cErr := g.trasher(relToRoot, toTrash)
if cErr != nil {
fmt.Printf("%s: %v\n", relToRoot, cErr)
fmt.Printf("\033[91m'%s': %v\033[00m\n", relToRoot, cErr)
} else if c != nil {
cl = append(cl, c)
}
Expand Down

0 comments on commit 29157c1

Please sign in to comment.