ipfs.go 4.37 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1 2 3
package main

import (
4
	"errors"
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
5
	"fmt"
6
	"os"
7
	"runtime/pprof"
8

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
9 10
	flag "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag"
	commander "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander"
11
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
12
	logging "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/op/go-logging"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
13 14

	config "github.com/jbenet/go-ipfs/config"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
15
	core "github.com/jbenet/go-ipfs/core"
16
	daemon "github.com/jbenet/go-ipfs/daemon"
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
17
	u "github.com/jbenet/go-ipfs/util"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
18 19
)

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
20
// The IPFS command tree. It is an instance of `commander.Command`.
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
21 22 23 24 25 26 27 28 29 30 31 32 33 34
var CmdIpfs = &commander.Command{
	UsageLine: "ipfs [<flags>] <command> [<args>]",
	Short:     "global versioned p2p merkledag file system",
	Long: `ipfs - global versioned p2p merkledag file system

Basic commands:

    add <path>    Add an object to ipfs.
    cat <ref>     Show ipfs object data.
    ls <ref>      List links from an object.
    refs <ref>    List link hashes from an object.

Tool commands:

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
35 36 37
    config        Manage configuration.
    version       Show ipfs version information.
    commands      List all available commands.
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
38 39 40

Advanced Commands:

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
41
    mount         Mount an ipfs read-only mountpoint.
42
    serve         Serve an interface to ipfs.
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
43 44 45 46 47

Use "ipfs help <command>" for more information about a command.
`,
	Run: ipfsCmd,
	Subcommands: []*commander.Command{
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
48
		cmdIpfsAdd,
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
49
		cmdIpfsCat,
50
		cmdIpfsLs,
Juan Batiz-Benet's avatar
refs  
Juan Batiz-Benet committed
51
		cmdIpfsRefs,
52
		cmdIpfsConfig,
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
53 54
		cmdIpfsVersion,
		cmdIpfsCommands,
55
		cmdIpfsMount,
56
		cmdIpfsInit,
verokarhu's avatar
verokarhu committed
57
		cmdIpfsServe,
Jeromy's avatar
Jeromy committed
58
		cmdIpfsRun,
59
		cmdIpfsName,
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
60 61 62 63
	},
	Flag: *flag.NewFlagSet("ipfs", flag.ExitOnError),
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
64
// log is the command logger
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
65
var log = u.Logger("cmd/ipfs", logging.ERROR)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
66

Jeromy's avatar
Jeromy committed
67
func init() {
Shanti Bouchez-Mongardé's avatar
Shanti Bouchez-Mongardé committed
68
	config, err := config.PathRoot()
69 70 71 72
	if err != nil {
		config = ""
	}
	CmdIpfs.Flag.String("c", config, "specify config directory")
Jeromy's avatar
Jeromy committed
73 74
}

Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
75 76 77 78 79
func ipfsCmd(c *commander.Command, args []string) error {
	u.POut(c.Long)
	return nil
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
80
func main() {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
	u.Debug = false

	// setup logging
	u.SetupLogging()

	// if debugging, setup profiling.
	if u.Debug {
		ofi, err := os.Create("cpu.prof")
		if err != nil {
			fmt.Println(err)
			return
		}
		pprof.StartCPUProfile(ofi)
		defer ofi.Close()
		defer pprof.StopCPUProfile()
96
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
97 98

	err := CmdIpfs.Dispatch(os.Args[1:])
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
99 100
	if err != nil {
		if len(err.Error()) > 0 {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
101
			fmt.Fprintf(os.Stderr, "ipfs %s: %v\n", os.Args[1], err)
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
102 103 104 105
		}
		os.Exit(1)
	}
	return
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
106
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
107

108
// localNode constructs a node
109
func localNode(confdir string, online bool) (*core.IpfsNode, error) {
Shanti Bouchez-Mongardé's avatar
Shanti Bouchez-Mongardé committed
110
	filename, err := config.Filename(confdir)
111 112 113 114 115
	if err != nil {
		return nil, err
	}

	cfg, err := config.Load(filename)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
116 117 118 119
	if err != nil {
		return nil, err
	}

120
	return core.NewIpfsNode(cfg, online)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
121
}
Jeromy's avatar
Jeromy committed
122 123

// Gets the config "-c" flag from the command, or returns
124
// the default configuration root directory
125
func getConfigDir(c *commander.Command) (string, error) {
126 127 128 129 130
	root := c
	for root.Parent != nil {
		root = root.Parent
	}
	conf := root.Flag.Lookup("c").Value.Get()
131
	if conf == nil {
Shanti Bouchez-Mongardé's avatar
Shanti Bouchez-Mongardé committed
132
		return config.PathRoot()
133
	}
Jeromy's avatar
Jeromy committed
134
	confStr, ok := conf.(string)
135
	if !ok {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
136
		return "", errors.New("failed to retrieve config flag value")
Jeromy's avatar
Jeromy committed
137
	}
138
	if len(confStr) == 0 {
Shanti Bouchez-Mongardé's avatar
Shanti Bouchez-Mongardé committed
139
		return config.PathRoot()
140
	}
141 142

	return u.TildeExpansion(confStr)
Jeromy's avatar
Jeromy committed
143
}
144 145 146 147 148 149 150 151 152 153 154

// cmdContext is a wrapper structure that keeps a node, a daemonlistener, and
// a config directory together. These three are needed for most commands.
type cmdContext struct {
	node      *core.IpfsNode
	daemon    *daemon.DaemonListener
	configDir string
}

// setupCmdContext initializes a cmdContext structure from a given command.
func setupCmdContext(c *commander.Command, online bool) (cc cmdContext, err error) {
155 156 157 158 159
	rootCmd := c
	for ; rootCmd.Parent != nil; rootCmd = c.Parent {
	}

	cc.configDir, err = getConfigDir(rootCmd)
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
	if err != nil {
		return
	}

	cc.node, err = localNode(cc.configDir, online)
	if err != nil {
		return
	}

	cc.daemon, err = setupDaemon(cc.configDir, cc.node)
	if err != nil {
		return
	}

	return
}

// setupDaemon sets up the daemon corresponding to given node.
func setupDaemon(confdir string, node *core.IpfsNode) (*daemon.DaemonListener, error) {
	if node.Config.Addresses.API == "" {
		return nil, errors.New("no config.Addresses.API endpoint supplied")
	}

	maddr, err := ma.NewMultiaddr(node.Config.Addresses.API)
	if err != nil {
		return nil, err
	}

	dl, err := daemon.NewDaemonListener(node, maddr, confdir)
	if err != nil {
		return nil, err
	}
	go dl.Listen()
	return dl, nil
}