Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
dms3
go-dms3
Commits
0332f3db
Commit
0332f3db
authored
9 years ago
by
Jeromy Johnson
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1348 from ipfs/tk/unixfs-ls
Add 'ipfs file ls …'
parents
aefdb4e0
4acab79d
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
414 additions
and
2 deletions
+414
-2
commands/response.go
commands/response.go
+3
-2
core/commands/root.go
core/commands/root.go
+3
-0
core/commands/unixfs/ls.go
core/commands/unixfs/ls.go
+202
-0
core/commands/unixfs/unixfs.go
core/commands/unixfs/unixfs.go
+21
-0
test/sharness/t0200-unixfs-ls.sh
test/sharness/t0200-unixfs-ls.sh
+185
-0
No files found.
commands/response.go
View file @
0332f3db
...
@@ -15,8 +15,9 @@ type ErrorType uint
...
@@ -15,8 +15,9 @@ type ErrorType uint
// ErrorTypes convey what category of error ocurred
// ErrorTypes convey what category of error ocurred
const
(
const
(
ErrNormal
ErrorType
=
iota
// general errors
ErrNormal
ErrorType
=
iota
// general errors
ErrClient
// error was caused by the client, (e.g. invalid CLI usage)
ErrClient
// error was caused by the client, (e.g. invalid CLI usage)
ErrImplementation
// programmer error in the server
// TODO: add more types of errors for better error-specific handling
// TODO: add more types of errors for better error-specific handling
)
)
...
...
This diff is collapsed.
Click to expand it.
core/commands/root.go
View file @
0332f3db
...
@@ -5,6 +5,7 @@ import (
...
@@ -5,6 +5,7 @@ import (
"strings"
"strings"
cmds
"github.com/ipfs/go-ipfs/commands"
cmds
"github.com/ipfs/go-ipfs/commands"
unixfs
"github.com/ipfs/go-ipfs/core/commands/unixfs"
evlog
"github.com/ipfs/go-ipfs/thirdparty/eventlog"
evlog
"github.com/ipfs/go-ipfs/thirdparty/eventlog"
)
)
...
@@ -35,6 +36,7 @@ DATA STRUCTURE COMMANDS
...
@@ -35,6 +36,7 @@ DATA STRUCTURE COMMANDS
block Interact with raw blocks in the datastore
block Interact with raw blocks in the datastore
object Interact with raw dag nodes
object Interact with raw dag nodes
file Interact with Unix filesystem objects
ADVANCED COMMANDS
ADVANCED COMMANDS
...
@@ -102,6 +104,7 @@ var rootSubcommands = map[string]*cmds.Command{
...
@@ -102,6 +104,7 @@ var rootSubcommands = map[string]*cmds.Command{
"stats"
:
StatsCmd
,
"stats"
:
StatsCmd
,
"swarm"
:
SwarmCmd
,
"swarm"
:
SwarmCmd
,
"tour"
:
tourCmd
,
"tour"
:
tourCmd
,
"file"
:
unixfs
.
UnixFSCmd
,
"update"
:
UpdateCmd
,
"update"
:
UpdateCmd
,
"version"
:
VersionCmd
,
"version"
:
VersionCmd
,
"bitswap"
:
BitswapCmd
,
"bitswap"
:
BitswapCmd
,
...
...
This diff is collapsed.
Click to expand it.
core/commands/unixfs/ls.go
0 → 100644
View file @
0332f3db
package
unixfs
import
(
"bytes"
"fmt"
"io"
"sort"
"text/tabwriter"
"time"
context
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
cmds
"github.com/ipfs/go-ipfs/commands"
core
"github.com/ipfs/go-ipfs/core"
path
"github.com/ipfs/go-ipfs/path"
unixfs
"github.com/ipfs/go-ipfs/unixfs"
unixfspb
"github.com/ipfs/go-ipfs/unixfs/pb"
)
type
LsLink
struct
{
Name
,
Hash
string
Size
uint64
Type
string
}
type
LsObject
struct
{
Hash
string
Size
uint64
Type
string
Links
[]
LsLink
}
type
LsOutput
struct
{
Arguments
map
[
string
]
string
Objects
map
[
string
]
*
LsObject
}
var
LsCmd
=
&
cmds
.
Command
{
Helptext
:
cmds
.
HelpText
{
Tagline
:
"List directory contents for Unix-filesystem objects"
,
ShortDescription
:
`
Retrieves the object named by <ipfs-or-ipns-path> and displays the
contents with the following format:
<hash> <type> <size> <name>
For files, the child size is the total size of the file contents. For
directories, the child size is the IPFS link size.
`
,
},
Arguments
:
[]
cmds
.
Argument
{
cmds
.
StringArg
(
"ipfs-path"
,
true
,
true
,
"The path to the IPFS object(s) to list links from"
)
.
EnableStdin
(),
},
Run
:
func
(
req
cmds
.
Request
,
res
cmds
.
Response
)
{
node
,
err
:=
req
.
Context
()
.
GetNode
()
if
err
!=
nil
{
res
.
SetError
(
err
,
cmds
.
ErrNormal
)
return
}
paths
:=
req
.
Arguments
()
output
:=
LsOutput
{
Arguments
:
map
[
string
]
string
{},
Objects
:
map
[
string
]
*
LsObject
{},
}
for
_
,
fpath
:=
range
paths
{
ctx
:=
req
.
Context
()
.
Context
merkleNode
,
err
:=
core
.
Resolve
(
ctx
,
node
,
path
.
Path
(
fpath
))
if
err
!=
nil
{
res
.
SetError
(
err
,
cmds
.
ErrNormal
)
return
}
key
,
err
:=
merkleNode
.
Key
()
if
err
!=
nil
{
res
.
SetError
(
err
,
cmds
.
ErrNormal
)
return
}
hash
:=
key
.
B58String
()
output
.
Arguments
[
fpath
]
=
hash
if
_
,
ok
:=
output
.
Objects
[
hash
];
ok
{
// duplicate argument for an already-listed node
continue
}
unixFSNode
,
err
:=
unixfs
.
FromBytes
(
merkleNode
.
Data
)
if
err
!=
nil
{
res
.
SetError
(
err
,
cmds
.
ErrNormal
)
return
}
t
:=
unixFSNode
.
GetType
()
output
.
Objects
[
hash
]
=
&
LsObject
{
Hash
:
key
.
String
(),
Type
:
t
.
String
(),
Size
:
unixFSNode
.
GetFilesize
(),
}
switch
t
{
default
:
res
.
SetError
(
fmt
.
Errorf
(
"unrecognized type: %s"
,
t
),
cmds
.
ErrImplementation
)
return
case
unixfspb
.
Data_File
:
break
case
unixfspb
.
Data_Directory
:
links
:=
make
([]
LsLink
,
len
(
merkleNode
.
Links
))
output
.
Objects
[
hash
]
.
Links
=
links
for
i
,
link
:=
range
merkleNode
.
Links
{
getCtx
,
cancel
:=
context
.
WithTimeout
(
ctx
,
time
.
Minute
)
defer
cancel
()
link
.
Node
,
err
=
link
.
GetNode
(
getCtx
,
node
.
DAG
)
if
err
!=
nil
{
res
.
SetError
(
err
,
cmds
.
ErrNormal
)
return
}
d
,
err
:=
unixfs
.
FromBytes
(
link
.
Node
.
Data
)
if
err
!=
nil
{
res
.
SetError
(
err
,
cmds
.
ErrNormal
)
return
}
t
:=
d
.
GetType
()
lsLink
:=
LsLink
{
Name
:
link
.
Name
,
Hash
:
link
.
Hash
.
B58String
(),
Type
:
t
.
String
(),
}
if
t
==
unixfspb
.
Data_File
{
lsLink
.
Size
=
d
.
GetFilesize
()
}
else
{
lsLink
.
Size
=
link
.
Size
}
links
[
i
]
=
lsLink
}
}
}
res
.
SetOutput
(
&
output
)
},
Marshalers
:
cmds
.
MarshalerMap
{
cmds
.
Text
:
func
(
res
cmds
.
Response
)
(
io
.
Reader
,
error
)
{
output
:=
res
.
Output
()
.
(
*
LsOutput
)
buf
:=
new
(
bytes
.
Buffer
)
w
:=
tabwriter
.
NewWriter
(
buf
,
1
,
2
,
1
,
' '
,
0
)
nonDirectories
:=
[]
string
{}
directories
:=
[]
string
{}
for
argument
,
hash
:=
range
output
.
Arguments
{
object
,
ok
:=
output
.
Objects
[
hash
]
if
!
ok
{
return
nil
,
fmt
.
Errorf
(
"unresolved hash: %s"
,
hash
)
}
if
object
.
Type
==
"Directory"
{
directories
=
append
(
directories
,
argument
)
}
else
{
nonDirectories
=
append
(
nonDirectories
,
argument
)
}
}
sort
.
Strings
(
nonDirectories
)
sort
.
Strings
(
directories
)
for
_
,
argument
:=
range
nonDirectories
{
fmt
.
Fprintf
(
w
,
"%s
\n
"
,
argument
)
}
seen
:=
map
[
string
]
bool
{}
for
i
,
argument
:=
range
directories
{
hash
:=
output
.
Arguments
[
argument
]
if
_
,
ok
:=
seen
[
hash
];
ok
{
continue
}
seen
[
hash
]
=
true
object
:=
output
.
Objects
[
hash
]
if
i
>
0
||
len
(
nonDirectories
)
>
0
{
fmt
.
Fprintln
(
w
)
}
if
len
(
output
.
Arguments
)
>
1
{
for
_
,
arg
:=
range
directories
[
i
:
]
{
if
output
.
Arguments
[
arg
]
==
hash
{
fmt
.
Fprintf
(
w
,
"%s:
\n
"
,
arg
)
}
}
}
for
_
,
link
:=
range
object
.
Links
{
fmt
.
Fprintf
(
w
,
"%s
\n
"
,
link
.
Name
)
}
}
w
.
Flush
()
return
buf
,
nil
},
},
Type
:
LsOutput
{},
}
This diff is collapsed.
Click to expand it.
core/commands/unixfs/unixfs.go
0 → 100644
View file @
0332f3db
package
unixfs
import
cmds
"github.com/ipfs/go-ipfs/commands"
var
UnixFSCmd
=
&
cmds
.
Command
{
Helptext
:
cmds
.
HelpText
{
Tagline
:
"Interact with ipfs objects representing Unix filesystems"
,
ShortDescription
:
`
'ipfs file' provides a familar interface to filesystems represtented
by IPFS objects that hides IPFS-implementation details like layout
objects (e.g. fanout and chunking).
`
,
Synopsis
:
`
ipfs file ls <path>... - List directory contents for <path>...
`
,
},
Subcommands
:
map
[
string
]
*
cmds
.
Command
{
"ls"
:
LsCmd
,
},
}
This diff is collapsed.
Click to expand it.
test/sharness/t0200-unixfs-ls.sh
0 → 100755
View file @
0332f3db
#!/bin/sh
#
# Copyright (c) 2014 Christian Couder
# MIT Licensed; see the LICENSE file in this repository.
#
test_description
=
"Test file ls command"
.
lib/test-lib.sh
test_init_ipfs
test_ls_cmd
()
{
test_expect_success
"'ipfs add -r testData' succeeds"
'
mkdir -p testData testData/d1 testData/d2 &&
echo "test" >testData/f1 &&
echo "data" >testData/f2 &&
echo "hello" >testData/d1/a &&
random 128 42 >testData/d1/128 &&
echo "world" >testData/d2/a &&
random 1024 42 >testData/d2/1024 &&
ipfs add -r testData >actual_add
'
test_expect_success
"'ipfs add' output looks good"
'
cat <<-\EOF >expected_add &&
added QmQNd6ubRXaNG6Prov8o6vk3bn6eWsj9FxLGrAVDUAGkGe testData/d1/128
added QmZULkCELmmk5XNfCgTnCyFgAVxBRBXyDHGGMVoLFLiXEN testData/d1/a
added QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss testData/d1
added QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd testData/d2/1024
added QmaRGe7bVmVaLmxbrMiVNXqW4pRNNp3xq7hFtyRKA3mtJL testData/d2/a
added QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy testData/d2
added QmeomffUNfmQy76CQGy9NdmqEnnHU9soCexBnGU3ezPHVH testData/f1
added QmNtocSs7MoDkJMc1RkyisCSKvLadujPsfJfSdJ3e1eA1M testData/f2
added QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj testData
EOF
test_cmp expected_add actual_add
'
test_expect_success
"'ipfs file ls <dir>' succeeds"
'
ipfs file ls QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy >actual_ls_one_directory
'
test_expect_success
"'ipfs file ls <dir>' output looks good"
'
cat <<-\EOF >expected_ls_one_directory &&
1024
a
EOF
test_cmp expected_ls_one_directory actual_ls_one_directory
'
test_expect_success
"'ipfs file ls <three dir hashes>' succeeds"
'
ipfs file ls QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss >actual_ls_three_directories
'
test_expect_success
"'ipfs file ls <three dir hashes>' output looks good"
'
cat <<-\EOF >expected_ls_three_directories &&
QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy:
1024
a
QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss:
128
a
QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj:
d1
d2
f1
f2
EOF
test_cmp expected_ls_three_directories actual_ls_three_directories
'
test_expect_success
"'ipfs file ls <file hashes>' succeeds"
'
ipfs file ls /ipfs/QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy/1024 QmQNd6ubRXaNG6Prov8o6vk3bn6eWsj9FxLGrAVDUAGkGe >actual_ls_file
'
test_expect_success
"'ipfs file ls <file hashes>' output looks good"
'
cat <<-\EOF >expected_ls_file &&
/ipfs/QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy/1024
QmQNd6ubRXaNG6Prov8o6vk3bn6eWsj9FxLGrAVDUAGkGe
EOF
test_cmp expected_ls_file actual_ls_file
'
test_expect_success
"'ipfs file ls <duplicates>' succeeds"
'
ipfs file ls /ipfs/QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj/d1 /ipfs/QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss /ipfs/QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy/1024 /ipfs/QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd >actual_ls_duplicates_file
'
test_expect_success
"'ipfs file ls <duplicates>' output looks good"
'
cat <<-\EOF >expected_ls_duplicates_file &&
/ipfs/QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy/1024
/ipfs/QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd
/ipfs/QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss:
/ipfs/QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj/d1:
128
a
EOF
test_cmp expected_ls_duplicates_file actual_ls_duplicates_file
'
test_expect_success
"'ipfs --encoding=json file ls <file hashes>' succeeds"
'
ipfs --encoding=json file ls /ipfs/QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy/1024 >actual_json_ls_file
'
test_expect_success
"'ipfs --encoding=json file ls <file hashes>' output looks good"
'
cat <<-\EOF >expected_json_ls_file_trailing_newline &&
{
"Arguments": {
"/ipfs/QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy/1024": "QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd"
},
"Objects": {
"QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd": {
"Hash": "QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd",
"Size": 1024,
"Type": "File",
"Links": null
}
}
}
EOF
printf %s "$(cat expected_json_ls_file_trailing_newline)" >expected_json_ls_file &&
test_cmp expected_json_ls_file actual_json_ls_file
'
test_expect_success
"'ipfs --encoding=json file ls <duplicates>' succeeds"
'
ipfs --encoding=json file ls /ipfs/QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj/d1 /ipfs/QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss /ipfs/QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy/1024 /ipfs/QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd >actual_json_ls_duplicates_file
'
test_expect_success
"'ipfs --encoding=json file ls <duplicates>' output looks good"
'
cat <<-\EOF >expected_json_ls_duplicates_file_trailing_newline &&
{
"Arguments": {
"/ipfs/QmR3jhV4XpxxPjPT3Y8vNnWvWNvakdcT3H6vqpRBsX1MLy/1024": "QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd",
"/ipfs/QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss": "QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss",
"/ipfs/QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd": "QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd",
"/ipfs/QmfNy183bXiRVyrhyWtq3TwHn79yHEkiAGFr18P7YNzESj/d1": "QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss"
},
"Objects": {
"QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss": {
"Hash": "QmSix55yz8CzWXf5ZVM9vgEvijnEeeXiTSarVtsqiiCJss",
"Size": 0,
"Type": "Directory",
"Links": [
{
"Name": "128",
"Hash": "QmQNd6ubRXaNG6Prov8o6vk3bn6eWsj9FxLGrAVDUAGkGe",
"Size": 128,
"Type": "File"
},
{
"Name": "a",
"Hash": "QmZULkCELmmk5XNfCgTnCyFgAVxBRBXyDHGGMVoLFLiXEN",
"Size": 6,
"Type": "File"
}
]
},
"QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd": {
"Hash": "QmbQBUSRL9raZtNXfpTDeaxQapibJEG6qEY8WqAN22aUzd",
"Size": 1024,
"Type": "File",
"Links": null
}
}
}
EOF
printf %s "$(cat expected_json_ls_duplicates_file_trailing_newline)" >expected_json_ls_duplicates_file &&
test_cmp expected_json_ls_duplicates_file actual_json_ls_duplicates_file
'
}
# should work offline
test_ls_cmd
# should work online
test_launch_ipfs_daemon
test_ls_cmd
test_kill_ipfs_daemon
test_done
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment