Skip to content

Commit

Permalink
Merge pull request #213 from jbenet/tour
Browse files Browse the repository at this point in the history
ipfs tour
  • Loading branch information
jbenet committed Oct 27, 2014
2 parents b4ea414 + 0ee4b3e commit 0197fe6
Show file tree
Hide file tree
Showing 7 changed files with 273 additions and 18 deletions.
15 changes: 0 additions & 15 deletions cmd/ipfs/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -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, "/")
Expand Down
22 changes: 19 additions & 3 deletions cmd/ipfs/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down Expand Up @@ -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)
}
1 change: 1 addition & 0 deletions cmd/ipfs/ipfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ Use "ipfs help <command>" for more information about a command.
cmdIpfsUpdate,
cmdIpfsLog,
cmdIpfsPin,
cmdIpfsTour,
},
Flag: *flag.NewFlagSet("ipfs", flag.ExitOnError),
}
Expand Down
134 changes: 134 additions & 0 deletions cmd/ipfs/tour.go
Original file line number Diff line number Diff line change
@@ -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 ""
}
7 changes: 7 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down
26 changes: 26 additions & 0 deletions tour/all.go
Original file line number Diff line number Diff line change
@@ -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 changes: 86 additions & 0 deletions tour/tour.go
Original file line number Diff line number Diff line change
@@ -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)
}

0 comments on commit 0197fe6

Please sign in to comment.