leap_cli 1.8.1 → 1.9

Sign up to get free protection for your applications and to get access to all the features.
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