polytrix 0.1.2 → 0.1.3
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.
- checksums.yaml +4 -4
- data/.rubocop-todo.yml +14 -5
- data/Gemfile +2 -1
- data/README.md +139 -177
- data/Rakefile +5 -12
- data/bin/polytrix +0 -1
- data/features/bootstrapping.feature +0 -3
- data/features/cloning.feature +0 -3
- data/features/show.feature +38 -0
- data/features/states.feature +12 -13
- data/features/step_definitions/sdk_steps.rb +0 -4
- data/lib/polytrix/challenge.rb +135 -53
- data/lib/polytrix/challenge_result.rb +0 -2
- data/lib/polytrix/challenge_runner.rb +28 -18
- data/lib/polytrix/cli.rb +53 -69
- data/lib/polytrix/color.rb +2 -2
- data/lib/polytrix/command/action.rb +4 -3
- data/lib/polytrix/command/list.rb +39 -28
- data/lib/polytrix/command/report.rb +9 -86
- data/lib/polytrix/command/reports/code2doc.rb +72 -0
- data/lib/polytrix/command/reports/dashboard.rb +125 -0
- data/lib/polytrix/command/show.rb +148 -0
- data/lib/polytrix/command.rb +37 -104
- data/lib/polytrix/configuration.rb +14 -18
- data/lib/polytrix/{core/hashie.rb → dash.rb} +4 -3
- data/lib/polytrix/documentation/code_segmenter.rb +8 -8
- data/lib/polytrix/documentation/comment_styles.rb +1 -1
- data/lib/polytrix/documentation/helpers/code_helper.rb +9 -0
- data/lib/polytrix/documentation_generator.rb +11 -14
- data/lib/polytrix/error.rb +104 -97
- data/lib/polytrix/executor.rb +33 -0
- data/lib/polytrix/{runners → executors}/buff_shellout_executor.rb +1 -1
- data/lib/polytrix/executors/linux_challenge_executor.rb +29 -0
- data/lib/polytrix/executors/mixlib_shellout_executor.rb +55 -0
- data/lib/polytrix/{runners/windows_challenge_runner.rb → executors/windows_challenge_executor.rb} +4 -11
- data/lib/polytrix/{core/implementor.rb → implementor.rb} +10 -6
- data/lib/polytrix/manifest.rb +2 -31
- data/lib/polytrix/{reports → reporters}/hash_reporter.rb +6 -2
- data/lib/polytrix/{reports → reporters}/json_reporter.rb +2 -2
- data/lib/polytrix/{reports → reporters}/markdown_reporter.rb +7 -2
- data/lib/polytrix/{reports → reporters}/yaml_reporter.rb +2 -2
- data/lib/polytrix/reporters.rb +27 -0
- data/lib/polytrix/result.rb +6 -5
- data/lib/polytrix/spies/file_system_spy.rb +15 -0
- data/lib/polytrix/spies.rb +61 -0
- data/lib/polytrix/state_file.rb +1 -20
- data/lib/polytrix/util.rb +157 -62
- data/lib/polytrix/validation.rb +41 -2
- data/lib/polytrix/validator.rb +9 -4
- data/lib/polytrix/version.rb +1 -1
- data/lib/polytrix.rb +110 -105
- data/polytrix.gemspec +7 -2
- data/polytrix.yml +16 -13
- data/resources/assets/pygments/autumn.css +58 -0
- data/resources/assets/pygments/borland.css +46 -0
- data/resources/assets/pygments/bw.css +34 -0
- data/resources/assets/pygments/colorful.css +61 -0
- data/resources/assets/pygments/default.css +62 -0
- data/resources/assets/pygments/emacs.css +61 -0
- data/resources/assets/pygments/friendly.css +61 -0
- data/resources/assets/pygments/fruity.css +69 -0
- data/resources/assets/pygments/github.css +61 -0
- data/resources/assets/pygments/manni.css +61 -0
- data/resources/assets/pygments/monokai.css +64 -0
- data/resources/assets/pygments/murphy.css +61 -0
- data/resources/assets/pygments/native.css +69 -0
- data/resources/assets/pygments/pastie.css +60 -0
- data/resources/assets/pygments/perldoc.css +58 -0
- data/resources/assets/pygments/tango.css +69 -0
- data/resources/assets/pygments/trac.css +59 -0
- data/resources/assets/pygments/vim.css +69 -0
- data/resources/assets/pygments/vs.css +33 -0
- data/resources/assets/pygments/zenburn.css +1 -0
- data/resources/assets/style.css +41 -0
- data/resources/templates/dashboard/files/dashboard.html.tt +82 -0
- data/resources/templates/dashboard/templates/_test_report.html.tt +87 -0
- data/samples/bootstrap.sh +2 -0
- data/samples/clone.sh +2 -0
- data/samples/code2doc.sh +4 -0
- data/samples/docs/samples/code2doc/java/katas-hello_world-java.md +17 -0
- data/samples/docs/samples/code2doc/java/katas-quine-java.md +35 -0
- data/samples/docs/samples/code2doc/python/katas-hello_world-python.md +5 -0
- data/samples/docs/samples/code2doc/python/katas-quine-python.md +6 -0
- data/samples/docs/samples/code2doc/ruby/katas-hello_world-ruby.md +11 -0
- data/samples/exec.sh +2 -0
- data/samples/polytrix.rb +2 -2
- data/samples/polytrix.yml +5 -2
- data/samples/show.sh +4 -0
- data/samples/test.sh +2 -0
- data/samples/tests/polytrix/validators.rb +2 -2
- data/samples/verify.sh +3 -0
- data/scripts/wrapper +4 -7
- data/spec/fabricators/challenge_fabricator.rb +2 -9
- data/spec/fabricators/implementor_fabricator.rb +0 -8
- data/spec/fabricators/manifest_fabricator.rb +2 -9
- data/spec/fabricators/validator_fabricator.rb +2 -4
- data/spec/polytrix/challenge_runner_spec.rb +20 -0
- data/spec/polytrix/documentation/helpers/code_helper_spec.rb +7 -7
- data/spec/polytrix/file_finder_spec.rb +5 -5
- data/spec/polytrix/manifest_spec.rb +0 -21
- data/spec/polytrix/result_spec.rb +14 -14
- data/spec/polytrix/validator_registry_spec.rb +4 -4
- data/spec/polytrix/validator_spec.rb +9 -9
- data/spec/polytrix_spec.rb +1 -25
- data/spec/spec_helper.rb +8 -1
- metadata +130 -38
- data/features/execution.feature +0 -53
- data/features/fixtures/spec/polytrix_spec.rb +0 -7
- data/lib/polytrix/cli/report.rb +0 -84
- data/lib/polytrix/command/rundoc.rb +0 -27
- data/lib/polytrix/core/file_system_helper.rb +0 -75
- data/lib/polytrix/core/manifest_section.rb +0 -4
- data/lib/polytrix/core/string_helpers.rb +0 -15
- data/lib/polytrix/documentation/view_helper.rb +0 -21
- data/lib/polytrix/rspec/documentation_formatter.rb +0 -66
- data/lib/polytrix/rspec/yaml_report.rb +0 -51
- data/lib/polytrix/rspec.rb +0 -56
- data/lib/polytrix/runners/executor.rb +0 -34
- data/lib/polytrix/runners/linux_challenge_runner.rb +0 -23
- data/lib/polytrix/runners/middleware/change_directory.rb +0 -20
- data/lib/polytrix/runners/middleware/feature_executor.rb +0 -24
- data/lib/polytrix/runners/middleware/setup_env_vars.rb +0 -42
- data/lib/polytrix/runners/mixlib_shellout_executor.rb +0 -83
- data/lib/polytrix/validations.rb +0 -23
- data/samples/scripts/wrapper +0 -7
- data/spec/polytrix/middleware/feature_executor_spec.rb +0 -48
- data/spec/polytrix/validations_spec.rb +0 -16
data/lib/polytrix/command.rb
CHANGED
|
@@ -2,13 +2,10 @@ require 'thread'
|
|
|
2
2
|
|
|
3
3
|
module Polytrix
|
|
4
4
|
module Command
|
|
5
|
-
class Base
|
|
5
|
+
class Base # rubocop:disable ClassLength
|
|
6
6
|
include Polytrix::DefaultLogger
|
|
7
7
|
include Polytrix::Logging
|
|
8
|
-
include Polytrix::
|
|
9
|
-
|
|
10
|
-
# Need standard executor...
|
|
11
|
-
SUPPORTED_EXTENSIONS = %w(py rb js)
|
|
8
|
+
include Polytrix::Util::FileSystem
|
|
12
9
|
|
|
13
10
|
# Contstructs a new Command object.
|
|
14
11
|
#
|
|
@@ -28,9 +25,9 @@ module Polytrix
|
|
|
28
25
|
@action = options.fetch(:action, nil)
|
|
29
26
|
@help = options.fetch(:help, -> { 'No help provided' })
|
|
30
27
|
@manifest_file = options.fetch('manifest', nil)
|
|
31
|
-
@test_dir = options.fetch('test_dir', nil)
|
|
32
28
|
@loader = options.fetch(:loader, nil)
|
|
33
29
|
@shell = options.fetch(:shell)
|
|
30
|
+
@queue = Queue.new
|
|
34
31
|
end
|
|
35
32
|
|
|
36
33
|
private
|
|
@@ -47,10 +44,6 @@ module Polytrix
|
|
|
47
44
|
# @api private
|
|
48
45
|
attr_reader :help
|
|
49
46
|
|
|
50
|
-
# @return [Config] a Config object
|
|
51
|
-
# @api private
|
|
52
|
-
attr_reader :test_dir
|
|
53
|
-
|
|
54
47
|
# @return [Thor::Shell] a Thor shell object
|
|
55
48
|
# @api private
|
|
56
49
|
attr_reader :shell
|
|
@@ -60,50 +53,7 @@ module Polytrix
|
|
|
60
53
|
attr_reader :action
|
|
61
54
|
|
|
62
55
|
def setup
|
|
63
|
-
|
|
64
|
-
if File.exists? manifest_file
|
|
65
|
-
logger.debug "Loading manifest file: #{manifest_file}"
|
|
66
|
-
Polytrix.configuration.manifest = @manifest_file
|
|
67
|
-
elsif @options.solo
|
|
68
|
-
solo_setup
|
|
69
|
-
else
|
|
70
|
-
fail StandardError, "No manifest found at #{manifest_file} and not using --solo mode"
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
Polytrix.configuration.documentation_dir = options[:target_dir]
|
|
74
|
-
Polytrix.configuration.documentation_format = options[:format]
|
|
75
|
-
|
|
76
|
-
manifest.build_challenges
|
|
77
|
-
|
|
78
|
-
test_dir = @test_dir.nil? ? nil : File.expand_path(@test_dir)
|
|
79
|
-
if test_dir && File.directory?(test_dir)
|
|
80
|
-
$LOAD_PATH.unshift test_dir
|
|
81
|
-
Dir["#{test_dir}/**/*.rb"].each do | file_to_require |
|
|
82
|
-
require relativize(file_to_require, test_dir).to_s.gsub('.rb', '')
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def solo_setup
|
|
88
|
-
suites = {}
|
|
89
|
-
solo_basedir = @options.solo
|
|
90
|
-
solo_glob = @options.fetch('solo_glob', "**/*.{#{SUPPORTED_EXTENSIONS.join(',')}}")
|
|
91
|
-
Dir[File.join(solo_basedir, solo_glob)].sort.each do | code_sample |
|
|
92
|
-
code_sample = Pathname.new(code_sample)
|
|
93
|
-
suite_name = relativize(code_sample.dirname, solo_basedir).to_s
|
|
94
|
-
suite_name = solo_basedir if suite_name == '.'
|
|
95
|
-
scenario_name = code_sample.basename(code_sample.extname).to_s
|
|
96
|
-
suite = suites[suite_name] ||= Polytrix::Manifest::Suite.new(samples: [])
|
|
97
|
-
suite.samples << scenario_name
|
|
98
|
-
end
|
|
99
|
-
@manifest = Polytrix.configuration.manifest = Polytrix::Manifest.new(
|
|
100
|
-
implementors: {
|
|
101
|
-
File.basename(solo_basedir) => {
|
|
102
|
-
basedir: solo_basedir
|
|
103
|
-
}
|
|
104
|
-
},
|
|
105
|
-
suites: suites
|
|
106
|
-
)
|
|
56
|
+
Polytrix.setup(options, @manifest_file)
|
|
107
57
|
end
|
|
108
58
|
|
|
109
59
|
def manifest
|
|
@@ -124,44 +74,6 @@ module Polytrix
|
|
|
124
74
|
exit 1
|
|
125
75
|
end
|
|
126
76
|
|
|
127
|
-
# @return [Array<Scenario>] an array of scenarios
|
|
128
|
-
# @raise [SystemExit] if no scenario are returned
|
|
129
|
-
# @api private
|
|
130
|
-
def all_scenarios
|
|
131
|
-
result = manifest.challenges.values
|
|
132
|
-
|
|
133
|
-
if result.empty?
|
|
134
|
-
die 'No scenarios defined'
|
|
135
|
-
else
|
|
136
|
-
result
|
|
137
|
-
end
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
# Return an array on scenarios whos name matches the regular expression.
|
|
141
|
-
#
|
|
142
|
-
# @param regexp [Regexp] a regular expression matching on instance names
|
|
143
|
-
# @return [Array<Instance>] an array of scenarios
|
|
144
|
-
# @raise [SystemExit] if no scenarios are returned or the regular
|
|
145
|
-
# expression is invalid
|
|
146
|
-
# @api private
|
|
147
|
-
def filtered_scenarios(regexp)
|
|
148
|
-
result = begin
|
|
149
|
-
manifest.challenges.get(regexp) ||
|
|
150
|
-
manifest.challenges.get_all(/#{regexp}/)
|
|
151
|
-
rescue RegexpError => e
|
|
152
|
-
die "Invalid Ruby regular expression, " \
|
|
153
|
-
"you may need to single quote the argument. " \
|
|
154
|
-
"Please try again or consult http://rubular.com/ (#{e.message})"
|
|
155
|
-
end
|
|
156
|
-
result = [result] unless result.is_a? Array
|
|
157
|
-
|
|
158
|
-
if result.empty?
|
|
159
|
-
die "No scenarios for regex `#{regexp}', try running `polytrix list'"
|
|
160
|
-
else
|
|
161
|
-
result
|
|
162
|
-
end
|
|
163
|
-
end
|
|
164
|
-
|
|
165
77
|
# Return an array on scenarios whos name matches the regular expression,
|
|
166
78
|
# the full instance name, or the `"all"` literal.
|
|
167
79
|
#
|
|
@@ -169,9 +81,14 @@ module Polytrix
|
|
|
169
81
|
# `"all"`, or `nil`
|
|
170
82
|
# @return [Array<Instance>] an array of scenarios
|
|
171
83
|
# @api private
|
|
172
|
-
def parse_subcommand(
|
|
173
|
-
|
|
174
|
-
|
|
84
|
+
def parse_subcommand(regexp = nil)
|
|
85
|
+
scenarios = Polytrix.filter_scenarios(regexp, options)
|
|
86
|
+
die "No scenarios for regex `#{regexp}', try running `polytrix list'" if scenarios.empty?
|
|
87
|
+
scenarios
|
|
88
|
+
rescue RegexpError => e
|
|
89
|
+
die 'Invalid Ruby regular expression, ' \
|
|
90
|
+
'you may need to single quote the argument. ' \
|
|
91
|
+
"Please try again or consult http://rubular.com/ (#{e.message})"
|
|
175
92
|
end
|
|
176
93
|
end
|
|
177
94
|
|
|
@@ -184,26 +101,42 @@ module Polytrix
|
|
|
184
101
|
#
|
|
185
102
|
# @param action [String] action to perform
|
|
186
103
|
# @param scenarios [Array<Instance>] an array of scenarios
|
|
187
|
-
def run_action(
|
|
104
|
+
def run_action(_action, scenarios, *_args)
|
|
188
105
|
concurrency = 1
|
|
189
106
|
if options[:concurrency]
|
|
190
107
|
concurrency = options[:concurrency] || scenarios.size
|
|
191
108
|
concurrency = scenarios.size if concurrency > scenarios.size
|
|
192
109
|
end
|
|
193
110
|
|
|
194
|
-
queue
|
|
195
|
-
|
|
196
|
-
|
|
111
|
+
scenarios.each { |i| @queue << i }
|
|
112
|
+
concurrency.times { @queue << nil }
|
|
113
|
+
|
|
114
|
+
threads = concurrency.times.map { |i| spawn(i) }
|
|
115
|
+
threads.map do |t|
|
|
116
|
+
begin
|
|
117
|
+
t.join
|
|
118
|
+
rescue Polytrix::ExecutionError, Polytrix::ChallengeFailure
|
|
119
|
+
# respawn thread
|
|
120
|
+
t.kill
|
|
121
|
+
threads.delete(t)
|
|
122
|
+
threads.push(spawn)
|
|
123
|
+
end
|
|
124
|
+
end while threads.any?(&:alive?)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
private
|
|
197
128
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
129
|
+
def spawn(i)
|
|
130
|
+
Thread.new(i) do |test_env_number|
|
|
131
|
+
Thread.current[:test_env_number] = test_env_number
|
|
132
|
+
while (instance = @queue.pop)
|
|
133
|
+
begin
|
|
202
134
|
instance.public_send(action, *args)
|
|
135
|
+
rescue Polytrix::ExecutionError, Polytrix::ChallengeFailure => e
|
|
136
|
+
logger.error(e)
|
|
203
137
|
end
|
|
204
138
|
end
|
|
205
139
|
end
|
|
206
|
-
threads.map { |i| i.join }
|
|
207
140
|
end
|
|
208
141
|
end
|
|
209
142
|
end
|
|
@@ -1,27 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
|
+
require 'rspec/support'
|
|
3
|
+
require 'rspec/expectations'
|
|
2
4
|
|
|
3
5
|
module Polytrix
|
|
4
6
|
RESOURCES_DIR = File.expand_path '../../../resources', __FILE__
|
|
5
|
-
# Autoload pool
|
|
6
|
-
module Runners
|
|
7
|
-
module Middleware
|
|
8
|
-
autoload :FeatureExecutor, 'polytrix/runners/middleware/feature_executor'
|
|
9
|
-
autoload :SetupEnvVars, 'polytrix/runners/middleware/setup_env_vars'
|
|
10
|
-
autoload :ChangeDirectory, 'polytrix/runners/middleware/change_directory'
|
|
11
|
-
|
|
12
|
-
STANDARD_MIDDLEWARE = ::Middleware::Builder.new do
|
|
13
|
-
use Polytrix::Runners::Middleware::ChangeDirectory
|
|
14
|
-
use Polytrix::Runners::Middleware::SetupEnvVars
|
|
15
|
-
use Polytrix::Runners::Middleware::FeatureExecutor
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
7
|
|
|
20
8
|
class Configuration < Polytrix::ManifestSection
|
|
21
9
|
property :dry_run, default: false
|
|
22
10
|
property :log_root, default: '.polytrix/logs'
|
|
23
11
|
property :log_level, default: :info
|
|
24
|
-
property :middleware, default: Polytrix::Runners::Middleware::STANDARD_MIDDLEWARE
|
|
25
12
|
property :implementors, default: []
|
|
26
13
|
# coerce_key :implementors, Polytrix::Implementor
|
|
27
14
|
property :suppress_output, default: false
|
|
@@ -29,8 +16,13 @@ module Polytrix
|
|
|
29
16
|
property :template_dir, default: "#{RESOURCES_DIR}"
|
|
30
17
|
property :documentation_dir, default: 'docs/'
|
|
31
18
|
property :documentation_format, default: 'md'
|
|
32
|
-
|
|
33
|
-
|
|
19
|
+
|
|
20
|
+
# TODO: This should probably be configurable, or tied to Thor color options.
|
|
21
|
+
if RSpec.respond_to?(:configuration)
|
|
22
|
+
RSpec.configuration.color = true
|
|
23
|
+
else
|
|
24
|
+
RSpec::Expectations.configuration.color = true
|
|
25
|
+
end
|
|
34
26
|
|
|
35
27
|
def default_logger
|
|
36
28
|
@default_logger ||= Logger.new(stdout: $stdout, level: env_log)
|
|
@@ -66,6 +58,10 @@ module Polytrix
|
|
|
66
58
|
|
|
67
59
|
attr_writer :default_validator_callback
|
|
68
60
|
|
|
61
|
+
def register_spy(spy)
|
|
62
|
+
Polytrix::Spies.register_spy(spy)
|
|
63
|
+
end
|
|
64
|
+
|
|
69
65
|
private
|
|
70
66
|
|
|
71
67
|
# Determine the default log level from an environment variable, if it is
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
require 'hashie/dash'
|
|
2
|
-
require 'hashie/mash'
|
|
3
2
|
require 'hashie/extensions/coercion'
|
|
4
3
|
|
|
5
4
|
module Polytrix
|
|
@@ -7,8 +6,10 @@ module Polytrix
|
|
|
7
6
|
include Hashie::Extensions::Coercion
|
|
8
7
|
|
|
9
8
|
def initialize(hash = {})
|
|
10
|
-
|
|
11
|
-
super mash.to_hash(symbolize_keys: true)
|
|
9
|
+
super Polytrix::Util.symbolized_hash(hash)
|
|
12
10
|
end
|
|
13
11
|
end
|
|
12
|
+
|
|
13
|
+
class ManifestSection < Polytrix::Dash
|
|
14
|
+
end
|
|
14
15
|
end
|
|
@@ -5,7 +5,7 @@ module Polytrix
|
|
|
5
5
|
# This class was extracted from the [Rocco](http://rtomayko.github.com/rocco/) project
|
|
6
6
|
# which was in turn based on the [Docco](http://jashkenas.github.com/docco/).
|
|
7
7
|
class CodeSegmenter # rubocop:disable all
|
|
8
|
-
|
|
8
|
+
# Cops are disabled because the code is from Rocco
|
|
9
9
|
include CommentStyles
|
|
10
10
|
|
|
11
11
|
DEFAULT_OPTIONS = {
|
|
@@ -23,7 +23,7 @@ module Polytrix
|
|
|
23
23
|
# Parse the raw file source_code into a list of two-tuples. Each tuple has the
|
|
24
24
|
# form `[docs, code]` where both elements are arrays containing the
|
|
25
25
|
# raw lines parsed from the input file, comment characters stripped.
|
|
26
|
-
def segment(source_code)
|
|
26
|
+
def segment(source_code) # rubocop:disable all
|
|
27
27
|
sections, docs, code = [], [], []
|
|
28
28
|
lines = source_code.split("\n")
|
|
29
29
|
|
|
@@ -42,20 +42,20 @@ module Polytrix
|
|
|
42
42
|
in_heredoc = false
|
|
43
43
|
single_line_comment, block_comment_start, block_comment_mid, block_comment_end =
|
|
44
44
|
nil, nil, nil, nil
|
|
45
|
-
|
|
45
|
+
unless @options[:comment_chars][:single].nil?
|
|
46
46
|
single_line_comment = Regexp.new("^\\s*#{Regexp.escape(@options[:comment_chars][:single])}\\s?")
|
|
47
47
|
end
|
|
48
|
-
|
|
48
|
+
unless @options[:comment_chars][:multi].nil?
|
|
49
49
|
block_comment_start = Regexp.new("^\\s*#{Regexp.escape(@options[:comment_chars][:multi][:start])}\\s*$")
|
|
50
50
|
block_comment_end = Regexp.new("^\\s*#{Regexp.escape(@options[:comment_chars][:multi][:end])}\\s*$")
|
|
51
|
-
block_comment_one_liner = Regexp.new("^\\s*#{Regexp.escape(@options[:comment_chars][:multi][:start])}\\s*(.*?)\\s*#{Regexp.escape(@options[:comment_chars][:multi][:end])}\\s*$")
|
|
51
|
+
block_comment_one_liner = Regexp.new("^\\s*#{Regexp.escape(@options[:comment_chars][:multi][:start])}\\s*(.*?)\\s*#{Regexp.escape(@options[:comment_chars][:multi][:end])}\\s*$") # rubocop:disable Metrics/LineLength
|
|
52
52
|
block_comment_start_with = Regexp.new("^\\s*#{Regexp.escape(@options[:comment_chars][:multi][:start])}\\s*(.*?)$")
|
|
53
53
|
block_comment_end_with = Regexp.new("\\s*(.*?)\\s*#{Regexp.escape(@options[:comment_chars][:multi][:end])}\\s*$")
|
|
54
54
|
if @options[:comment_chars][:multi][:middle]
|
|
55
55
|
block_comment_mid = Regexp.new("^\\s*#{Regexp.escape(@options[:comment_chars][:multi][:middle])}\\s?")
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
|
-
|
|
58
|
+
unless @options[:comment_chars][:heredoc].nil?
|
|
59
59
|
heredoc_start = Regexp.new("#{Regexp.escape(@options[:comment_chars][:heredoc])}(\\S+)$")
|
|
60
60
|
end
|
|
61
61
|
lines.each do |line|
|
|
@@ -67,8 +67,8 @@ module Polytrix
|
|
|
67
67
|
in_comment_block = false
|
|
68
68
|
elsif block_comment_end_with && line.match(block_comment_end_with)
|
|
69
69
|
in_comment_block = false
|
|
70
|
-
docs << line.match(block_comment_end_with).captures.first
|
|
71
|
-
sub(block_comment_mid || '', '')
|
|
70
|
+
docs << line.match(block_comment_end_with).captures.first
|
|
71
|
+
.sub(block_comment_mid || '', '')
|
|
72
72
|
else
|
|
73
73
|
docs << line.sub(block_comment_mid || '', '')
|
|
74
74
|
end
|
|
@@ -15,7 +15,7 @@ module Polytrix
|
|
|
15
15
|
extension.tr! '.', ''
|
|
16
16
|
return extension, COMMENT_STYLES[extension] if COMMENT_STYLES.key? extension
|
|
17
17
|
|
|
18
|
-
COMMENT_STYLES.each do |
|
|
18
|
+
COMMENT_STYLES.each do | _style_name, style |
|
|
19
19
|
return extension, style if style[:extensions].include? extension
|
|
20
20
|
end
|
|
21
21
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'polytrix/documentation/code_segmenter'
|
|
2
|
+
require 'rouge'
|
|
2
3
|
|
|
3
4
|
module Polytrix
|
|
4
5
|
module Documentation
|
|
@@ -35,6 +36,14 @@ module Polytrix
|
|
|
35
36
|
File.read absolute_source_file
|
|
36
37
|
end
|
|
37
38
|
|
|
39
|
+
def source?
|
|
40
|
+
!absolute_source_file.nil?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def highlighted_code(formatter = 'terminal256')
|
|
44
|
+
highlight(source, language: implementor.language, filename: absolute_source_file, formatter: formatter)
|
|
45
|
+
end
|
|
46
|
+
|
|
38
47
|
def code_block(source_code, language, opts = { format: :markdown })
|
|
39
48
|
case opts[:format]
|
|
40
49
|
when :rst
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
require 'tilt' #
|
|
1
|
+
require 'tilt' # padrino-helpers wants you to pre-require tilt/erubis
|
|
2
|
+
require 'erubis'
|
|
2
3
|
require 'padrino-helpers'
|
|
3
4
|
|
|
4
5
|
module Polytrix
|
|
@@ -20,23 +21,19 @@ module Polytrix
|
|
|
20
21
|
end
|
|
21
22
|
|
|
22
23
|
def process(challenges)
|
|
24
|
+
return nil unless File.readable? @template_file
|
|
25
|
+
|
|
23
26
|
@challenges = challenges
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
erb = ERB.new File.read(@template_file)
|
|
27
|
-
@result = erb.result(binding) || ''
|
|
28
|
-
end
|
|
27
|
+
erb = ERB.new File.read(@template_file)
|
|
28
|
+
@result = erb.result(binding) || ''
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def save(target_file)
|
|
32
|
-
fail 'No results to write, please call process before save' if @result.nil?
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
File.open(target_file, 'wb') do |f|
|
|
38
|
-
f.write @result
|
|
39
|
-
end
|
|
32
|
+
fail 'No results to write, please call process before save' if @result.nil? || @result.empty?
|
|
33
|
+
|
|
34
|
+
FileUtils.mkdir_p File.dirname(target_file)
|
|
35
|
+
File.open(target_file, 'wb') do |f|
|
|
36
|
+
f.write @result
|
|
40
37
|
end
|
|
41
38
|
end
|
|
42
39
|
|
data/lib/polytrix/error.rb
CHANGED
|
@@ -96,114 +96,121 @@ module Polytrix
|
|
|
96
96
|
# Exception class capturing what caused an challenge to die.
|
|
97
97
|
class ChallengeFailure < TransientFailure; end
|
|
98
98
|
|
|
99
|
+
# Exception class capturing what caused a validation to fail.
|
|
100
|
+
class ValidationFailure < TransientFailure; end
|
|
101
|
+
|
|
99
102
|
class ExecutionError < TransientFailure
|
|
100
103
|
attr_accessor :execution_result
|
|
101
104
|
end
|
|
102
105
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
Polytrix
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
Polytrix
|
|
143
|
-
|
|
106
|
+
class << self
|
|
107
|
+
# Yields to a code block in order to consistently emit a useful crash/error
|
|
108
|
+
# message and exit appropriately. There are two primary failure conditions:
|
|
109
|
+
# an expected challenge failure, and any other unexpected failures.
|
|
110
|
+
#
|
|
111
|
+
# **Note** This method may call `Kernel.exit` so may not return if the
|
|
112
|
+
# yielded code block raises an exception.
|
|
113
|
+
#
|
|
114
|
+
# ## Challenge Failure
|
|
115
|
+
#
|
|
116
|
+
# This is an expected failure scenario which could happen if an challenge
|
|
117
|
+
# couldn't be created, a Chef run didn't successfully converge, a
|
|
118
|
+
# post-convergence test suite failed, etc. In other words, you can count on
|
|
119
|
+
# encountering these failures all the time--this is Polytrix's worldview:
|
|
120
|
+
# crash early and often. In this case a cleanly formatted exception is
|
|
121
|
+
# written to `STDERR` and the exception message is written to
|
|
122
|
+
# the common Polytrix file logger.
|
|
123
|
+
#
|
|
124
|
+
# ## Unexpected Failure
|
|
125
|
+
#
|
|
126
|
+
# All other forms of `Polytrix::Error` exceptions are considered unexpected
|
|
127
|
+
# or unplanned exceptions, typically from user configuration errors, driver
|
|
128
|
+
# or provisioner coding issues or bugs, or internal code issues. Given
|
|
129
|
+
# a stable release of Polytrix and a solid set of drivers and provisioners,
|
|
130
|
+
# the most likely cause of this is user configuration error originating in
|
|
131
|
+
# the `.polytrix.yml` setup. For this reason, the exception is written to
|
|
132
|
+
# `STDERR`, a full formatted exception trace is written to the common
|
|
133
|
+
# Polytrix file logger, and a message is displayed on `STDERR` to the user
|
|
134
|
+
# informing them to check the log files and check their configuration with
|
|
135
|
+
# the `polytrix diagnose` subcommand.
|
|
136
|
+
#
|
|
137
|
+
# @raise [SystemExit] if an exception is raised in the yielded block
|
|
138
|
+
def with_friendly_errors
|
|
139
|
+
yield
|
|
140
|
+
rescue Polytrix::ChallengeFailure => e
|
|
141
|
+
Polytrix.mutex.synchronize do
|
|
142
|
+
handle_challenge_failure(e)
|
|
143
|
+
end
|
|
144
|
+
exit 10
|
|
145
|
+
rescue Polytrix::Error => e
|
|
146
|
+
Polytrix.mutex.synchronize do
|
|
147
|
+
handle_error(e)
|
|
148
|
+
end
|
|
149
|
+
exit 20
|
|
144
150
|
end
|
|
145
|
-
exit 20
|
|
146
|
-
end
|
|
147
151
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
Array(lines).each do |line|
|
|
159
|
-
if Polytrix.logger.debug?
|
|
160
|
-
Polytrix.logger.debug(line)
|
|
161
|
-
else
|
|
162
|
-
Polytrix.logger.logdev && Polytrix.logger.logdev.public_send(level, line)
|
|
163
|
-
end
|
|
152
|
+
# Handles an challenge failure exception.
|
|
153
|
+
#
|
|
154
|
+
# @param e [StandardError] an exception to handle
|
|
155
|
+
# @see Polytrix.with_friendly_errors
|
|
156
|
+
# @api private
|
|
157
|
+
def handle_challenge_failure(e)
|
|
158
|
+
stderr_log(e.message.split(/\s{2,}/))
|
|
159
|
+
stderr_log(Error.formatted_exception(e.original))
|
|
160
|
+
file_log(:error, e.message.split(/\s{2,}/).first)
|
|
161
|
+
debug_log(Error.formatted_trace(e))
|
|
164
162
|
end
|
|
165
|
-
end
|
|
166
163
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
164
|
+
alias_method :handle_validation_failure, :handle_challenge_failure
|
|
165
|
+
|
|
166
|
+
# Handles an unexpected failure exception.
|
|
167
|
+
#
|
|
168
|
+
# @param e [StandardError] an exception to handle
|
|
169
|
+
# @see Polytrix.with_friendly_errors
|
|
170
|
+
# @api private
|
|
171
|
+
def handle_error(e)
|
|
172
|
+
stderr_log(Error.formatted_exception(e))
|
|
173
|
+
stderr_log('Please see .polytrix/logs/polytrix.log for more details')
|
|
174
|
+
# stderr_log("Also try running `polytrix diagnose --all` for configuration\n")
|
|
175
|
+
file_log(:error, Error.formatted_trace(e))
|
|
174
176
|
end
|
|
175
|
-
end
|
|
176
177
|
|
|
177
|
-
|
|
178
|
-
# severity.
|
|
179
|
-
#
|
|
180
|
-
# @param lines [Array<String>] an array of strings to log
|
|
181
|
-
# @api private
|
|
182
|
-
def self.debug_log(lines)
|
|
183
|
-
Array(lines).each { |line| Polytrix.logger.debug(line) }
|
|
184
|
-
end
|
|
178
|
+
private
|
|
185
179
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
180
|
+
# Writes an array of lines to the common Polytrix logger's file device at the
|
|
181
|
+
# given severity level. If the Polytrix logger is set to debug severity, then
|
|
182
|
+
# the array of lines will also be written to the console output.
|
|
183
|
+
#
|
|
184
|
+
# @param level [Symbol,String] the desired log level
|
|
185
|
+
# @param lines [Array<String>] an array of strings to log
|
|
186
|
+
# @api private
|
|
187
|
+
def file_log(level, lines)
|
|
188
|
+
Array(lines).each do |line|
|
|
189
|
+
if Polytrix.logger.debug?
|
|
190
|
+
Polytrix.logger.debug(line)
|
|
191
|
+
else
|
|
192
|
+
Polytrix.logger.logdev && Polytrix.logger.logdev.public_send(level, line)
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
197
196
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
197
|
+
# Writes an array of lines to the `STDERR` device.
|
|
198
|
+
#
|
|
199
|
+
# @param lines [Array<String>] an array of strings to log
|
|
200
|
+
# @api private
|
|
201
|
+
def stderr_log(lines)
|
|
202
|
+
Array(lines).each do |line|
|
|
203
|
+
$stderr.puts(Color.colorize(">>>>>> #{line}", :red))
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Writes an array of lines to the common Polytrix debugger with debug
|
|
208
|
+
# severity.
|
|
209
|
+
#
|
|
210
|
+
# @param lines [Array<String>] an array of strings to log
|
|
211
|
+
# @api private
|
|
212
|
+
def debug_log(lines)
|
|
213
|
+
Array(lines).each { |line| Polytrix.logger.debug(line) }
|
|
214
|
+
end
|
|
208
215
|
end
|
|
209
216
|
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Polytrix
|
|
2
|
+
module Executors
|
|
3
|
+
autoload :BuffShellOutExecutor, 'polytrix/executors/buff_shellout_executor'
|
|
4
|
+
autoload :MixlibShellOutExecutor, 'polytrix/executors/mixlib_shellout_executor'
|
|
5
|
+
|
|
6
|
+
class ExecutionResult < Polytrix::Dash
|
|
7
|
+
property :exitstatus, require: true
|
|
8
|
+
property :stdout, required: true
|
|
9
|
+
property :stderr, required: true
|
|
10
|
+
coerce_value String, ->(v) { v.force_encoding('utf-8') }
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module Executor
|
|
15
|
+
attr_writer :executor
|
|
16
|
+
attr_accessor :env
|
|
17
|
+
|
|
18
|
+
def executor
|
|
19
|
+
@executor ||= if RUBY_PLATFORM == 'java'
|
|
20
|
+
# TODO: Display warning that JRuby support is experimental
|
|
21
|
+
# (because executor may not be equivalent)
|
|
22
|
+
Polytrix::Executors::BuffShellOutExecutor.new
|
|
23
|
+
else
|
|
24
|
+
Polytrix::Executors::MixlibShellOutExecutor.new
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def execute(command, opts = {})
|
|
29
|
+
opts[:env] = env unless env.nil?
|
|
30
|
+
executor.execute(command, opts)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|