Skip to content

Commit

Permalink
Add "ipfs block rm" command.
Browse files Browse the repository at this point in the history
License: MIT
Signed-off-by: Kevin Atkinson <k@kevina.org>
  • Loading branch information
kevina committed Jul 10, 2016
1 parent 4e67003 commit 36a6f93
Show file tree
Hide file tree
Showing 2 changed files with 167 additions and 1 deletion.
99 changes: 99 additions & 0 deletions core/commands/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import (
"strings"

"github.com/ipfs/go-ipfs/blocks"
bs "github.com/ipfs/go-ipfs/blocks/blockstore"
key "github.com/ipfs/go-ipfs/blocks/key"
cmds "github.com/ipfs/go-ipfs/commands"
"github.com/ipfs/go-ipfs/pin"
mh "gx/ipfs/QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku/go-multihash"
u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
)
Expand Down Expand Up @@ -38,6 +40,7 @@ multihash.
"stat": blockStatCmd,
"get": blockGetCmd,
"put": blockPutCmd,
"rm": blockRmCmd,
},
}

Expand Down Expand Up @@ -185,3 +188,99 @@ func getBlockForKey(req cmds.Request, skey string) (blocks.Block, error) {
log.Debugf("ipfs block: got block with key: %q", b.Key())
return b, nil
}

var blockRmCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Remove IPFS block(s).",
ShortDescription: `
'ipfs block put' is a plumbing command for removing raw ipfs blocks.
It takes a list of base58 encoded multihashs to remove.
`,
},
Arguments: []cmds.Argument{
cmds.StringArg("hash", true, true, "Bash58 encoded multihash of block(s) to remove."),
},
Options: []cmds.Option{
cmds.BoolOption("ignore-pins", "Ignore pins.").Default(false),
},
Run: func(req cmds.Request, res cmds.Response) {
ignorePins, _, err := req.Option("ignore-pins").Bool()
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
n, err := req.InvocContext().GetNode()
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
hashes := req.Arguments()
keys := make([]key.Key, 0, len(hashes))
for _, hash := range hashes {
k := key.B58KeyDecode(hash)
keys = append(keys, k)
}
rdr, wtr := io.Pipe()
go func() {
pinning := n.Pinning
if ignorePins {
pinning = nil
}
err := rmBlocks(n.Blockstore, pinning, wtr, keys)
if err != nil {
wtr.CloseWithError(fmt.Errorf("Some blocks not deleted: %s", err))
} else {
wtr.Close()
}
}()
res.SetOutput(rdr)
return
},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {
return res.(io.Reader), nil
},
},
}

type noopLocker struct{}

func (noopLocker) Unlock() {}

// pins may be nil
func rmBlocks(blocks bs.GCBlockstore, pins pin.Pinner, out io.Writer, keys []key.Key) error {
var unlocker bs.Unlocker = noopLocker{}
defer unlocker.Unlock()
if pins != nil {
// Need to make sure that some operation that is
// finishing with a pin is ocurr simultaneously.
unlocker = blocks.GCLock()
err := checkIfPinned(pins, keys)
if err != nil {
return err
}
}
for _, k := range keys {
err := blocks.DeleteBlock(k)
if err != nil {
return fmt.Errorf("%s: %s", k, err)
}
if out != nil {
fmt.Fprintf(out, "deleted %s\n", k)
}
}
return nil
}

func checkIfPinned(pins pin.Pinner, keys []key.Key) error {
for _, k := range keys {
reason, pinned, err := pins.IsPinned(k)
if err != nil {
return err
}
if pinned {
return fmt.Errorf("%s pinned via %s", k, reason)
}
}
return nil
}
69 changes: 68 additions & 1 deletion test/sharness/t0050-block.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,77 @@ test_expect_success "'ipfs block stat' succeeds" '
ipfs block stat $HASH >actual_stat
'

test_expect_success "'ipfs block get' output looks good" '
test_expect_success "'ipfs block stat' output looks good" '
echo "Key: $HASH" >expected_stat &&
echo "Size: 12" >>expected_stat &&
test_cmp expected_stat actual_stat
'

test_expect_success "'ipfs block rm' succeeds" '
ipfs block rm $HASH >actual_rm
'

test_expect_success "'ipfs block rm' output looks good" '
echo "deleted $HASH" > expected_rm &&
test_cmp expected_rm actual_rm
'

test_expect_success "'ipfs block rm' block actually removed" '
test_must_fail ipfs block stat $HASH
'

DIRHASH=QmdWmVmM6W2abTgkEfpbtA1CJyTWS2rhuUB9uP1xV8Uwtf
FILE1HASH=Qmae3RedM7SNkWGsdzYzsr6svmsFdsva4WoTvYYsWhUSVz
FILE2HASH=QmUtkGLvPf63NwVzLPKPUYgwhn8ZYPWF6vKWN3fZ2amfJF
FILE3HASH=Qmesmmf1EEG1orJb6XdK6DabxexsseJnCfw8pqWgonbkoj

test_expect_success "add and pin directory" '
mkdir adir &&
echo "file1" > adir/file1 &&
echo "file2" > adir/file2 &&
echo "file3" > adir/file3 &&
ipfs add -r adir
ipfs pin add -r $DIRHASH
'

test_expect_success "can't remove pinned block" '
test_must_fail ipfs block rm $DIRHASH 2> block_rm_err
'

test_expect_success "can't remove pinned block: output looks good" '
grep -q "$DIRHASH pinned via recursive" block_rm_err
'

test_expect_success "can't remove indirectly pinned block" '
test_must_fail ipfs block rm $FILE1HASH 2> block_rm_err
'

test_expect_success "can't remove indirectly pinned block: output looks good" '
grep -q "$FILE1HASH pinned via $DIRHASH" block_rm_err
'

test_expect_success "multi-block 'ipfs block rm --ignore-pins' succeeds" '
ipfs block rm --ignore-pins $DIRHASH >actual_rm
'

test_expect_success "multi-block 'ipfs block rm --ignore-pins' output looks good" '
echo "deleted $DIRHASH" > expected_rm &&
test_cmp expected_rm actual_rm
'

test_expect_success "fix up pins" '
ipfs pin rm -r $DIRHASH
'

test_expect_success "multi-block 'ipfs block rm' succeeds" '
ipfs block rm $FILE1HASH $FILE2HASH $FILE3HASH > actual_rm
'

test_expect_success "multi-block 'ipfs block rm' output looks good" '
echo "deleted $FILE1HASH" > expected_rm &&
echo "deleted $FILE2HASH" >> expected_rm &&
echo "deleted $FILE3HASH" >> expected_rm &&
test_cmp expected_rm actual_rm
'

test_done

0 comments on commit 36a6f93

Please sign in to comment.