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 }