leap_cli 1.8.1 → 1.9

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/bin/leap +6 -12
  3. data/lib/leap_cli.rb +3 -23
  4. data/lib/leap_cli/bootstrap.rb +36 -12
  5. data/lib/leap_cli/commands/common.rb +88 -46
  6. data/lib/leap_cli/commands/new.rb +24 -17
  7. data/lib/leap_cli/commands/pre.rb +3 -1
  8. data/lib/leap_cli/core_ext/hash.rb +19 -0
  9. data/lib/leap_cli/leapfile.rb +47 -32
  10. data/lib/leap_cli/log.rb +196 -88
  11. data/lib/leap_cli/path.rb +5 -5
  12. data/lib/leap_cli/util.rb +28 -18
  13. data/lib/leap_cli/version.rb +8 -3
  14. data/vendor/acme-client/lib/acme-client.rb +1 -0
  15. data/vendor/acme-client/lib/acme/client.rb +122 -0
  16. data/vendor/acme-client/lib/acme/client/certificate.rb +30 -0
  17. data/vendor/acme-client/lib/acme/client/certificate_request.rb +111 -0
  18. data/vendor/acme-client/lib/acme/client/crypto.rb +98 -0
  19. data/vendor/acme-client/lib/acme/client/error.rb +16 -0
  20. data/vendor/acme-client/lib/acme/client/faraday_middleware.rb +123 -0
  21. data/vendor/acme-client/lib/acme/client/resources.rb +5 -0
  22. data/vendor/acme-client/lib/acme/client/resources/authorization.rb +44 -0
  23. data/vendor/acme-client/lib/acme/client/resources/challenges.rb +6 -0
  24. data/vendor/acme-client/lib/acme/client/resources/challenges/base.rb +43 -0
  25. data/vendor/acme-client/lib/acme/client/resources/challenges/dns01.rb +19 -0
  26. data/vendor/acme-client/lib/acme/client/resources/challenges/http01.rb +18 -0
  27. data/vendor/acme-client/lib/acme/client/resources/challenges/tls_sni01.rb +24 -0
  28. data/vendor/acme-client/lib/acme/client/resources/registration.rb +37 -0
  29. data/vendor/acme-client/lib/acme/client/self_sign_certificate.rb +60 -0
  30. data/vendor/acme-client/lib/acme/client/version.rb +7 -0
  31. data/vendor/base32/lib/base32.rb +67 -0
  32. data/vendor/certificate_authority/lib/certificate_authority.rb +2 -1
  33. data/vendor/certificate_authority/lib/certificate_authority/certificate.rb +4 -4
  34. data/vendor/certificate_authority/lib/certificate_authority/certificate_revocation_list.rb +7 -5
  35. data/vendor/certificate_authority/lib/certificate_authority/core_extensions.rb +46 -0
  36. data/vendor/certificate_authority/lib/certificate_authority/distinguished_name.rb +6 -2
  37. data/vendor/certificate_authority/lib/certificate_authority/extensions.rb +10 -3
  38. data/vendor/certificate_authority/lib/certificate_authority/key_material.rb +11 -9
  39. data/vendor/certificate_authority/lib/certificate_authority/ocsp_handler.rb +3 -3
  40. data/vendor/certificate_authority/lib/certificate_authority/pkcs11_key_material.rb +0 -2
  41. data/vendor/certificate_authority/lib/certificate_authority/serial_number.rb +8 -2
  42. data/vendor/certificate_authority/lib/certificate_authority/validations.rb +31 -0
  43. data/vendor/rsync_command/lib/rsync_command.rb +49 -12
  44. metadata +50 -91
  45. data/lib/leap/platform.rb +0 -90
  46. data/lib/leap_cli/config/environment.rb +0 -180
  47. data/lib/leap_cli/config/filter.rb +0 -178
  48. data/lib/leap_cli/config/manager.rb +0 -419
  49. data/lib/leap_cli/config/node.rb +0 -77
  50. data/lib/leap_cli/config/object.rb +0 -428
  51. data/lib/leap_cli/config/object_list.rb +0 -209
  52. data/lib/leap_cli/config/provider.rb +0 -22
  53. data/lib/leap_cli/config/secrets.rb +0 -87
  54. data/lib/leap_cli/config/sources.rb +0 -11
  55. data/lib/leap_cli/config/tag.rb +0 -25
  56. data/lib/leap_cli/lib_ext/capistrano_connections.rb +0 -16
  57. data/lib/leap_cli/logger.rb +0 -237
  58. data/lib/leap_cli/remote/leap_plugin.rb +0 -192
  59. data/lib/leap_cli/remote/puppet_plugin.rb +0 -26
  60. data/lib/leap_cli/remote/rsync_plugin.rb +0 -35
  61. data/lib/leap_cli/remote/tasks.rb +0 -51
  62. data/lib/leap_cli/ssh_key.rb +0 -195
  63. data/lib/leap_cli/util/remote_command.rb +0 -158
  64. data/lib/leap_cli/util/secret.rb +0 -55
  65. data/lib/leap_cli/util/x509.rb +0 -33
@@ -1,209 +0,0 @@
1
- require 'tsort'
2
-
3
- module LeapCli
4
- module Config
5
- #
6
- # A list of Config::Object instances (internally stored as a hash)
7
- #
8
- class ObjectList < Hash
9
- include TSort
10
-
11
- def initialize(config=nil)
12
- if config
13
- self.add(config['name'], config)
14
- end
15
- end
16
-
17
- #
18
- # If the key is a string, the Config::Object it references is returned.
19
- #
20
- # If the key is a hash, we treat it as a condition and filter all the Config::Objects using the condition.
21
- # A new ObjectList is returned.
22
- #
23
- # Examples:
24
- #
25
- # nodes['vpn1']
26
- # node named 'vpn1'
27
- #
28
- # nodes[:public_dns => true]
29
- # all nodes with public dns
30
- #
31
- # nodes[:services => 'openvpn', 'location.country_code' => 'US']
32
- # all nodes with services containing 'openvpn' OR country code of US
33
- #
34
- # Sometimes, you want to do an OR condition with multiple conditions
35
- # for the same field. Since hash keys must be unique, you can use
36
- # an array representation instead:
37
- #
38
- # nodes[[:services, 'openvpn'], [:services, 'tor']]
39
- # nodes with openvpn OR tor service
40
- #
41
- # nodes[:services => 'openvpn'][:tags => 'production']
42
- # nodes with openvpn AND are production
43
- #
44
- def [](key)
45
- if key.is_a?(Hash) || key.is_a?(Array)
46
- filter(key)
47
- else
48
- super key.to_s
49
- end
50
- end
51
-
52
- def exclude(node)
53
- list = self.dup
54
- list.delete(node.name)
55
- return list
56
- end
57
-
58
- def each_node(&block)
59
- self.keys.sort.each do |node_name|
60
- yield self[node_name]
61
- end
62
- end
63
-
64
- #
65
- # filters this object list, producing a new list.
66
- # filter is an array or a hash. see []
67
- #
68
- def filter(filter)
69
- results = Config::ObjectList.new
70
- filter.each do |field, match_value|
71
- field = field.is_a?(Symbol) ? field.to_s : field
72
- match_value = match_value.is_a?(Symbol) ? match_value.to_s : match_value
73
- if match_value.is_a?(String) && match_value =~ /^!/
74
- operator = :not_equal
75
- match_value = match_value.sub(/^!/, '')
76
- else
77
- operator = :equal
78
- end
79
- each do |name, config|
80
- value = config[field]
81
- if value.is_a? Array
82
- if operator == :equal && value.include?(match_value)
83
- results[name] = config
84
- elsif operator == :not_equal && !value.include?(match_value)
85
- results[name] = config
86
- end
87
- else
88
- if operator == :equal && value == match_value
89
- results[name] = config
90
- elsif operator == :not_equal && value != match_value
91
- results[name] = config
92
- end
93
- end
94
- end
95
- end
96
- results
97
- end
98
-
99
- def add(name, object)
100
- self[name] = object
101
- end
102
-
103
- #
104
- # converts the hash of configs into an array of hashes, with ONLY the specified fields
105
- #
106
- def fields(*fields)
107
- result = []
108
- keys.sort.each do |name|
109
- result << self[name].pick(*fields)
110
- end
111
- result
112
- end
113
-
114
- #
115
- # like fields(), but returns an array of values instead of an array of hashes.
116
- #
117
- def field(field)
118
- field = field.to_s
119
- result = []
120
- keys.sort.each do |name|
121
- result << self[name].get(field)
122
- end
123
- result
124
- end
125
-
126
- #
127
- # pick_fields(field1, field2, ...)
128
- #
129
- # generates a Hash from the object list, but with only the fields that are picked.
130
- #
131
- # If there are more than one field, then the result is a Hash of Hashes.
132
- # If there is just one field, it is a simple map to the value.
133
- #
134
- # For example:
135
- #
136
- # "neighbors" = "= nodes_like_me[:services => :couchdb].pick_fields('domain.full', 'ip_address')"
137
- #
138
- # generates this:
139
- #
140
- # neighbors:
141
- # couch1:
142
- # domain_full: couch1.bitmask.net
143
- # ip_address: "10.5.5.44"
144
- # couch2:
145
- # domain_full: couch2.bitmask.net
146
- # ip_address: "10.5.5.52"
147
- #
148
- # But this:
149
- #
150
- # "neighbors": "= nodes_like_me[:services => :couchdb].pick_fields('domain.full')"
151
- #
152
- # will generate this:
153
- #
154
- # neighbors:
155
- # couch1: couch1.bitmask.net
156
- # couch2: couch2.bitmask.net
157
- #
158
- def pick_fields(*fields)
159
- self.values.inject({}) do |hsh, node|
160
- value = self[node.name].pick(*fields)
161
- if fields.size == 1
162
- value = value.values.first
163
- end
164
- hsh[node.name] = value
165
- hsh
166
- end
167
- end
168
-
169
- #
170
- # Applies inherit_from! to all objects.
171
- #
172
- # 'env' specifies what environment should be for
173
- # each object in the list.
174
- #
175
- def inherit_from!(object_list, env)
176
- object_list.each do |name, object|
177
- if self[name]
178
- self[name].inherit_from!(object)
179
- else
180
- self[name] = object.duplicate(env)
181
- end
182
- end
183
- end
184
-
185
- #
186
- # topographical sort based on test dependency
187
- #
188
- def tsort_each_node(&block)
189
- self.each_key(&block)
190
- end
191
-
192
- def tsort_each_child(node_name, &block)
193
- if self[node_name]
194
- self[node_name].test_dependencies.each do |test_me_first|
195
- if self[test_me_first] # TODO: in the future, allow for ability to optionally pull in all dependencies.
196
- # not just the ones that pass the node filter.
197
- yield(test_me_first)
198
- end
199
- end
200
- end
201
- end
202
-
203
- def names_in_test_dependency_order
204
- self.tsort
205
- end
206
-
207
- end
208
- end
209
- end
@@ -1,22 +0,0 @@
1
- #
2
- # Configuration class for provider.json
3
- #
4
-
5
- module LeapCli; module Config
6
- class Provider < Object
7
- attr_reader :environment
8
- def set_env(e)
9
- if e == 'default'
10
- @environment = nil
11
- else
12
- @environment = e
13
- end
14
- end
15
- def provider
16
- self
17
- end
18
- def validate!
19
- # nothing here yet :(
20
- end
21
- end
22
- end; end
@@ -1,87 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- # A class for the secrets.json file
4
- #
5
-
6
- module LeapCli; module Config
7
-
8
- class Secrets < Object
9
- attr_reader :node_list
10
-
11
- def initialize(manager=nil)
12
- super(manager)
13
- @discovered_keys = {}
14
- end
15
-
16
- # we can't use fetch() or get(), since those already have special meanings
17
- def retrieve(key, environment)
18
- environment ||= 'default'
19
- self.fetch(environment, {})[key.to_s]
20
- end
21
-
22
- def set(*args, &block)
23
- if block_given?
24
- set_with_block(*args, &block)
25
- else
26
- set_without_block(*args)
27
- end
28
- end
29
-
30
- # searches over all keys matching the regexp, checking to see if the value
31
- # has been already used by any of them.
32
- def taken?(regexp, value, environment)
33
- self.keys.grep(regexp).each do |key|
34
- return true if self.retrieve(key, environment) == value
35
- end
36
- return false
37
- end
38
-
39
- def set_without_block(key, value, environment)
40
- set_with_block(key, environment) {value}
41
- end
42
-
43
- def set_with_block(key, environment, &block)
44
- environment ||= 'default'
45
- key = key.to_s
46
- @discovered_keys[environment] ||= {}
47
- @discovered_keys[environment][key] = true
48
- self[environment] ||= {}
49
- self[environment][key] ||= yield
50
- end
51
-
52
- #
53
- # if clean is true, then only secrets that have been discovered
54
- # during this run will be exported.
55
- #
56
- # if environment is also pinned, then we will clean those secrets
57
- # just for that environment.
58
- #
59
- # the clean argument should only be used when all nodes have
60
- # been processed, otherwise secrets that are actually in use will
61
- # get mistakenly removed.
62
- #
63
- def dump_json(clean=false)
64
- pinned_env = LeapCli.leapfile.environment
65
- if clean
66
- self.each_key do |environment|
67
- if pinned_env.nil? || pinned_env == environment
68
- env = self[environment]
69
- if env.nil?
70
- raise StandardError.new("secrets.json file seems corrupted. No such environment '#{environment}'")
71
- end
72
- env.each_key do |key|
73
- unless @discovered_keys[environment] && @discovered_keys[environment][key]
74
- self[environment].delete(key)
75
- end
76
- end
77
- if self[environment].empty?
78
- self.delete(environment)
79
- end
80
- end
81
- end
82
- end
83
- super()
84
- end
85
- end
86
-
87
- end; end
@@ -1,11 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- # A class for the sources.json file
4
- #
5
-
6
- module LeapCli
7
- module Config
8
- class Sources < Object
9
- end
10
- end
11
- end
@@ -1,25 +0,0 @@
1
- #
2
- #
3
- # A class for node services or node tags.
4
- #
5
- #
6
-
7
- module LeapCli; module Config
8
-
9
- class Tag < Object
10
- attr_reader :node_list
11
-
12
- def initialize(environment=nil)
13
- super(environment)
14
- @node_list = Config::ObjectList.new
15
- end
16
-
17
- # don't copy the node list pointer when this object is dup'ed.
18
- def initialize_copy(orig)
19
- super
20
- @node_list = Config::ObjectList.new
21
- end
22
-
23
- end
24
-
25
- end; end
@@ -1,16 +0,0 @@
1
- module Capistrano
2
- class Configuration
3
- module Connections
4
- def failed!(server)
5
- @failure_callback.call(server) if @failure_callback
6
- Thread.current[:failed_sessions] << server
7
- end
8
-
9
- def call_on_failure(&block)
10
- @failure_callback = block
11
- end
12
- end
13
- end
14
- end
15
-
16
-
@@ -1,237 +0,0 @@
1
- #
2
- # A drop in replacement for Capistrano::Logger that integrates better with LEAP CLI.
3
- #
4
-
5
- require 'capistrano/logger'
6
-
7
- #
8
- # from Capistrano::Logger
9
- # =========================
10
- #
11
- # IMPORTANT = 0
12
- # INFO = 1
13
- # DEBUG = 2
14
- # TRACE = 3
15
- # MAX_LEVEL = 3
16
- # COLORS = {
17
- # :none => "0",
18
- # :black => "30",
19
- # :red => "31",
20
- # :green => "32",
21
- # :yellow => "33",
22
- # :blue => "34",
23
- # :magenta => "35",
24
- # :cyan => "36",
25
- # :white => "37"
26
- # }
27
- # STYLES = {
28
- # :bright => 1,
29
- # :dim => 2,
30
- # :underscore => 4,
31
- # :blink => 5,
32
- # :reverse => 7,
33
- # :hidden => 8
34
- # }
35
- #
36
-
37
- module LeapCli
38
- class Logger < Capistrano::Logger
39
-
40
- def initialize(options={})
41
- @options = options
42
- @level = options[:level] || 0
43
- @message_buffer = nil
44
- end
45
-
46
- def log(level, message, line_prefix=nil, options={})
47
- if message !~ /\n$/ && level <= 2 && line_prefix.is_a?(String)
48
- # in some cases, when the message doesn't end with a return, we buffer it and
49
- # wait until we encounter the return before we log the message out.
50
- @message_buffer ||= ""
51
- @message_buffer += message
52
- return
53
- elsif @message_buffer
54
- message = @message_buffer + message
55
- @message_buffer = nil
56
- end
57
-
58
- options[:level] ||= level
59
- [:stdout, :log].each do |mode|
60
- LeapCli::log_raw(mode) do
61
- message_lines(mode, message, line_prefix, options)
62
- end
63
- end
64
- end
65
-
66
- private
67
-
68
- def message_lines(mode, message, line_prefix, options)
69
- formatted_message, formatted_prefix, message_options = apply_formatting(mode, message, line_prefix, options)
70
- if message_options[:level] <= self.level && formatted_message && formatted_message.chars.any?
71
- if formatted_prefix
72
- formatted_message.lines.collect { |line|
73
- "[#{formatted_prefix}] #{line.sub(/\s+$/, '')}"
74
- }
75
- else
76
- formatted_message.lines.collect {|line| line.sub(/\s+$/, '')}
77
- end
78
- else
79
- nil
80
- end
81
- end
82
-
83
- ##
84
- ## FORMATTING
85
- ##
86
-
87
- #
88
- # options for formatters:
89
- #
90
- # :match => regexp for matching a log line
91
- # :color => what color the line should be
92
- # :style => what style the line should be
93
- # :priority => what order the formatters are applied in. higher numbers first.
94
- # :match_level => only apply filter at the specified log level
95
- # :level => make this line visible at this log level or higher
96
- # :replace => replace the matched text
97
- # :exit => force the exit code to be this (does not interrupt program, just
98
- # ensures a specific exit code when the program eventually exits)
99
- #
100
- @formatters = [
101
- # TRACE
102
- { :match => /command finished/, :color => :white, :style => :dim, :match_level => 3, :priority => -10 },
103
- { :match => /executing locally/, :color => :yellow, :match_level => 3, :priority => -20 },
104
-
105
- # DEBUG
106
- #{ :match => /executing .*/, :color => :green, :match_level => 2, :priority => -10, :timestamp => true },
107
- #{ :match => /.*/, :color => :yellow, :match_level => 2, :priority => -30 },
108
- { :match => /^transaction:/, :level => 3 },
109
-
110
- # INFO
111
- { :match => /.*out\] (fatal:|ERROR:).*/, :color => :red, :match_level => 1, :priority => -10 },
112
- { :match => /Permission denied/, :color => :red, :match_level => 1, :priority => -20 },
113
- { :match => /sh: .+: command not found/, :color => :magenta, :match_level => 1, :priority => -30 },
114
-
115
- # IMPORTANT
116
- { :match => /^(E|e)rr ::/, :color => :red, :match_level => 0, :priority => -10, :exit => 1},
117
- { :match => /^ERROR:/, :color => :red, :priority => -10, :exit => 1},
118
- { :match => /.*/, :color => :blue, :match_level => 0, :priority => -20 },
119
-
120
- # CLEANUP
121
- { :match => /\s+$/, :replace => '', :priority => 0},
122
-
123
- # DEBIAN PACKAGES
124
- { :match => /^(Hit|Ign) /, :color => :green, :priority => -20},
125
- { :match => /^Err /, :color => :red, :priority => -20},
126
- { :match => /^W(ARNING)?: /, :color => :yellow, :priority => -20},
127
- { :match => /^E: /, :color => :red, :priority => -20},
128
- { :match => /already the newest version/, :color => :green, :priority => -20},
129
- { :match => /WARNING: The following packages cannot be authenticated!/, :color => :red, :level => 0, :priority => -10},
130
-
131
- # PUPPET
132
- { :match => /^(W|w)arning: Not collecting exported resources without storeconfigs/, :level => 2, :color => :yellow, :priority => -10},
133
- { :match => /^(W|w)arning: Found multiple default providers for vcsrepo:/, :level => 2, :color => :yellow, :priority => -10},
134
- { :match => /^(W|w)arning: .*is deprecated.*$/, :level => 2, :color => :yellow, :priority => -10},
135
- { :match => /^(W|w)arning: Scope.*$/, :level => 2, :color => :yellow, :priority => -10},
136
- { :match => /^(N|n)otice:/, :level => 1, :color => :cyan, :priority => -20},
137
- { :match => /^(N|n)otice:.*executed successfully$/, :level => 2, :color => :cyan, :priority => -15},
138
- { :match => /^(W|w)arning:/, :level => 0, :color => :yellow, :priority => -20},
139
- { :match => /^Duplicate declaration:/, :level => 0, :color => :red, :priority => -20},
140
- { :match => /Finished catalog run/, :level => 0, :color => :green, :priority => -10},
141
- { :match => /^APPLY COMPLETE \(changes made\)/, :level => 0, :color => :green, :priority => -10},
142
- { :match => /^APPLY COMPLETE \(no changes\)/, :level => 0, :color => :green, :priority => -10},
143
-
144
- # PUPPET FATAL ERRORS
145
- { :match => /^(E|e)rr(or|):/, :level => 0, :color => :red, :priority => -1, :exit => 1},
146
- { :match => /^Wrapped exception:/, :level => 0, :color => :red, :priority => -1, :exit => 1},
147
- { :match => /^Failed to parse template/, :level => 0, :color => :red, :priority => -1, :exit => 1},
148
- { :match => /^Execution of.*returned/, :level => 0, :color => :red, :priority => -1, :exit => 1},
149
- { :match => /^Parameter matches failed:/, :level => 0, :color => :red, :priority => -1, :exit => 1},
150
- { :match => /^Syntax error/, :level => 0, :color => :red, :priority => -1, :exit => 1},
151
- { :match => /^Cannot reassign variable/, :level => 0, :color => :red, :priority => -1, :exit => 1},
152
- { :match => /^Could not find template/, :level => 0, :color => :red, :priority => -1, :exit => 1},
153
- { :match => /^APPLY COMPLETE.*fail/, :level => 0, :color => :red, :priority => -1, :exit => 1},
154
-
155
- # TESTS
156
- { :match => /^PASS: /, :color => :green, :priority => -20},
157
- { :match => /^(FAIL|ERROR): /, :color => :red, :priority => -20},
158
- { :match => /^(SKIP|WARN): /, :color => :yellow, :priority => -20},
159
- { :match => /\d+ tests: \d+ passes, \d+ skips, 0 warnings, 0 failures, 0 errors/, :color => :blue, :priority => -20},
160
-
161
- # LOG SUPPRESSION
162
- { :match => /^(W|w)arning: You cannot collect without storeconfigs being set/, :level => 2, :priority => 10},
163
- { :match => /^(W|w)arning: You cannot collect exported resources without storeconfigs being set/, :level => 2, :priority => 10}
164
- ]
165
-
166
- def self.sorted_formatters
167
- # Sort matchers in reverse order so we can break if we found a match.
168
- @sorted_formatters ||= @formatters.sort_by { |i| -(i[:priority] || i[:prio] || 0) }
169
- end
170
-
171
- @prefix_formatters = [
172
- { :match => /(err|out) :: /, :replace => '', :priority => 0},
173
- { :match => /\s+$/, :replace => '', :priority => 0}
174
- ]
175
- def self.prefix_formatters; @prefix_formatters; end
176
-
177
- def apply_formatting(mode, message, line_prefix = nil, options={})
178
- message = message.dup
179
- options = options.dup
180
- if !line_prefix.nil?
181
- if !line_prefix.is_a?(String)
182
- line_prefix = line_prefix.to_s.dup
183
- else
184
- line_prefix = line_prefix.dup
185
- end
186
- end
187
- color = options[:color] || :none
188
- style = options[:style]
189
-
190
- if line_prefix
191
- self.class.prefix_formatters.each do |formatter|
192
- if line_prefix =~ formatter[:match] && formatter[:replace]
193
- line_prefix.gsub!(formatter[:match], formatter[:replace])
194
- end
195
- end
196
- end
197
-
198
- self.class.sorted_formatters.each do |formatter|
199
- if (formatter[:match_level] == level || formatter[:match_level].nil?)
200
- if message =~ formatter[:match]
201
- options[:level] = formatter[:level] if formatter[:level]
202
- color = formatter[:color] if formatter[:color]
203
- style = formatter[:style] || formatter[:attribute] # (support original cap colors)
204
-
205
- message.gsub!(formatter[:match], formatter[:replace]) if formatter[:replace]
206
- message.replace(formatter[:prepend] + message) unless formatter[:prepend].nil?
207
- message.replace(message + formatter[:append]) unless formatter[:append].nil?
208
- message.replace(Time.now.strftime('%Y-%m-%d %T') + ' ' + message) if formatter[:timestamp]
209
-
210
- if formatter[:exit]
211
- LeapCli::Util.exit_status(formatter[:exit])
212
- end
213
-
214
- # stop formatting, unless formatter was just for string replacement
215
- break unless formatter[:replace]
216
- end
217
- end
218
- end
219
-
220
- if color == :hide
221
- return nil
222
- elsif mode == :log || (color == :none && style.nil?) || !LeapCli.log_in_color
223
- return [message, line_prefix, options]
224
- else
225
- term_color = COLORS[color]
226
- term_style = STYLES[style]
227
- if line_prefix.nil?
228
- message.replace format(message, term_color, term_style)
229
- else
230
- line_prefix.replace format(line_prefix, term_color, term_style).strip # format() appends a \n
231
- end
232
- return [message, line_prefix, options]
233
- end
234
- end
235
-
236
- end
237
- end