Merge pull request #213 from jbenet/tour

ipfs tour
This commit is contained in:
Juan Batiz-Benet 2014-10-27 11:46:58 -07:00
commit 0197fe6046
7 changed files with 273 additions and 18 deletions

View File

@ -187,21 +187,6 @@ func bootstrapListCmd(c *commander.Command, inp []string) error {
return nil
}
func writeConfig(c *commander.Command, cfg *config.Config) error {
confdir, err := getConfigDir(c)
if err != nil {
return err
}
filename, err := config.Filename(confdir)
if err != nil {
return err
}
return config.WriteConfigFile(filename, cfg)
}
func bootstrapInputToPeers(input []string) ([]*config.BootstrapPeer, error) {
split := func(addr string) (string, string) {
idx := strings.LastIndex(addr, "/")

View File

@ -3,13 +3,14 @@ package main
import (
"errors"
"fmt"
"io"
"os"
"os/exec"
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag"
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander"
config "github.com/jbenet/go-ipfs/config"
u "github.com/jbenet/go-ipfs/util"
"io"
"os"
"os/exec"
)
var cmdIpfsConfig = &commander.Command{
@ -125,3 +126,18 @@ func configEditor(filename string) error {
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
return cmd.Run()
}
func writeConfig(c *commander.Command, cfg *config.Config) error {
confdir, err := getConfigDir(c)
if err != nil {
return err
}
filename, err := config.Filename(confdir)
if err != nil {
return err
}
return config.WriteConfigFile(filename, cfg)
}

View File

@ -73,6 +73,7 @@ Use "ipfs help <command>" for more information about a command.
cmdIpfsUpdate,
cmdIpfsLog,
cmdIpfsPin,
cmdIpfsTour,
},
Flag: *flag.NewFlagSet("ipfs", flag.ExitOnError),
}

134
cmd/ipfs/tour.go Normal file
View File

@ -0,0 +1,134 @@
// +build linux darwin freebsd
package main
import (
"fmt"
config "github.com/jbenet/go-ipfs/config"
tour "github.com/jbenet/go-ipfs/tour"
commander "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander"
)
var cmdIpfsTour = &commander.Command{
UsageLine: "tour [<number>]",
Short: "Take the IPFS Tour.",
Long: `ipfs tour - Take the IPFS Tour.
ipfs tour [<number>] - Show tour topic. Default to current.
ipfs tour next - Show the next tour topic.
ipfs tour list - Show a list of topics.
ipfs tour restart - Restart the tour.
This is a tour that takes you through various IPFS concepts,
features, and tools to make sure you get up to speed with
IPFS very quickly. To start, run:
ipfs tour
`,
Run: tourCmd,
Subcommands: []*commander.Command{
cmdIpfsTourNext,
cmdIpfsTourList,
cmdIpfsTourRestart,
},
}
var cmdIpfsTourNext = &commander.Command{
UsageLine: "next",
Short: "Show the next IPFS Tour topic.",
Run: tourNextCmd,
}
var cmdIpfsTourList = &commander.Command{
UsageLine: "list",
Short: "Show a list of IPFS Tour topics.",
Run: tourListCmd,
}
var cmdIpfsTourRestart = &commander.Command{
UsageLine: "restart",
Short: "Restart the IPFS Tour.",
Run: tourRestartCmd,
}
func tourCmd(c *commander.Command, inp []string) error {
cfg, err := getConfig(c)
if err != nil {
return err
}
topic := tour.TopicID(cfg.Tour.Last)
if len(inp) > 0 {
topic = tour.TopicID(inp[0])
}
return tourShow(topic)
}
func tourNextCmd(c *commander.Command, _ []string) error {
cfg, err := getConfig(c)
if err != nil {
return err
}
topic := tour.NextTopic(tour.TopicID(cfg.Tour.Last))
if err := tourShow(topic); err != nil {
return err
}
// if topic didn't change (last) done
if string(topic) == cfg.Tour.Last {
return nil
}
// topic changed, not last. write it out.
cfg.Tour.Last = string(topic)
return writeConfig(c, cfg)
}
func tourListCmd(c *commander.Command, _ []string) error {
cfg, err := getConfig(c)
if err != nil {
return err
}
lastid := tour.TopicID(cfg.Tour.Last)
for _, id := range tour.IDs {
c := ' '
switch {
case id == lastid:
c = '*'
case id.LessThan(lastid):
c = '✓'
}
t := tour.Topics[id]
fmt.Printf("- %c %-5.5s %s\n", c, id, t.Title)
}
return nil
}
func tourRestartCmd(c *commander.Command, _ []string) error {
cfg, err := getConfig(c)
if err != nil {
return err
}
cfg.Tour.Last = ""
return writeConfig(c, cfg)
}
func tourShow(id tour.ID) error {
t, found := tour.Topics[id]
if !found {
return fmt.Errorf("no topic with id: %s", id)
}
fmt.Printf("Tour %s - %s\n\n%s\n", t.ID, t.Title, t.Text)
return nil
}
func lastTour(cfg *config.Config) string {
return ""
}

View File

@ -47,6 +47,12 @@ func (bp *BootstrapPeer) String() string {
return bp.Address + "/" + bp.PeerID
}
// Tour stores the ipfs tour read-list and resume point
type Tour struct {
Last string // last tour topic read
// Done []string // all topics done so far
}
// Config is used to load IPFS config files.
type Config struct {
Identity Identity // local node's peer identity
@ -55,6 +61,7 @@ type Config struct {
Mounts Mounts // local node's mount points
Version Version // local node's version management
Bootstrap []*BootstrapPeer // local nodes's bootstrap peers
Tour Tour // local node's tour position
}
// DefaultPathRoot is the path to the default config dir location.

26
tour/all.go Normal file
View File

@ -0,0 +1,26 @@
package tour
import "sort"
func init() {
for _, t := range allTopics {
Topics[t.ID] = t
IDs = append(IDs, t.ID)
}
sort.Sort(IDSlice(IDs))
}
// Topics contains a mapping of Tour Topic ID to Topic
var allTopics = []Topic{
Topic{
ID: ID("0"),
Title: "Hello Mars",
Text: "Hello Mars",
},
Topic{
ID: ID("0.1"),
Title: "Hello Mars 2",
Text: "Hello Mars 2",
},
}

86
tour/tour.go Normal file
View File

@ -0,0 +1,86 @@
package tour
import (
"strconv"
"strings"
u "github.com/jbenet/go-ipfs/util"
)
var log = u.Logger("tour")
// ID is a string identifier for topics
type ID string
// LessThan returns whether this ID is sorted earlier than another.
func (i ID) LessThan(o ID) bool {
return compareDottedInts(string(i), string(o))
}
// IDSlice implements the sort interface for ID slices.
type IDSlice []ID
func (a IDSlice) Len() int { return len(a) }
func (a IDSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a IDSlice) Less(i, j int) bool { return a[i].LessThan(a[j]) }
// Topic is a type of objects that structures a tour topic.
type Topic struct {
ID ID
Title string
Text string
}
// Topics is a sorted list of topic IDs
var IDs []ID
// Topics contains a mapping of Tour Topic ID to Topic
var Topics = map[ID]Topic{}
// NextTopic returns the next in-order topic
func NextTopic(topic ID) ID {
for _, id := range IDs {
if topic.LessThan(id) {
return id
}
}
return topic // last one, it seems.
}
// TopicID returns a valid tour topic ID from given string
func TopicID(t string) ID {
if t == "" { // if empty, use first ID
return IDs[0]
}
return ID(t)
}
func compareDottedInts(i, o string) bool {
is := strings.Split(i, ".")
os := strings.Split(o, ".")
for n, vis := range is {
if n >= len(os) {
return false // os is smaller.
}
vos := os[n]
ivis, err1 := strconv.Atoi(vis)
ivos, err2 := strconv.Atoi(vos)
if err1 != nil || err2 != nil {
log.Error(err1)
log.Error(err2)
panic("tour ID LessThan: not an int")
}
if ivis < ivos {
return true
}
if ivis > ivos {
return false
}
}
return len(os) > len(is)
}