ipfs.go 5.12 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 37 38
    config        Manage configuration.
    version       Show ipfs version information.
    commands      List all available commands.
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
39 40 41

Advanced Commands:

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

Jeromy's avatar
Jeromy committed
45 46
	net-diag	  Print network diagnostic

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

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

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

Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
82 83 84 85 86
func ipfsCmd(c *commander.Command, args []string) error {
	u.POut(c.Long)
	return nil
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
87
func main() {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
88 89 90
	u.Debug = false

	// setup logging
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
91
	// u.SetupLogging() done in an init() block now.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
92 93 94 95 96 97 98 99 100 101 102

	// 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()
103
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
104 105

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

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

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

127
	if cfg.Version.ShouldCheckForUpdate() {
128
		obsolete := updates.CheckForUpdates()
129
		if obsolete != nil {
130
			if cfg.Version.Check == config.CheckError {
131 132
				return nil, obsolete
			}
133 134 135

			// when "warn" version.check mode we just show warning message
			log.Warning(fmt.Sprintf("%v", obsolete))
136 137
		} else {
			// update most recent check timestamp in config
138
			config.RecordUpdateCheck(cfg, filename)
139 140 141
		}
	}

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

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

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

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

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

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

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

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

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