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