Skip to content

Commit

Permalink
Support ls -R
Browse files Browse the repository at this point in the history
  • Loading branch information
Colm Dougan authored and colinmarc committed Jul 11, 2023
1 parent f5542d2 commit a909804
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 21 deletions.
69 changes: 50 additions & 19 deletions cmd/hdfs/ls.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 13,7 @@ import (
"github.com/colinmarc/hdfs/v2"
)

func ls(paths []string, long, all, humanReadable bool) {
func ls(paths []string, long, all, humanReadable, recursive bool) {
paths, client, err := getClientAndExpandedPaths(paths)
if err != nil {
fatal(err)
Expand All @@ -25,7 25,8 @@ func ls(paths []string, long, all, humanReadable bool) {

files := make([]string, 0, len(paths))
fileInfos := make([]os.FileInfo, 0, len(paths))
dirs := make([]string, 0, len(paths))

var dirs []string
for _, p := range paths {
fi, err := client.Stat(p)
if err != nil {
Expand All @@ -40,34 41,64 @@ func ls(paths []string, long, all, humanReadable bool) {
}
}

// The target is a directory; print its contents instead of the directory
// entry itself. Even recursive ls on a single directory still just prints the
// toplevel first, without a leading "/foo/bar:".
skipTopLevel = false
if len(files) == 0 && len(dirs) == 1 {
printDir(client, dirs[0], long, all, humanReadable)
skipTopLevel = true
}

if long {
tw := lsTabWriter()
for i, p := range files {
printLong(tw, p, fileInfos[i], humanReadable)
}

tw.Flush()
} else {
if long {
tw := lsTabWriter()
for i, p := range files {
printLong(tw, p, fileInfos[i], humanReadable)
}
for _, p := range files {
fmt.Println(p)
}
}

tw.Flush()
} else {
for _, p := range files {
fmt.Println(p)
}
// Add all nested directories for the recursive case. These are printed as
// "siblings".
if recursive {
var nestedDirs []string
for _, dir := range dirs {
client.Walk(dir, func(path string, info fs.FileInfo, err error) error {
if err != nil {
return err
}

if info.IsDir() {
nestedDirs = append(nestedDirs, path)
}

return nil
})
}

for i, dir := range dirs {
if i > 0 || len(files) > 0 {
fmt.Println()
}
if skipTopLevel && len(nestedDirs) > 0 {
dirs = nestedDirs[1:]
} else {
dirs = nestedDirs
}
}

fmt.Printf("%s/:\n", dir)
printDir(client, dir, long, all, humanReadable)
for i, dir := range dirs {
if i > 0 || len(files) > 0 {
fmt.Println()
}

fmt.Printf("\n%s:\n", dir)
printDir(client, dir, long, all, humanReadable)
}
}

func printDir(client *hdfs.Client, dir string, long, all, humanReadable bool) {
func printDir(client *hdfs.Client, dir string, long, all, humanReadable) {
dirReader, err := client.Open(dir)
if err != nil {
fatal(err)
Expand Down
5 changes: 3 additions & 2 deletions cmd/hdfs/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 22,7 @@ var (
The flags available are a subset of the POSIX ones, but should behave similarly.
Valid commands:
ls [-lah] [FILE]...
ls [-lahR] [FILE]...
rm [-rf] FILE...
mv [-nT] SOURCE... DEST
mkdir [-p] FILE...
Expand All @@ -46,6 46,7 @@ Valid commands:
lsl = lsOpts.Bool('l')
lsa = lsOpts.Bool('a')
lsh = lsOpts.Bool('h')
lsR = lsOpts.Bool('R')

rmOpts = getopt.New()
rmr = rmOpts.Bool('r')
Expand Down Expand Up @@ -118,7 119,7 @@ func main() {
fatal("gohdfs version", version)
case "ls":
lsOpts.Parse(argv)
ls(lsOpts.Args(), *lsl, *lsa, *lsh)
ls(lsOpts.Args(), *lsl, *lsa, *lsh, *lsR)
case "rm":
rmOpts.Parse(argv)
rm(rmOpts.Args(), *rmr, *rmf)
Expand Down
16 changes: 16 additions & 0 deletions cmd/hdfs/test/glob.bats
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 43,22 @@ d
OUT
}

@test "ls recursive on glob" {
run $HDFS ls -R /_test_cmd/ls/dir*
assert_success
assert_output <<OUT
/_test_cmd/ls/dir1:
a
b
c
/_test_cmd/ls/dir2:
d
/_test_cmd/ls/dir3:
OUT
}

@test "ls with two globs, one of which is qualified" {
run $HDFS ls /_test_cmd/glob/dir*/*
assert_success
Expand Down
46 changes: 46 additions & 0 deletions cmd/hdfs/test/ls.bats
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 22,44 @@ c
OUT
}

@test "ls recursive on nested dir" {
run $HDFS ls -R /_test_cmd/ls
assert_success
assert_output <<OUT
dir1
dir2
dir3
/_test_cmd/ls/dir1:
a
b
c
/_test_cmd/ls/dir2:
d
/_test_cmd/ls/dir3:
OUT
}

@test "ls recursive on leaf dir" {
run $HDFS ls -R /_test_cmd/ls/dir1
assert_success
assert_output <<OUT
a
b
c
OUT
}

@test "ls recursive on file" {
run $HDFS ls -R /_test_cmd/ls/dir1/c
assert_success
assert_output <<OUT
/_test_cmd/ls/dir1/c
OUT
}

@test "ls single files" {
run $HDFS ls /_test_cmd/ls/dir1/a /_test_cmd/ls/dir1/b
assert_success
Expand All @@ -39,6 77,14 @@ stat /_test_cmd/nonexistent: file does not exist
OUT
}

@test "ls recursive nonexistent" {
run $HDFS ls -R /_test_cmd/nonexistent
assert_failure
assert_output <<OUT
stat /_test_cmd/nonexistent: file does not exist
OUT
}

teardown() {
$HDFS rm -r /_test_cmd/ls
}

0 comments on commit a909804

Please sign in to comment.