-
Notifications
You must be signed in to change notification settings - Fork 47
/
init.go
168 lines (144 loc) · 4.16 KB
/
init.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package server
import (
"bufio"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"time"
"github.com/pkg/errors"
"github.com/tendermint/tmlibs/log"
)
const (
// AppStateKey is the key in the json json where all info
// on initializing the app can be found
AppStateKey = "app_state"
DirConfig = "config"
GenesisTimeKey = "genesis_time"
ErrorAlreadyInitialised = "the application has already been initialised, use %s flag to override"
FlagForce = "f"
flagIndexAll = "all"
flagIndexTags = "tags"
)
/*
Usage:
xxx init // index all
xxx init -all=f // no index
xxx init -tags=foo,bar // index only foo and bar
*/
func parseIndex(args []string) (bool, bool, string, []string, error) {
// parse flagIndexAll, flagIndexTags and return the result
indexFlags := flag.NewFlagSet("init", flag.ExitOnError)
tags := indexFlags.String(flagIndexTags, "", "comma-separated list of tags to index")
all := indexFlags.Bool(flagIndexAll, true, "")
force := indexFlags.Bool(FlagForce, false, "")
err := indexFlags.Parse(args)
return *all, *force, *tags, indexFlags.Args(), err
}
// InitCmd will initialize all files for tendermint,
// along with proper app_options.
// The application can pass in a function to generate
// proper options. And may want to use GenerateCoinKey
// to create default account(s).
func InitCmd(gen GenOptions, logger log.Logger, home string, args []string) error {
genFile := filepath.Join(home, DirConfig, "genesis.json")
confFile := filepath.Join(home, DirConfig, "config.toml")
all, force, tags, args, err := parseIndex(args)
if err != nil {
return err
}
err = setTxIndex(confFile, all, tags, force)
if err != nil {
return err
}
// no app_options, leave like tendermint
if gen == nil {
return nil
}
// Now, we want to add the custom app_options
options, err := gen(args)
if err != nil {
return err
}
// And add them to the genesis file
err = addGenesisOptions(genFile, options, force)
if err == nil {
fmt.Println("The application has been succesfully initialised.")
}
return err
}
// GenOptions can parse command-line and flag to
// generate default app_options for the genesis file.
// This is application-specific
type GenOptions func(args []string) (json.RawMessage, error)
// GenesisDoc involves some tendermint-specific structures we don't
// want to parse, so we just grab it into a raw object format,
// so we can add one line.
type GenesisDoc map[string]json.RawMessage
func addGenesisOptions(filename string, options json.RawMessage, force bool) error {
bz, err := ioutil.ReadFile(filename)
if err != nil {
return err
}
var doc GenesisDoc
err = json.Unmarshal(bz, &doc)
if err != nil {
return err
}
v, ok := doc[AppStateKey]
if !force && ok && len(v) > 0 {
return fmt.Errorf(ErrorAlreadyInitialised, FlagForce)
}
timeJson, _ := time.Now().MarshalJSON()
doc[AppStateKey] = options
doc[GenesisTimeKey] = timeJson
out, err := json.MarshalIndent(doc, "", " ")
if err != nil {
return err
}
return ioutil.WriteFile(filename, out, 0600)
}
var (
prefixIndexer = "indexer"
prefixIndexAll = "index_all_tags"
prefixIndexTags = "index_tags"
setIndexer = `indexer = "kv"`
)
// setTxIndex sets the following fields in config.toml
// indexer = "kv"
// index_all_tags = <all>
// index_tags = <tags>
func setTxIndex(config string, all bool, tags string, force bool) error {
f, err := os.Open(config)
if err != nil {
return errors.WithStack(err)
}
// translate the file into a buffer in memory
scan := bufio.NewScanner(f)
var buf []string
for scan.Scan() {
line := scan.Text()
if strings.HasPrefix(line, prefixIndexer) {
line = setIndexer
} else if strings.HasPrefix(line, prefixIndexAll) {
line = fmt.Sprintf("%s = %t", prefixIndexAll, all)
} else if strings.HasPrefix(line, prefixIndexTags) {
line = fmt.Sprintf(`%s = "%s"`, prefixIndexTags, tags)
}
buf = append(buf, line)
}
buf = append(buf, "")
f.Close()
// write to output
out, err := os.Create(config)
if err != nil {
return errors.WithStack(err)
}
output := strings.Join(buf, "\n")
_, err = out.WriteString(output)
out.Close()
return err
}