github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/core/commands/tour.go (about)

     1  package commands
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"html/template"
     7  	"io"
     8  
     9  	cmds "github.com/ipfs/go-ipfs/commands"
    10  	config "github.com/ipfs/go-ipfs/repo/config"
    11  	fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
    12  	tour "github.com/ipfs/go-ipfs/tour"
    13  )
    14  
    15  var tourCmd = &cmds.Command{
    16  	Helptext: cmds.HelpText{
    17  		Tagline: "An introduction to IPFS",
    18  		ShortDescription: `
    19  This is a tour that takes you through various IPFS concepts,
    20  features, and tools to make sure you get up to speed with
    21  IPFS very quickly. To start, run:
    22  
    23      ipfs tour
    24  `,
    25  	},
    26  
    27  	Arguments: []cmds.Argument{
    28  		cmds.StringArg("id", false, false, "The id of the topic you would like to tour"),
    29  	},
    30  	Subcommands: map[string]*cmds.Command{
    31  		"list":    cmdIpfsTourList,
    32  		"next":    cmdIpfsTourNext,
    33  		"restart": cmdIpfsTourRestart,
    34  	},
    35  	Run: tourRunFunc,
    36  }
    37  
    38  func tourRunFunc(req cmds.Request, res cmds.Response) {
    39  
    40  	cfg, err := req.InvocContext().GetConfig()
    41  	if err != nil {
    42  		res.SetError(err, cmds.ErrNormal)
    43  		return
    44  	}
    45  
    46  	id := tour.TopicID(cfg.Tour.Last)
    47  	if len(req.Arguments()) > 0 {
    48  		id = tour.TopicID(req.Arguments()[0])
    49  	}
    50  
    51  	w := new(bytes.Buffer)
    52  	t, err := tourGet(id)
    53  	if err != nil {
    54  
    55  		// If no topic exists for this id, we handle this error right here.
    56  		// To help the user achieve the task, we construct a response
    57  		// comprised of...
    58  		// 1) a simple error message
    59  		// 2) the full list of topics
    60  
    61  		fmt.Fprintln(w, "ERROR")
    62  		fmt.Fprintln(w, err)
    63  		fmt.Fprintln(w, "")
    64  		fprintTourList(w, tour.TopicID(cfg.Tour.Last))
    65  		res.SetOutput(w)
    66  
    67  		return
    68  	}
    69  
    70  	fprintTourShow(w, t)
    71  	res.SetOutput(w)
    72  }
    73  
    74  var cmdIpfsTourNext = &cmds.Command{
    75  	Helptext: cmds.HelpText{
    76  		Tagline: "Show the next IPFS Tour topic",
    77  	},
    78  
    79  	Run: func(req cmds.Request, res cmds.Response) {
    80  		w := new(bytes.Buffer)
    81  		path := req.InvocContext().ConfigRoot
    82  		cfg, err := req.InvocContext().GetConfig()
    83  		if err != nil {
    84  			res.SetError(err, cmds.ErrNormal)
    85  			return
    86  		}
    87  
    88  		id := tour.NextTopic(tour.TopicID(cfg.Tour.Last))
    89  		topic, err := tourGet(id)
    90  		if err != nil {
    91  			res.SetError(err, cmds.ErrNormal)
    92  			return
    93  		}
    94  		if err := fprintTourShow(w, topic); err != nil {
    95  			res.SetError(err, cmds.ErrNormal)
    96  			return
    97  		}
    98  
    99  		// topic changed, not last. write it out.
   100  		if string(id) != cfg.Tour.Last {
   101  			cfg.Tour.Last = string(id)
   102  			err := writeConfig(path, cfg)
   103  			if err != nil {
   104  				res.SetError(err, cmds.ErrNormal)
   105  				return
   106  			}
   107  		}
   108  
   109  		res.SetOutput(w)
   110  	},
   111  }
   112  
   113  var cmdIpfsTourRestart = &cmds.Command{
   114  	Helptext: cmds.HelpText{
   115  		Tagline: "Restart the IPFS Tour",
   116  	},
   117  
   118  	Run: func(req cmds.Request, res cmds.Response) {
   119  		path := req.InvocContext().ConfigRoot
   120  		cfg, err := req.InvocContext().GetConfig()
   121  		if err != nil {
   122  			res.SetError(err, cmds.ErrNormal)
   123  			return
   124  		}
   125  
   126  		cfg.Tour.Last = ""
   127  		err = writeConfig(path, cfg)
   128  		if err != nil {
   129  			res.SetError(err, cmds.ErrNormal)
   130  			return
   131  		}
   132  	},
   133  }
   134  
   135  var cmdIpfsTourList = &cmds.Command{
   136  	Helptext: cmds.HelpText{
   137  		Tagline: "Show a list of IPFS Tour topics",
   138  	},
   139  
   140  	Run: func(req cmds.Request, res cmds.Response) {
   141  		cfg, err := req.InvocContext().GetConfig()
   142  		if err != nil {
   143  			res.SetError(err, cmds.ErrNormal)
   144  			return
   145  		}
   146  
   147  		w := new(bytes.Buffer)
   148  		fprintTourList(w, tour.TopicID(cfg.Tour.Last))
   149  		res.SetOutput(w)
   150  	},
   151  }
   152  
   153  func fprintTourList(w io.Writer, lastid tour.ID) {
   154  	for _, id := range tour.IDs {
   155  		c := ' '
   156  		switch {
   157  		case id == lastid:
   158  			c = '*'
   159  		case id.LessThan(lastid):
   160  			c = '✓'
   161  		}
   162  
   163  		t := tour.Topics[id]
   164  		fmt.Fprintf(w, "- %c %-5.5s %s\n", c, id, t.Title)
   165  	}
   166  }
   167  
   168  // fprintTourShow writes a text-formatted topic to the writer
   169  func fprintTourShow(w io.Writer, t *tour.Topic) error {
   170  	tmpl := `
   171  Tour {{ .ID }} - {{ .Title }}
   172  
   173  {{ .Text }}
   174  
   175  `
   176  	ttempl, err := template.New("tour").Parse(tmpl)
   177  	if err != nil {
   178  		return err
   179  	}
   180  	return ttempl.Execute(w, t)
   181  }
   182  
   183  // tourGet returns the topic given its ID. Returns an error if topic does not
   184  // exist.
   185  func tourGet(id tour.ID) (*tour.Topic, error) {
   186  	t, found := tour.Topics[id]
   187  	if !found {
   188  		return nil, fmt.Errorf("no topic with id: %s", id)
   189  	}
   190  	return &t, nil
   191  }
   192  
   193  // TODO share func
   194  func writeConfig(path string, cfg *config.Config) error {
   195  	// NB: This needs to run on the daemon.
   196  	r, err := fsrepo.Open(path)
   197  	if err != nil {
   198  		return err
   199  	}
   200  	defer r.Close()
   201  	return r.SetConfig(cfg)
   202  }