init.go 4.31 KB
Newer Older
1
package main
Matt Bell's avatar
Matt Bell committed
2 3

import (
4
	"bytes"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
5
	"fmt"
6
	"io"
Matt Bell's avatar
Matt Bell committed
7

8
	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9
	assets "github.com/jbenet/go-ipfs/assets"
Matt Bell's avatar
Matt Bell committed
10
	cmds "github.com/jbenet/go-ipfs/commands"
11
	core "github.com/jbenet/go-ipfs/core"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
12
	coreunix "github.com/jbenet/go-ipfs/core/coreunix"
Jeromy's avatar
Jeromy committed
13
	ipns "github.com/jbenet/go-ipfs/fuse/ipns"
14
	config "github.com/jbenet/go-ipfs/repo/config"
15
	fsrepo "github.com/jbenet/go-ipfs/repo/fsrepo"
16
	uio "github.com/jbenet/go-ipfs/unixfs/io"
Matt Bell's avatar
Matt Bell committed
17
	u "github.com/jbenet/go-ipfs/util"
18
	debugerror "github.com/jbenet/go-ipfs/util/debugerror"
Matt Bell's avatar
Matt Bell committed
19 20
)

21 22
const nBitsForKeypairDefault = 4096

Matt Bell's avatar
Matt Bell committed
23
var initCmd = &cmds.Command{
24 25 26 27
	Helptext: cmds.HelpText{
		Tagline:          "Initializes IPFS config file",
		ShortDescription: "Initializes IPFS configuration files and generates a new keypair.",
	},
28

Matt Bell's avatar
Matt Bell committed
29
	Options: []cmds.Option{
30
		cmds.IntOption("bits", "b", "Number of bits to use in the generated RSA private key (defaults to 4096)"),
31
		cmds.BoolOption("force", "f", "Overwrite existing config (if it exists)"),
32 33 34 35 36

		// TODO need to decide whether to expose the override as a file or a
		// directory. That is: should we allow the user to also specify the
		// name of the file?
		// TODO cmds.StringOption("event-logs", "l", "Location for machine-readable event logs"),
Matt Bell's avatar
Matt Bell committed
37
	},
38
	Run: func(req cmds.Request, res cmds.Response) {
39

40
		force, _, err := req.Option("f").Bool() // if !found, it's okay force == false
41
		if err != nil {
42 43
			res.SetError(err, cmds.ErrNormal)
			return
44 45
		}

46
		nBitsForKeypair, bitsOptFound, err := req.Option("b").Int()
47
		if err != nil {
48 49
			res.SetError(err, cmds.ErrNormal)
			return
50
		}
Henry's avatar
Henry committed
51

52
		if !bitsOptFound {
53
			nBitsForKeypair = nBitsForKeypairDefault
54 55
		}

56 57 58 59 60 61 62 63 64
		rpipe, wpipe := io.Pipe()
		go func() {
			defer wpipe.Close()
			if err := doInit(wpipe, req.Context().ConfigRoot, force, nBitsForKeypair); err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}
		}()
		res.SetOutput(rpipe)
65 66
	},
}
Matt Bell's avatar
Matt Bell committed
67

68
var errRepoExists = debugerror.New(`ipfs configuration file already exists!
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
69 70 71 72
Reinitializing would overwrite your keys.
(use -f to force overwrite)
`)

73 74
func initWithDefaults(out io.Writer, repoRoot string) error {
	err := doInit(out, repoRoot, false, nBitsForKeypairDefault)
Brian Tiger Chow's avatar
Brian Tiger Chow committed
75
	return debugerror.Wrap(err)
76 77
}

78
func doInit(out io.Writer, repoRoot string, force bool, nBitsForKeypair int) error {
Henry's avatar
Henry committed
79
	if _, err := fmt.Fprintf(out, "initializing ipfs node at %s\n", repoRoot); err != nil {
80 81
		return err
	}
82

83
	if fsrepo.IsInitialized(repoRoot) && !force {
84
		return errRepoExists
85
	}
Henry's avatar
Henry committed
86

87
	conf, err := config.Init(out, nBitsForKeypair)
88
	if err != nil {
89
		return err
90
	}
Henry's avatar
Henry committed
91

92
	if fsrepo.IsInitialized(repoRoot) {
93
		if err := fsrepo.Remove(repoRoot); err != nil {
94
			return err
95
		}
96
	}
Henry's avatar
Henry committed
97

98
	if err := fsrepo.Init(repoRoot, conf); err != nil {
99
		return err
100
	}
101

102 103
	if err := addDefaultAssets(out, repoRoot); err != nil {
		return err
Jeromy's avatar
Jeromy committed
104
	}
105 106

	return initializeIpnsKeyspace(repoRoot)
107 108
}

109
func addDefaultAssets(out io.Writer, repoRoot string) error {
110
	ctx, cancel := context.WithCancel(context.Background())
111
	defer cancel()
Henry's avatar
Henry committed
112

113 114 115 116
	r := fsrepo.At(repoRoot)
	if err := r.Open(); err != nil { // NB: repo is owned by the node
		return err
	}
Henry's avatar
Henry committed
117

118
	nd, err := core.NewIPFSNode(ctx, core.Offline(r))
119
	if err != nil {
120
		return err
121 122 123
	}
	defer nd.Close()

124 125 126 127 128 129 130 131 132
	dirb := uio.NewDirectory(nd.DAG)

	// add every file in the assets pkg
	for fname, file := range assets.Init_dir {
		buf := bytes.NewBufferString(file)
		s, err := coreunix.Add(nd, buf)
		if err != nil {
			return err
		}
Henry's avatar
Henry committed
133

134 135 136 137 138 139 140 141
		k := u.B58KeyDecode(s)
		if err := dirb.AddChild(fname, k); err != nil {
			return err
		}
	}

	dir := dirb.GetNode()
	dkey, err := nd.DAG.Add(dir)
142
	if err != nil {
143 144
		return err
	}
Henry's avatar
Henry committed
145

146 147
	if err := nd.Pinning.Pin(dir, true); err != nil {
		return err
148
	}
Henry's avatar
Henry committed
149

150 151 152 153
	if err := nd.Pinning.Flush(); err != nil {
		return err
	}

Henry's avatar
Henry committed
154 155 156 157 158 159
	if _, err = fmt.Fprintf(out, "to get started, enter:\n"); err != nil {
		return err
	}

	_, err = fmt.Fprintf(out, "\n\tipfs cat /ipfs/%s/readme\n\n", dkey)
	return err
Matt Bell's avatar
Matt Bell committed
160
}
Brian Tiger Chow's avatar
Brian Tiger Chow committed
161

Jeromy's avatar
Jeromy committed
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
func initializeIpnsKeyspace(repoRoot string) error {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	r := fsrepo.At(repoRoot)
	if err := r.Open(); err != nil { // NB: repo is owned by the node
		return err
	}

	nd, err := core.NewIPFSNode(ctx, core.Offline(r))
	if err != nil {
		return err
	}
	defer nd.Close()

	err = nd.SetupOfflineRouting()
	if err != nil {
		return err
	}

	return ipns.InitializeKeyspace(nd, nd.PrivateKey)
}