github.com/aychain/blockbook@v0.1.1-0.20181121092459-6d1fc7e07c5b/build/tools/templates.go (about) 1 package build 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "os" 9 "os/exec" 10 "path/filepath" 11 "text/template" 12 "time" 13 ) 14 15 type Config struct { 16 Meta struct { 17 BuildDatetime string // generated field 18 PackageMaintainer string `json:"package_maintainer"` 19 PackageMaintainerEmail string `json:"package_maintainer_email"` 20 } 21 Env struct { 22 Version string `json:"version"` 23 BackendInstallPath string `json:"backend_install_path"` 24 BackendDataPath string `json:"backend_data_path"` 25 BlockbookInstallPath string `json:"blockbook_install_path"` 26 BlockbookDataPath string `json:"blockbook_data_path"` 27 } `json:"env"` 28 Coin struct { 29 Name string `json:"name"` 30 Shortcut string `json:"shortcut"` 31 Label string `json:"label"` 32 Alias string `json:"alias"` 33 } `json:"coin"` 34 Ports struct { 35 BackendRPC int `json:"backend_rpc"` 36 BackendMessageQueue int `json:"backend_message_queue"` 37 BlockbookInternal int `json:"blockbook_internal"` 38 BlockbookPublic int `json:"blockbook_public"` 39 } `json:"ports"` 40 IPC struct { 41 RPCURLTemplate string `json:"rpc_url_template"` 42 RPCUser string `json:"rpc_user"` 43 RPCPass string `json:"rpc_pass"` 44 RPCTimeout int `json:"rpc_timeout"` 45 MessageQueueBindingTemplate string `json:"message_queue_binding_template"` 46 } `json:"ipc"` 47 Backend struct { 48 PackageName string `json:"package_name"` 49 PackageRevision string `json:"package_revision"` 50 SystemUser string `json:"system_user"` 51 Version string `json:"version"` 52 BinaryURL string `json:"binary_url"` 53 VerificationType string `json:"verification_type"` 54 VerificationSource string `json:"verification_source"` 55 ExtractCommand string `json:"extract_command"` 56 ExcludeFiles []string `json:"exclude_files"` 57 ExecCommandTemplate string `json:"exec_command_template"` 58 LogrotateFilesTemplate string `json:"logrotate_files_template"` 59 PostinstScriptTemplate string `json:"postinst_script_template"` 60 ServiceType string `json:"service_type"` 61 ServiceAdditionalParamsTemplate string `json:"service_additional_params_template"` 62 ProtectMemory bool `json:"protect_memory"` 63 Mainnet bool `json:"mainnet"` 64 ServerConfigFile string `json:"server_config_file"` 65 ClientConfigFile string `json:"client_config_file"` 66 AdditionalParams interface{} `json:"additional_params"` 67 } `json:"backend"` 68 Blockbook struct { 69 PackageName string `json:"package_name"` 70 SystemUser string `json:"system_user"` 71 InternalBindingTemplate string `json:"internal_binding_template"` 72 PublicBindingTemplate string `json:"public_binding_template"` 73 ExplorerURL string `json:"explorer_url"` 74 AdditionalParams string `json:"additional_params"` 75 BlockChain struct { 76 Parse bool `json:"parse"` 77 Subversion string `json:"subversion"` 78 AddressFormat string `json:"address_format"` 79 MempoolWorkers int `json:"mempool_workers"` 80 MempoolSubWorkers int `json:"mempool_sub_workers"` 81 BlockAddressesToKeep int `json:"block_addresses_to_keep"` 82 AdditionalParams map[string]json.RawMessage `json:"additional_params"` 83 } `json:"block_chain"` 84 } `json:"blockbook"` 85 IntegrationTests map[string][]string `json:"integration_tests"` 86 } 87 88 func jsonToString(msg json.RawMessage) (string, error) { 89 d, err := msg.MarshalJSON() 90 if err != nil { 91 return "", err 92 } 93 return string(d), nil 94 } 95 96 func generateRPCAuth(user, pass string) (string, error) { 97 cmd := exec.Command("/bin/bash", "-c", "build/scripts/rpcauth.py \"$0\" \"$1\" | sed -n -e 2p", user, pass) 98 var out bytes.Buffer 99 cmd.Stdout = &out 100 err := cmd.Run() 101 if err != nil { 102 return "", err 103 } 104 return out.String(), nil 105 } 106 107 func (c *Config) ParseTemplate() *template.Template { 108 templates := map[string]string{ 109 "IPC.RPCURLTemplate": c.IPC.RPCURLTemplate, 110 "IPC.MessageQueueBindingTemplate": c.IPC.MessageQueueBindingTemplate, 111 "Backend.ExecCommandTemplate": c.Backend.ExecCommandTemplate, 112 "Backend.LogrotateFilesTemplate": c.Backend.LogrotateFilesTemplate, 113 "Backend.PostinstScriptTemplate": c.Backend.PostinstScriptTemplate, 114 "Backend.ServiceAdditionalParamsTemplate": c.Backend.ServiceAdditionalParamsTemplate, 115 "Blockbook.InternalBindingTemplate": c.Blockbook.InternalBindingTemplate, 116 "Blockbook.PublicBindingTemplate": c.Blockbook.PublicBindingTemplate, 117 } 118 119 funcMap := template.FuncMap{ 120 "jsonToString": jsonToString, 121 "generateRPCAuth": generateRPCAuth, 122 } 123 124 t := template.New("").Funcs(funcMap) 125 126 for name, def := range templates { 127 t = template.Must(t.Parse(fmt.Sprintf(`{{define "%s"}}%s{{end}}`, name, def))) 128 } 129 130 return t 131 } 132 133 func LoadConfig(configsDir, coin string) (*Config, error) { 134 config := new(Config) 135 136 f, err := os.Open(filepath.Join(configsDir, "coins", coin+".json")) 137 if err != nil { 138 return nil, err 139 } 140 d := json.NewDecoder(f) 141 err = d.Decode(config) 142 if err != nil { 143 return nil, err 144 } 145 146 f, err = os.Open(filepath.Join(configsDir, "environ.json")) 147 if err != nil { 148 return nil, err 149 } 150 d = json.NewDecoder(f) 151 err = d.Decode(&config.Env) 152 if err != nil { 153 return nil, err 154 } 155 156 config.Meta.BuildDatetime = time.Now().Format("Mon, 02 Jan 2006 15:04:05 -0700") 157 158 if !isEmpty(config, "backend") { 159 switch config.Backend.ServiceType { 160 case "forking": 161 case "simple": 162 default: 163 return nil, fmt.Errorf("Invalid service type: %s", config.Backend.ServiceType) 164 } 165 166 switch config.Backend.VerificationType { 167 case "": 168 case "gpg": 169 case "sha256": 170 case "gpg-sha256": 171 default: 172 return nil, fmt.Errorf("Invalid verification type: %s", config.Backend.VerificationType) 173 } 174 } 175 176 return config, nil 177 } 178 179 func isEmpty(config *Config, target string) bool { 180 switch target { 181 case "backend": 182 return config.Backend.PackageName == "" 183 case "blockbook": 184 return config.Blockbook.PackageName == "" 185 default: 186 panic("Invalid target name: " + target) 187 } 188 } 189 190 func GeneratePackageDefinitions(config *Config, templateDir, outputDir string) error { 191 templ := config.ParseTemplate() 192 193 err := makeOutputDir(outputDir) 194 if err != nil { 195 return err 196 } 197 198 for _, subdir := range []string{"backend", "blockbook"} { 199 if isEmpty(config, subdir) { 200 continue 201 } 202 203 root := filepath.Join(templateDir, subdir) 204 205 err = os.Mkdir(filepath.Join(outputDir, subdir), 0755) 206 if err != nil { 207 return err 208 } 209 210 err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error { 211 if err != nil { 212 return fmt.Errorf("%s: %s", path, err) 213 } 214 215 if path == root { 216 return nil 217 } 218 if filepath.Base(path)[0] == '.' { 219 return nil 220 } 221 222 subpath := path[len(root)-len(subdir):] 223 224 if info.IsDir() { 225 err = os.Mkdir(filepath.Join(outputDir, subpath), info.Mode()) 226 if err != nil { 227 return fmt.Errorf("%s: %s", path, err) 228 } 229 return nil 230 } 231 232 t := template.Must(templ.Clone()) 233 t = template.Must(t.ParseFiles(path)) 234 235 err = writeTemplate(filepath.Join(outputDir, subpath), info, t, config) 236 if err != nil { 237 return fmt.Errorf("%s: %s", path, err) 238 } 239 240 return nil 241 }) 242 if err != nil { 243 return err 244 } 245 } 246 247 if !isEmpty(config, "backend") { 248 err = writeBackendServerConfigFile(config, outputDir) 249 if err == nil { 250 err = writeBackendClientConfigFile(config, outputDir) 251 } 252 if err != nil { 253 return err 254 } 255 } 256 257 return nil 258 } 259 260 func makeOutputDir(path string) error { 261 err := os.RemoveAll(path) 262 if err == nil { 263 err = os.Mkdir(path, 0755) 264 } 265 return err 266 } 267 268 func writeTemplate(path string, info os.FileInfo, templ *template.Template, config *Config) error { 269 f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, info.Mode()) 270 if err != nil { 271 return err 272 } 273 defer f.Close() 274 275 err = templ.ExecuteTemplate(f, "main", config) 276 if err != nil { 277 return err 278 } 279 280 return nil 281 } 282 283 func writeBackendServerConfigFile(config *Config, outputDir string) error { 284 out, err := os.OpenFile(filepath.Join(outputDir, "backend/server.conf"), os.O_CREATE|os.O_WRONLY, 0644) 285 if err != nil { 286 return err 287 } 288 defer out.Close() 289 290 if config.Backend.ServerConfigFile == "" { 291 return nil 292 } else { 293 in, err := os.Open(filepath.Join(outputDir, "backend/config", config.Backend.ServerConfigFile)) 294 if err != nil { 295 return err 296 } 297 defer in.Close() 298 299 _, err = io.Copy(out, in) 300 if err != nil { 301 return err 302 } 303 } 304 305 return nil 306 } 307 308 func writeBackendClientConfigFile(config *Config, outputDir string) error { 309 out, err := os.OpenFile(filepath.Join(outputDir, "backend/client.conf"), os.O_CREATE|os.O_WRONLY, 0644) 310 if err != nil { 311 return err 312 } 313 defer out.Close() 314 315 if config.Backend.ClientConfigFile == "" { 316 return nil 317 } else { 318 in, err := os.Open(filepath.Join(outputDir, "backend/config", config.Backend.ClientConfigFile)) 319 if err != nil { 320 return err 321 } 322 defer in.Close() 323 324 _, err = io.Copy(out, in) 325 if err != nil { 326 return err 327 } 328 } 329 330 return nil 331 }