1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-07-01 19:24:14 +08:00

Merge pull request #4123 from sherodtaylor/feature/tour/remove-tour

remove tour command from ipfs
This commit is contained in:
Jeromy Johnson
2017-08-15 17:06:36 -07:00
committed by GitHub
20 changed files with 43 additions and 732 deletions

View File

@ -1,4 +1,4 @@
//go:generate go-bindata -pkg=assets -prefix=$GOPATH/src/gx/ipfs/QmQfeKxQtBN721pekQh6Jq24adFUjnU65YdY3GNczfuG2T init-doc $GOPATH/src/gx/ipfs/QmQfeKxQtBN721pekQh6Jq24adFUjnU65YdY3GNczfuG2T/dir-index-html
//go:generate go-bindata -pkg=assets -prefix=$GOPATH/src/gx/ipfs/QmdZ4PvPHFQVLLEve7DgoKDcSY19wwpGBB1GKjjKi2rEL1 init-doc $GOPATH/src/gx/ipfs/QmdZ4PvPHFQVLLEve7DgoKDcSY19wwpGBB1GKjjKi2rEL1/dir-index-html
//go:generate gofmt -w bindata.go
package assets
@ -34,7 +34,7 @@ func SeedInitDocs(nd *core.IpfsNode) (*cid.Cid, error) {
return addAssetList(nd, initDocPaths)
}
var initDirPath = filepath.Join(os.Getenv("GOPATH"), "gx", "ipfs", "QmQfeKxQtBN721pekQh6Jq24adFUjnU65YdY3GNczfuG2T", "dir-index-html")
var initDirPath = filepath.Join(os.Getenv("GOPATH"), "gx", "ipfs", "QmdZ4PvPHFQVLLEve7DgoKDcSY19wwpGBB1GKjjKi2rEL1", "dir-index-html")
var initDirIndex = []string{
filepath.Join(initDirPath, "knownIcons.txt"),
filepath.Join(initDirPath, "dir-index.html"),

View File

@ -9,7 +9,7 @@ import (
// TestEmbeddedDocs makes sure we don't forget to regenerate after documentation change
func TestEmbeddedDocs(t *testing.T) {
testNFiles(initDocPaths, 6, t, "documents")
testNFiles(initDocPaths, 5, t, "documents")
}
func TestDirIndex(t *testing.T) {

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
# 0.1 - Quick Start
This is a set of short examples with minimal explanation. It is meant as
a "quick start". Soon, we'll write a longer tour :-)
a "quick start".
Add a file to ipfs:

View File

@ -1,34 +0,0 @@
WIP
# 0.0 - Introduction
Welcome to IPFS! This tour will guide you through a few of the
features of this tool, and the most common commands. Then, it will
immerse you into the world of merkledags and the amazing things
you can do with them.
This tour has many parts, and can be taken in different sequences.
Different people learn different ways, so choose your own adventure:
To start with the concepts, try:
- The Merkle DAG
- Data Structures on the Merkle DAG
- Representing Files with unixfs
- add, cat, ls, refs
...
To start with the examples, try:
- add, cat, ls, refs
- Representing Files with unixfs
- Data Structures on the Merkle DAG
- The Merkle DAG
...
To start with the network, try:
- IPFS Nodes
- Running the daemon
- The Swarm
- The Web

View File

@ -122,7 +122,6 @@ var rootSubcommands = map[string]*cmds.Command{
"stats": StatsCmd,
"swarm": SwarmCmd,
"tar": TarCmd,
"tour": tourCmd,
"file": unixfs.UnixFSCmd,
"update": ExternalBinary(),
"version": VersionCmd,

View File

@ -1,202 +0,0 @@
package commands
import (
"bytes"
"fmt"
"html/template"
"io"
cmds "github.com/ipfs/go-ipfs/commands"
config "github.com/ipfs/go-ipfs/repo/config"
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
tour "github.com/ipfs/go-ipfs/tour"
)
var tourCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Provide an introduction to IPFS.",
ShortDescription: `
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
`,
},
Arguments: []cmds.Argument{
cmds.StringArg("id", false, false, "The id of the topic you would like to tour."),
},
Subcommands: map[string]*cmds.Command{
"list": cmdIpfsTourList,
"next": cmdIpfsTourNext,
"restart": cmdIpfsTourRestart,
},
Run: tourRunFunc,
}
func tourRunFunc(req cmds.Request, res cmds.Response) {
cfg, err := req.InvocContext().GetConfig()
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
id := tour.TopicID(cfg.Tour.Last)
if len(req.Arguments()) > 0 {
id = tour.TopicID(req.Arguments()[0])
}
w := new(bytes.Buffer)
t, err := tourGet(id)
if err != nil {
// If no topic exists for this id, we handle this error right here.
// To help the user achieve the task, we construct a response
// comprised of...
// 1) a simple error message
// 2) the full list of topics
fmt.Fprintln(w, "ERROR")
fmt.Fprintln(w, err)
fmt.Fprintln(w, "")
fprintTourList(w, tour.TopicID(cfg.Tour.Last))
res.SetOutput(w)
return
}
fprintTourShow(w, t)
res.SetOutput(w)
}
var cmdIpfsTourNext = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Show the next IPFS Tour topic.",
},
Run: func(req cmds.Request, res cmds.Response) {
w := new(bytes.Buffer)
path := req.InvocContext().ConfigRoot
cfg, err := req.InvocContext().GetConfig()
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
id := tour.NextTopic(tour.TopicID(cfg.Tour.Last))
topic, err := tourGet(id)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
if err := fprintTourShow(w, topic); err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
// topic changed, not last. write it out.
if string(id) != cfg.Tour.Last {
cfg.Tour.Last = string(id)
err := writeConfig(path, cfg)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
}
res.SetOutput(w)
},
}
var cmdIpfsTourRestart = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Restart the IPFS Tour.",
},
Run: func(req cmds.Request, res cmds.Response) {
path := req.InvocContext().ConfigRoot
cfg, err := req.InvocContext().GetConfig()
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
cfg.Tour.Last = ""
err = writeConfig(path, cfg)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
},
}
var cmdIpfsTourList = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Show a list of IPFS Tour topics.",
},
Run: func(req cmds.Request, res cmds.Response) {
cfg, err := req.InvocContext().GetConfig()
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
w := new(bytes.Buffer)
fprintTourList(w, tour.TopicID(cfg.Tour.Last))
res.SetOutput(w)
},
}
func fprintTourList(w io.Writer, lastid tour.ID) {
for _, id := range tour.IDs {
c := ' '
switch {
case id == lastid:
c = '*'
case id.LessThan(lastid):
c = '✓'
}
t := tour.Topics[id]
fmt.Fprintf(w, "- %c %-5.5s %s\n", c, id, t.Title)
}
}
// fprintTourShow writes a text-formatted topic to the writer
func fprintTourShow(w io.Writer, t *tour.Topic) error {
tmpl := `
Tour {{ .ID }} - {{ .Title }}
{{ .Text }}
`
ttempl, err := template.New("tour").Parse(tmpl)
if err != nil {
return err
}
return ttempl.Execute(w, t)
}
// tourGet returns the topic given its ID. Returns an error if topic does not
// exist.
func tourGet(id tour.ID) (*tour.Topic, error) {
t, found := tour.Topics[id]
if !found {
return nil, fmt.Errorf("no topic with id: %s", id)
}
return &t, nil
}
// TODO share func
func writeConfig(path string, cfg *config.Config) error {
// NB: This needs to run on the daemon.
r, err := fsrepo.Open(path)
if err != nil {
return err
}
defer r.Close()
return r.SetConfig(cfg)
}

View File

@ -1,27 +0,0 @@
package commands
import (
"bytes"
"testing"
"github.com/ipfs/go-ipfs/tour"
)
func TestParseTourTemplate(t *testing.T) {
topic := &tour.Topic{
ID: "42",
Content: tour.Content{
Title: "ipfs CLI test files",
Text: `
Welcome to the ipfs test files
This is where we test our beautiful command line interfaces
`,
},
}
buf := new(bytes.Buffer)
err := fprintTourShow(buf, topic)
if err != nil {
t.Fatal(err)
}
t.Log(buf.String())
}

View File

@ -18,7 +18,6 @@ a running daemon do not read the config file at runtime.
- [`ReproviderInterval`](#reproviderinterval)
- [`SupernodeRouting`](#supernoderouting)
- [`Swarm`](#swarm)
- [`Tour`](#tour)
## `Addresses`
Contains information about various listener addresses to be used by this node.
@ -221,5 +220,3 @@ improvement, as well as a reduction in memory usage.
- `DisableNatPortMap`
Disable NAT discovery.
## `Tour`
Unused.

View File

@ -811,26 +811,6 @@ _ipfs_tar_cat()
fi
}
_ipfs_tour()
{
_ipfs_comp "list next restart --help"
}
_ipfs_tour_list()
{
_ipfs_help_only
}
_ipfs_tour_next()
{
_ipfs_help_only
}
_ipfs_tour_restart()
{
_ipfs_help_only
}
_ipfs_update()
{
if [[ ${word} == -* ]] ; then
@ -964,7 +944,7 @@ _ipfs()
1)
local opts="add bitswap block bootstrap cat commands config daemon dag dht \
diag dns file files get id init log ls mount name object pin ping pubsub \
refs repo resolve stats swarm tar tour update version"
refs repo resolve stats swarm tar update version"
COMPREPLY=( $(compgen -W "${opts}" -- ${word}) );;
2)
local command="${COMP_WORDS[1]}"

View File

@ -21,7 +21,6 @@ type Config struct {
Discovery Discovery // local node's discovery mechanisms
Ipns Ipns // Ipns settings
Bootstrap []string // local nodes's bootstrap peer addresses
Tour Tour // local node's tour position
Gateway Gateway // local node's gateway server options
SupernodeRouting SupernodeClientConfig // local node's routing servers (if SupernodeRouting enabled)
API API // local node's API settings

View File

@ -1,7 +0,0 @@
package config
// 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
}

View File

@ -25,8 +25,5 @@
"AutoUpdate": "minor"
},
"Bootstrap": [
],
"Tour": {
"Last": ""
}
]
}

View File

@ -19,9 +19,6 @@
"IPFS": "/ipfs",
"IPNS": "/ipns"
},
"Tour": {
"Last": ""
},
"Version": {
"AutoUpdate": "minor",
"Check": "error",

View File

@ -19,9 +19,6 @@
"IPFS": "/ipfs",
"IPNS": "/ipns"
},
"Tour": {
"Last": ""
},
"Version": {
"AutoUpdate": "minor",
"Check": "error",

View File

@ -1,5 +1,5 @@
# this file defines several useful hashes used across the test codebase.
# thus they can be defined + changed in one place
HASH_WELCOME_DOCS="QmVLDAhCY3X9P2uRudKAryuQFPM5zqA3Yij1dY8FpGbL7T"
HASH_WELCOME_DOCS="QmS4ustL54uo8FzR9455qaxZwuMiUhyvMcX9Ba8nUH4uVv"
HASH_EMPTY_DIR="QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"

View File

@ -140,7 +140,7 @@ test_expect_success "refs IPFS directory file through readonly API succeeds" '
'
test_expect_success "test gateway api is sanitized" '
for cmd in "add" "block/put" "bootstrap" "config" "dht" "diag" "dns" "get" "id" "mount" "name/publish" "object/put" "object/new" "object/patch" "pin" "ping" "refs/local" "repo" "resolve" "stats" "swarm" "tour" "file" "update" "version" "bitswap"; do
for cmd in "add" "block/put" "bootstrap" "config" "dht" "diag" "dns" "get" "id" "mount" "name/publish" "object/put" "object/new" "object/patch" "pin" "ping" "refs/local" "repo" "resolve" "stats" "swarm" "file" "update" "version" "bitswap"; do
test_curl_resp_http_code "http://127.0.0.1:$port/api/v0/$cmd" "HTTP/1.1 404 Not Found"
done
'

View File

@ -1,279 +0,0 @@
package tour
import "sort"
func init() {
for _, t := range allTopics {
Topics[t.ID] = t
IDs = append(IDs, t.ID)
}
sort.Sort(IDSlice(IDs))
}
// TODO move content into individual files if desired
// TODO(brian): If sub-topics are needed, write recursively (as tree comprised
// of Section nodes:
//
// type Section interface {
// Sections() []Section
// Topic() Topic
// }
var (
// TODO bootstrapping
// TODO pinning: ensuring a block is kept in local storage (i.e. not
// evicted from cache).
Introduction = Chapter(0)
FileBasics = Chapter(1)
NodeBasics = Chapter(2)
MerkleDag = Chapter(3)
Network = Chapter(4)
Daemon = Chapter(5)
Routing = Chapter(6)
Exchange = Chapter(7)
Ipns = Chapter(8)
Mounting = Chapter(9)
Plumbing = Chapter(10)
Formats = Chapter(11)
)
// Topics contains a mapping of Tour Topic ID to Topic
var allTopics = []Topic{
{ID: Introduction(0), Content: IntroHelloMars},
{ID: Introduction(1), Content: IntroTour},
{ID: Introduction(2), Content: IntroAboutIpfs},
{ID: FileBasics(1), Content: FileBasicsFilesystem},
{ID: FileBasics(2), Content: FileBasicsGetting},
{ID: FileBasics(3), Content: FileBasicsAdding},
{ID: FileBasics(4), Content: FileBasicsDirectories},
{ID: FileBasics(5), Content: FileBasicsDistributed},
{ID: FileBasics(6), Content: FileBasicsMounting},
{NodeBasics(0), NodeBasicsInit},
{NodeBasics(1), NodeBasicsHelp},
{NodeBasics(2), NodeBasicsUpdate},
{NodeBasics(3), NodeBasicsConfig},
{MerkleDag(0), MerkleDagIntro},
{MerkleDag(1), MerkleDagContentAddressing},
{MerkleDag(2), MerkleDagContentAddressingLinks},
{MerkleDag(3), MerkleDagRedux},
{MerkleDag(4), MerkleDagIpfsObjects},
{MerkleDag(5), MerkleDagIpfsPaths},
{MerkleDag(6), MerkleDagImmutability},
{MerkleDag(7), MerkleDagUseCaseUnixFS},
{MerkleDag(8), MerkleDagUseCaseGitObjects},
{MerkleDag(9), MerkleDagUseCaseOperationalTransforms},
{Network(0), Network_Intro},
{Network(1), Network_Ipfs_Peers},
{Network(2), Network_Daemon},
{Network(3), Network_Routing},
{Network(4), Network_Exchange},
{Network(5), Network_Intro},
// TODO daemon - {API, API Clients, Example} how old-school http + ftp
// clients show it
{Daemon(0), Daemon_Intro},
{Daemon(1), Daemon_Running_Commands},
{Daemon(2), Daemon_Web_UI},
{Routing(0), Routing_Intro},
{Routing(1), Rouing_Interface},
{Routing(2), Routing_Resolving},
{Routing(3), Routing_DHT},
{Routing(4), Routing_Other},
// TODO Exchange_Providing
// TODO Exchange_Providers
{Exchange(0), Exchange_Intro},
{Exchange(1), Exchange_Getting_Blocks},
{Exchange(2), Exchange_Strategies},
{Exchange(3), Exchange_Bitswap},
{Ipns(0), Ipns_Name_System},
{Ipns(1), Ipns_Mutability},
{Ipns(2), Ipns_PKI_Review},
{Ipns(3), Ipns_Publishing},
{Ipns(4), Ipns_Resolving},
{Ipns(5), Ipns_Consistency},
{Ipns(6), Ipns_Records_Etc},
{Mounting(0), Mounting_General},
{Mounting(1), Mounting_Ipfs},
{Mounting(2), Mounting_Ipns},
{Plumbing(0), Plumbing_Intro},
{Plumbing(1), Plumbing_Ipfs_Block},
{Plumbing(2), Plumbing_Ipfs_Object},
{Plumbing(3), Plumbing_Ipfs_Refs},
{Plumbing(4), Plumbing_Ipfs_Ping},
{Plumbing(5), Plumbing_Ipfs_Id},
{Formats(0), Formats_MerkleDag},
{Formats(1), Formats_Multihash},
{Formats(2), Formats_Multiaddr},
{Formats(3), Formats_Multicodec},
{Formats(4), Formats_Multicodec},
{Formats(5), Formats_Multikey},
{Formats(6), Formats_Protocol_Specific},
}
// Introduction
var IntroHelloMars = Content{
Title: "Hello Mars",
Text: `
check things work
`,
}
var IntroTour = Content{
Title: "Hello Mars",
Text: `
how this works
`,
}
var IntroAboutIpfs = Content{
Title: "About IPFS",
}
// File Basics
var FileBasicsFilesystem = Content{
Title: "Filesystem",
Text: `
`,
}
var FileBasicsGetting = Content{
Title: "Getting Files",
Text: `ipfs cat
`,
}
var FileBasicsAdding = Content{
Title: "Adding Files",
Text: `ipfs add
`,
}
var FileBasicsDirectories = Content{
Title: "Directories",
Text: `ipfs ls
`,
}
var FileBasicsDistributed = Content{
Title: "Distributed",
Text: `ipfs cat from mars
`,
}
var FileBasicsMounting = Content{
Title: "Getting Files",
Text: `ipfs mount (simple)
`,
}
// Node Basics
var NodeBasicsInit = Content{
Title: "Basics - init",
// TODO touch on PKI
//
// This is somewhat relevant at 'ipfs init' since the generated key pair is the
// basis for the node's identity in the network. A cursory nod may be
// sufficient at that stage, and goes a long way in explaining init's raison
// d'être.
// NB: user is introduced to 'ipfs init' before 'ipfs add'.
Text: `
`,
}
var NodeBasicsHelp = Content{
Title: "Basics - help",
Text: `
`,
}
var NodeBasicsUpdate = Content{
Title: "Basics - update",
Text: `
`,
}
var NodeBasicsConfig = Content{
Title: "Basics - config",
Text: `
`,
}
// Merkle DAG
var MerkleDagIntro = Content{}
var MerkleDagContentAddressing = Content{}
var MerkleDagContentAddressingLinks = Content{}
var MerkleDagRedux = Content{}
var MerkleDagIpfsObjects = Content{}
var MerkleDagIpfsPaths = Content{}
var MerkleDagImmutability = Content{
Title: "Immutability",
Text: `
TODO plan9
TODO git
`,
}
var MerkleDagUseCaseUnixFS = Content{}
var MerkleDagUseCaseGitObjects = Content{}
var MerkleDagUseCaseOperationalTransforms = Content{}
var Network_Intro = Content{}
var Network_Ipfs_Peers = Content{}
var Network_Daemon = Content{}
var Network_Routing = Content{}
var Network_Exchange = Content{}
var Network_Naming = Content{}
var Daemon_Intro = Content{}
var Daemon_Running_Commands = Content{}
var Daemon_Web_UI = Content{}
var Routing_Intro = Content{}
var Rouing_Interface = Content{}
var Routing_Resolving = Content{}
var Routing_DHT = Content{}
var Routing_Other = Content{}
var Exchange_Intro = Content{}
var Exchange_Bitswap = Content{}
var Exchange_Strategies = Content{}
var Exchange_Getting_Blocks = Content{}
var Ipns_Consistency = Content{}
var Ipns_Mutability = Content{}
var Ipns_Name_System = Content{}
var Ipns_PKI_Review = Content{
Title: "PKI Review",
Text: `
TODO sign verify
`,
}
var Ipns_Publishing = Content{}
var Ipns_Records_Etc = Content{}
var Ipns_Resolving = Content{}
var Mounting_General = Content{} // TODO note fuse
var Mounting_Ipfs = Content{} // TODO cd, ls, cat
var Mounting_Ipns = Content{} // TODO editing
var Plumbing_Intro = Content{}
var Plumbing_Ipfs_Block = Content{}
var Plumbing_Ipfs_Object = Content{}
var Plumbing_Ipfs_Refs = Content{}
var Plumbing_Ipfs_Ping = Content{}
var Plumbing_Ipfs_Id = Content{}
var Formats_MerkleDag = Content{}
var Formats_Multihash = Content{}
var Formats_Multiaddr = Content{}
var Formats_Multicodec = Content{}
var Formats_Multikey = Content{}
var Formats_Protocol_Specific = Content{}

View File

@ -1,16 +0,0 @@
package tour
import "fmt"
// returns a partially applied function.
//
// It's designed to make it easy to re-order chapters with minimal fuss.
//
// eg.
// Intro := Chapter(1)
// ID("1.1") == Intro(1) == Chapter(1)(1)
func Chapter(number int) func(topic int) ID {
return func(topic int) ID {
return ID(fmt.Sprintf("%d.%d", number, topic))
}
}

View File

@ -1,90 +0,0 @@
package tour
import (
"strconv"
"strings"
logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
)
var log = logging.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
Content
}
type Content struct {
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.Debug(err1)
log.Debug(err2)
panic("tour ID LessThan: not an int")
}
if ivis < ivos {
return true
}
if ivis > ivos {
return false
}
}
return len(os) > len(is)
}