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

import (
4
	"bytes"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
5
	"errors"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
6
	"fmt"
7
	"io"
Matt Bell's avatar
Matt Bell committed
8

9 10 11 12 13 14 15 16 17 18
	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
	assets "github.com/ipfs/go-ipfs/assets"
	cmds "github.com/ipfs/go-ipfs/commands"
	core "github.com/ipfs/go-ipfs/core"
	coreunix "github.com/ipfs/go-ipfs/core/coreunix"
	namesys "github.com/ipfs/go-ipfs/namesys"
	config "github.com/ipfs/go-ipfs/repo/config"
	fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
	uio "github.com/ipfs/go-ipfs/unixfs/io"
	u "github.com/ipfs/go-ipfs/util"
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

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
68
var errRepoExists = errors.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)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
75
	return 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
	r, err := fsrepo.Open(repoRoot)
	if err != nil { // NB: repo is owned by the node
115 116
		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

Jeromy's avatar
Jeromy committed
146
	if err := nd.Pinning.Pin(ctx, dir, true); err != nil {
147
		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
func initializeIpnsKeyspace(repoRoot string) error {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

166 167
	r, err := fsrepo.Open(repoRoot)
	if err != nil { // NB: repo is owned by the node
Jeromy's avatar
Jeromy committed
168 169 170 171 172 173 174 175 176 177 178 179 180 181
		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
	}

182
	return namesys.InitializeKeyspace(ctx, nd.DAG, nd.Namesys, nd.Pinning, nd.PrivateKey)
Jeromy's avatar
Jeromy committed
183
}