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