ipfs.go 5.24 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
	flag "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag"
10
	"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/inconshreveable/go-update/check"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
11
	commander "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander"
12
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
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"
17
	updates "github.com/jbenet/go-ipfs/updates"
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
18
	u "github.com/jbenet/go-ipfs/util"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
19 20
)

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
21
// The IPFS command tree. It is an instance of `commander.Command`.
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
22 23 24 25 26 27 28
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:

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

Henry's avatar
Henry committed
41 42 43 44
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
45 46
Advanced Commands:

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
47
    mount         Mount an ipfs read-only mountpoint.
48
    serve         Serve an interface to ipfs.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
49
    net-diag      Print network diagnostic
Jeromy's avatar
Jeromy committed
50

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

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

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

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

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

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

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

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

130
	if cfg.Version.ShouldCheckForUpdate() {
131 132 133 134 135
		_, err := updates.CheckForUpdate()
		if err != nil {
			if err != check.NoUpdateAvailable {
				log.Error("Error while checking for update: %v\n", err)
				return nil, err
136

137 138
			}
			log.Notice("No update available")
139
		}
140 141

		config.RecordUpdateCheck(cfg, filename)
142 143
	}

144
	return core.NewIpfsNode(cfg, online)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
145
}
Jeromy's avatar
Jeromy committed
146 147

// Gets the config "-c" flag from the command, or returns
148
// the default configuration root directory
149
func getConfigDir(c *commander.Command) (string, error) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
150 151 152

	// use the root cmd (that's where config is specified)
	for ; c.Parent != nil; c = c.Parent {
153
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
154 155 156 157 158

	// flag should be defined on root.
	param := c.Flag.Lookup("c").Value.Get().(string)
	if param != "" {
		return u.TildeExpansion(param)
159
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
160 161 162 163 164 165 166 167

	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
168
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
169 170 171 172

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

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
175
	return config.Load(filename)
Jeromy's avatar
Jeromy committed
176
}
177 178 179 180 181 182 183 184 185 186 187

// 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) {
188
	rootCmd := c
189
	for ; rootCmd.Parent != nil; rootCmd = rootCmd.Parent {
190 191 192
	}

	cc.configDir, err = getConfigDir(rootCmd)
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 221 222 223 224 225 226 227
	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
}