ipfs.go 4.88 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"
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
16
	u "github.com/jbenet/go-ipfs/util"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
17 18
)

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

27
    init          Initialize ipfs local configuration.
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
28 29 30 31 32 33 34
    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,
60
		cmdIpfsBootstrap,
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
61 62 63 64
	},
	Flag: *flag.NewFlagSet("ipfs", flag.ExitOnError),
}

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

Jeromy's avatar
Jeromy committed
68
func init() {
Shanti Bouchez-Mongardé's avatar
Shanti Bouchez-Mongardé committed
69
	config, err := config.PathRoot()
70
	if err != nil {
71 72
		u.POut("Failure initializing the default Config Directory: ", err)
		os.Exit(1)
73 74
	}
	CmdIpfs.Flag.String("c", config, "specify config directory")
Jeromy's avatar
Jeromy committed
75 76
}

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

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
82
func main() {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
83 84 85
	u.Debug = false

	// setup logging
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
86
	// u.SetupLogging() done in an init() block now.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
87 88 89 90 91 92 93 94 95 96 97

	// 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()
98
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
99 100

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

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

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

122
	if cfg.Version.Check != config.CheckIgnore {
123 124
		obsolete := checkForUpdates()
		if obsolete != nil {
125
			if cfg.Version.Check == config.CheckError {
126 127
				return nil, obsolete
			}
128
			fmt.Println(obsolete) // when "warn" version.check mode we just show warning message
129 130 131
		}
	}

132
	return core.NewIpfsNode(cfg, online)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
133
}
Jeromy's avatar
Jeromy committed
134 135

// Gets the config "-c" flag from the command, or returns
136
// the default configuration root directory
137
func getConfigDir(c *commander.Command) (string, error) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
138 139 140

	// use the root cmd (that's where config is specified)
	for ; c.Parent != nil; c = c.Parent {
141
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
142 143 144 145 146

	// flag should be defined on root.
	param := c.Flag.Lookup("c").Value.Get().(string)
	if param != "" {
		return u.TildeExpansion(param)
147
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
148 149 150 151 152 153 154 155

	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
156
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
157 158 159 160

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

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
163
	return config.Load(filename)
Jeromy's avatar
Jeromy committed
164
}
165 166 167 168 169 170 171 172 173 174 175

// 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) {
176 177 178 179 180
	rootCmd := c
	for ; rootCmd.Parent != nil; rootCmd = c.Parent {
	}

	cc.configDir, err = getConfigDir(rootCmd)
181 182 183 184 185 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
	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
}