mirror of
https://github.com/aljazceru/nigiri.git
synced 2026-02-22 06:44:28 +01:00
add cli
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1 +1,4 @@
|
||||
.DS_Store
|
||||
.DS_Store
|
||||
|
||||
vendor/
|
||||
build/
|
||||
190
Gopkg.lock
generated
Normal file
190
Gopkg.lock
generated
Normal file
@@ -0,0 +1,190 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
digest = "1:abeb38ade3f32a92943e5be54f55ed6d6e3b6602761d74b4aab4c9dd45c18abd"
|
||||
name = "github.com/fsnotify/fsnotify"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
|
||||
version = "v1.4.7"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c0d19ab64b32ce9fe5cf4ddceba78d5bc9807f0016db6b1183599da3dcc24d10"
|
||||
name = "github.com/hashicorp/hcl"
|
||||
packages = [
|
||||
".",
|
||||
"hcl/ast",
|
||||
"hcl/parser",
|
||||
"hcl/printer",
|
||||
"hcl/scanner",
|
||||
"hcl/strconv",
|
||||
"hcl/token",
|
||||
"json/parser",
|
||||
"json/scanner",
|
||||
"json/token",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "8cb6e5b959231cc1119e43259c4a608f9c51a241"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
|
||||
name = "github.com/inconshreveable/mousetrap"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
||||
version = "v1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:31e761d97c76151dde79e9d28964a812c46efc5baee4085b86f68f0c654450de"
|
||||
name = "github.com/konsorten/go-windows-terminal-sequences"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "f55edac94c9bbba5d6182a4be46d86a2c9b5b50e"
|
||||
version = "v1.0.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c568d7727aa262c32bdf8a3f7db83614f7af0ed661474b24588de635c20024c7"
|
||||
name = "github.com/magiconair/properties"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "c2353362d570a7bfa228149c62842019201cfb71"
|
||||
version = "v1.8.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:5d231480e1c64a726869bc4142d270184c419749d34f167646baa21008eb0a79"
|
||||
name = "github.com/mitchellh/go-homedir"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "af06845cf3004701891bf4fdb884bfe4920b3727"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:53bc4cd4914cd7cd52139990d5170d6dc99067ae31c56530621b18b35fc30318"
|
||||
name = "github.com/mitchellh/mapstructure"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "3536a929edddb9a5b34bd6861dc4a9647cb459fe"
|
||||
version = "v1.1.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:95741de3af260a92cc5c7f3f3061e85273f5a81b5db20d4bd68da74bd521675e"
|
||||
name = "github.com/pelletier/go-toml"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e4c72127d910a96daf869a44f3dd563b86dbe6931a172863a0e99c5ff04b59e4"
|
||||
name = "github.com/sirupsen/logrus"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "dae0fa8d5b0c810a8ab733fbd5510c7cae84eca4"
|
||||
version = "v1.4.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:bb495ec276ab82d3dd08504bbc0594a65de8c3b22c6f2aaa92d05b73fbf3a82e"
|
||||
name = "github.com/spf13/afero"
|
||||
packages = [
|
||||
".",
|
||||
"mem",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "588a75ec4f32903aa5e39a2619ba6a4631e28424"
|
||||
version = "v1.2.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:08d65904057412fc0270fc4812a1c90c594186819243160dc779a402d4b6d0bc"
|
||||
name = "github.com/spf13/cast"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "8c9545af88b134710ab1cd196795e7f2388358d7"
|
||||
version = "v1.3.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:645cabccbb4fa8aab25a956cbcbdf6a6845ca736b2c64e197ca7cbb9d210b939"
|
||||
name = "github.com/spf13/cobra"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:1b753ec16506f5864d26a28b43703c58831255059644351bbcb019b843950900"
|
||||
name = "github.com/spf13/jwalterweatherman"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "94f6ae3ed3bceceafa716478c5fbf8d29ca601a1"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c1b1102241e7f645bc8e0c22ae352e8f0dc6484b6cb4d132fa9f24174e0119e2"
|
||||
name = "github.com/spf13/pflag"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "298182f68c66c05229eb03ac171abe6e309ee79a"
|
||||
version = "v1.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:1b773526998f3dbde3a51a4a5881680c4d237d3600f570d900f97ac93c7ba0a8"
|
||||
name = "github.com/spf13/viper"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "9e56dacc08fbbf8c9ee2dbc717553c758ce42bc9"
|
||||
version = "v1.3.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:bbe51412d9915d64ffaa96b51d409e070665efc5194fcf145c4a27d4133107a4"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = ["ssh/terminal"]
|
||||
pruneopts = "UT"
|
||||
revision = "a5d413f7728c81fb97d96a2b722368945f651e78"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:6b3e6ddcebac95be1d690dbd53b5aa2e520715becb7e521bb526ccf3b4c53c15"
|
||||
name = "golang.org/x/sys"
|
||||
packages = [
|
||||
"unix",
|
||||
"windows",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "f49334f85ddcf0f08d7fb6dd7363e9e6d6b777eb"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:8029e9743749d4be5bc9f7d42ea1659471767860f0cdc34d37c3111bd308a295"
|
||||
name = "golang.org/x/text"
|
||||
packages = [
|
||||
"internal/gen",
|
||||
"internal/triegen",
|
||||
"internal/ucd",
|
||||
"transform",
|
||||
"unicode/cldr",
|
||||
"unicode/norm",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4d2e5a73dc1500038e504a8d78b986630e3626dc027bc030ba5c75da257cdb96"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "51d6538a90f86fe93ac480b35f37b2be17fef232"
|
||||
version = "v2.2.2"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
input-imports = [
|
||||
"github.com/mitchellh/go-homedir",
|
||||
"github.com/sirupsen/logrus",
|
||||
"github.com/spf13/cobra",
|
||||
"github.com/spf13/viper",
|
||||
]
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
30
Gopkg.toml
Normal file
30
Gopkg.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
#
|
||||
# [prune]
|
||||
# non-go = false
|
||||
# go-tests = true
|
||||
# unused-packages = true
|
||||
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
44
README.md
44
README.md
@@ -15,53 +15,65 @@ A dockerized environment hosting a bitcoin and liquid daemons in regtest network
|
||||
|
||||
## Directions
|
||||
|
||||
| Preparation Time: 20 min | Cooking Difficulty: Easy |
|
||||
| Preparation Time: 5 min | Cooking Difficulty: Easy |
|
||||
| --- | --- |
|
||||
|
||||
Clone the repo:
|
||||
|
||||
```bash
|
||||
$ git clone https://github.com/vulpemventures/nigiri.git && cd nigiri
|
||||
$ git clone https://github.com/vulpemventures/nigiri.git
|
||||
```
|
||||
|
||||
Create and start nigiri (only the first time or after cleaning):
|
||||
Enter project directory and install dependencies:
|
||||
|
||||
```bash
|
||||
$ bash scripts/create
|
||||
nigiri $ bash scripts/install
|
||||
```
|
||||
|
||||
Build binary (Mac version):
|
||||
```
|
||||
nigiri $ bash scripts/build darwin amd64
|
||||
```
|
||||
|
||||
At the moment bitcoind, liquidd and electrs are started on *regtest* network.
|
||||
|
||||
Start nigiri:
|
||||
Initialize nigiri:
|
||||
|
||||
```bash
|
||||
$ bash scripts/start
|
||||
nigiri/build $ nigiri-linux-amd64 init
|
||||
```
|
||||
|
||||
This will start 4 containers that run the following services respectevely:
|
||||
Initialize nigiri configuation file at at path `~/.nigiri/nigiri.config.json`.
|
||||
|
||||
* bitcoin daemon (regtest)
|
||||
* liquid daemon
|
||||
Create and run nigiri environment:
|
||||
|
||||
```bash
|
||||
nigiri/build $ nigiri-linux-amd64 create
|
||||
```
|
||||
|
||||
This will start 3 containers for `regtest` bitcoin network that run the following services respectevely:
|
||||
|
||||
* bitcoin daemon
|
||||
* electrs REST server
|
||||
* API passthrough with optional faucet and mining capabilities (nigiri-chopsticks)
|
||||
|
||||
Stop nigiri:
|
||||
After command has finished, nigiri start listening at `http://localhost:3000/`.
|
||||
|
||||
Start/Stop nigiri:
|
||||
|
||||
```bash
|
||||
$ bash scripts/stop
|
||||
nigiri/build $ nigiri-linux-amd64 start|stop
|
||||
```
|
||||
|
||||
Stop and uninstall nigiri:
|
||||
Stop and delete nigiri environment:
|
||||
|
||||
```bash
|
||||
$ bash scripts/clean
|
||||
nigiri/build $ nigiri-linux-amd64 delete
|
||||
```
|
||||
|
||||
When setup is completed, you can call any endpoint at `http://localhost:3000/`.
|
||||
|
||||
## Nutrition Facts
|
||||
|
||||
The [list](https://github.com/blockstream/esplora/blob/master/API.md) of all available endpoints has been extended with one more `POST /send` which expects a body `{ "address": <receiving_address> }`
|
||||
The [list](https://github.com/blockstream/esplora/blob/master/API.md) of all available endpoints can be extended with one more `POST /faucet` which expects a body `{ "address": <receiving_address> }` by enabling faucet.
|
||||
|
||||
## Footnotes
|
||||
|
||||
|
||||
7
cli/builder/main.go
Normal file
7
cli/builder/main.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package builder
|
||||
|
||||
type ComposeBuilder interface {
|
||||
New(rootPath string)
|
||||
Build() error
|
||||
Delete() error
|
||||
}
|
||||
48
cli/cmd/create.go
Normal file
48
cli/cmd/create.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/vulpemventures/nigiri/cli/builder"
|
||||
"github.com/vulpemventures/nigiri/cli/config"
|
||||
"github.com/vulpemventures/nigiri/cli/helpers"
|
||||
)
|
||||
|
||||
var composeBuilder = map[string]func(path string) builder.ComposeBuilder{
|
||||
"regtest": helpers.NewRegtestBuilder,
|
||||
}
|
||||
|
||||
var CreateCmd = &cobra.Command{
|
||||
Use: "create",
|
||||
Short: "Build and run the entire Docker environment",
|
||||
Run: create,
|
||||
PreRun: createChecks,
|
||||
}
|
||||
|
||||
func createChecks(cmd *cobra.Command, args []string) {
|
||||
if err := config.ReadFromFile(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if composeExists() {
|
||||
log.Fatal("Docker environment already exists, please delete it first")
|
||||
}
|
||||
}
|
||||
|
||||
func create(cmd *cobra.Command, args []string) {
|
||||
viper := config.Viper()
|
||||
network := viper.GetString("network")
|
||||
composePath := getComposePath()
|
||||
|
||||
composer := composeBuilder[network](composePath)
|
||||
if err := composer.Build(); err != nil {
|
||||
log.WithError(err).Fatal("Error while composing Docker environment:")
|
||||
}
|
||||
}
|
||||
|
||||
func composeExists() bool {
|
||||
_, err := os.Stat(getComposePath())
|
||||
return !os.IsNotExist(err)
|
||||
}
|
||||
35
cli/cmd/delete.go
Normal file
35
cli/cmd/delete.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/vulpemventures/nigiri/cli/config"
|
||||
)
|
||||
|
||||
var DeleteCmd = &cobra.Command{
|
||||
Use: "delete",
|
||||
Short: "Delete all Docker environment components",
|
||||
Run: delete,
|
||||
PreRun: deleteChecks,
|
||||
}
|
||||
|
||||
func delete(cmd *cobra.Command, args []string) {
|
||||
viper := config.Viper()
|
||||
network := viper.GetString("network")
|
||||
composePath := getComposePath()
|
||||
|
||||
composer := composeBuilder[network](composePath)
|
||||
if err := composer.Delete(); err != nil {
|
||||
log.WithError(err).Fatal("Error while deleting Docker environment:")
|
||||
}
|
||||
}
|
||||
|
||||
func deleteChecks(cmd *cobra.Command, args []string) {
|
||||
if err := config.ReadFromFile(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if !composeExists() {
|
||||
log.Fatal("Docker environment does not exist")
|
||||
}
|
||||
}
|
||||
46
cli/cmd/flags.go
Normal file
46
cli/cmd/flags.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/mitchellh/go-homedir"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/vulpemventures/nigiri/cli/config"
|
||||
)
|
||||
|
||||
var (
|
||||
flagNetwork string
|
||||
flagDatadir string
|
||||
flagConfig string
|
||||
)
|
||||
|
||||
var RootCmd = &cobra.Command{
|
||||
Use: "nigiri",
|
||||
Short: "Nigiri lets you manage a full dockerized bitcoin environment",
|
||||
Long: "A dockerized environment with a bitcoin and liquid node + block explorer powered by an electrum server",
|
||||
}
|
||||
|
||||
func init() {
|
||||
home, _ := homedir.Expand("~")
|
||||
defaultDir := filepath.Join(home, ".nigiri")
|
||||
|
||||
RootCmd.PersistentFlags().StringVar(&flagNetwork, "network", "regtest", "Set bitcoin network for containers' services - regtest only for now")
|
||||
InitCmd.PersistentFlags().StringVar(&flagDatadir, "datadir", defaultDir, "Set directory for docker containers")
|
||||
|
||||
RootCmd.AddCommand(InitCmd)
|
||||
RootCmd.AddCommand(CreateCmd)
|
||||
RootCmd.AddCommand(StartCmd)
|
||||
RootCmd.AddCommand(StopCmd)
|
||||
RootCmd.AddCommand(DeleteCmd)
|
||||
|
||||
viper := config.Viper()
|
||||
viper.BindPFlag(config.Network, RootCmd.PersistentFlags().Lookup("network"))
|
||||
viper.BindPFlag(config.Datadir, InitCmd.PersistentFlags().Lookup("datadir"))
|
||||
|
||||
cobra.OnInitialize(func() {
|
||||
log.SetOutput(os.Stdout)
|
||||
log.SetLevel(log.InfoLevel)
|
||||
})
|
||||
}
|
||||
60
cli/cmd/init.go
Normal file
60
cli/cmd/init.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/vulpemventures/nigiri/cli/config"
|
||||
)
|
||||
|
||||
var InitCmd = &cobra.Command{
|
||||
Use: "init",
|
||||
Short: "Initialize configuration file",
|
||||
Run: run,
|
||||
PreRun: runChecks,
|
||||
}
|
||||
|
||||
func run(cmd *cobra.Command, args []string) {
|
||||
viper := config.Viper()
|
||||
|
||||
if err := viper.WriteConfig(); err != nil {
|
||||
log.WithError(err).Fatal("An error occured while writing config file")
|
||||
}
|
||||
}
|
||||
|
||||
func runChecks(cmd *cobra.Command, args []string) {
|
||||
network := cmd.Flags().Lookup("network").Value.String()
|
||||
|
||||
// check valid network
|
||||
if !isNetworkOk(network) {
|
||||
log.WithField("network_flag", network).Fatal("Invalid network")
|
||||
}
|
||||
|
||||
// scratch ~/.nigiri/ if not exists
|
||||
if err := os.MkdirAll(config.GetPath(), 0755); err != nil {
|
||||
log.WithError(err).Fatal("An error occured while scratching config dir")
|
||||
}
|
||||
|
||||
// check if config file already exists
|
||||
if _, err := os.Stat(config.GetFullPath()); !os.IsNotExist(err) {
|
||||
log.Fatal("File already exists, please delete it first")
|
||||
}
|
||||
}
|
||||
|
||||
func isNetworkOk(network string) bool {
|
||||
var ok bool
|
||||
for _, n := range []string{"regtest"} {
|
||||
if network == n {
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
func fileExists(path string) bool {
|
||||
_, err := os.Stat(filepath.Join(path, config.Filename))
|
||||
return !os.IsNotExist(err)
|
||||
}
|
||||
48
cli/cmd/start.go
Normal file
48
cli/cmd/start.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/vulpemventures/nigiri/cli/config"
|
||||
)
|
||||
|
||||
var StartCmd = &cobra.Command{
|
||||
Use: "start",
|
||||
Short: "Start containers",
|
||||
Run: start,
|
||||
PreRun: startStopChecks,
|
||||
}
|
||||
|
||||
func start(cmd *cobra.Command, args []string) {
|
||||
composePath := filepath.Join(getComposePath(), "docker-compose.yml")
|
||||
cmdStart := exec.Command("docker-compose", "-f", composePath, "start")
|
||||
cmdStart.Stdout = os.Stdout
|
||||
cmdStart.Stderr = os.Stderr
|
||||
|
||||
if err := cmdStart.Run(); err != nil {
|
||||
log.WithError(err).Fatal("Error while starting Docker containers:")
|
||||
}
|
||||
}
|
||||
|
||||
func startStopChecks(cmd *cobra.Command, args []string) {
|
||||
if err := config.ReadFromFile(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if !composeExists() {
|
||||
log.Fatal("Docker environment does not exist")
|
||||
}
|
||||
}
|
||||
|
||||
func getComposePath() string {
|
||||
viper := config.Viper()
|
||||
datadir := viper.GetString("datadir")
|
||||
network := viper.GetString("network")
|
||||
|
||||
return filepath.Join(datadir, fmt.Sprintf("resources-%s", network))
|
||||
}
|
||||
28
cli/cmd/stop.go
Normal file
28
cli/cmd/stop.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var StopCmd = &cobra.Command{
|
||||
Use: "stop",
|
||||
Short: "Stop containers",
|
||||
Run: stop,
|
||||
PreRun: startStopChecks,
|
||||
}
|
||||
|
||||
func stop(cmd *cobra.Command, args []string) {
|
||||
composePath := filepath.Join(getComposePath(), "docker-compose.yml")
|
||||
cmdStart := exec.Command("docker-compose", "-f", composePath, "stop")
|
||||
cmdStart.Stdout = os.Stdout
|
||||
cmdStart.Stderr = os.Stderr
|
||||
|
||||
if err := cmdStart.Run(); err != nil {
|
||||
log.WithError(err).Fatal("Error while stopping Docker containers:")
|
||||
}
|
||||
}
|
||||
59
cli/config/main.go
Normal file
59
cli/config/main.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const (
|
||||
Datadir = "datadir"
|
||||
Network = "network"
|
||||
Filename = "nigiri.config.json"
|
||||
)
|
||||
|
||||
var vip *viper.Viper
|
||||
|
||||
func init() {
|
||||
vip = viper.New()
|
||||
vip.SetEnvPrefix("NIGIRI")
|
||||
vip.AutomaticEnv()
|
||||
vip.BindEnv("config")
|
||||
|
||||
defaults := viper.New()
|
||||
newDefaultConfig(defaults)
|
||||
setConfigFromDefaults(vip, defaults)
|
||||
vip.SetConfigFile(GetFullPath())
|
||||
}
|
||||
|
||||
func Viper() *viper.Viper {
|
||||
return vip
|
||||
}
|
||||
|
||||
func ReadFromFile() error {
|
||||
vip.AddConfigPath(GetFullPath())
|
||||
return vip.ReadInConfig()
|
||||
}
|
||||
|
||||
func GetPath() string {
|
||||
home, _ := homedir.Expand("~")
|
||||
return filepath.Join(home, ".nigiri")
|
||||
}
|
||||
|
||||
func GetFullPath() string {
|
||||
home, _ := homedir.Expand("~")
|
||||
return filepath.Join(home, ".nigiri", Filename)
|
||||
}
|
||||
|
||||
func newDefaultConfig(v *viper.Viper) {
|
||||
v.SetDefault("datadir", GetPath())
|
||||
v.SetDefault("network", "regtest")
|
||||
v.SetDefault("version", "0.1.0")
|
||||
}
|
||||
|
||||
func setConfigFromDefaults(v *viper.Viper, d *viper.Viper) {
|
||||
for key, value := range d.AllSettings() {
|
||||
v.SetDefault(key, value)
|
||||
}
|
||||
}
|
||||
246
cli/helpers/regtestbuilder.go
Normal file
246
cli/helpers/regtestbuilder.go
Normal file
@@ -0,0 +1,246 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/vulpemventures/nigiri/cli/builder"
|
||||
)
|
||||
|
||||
func NewRegtestBuilder(rootPath string) builder.ComposeBuilder {
|
||||
rb := ®testbuilder{}
|
||||
rb.New(rootPath)
|
||||
|
||||
return rb
|
||||
}
|
||||
|
||||
type regtestbuilder struct {
|
||||
path string
|
||||
}
|
||||
|
||||
func (rb *regtestbuilder) New(rootPath string) {
|
||||
rb.path = rootPath
|
||||
}
|
||||
|
||||
func (rb *regtestbuilder) Build() error {
|
||||
if err := buildComposeFile(rb.path); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := buildBitcoinContainer(filepath.Join(rb.path, "bitcoin")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := buildElectrsContainer(filepath.Join(rb.path, "electrs")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return runCompose(rb.path)
|
||||
}
|
||||
|
||||
func (rb *regtestbuilder) Delete() error {
|
||||
return deleteAll(rb.path)
|
||||
}
|
||||
|
||||
func runCompose(path string) error {
|
||||
composePath := filepath.Join(path, "docker-compose.yml")
|
||||
cmd := exec.Command("docker-compose", "-f", composePath, "up", "-d")
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
func buildComposeFile(path string) error {
|
||||
if err := os.MkdirAll(path, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r := strings.NewReplacer("\t", " ")
|
||||
if err := ioutil.WriteFile(filepath.Join(path, "docker-compose.yml"), []byte(r.Replace(composeFile)), os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildBitcoinContainer(path string) error {
|
||||
configPath := filepath.Join(path, "config")
|
||||
if err := os.MkdirAll(configPath, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(filepath.Join(path, "run"), []byte(btcRunFile), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(filepath.Join(path, "Dockerfile"), []byte(btcDockerFile), 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(filepath.Join(configPath, "bitcoin.conf"), []byte(btcConfigFile), 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildElectrsContainer(path string) error {
|
||||
if err := os.MkdirAll(path, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(filepath.Join(path, "run"), []byte(electrsRunFile), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(filepath.Join(path, "Dockerfile"), []byte(electrsDockerFile), 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteAll(path string) error {
|
||||
_, basename := filepath.Split(path)
|
||||
composePath := filepath.Join(path, "docker-compose.yml")
|
||||
volume := fmt.Sprintf("%s_bitcoin-config", basename)
|
||||
images := []string{
|
||||
fmt.Sprintf("%s_bitcoin", basename),
|
||||
fmt.Sprintf("%s_electrs", basename),
|
||||
}
|
||||
|
||||
cmdCompose := fmt.Sprintf("docker-compose -f %s down", composePath)
|
||||
cmdVolume := fmt.Sprintf("docker volume rm %s", volume)
|
||||
cmdImage := fmt.Sprintf("docker rmi %s", strings.Join(images, " "))
|
||||
cmdDelete := fmt.Sprintf("rm -rf %s", path)
|
||||
|
||||
cmd := exec.Command(
|
||||
"/bin/sh", "-c",
|
||||
fmt.Sprintf("%s; %s; %s; %s", cmdCompose, cmdVolume, cmdImage, cmdDelete),
|
||||
)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
const composeFile = `version: '3'
|
||||
services:
|
||||
bitcoin:
|
||||
build:
|
||||
context: bitcoin/
|
||||
dockerfile: Dockerfile
|
||||
networks:
|
||||
local:
|
||||
ipv4_address: 10.10.0.10
|
||||
volumes:
|
||||
- bitcoin-config:/config
|
||||
electrs:
|
||||
build:
|
||||
context: electrs/
|
||||
dockerfile: Dockerfile
|
||||
networks:
|
||||
local:
|
||||
ipv4_address: 10.10.0.12
|
||||
volumes:
|
||||
- bitcoin-config:/config
|
||||
# chopsticks:
|
||||
# build:
|
||||
# context: chopsticks/
|
||||
# dockerfile: Dockerfile
|
||||
# ports:
|
||||
# - 3000:3000
|
||||
# networks:
|
||||
# local:
|
||||
# ipv4_address: 10.10.0.13
|
||||
|
||||
networks:
|
||||
local:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 10.10.0.0/24
|
||||
|
||||
volumes:
|
||||
bitcoin-config:`
|
||||
|
||||
const btcDockerFile = `FROM ubuntu:18.04
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install --yes clang cmake jq software-properties-common && \
|
||||
add-apt-repository --yes ppa:bitcoin/bitcoin && \
|
||||
apt-get update && \
|
||||
apt-get install --yes bitcoind
|
||||
|
||||
RUN mkdir -p /config /script
|
||||
|
||||
ADD config /config
|
||||
ADD run /script
|
||||
|
||||
WORKDIR /script
|
||||
|
||||
EXPOSE 19001
|
||||
STOPSIGNAL SIGINT
|
||||
|
||||
CMD ["./run"]`
|
||||
|
||||
const btcRunFile = `#!/bin/bash
|
||||
set -ex
|
||||
|
||||
b1="bitcoin-cli -datadir=/config"
|
||||
|
||||
function clean {
|
||||
$b1 stop
|
||||
}
|
||||
|
||||
trap clean SIGINT
|
||||
|
||||
bitcoind -datadir=/config &
|
||||
|
||||
sleep 10
|
||||
|
||||
$b1 generate 200
|
||||
wait $!`
|
||||
|
||||
const btcConfigFile = `regtest=1
|
||||
testnet=0
|
||||
dnsseed=0
|
||||
upnp=0
|
||||
|
||||
[regtest]
|
||||
port=19000
|
||||
rpcport=19001
|
||||
|
||||
server=1
|
||||
txindex=0
|
||||
|
||||
rpcuser=admin1
|
||||
rpcpassword=123
|
||||
rpcallowip=0.0.0.0/0`
|
||||
|
||||
const electrsDockerFile = `FROM ubuntu:18.04
|
||||
|
||||
RUN apt-get update && apt-get install --yes wget
|
||||
|
||||
WORKDIR /build
|
||||
RUN wget -qO- https://github.com/vulpemventures/electrs/releases/download/v0.4.1-bin/electrs.tar.gz | tar -xvz && rm -rf electrs.tar.gz
|
||||
|
||||
WORKDIR /scripts
|
||||
ADD run /scripts
|
||||
|
||||
EXPOSE 3002
|
||||
STOPSIGNAL SIGINT
|
||||
|
||||
CMD ["./run"]`
|
||||
|
||||
const electrsRunFile = `#!/bin/bash
|
||||
set -e
|
||||
|
||||
function clean {
|
||||
kill -9 $(pidof electrs)
|
||||
}
|
||||
trap clean SIGINT
|
||||
|
||||
/build/electrs -vvvv --network regtest --daemon-dir /config --daemon-rpc-addr="10.10.0.10:19001" --cookie="admin1:123" --http-addr="0.0.0.0:3002" &
|
||||
wait $!`
|
||||
7
cli/main.go
Normal file
7
cli/main.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package main
|
||||
|
||||
import "github.com/vulpemventures/nigiri/cli/cmd"
|
||||
|
||||
func main() {
|
||||
cmd.RootCmd.Execute()
|
||||
}
|
||||
9
scripts/build
Normal file
9
scripts/build
Normal file
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
set -ex
|
||||
|
||||
PARENT_PATH=$(dirname $(cd $(dirname $0); pwd -P))
|
||||
|
||||
pushd $PARENT_PATH
|
||||
mkdir -p build
|
||||
GOOS=$1 GOARCH=$2 go build -o build/nigiri-$1-$2 ./cli
|
||||
popd
|
||||
10
scripts/install
Normal file
10
scripts/install
Normal file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
set -ex
|
||||
|
||||
PARENT_PATH=$(dirname $(cd $(dirname $0); pwd -P))
|
||||
|
||||
pushd $PARENT_PATH
|
||||
dep ensure -v
|
||||
|
||||
go generate ./...
|
||||
popd
|
||||
Reference in New Issue
Block a user