cardano-up 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 630dda3bb909a92e0fa63562f5aff0f90afa817c8f5170f7567bcf059a962f2e
4
+ data.tar.gz: c37378163253bb7945188c3a8794d6e01d638a0a4a053e887347b9aef5046a48
5
+ SHA512:
6
+ metadata.gz: 7e84594cee7e1fe4716f78c58f1deb39676f0d3ff3d7a721af055d13b6e627e96085dbceabda516665036f0137393121a29176df07bef07c9120872d680013b5
7
+ data.tar.gz: 602b2379f4fd6a2dad86f2f4234ca4c3e7492cb194f73a95e60675f40d502e9dcaef2e3dc37532ae5ccd8b19a48eeddc96d1bd93f1197cceeda64451dd49f10d
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 Piotr Stachyra
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # Cardano Up!
2
+ <a href="https://badge.fury.io/rb/cardano-up">
3
+ <img src="https://badge.fury.io/rb/cardano-up.svg" alt="Gem Version">
4
+ </a>
5
+ <a href="https://github.com/piotr-iohk/cardano-up/releases">
6
+ <img src="https://img.shields.io/github/release/piotr-iohk/cardano-up.svg" />
7
+ </a>
8
+ <a href="https://github.com/piotr-iohk/cardano-up/actions?query=workflow%3ATests">
9
+ <img src="https://github.com/piotr-iohk/cardano-up/workflows/Tests/badge.svg" />
10
+ </a>
11
+ <a href="https://github.com/piotr-iohk/cardano-up/actions?query=workflow%3ADocs">
12
+ <img src="https://github.com/piotr-iohk/cardano-up/workflows/Docs/badge.svg" />
13
+ </a>
14
+ <a href="https://github.com/piotr-iohk/cardano-up/actions?query=workflow%3ARubocop">
15
+ <img src="https://github.com/piotr-iohk/cardano-up/workflows/Rubocop/badge.svg" />
16
+ </a>
17
+
18
+ ## Overview
19
+
20
+ This Ruby gem provides easy way for:
21
+ - getting `cardano-node`, `cardano-cli`, `cardano-wallet`, `cardano-addresses` and `bech32` tools onto your system (Linux, MacOS or Windows).
22
+ - getting configuration for any Cardano public environment.
23
+ - starting, managing and monitoring cardano-node and cardano-wallet services.
24
+
25
+ <img src="cardano-up.gif" />
26
+
27
+ ## Installation
28
+
29
+ $ gem install cardano-up
30
+
31
+ ## Usage
32
+
33
+ It only takes a single command to start node and wallet on your system. Say, on `mainnet`?
34
+
35
+ $ cardano-up mainnet node-wallet up
36
+
37
+ That's it! 🎉
38
+
39
+ If any configs are missing cardano-up will download them. If any binaries are missing cardano-up will get ones from latest release.
40
+
41
+ Call `$ cardano-up --help` to explore more options.
42
+
43
+ ## Documentation
44
+
45
+ | Link | Description |
46
+ |--|--|
47
+ | [Ruby API (edge)](https://piotr-iohk.github.io/cardano-up/master/) | cardano-up API doc |
48
+
49
+ ## How it works
50
+
51
+ **Configurations** for the networks are downloaded from [Cardano Book](https://book.world.dev.cardano.org/environments.html).
52
+
53
+ **Binaries** come from [cardano-wallet](https://github.com/input-output-hk/cardano-wallet) which actually provides `cardano-node`, `cardano-cli`, `cardano-wallet`, `cardano-addresses` and `bech32` tools in each of its release bundles. This ensures that all components are compatible and work smoothly together. You can get any public release of the cardano-wallet bundle as well as `master` version and even any of the PRs that are currently being worked on.
54
+
55
+ **Starting** `cardano-node` and `cardano-wallet`, cardano-up attempts to launch separate [`screen`](https://www.gnu.org/software/screen/) sessions for wallet and node respectively. If screen is not present on your system you can install it using package manager, e.g.:
56
+
57
+ MacOS:
58
+
59
+ $ brew install screen
60
+
61
+ Linux:
62
+
63
+ $ sudo apt-get install screen
64
+
65
+ In case of Windows it will attempt to install cardano-node and cardano-wallet as Windows services using [`nssm`](https://nssm.cc/) tool. Nssm can be installed via choco package manager:
66
+
67
+ $ choco install nssm
68
+
69
+ > :warning: nssm requires administrator permissions to register Windows services, therefore you need to start your cmd as an administrator.
70
+
71
+ By default cardano-up keeps all files at `$HOME/.cardano-up/` however this can be configured by editing `$HOME/.cardano-up/.cardano-up.json` directly or via `config` sub-command. One can check the contents of this internal config file by calling `$ cardano-up config`.
72
+
73
+ ## License
74
+
75
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/bin/cardano-up ADDED
@@ -0,0 +1,236 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'cardano-up'
5
+ require 'docopt'
6
+
7
+ doc = <<~DOCOPT
8
+ Cardano Up!
9
+ Lightweight manager for Cardano binaries and configs.
10
+
11
+ Usage:
12
+ #{File.basename(__FILE__)} install [<release>]
13
+ #{File.basename(__FILE__)} get-configs <env>
14
+ #{File.basename(__FILE__)} <env> (node|wallet|node-wallet) up [--port <port>]
15
+ #{File.basename(__FILE__)} <env> (node|wallet|node-wallet) down
16
+ #{File.basename(__FILE__)} <env> (node|wallet) tail
17
+ #{File.basename(__FILE__)} config [--set-default] [--bindir <path>] [--configdir <path>] [--logdir <path>] [--statedir <path>]
18
+ #{File.basename(__FILE__)} -v | --version
19
+ #{File.basename(__FILE__)} -h | --help
20
+
21
+ Options:
22
+ install Install cardano-node, cardano-cli, cardano-wallet, cardano-addresses and bech32.
23
+ <release> latest | release tag | master | pr num [default: latest]
24
+ get-configs Get configs for particular Cardano environment.
25
+ <env> mainnet | preview | preprod etc.
26
+ up Start particular service. If any configs are missing #{File.basename(__FILE__)}
27
+ will download them. If any binaries are missing #{File.basename(__FILE__)} will get
28
+ ones from latest release.
29
+ down Stop particular service.
30
+ tail Follow logs for particular service.
31
+ --port <port> Specify wallet port. [default: 8090]
32
+
33
+ config Internal config for #{File.basename(__FILE__)}
34
+ --set-default Overwrite config with default values.
35
+ --bindir <path> Set bin dir.
36
+ --configdir <path> Set config dir.
37
+ --logdir <path> Set log dir.
38
+ --statedir <path> Set state dir.
39
+
40
+ -v --version Check #{File.basename(__FILE__)} version and versions of
41
+ installed binaries if available.
42
+ -h --help This help.
43
+ DOCOPT
44
+
45
+ def pretty_json(c)
46
+ puts JSON.pretty_generate(c)
47
+ end
48
+
49
+ def ok
50
+ warn 'Ok.'
51
+ end
52
+
53
+ begin
54
+ CardanoUp.configure_default unless CardanoUp.configured?
55
+ o = Docopt.docopt(doc)
56
+
57
+ # VERSION
58
+ if o['--version'] == true
59
+ warn "#{File.basename(__FILE__)}: #{CardanoUp::VERSION}"
60
+ $stderr.puts
61
+ begin
62
+ pretty_json CardanoUp::Install.return_versions
63
+ rescue StandardError => e
64
+ warn 'Nothing installed? To fix run:'
65
+ warn " $ #{File.basename(__FILE__)} install"
66
+ warn e
67
+ end
68
+ exit 1
69
+ end
70
+
71
+ # CONFIG
72
+ if o['config'] == true
73
+ c = CardanoUp.config
74
+ if o['--set-default'] == true
75
+ c = CardanoUp.configure_default
76
+ warn 'Configs set to default!'
77
+ end
78
+ if o['--bindir']
79
+ bindir = o['--bindir']
80
+ c = CardanoUp.configure(bindir, nil, nil, nil)
81
+ warn 'Installdir updated!'
82
+ end
83
+ if o['--statedir']
84
+ statedir = o['--statedir']
85
+ c = CardanoUp.configure(nil, statedir, nil, nil)
86
+ warn 'Statedir updated!'
87
+ end
88
+ if o['--logdir']
89
+ logdir = o['--logdir']
90
+ c = CardanoUp.configure(nil, nil, logdir, nil)
91
+ warn 'Logdir updated!'
92
+ end
93
+ if o['--configdir']
94
+ configdir = o['--configdir']
95
+ c = CardanoUp.configure(nil, nil, nil, configdir)
96
+ warn 'Configdir updated!'
97
+ end
98
+
99
+ warn "Your config file is #{CardanoUp.adrestia_bundler_config}:"
100
+ $stderr.puts
101
+ pretty_json(c)
102
+ exit
103
+ end
104
+
105
+ # INSTALL
106
+ if o['install'] == true
107
+ release = o['<release>']
108
+ begin
109
+ $stderr.print "Installing '#{release}'... "
110
+ versions = CardanoUp::Install.install_bins(release)
111
+ ok
112
+ rescue CardanoUp::VersionNotSupportedError => e
113
+ warn(e.message)
114
+ exit 1
115
+ end
116
+ warn "Install dir: #{CardanoUp.config['bin_dir']}"
117
+ $stderr.puts
118
+ pretty_json(versions)
119
+ exit
120
+ end
121
+
122
+ # INSTALL CONFIGS
123
+ if o['get-configs'] == true
124
+ env = o['<env>']
125
+ begin
126
+ configs = CardanoUp::Install.install_configs(env)
127
+ rescue CardanoUp::EnvNotSupportedError => e
128
+ warn(e.message)
129
+ exit 1
130
+ end
131
+ warn "Downloaded configs for '#{env}' environment."
132
+ warn "Config dir: #{File.join(CardanoUp.config['config_dir'], env)}"
133
+ $stderr.puts
134
+ pretty_json(configs)
135
+ exit
136
+ end
137
+
138
+ # UP
139
+ if o['up'] == true
140
+ env = o['<env>']
141
+ port = o['--port']
142
+
143
+ begin
144
+ $stderr.print 'Configs: '
145
+ unless CardanoUp::Install.configs_exist?(env)
146
+ $stderr.print "installing configs for #{env}... "
147
+ CardanoUp::Install.install_configs(env)
148
+ end
149
+ ok
150
+
151
+ $stderr.print 'Binaries: '
152
+ begin
153
+ CardanoUp::Install.return_versions
154
+ ok
155
+ rescue StandardError
156
+ $stderr.print 'installing latest release binaries... '
157
+ CardanoUp::Install.install_bins('latest')
158
+ ok
159
+ end
160
+
161
+ $stderr.puts
162
+ warn 'Starting...'
163
+ $stderr.puts
164
+ c = CardanoUp::Start.prepare_configuration({ env: env, wallet_port: port })
165
+ rescue CardanoUp::EnvNotSupportedError => e
166
+ warn(e.message)
167
+ exit 1
168
+ end
169
+ begin
170
+ if o['node']
171
+ pretty_json CardanoUp::Start.start_node(c)
172
+ $stderr.puts
173
+ warn "Congratulations! You've just started cardano-node!"
174
+ elsif o['wallet']
175
+ pretty_json CardanoUp::Start.start_wallet(c)
176
+ $stderr.puts
177
+ warn "Congratulations! You've just started cardano-wallet!"
178
+ elsif o['node-wallet']
179
+ pretty_json CardanoUp::Start.start_node_and_wallet(c)
180
+ $stderr.puts
181
+ warn "Congratulations! You've just started cardano-node and cardano-wallet!"
182
+ end
183
+ rescue StandardError => e
184
+ warn 'Either you miss configs or binaries... To fix that try running:'
185
+ warn " $ #{File.basename(__FILE__)} get-configs #{env}"
186
+ warn " $ #{File.basename(__FILE__)} install"
187
+ warn e
188
+ exit 1
189
+ end
190
+ end
191
+
192
+ # STOP
193
+ if o['down'] == true
194
+ env = o['<env>']
195
+
196
+ begin
197
+ if o['node']
198
+ CardanoUp::Start.stop_node(env)
199
+ elsif o['wallet']
200
+ CardanoUp::Start.stop_wallet(env)
201
+ elsif o['node-wallet']
202
+ CardanoUp::Start.stop_node_and_wallet(env)
203
+ end
204
+ warn 'Stopped.'
205
+ rescue CardanoUp::EnvNotSupportedError => e
206
+ warn(e.message)
207
+ exit 1
208
+ end
209
+ end
210
+
211
+ # TAIL
212
+ if o['tail'] == true
213
+ env = o['<env>']
214
+ begin
215
+ log_dir = File.join(CardanoUp.config['log_dir'], env)
216
+ if o['node']
217
+ log_file = File.join(log_dir, 'node.log')
218
+ CardanoUp::Tail.tail(log_file)
219
+ elsif o['wallet']
220
+ log_file = File.join(log_dir, 'wallet.log')
221
+ CardanoUp::Tail.tail(log_file)
222
+ end
223
+ rescue CardanoUp::EnvNotSupportedError => e
224
+ warn(e.message)
225
+ exit 1
226
+ rescue StandardError => e
227
+ warn "Log file does not seem to exist: #{log_file}"
228
+ warn(e.message)
229
+ exit 1
230
+ rescue Interrupt
231
+ exit
232
+ end
233
+ end
234
+ rescue Docopt::Exit => e
235
+ puts e.message
236
+ end
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'cardano-up'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
data/bin/rebuild ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+ gem build *.gemspec -o cardano-up.gem
3
+ gem install cardano-up.gem
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CardanoUp
4
+ # Thrown when env is not supported
5
+ class EnvNotSupportedError < StandardError
6
+ def initialize(env)
7
+ super("Environment '#{env}' not supported. Supported are: #{ENVS}")
8
+ end
9
+ end
10
+
11
+ # Thrown when cardano_up internal config does not exists
12
+ class ConfigNotSetError < StandardError
13
+ def initialize
14
+ super("Config not exists at '#{CardanoUp.cardano_up_config}'!")
15
+ end
16
+ end
17
+
18
+ # Thrown when wallet port is not set
19
+ class WalletPortError < StandardError
20
+ def initialize
21
+ super('Wallet port is not set!')
22
+ end
23
+ end
24
+
25
+ # Thrown when version of bundle to download is not supported
26
+ class VersionNotSupportedError < StandardError
27
+ def initialize(ver)
28
+ super(["Not supported version: #{ver}. Supported are: 'latest', 'master',",
29
+ "tag (e.g. 'v2022-08-16') or pr number ('3045')"].join(' '))
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CardanoUp
4
+ # Installing configs for Cardano environments and binaries
5
+ module Install
6
+ # Check all necessary config files for particular environment exist.
7
+ # @param env [String] - one of {ENVS}
8
+ # @raise CardanoUp::EnvNotSupportedError
9
+ def self.configs_exist?(env)
10
+ CardanoUp.configure_default unless CardanoUp.configured?
11
+ raise CardanoUp::EnvNotSupportedError, env unless CardanoUp::ENVS.include?(env)
12
+
13
+ configs = CardanoUp.config
14
+ config_dir_env = FileUtils.mkdir_p(File.join(configs['config_dir'], env))
15
+ config_files = CardanoUp::CONFIG_FILES
16
+ not_existing = []
17
+ config_files.each do |file|
18
+ conf_file_path = File.join(config_dir_env, file)
19
+ not_existing << conf_file_path unless File.exist?(conf_file_path)
20
+ end
21
+ not_existing.empty?
22
+ end
23
+
24
+ # Get all necessary config files for particular environment.
25
+ # @param env [String] - one of {ENVS}
26
+ # @raise CardanoUp::EnvNotSupportedError
27
+ def self.install_configs(env)
28
+ CardanoUp.configure_default unless CardanoUp.configured?
29
+ raise CardanoUp::EnvNotSupportedError, env unless CardanoUp::ENVS.include?(env)
30
+
31
+ configs = CardanoUp.config
32
+ config_urls = CardanoUp::Utils.config_urls(env)
33
+ config_dir_env = FileUtils.mkdir_p(File.join(configs['config_dir'], env))
34
+ config_urls.each do |url|
35
+ CardanoUp::Utils.wget(url, File.join(config_dir_env, File.basename(url)))
36
+ end
37
+ end
38
+
39
+ # Get cardano-wallet bundle binaries to your computer.
40
+ # @param release [String] - 'latest' | /^v20.{2}-.{2}-.{2}/ | 'master' | '3341'
41
+ # @raise CardanoUp::VersionNotSupportedError
42
+ def self.install_bins(release)
43
+ CardanoUp.configure_default unless CardanoUp.configured?
44
+ configs = CardanoUp.config
45
+ url = CardanoUp::Utils.get_binary_url(release)
46
+ bin_dir_env = FileUtils.mkdir_p(configs['bin_dir']).first
47
+ file_to_unpack = File.join(bin_dir_env, 'binary-dist')
48
+ CardanoUp::Utils.wget(url, file_to_unpack)
49
+
50
+ unpack_binary(file_to_unpack, bin_dir_env)
51
+ return_versions(bin_dir_env)
52
+ end
53
+
54
+ def unpack_binary(file_path, destination)
55
+ if CardanoUp::Utils.win?
56
+ CardanoUp::Tar.unzip(file_path, destination)
57
+ else
58
+ gio = CardanoUp::Tar.ungzip(File.open(file_path, 'rb'))
59
+ CardanoUp::Tar.untar(gio, destination)
60
+ cw_dir = Dir[File.join(destination, '/cardano-wallet-*')].first
61
+ FileUtils.cp_r(Dir[File.join(cw_dir, '/*')], destination)
62
+ FileUtils.rm_rf(file_path)
63
+ FileUtils.rm_rf(cw_dir)
64
+ executables = Dir[File.join(destination, '/cardano-*')] << File.join(destination, '/bech32')
65
+ executables.each { |e| FileUtils.chmod('u+x', e) }
66
+ executables
67
+ end
68
+ end
69
+ module_function :unpack_binary
70
+ private_class_method :unpack_binary
71
+
72
+ # Return versions of installed components
73
+ # @raise CardanoUp::ConfigNotSetError
74
+ def self.return_versions(bin_dir = nil)
75
+ bindir = bin_dir.nil? ? CardanoUp.config['bin_dir'] : bin_dir
76
+ exe = CardanoUp::Utils.win? ? '.exe' : ''
77
+ cn = CardanoUp::Utils.cmd "#{bindir}/cardano-node#{exe} version"
78
+ cli = CardanoUp::Utils.cmd "#{bindir}/cardano-cli#{exe} version"
79
+ cw = CardanoUp::Utils.cmd "#{bindir}/cardano-wallet#{exe} version"
80
+ ca = CardanoUp::Utils.cmd "#{bindir}/cardano-address#{exe} version"
81
+ b32 = CardanoUp::Utils.cmd "#{bindir}/bech32#{exe} --version"
82
+ { 'cardano-node' => cn,
83
+ 'cardano-cli' => cli,
84
+ 'cardano-wallet' => cw,
85
+ 'cardano-address' => ca,
86
+ 'bech32' => b32 }
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,248 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CardanoUp
4
+ ##
5
+ # Start cardano-node and cardano-wallet on your system.
6
+ #
7
+ # For Linux and MacOS it will attempt to start separate screen sessions for
8
+ # wallet and node respectively, therefore 'screen' tool is required on your system.
9
+ # @see https://www.gnu.org/software/screen/
10
+ # If screen is not present you can install it using your package manager for instance:
11
+ # # MacOS:
12
+ # brew install screen
13
+ # # Linux:
14
+ # sudo apt-get install screen
15
+ #
16
+ # For Windows it will attepmt to install cardano-node and cardano-wallet as Windows services
17
+ # using 'nssm' tool.
18
+ # @see https://nssm.cc/
19
+ # Nssm can be installed via choco package manager:
20
+ # choco install nssm
21
+ module Start
22
+ # Prepare configuration for wallet and node to be started
23
+ # @param env [Hash] provide env and wallet_port, e.g. { env: 'mainnet', wallet_port: '8090' }
24
+ # @raise CardanoUp::EnvNotSupportedError
25
+ # @raise CardanoUp::WalletPortError
26
+ def self.prepare_configuration(opt = { env: 'mainnet', wallet_port: '8090' })
27
+ env = opt[:env]
28
+ raise CardanoUp::EnvNotSupportedError, env unless CardanoUp::ENVS.include? env
29
+
30
+ wallet_port = opt[:wallet_port]
31
+ raise CardanoUp::WalletPortError if wallet_port.nil? || wallet_port.empty?
32
+
33
+ token_metadata_server = env == 'mainnet' ? CardanoUp::MAINNET_TOKEN_SERVER : CardanoUp::TESTNET_TOKEN_SERVER
34
+
35
+ CardanoUp.configure_default unless CardanoUp.configured?
36
+ configs = CardanoUp.config
37
+ bin_dir = configs['bin_dir']
38
+ config_dir = File.join(configs['config_dir'], env)
39
+ log_dir = File.join(configs['log_dir'], env)
40
+ state_dir = File.join(configs['state_dir'], env)
41
+ wallet_db_dir = File.join(state_dir, 'wallet-db')
42
+ node_db_dir = File.join(state_dir, 'node-db')
43
+ [bin_dir, config_dir, log_dir, state_dir, wallet_db_dir, node_db_dir].each do |dir|
44
+ FileUtils.mkdir_p(dir)
45
+ end
46
+
47
+ node_socket = if CardanoUp::Utils.win?
48
+ "\\\\.\\pipe\\cardano-node-#{env}"
49
+ else
50
+ File.join(state_dir, 'node.socket')
51
+ end
52
+ network = env == 'mainnet' ? '--mainnet' : "--testnet #{config_dir}/byron-genesis.json"
53
+
54
+ {
55
+ env: env,
56
+ wallet_port: wallet_port,
57
+ token_metadata_server: token_metadata_server,
58
+ bin_dir: bin_dir,
59
+ config_dir: config_dir,
60
+ log_dir: log_dir,
61
+ state_dir: state_dir,
62
+ wallet_db_dir: wallet_db_dir,
63
+ node_db_dir: node_db_dir,
64
+ node_socket: node_socket,
65
+ network: network
66
+ }
67
+ end
68
+
69
+ # @param configuration [Hash] output of prepare_configuration
70
+ def self.start_node(configuration)
71
+ env = configuration[:env]
72
+ bin_dir = configuration[:bin_dir]
73
+ config_dir = configuration[:config_dir]
74
+ log_dir = configuration[:log_dir]
75
+ node_db_dir = configuration[:node_db_dir]
76
+ node_socket = configuration[:node_socket]
77
+
78
+ exe = CardanoUp::Utils.win? ? '.exe' : ''
79
+ version = CardanoUp::Utils.cmd "#{bin_dir}/cardano-node#{exe} version"
80
+
81
+ if CardanoUp::Utils.win?
82
+ # Turn off p2p for Windows
83
+ # TODO: remove after https://github.com/input-output-hk/ouroboros-network/issues/3968 released
84
+ config_win = JSON.parse(File.read("#{config_dir}/config.json"))
85
+ config_win['EnableP2P'] = false
86
+ File.write("#{config_dir}/config.json", JSON.pretty_generate(config_win))
87
+ topology = %({
88
+ "Producers": [
89
+ {
90
+ "addr": "#{env}-node.world.dev.cardano.org",
91
+ "port": 30002,
92
+ "valency": 2
93
+ }
94
+ ]
95
+ })
96
+ File.write("#{config_dir}/topology.json", topology)
97
+
98
+ # create cardano-node.bat file
99
+ node_cmd = ["#{bin_dir}/cardano-node.exe run",
100
+ "--config #{config_dir}/config.json",
101
+ "--topology #{config_dir}/topology.json",
102
+ "--database-path #{node_db_dir}",
103
+ "--socket-path #{node_socket}"].join(' ')
104
+ File.write("#{bin_dir}/cardano-node.bat", node_cmd)
105
+ node_service = "cardano-node-#{env}"
106
+ install_node = "nssm install #{node_service} #{bin_dir}/cardano-node.bat"
107
+ log_stdout_node = "nssm set #{node_service} AppStdout #{log_dir}/node.log"
108
+ log_stderr_node = "nssm set #{node_service} AppStderr #{log_dir}/node.log"
109
+ start_node = "nssm start #{node_service}"
110
+
111
+ CardanoUp::Utils.cmd install_node
112
+ CardanoUp::Utils.cmd log_stdout_node
113
+ CardanoUp::Utils.cmd log_stderr_node
114
+ CardanoUp::Utils.cmd start_node
115
+ else
116
+ node_cmd = ["#{bin_dir}/cardano-node run",
117
+ "--config #{config_dir}/config.json",
118
+ "--topology #{config_dir}/topology.json",
119
+ "--database-path #{node_db_dir}",
120
+ "--socket-path #{node_socket}"].join(' ')
121
+ node_service = "NODE_#{env}"
122
+ CardanoUp::Utils.cmd "screen -dmS #{node_service} -L -Logfile #{log_dir}/node.log #{node_cmd}"
123
+ end
124
+
125
+ {
126
+ node: {
127
+ service: node_service,
128
+ network: env,
129
+ version: version,
130
+ log: "#{log_dir}/node.log",
131
+ db_dir: node_db_dir,
132
+ socket_path: node_socket,
133
+ protocol_magic: get_protocol_magic(config_dir),
134
+ bin: node_cmd.split.first,
135
+ cmd: node_cmd
136
+ }
137
+ }
138
+ end
139
+
140
+ # @param configuration [Hash] output of prepare_configuration
141
+ def self.start_wallet(configuration)
142
+ env = configuration[:env]
143
+ wallet_port = configuration[:wallet_port]
144
+ token_metadata_server = configuration[:token_metadata_server]
145
+ bin_dir = configuration[:bin_dir]
146
+ log_dir = configuration[:log_dir]
147
+ wallet_db_dir = configuration[:wallet_db_dir]
148
+ node_socket = configuration[:node_socket]
149
+ network = configuration[:network]
150
+
151
+ exe = CardanoUp::Utils.win? ? '.exe' : ''
152
+ version = CardanoUp::Utils.cmd "#{bin_dir}/cardano-wallet#{exe} version"
153
+
154
+ if CardanoUp::Utils.win?
155
+
156
+ # create cardano-wallet.bat file
157
+ wallet_cmd = ["#{bin_dir}/cardano-wallet.exe serve",
158
+ "--port #{wallet_port}",
159
+ "--node-socket #{node_socket}",
160
+ network.to_s,
161
+ "--database #{wallet_db_dir}",
162
+ "--token-metadata-server #{token_metadata_server}"].join(' ')
163
+ File.write("#{bin_dir}/cardano-wallet.bat", wallet_cmd)
164
+ wallet_service = "cardano-wallet-#{env}"
165
+ install_wallet = "nssm install #{wallet_service} #{bin_dir}/cardano-wallet.bat"
166
+ log_stdout_wallet = "nssm set #{wallet_service} AppStdout #{log_dir}/wallet.log"
167
+ log_stderr_wallet = "nssm set #{wallet_service} AppStderr #{log_dir}/wallet.log"
168
+ start_wallet = "nssm start #{wallet_service}"
169
+
170
+ CardanoUp::Utils.cmd install_wallet
171
+ CardanoUp::Utils.cmd log_stdout_wallet
172
+ CardanoUp::Utils.cmd log_stderr_wallet
173
+ CardanoUp::Utils.cmd start_wallet
174
+ else
175
+ wallet_cmd = ["#{bin_dir}/cardano-wallet serve",
176
+ "--port #{wallet_port}",
177
+ "--node-socket #{node_socket}",
178
+ network.to_s,
179
+ "--database #{wallet_db_dir}",
180
+ "--token-metadata-server #{token_metadata_server}"].join(' ')
181
+ wallet_service = "WALLET_#{env}"
182
+ CardanoUp::Utils.cmd "screen -dmS #{wallet_service} -L -Logfile #{log_dir}/wallet.log #{wallet_cmd}"
183
+ end
184
+
185
+ {
186
+ wallet: {
187
+ service: wallet_service,
188
+ network: env,
189
+ version: version,
190
+ log: "#{log_dir}/wallet.log",
191
+ db_dir: wallet_db_dir,
192
+ port: wallet_port.to_i,
193
+ host: "http://localhost:#{wallet_port}/v2",
194
+ bin: wallet_cmd.split.first,
195
+ cmd: wallet_cmd
196
+ }
197
+ }
198
+ end
199
+
200
+ # @param configuration [Hash] output of prepare_configuration
201
+ def self.start_node_and_wallet(configuration)
202
+ cn = start_node(configuration)
203
+ cw = start_wallet(configuration)
204
+ cn.merge(cw)
205
+ end
206
+
207
+ # @raise CardanoUp::EnvNotSupportedError
208
+ def self.stop_node(env)
209
+ raise CardanoUp::EnvNotSupportedError, env unless CardanoUp::ENVS.include? env
210
+
211
+ if CardanoUp::Utils.win?
212
+ CardanoUp::Utils.cmd "nssm stop cardano-node-#{env}"
213
+ CardanoUp::Utils.cmd "nssm remove cardano-node-#{env} confirm"
214
+ else
215
+ CardanoUp::Utils.cmd "screen -S NODE_#{env} -X at '0' stuff '^C'"
216
+ CardanoUp::Utils.cmd "screen -XS NODE_#{env} quit"
217
+ end
218
+ end
219
+
220
+ # @raise CardanoUp::EnvNotSupportedError
221
+ def self.stop_wallet(env)
222
+ raise CardanoUp::EnvNotSupportedError, env unless CardanoUp::ENVS.include? env
223
+
224
+ if CardanoUp::Utils.win?
225
+ CardanoUp::Utils.cmd "nssm stop cardano-wallet-#{env}"
226
+ CardanoUp::Utils.cmd "nssm remove cardano-wallet-#{env} confirm"
227
+ else
228
+ CardanoUp::Utils.cmd "screen -S WALLET_#{env} -X at '0' stuff '^C'"
229
+ CardanoUp::Utils.cmd "screen -XS WALLET_#{env} quit"
230
+ end
231
+ end
232
+
233
+ # @raise CardanoUp::EnvNotSupportedError
234
+ def self.stop_node_and_wallet(env)
235
+ stop_wallet(env)
236
+ stop_node(env)
237
+ end
238
+
239
+ ##
240
+ # Get protocol magic from config's byron-genesis.json
241
+ def get_protocol_magic(config)
242
+ byron_genesis = JSON.parse(File.read(File.join(config, 'byron-genesis.json')))
243
+ byron_genesis['protocolConsts']['protocolMagic'].to_i
244
+ end
245
+ module_function :get_protocol_magic
246
+ private_class_method :get_protocol_magic
247
+ end
248
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CardanoUp
4
+ # Tail log file
5
+ module Tail
6
+ def self.tail(file_path)
7
+ File.open(file_path) do |log|
8
+ log.extend(File::Tail)
9
+ log.interval
10
+ log.backward(10)
11
+ log.tail { |line| warn line }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CardanoUp
4
+ # unpacking archives
5
+ module Tar
6
+ # unzip file to destination directory
7
+ def self.unzip(file, destination)
8
+ FileUtils.mkdir_p(destination)
9
+ Zip::File.open(file) do |zip_file|
10
+ zip_file.each do |f|
11
+ fpath = File.join(destination, f.name)
12
+ zip_file.extract(f, fpath)
13
+ end
14
+ end
15
+ end
16
+
17
+ # un-gzips the given IO, returning the
18
+ # decompressed version as a StringIO
19
+ def self.ungzip(tarfile)
20
+ z = Zlib::GzipReader.new(tarfile)
21
+ unzipped = StringIO.new(z.read)
22
+ z.close
23
+ unzipped
24
+ end
25
+
26
+ # untars the given IO into the specified
27
+ # directory
28
+ def self.untar(io, destination)
29
+ Gem::Package::TarReader.new io do |tar|
30
+ tar.each do |tarfile|
31
+ destination_file = File.join destination, tarfile.full_name
32
+
33
+ if tarfile.directory?
34
+ FileUtils.mkdir_p destination_file
35
+ else
36
+ destination_directory = File.dirname(destination_file)
37
+ FileUtils.mkdir_p destination_directory unless File.directory?(destination_directory)
38
+ File.open destination_file, 'wb' do |f|
39
+ f.print tarfile.read
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CardanoUp
4
+ # Utility methods
5
+ module Utils
6
+ def self.cmd(cmd, display_result: false)
7
+ cmd.gsub(/\s+/, ' ')
8
+ res = `#{cmd}`
9
+ puts cmd if display_result
10
+ puts res if display_result
11
+ res.gsub("\n", '')
12
+ end
13
+
14
+ def self.wget(url, file = nil)
15
+ file ||= File.basename(url)
16
+ resp = HTTParty.get(url)
17
+ File.binwrite(file, resp.body)
18
+ end
19
+
20
+ def self.win?
21
+ RUBY_PLATFORM =~ /cygwin|mswin|mingw|bccwin|wince|emx/
22
+ end
23
+
24
+ def self.linux?
25
+ RUBY_PLATFORM =~ /linux/
26
+ end
27
+
28
+ def self.mac?
29
+ RUBY_PLATFORM =~ /darwin/
30
+ end
31
+
32
+ def self.latest_tag
33
+ HTTParty.get("#{CardanoUp::BINS_BASE_URL}/releases/latest",
34
+ headers: { 'Accept' => 'application/json' })['tag_name']
35
+ end
36
+
37
+ ##
38
+ # Latest binary url for latest release or particular tag, from master or pr num.
39
+ # @param release [String] - 'latest' | /^v20.{2}-.{2}-.{2}/ | 'master' | '3341'
40
+ # @raise CardanoUp::VersionNotSupportedError
41
+ def self.get_binary_url(release = 'latest')
42
+ unless release == 'master' || release == 'latest' || release =~ /^v20.{2}-.{2}-.{2}/ || release =~ /^\d+$/
43
+ raise CardanoUp::VersionNotSupportedError, release
44
+ end
45
+
46
+ url = ''
47
+ if release == 'latest' || release =~ /^v20.{2}-.{2}-.{2}/
48
+ tag = release == 'latest' ? latest_tag : release
49
+ if linux?
50
+ file = "cardano-wallet-#{tag}-linux64.tar.gz"
51
+ elsif mac?
52
+ file = "cardano-wallet-#{tag}-macos-intel.tar.gz"
53
+ elsif win?
54
+ file = "cardano-wallet-#{tag}-win64.zip"
55
+ end
56
+ url = "#{CardanoUp::BINS_BASE_URL}/releases/download/#{tag}/#{file}"
57
+ else
58
+ if linux?
59
+ os = 'linux.musl.cardano-wallet-linux64'
60
+ elsif mac?
61
+ os = 'macos.intel.cardano-wallet-macos-intel'
62
+ elsif win?
63
+ os = 'linux.windows.cardano-wallet-win64'
64
+ end
65
+
66
+ url = if release == 'master'
67
+ "#{CardanoUp::HYDRA_BASE_URL}/#{os}/latest/download-by-type/file/binary-dist"
68
+ else
69
+ "#{CardanoUp::HYDRA_BASE_URL}-pr-#{release}/#{os}/latest/download-by-type/file/binary-dist"
70
+ end
71
+ end
72
+ url
73
+ end
74
+
75
+ ##
76
+ # Latest Cardano configs
77
+ # @raise CardanoUp::EnvNotSupportedError
78
+ def self.configs_base_url(env)
79
+ raise CardanoUp::EnvNotSupportedError, env unless CardanoUp::ENVS.include?(env)
80
+
81
+ "#{CardanoUp::CONFIGS_BASE_URL}/#{env}/"
82
+ end
83
+
84
+ # @raise CardanoUp::EnvNotSupportedError
85
+ def self.config_urls(env)
86
+ raise CardanoUp::EnvNotSupportedError, env unless CardanoUp::ENVS.include?(env)
87
+
88
+ base_url = configs_base_url(env)
89
+ configs = []
90
+ CardanoUp::CONFIG_FILES.each do |file|
91
+ configs << "#{base_url}#{file}"
92
+ end
93
+ configs
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Version
4
+ module CardanoUp
5
+ VERSION ||= '0.1.0'
6
+ end
data/lib/cardano-up.rb ADDED
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubygems'
4
+ require 'rubygems/package'
5
+ require 'httparty'
6
+ require 'fileutils'
7
+ require 'file-tail'
8
+ require 'json'
9
+ require 'zlib'
10
+ require 'zip'
11
+
12
+ require 'cardano-up/version'
13
+ require 'cardano-up/err'
14
+ require 'cardano-up/utils'
15
+ require 'cardano-up/tar'
16
+ require 'cardano-up/install'
17
+ require 'cardano-up/start'
18
+ require 'cardano-up/tail'
19
+
20
+ # Cardano Up!
21
+ # Lightweight manager for Cardano binaries and configs.
22
+ module CardanoUp
23
+ CONFIGS_BASE_URL = 'https://book.world.dev.cardano.org/environments'
24
+ BINS_BASE_URL = 'https://github.com/input-output-hk/cardano-wallet'
25
+ HYDRA_BASE_URL = 'https://hydra.iohk.io/job/Cardano/cardano-wallet'
26
+ ENVS = %w[mainnet preview preprod shelley-qa
27
+ staging vasil-qa vasil-dev mixed testnet].freeze
28
+ CONFIG_FILES = ['alonzo-genesis.json', 'byron-genesis.json', 'shelley-genesis.json',
29
+ 'config.json', 'topology.json'].freeze
30
+ MAINNET_TOKEN_SERVER = 'https://tokens.cardano.org'
31
+ TESTNET_TOKEN_SERVER = 'https://metadata.cardano-testnet.iohkdev.io'
32
+ # It is recommended to use default value for {base_dir},
33
+ # however it is possible to modify it with {base_dir=}.
34
+ @base_dir = File.join(Dir.home, '.cardano-up')
35
+
36
+ # It is recommended to use default value for {cardano_up_config},
37
+ # however it is possible to modify it with {cardano_up_config=}.
38
+ @cardano_up_config = File.join(@base_dir, '.cardano-up.json')
39
+
40
+ def self.base_dir
41
+ @base_dir
42
+ end
43
+
44
+ def self.base_dir=(value)
45
+ @base_dir = value
46
+ @cardano_up_config = File.join(@base_dir, 'config.json')
47
+ @base_dir
48
+ end
49
+
50
+ def self.cardano_up_config
51
+ @cardano_up_config
52
+ end
53
+
54
+ def self.cardano_up_config=(value)
55
+ @cardano_up_config = value
56
+ end
57
+
58
+ # Check if CardanoUp config exists
59
+ def self.configured?
60
+ File.exist?(@cardano_up_config)
61
+ end
62
+
63
+ # Set default config for CardanoUp
64
+ def self.configure_default
65
+ configure(File.join(@base_dir, 'bins'),
66
+ File.join(@base_dir, 'state'),
67
+ File.join(@base_dir, 'logs'),
68
+ File.join(@base_dir, 'configs'))
69
+ end
70
+
71
+ # Set custom config for CardanoUp
72
+ def self.configure(bin_dir, state_dir, logs_dir, config_dir)
73
+ FileUtils.mkdir_p(@base_dir)
74
+ c = if configured?
75
+ CardanoUp.config
76
+ else
77
+ { 'bin_dir' => File.join(@base_dir, 'bins'),
78
+ 'state_dir' => File.join(@base_dir, 'state'),
79
+ 'log_dir' => File.join(@base_dir, 'state'),
80
+ 'config_dir' => File.join(@base_dir, 'configs') }
81
+ end
82
+ c['bin_dir'] = bin_dir if bin_dir
83
+ c['state_dir'] = state_dir if state_dir
84
+ c['log_dir'] = logs_dir if logs_dir
85
+ c['config_dir'] = config_dir if config_dir
86
+ File.write(@cardano_up_config, JSON.pretty_generate(c))
87
+ JSON.parse(File.read(@cardano_up_config))
88
+ end
89
+
90
+ # Get config values
91
+ def self.config
92
+ raise CardanoUp::ConfigNotSetError unless configured?
93
+
94
+ JSON.parse(File.read(@cardano_up_config))
95
+ end
96
+
97
+ # Remove configuration file
98
+ def self.remove_cardano_up_config
99
+ FileUtils.rm_f(@cardano_up_config)
100
+ end
101
+
102
+ # dir [String] config dir
103
+ def self.clean_config_dir(dir)
104
+ FileUtils.rm_f(config[dir])
105
+ end
106
+ end
metadata ADDED
@@ -0,0 +1,166 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cardano-up
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Piotr Stachyra
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-10-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: docopt
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.6.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.6.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: file-tail
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 1.2.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 1.2.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: httparty
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 0.20.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 0.20.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubyzip
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 2.3.2
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 2.3.2
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '12.3'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '12.3'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.11'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.11'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.36'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.36'
111
+ description: |-
112
+ Cardano Up lets you get all essential Cardano
113
+ tools on your system: cardano-node, cardano-cli, cardano-wallet,
114
+ cardano-addresses and bech32. Then easily manage configuration
115
+ for different environments and launch node and wallet services.
116
+ email:
117
+ - piotr.stachyra@gmail.com
118
+ executables:
119
+ - cardano-up
120
+ extensions: []
121
+ extra_rdoc_files: []
122
+ files:
123
+ - LICENSE.txt
124
+ - README.md
125
+ - bin/cardano-up
126
+ - bin/console
127
+ - bin/rebuild
128
+ - bin/setup
129
+ - lib/cardano-up.rb
130
+ - lib/cardano-up/err.rb
131
+ - lib/cardano-up/install.rb
132
+ - lib/cardano-up/start.rb
133
+ - lib/cardano-up/tail.rb
134
+ - lib/cardano-up/tar.rb
135
+ - lib/cardano-up/utils.rb
136
+ - lib/cardano-up/version.rb
137
+ homepage: https://github.com/piotr-iohk/cardano-up
138
+ licenses:
139
+ - MIT
140
+ metadata:
141
+ allowed_push_host: https://rubygems.org/
142
+ homepage_uri: https://github.com/piotr-iohk/cardano-up
143
+ source_code_uri: https://github.com/piotr-iohk/cardano-up
144
+ changelog_uri: https://github.com/piotr-iohk/cardano-up
145
+ rubygems_mfa_required: 'true'
146
+ post_install_message:
147
+ rdoc_options: []
148
+ require_paths:
149
+ - lib
150
+ - bin
151
+ required_ruby_version: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ version: 2.7.0
156
+ required_rubygems_version: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ requirements: []
162
+ rubygems_version: 3.0.3.1
163
+ signing_key:
164
+ specification_version: 4
165
+ summary: Lightweight manager for Cardano binaries and configs.
166
+ test_files: []