"block rm": use channel instead of pipe / don't abort on non-fatal error
License: MIT Signed-off-by: Kevin Atkinson <k@kevina.org>
Kevin Atkinson committed
Aug 10, 2016 at 16:53 UTC
6ad497bcf06a831c5017c05a817140a250d04d69
2 files changed
+60
-36
core/commands/block.go
+53
-29
@@ -220,67 +220,91 @@ It takes a list of base58 encoded multihashs to remove.
220
k := key.B58KeyDecode(hash)
221
keys = append(keys, k)
222
}
223
- rdr, wtr := io.Pipe()
223
+ outChan := make(chan interface{})
224
+ res.SetOutput((<-chan interface{})(outChan))
225
go func() {
226
+ defer close(outChan)
227
pinning := n.Pinning
228
if ignorePins {
229
pinning = nil
230
}
229
- err := rmBlocks(n.Blockstore, pinning, wtr, keys)
230
- if err != nil {
231
- wtr.CloseWithError(fmt.Errorf("Some blocks not deleted: %s", err))
232
- } else {
233
- wtr.Close()
234
- }
231
+ rmBlocks(n.Blockstore, pinning, outChan, keys)
232
}()
236
- res.SetOutput(rdr)
233
return
234
},
239
- Marshalers: cmds.MarshalerMap{
240
- cmds.Text: func(res cmds.Response) (io.Reader, error) {
241
- return res.(io.Reader), nil
242
- },
235
+ PostRun: func(req cmds.Request, res cmds.Response) {
236
+ if res.Error() != nil {
237
+ return
238
+ }
239
+ outChan, ok := res.Output().(<-chan interface{})
240
+ if !ok {
241
+ res.SetError(u.ErrCast(), cmds.ErrNormal)
242
+ return
243
+ }
244
+ res.SetOutput(nil)
245
+
246
+ someFailed := false
247
+ for out := range outChan {
248
+ o := out.(*RemovedBlock)
249
+ if o.Error != "" {
250
+ someFailed = true
251
+ fmt.Fprintf(res.Stderr(), "cannot remove %s: %s\n", o.Hash, o.Error)
252
+ } else {
253
+ fmt.Fprintf(res.Stdout(), "removed %s\n", o.Hash)
254
+ }
255
+ }
256
+ if someFailed {
257
+ res.SetError(fmt.Errorf("some blocks not removed"), cmds.ErrNormal)
258
+ }
259
},
260
+ Type: RemovedBlock{},
261
+}
262
+
263
+type RemovedBlock struct {
264
+ Hash string
265
+ Error string `json:",omitempty"`
266
}
267
268
// pins may be nil
247
-func rmBlocks(blocks bs.GCBlockstore, pins pin.Pinner, out io.Writer, keys []key.Key) error {
269
+func rmBlocks(blocks bs.GCBlockstore, pins pin.Pinner, out chan<- interface{}, keys []key.Key) {
270
var unlocker bs.Unlocker
271
defer func() {
272
if unlocker != nil {
273
unlocker.Unlock()
274
}
275
}()
276
+ stillOkay := keys
277
if pins != nil {
278
// Need to make sure that some operation that is
279
// finishing with a pin is ocurr simultaneously.
280
unlocker = blocks.GCLock()
258
- err := checkIfPinned(pins, keys)
259
- if err != nil {
260
- return err
261
- }
281
+ stillOkay = checkIfPinned(pins, keys, out)
282
}
263
- for _, k := range keys {
283
+ for _, k := range stillOkay {
284
err := blocks.DeleteBlock(k)
285
if err != nil {
266
- return fmt.Errorf("%s: %s", k, err)
267
- }
268
- if out != nil {
269
- fmt.Fprintf(out, "deleted %s\n", k)
286
+ out <- &RemovedBlock{ Hash: k.String(), Error: err.Error()}
287
+ } else {
288
+ out <- &RemovedBlock{ Hash: k.String() }
289
}
290
}
272
- return nil
291
}
292
275
-func checkIfPinned(pins pin.Pinner, keys []key.Key) error {
293
+func checkIfPinned(pins pin.Pinner, keys []key.Key, out chan<- interface{}) []key.Key {
294
+ stillOkay := make([]key.Key, 0, len(keys))
295
for _, k := range keys {
296
reason, pinned, err := pins.IsPinned(k)
297
if err != nil {
279
- return err
280
- }
281
- if pinned {
282
- return fmt.Errorf("%s pinned via %s", k, reason)
298
+ out <- &RemovedBlock {
299
+ Hash: k.String(),
300
+ Error: fmt.Sprintf("pin check failed %s", err.Error()) }
301
+ } else if pinned {
302
+ out <- &RemovedBlock {
303
+ Hash: k.String(),
304
+ Error: fmt.Sprintf("pinned via %s", reason) }
305
+ } else {
306
+ stillOkay = append(stillOkay, k)
307
}
308
}
285
- return nil
309
+ return stillOkay
310
}
test/sharness/t0050-block.sh
+7
-7
@@ -44,7 +44,7 @@ test_expect_success "'ipfs block rm' succeeds" '
44
'
45
46
test_expect_success "'ipfs block rm' output looks good" '
47
- echo "deleted $HASH" > expected_rm &&
47
+ echo "removed $HASH" > expected_rm &&
48
test_cmp expected_rm actual_rm
49
'
50
@@ -71,7 +71,7 @@ test_expect_success "can't remove pinned block" '
71
'
72
73
test_expect_success "can't remove pinned block: output looks good" '
74
- grep -q "$DIRHASH pinned via recursive" block_rm_err
74
+ grep -q "$DIRHASH: pinned via recursive" block_rm_err
75
'
76
77
test_expect_success "can't remove indirectly pinned block" '
@@ -79,7 +79,7 @@ test_expect_success "can't remove indirectly pinned block" '
79
'
80
81
test_expect_success "can't remove indirectly pinned block: output looks good" '
82
- grep -q "$FILE1HASH pinned via $DIRHASH" block_rm_err
82
+ grep -q "$FILE1HASH: pinned via $DIRHASH" block_rm_err
83
'
84
85
test_expect_success "multi-block 'ipfs block rm --ignore-pins' succeeds" '
@@ -87,7 +87,7 @@ test_expect_success "multi-block 'ipfs block rm --ignore-pins' succeeds" '
87
'
88
89
test_expect_success "multi-block 'ipfs block rm --ignore-pins' output looks good" '
90
- echo "deleted $DIRHASH" > expected_rm &&
90
+ echo "removed $DIRHASH" > expected_rm &&
91
test_cmp expected_rm actual_rm
92
'
93
@@ -100,9 +100,9 @@ test_expect_success "multi-block 'ipfs block rm' succeeds" '
100
'
101
102
test_expect_success "multi-block 'ipfs block rm' output looks good" '
103
- echo "deleted $FILE1HASH" > expected_rm &&
104
- echo "deleted $FILE2HASH" >> expected_rm &&
105
- echo "deleted $FILE3HASH" >> expected_rm &&
103
+ echo "removed $FILE1HASH" > expected_rm &&
104
+ echo "removed $FILE2HASH" >> expected_rm &&
105
+ echo "removed $FILE3HASH" >> expected_rm &&
106
test_cmp expected_rm actual_rm
107
'
108