github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/core/commands/refs.go (about) 1 package commands 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io" 8 "strings" 9 10 context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" 11 key "github.com/ipfs/go-ipfs/blocks/key" 12 cmds "github.com/ipfs/go-ipfs/commands" 13 "github.com/ipfs/go-ipfs/core" 14 dag "github.com/ipfs/go-ipfs/merkledag" 15 path "github.com/ipfs/go-ipfs/path" 16 u "github.com/ipfs/go-ipfs/util" 17 ) 18 19 // KeyList is a general type for outputting lists of keys 20 type KeyList struct { 21 Keys []key.Key 22 } 23 24 // KeyListTextMarshaler outputs a KeyList as plaintext, one key per line 25 func KeyListTextMarshaler(res cmds.Response) (io.Reader, error) { 26 output := res.Output().(*KeyList) 27 buf := new(bytes.Buffer) 28 for _, key := range output.Keys { 29 buf.WriteString(key.B58String() + "\n") 30 } 31 return buf, nil 32 } 33 34 var RefsCmd = &cmds.Command{ 35 Helptext: cmds.HelpText{ 36 Tagline: "Lists links (references) from an object", 37 ShortDescription: ` 38 Retrieves the object named by <ipfs-path> and displays the link 39 hashes it contains, with the following format: 40 41 <link base58 hash> 42 43 Note: list all refs recursively with -r. 44 `, 45 }, 46 Subcommands: map[string]*cmds.Command{ 47 "local": RefsLocalCmd, 48 }, 49 Arguments: []cmds.Argument{ 50 cmds.StringArg("ipfs-path", true, true, "Path to the object(s) to list refs from").EnableStdin(), 51 }, 52 Options: []cmds.Option{ 53 cmds.StringOption("format", "Emit edges with given format. tokens: <src> <dst> <linkname>"), 54 cmds.BoolOption("edges", "e", "Emit edge format: `<from> -> <to>`"), 55 cmds.BoolOption("unique", "u", "Omit duplicate refs from output"), 56 cmds.BoolOption("recursive", "r", "Recursively list links of child nodes"), 57 }, 58 Run: func(req cmds.Request, res cmds.Response) { 59 ctx := req.Context() 60 n, err := req.InvocContext().GetNode() 61 if err != nil { 62 res.SetError(err, cmds.ErrNormal) 63 return 64 } 65 66 unique, _, err := req.Option("unique").Bool() 67 if err != nil { 68 res.SetError(err, cmds.ErrNormal) 69 return 70 } 71 72 recursive, _, err := req.Option("recursive").Bool() 73 if err != nil { 74 res.SetError(err, cmds.ErrNormal) 75 return 76 } 77 78 edges, _, err := req.Option("edges").Bool() 79 if err != nil { 80 res.SetError(err, cmds.ErrNormal) 81 return 82 } 83 84 format, _, err := req.Option("format").String() 85 if err != nil { 86 res.SetError(err, cmds.ErrNormal) 87 return 88 } 89 90 objs, err := objectsForPaths(ctx, n, req.Arguments()) 91 if err != nil { 92 res.SetError(err, cmds.ErrNormal) 93 return 94 } 95 96 out := make(chan interface{}) 97 res.SetOutput((<-chan interface{})(out)) 98 99 go func() { 100 defer close(out) 101 102 rw := RefWriter{ 103 out: out, 104 DAG: n.DAG, 105 Ctx: ctx, 106 Unique: unique, 107 PrintEdge: edges, 108 PrintFmt: format, 109 Recursive: recursive, 110 } 111 112 for _, o := range objs { 113 if _, err := rw.WriteRefs(o); err != nil { 114 out <- &RefWrapper{Err: err.Error()} 115 return 116 } 117 } 118 }() 119 }, 120 Marshalers: cmds.MarshalerMap{ 121 cmds.Text: func(res cmds.Response) (io.Reader, error) { 122 outChan, ok := res.Output().(<-chan interface{}) 123 if !ok { 124 return nil, u.ErrCast() 125 } 126 127 marshal := func(v interface{}) (io.Reader, error) { 128 obj, ok := v.(*RefWrapper) 129 if !ok { 130 fmt.Println("%#v", v) 131 return nil, u.ErrCast() 132 } 133 134 if obj.Err != "" { 135 return nil, errors.New(obj.Err) 136 } 137 138 return strings.NewReader(obj.Ref + "\n"), nil 139 } 140 141 return &cmds.ChannelMarshaler{ 142 Channel: outChan, 143 Marshaler: marshal, 144 Res: res, 145 }, nil 146 }, 147 }, 148 Type: RefWrapper{}, 149 } 150 151 var RefsLocalCmd = &cmds.Command{ 152 Helptext: cmds.HelpText{ 153 Tagline: "Lists all local references", 154 ShortDescription: ` 155 Displays the hashes of all local objects. 156 `, 157 }, 158 159 Run: func(req cmds.Request, res cmds.Response) { 160 ctx := req.Context() 161 n, err := req.InvocContext().GetNode() 162 if err != nil { 163 res.SetError(err, cmds.ErrNormal) 164 return 165 } 166 167 // todo: make async 168 allKeys, err := n.Blockstore.AllKeysChan(ctx) 169 if err != nil { 170 res.SetError(err, cmds.ErrNormal) 171 return 172 } 173 174 piper, pipew := io.Pipe() 175 176 go func() { 177 defer pipew.Close() 178 179 for k := range allKeys { 180 s := k.Pretty() + "\n" 181 if _, err := pipew.Write([]byte(s)); err != nil { 182 log.Error("pipe write error: ", err) 183 return 184 } 185 } 186 }() 187 188 res.SetOutput(piper) 189 }, 190 } 191 192 func objectsForPaths(ctx context.Context, n *core.IpfsNode, paths []string) ([]*dag.Node, error) { 193 objects := make([]*dag.Node, len(paths)) 194 for i, p := range paths { 195 o, err := core.Resolve(ctx, n, path.Path(p)) 196 if err != nil { 197 return nil, err 198 } 199 objects[i] = o 200 } 201 return objects, nil 202 } 203 204 type RefWrapper struct { 205 Ref string 206 Err string 207 } 208 209 type RefWriter struct { 210 out chan interface{} 211 DAG dag.DAGService 212 Ctx context.Context 213 214 Unique bool 215 Recursive bool 216 PrintEdge bool 217 PrintFmt string 218 219 seen map[key.Key]struct{} 220 } 221 222 // WriteRefs writes refs of the given object to the underlying writer. 223 func (rw *RefWriter) WriteRefs(n *dag.Node) (int, error) { 224 if rw.Recursive { 225 return rw.writeRefsRecursive(n) 226 } 227 return rw.writeRefsSingle(n) 228 } 229 230 func (rw *RefWriter) writeRefsRecursive(n *dag.Node) (int, error) { 231 nkey, err := n.Key() 232 if err != nil { 233 return 0, err 234 } 235 236 var count int 237 for i, ng := range rw.DAG.GetDAG(rw.Ctx, n) { 238 lk := key.Key(n.Links[i].Hash) 239 if rw.skip(lk) { 240 continue 241 } 242 243 if err := rw.WriteEdge(nkey, lk, n.Links[i].Name); err != nil { 244 return count, err 245 } 246 247 nd, err := ng.Get(rw.Ctx) 248 if err != nil { 249 return count, err 250 } 251 252 c, err := rw.writeRefsRecursive(nd) 253 count += c 254 if err != nil { 255 return count, err 256 } 257 } 258 return count, nil 259 } 260 261 func (rw *RefWriter) writeRefsSingle(n *dag.Node) (int, error) { 262 nkey, err := n.Key() 263 if err != nil { 264 return 0, err 265 } 266 267 if rw.skip(nkey) { 268 return 0, nil 269 } 270 271 count := 0 272 for _, l := range n.Links { 273 lk := key.Key(l.Hash) 274 275 if rw.skip(lk) { 276 continue 277 } 278 279 if err := rw.WriteEdge(nkey, lk, l.Name); err != nil { 280 return count, err 281 } 282 count++ 283 } 284 return count, nil 285 } 286 287 // skip returns whether to skip a key 288 func (rw *RefWriter) skip(k key.Key) bool { 289 if !rw.Unique { 290 return false 291 } 292 293 if rw.seen == nil { 294 rw.seen = make(map[key.Key]struct{}) 295 } 296 297 _, found := rw.seen[k] 298 if !found { 299 rw.seen[k] = struct{}{} 300 } 301 return found 302 } 303 304 // Write one edge 305 func (rw *RefWriter) WriteEdge(from, to key.Key, linkname string) error { 306 if rw.Ctx != nil { 307 select { 308 case <-rw.Ctx.Done(): // just in case. 309 return rw.Ctx.Err() 310 default: 311 } 312 } 313 314 var s string 315 switch { 316 case rw.PrintFmt != "": 317 s = rw.PrintFmt 318 s = strings.Replace(s, "<src>", from.Pretty(), -1) 319 s = strings.Replace(s, "<dst>", to.Pretty(), -1) 320 s = strings.Replace(s, "<linkname>", linkname, -1) 321 case rw.PrintEdge: 322 s = from.Pretty() + " -> " + to.Pretty() 323 default: 324 s += to.Pretty() 325 } 326 327 rw.out <- &RefWrapper{Ref: s} 328 return nil 329 }