main.go 5.33 KB
Newer Older
1 2 3 4 5 6 7 8
package main

import (
	"fmt"
	"io"
	"os"
	"runtime/pprof"

9
	logging "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-logging"
10 11 12
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
	manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net"

13 14 15 16 17 18 19 20 21 22 23 24 25
	cmds "github.com/jbenet/go-ipfs/commands"
	cmdsCli "github.com/jbenet/go-ipfs/commands/cli"
	cmdsHttp "github.com/jbenet/go-ipfs/commands/http"
	"github.com/jbenet/go-ipfs/config"
	"github.com/jbenet/go-ipfs/core"
	commands "github.com/jbenet/go-ipfs/core/commands2"
	daemon "github.com/jbenet/go-ipfs/daemon2"
	u "github.com/jbenet/go-ipfs/util"
)

// log is the command logger
var log = u.Logger("cmd/ipfs")

26 27
const heapProfile = "ipfs.mprof"

28 29
func main() {
	args := os.Args[1:]
30 31 32 33
	req, root := createRequest(args)
	handleOptions(req, root)
	res := callCommand(req, root)
	outputResponse(res)
34 35 36 37 38 39 40

	if u.Debug {
		err := writeHeapProfileToFile()
		if err != nil {
			log.Critical(err)
		}
	}
41
}
42

43
func createRequest(args []string) (cmds.Request, *cmds.Command) {
44
	req, root, cmd, err := cmdsCli.Parse(args, Root, commands.Root)
45 46
	if err != nil {
		fmt.Println(err)
47 48 49 50 51 52 53
		if cmd != nil {
			if cmd.Help != "" {
				fmt.Println(cmd.Help)
			}
		} else {
			fmt.Println(Root.Help)
		}
54 55 56
		os.Exit(1)
	}

57
	options, err := getOptions(req, root)
58 59 60 61 62
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
	configPath, err := getConfigRoot(options)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	conf, err := getConfig(configPath)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	ctx := req.Context()
	ctx.ConfigRoot = configPath
	ctx.Config = conf

	if _, found := options.Option("encoding"); !found {
80
		if req.Command().Marshallers != nil && req.Command().Marshallers[cmds.Text] != nil {
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
			req.SetOption("encoding", cmds.Text)
		} else {
			req.SetOption("encoding", cmds.JSON)
		}
	}

	return req, root
}

func handleOptions(req cmds.Request, root *cmds.Command) {
	options, err := getOptions(req, root)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

97 98 99 100 101 102 103 104
	if help, found := options.Option("help"); found {
		if helpBool, ok := help.(bool); helpBool && ok {
			fmt.Println(req.Command().Help)
			os.Exit(0)
		} else if !ok {
			fmt.Println("error: expected 'help' option to be a bool")
			os.Exit(1)
		}
105 106
	}

107 108 109 110
	if debug, found := options.Option("debug"); found {
		if debugBool, ok := debug.(bool); debugBool && ok {
			u.Debug = true

111 112
			u.SetAllLoggers(logging.DEBUG)

113 114 115 116 117 118 119 120 121 122
			// 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()
123
			}
124 125 126
		} else if !ok {
			fmt.Println("error: expected 'debug' option to be a bool")
			os.Exit(1)
127 128
		}
	}
129
}
130

131
func callCommand(req cmds.Request, root *cmds.Command) cmds.Response {
132
	var res cmds.Response
133

134 135
	if root == Root {
		res = root.Call(req)
136 137

	} else {
138 139 140 141 142 143
		options, err := getOptions(req, root)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

144
		var found bool
145
		var local interface{}
146
		localBool := false
147
		if local, found = options.Option("local"); found {
148 149 150 151 152 153 154
			var ok bool
			localBool, ok = local.(bool)
			if !ok {
				fmt.Println("error: expected 'local' option to be a bool")
				os.Exit(1)
			}
		}
155

156
		if (!found || !localBool) && daemon.Locked(req.Context().ConfigRoot) {
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
			addr, err := ma.NewMultiaddr(req.Context().Config.Addresses.API)
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}

			_, host, err := manet.DialArgs(addr)
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}

			client := cmdsHttp.NewClient(host)

			res, err = client.Send(req)
172 173 174 175 176 177
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}

		} else {
178
			node, err := core.NewIpfsNode(req.Context().Config, false)
179 180 181 182
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
Brian Tiger Chow's avatar
Brian Tiger Chow committed
183
			defer node.Close()
184
			req.Context().Node = node
185

186
			res = root.Call(req)
187 188 189
		}
	}

190 191 192 193
	return res
}

func outputResponse(res cmds.Response) {
194 195 196
	if res.Error() != nil {
		fmt.Println(res.Error().Error())

197
		if res.Request().Command().Help != "" && res.Error().Code == cmds.ErrClient {
198
			// TODO: convert from markdown to ANSI terminal format?
199
			fmt.Println(res.Request().Command().Help)
200 201 202 203 204
		}

		os.Exit(1)
	}

205
	out, err := res.Reader()
206 207
	if err != nil {
		fmt.Println(err.Error())
208
		return
209
	}
210 211

	io.Copy(os.Stdout, out)
212 213 214
}

func getOptions(req cmds.Request, root *cmds.Command) (cmds.Request, error) {
215
	tempReq := cmds.NewRequest(req.Path(), req.Options(), nil, nil)
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231

	options, err := root.GetOptions(tempReq.Path())
	if err != nil {
		return nil, err
	}

	err = tempReq.ConvertOptions(options)
	if err != nil {
		return nil, err
	}

	return tempReq, nil
}

func getConfigRoot(req cmds.Request) (string, error) {
	if opt, found := req.Option("config"); found {
232 233 234 235 236
		if optStr, ok := opt.(string); ok {
			return optStr, nil
		} else {
			return "", fmt.Errorf("Expected 'config' option to be a string")
		}
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
	}

	configPath, err := config.PathRoot()
	if err != nil {
		return "", err
	}
	return configPath, nil
}

func getConfig(path string) (*config.Config, error) {
	configFile, err := config.Filename(path)
	if err != nil {
		return nil, err
	}

	return config.Load(configFile)
}
254 255 256 257 258 259 260 261 262

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