ipfs.go 5 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 13

	config "github.com/jbenet/go-ipfs/config"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
14
	core "github.com/jbenet/go-ipfs/core"
15
	daemon "github.com/jbenet/go-ipfs/daemon"
16
	updates "github.com/jbenet/go-ipfs/updates"
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
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:

28
    init          Initialize ipfs local configuration.
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
29 30 31 32 33 34 35
    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
36
    config        Manage configuration.
37
    update        Download and apply go-ipfs updates.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
38 39
    version       Show ipfs version information.
    commands      List all available commands.
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
40 41 42

Advanced Commands:

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
43
    mount         Mount an ipfs read-only mountpoint.
44
    serve         Serve an interface to ipfs.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
45
    net-diag      Print network diagnostic
Jeromy's avatar
Jeromy committed
46

47 48 49 50 51 52
Plumbing commands:

    block         Interact with raw blocks in the datastore
    object        Interact with raw dag nodes


Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
53 54 55 56
Use "ipfs help <command>" for more information about a command.
`,
	Run: ipfsCmd,
	Subcommands: []*commander.Command{
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
57
		cmdIpfsAdd,
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
58
		cmdIpfsCat,
59
		cmdIpfsLs,
Juan Batiz-Benet's avatar
refs  
Juan Batiz-Benet committed
60
		cmdIpfsRefs,
61
		cmdIpfsConfig,
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
62 63
		cmdIpfsVersion,
		cmdIpfsCommands,
64
		cmdIpfsMount,
65
		cmdIpfsInit,
verokarhu's avatar
verokarhu committed
66
		cmdIpfsServe,
Jeromy's avatar
Jeromy committed
67
		cmdIpfsRun,
68
		cmdIpfsName,
69
		cmdIpfsBootstrap,
70
		cmdIpfsDiag,
71
		cmdIpfsBlock,
Henry's avatar
Henry committed
72
		cmdIpfsObject,
Henry's avatar
Henry committed
73
		cmdIpfsUpdate,
Henry's avatar
Henry committed
74
		cmdIpfsLog,
Jeromy's avatar
Jeromy committed
75
		cmdIpfsPin,
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
76
		cmdIpfsTour,
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
77 78 79 80
	},
	Flag: *flag.NewFlagSet("ipfs", flag.ExitOnError),
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
81
// log is the command logger
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
82
var log = u.Logger("cmd/ipfs")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
83

Jeromy's avatar
Jeromy committed
84
func init() {
Shanti Bouchez-Mongardé's avatar
Shanti Bouchez-Mongardé committed
85
	config, err := config.PathRoot()
86
	if err != nil {
87
		fmt.Fprintln(os.Stderr, "Failure initializing the default Config Directory: ", err)
88
		os.Exit(1)
89 90
	}
	CmdIpfs.Flag.String("c", config, "specify config directory")
Jeromy's avatar
Jeromy committed
91 92
}

Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
93 94 95 96 97
func ipfsCmd(c *commander.Command, args []string) error {
	u.POut(c.Long)
	return nil
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
98
func main() {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
99 100 101 102 103 104 105 106 107 108
	// 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()
109
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
110 111

	err := CmdIpfs.Dispatch(os.Args[1:])
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
112 113
	if err != nil {
		if len(err.Error()) > 0 {
114
			fmt.Fprintf(os.Stderr, "ipfs %s: %v\n", os.Args[1], err)
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
115 116 117 118
		}
		os.Exit(1)
	}
	return
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
119
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
120

121
// localNode constructs a node
122
func localNode(confdir string, online bool) (*core.IpfsNode, error) {
Shanti Bouchez-Mongardé's avatar
Shanti Bouchez-Mongardé committed
123
	filename, err := config.Filename(confdir)
124 125 126 127 128
	if err != nil {
		return nil, err
	}

	cfg, err := config.Load(filename)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
129 130 131 132
	if err != nil {
		return nil, err
	}

133 134
	if err := updates.CliCheckForUpdates(cfg, filename); err != nil {
		return nil, err
135 136
	}

137
	return core.NewIpfsNode(cfg, online)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
138
}
Jeromy's avatar
Jeromy committed
139 140

// Gets the config "-c" flag from the command, or returns
141
// the default configuration root directory
142
func getConfigDir(c *commander.Command) (string, error) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
143 144 145

	// use the root cmd (that's where config is specified)
	for ; c.Parent != nil; c = c.Parent {
146
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
147 148 149 150 151

	// flag should be defined on root.
	param := c.Flag.Lookup("c").Value.Get().(string)
	if param != "" {
		return u.TildeExpansion(param)
152
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
153 154 155 156 157 158 159 160

	return config.PathRoot()
}

func getConfig(c *commander.Command) (*config.Config, error) {
	confdir, err := getConfigDir(c)
	if err != nil {
		return nil, err
Jeromy's avatar
Jeromy committed
161
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
162 163 164 165

	filename, err := config.Filename(confdir)
	if err != nil {
		return nil, err
166
	}
167

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
168
	return config.Load(filename)
Jeromy's avatar
Jeromy committed
169
}
170 171 172 173 174 175 176 177 178 179 180

// 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) {
181
	rootCmd := c
182
	for ; rootCmd.Parent != nil; rootCmd = rootCmd.Parent {
183 184 185
	}

	cc.configDir, err = getConfigDir(rootCmd)
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
	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
}