zold 0.16.27 → 0.16.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/bin/zold +19 -8
  4. data/fixtures/scripts/distribute-wallet.sh +1 -1
  5. data/fixtures/scripts/pull-on-start.sh +1 -1
  6. data/fixtures/scripts/push-and-pull.sh +1 -1
  7. data/fixtures/scripts/spread-wallets.sh +1 -1
  8. data/lib/zold/commands/alias.rb +4 -1
  9. data/lib/zold/commands/calculate.rb +4 -1
  10. data/lib/zold/commands/clean.rb +1 -1
  11. data/lib/zold/commands/create.rb +6 -3
  12. data/lib/zold/commands/diff.rb +4 -1
  13. data/lib/zold/commands/fetch.rb +4 -1
  14. data/lib/zold/commands/invoice.rb +4 -1
  15. data/lib/zold/commands/list.rb +12 -4
  16. data/lib/zold/commands/merge.rb +8 -1
  17. data/lib/zold/commands/next.rb +4 -1
  18. data/lib/zold/commands/node.rb +6 -3
  19. data/lib/zold/commands/pay.rb +4 -1
  20. data/lib/zold/commands/propagate.rb +4 -1
  21. data/lib/zold/commands/pull.rb +4 -1
  22. data/lib/zold/commands/push.rb +4 -1
  23. data/lib/zold/commands/remote.rb +6 -3
  24. data/lib/zold/commands/remove.rb +4 -1
  25. data/lib/zold/commands/routines/reconnect.rb +1 -1
  26. data/lib/zold/commands/routines/spread.rb +1 -1
  27. data/lib/zold/commands/show.rb +7 -3
  28. data/lib/zold/commands/taxes.rb +4 -1
  29. data/lib/zold/commands/thread_badge.rb +47 -0
  30. data/lib/zold/copies.rb +1 -1
  31. data/lib/zold/endless.rb +1 -1
  32. data/lib/zold/http.rb +3 -3
  33. data/lib/zold/key.rb +3 -0
  34. data/lib/zold/log.rb +52 -111
  35. data/lib/zold/metronome.rb +12 -10
  36. data/lib/zold/node/async_entrance.rb +2 -2
  37. data/lib/zold/node/entrance.rb +1 -1
  38. data/lib/zold/node/farm.rb +1 -1
  39. data/lib/zold/node/farmers.rb +1 -1
  40. data/lib/zold/node/front.rb +5 -5
  41. data/lib/zold/node/nodup_entrance.rb +1 -1
  42. data/lib/zold/node/spread_entrance.rb +1 -1
  43. data/lib/zold/node/sync_entrance.rb +1 -1
  44. data/lib/zold/patch.rb +2 -2
  45. data/lib/zold/remotes.rb +1 -1
  46. data/lib/zold/signature.rb +5 -1
  47. data/lib/zold/sync_wallets.rb +1 -1
  48. data/lib/zold/upgrades.rb +1 -1
  49. data/lib/zold/verbose_thread.rb +1 -1
  50. data/lib/zold/version.rb +1 -1
  51. data/lib/zold/version_file.rb +1 -1
  52. data/lib/zold/wallet.rb +2 -2
  53. data/resources/root.pub +14 -0
  54. data/test/commands/test_list.rb +2 -1
  55. data/test/commands/test_remote.rb +35 -4
  56. data/test/commands/test_show.rb +1 -1
  57. data/test/fake_home.rb +1 -1
  58. data/test/node/fake_node.rb +3 -2
  59. data/test/node/test_farm.rb +1 -1
  60. data/test/test__helper.rb +4 -3
  61. data/test/test_dir_items.rb +1 -1
  62. data/test/test_http.rb +44 -6
  63. data/test/test_key.rb +7 -0
  64. data/test/test_log.rb +12 -1
  65. data/test/test_remotes.rb +1 -1
  66. data/test/test_signature.rb +1 -0
  67. data/test/test_verbose_thread.rb +3 -3
  68. data/test/test_zold.rb +4 -3
  69. data/zold.gemspec +3 -2
  70. metadata +8 -5
@@ -24,6 +24,7 @@ require 'rainbow'
24
24
  require 'slop'
25
25
  require 'json'
26
26
  require 'net/http'
27
+ require_relative 'thread_badge'
27
28
  require_relative 'args'
28
29
  require_relative '../age'
29
30
  require_relative '../size'
@@ -39,7 +40,9 @@ require_relative '../json_page'
39
40
  module Zold
40
41
  # Wallet pushing command
41
42
  class Push
42
- def initialize(wallets:, remotes:, log: Log::Quiet.new)
43
+ prepend ThreadBadge
44
+
45
+ def initialize(wallets:, remotes:, log: Log::NULL)
43
46
  @wallets = wallets
44
47
  @remotes = remotes
45
48
  @log = log
@@ -27,6 +27,7 @@ require 'net/http'
27
27
  require 'json'
28
28
  require 'time'
29
29
  require 'zold/score'
30
+ require_relative 'thread_badge'
30
31
  require_relative 'args'
31
32
  require_relative '../node/farm'
32
33
  require_relative '../log'
@@ -44,7 +45,9 @@ require_relative '../gem'
44
45
  module Zold
45
46
  # Remote command
46
47
  class Remote
47
- def initialize(remotes:, farm: Farm::Empty.new, log: Log::Quiet.new)
48
+ prepend ThreadBadge
49
+
50
+ def initialize(remotes:, farm: Farm::Empty.new, log: Log::NULL)
48
51
  @remotes = remotes
49
52
  @farm = farm
50
53
  @log = log
@@ -103,9 +106,9 @@ Available options:"
103
106
  'The amount of update cycles to run, in order to fetch as many nodes as possible (default: 2)',
104
107
  default: 2
105
108
  o.string '--network',
106
- "The name of the network we work in (default: #{Wallet::MAIN_NETWORK}",
109
+ "The name of the network we work in (default: #{Wallet::MAINET}",
107
110
  required: true,
108
- default: Wallet::MAIN_NETWORK
111
+ default: Wallet::MAINET
109
112
  o.bool '--reboot',
110
113
  'Exit if any node reports version higher than we have',
111
114
  default: false
@@ -22,6 +22,7 @@
22
22
 
23
23
  require 'slop'
24
24
  require 'rainbow'
25
+ require_relative 'thread_badge'
25
26
  require_relative 'args'
26
27
  require_relative '../log'
27
28
 
@@ -32,7 +33,9 @@ require_relative '../log'
32
33
  module Zold
33
34
  # REMOVE command
34
35
  class Remove
35
- def initialize(wallets:, log: Log::Quiet.new)
36
+ prepend ThreadBadge
37
+
38
+ def initialize(wallets:, log: Log::NULL)
36
39
  @wallets = wallets
37
40
  @log = log
38
41
  end
@@ -32,7 +32,7 @@ module Zold
32
32
  module Routines
33
33
  # Reconnect to the network
34
34
  class Reconnect
35
- def initialize(opts, remotes, farm = Farm::Empty.new, network: 'test', log: Log::Quiet.new)
35
+ def initialize(opts, remotes, farm = Farm::Empty.new, network: 'test', log: Log::NULL)
36
36
  @opts = opts
37
37
  @remotes = remotes
38
38
  @farm = farm
@@ -33,7 +33,7 @@ module Zold
33
33
  module Routines
34
34
  # Spread them
35
35
  class Spread
36
- def initialize(opts, wallets, remotes, log: Log::Quiet.new)
36
+ def initialize(opts, wallets, remotes, log: Log::NULL)
37
37
  @opts = opts
38
38
  @wallets = wallets
39
39
  @remotes = remotes
@@ -22,6 +22,7 @@
22
22
 
23
23
  require 'slop'
24
24
  require 'rainbow'
25
+ require_relative 'thread_badge'
25
26
  require_relative 'args'
26
27
  require_relative '../log'
27
28
  require_relative '../id'
@@ -35,8 +36,11 @@ require_relative '../wallet'
35
36
  module Zold
36
37
  # Show command
37
38
  class Show
38
- def initialize(wallets:, log: Log::Quiet.new)
39
+ prepend ThreadBadge
40
+
41
+ def initialize(wallets:, copies:, log: Log::NULL)
39
42
  @wallets = wallets
43
+ @copies = copies
40
44
  @log = log
41
45
  end
42
46
 
@@ -49,7 +53,7 @@ Available options:"
49
53
  mine = Args.new(opts, @log).take || return
50
54
  if mine.empty?
51
55
  require_relative 'list'
52
- List.new(wallets: @wallets, log: @log).run(args)
56
+ List.new(wallets: @wallets, copies: @copies, log: @log).run(args)
53
57
  else
54
58
  total = Amount::ZERO
55
59
  mine.map { |i| Id.new(i) }.each do |id|
@@ -69,7 +73,7 @@ Available options:"
69
73
  @log.info(t.to_text)
70
74
  end
71
75
  msg = "The balance of #{wallet}: #{balance}"
72
- msg += " (net:#{wallet.network})" if wallet.network != Wallet::MAIN_NETWORK
76
+ msg += " (net:#{wallet.network})" if wallet.network != Wallet::MAINET
73
77
  @log.info(msg)
74
78
  balance
75
79
  end
@@ -24,6 +24,7 @@ require 'slop'
24
24
  require 'json'
25
25
  require 'rainbow'
26
26
  require 'zold/score'
27
+ require_relative 'thread_badge'
27
28
  require_relative 'args'
28
29
  require_relative 'pay'
29
30
  require_relative '../log'
@@ -51,7 +52,9 @@ module Zold
51
52
  # just selects the most suitable wallet to transfer taxes to and sends
52
53
  # the payment. More details you can find in the White Paper.
53
54
  class Taxes
54
- def initialize(wallets:, remotes:, log: Log::Quiet.new)
55
+ prepend ThreadBadge
56
+
57
+ def initialize(wallets:, remotes:, log: Log::NULL)
55
58
  @wallets = wallets
56
59
  @remotes = remotes
57
60
  @log = log
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2018 Yegor Bugayenko
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 all
13
+ # 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 NONINFINGEMENT. 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 THE
21
+ # SOFTWARE.
22
+
23
+ # Thread badge.
24
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
25
+ # Copyright:: Copyright (c) 2018 Yegor Bugayenko
26
+ # License:: MIT
27
+ module Zold
28
+ # This module should be included in each command, in order to label
29
+ # the current Thread correctly, when the command is running. This is mostly
30
+ # useful for debugging/testing purposes - want to be able to see what's
31
+ # going on in the thread when it gets stuck with a Futex.
32
+ #
33
+ # Since all commands have exactly the same external interface and implement
34
+ # the method "run," we catch all calls to this method and label the
35
+ # current thread properly. We label it back when it's over.
36
+ module ThreadBadge
37
+ def run(args = [])
38
+ before = Thread.current.name || ''
39
+ Thread.current.name = "#{before}:#{self.class.name.gsub(/^Zold::/, '')}"
40
+ begin
41
+ super(args)
42
+ ensure
43
+ Thread.current.name = before
44
+ end
45
+ end
46
+ end
47
+ end
@@ -39,7 +39,7 @@ module Zold
39
39
  # Extension for copy files
40
40
  EXT = '.zc'
41
41
 
42
- def initialize(dir, log: Log::Quiet.new)
42
+ def initialize(dir, log: Log::NULL)
43
43
  @dir = dir
44
44
  @log = log
45
45
  end
@@ -31,7 +31,7 @@ require_relative 'age'
31
31
  module Zold
32
32
  # Endless loop
33
33
  class Endless
34
- def initialize(title, log: Log::Quiet.new)
34
+ def initialize(title, log: Log::NULL)
35
35
  @title = title
36
36
  @log = log
37
37
  end
@@ -67,7 +67,7 @@ module Zold
67
67
  @network = network
68
68
  end
69
69
 
70
- def get(timeout: READ_TIMEOUT + CONNECT_TIMEOUT)
70
+ def get(timeout: READ_TIMEOUT)
71
71
  base_url = "#{@uri.scheme}://#{@uri.host}:#{@uri.port}"
72
72
  session = Patron::Session.new(
73
73
  timeout: timeout,
@@ -82,7 +82,7 @@ module Zold
82
82
  Error.new(e)
83
83
  end
84
84
 
85
- def put(body, timeout: READ_TIMEOUT + CONNECT_TIMEOUT)
85
+ def put(body, timeout: READ_TIMEOUT)
86
86
  base_url = "#{@uri.scheme}://#{@uri.host}:#{@uri.port}"
87
87
  session = Patron::Session.new(
88
88
  timeout: timeout,
@@ -109,7 +109,7 @@ module Zold
109
109
  end
110
110
 
111
111
  def to_s
112
- "#{code}: #{message}\n#{body}"
112
+ "#{status}: #{status_line}\n#{body}"
113
113
  end
114
114
 
115
115
  def body
@@ -51,6 +51,9 @@ module Zold
51
51
  end
52
52
  end
53
53
 
54
+ # Public key of the root wallet
55
+ ROOT = Key.new(file: File.expand_path(File.join(File.dirname(__FILE__), '../../resources/root.pub')))
56
+
54
57
  def ==(other)
55
58
  to_s == other.to_s
56
59
  end
@@ -20,10 +20,8 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
22
 
23
+ require 'logger'
23
24
  require 'rainbow'
24
- require 'monitor'
25
-
26
- STDOUT.sync = true
27
25
 
28
26
  # Zold module.
29
27
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
@@ -47,121 +45,64 @@ module Zold
47
45
  # messages. The user turns this mode by using --verbose command line argument.
48
46
  #
49
47
  module Log
50
- # Synchronized
51
- class Sync
52
- def initialize(log)
53
- @log = log
54
- @monitor = Monitor.new
55
- end
56
-
57
- def debug(msg)
58
- return unless debug?
59
- @monitor.synchronize do
60
- @log.debug(msg)
61
- end
62
- end
63
-
64
- def debug?
65
- @log.debug?
66
- end
67
-
68
- def info(msg)
69
- return unless info?
70
- @monitor.synchronize do
71
- @log.info(msg)
72
- end
73
- end
74
-
75
- def info?
76
- @log.info?
77
- end
78
-
79
- def error(msg)
80
- @monitor.synchronize do
81
- @log.error(msg)
82
- end
83
- end
48
+ def self.colored(text, severity)
49
+ case severity
50
+ when 'ERROR', 'FATAL'
51
+ return Rainbow(text).red
52
+ when 'DEBUG'
53
+ return Rainbow(text).yellow
54
+ end
55
+ text
84
56
  end
85
57
 
86
- # Extra verbose log
87
- class Verbose
88
- def debug(msg)
89
- print(msg)
90
- end
91
-
92
- def debug?
93
- true
94
- end
95
-
96
- def info(msg)
97
- print(msg)
98
- end
99
-
100
- def info?
101
- true
102
- end
103
-
104
- def error(msg)
105
- print("#{Rainbow('ERROR').red}: #{msg}")
106
- end
107
-
108
- private
109
-
110
- def print(text)
111
- puts(text)
58
+ # Compact formatter
59
+ COMPACT = proc do |severity, _time, _target, msg|
60
+ prefix = ''
61
+ case severity
62
+ when 'ERROR', 'FATAL'
63
+ prefix = 'E: '
64
+ when 'DEBUG'
65
+ prefix = 'D: '
112
66
  end
67
+ colored(prefix, severity) + msg.to_s.rstrip.gsub(/\n/, "\n" + (' ' * prefix.length)) + "\n"
113
68
  end
114
69
 
115
- # Regular log
116
- class Regular
117
- def debug(msg)
118
- # nothing
119
- end
120
-
121
- def debug?
122
- false
123
- end
124
-
125
- def info(msg)
126
- print(msg)
127
- end
128
-
129
- def info?
130
- true
131
- end
132
-
133
- def error(msg)
134
- print("#{Rainbow('ERROR').red}: #{msg}")
135
- end
136
-
137
- private
138
-
139
- def print(text)
140
- puts(text)
141
- end
70
+ # Short formatter
71
+ SHORT = proc do |_severity, _time, _target, msg|
72
+ msg.to_s.rstrip + "\n"
142
73
  end
143
74
 
144
- # Log that doesn't log anything
145
- class Quiet
146
- def debug(msg)
147
- # nothing to do here
148
- end
149
-
150
- def debug?
151
- false
152
- end
153
-
154
- def info(msg)
155
- # nothing to do here
156
- end
157
-
158
- def info?
159
- false
160
- end
161
-
162
- def error(msg)
163
- # nothing to do here
164
- end
75
+ # Full formatter
76
+ FULL = proc do |severity, time, _target, msg|
77
+ format(
78
+ "%<time>s %<severity>5s %<msg>s\n",
79
+ time: time.utc.iso8601,
80
+ severity: colored(severity, severity),
81
+ msg: msg.to_s.rstrip
82
+ )
165
83
  end
84
+
85
+ # No logging at all
86
+ NULL = Logger.new(STDOUT)
87
+ NULL.level = Logger::UNKNOWN
88
+ NULL.freeze
89
+
90
+ # Everything, including debug
91
+ VERBOSE = Logger.new(STDOUT)
92
+ VERBOSE.level = Logger::DEBUG
93
+ VERBOSE.formatter = COMPACT
94
+ VERBOSE.freeze
95
+
96
+ # Info and errors, no debug info
97
+ REGULAR = Logger.new(STDOUT)
98
+ REGULAR.level = Logger::INFO
99
+ REGULAR.formatter = COMPACT
100
+ REGULAR.freeze
101
+
102
+ # Errors only
103
+ ERRORS = Logger.new(STDOUT)
104
+ ERRORS.level = Logger::ERROR
105
+ ERRORS.formatter = COMPACT
106
+ ERRORS.freeze
166
107
  end
167
108
  end
@@ -32,7 +32,7 @@ require_relative 'verbose_thread'
32
32
  module Zold
33
33
  # Metronome
34
34
  class Metronome
35
- def initialize(log = Log::Quiet.new)
35
+ def initialize(log = Log::NULL)
36
36
  @log = log
37
37
  @routines = []
38
38
  @threads = []
@@ -86,16 +86,18 @@ module Zold
86
86
  begin
87
87
  yield(self)
88
88
  ensure
89
- alive = false
90
- @log.info("Stopping the metronome with #{@threads.count} threads: #{@threads.map(&:name).join(', ')}")
91
89
  start = Time.now
92
- @threads.each do |t|
93
- tstart = Time.now
94
- if t.join(60)
95
- @log.info("Thread #{t.name} finished in #{Age.new(tstart)}")
96
- else
97
- t.exit
98
- @log.info("Thread #{t.name} killed in #{Age.new(tstart)}")
90
+ unless @threads.empty?
91
+ alive = false
92
+ @log.info("Stopping the metronome with #{@threads.count} threads: #{@threads.map(&:name).join(', ')}")
93
+ @threads.each do |t|
94
+ tstart = Time.now
95
+ if t.join(60)
96
+ @log.info("Thread #{t.name} finished in #{Age.new(tstart)}")
97
+ else
98
+ t.exit
99
+ @log.info("Thread #{t.name} killed in #{Age.new(tstart)}")
100
+ end
99
101
  end
100
102
  end
101
103
  @log.info("Metronome stopped in #{Age.new(start)}, #{@failures.count} failures")