ipfs.go 5.3 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
)

20 21
const heapProfile = "ipfs.mprof"

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

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

Advanced Commands:

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

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

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

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

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

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
100
func main() {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
101 102 103
	// if debugging, setup profiling.
	if u.Debug {
		ofi, err := os.Create("cpu.prof")
104 105
		defer ofi.Close()

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
106 107 108 109
		if err != nil {
			fmt.Println(err)
			return
		}
110

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
111 112
		pprof.StartCPUProfile(ofi)
		defer pprof.StopCPUProfile()
113
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
114 115

	err := CmdIpfs.Dispatch(os.Args[1:])
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
116 117
	if err != nil {
		if len(err.Error()) > 0 {
118
			fmt.Fprintf(os.Stderr, "ipfs %s: %v\n", os.Args[1], err)
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
119 120 121
		}
		os.Exit(1)
	}
122 123 124 125 126 127 128

	if u.Debug {
		err := writeHeapProfileToFile()
		if err != nil {
			log.Critical(err)
		}
	}
Juan Batiz-Benet's avatar
refmt  
Juan Batiz-Benet committed
129
	return
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
130
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
131

132
// localNode constructs a node
133
func localNode(confdir string, online bool) (*core.IpfsNode, error) {
Shanti Bouchez-Mongardé's avatar
Shanti Bouchez-Mongardé committed
134
	filename, err := config.Filename(confdir)
135 136 137 138 139
	if err != nil {
		return nil, err
	}

	cfg, err := config.Load(filename)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
140 141 142 143
	if err != nil {
		return nil, err
	}

144 145
	if err := updates.CliCheckForUpdates(cfg, filename); err != nil {
		return nil, err
146 147
	}

148
	return core.NewIpfsNode(cfg, online)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
149
}
Jeromy's avatar
Jeromy committed
150 151

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

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

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

	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
172
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
173 174 175 176

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

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
179
	return config.Load(filename)
Jeromy's avatar
Jeromy committed
180
}
181 182 183 184 185 186 187 188 189 190 191

// 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) {
192
	rootCmd := c
193
	for ; rootCmd.Parent != nil; rootCmd = rootCmd.Parent {
194 195 196
	}

	cc.configDir, err = getConfigDir(rootCmd)
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 228 229 230 231
	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
}
232 233 234 235 236 237 238 239 240

func writeHeapProfileToFile() error {
	mprof, err := os.Create(heapProfile)
	if err != nil {
		log.Fatal(err)
	}
	defer mprof.Close()
	return pprof.WriteHeapProfile(mprof)
}