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  }