From d1fa4bd9b5a3a9ec8620fb67fe052bec3bd314cc Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Tue, 28 Oct 2014 23:48:11 -0700 Subject: [PATCH] copy to old location --- cmd/ipfs/.gitignore | 1 + cmd/ipfs/Makefile | 7 ++ cmd/ipfs/README.md | 29 +++++ cmd/ipfs/add.go | 39 +++++++ cmd/ipfs/block.go | 58 ++++++++++ cmd/ipfs/bootstrap.go | 236 ++++++++++++++++++++++++++++++++++++++ cmd/ipfs/cat.go | 26 +++++ cmd/ipfs/commands.go | 74 ++++++++++++ cmd/ipfs/config.go | 143 +++++++++++++++++++++++ cmd/ipfs/diag.go | 32 ++++++ cmd/ipfs/equinox.yaml | 6 + cmd/ipfs/gen.go | 72 ++++++++++++ cmd/ipfs/init.go | 150 ++++++++++++++++++++++++ cmd/ipfs/ipfs.go | 220 +++++++++++++++++++++++++++++++++++ cmd/ipfs/log.go | 29 +++++ cmd/ipfs/ls.go | 29 +++++ cmd/ipfs/mount_unix.go | 94 +++++++++++++++ cmd/ipfs/mount_windows.go | 19 +++ cmd/ipfs/name.go | 57 +++++++++ cmd/ipfs/objects.go | 112 ++++++++++++++++++ cmd/ipfs/pin.go | 62 ++++++++++ cmd/ipfs/publish.go | 41 +++++++ cmd/ipfs/refs.go | 36 ++++++ cmd/ipfs/resolve.go | 42 +++++++ cmd/ipfs/run.go | 36 ++++++ cmd/ipfs/serve.go | 49 ++++++++ cmd/ipfs/tour.go | 134 ++++++++++++++++++++++ cmd/ipfs/update.go | 62 ++++++++++ cmd/ipfs/version.go | 30 +++++ 29 files changed, 1925 insertions(+) create mode 100644 cmd/ipfs/.gitignore create mode 100644 cmd/ipfs/Makefile create mode 100644 cmd/ipfs/README.md create mode 100644 cmd/ipfs/add.go create mode 100644 cmd/ipfs/block.go create mode 100644 cmd/ipfs/bootstrap.go create mode 100644 cmd/ipfs/cat.go create mode 100644 cmd/ipfs/commands.go create mode 100644 cmd/ipfs/config.go create mode 100644 cmd/ipfs/diag.go create mode 100644 cmd/ipfs/equinox.yaml create mode 100644 cmd/ipfs/gen.go create mode 100644 cmd/ipfs/init.go create mode 100644 cmd/ipfs/ipfs.go create mode 100644 cmd/ipfs/log.go create mode 100644 cmd/ipfs/ls.go create mode 100644 cmd/ipfs/mount_unix.go create mode 100644 cmd/ipfs/mount_windows.go create mode 100644 cmd/ipfs/name.go create mode 100644 cmd/ipfs/objects.go create mode 100644 cmd/ipfs/pin.go create mode 100644 cmd/ipfs/publish.go create mode 100644 cmd/ipfs/refs.go create mode 100644 cmd/ipfs/resolve.go create mode 100644 cmd/ipfs/run.go create mode 100644 cmd/ipfs/serve.go create mode 100644 cmd/ipfs/tour.go create mode 100644 cmd/ipfs/update.go create mode 100644 cmd/ipfs/version.go diff --git a/cmd/ipfs/.gitignore b/cmd/ipfs/.gitignore new file mode 100644 index 000000000..8de552d0c --- /dev/null +++ b/cmd/ipfs/.gitignore @@ -0,0 +1 @@ +./ipfs diff --git a/cmd/ipfs/Makefile b/cmd/ipfs/Makefile new file mode 100644 index 000000000..fccb80330 --- /dev/null +++ b/cmd/ipfs/Makefile @@ -0,0 +1,7 @@ +all: install + +build: + go build + +install: build + go install diff --git a/cmd/ipfs/README.md b/cmd/ipfs/README.md new file mode 100644 index 000000000..0051f68e9 --- /dev/null +++ b/cmd/ipfs/README.md @@ -0,0 +1,29 @@ +# go-ipfs/cmd/ipfs + +This is the ipfs commandline tool. For now, it's the main entry point to using IPFS. Use it. + +``` +> go build +> go install +> ipfs +ipfs - global versioned p2p merkledag file system + +Basic commands: + + add Add an object to ipfs. + cat Show ipfs object data. + ls List links from an object. + refs List link hashes from an object. + +Tool commands: + + config Manage configuration. + version Show ipfs version information. + commands List all available commands. + +Advanced Commands: + + mount Mount an ipfs read-only mountpoint. + +Use "ipfs help " for more information about a command. +``` diff --git a/cmd/ipfs/add.go b/cmd/ipfs/add.go new file mode 100644 index 000000000..a755f699e --- /dev/null +++ b/cmd/ipfs/add.go @@ -0,0 +1,39 @@ +package main + +import ( + "fmt" + "path/filepath" + + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag" + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" + "github.com/jbenet/go-ipfs/core/commands" +) + +// Error indicating the max depth has been exceded. +var ErrDepthLimitExceeded = fmt.Errorf("depth limit exceeded") + +var cmdIpfsAdd = &commander.Command{ + UsageLine: "add", + Short: "Add an object to ipfs.", + Long: `ipfs add ... - Add objects to ipfs. + + Adds contents of to ipfs. Use -r to add directories. + Note that directories are added recursively, to form the ipfs + MerkleDAG. A smarter partial add with a staging area (like git) + remains to be implemented. +`, + Run: addCmd, + Flag: *flag.NewFlagSet("ipfs-add", flag.ExitOnError), +} + +func init() { + cmdIpfsAdd.Flag.Bool("r", false, "add objects recursively") +} + +var addCmd = makeCommand(command{ + name: "add", + args: 1, + flags: []string{"r"}, + cmdFn: commands.Add, + argFilter: filepath.Abs, +}) diff --git a/cmd/ipfs/block.go b/cmd/ipfs/block.go new file mode 100644 index 000000000..2f139d0bc --- /dev/null +++ b/cmd/ipfs/block.go @@ -0,0 +1,58 @@ +package main + +import ( + 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" + "github.com/jbenet/go-ipfs/core/commands" +) + +var cmdIpfsBlock = &commander.Command{ + UsageLine: "block", + Short: "manipulate raw ipfs blocks", + Long: `ipfs block - manipulate raw ipfs blocks + + ipfs block get - get and output block named by + ipfs block put - store stdin as a block, outputs + +ipfs block is a plumbing command used to manipulate raw ipfs blocks. +Reads from stdin or writes to stdout, and is a base58 encoded +multihash.`, + // Run: blockGetCmd, + Subcommands: []*commander.Command{ + cmdIpfsBlockGet, + cmdIpfsBlockPut, + }, + Flag: *flag.NewFlagSet("ipfs-block", flag.ExitOnError), +} + +var cmdIpfsBlockGet = &commander.Command{ + UsageLine: "get ", + Short: "get and output block named by ", + Long: `ipfs get - get and output block named by + +ipfs block get is a plumbing command for retreiving raw ipfs blocks. +It outputs to stdout, and is a base58 encoded multihash.`, + Run: makeCommand(command{ + name: "blockGet", + args: 1, + flags: nil, + online: true, + cmdFn: commands.BlockGet, + }), +} + +var cmdIpfsBlockPut = &commander.Command{ + UsageLine: "put", + Short: "store stdin as a block, outputs ", + Long: `ipfs put - store stdin as a block, outputs + +ipfs block put is a plumbing command for storing raw ipfs blocks. +It reads from stding, and is a base58 encoded multihash.`, + Run: makeCommand(command{ + name: "blockPut", + args: 0, + flags: nil, + online: true, + cmdFn: commands.BlockPut, + }), +} diff --git a/cmd/ipfs/bootstrap.go b/cmd/ipfs/bootstrap.go new file mode 100644 index 000000000..6f6a78574 --- /dev/null +++ b/cmd/ipfs/bootstrap.go @@ -0,0 +1,236 @@ +package main + +import ( + "errors" + "strings" + + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag" + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" + ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" + mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash" + + config "github.com/jbenet/go-ipfs/config" + peer "github.com/jbenet/go-ipfs/peer" + u "github.com/jbenet/go-ipfs/util" +) + +var cmdIpfsBootstrap = &commander.Command{ + UsageLine: "bootstrap", + Short: "Show a list of bootstrapped addresses.", + Long: `ipfs bootstrap - show, or manipulate bootstrap node addresses + +Running 'ipfs bootstrap' with no arguments will run 'ipfs bootstrap list'. + +Commands: + + list Show the boostrap list. + add
Add a node's address to the bootstrap list. + remove
Remove an address from the bootstrap list. + +` + bootstrapSecurityWarning, + Run: bootstrapListCmd, + Subcommands: []*commander.Command{ + cmdIpfsBootstrapRemove, + cmdIpfsBootstrapAdd, + cmdIpfsBootstrapList, + }, + Flag: *flag.NewFlagSet("ipfs-bootstrap", flag.ExitOnError), +} + +var cmdIpfsBootstrapRemove = &commander.Command{ + UsageLine: "remove
", + Short: "Remove addresses from the bootstrap list.", + Long: `ipfs bootstrap remove - remove addresses from the bootstrap list +` + bootstrapSecurityWarning, + Run: bootstrapRemoveCmd, + Flag: *flag.NewFlagSet("ipfs-bootstrap-remove", flag.ExitOnError), +} + +var cmdIpfsBootstrapAdd = &commander.Command{ + UsageLine: "add
", + Short: "Add addresses to the bootstrap list.", + Long: `ipfs bootstrap add - add addresses to the bootstrap list +` + bootstrapSecurityWarning, + Run: bootstrapAddCmd, + Flag: *flag.NewFlagSet("ipfs-bootstrap-add", flag.ExitOnError), +} + +var cmdIpfsBootstrapList = &commander.Command{ + UsageLine: "list", + Short: "Show addresses in the bootstrap list.", + Run: bootstrapListCmd, + Flag: *flag.NewFlagSet("ipfs-bootstrap-list", flag.ExitOnError), +} + +func bootstrapRemoveCmd(c *commander.Command, inp []string) error { + + if len(inp) == 0 { + return errors.New("remove: no address or peerid specified") + } + + toRemove, err := bootstrapInputToPeers(inp) + if err != nil { + return err + } + + cfg, err := getConfig(c) + if err != nil { + return err + } + + keep := []*config.BootstrapPeer{} + remove := []*config.BootstrapPeer{} + + // function to filer what to keep + shouldKeep := func(bp *config.BootstrapPeer) bool { + for _, skipBP := range toRemove { + + // IDs must match to skip. + if bp.PeerID != skipBP.PeerID { + continue + } + + // if Addresses match, or skipBP has no addr (wildcard) + if skipBP.Address == bp.Address || skipBP.Address == "" { + return false + } + } + return true + } + + // filter all the existing peers + for _, currBP := range cfg.Bootstrap { + if shouldKeep(currBP) { + keep = append(keep, currBP) + } else { + remove = append(remove, currBP) + } + } + + // if didn't remove anyone, bail. + if len(keep) == len(cfg.Bootstrap) { + return errors.New("remove: peer given did not match any in list") + } + + // write new config + cfg.Bootstrap = keep + if err := writeConfig(c, cfg); err != nil { + return err + } + + for _, bp := range remove { + u.POut("removed %s\n", bp) + } + return nil +} + +func bootstrapAddCmd(c *commander.Command, inp []string) error { + + if len(inp) == 0 { + return errors.New("add: no address specified") + } + + toAdd, err := bootstrapInputToPeers(inp) + if err != nil { + return err + } + + cfg, err := getConfig(c) + if err != nil { + return err + } + + // function to check whether a peer is already in the list. + combine := func(lists ...[]*config.BootstrapPeer) []*config.BootstrapPeer { + + set := map[string]struct{}{} + final := []*config.BootstrapPeer{} + + for _, list := range lists { + for _, peer := range list { + // if already in the set, continue + _, found := set[peer.String()] + if found { + continue + } + + set[peer.String()] = struct{}{} + final = append(final, peer) + } + } + return final + } + + // combine both lists, removing dups. + cfg.Bootstrap = combine(cfg.Bootstrap, toAdd) + if err := writeConfig(c, cfg); err != nil { + return err + } + + for _, bp := range toAdd { + u.POut("added %s\n", bp) + } + return nil +} + +func bootstrapListCmd(c *commander.Command, inp []string) error { + + cfg, err := getConfig(c) + if err != nil { + return err + } + + for _, bp := range cfg.Bootstrap { + u.POut("%s\n", bp) + } + + return nil +} + +func bootstrapInputToPeers(input []string) ([]*config.BootstrapPeer, error) { + split := func(addr string) (string, string) { + idx := strings.LastIndex(addr, "/") + if idx == -1 { + return "", addr + } + return addr[:idx], addr[idx+1:] + } + + peers := []*config.BootstrapPeer{} + for _, addr := range input { + addrS, peeridS := split(addr) + + // make sure addrS parses as a multiaddr. + if len(addrS) > 0 { + maddr, err := ma.NewMultiaddr(addrS) + if err != nil { + return nil, err + } + + addrS = maddr.String() + } + + // make sure idS parses as a peer.ID + peerid, err := mh.FromB58String(peeridS) + if err != nil { + return nil, err + } + + // construct config entry + peers = append(peers, &config.BootstrapPeer{ + Address: addrS, + PeerID: peer.ID(peerid).Pretty(), + }) + } + return peers, nil +} + +const bootstrapSecurityWarning = ` +SECURITY WARNING: + +The bootstrap command manipulates the "bootstrap list", which contains +the addresses of bootstrap nodes. These are the *trusted peers* from +which to learn about other peers in the network. Only edit this list +if you understand the risks of adding or removing nodes from this list. + +` diff --git a/cmd/ipfs/cat.go b/cmd/ipfs/cat.go new file mode 100644 index 000000000..168a4841e --- /dev/null +++ b/cmd/ipfs/cat.go @@ -0,0 +1,26 @@ +package main + +import ( + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag" + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" + "github.com/jbenet/go-ipfs/core/commands" +) + +var cmdIpfsCat = &commander.Command{ + UsageLine: "cat", + Short: "Show ipfs object data.", + Long: `ipfs cat - Show ipfs object data. + + Retrieves the object named by and displays the Data + it contains. +`, + Run: catCmd, + Flag: *flag.NewFlagSet("ipfs-cat", flag.ExitOnError), +} + +var catCmd = makeCommand(command{ + name: "cat", + args: 1, + flags: nil, + cmdFn: commands.Cat, +}) diff --git a/cmd/ipfs/commands.go b/cmd/ipfs/commands.go new file mode 100644 index 000000000..cc0ed089a --- /dev/null +++ b/cmd/ipfs/commands.go @@ -0,0 +1,74 @@ +package main + +import ( + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" + u "github.com/jbenet/go-ipfs/util" + "strings" + "time" +) + +var cmdIpfsCommands = &commander.Command{ + UsageLine: "commands", + Short: "List all available commands.", + Long: `ipfs commands - List all available commands. + + Lists all available commands (and sub-commands) and exits. + `, + Run: commandsCmd, + Subcommands: []*commander.Command{ + cmdIpfsCommandsHelp, + }, +} + +func commandsCmd(c *commander.Command, args []string) error { + var listCmds func(c *commander.Command) + listCmds = func(c *commander.Command) { + u.POut("%s\n", c.FullSpacedName()) + for _, sc := range c.Subcommands { + listCmds(sc) + } + } + + listCmds(c.Parent) + return nil +} + +var cmdIpfsCommandsHelp = &commander.Command{ + UsageLine: "help", + Short: "List all available commands' help pages.", + Long: `ipfs commands help - List all available commands's help pages. + + Shows the pages of all available commands (and sub-commands) and exits. + Outputs a markdown document. + `, + Run: commandsHelpCmd, +} + +func commandsHelpCmd(c *commander.Command, args []string) error { + u.POut(referenceHeaderMsg) + u.POut("Generated on %s.\n\n", time.Now().UTC().Format("2006-01-02")) + + var printCmds func(*commander.Command, int) + printCmds = func(c *commander.Command, level int) { + u.POut("%s ", strings.Repeat("#", level)) + u.POut("%s\n\n", c.FullSpacedName()) + u.POut("```\n") + u.POut("%s\n", c.Long) + u.POut("```\n\n") + + for _, sc := range c.Subcommands { + printCmds(sc, level+1) + } + } + + printCmds(c.Parent.Parent, 1) + return nil +} + +const referenceHeaderMsg = ` +# ipfs command reference + +This document lists every ipfs command (including subcommands), along with +its help page. It can be viewed by running 'ipfs commands help'. + +` diff --git a/cmd/ipfs/config.go b/cmd/ipfs/config.go new file mode 100644 index 000000000..f1f8be92e --- /dev/null +++ b/cmd/ipfs/config.go @@ -0,0 +1,143 @@ +package main + +import ( + "errors" + "fmt" + "io" + "os" + "os/exec" + + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag" + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" + config "github.com/jbenet/go-ipfs/config" + u "github.com/jbenet/go-ipfs/util" +) + +var cmdIpfsConfig = &commander.Command{ + UsageLine: "config", + Short: "Get/Set ipfs config values", + Long: `ipfs config [] [] - Get/Set ipfs config values. + + ipfs config - Get value of + ipfs config - Set value of to + ipfs config --show - Show config file + ipfs config --edit - Edit config file in $EDITOR + +Examples: + + Get the value of the 'datastore.path' key: + + ipfs config datastore.path + + Set the value of the 'datastore.path' key: + + ipfs config datastore.path ~/.go-ipfs/datastore + +`, + Run: configCmd, + Flag: *flag.NewFlagSet("ipfs-config", flag.ExitOnError), +} + +func init() { + cmdIpfsConfig.Flag.Bool("edit", false, "Edit config file in $EDITOR") + cmdIpfsConfig.Flag.Bool("show", false, "Show config file") +} + +func configCmd(c *commander.Command, inp []string) error { + + confdir, err := getConfigDir(c.Parent) + if err != nil { + return err + } + + filename, err := config.Filename(confdir) + if err != nil { + return err + } + + // if editing, open the editor + if c.Flag.Lookup("edit").Value.Get().(bool) { + return configEditor(filename) + } + + // if showing, cat the file + if c.Flag.Lookup("show").Value.Get().(bool) { + return configCat(filename) + } + + if len(inp) == 0 { + // "ipfs config" run without parameters + u.POut(c.Long) + return nil + } + + // Getter (1 param) + if len(inp) == 1 { + value, err := config.ReadConfigKey(filename, inp[0]) + if err != nil { + return fmt.Errorf("Failed to get config value: %s", err) + } + + strval, ok := value.(string) + if ok { + u.POut("%s\n", strval) + return nil + } + + if err := config.Encode(os.Stdout, value); err != nil { + return fmt.Errorf("Failed to encode config value: %s", err) + } + u.POut("\n") + return nil + } + + // Setter (>1 params) + err = config.WriteConfigKey(filename, inp[0], inp[1]) + if err != nil { + return fmt.Errorf("Failed to set config value: %s", err) + } + + return nil +} + +func configCat(filename string) error { + + file, err := os.Open(filename) + if err != nil { + return err + } + defer file.Close() + + if _, err = io.Copy(os.Stdout, file); err != nil { + return err + } + u.POut("\n") + return nil +} + +func configEditor(filename string) error { + + editor := os.Getenv("EDITOR") + if editor == "" { + return errors.New("ENV variable $EDITOR not set") + } + + cmd := exec.Command("sh", "-c", editor+" "+filename) + cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr + return cmd.Run() +} + +func writeConfig(c *commander.Command, cfg *config.Config) error { + + confdir, err := getConfigDir(c) + if err != nil { + return err + } + + filename, err := config.Filename(confdir) + if err != nil { + return err + } + + return config.WriteConfigFile(filename, cfg) +} diff --git a/cmd/ipfs/diag.go b/cmd/ipfs/diag.go new file mode 100644 index 000000000..657ddae17 --- /dev/null +++ b/cmd/ipfs/diag.go @@ -0,0 +1,32 @@ +package main + +import ( + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag" + + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" + "github.com/jbenet/go-ipfs/core/commands" +) + +var cmdIpfsDiag = &commander.Command{ + UsageLine: "net-diag", + Short: "Generate a diagnostics report", + Long: `ipfs net-diag - Generate a diagnostics report. + + Sends out a message to each node in the network recursively + requesting a listing of data about them including number of + connected peers and latencies between them. +`, + Run: diagCmd, + Flag: *flag.NewFlagSet("ipfs-net-diag", flag.ExitOnError), +} + +func init() { + cmdIpfsDiag.Flag.Bool("raw", false, "print raw json output") +} + +var diagCmd = makeCommand(command{ + name: "diag", + args: 0, + flags: []string{"raw"}, + cmdFn: commands.Diag, +}) diff --git a/cmd/ipfs/equinox.yaml b/cmd/ipfs/equinox.yaml new file mode 100644 index 000000000..9e764e05c --- /dev/null +++ b/cmd/ipfs/equinox.yaml @@ -0,0 +1,6 @@ +--- +equinox-account: CHANGEME +equinox-secret: CHANGEME +equinox-app: CHANGEME +channel: stable +private-key: equinox-priv diff --git a/cmd/ipfs/gen.go b/cmd/ipfs/gen.go new file mode 100644 index 000000000..e6a957dac --- /dev/null +++ b/cmd/ipfs/gen.go @@ -0,0 +1,72 @@ +package main + +import ( + "fmt" + "os" + + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" + "github.com/jbenet/go-ipfs/core/commands" + "github.com/jbenet/go-ipfs/daemon" + u "github.com/jbenet/go-ipfs/util" +) + +// command is the descriptor of an ipfs daemon command. +// Used with makeCommand to proxy over commands via the daemon. +type command struct { + name string + args int + flags []string + online bool + cmdFn commands.CmdFunc + argFilter func(string) (string, error) +} + +// commanderFunc is a function that can be passed into the Commander library as +// a command handler. Defined here because commander lacks this definition. +type commanderFunc func(*commander.Command, []string) error + +// makeCommand Wraps a commands.CmdFunc so that it may be safely run by the +// commander library +func makeCommand(cmdDesc command) commanderFunc { + return func(c *commander.Command, inp []string) error { + if len(inp) < cmdDesc.args { + u.POut(c.Long) + return nil + } + confdir, err := getConfigDir(c) + if err != nil { + return err + } + + cmd := daemon.NewCommand() + cmd.Command = cmdDesc.name + if cmdDesc.argFilter != nil { + for _, a := range inp { + s, err := cmdDesc.argFilter(a) + if err != nil { + return err + } + cmd.Args = append(cmd.Args, s) + } + } else { + cmd.Args = inp + } + + for _, a := range cmdDesc.flags { + cmd.Opts[a] = c.Flag.Lookup(a).Value.Get() + } + + err = daemon.SendCommand(cmd, confdir) + if err != nil { + log.Info("Executing command locally: %s", err) + // Do locally + n, err := localNode(confdir, cmdDesc.online) + if err != nil { + return fmt.Errorf("Local node creation failed: %v", err) + } + + return cmdDesc.cmdFn(n, cmd.Args, cmd.Opts, os.Stdout) + } + return nil + } +} diff --git a/cmd/ipfs/init.go b/cmd/ipfs/init.go new file mode 100644 index 000000000..2c4446c58 --- /dev/null +++ b/cmd/ipfs/init.go @@ -0,0 +1,150 @@ +package main + +import ( + "encoding/base64" + "errors" + "os" + "path/filepath" + + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag" + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" + config "github.com/jbenet/go-ipfs/config" + ci "github.com/jbenet/go-ipfs/crypto" + peer "github.com/jbenet/go-ipfs/peer" + updates "github.com/jbenet/go-ipfs/updates" + u "github.com/jbenet/go-ipfs/util" +) + +var cmdIpfsInit = &commander.Command{ + UsageLine: "init", + Short: "Initialize ipfs local configuration", + Long: `ipfs init + + Initializes ipfs configuration files and generates a + new keypair. +`, + Run: initCmd, + Flag: *flag.NewFlagSet("ipfs-init", flag.ExitOnError), +} + +func init() { + cmdIpfsInit.Flag.Int("b", 4096, "number of bits for keypair") + cmdIpfsInit.Flag.String("p", "", "passphrase for encrypting keys") + cmdIpfsInit.Flag.Bool("f", false, "force overwrite of existing config") + cmdIpfsInit.Flag.String("d", "", "Change default datastore location") +} + +func initCmd(c *commander.Command, inp []string) error { + configpath, err := getConfigDir(c.Parent) + if err != nil { + return err + } + + u.POut("initializing ipfs node at %s\n", configpath) + filename, err := config.Filename(configpath) + if err != nil { + return errors.New("Couldn't get home directory path") + } + + dspath, ok := c.Flag.Lookup("d").Value.Get().(string) + if !ok { + return errors.New("failed to parse datastore flag") + } + + fi, err := os.Lstat(filename) + force, ok := c.Flag.Lookup("f").Value.Get().(bool) + if !ok { + return errors.New("failed to parse force flag") + } + if fi != nil || (err != nil && !os.IsNotExist(err)) { + if !force { + return errors.New("ipfs configuration file already exists!\nReinitializing would overwrite your keys.\n(use -f to force overwrite)") + } + } + cfg := new(config.Config) + + cfg.Datastore = config.Datastore{} + if len(dspath) == 0 { + dspath, err = config.DataStorePath("") + if err != nil { + return err + } + } + cfg.Datastore.Path = dspath + cfg.Datastore.Type = "leveldb" + + // Construct the data store if missing + if err := os.MkdirAll(dspath, os.ModePerm); err != nil { + return err + } + + // Check the directory is writeable + if f, err := os.Create(filepath.Join(dspath, "._check_writeable")); err == nil { + os.Remove(f.Name()) + } else { + return errors.New("Datastore '" + dspath + "' is not writeable") + } + + cfg.Identity = config.Identity{} + + // setup the node addresses. + cfg.Addresses = config.Addresses{ + Swarm: "/ip4/0.0.0.0/tcp/4001", + API: "/ip4/127.0.0.1/tcp/5001", + } + + // setup the node mount points. + cfg.Mounts = config.Mounts{ + IPFS: "/ipfs", + IPNS: "/ipns", + } + + nbits, ok := c.Flag.Lookup("b").Value.Get().(int) + if !ok { + return errors.New("failed to get bits flag") + } + if nbits < 1024 { + return errors.New("Bitsize less than 1024 is considered unsafe.") + } + + u.POut("generating key pair\n") + sk, pk, err := ci.GenerateKeyPair(ci.RSA, nbits) + if err != nil { + return err + } + + // currently storing key unencrypted. in the future we need to encrypt it. + // TODO(security) + skbytes, err := sk.Bytes() + if err != nil { + return err + } + cfg.Identity.PrivKey = base64.StdEncoding.EncodeToString(skbytes) + + id, err := peer.IDFromPubKey(pk) + if err != nil { + return err + } + cfg.Identity.PeerID = id.Pretty() + + // Use these hardcoded bootstrap peers for now. + cfg.Bootstrap = []*config.BootstrapPeer{ + &config.BootstrapPeer{ + // mars.i.ipfs.io + PeerID: "QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", + Address: "/ip4/104.131.131.82/tcp/4001", + }, + } + + // tracking ipfs version used to generate the init folder and adding update checker default setting. + cfg.Version = config.Version{ + Check: "error", + Current: updates.Version, + } + + err = config.WriteConfigFile(filename, cfg) + if err != nil { + return err + } + return nil +} diff --git a/cmd/ipfs/ipfs.go b/cmd/ipfs/ipfs.go new file mode 100644 index 000000000..9ce5d7faf --- /dev/null +++ b/cmd/ipfs/ipfs.go @@ -0,0 +1,220 @@ +package main + +import ( + "errors" + "fmt" + "os" + "runtime/pprof" + + 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" + ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" + + config "github.com/jbenet/go-ipfs/config" + core "github.com/jbenet/go-ipfs/core" + daemon "github.com/jbenet/go-ipfs/daemon" + updates "github.com/jbenet/go-ipfs/updates" + u "github.com/jbenet/go-ipfs/util" +) + +// The IPFS command tree. It is an instance of `commander.Command`. +var CmdIpfs = &commander.Command{ + UsageLine: "ipfs [] []", + Short: "global versioned p2p merkledag file system", + Long: `ipfs - global versioned p2p merkledag file system + +Basic commands: + + init Initialize ipfs local configuration. + add Add an object to ipfs. + cat Show ipfs object data. + ls List links from an object. + refs List link hashes from an object. + +Tool commands: + + config Manage configuration. + update Download and apply go-ipfs updates. + version Show ipfs version information. + commands List all available commands. + +Advanced Commands: + + mount Mount an ipfs read-only mountpoint. + serve Serve an interface to ipfs. + net-diag Print network diagnostic + +Plumbing commands: + + block Interact with raw blocks in the datastore + object Interact with raw dag nodes + + +Use "ipfs help " for more information about a command. +`, + Run: ipfsCmd, + Subcommands: []*commander.Command{ + cmdIpfsAdd, + cmdIpfsCat, + cmdIpfsLs, + cmdIpfsRefs, + cmdIpfsConfig, + cmdIpfsVersion, + cmdIpfsCommands, + cmdIpfsMount, + cmdIpfsInit, + cmdIpfsServe, + cmdIpfsRun, + cmdIpfsName, + cmdIpfsBootstrap, + cmdIpfsDiag, + cmdIpfsBlock, + cmdIpfsObject, + cmdIpfsUpdate, + cmdIpfsLog, + cmdIpfsPin, + cmdIpfsTour, + }, + Flag: *flag.NewFlagSet("ipfs", flag.ExitOnError), +} + +// log is the command logger +var log = u.Logger("cmd/ipfs") + +func init() { + config, err := config.PathRoot() + if err != nil { + fmt.Fprintln(os.Stderr, "Failure initializing the default Config Directory: ", err) + os.Exit(1) + } + CmdIpfs.Flag.String("c", config, "specify config directory") +} + +func ipfsCmd(c *commander.Command, args []string) error { + u.POut(c.Long) + return nil +} + +func main() { + // 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() + } + + err := CmdIpfs.Dispatch(os.Args[1:]) + if err != nil { + if len(err.Error()) > 0 { + fmt.Fprintf(os.Stderr, "ipfs %s: %v\n", os.Args[1], err) + } + os.Exit(1) + } + return +} + +// localNode constructs a node +func localNode(confdir string, online bool) (*core.IpfsNode, error) { + filename, err := config.Filename(confdir) + if err != nil { + return nil, err + } + + cfg, err := config.Load(filename) + if err != nil { + return nil, err + } + + if err := updates.CliCheckForUpdates(cfg, filename); err != nil { + return nil, err + } + + return core.NewIpfsNode(cfg, online) +} + +// Gets the config "-c" flag from the command, or returns +// the default configuration root directory +func getConfigDir(c *commander.Command) (string, error) { + + // use the root cmd (that's where config is specified) + for ; c.Parent != nil; c = c.Parent { + } + + // flag should be defined on root. + param := c.Flag.Lookup("c").Value.Get().(string) + if param != "" { + return u.TildeExpansion(param) + } + + return config.PathRoot() +} + +func getConfig(c *commander.Command) (*config.Config, error) { + confdir, err := getConfigDir(c) + if err != nil { + return nil, err + } + + filename, err := config.Filename(confdir) + if err != nil { + return nil, err + } + + return config.Load(filename) +} + +// 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) { + rootCmd := c + for ; rootCmd.Parent != nil; rootCmd = rootCmd.Parent { + } + + cc.configDir, err = getConfigDir(rootCmd) + 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 +} diff --git a/cmd/ipfs/log.go b/cmd/ipfs/log.go new file mode 100644 index 000000000..255b7c263 --- /dev/null +++ b/cmd/ipfs/log.go @@ -0,0 +1,29 @@ +package main + +import ( + 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" + "github.com/jbenet/go-ipfs/core/commands" +) + +var cmdIpfsLog = &commander.Command{ + UsageLine: "log ", + Short: "switch logging levels of a running daemon", + Long: `ipfs log - switch logging levels of a running daemon + + is a the subsystem logging identifier. Use * for all subsystems. + is one of: debug, info, notice, warning, error, critical + +ipfs log is a utility command used to change the logging output of a running daemon. +`, + Run: logCmd, + Flag: *flag.NewFlagSet("ipfs-log", flag.ExitOnError), +} + +var logCmd = makeCommand(command{ + name: "log", + args: 2, + flags: nil, + online: true, + cmdFn: commands.Log, +}) diff --git a/cmd/ipfs/ls.go b/cmd/ipfs/ls.go new file mode 100644 index 000000000..0a2e8aff9 --- /dev/null +++ b/cmd/ipfs/ls.go @@ -0,0 +1,29 @@ +package main + +import ( + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag" + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" + "github.com/jbenet/go-ipfs/core/commands" +) + +var cmdIpfsLs = &commander.Command{ + UsageLine: "ls", + Short: "List links from an object.", + Long: `ipfs ls - List links from an object. + + Retrieves the object named by and displays the links + it contains, with the following format: + + + +`, + Run: lsCmd, + Flag: *flag.NewFlagSet("ipfs-ls", flag.ExitOnError), +} + +var lsCmd = makeCommand(command{ + name: "ls", + args: 1, + flags: nil, + cmdFn: commands.Ls, +}) diff --git a/cmd/ipfs/mount_unix.go b/cmd/ipfs/mount_unix.go new file mode 100644 index 000000000..84fbc9cf6 --- /dev/null +++ b/cmd/ipfs/mount_unix.go @@ -0,0 +1,94 @@ +// +build linux darwin freebsd + +package main + +import ( + "fmt" + + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag" + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" + + core "github.com/jbenet/go-ipfs/core" + ipns "github.com/jbenet/go-ipfs/fuse/ipns" + rofs "github.com/jbenet/go-ipfs/fuse/readonly" +) + +var cmdIpfsMount = &commander.Command{ + UsageLine: "mount", + Short: "Mount an ipfs read-only mountpoint.", + Long: `ipfs mount - Mount an ipfs read-only mountpoint. + + Mount ipfs at a read-only mountpoint on the OS. All ipfs objects + will be accessible under that directory. Note that the root will + not be listable, as it is virtual. Accessing known paths directly. + +`, + Run: mountCmd, + Flag: *flag.NewFlagSet("ipfs-mount", flag.ExitOnError), +} + +func init() { + cmdIpfsMount.Flag.String("f", "", "specify a mountpoint for ipfs") + cmdIpfsMount.Flag.String("n", "", "specify a mountpoint for ipns") +} + +func mountCmd(c *commander.Command, inp []string) error { + + cc, err := setupCmdContext(c, true) + if err != nil { + return err + } + defer cc.daemon.Close() + + // update fsdir with flag. + fsdir := cc.node.Config.Mounts.IPFS + if val, ok := c.Flag.Lookup("f").Value.Get().(string); ok && val != "" { + fsdir = val + } + fsdone := mountIpfs(cc.node, fsdir) + + // get default mount points + nsdir := cc.node.Config.Mounts.IPNS + if val, ok := c.Flag.Lookup("n").Value.Get().(string); ok && val != "" { + nsdir = val + } + nsdone := mountIpns(cc.node, nsdir, fsdir) + + // wait till mounts are done. + err1 := <-fsdone + err2 := <-nsdone + + if err1 != nil { + return err1 + } + return err2 +} + +func mountIpfs(node *core.IpfsNode, fsdir string) <-chan error { + done := make(chan error) + fmt.Printf("mounting ipfs at %s\n", fsdir) + + go func() { + err := rofs.Mount(node, fsdir) + done <- err + close(done) + }() + + return done +} + +func mountIpns(node *core.IpfsNode, nsdir, fsdir string) <-chan error { + if nsdir == "" { + return nil + } + done := make(chan error) + fmt.Printf("mounting ipns at %s\n", nsdir) + + go func() { + err := ipns.Mount(node, nsdir, fsdir) + done <- err + close(done) + }() + + return done +} diff --git a/cmd/ipfs/mount_windows.go b/cmd/ipfs/mount_windows.go new file mode 100644 index 000000000..aabf4b4ff --- /dev/null +++ b/cmd/ipfs/mount_windows.go @@ -0,0 +1,19 @@ +package main + +import ( + "errors" + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag" + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" +) + +var cmdIpfsMount = &commander.Command{ + UsageLine: "mount", + Short: "Mount an ipfs read-only mountpoint.", + Long: `Not yet implemented on windows.`, + Run: mountCmd, + Flag: *flag.NewFlagSet("ipfs-mount", flag.ExitOnError), +} + +func mountCmd(c *commander.Command, inp []string) error { + return errors.New("mount not yet implemented on windows") +} diff --git a/cmd/ipfs/name.go b/cmd/ipfs/name.go new file mode 100644 index 000000000..7021fe612 --- /dev/null +++ b/cmd/ipfs/name.go @@ -0,0 +1,57 @@ +package main + +import ( + "fmt" + + 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" +) + +var cmdIpfsName = &commander.Command{ + UsageLine: "name [publish | resolve]", + Short: "ipfs namespace (ipns) tool", + Long: `ipfs name - Get/Set ipfs config values. + + ipfs name publish [] - Assign the to + ipfs name resolve [] - Resolve the value of + +IPNS is a PKI namespace, where names are the hashes of public keys, and +the private key enables publishing new (signed) values. In both publish +and resolve, the default value of is your own identity public key. + + +Examples: + +Publish a to your identity name: + + > ipfs name publish QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy + published name QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n to QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy + +Publish a to another public key: + + > ipfs name publish QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy + published name QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n to QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy + +Resolve the value of your identity: + + > ipfs name resolve + QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy + +Resolve te value of another name: + + > ipfs name resolve QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n + QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy + +`, + Run: nameCmd, + Flag: *flag.NewFlagSet("ipfs-name", flag.ExitOnError), + Subcommands: []*commander.Command{ + cmdIpfsPub, + cmdIpfsResolve, + }, +} + +func nameCmd(c *commander.Command, args []string) error { + fmt.Println(c.Long) + return nil +} diff --git a/cmd/ipfs/objects.go b/cmd/ipfs/objects.go new file mode 100644 index 000000000..c2092ebf0 --- /dev/null +++ b/cmd/ipfs/objects.go @@ -0,0 +1,112 @@ +package main + +import ( + 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" + "github.com/jbenet/go-ipfs/core/commands" +) + +var cmdIpfsObject = &commander.Command{ + UsageLine: "object", + Short: "interact with ipfs objects", + Long: `ipfs object - interact with ipfs objects + + ipfs object data - return the data for this key as raw bytes + ipfs object links - lists (the keys of ?) the links this key points to + ipfs object get - output dag object to stdout + ipfs object put - add dag object from stdin + +ipfs object is a plumbing command used to manipulate dag objects directly. +- is a base58 encoded multihash. +- It reads from stdin or writes to stdout. +- It accepts multiple encodings: --encoding=[ protobuf, json, ... ]`, + Subcommands: []*commander.Command{ + cmdIpfsObjectData, + cmdIpfsObjectLinks, + cmdIpfsObjectGet, + cmdIpfsObjectPut, + }, + Flag: *flag.NewFlagSet("ipfs-object", flag.ExitOnError), +} + +var cmdIpfsObjectData = &commander.Command{ + UsageLine: "data ", + Short: "data outputs the raw bytes named by ", + Long: `ipfs data - data outputs the raw bytes named by + +ipfs data is a plumbing command for retreiving the raw bytes stored in a dag node. +It outputs to stdout, and is a base58 encoded multihash.`, + Run: makeCommand(command{ + name: "objectData", + args: 1, + flags: nil, + online: true, + cmdFn: commands.ObjectData, + }), +} + +var cmdIpfsObjectLinks = &commander.Command{ + UsageLine: "links ", + Short: "outputs the links pointed to by ", + Long: `ipfs links - outputs the links pointed to by + +ipfs block get is a plumbing command for retreiving raw ipfs blocks. +It outputs to stdout, and is a base58 encoded multihash.`, + Run: makeCommand(command{ + name: "objectLinks", + args: 1, + flags: nil, + online: true, + cmdFn: commands.ObjectLinks, + }), +} + +func init() { + cmdIpfsObjectGet.Flag.String("encoding", "json", "the encoding to use..") + cmdIpfsObjectPut.Flag.String("encoding", "json", "the encoding to use..") +} + +var cmdIpfsObjectGet = &commander.Command{ + UsageLine: "get ", + Short: "get and serialize the dag node named by ", + Long: `ipfs get - get and output the dag node named by + +ipfs object get is a plumbing command for retreiving dag nodes. +It serialize the dag node to the format specified by the format flag. +It outputs to stdout, and is a base58 encoded multihash. + +Formats: + +This command outputs and accepts data in a variety of encodings: protobuf, json, etc. +Use the --encoding flag +`, + Run: makeCommand(command{ + name: "blockGet", + args: 1, + flags: []string{"encoding"}, + online: true, + cmdFn: commands.ObjectGet, + }), +} + +var cmdIpfsObjectPut = &commander.Command{ + UsageLine: "put", + Short: "store stdin as a dag object, outputs ", + Long: `ipfs put - store stdin as a dag object, outputs + +ipfs object put is a plumbing command for storing dag nodes. +It serialize the dag node to the format specified by the format flag. +It reads from stding, and is a base58 encoded multihash. + +Formats: + +This command outputs and accepts data in a variety of encodings: protobuf, json, etc. +Use the --encoding flag`, + Run: makeCommand(command{ + name: "blockPut", + args: 0, + flags: []string{"encoding"}, + online: true, + cmdFn: commands.ObjectPut, + }), +} diff --git a/cmd/ipfs/pin.go b/cmd/ipfs/pin.go new file mode 100644 index 000000000..5b331f190 --- /dev/null +++ b/cmd/ipfs/pin.go @@ -0,0 +1,62 @@ +package main + +import ( + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag" + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" + "github.com/jbenet/go-ipfs/core/commands" +) + +var cmdIpfsPin = &commander.Command{ + UsageLine: "pin", + Short: "", + Long: `ipfs pin [add|rm] - object pinning commands +`, + Subcommands: []*commander.Command{ + cmdIpfsSubPin, + cmdIpfsSubUnpin, + }, +} + +var cmdIpfsSubPin = &commander.Command{ + UsageLine: "add", + Short: "pin an ipfs object to local storage.", + Long: `ipfs pin add - pin ipfs object to local storage. + + Retrieves the object named by and stores it locally + on disk. +`, + Run: pinSubCmd, + Flag: *flag.NewFlagSet("ipfs-pin", flag.ExitOnError), +} + +var pinSubCmd = makeCommand(command{ + name: "pin", + args: 1, + flags: []string{"r", "d"}, + cmdFn: commands.Pin, +}) + +var cmdIpfsSubUnpin = &commander.Command{ + UsageLine: "rm", + Short: "unpin an ipfs object from local storage.", + Long: `ipfs pin rm - unpin ipfs object from local storage. + + Removes the pin from the given object allowing it to be garbage + collected if needed. +`, + Run: unpinSubCmd, + Flag: *flag.NewFlagSet("ipfs-unpin", flag.ExitOnError), +} + +var unpinSubCmd = makeCommand(command{ + name: "unpin", + args: 1, + flags: []string{"r"}, + cmdFn: commands.Unpin, +}) + +func init() { + cmdIpfsSubPin.Flag.Bool("r", false, "pin objects recursively") + cmdIpfsSubPin.Flag.Int("d", 1, "recursive depth") + cmdIpfsSubUnpin.Flag.Bool("r", false, "unpin objects recursively") +} diff --git a/cmd/ipfs/publish.go b/cmd/ipfs/publish.go new file mode 100644 index 000000000..041da0028 --- /dev/null +++ b/cmd/ipfs/publish.go @@ -0,0 +1,41 @@ +package main + +import ( + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag" + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" + "github.com/jbenet/go-ipfs/core/commands" +) + +var cmdIpfsPub = &commander.Command{ + UsageLine: "publish", + Short: "publish a to ipns.", + Long: `ipfs publish [] - publish a to ipns. + +IPNS is a PKI namespace, where names are the hashes of public keys, and +the private key enables publishing new (signed) values. In publish, the +default value of is your own identity public key. + +Examples: + +Publish a to your identity name: + + > ipfs name publish QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy + published name QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n to QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy + +Publish a to another public key: + + > ipfs name publish QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy + published name QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n to QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy + +`, + Run: pubCmd, + Flag: *flag.NewFlagSet("ipfs-publish", flag.ExitOnError), +} + +var pubCmd = makeCommand(command{ + name: "publish", + args: 1, + flags: nil, + online: true, + cmdFn: commands.Publish, +}) diff --git a/cmd/ipfs/refs.go b/cmd/ipfs/refs.go new file mode 100644 index 000000000..b3aaf85fc --- /dev/null +++ b/cmd/ipfs/refs.go @@ -0,0 +1,36 @@ +package main + +import ( + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag" + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" + commands "github.com/jbenet/go-ipfs/core/commands" +) + +var cmdIpfsRefs = &commander.Command{ + UsageLine: "refs", + Short: "List link hashes from an object.", + Long: `ipfs refs - List link hashes from an object.. + + Retrieves the object named by and displays the link + hashes it contains, with the following format: + + + + Note: list all refs recursively with -r. + +`, + Run: refCmd, + Flag: *flag.NewFlagSet("ipfs-refs", flag.ExitOnError), +} + +func init() { + cmdIpfsRefs.Flag.Bool("r", false, "recursive: list refs recursively") + cmdIpfsRefs.Flag.Bool("u", false, "unique: list each ref only once") +} + +var refCmd = makeCommand(command{ + name: "refs", + args: 1, + flags: []string{"r", "u"}, + cmdFn: commands.Refs, +}) diff --git a/cmd/ipfs/resolve.go b/cmd/ipfs/resolve.go new file mode 100644 index 000000000..9f5107ff8 --- /dev/null +++ b/cmd/ipfs/resolve.go @@ -0,0 +1,42 @@ +package main + +import ( + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag" + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" + "github.com/jbenet/go-ipfs/core/commands" +) + +var cmdIpfsResolve = &commander.Command{ + UsageLine: "resolve", + Short: "resolve an ipns name to a ", + Long: `ipfs resolve [] - Resolve an ipns name to a . + +IPNS is a PKI namespace, where names are the hashes of public keys, and +the private key enables publishing new (signed) values. In resolve, the +default value of is your own identity public key. + + +Examples: + +Resolve the value of your identity: + + > ipfs name resolve + QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy + +Resolve te value of another name: + + > ipfs name resolve QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n + QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy + +`, + Run: resolveCmd, + Flag: *flag.NewFlagSet("ipfs-resolve", flag.ExitOnError), +} + +var resolveCmd = makeCommand(command{ + name: "resolve", + args: 0, + flags: nil, + online: true, + cmdFn: commands.Resolve, +}) diff --git a/cmd/ipfs/run.go b/cmd/ipfs/run.go new file mode 100644 index 000000000..b651ca9d9 --- /dev/null +++ b/cmd/ipfs/run.go @@ -0,0 +1,36 @@ +package main + +import ( + "os" + "os/signal" + "syscall" + + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag" + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" +) + +var cmdIpfsRun = &commander.Command{ + UsageLine: "run", + Short: "run local ifps node.", + Long: `run a local ipfs node with no other interface. +`, + Run: runCmd, + Flag: *flag.NewFlagSet("ipfs-run", flag.ExitOnError), +} + +func runCmd(c *commander.Command, inp []string) error { + cc, err := setupCmdContext(c, true) + if err != nil { + return err + } + + sigc := make(chan os.Signal, 1) + signal.Notify(sigc, syscall.SIGHUP, syscall.SIGINT, + syscall.SIGTERM, syscall.SIGQUIT) + + // wait until we get a signal to exit. + <-sigc + + cc.daemon.Close() + return nil +} diff --git a/cmd/ipfs/serve.go b/cmd/ipfs/serve.go new file mode 100644 index 000000000..fda3b3f22 --- /dev/null +++ b/cmd/ipfs/serve.go @@ -0,0 +1,49 @@ +package main + +import ( + "fmt" + + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag" + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" + ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" + + h "github.com/jbenet/go-ipfs/server/http" +) + +var cmdIpfsServe = &commander.Command{ + UsageLine: "serve", + Short: "Serve an interface to ipfs", + Subcommands: []*commander.Command{ + cmdIpfsServeHTTP, + }, + Flag: *flag.NewFlagSet("ipfs-serve", flag.ExitOnError), +} + +var cmdIpfsServeHTTP = &commander.Command{ + UsageLine: "http", + Short: "Serve an HTTP API", + Long: `ipfs serve http - Serve an http gateway into ipfs.`, + Run: serveHTTPCmd, + Flag: *flag.NewFlagSet("ipfs-serve-http", flag.ExitOnError), +} + +func init() { + cmdIpfsServeHTTP.Flag.String("address", "/ip4/127.0.0.1/tcp/8080", "Listen Address") +} + +func serveHTTPCmd(c *commander.Command, _ []string) error { + cc, err := setupCmdContext(c, true) + if err != nil { + return err + } + defer cc.daemon.Close() + + address := c.Flag.Lookup("address").Value.Get().(string) + maddr, err := ma.NewMultiaddr(address) + if err != nil { + return err + } + + fmt.Printf("Serving on %s\n", address) + return h.Serve(maddr, cc.node) +} diff --git a/cmd/ipfs/tour.go b/cmd/ipfs/tour.go new file mode 100644 index 000000000..0656625e8 --- /dev/null +++ b/cmd/ipfs/tour.go @@ -0,0 +1,134 @@ +// +build linux darwin freebsd + +package main + +import ( + "fmt" + + config "github.com/jbenet/go-ipfs/config" + tour "github.com/jbenet/go-ipfs/tour" + + commander "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" +) + +var cmdIpfsTour = &commander.Command{ + UsageLine: "tour []", + Short: "Take the IPFS Tour.", + Long: `ipfs tour - Take the IPFS Tour. + + ipfs tour [] - Show tour topic. Default to current. + ipfs tour next - Show the next tour topic. + ipfs tour list - Show a list of topics. + ipfs tour restart - Restart the tour. + +This is a tour that takes you through various IPFS concepts, +features, and tools to make sure you get up to speed with +IPFS very quickly. To start, run: + + ipfs tour +`, + Run: tourCmd, + Subcommands: []*commander.Command{ + cmdIpfsTourNext, + cmdIpfsTourList, + cmdIpfsTourRestart, + }, +} + +var cmdIpfsTourNext = &commander.Command{ + UsageLine: "next", + Short: "Show the next IPFS Tour topic.", + Run: tourNextCmd, +} + +var cmdIpfsTourList = &commander.Command{ + UsageLine: "list", + Short: "Show a list of IPFS Tour topics.", + Run: tourListCmd, +} + +var cmdIpfsTourRestart = &commander.Command{ + UsageLine: "restart", + Short: "Restart the IPFS Tour.", + Run: tourRestartCmd, +} + +func tourCmd(c *commander.Command, inp []string) error { + cfg, err := getConfig(c) + if err != nil { + return err + } + + topic := tour.TopicID(cfg.Tour.Last) + if len(inp) > 0 { + topic = tour.TopicID(inp[0]) + } + return tourShow(topic) +} + +func tourNextCmd(c *commander.Command, _ []string) error { + cfg, err := getConfig(c) + if err != nil { + return err + } + + topic := tour.NextTopic(tour.TopicID(cfg.Tour.Last)) + if err := tourShow(topic); err != nil { + return err + } + + // if topic didn't change (last) done + if string(topic) == cfg.Tour.Last { + return nil + } + + // topic changed, not last. write it out. + cfg.Tour.Last = string(topic) + return writeConfig(c, cfg) +} + +func tourListCmd(c *commander.Command, _ []string) error { + cfg, err := getConfig(c) + if err != nil { + return err + } + lastid := tour.TopicID(cfg.Tour.Last) + + for _, id := range tour.IDs { + c := ' ' + switch { + case id == lastid: + c = '*' + case id.LessThan(lastid): + c = '✓' + } + + t := tour.Topics[id] + fmt.Printf("- %c %-5.5s %s\n", c, id, t.Title) + } + return nil +} + +func tourRestartCmd(c *commander.Command, _ []string) error { + cfg, err := getConfig(c) + if err != nil { + return err + } + + cfg.Tour.Last = "" + return writeConfig(c, cfg) +} + +func tourShow(id tour.ID) error { + t, found := tour.Topics[id] + if !found { + return fmt.Errorf("no topic with id: %s", id) + } + + fmt.Printf("Tour %s - %s\n\n%s\n", t.ID, t.Title, t.Text) + return nil +} + +func lastTour(cfg *config.Config) string { + return "" +} diff --git a/cmd/ipfs/update.go b/cmd/ipfs/update.go new file mode 100644 index 000000000..e6d078253 --- /dev/null +++ b/cmd/ipfs/update.go @@ -0,0 +1,62 @@ +package main + +import ( + 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" + "github.com/jbenet/go-ipfs/core/commands" +) + +func init() { + cmdIpfsUpdate.Flag.Bool("force", false, "force shutdown of daemon when updating") +} + +var cmdIpfsUpdate = &commander.Command{ + UsageLine: "update", + Short: "check for updates and apply them", + Long: `ipfs update - check for updates and apply them + + ipfs update - apply + ipfs update check - just check + ipfs update log - list the changelogs + +ipfs update is a utility command used to check for updates and apply them. +I wont even try, @jbenet. You do this much better :)`, + Run: makeCommand(command{ + name: "updateApply", + args: 0, + flags: []string{"force"}, + online: true, + cmdFn: commands.UpdateApply, + }), + Subcommands: []*commander.Command{ + cmdIpfsUpdateCheck, + cmdIpfsUpdateLog, + }, + Flag: *flag.NewFlagSet("ipfs-update", flag.ExitOnError), +} + +var cmdIpfsUpdateCheck = &commander.Command{ + UsageLine: "check", + Short: "", + Long: `ipfs update check `, + Run: makeCommand(command{ + name: "updateCheck", + args: 0, + flags: nil, + online: false, + cmdFn: commands.UpdateCheck, + }), +} + +var cmdIpfsUpdateLog = &commander.Command{ + UsageLine: "log", + Short: "list the last versions and their changelog", + Long: `ipfs updage log - list the last versions and their changelog`, + Run: makeCommand(command{ + name: "updateLog", + args: 0, + flags: nil, + online: false, + cmdFn: commands.UpdateCheck, + }), +} diff --git a/cmd/ipfs/version.go b/cmd/ipfs/version.go new file mode 100644 index 000000000..1c02bf69f --- /dev/null +++ b/cmd/ipfs/version.go @@ -0,0 +1,30 @@ +package main + +import ( + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" + updates "github.com/jbenet/go-ipfs/updates" + u "github.com/jbenet/go-ipfs/util" +) + +var cmdIpfsVersion = &commander.Command{ + UsageLine: "version", + Short: "Show ipfs version information.", + Long: `ipfs version - Show ipfs version information. + + Returns the current version of ipfs and exits. + `, + Run: versionCmd, +} + +func init() { + cmdIpfsVersion.Flag.Bool("number", false, "show only the number") +} + +func versionCmd(c *commander.Command, _ []string) error { + number := c.Flag.Lookup("number").Value.Get().(bool) + if !number { + u.POut("ipfs version ") + } + u.POut("%s\n", updates.Version) + return nil +}