konpeito 0.1.0
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 +7 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +75 -0
- data/CONTRIBUTING.md +123 -0
- data/LICENSE +21 -0
- data/README.md +257 -0
- data/Rakefile +11 -0
- data/bin/konpeito +6 -0
- data/konpeito.gemspec +43 -0
- data/lib/konpeito/ast/typed_ast.rb +620 -0
- data/lib/konpeito/ast/visitor.rb +78 -0
- data/lib/konpeito/cache/cache_manager.rb +230 -0
- data/lib/konpeito/cache/dependency_graph.rb +192 -0
- data/lib/konpeito/cache.rb +8 -0
- data/lib/konpeito/cli/base_command.rb +187 -0
- data/lib/konpeito/cli/build_command.rb +220 -0
- data/lib/konpeito/cli/check_command.rb +104 -0
- data/lib/konpeito/cli/config.rb +231 -0
- data/lib/konpeito/cli/deps_command.rb +128 -0
- data/lib/konpeito/cli/doctor_command.rb +340 -0
- data/lib/konpeito/cli/fmt_command.rb +199 -0
- data/lib/konpeito/cli/init_command.rb +312 -0
- data/lib/konpeito/cli/lsp_command.rb +40 -0
- data/lib/konpeito/cli/run_command.rb +150 -0
- data/lib/konpeito/cli/test_command.rb +248 -0
- data/lib/konpeito/cli/watch_command.rb +212 -0
- data/lib/konpeito/cli.rb +301 -0
- data/lib/konpeito/codegen/builtin_methods.rb +229 -0
- data/lib/konpeito/codegen/cruby_backend.rb +1090 -0
- data/lib/konpeito/codegen/debug_info.rb +352 -0
- data/lib/konpeito/codegen/inliner.rb +486 -0
- data/lib/konpeito/codegen/jvm_backend.rb +197 -0
- data/lib/konpeito/codegen/jvm_generator.rb +13412 -0
- data/lib/konpeito/codegen/llvm_generator.rb +13191 -0
- data/lib/konpeito/codegen/loop_optimizer.rb +363 -0
- data/lib/konpeito/codegen/monomorphizer.rb +359 -0
- data/lib/konpeito/codegen/profile_runtime.c +341 -0
- data/lib/konpeito/codegen/profiler.rb +99 -0
- data/lib/konpeito/compiler.rb +592 -0
- data/lib/konpeito/dependency_resolver.rb +296 -0
- data/lib/konpeito/diagnostics/collector.rb +127 -0
- data/lib/konpeito/diagnostics/diagnostic.rb +237 -0
- data/lib/konpeito/diagnostics/renderer.rb +144 -0
- data/lib/konpeito/formatter/formatter.rb +1214 -0
- data/lib/konpeito/hir/builder.rb +7167 -0
- data/lib/konpeito/hir/nodes.rb +2465 -0
- data/lib/konpeito/lsp/document_manager.rb +820 -0
- data/lib/konpeito/lsp/server.rb +183 -0
- data/lib/konpeito/lsp/transport.rb +38 -0
- data/lib/konpeito/parser/prism_adapter.rb +65 -0
- data/lib/konpeito/platform.rb +103 -0
- data/lib/konpeito/profile/report.rb +136 -0
- data/lib/konpeito/rbs_inline/preprocessor.rb +199 -0
- data/lib/konpeito/stdlib/compression/compression.rb +72 -0
- data/lib/konpeito/stdlib/compression/compression.rbs +60 -0
- data/lib/konpeito/stdlib/compression/compression_native.c +415 -0
- data/lib/konpeito/stdlib/compression/extconf.rb +19 -0
- data/lib/konpeito/stdlib/crypto/crypto.rb +85 -0
- data/lib/konpeito/stdlib/crypto/crypto.rbs +74 -0
- data/lib/konpeito/stdlib/crypto/crypto_native.c +312 -0
- data/lib/konpeito/stdlib/crypto/extconf.rb +40 -0
- data/lib/konpeito/stdlib/http/extconf.rb +19 -0
- data/lib/konpeito/stdlib/http/http.rb +125 -0
- data/lib/konpeito/stdlib/http/http.rbs +57 -0
- data/lib/konpeito/stdlib/http/http_native.c +440 -0
- data/lib/konpeito/stdlib/json/extconf.rb +17 -0
- data/lib/konpeito/stdlib/json/json.rb +44 -0
- data/lib/konpeito/stdlib/json/json.rbs +33 -0
- data/lib/konpeito/stdlib/json/json_native.c +286 -0
- data/lib/konpeito/stdlib/ui/extconf.rb +216 -0
- data/lib/konpeito/stdlib/ui/konpeito_ui_native.cpp +1625 -0
- data/lib/konpeito/stdlib/ui/konpeito_ui_native.h +162 -0
- data/lib/konpeito/stdlib/ui/ui.rb +318 -0
- data/lib/konpeito/stdlib/ui/ui.rbs +247 -0
- data/lib/konpeito/type_checker/annotation_parser.rb +67 -0
- data/lib/konpeito/type_checker/hm_inferrer.rb +2565 -0
- data/lib/konpeito/type_checker/inferrer.rb +565 -0
- data/lib/konpeito/type_checker/rbs_loader.rb +1621 -0
- data/lib/konpeito/type_checker/type_resolver.rb +276 -0
- data/lib/konpeito/type_checker/types.rb +1434 -0
- data/lib/konpeito/type_checker/unification.rb +323 -0
- data/lib/konpeito/ui/animation/animated_state.rb +80 -0
- data/lib/konpeito/ui/animation/easing.rb +59 -0
- data/lib/konpeito/ui/animation/value_tween.rb +66 -0
- data/lib/konpeito/ui/app.rb +379 -0
- data/lib/konpeito/ui/box.rb +38 -0
- data/lib/konpeito/ui/castella.rb +70 -0
- data/lib/konpeito/ui/castella_native.rb +76 -0
- data/lib/konpeito/ui/chart/area_chart.rb +305 -0
- data/lib/konpeito/ui/chart/bar_chart.rb +288 -0
- data/lib/konpeito/ui/chart/base_chart.rb +210 -0
- data/lib/konpeito/ui/chart/chart_helpers.rb +79 -0
- data/lib/konpeito/ui/chart/gauge_chart.rb +171 -0
- data/lib/konpeito/ui/chart/heatmap_chart.rb +222 -0
- data/lib/konpeito/ui/chart/line_chart.rb +289 -0
- data/lib/konpeito/ui/chart/pie_chart.rb +219 -0
- data/lib/konpeito/ui/chart/scales.rb +77 -0
- data/lib/konpeito/ui/chart/scatter_chart.rb +303 -0
- data/lib/konpeito/ui/chart/stacked_bar_chart.rb +276 -0
- data/lib/konpeito/ui/column.rb +271 -0
- data/lib/konpeito/ui/core.rb +2199 -0
- data/lib/konpeito/ui/dsl.rb +443 -0
- data/lib/konpeito/ui/frame.rb +171 -0
- data/lib/konpeito/ui/frame_native.rb +494 -0
- data/lib/konpeito/ui/markdown/ast.rb +124 -0
- data/lib/konpeito/ui/markdown/mermaid/layout.rb +387 -0
- data/lib/konpeito/ui/markdown/mermaid/models.rb +232 -0
- data/lib/konpeito/ui/markdown/mermaid/parser.rb +519 -0
- data/lib/konpeito/ui/markdown/mermaid/renderer.rb +336 -0
- data/lib/konpeito/ui/markdown/parser.rb +805 -0
- data/lib/konpeito/ui/markdown/renderer.rb +639 -0
- data/lib/konpeito/ui/markdown/theme.rb +165 -0
- data/lib/konpeito/ui/render_node.rb +260 -0
- data/lib/konpeito/ui/row.rb +207 -0
- data/lib/konpeito/ui/spacer.rb +18 -0
- data/lib/konpeito/ui/style.rb +799 -0
- data/lib/konpeito/ui/theme.rb +563 -0
- data/lib/konpeito/ui/themes/material.rb +35 -0
- data/lib/konpeito/ui/themes/tokyo_night.rb +6 -0
- data/lib/konpeito/ui/widgets/button.rb +103 -0
- data/lib/konpeito/ui/widgets/calendar.rb +1034 -0
- data/lib/konpeito/ui/widgets/checkbox.rb +119 -0
- data/lib/konpeito/ui/widgets/container.rb +91 -0
- data/lib/konpeito/ui/widgets/data_table.rb +667 -0
- data/lib/konpeito/ui/widgets/divider.rb +29 -0
- data/lib/konpeito/ui/widgets/image.rb +105 -0
- data/lib/konpeito/ui/widgets/input.rb +485 -0
- data/lib/konpeito/ui/widgets/markdown.rb +57 -0
- data/lib/konpeito/ui/widgets/modal.rb +163 -0
- data/lib/konpeito/ui/widgets/multiline_input.rb +968 -0
- data/lib/konpeito/ui/widgets/multiline_text.rb +180 -0
- data/lib/konpeito/ui/widgets/net_image.rb +100 -0
- data/lib/konpeito/ui/widgets/progress_bar.rb +70 -0
- data/lib/konpeito/ui/widgets/radio_buttons.rb +93 -0
- data/lib/konpeito/ui/widgets/slider.rb +133 -0
- data/lib/konpeito/ui/widgets/switch.rb +84 -0
- data/lib/konpeito/ui/widgets/tabs.rb +157 -0
- data/lib/konpeito/ui/widgets/text.rb +110 -0
- data/lib/konpeito/ui/widgets/tree.rb +426 -0
- data/lib/konpeito/version.rb +5 -0
- data/lib/konpeito.rb +109 -0
- data/test_native_array.rb +172 -0
- data/test_native_array_class.rb +197 -0
- data/test_native_class.rb +151 -0
- data/tools/konpeito-asm/build.sh +65 -0
- data/tools/konpeito-asm/lib/asm-9.7.1.jar +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KArray.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCompression.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KConditionVariable.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCrypto.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KFile.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHTTP.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHash.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON$Parser.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KMath.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactor.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactorPort.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KSizedQueue.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KThread.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KTime.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/RubyDispatch.class +0 -0
- data/tools/konpeito-asm/src/ClassIntrospector.java +312 -0
- data/tools/konpeito-asm/src/KonpeitoAssembler.java +659 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KArray.java +390 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KCompression.java +168 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KConditionVariable.java +48 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KCrypto.java +151 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KFile.java +100 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KHTTP.java +113 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KHash.java +228 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KJSON.java +405 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KMath.java +54 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KRactor.java +244 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KRactorPort.java +53 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KSizedQueue.java +49 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KThread.java +49 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KTime.java +53 -0
- data/tools/konpeito-asm/src/konpeito/runtime/RubyDispatch.java +416 -0
- metadata +267 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Konpeito
|
|
4
|
+
module Commands
|
|
5
|
+
# Test command - run tests with Minitest
|
|
6
|
+
class TestCommand < BaseCommand
|
|
7
|
+
def self.command_name
|
|
8
|
+
"test"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.description
|
|
12
|
+
"Run tests (Minitest integration)"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def run
|
|
16
|
+
parse_options!
|
|
17
|
+
|
|
18
|
+
test_files = find_test_files
|
|
19
|
+
|
|
20
|
+
if test_files.empty?
|
|
21
|
+
puts "No test files found matching pattern: #{options[:pattern]}"
|
|
22
|
+
return
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
target = options[:target] || config.target
|
|
26
|
+
|
|
27
|
+
if target == :jvm
|
|
28
|
+
run_jvm_tests(test_files)
|
|
29
|
+
else
|
|
30
|
+
if options[:compile_first]
|
|
31
|
+
compile_source_files
|
|
32
|
+
end
|
|
33
|
+
run_tests(test_files)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
protected
|
|
38
|
+
|
|
39
|
+
def default_options
|
|
40
|
+
{
|
|
41
|
+
verbose: false,
|
|
42
|
+
color: $stderr.tty?,
|
|
43
|
+
pattern: config.test_pattern,
|
|
44
|
+
compile_first: false,
|
|
45
|
+
name_pattern: nil,
|
|
46
|
+
target: nil,
|
|
47
|
+
classpath: nil
|
|
48
|
+
}
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def setup_option_parser(opts)
|
|
52
|
+
opts.on("-p", "--pattern PATTERN", "Test file pattern (default: test/**/*_test.rb)") do |pattern|
|
|
53
|
+
options[:pattern] = pattern
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
opts.on("-n", "--name PATTERN", "Run tests matching name pattern") do |pattern|
|
|
57
|
+
options[:name_pattern] = pattern
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
opts.on("--compile", "Compile source files before running tests") do
|
|
61
|
+
options[:compile_first] = true
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
opts.on("--target TARGET", %i[native jvm], "Target platform (native, jvm)") do |target|
|
|
65
|
+
options[:target] = target
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
opts.on("--classpath PATH", "Add external JARs/directories to classpath (JVM only)") do |path|
|
|
69
|
+
options[:classpath] = path
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
super
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def banner
|
|
76
|
+
<<~BANNER.chomp
|
|
77
|
+
Usage: konpeito test [options] [test_files...]
|
|
78
|
+
|
|
79
|
+
Examples:
|
|
80
|
+
konpeito test Run all tests
|
|
81
|
+
konpeito test test/main_test.rb Run specific test file
|
|
82
|
+
konpeito test -n test_hello Run matching test name
|
|
83
|
+
konpeito test --target jvm Run JVM tests
|
|
84
|
+
BANNER
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
private
|
|
88
|
+
|
|
89
|
+
def find_test_files
|
|
90
|
+
if args.empty?
|
|
91
|
+
Dir.glob(options[:pattern])
|
|
92
|
+
else
|
|
93
|
+
args.select { |f| File.exist?(f) }
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def compile_source_files
|
|
98
|
+
puts_verbose "Compiling source files..."
|
|
99
|
+
|
|
100
|
+
src_files = Dir.glob("src/**/*.rb")
|
|
101
|
+
src_files.each do |source_file|
|
|
102
|
+
puts_verbose " Compiling #{source_file}..."
|
|
103
|
+
begin
|
|
104
|
+
output_file = default_output_name(source_file)
|
|
105
|
+
compiler = Compiler.new(
|
|
106
|
+
source_file: source_file,
|
|
107
|
+
output_file: output_file,
|
|
108
|
+
format: :cruby_ext,
|
|
109
|
+
verbose: options[:verbose],
|
|
110
|
+
rbs_paths: config.rbs_paths,
|
|
111
|
+
require_paths: config.require_paths
|
|
112
|
+
)
|
|
113
|
+
compiler.compile
|
|
114
|
+
rescue Konpeito::Error => e
|
|
115
|
+
$stderr.puts "Warning: Failed to compile #{source_file}: #{e.message}"
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def run_jvm_tests(test_files)
|
|
121
|
+
require "tmpdir"
|
|
122
|
+
require "fileutils"
|
|
123
|
+
|
|
124
|
+
passed = 0
|
|
125
|
+
failed = 0
|
|
126
|
+
errors = 0
|
|
127
|
+
|
|
128
|
+
# Build classpath
|
|
129
|
+
classpath_parts = []
|
|
130
|
+
cp = options[:classpath] || config.jvm_classpath
|
|
131
|
+
classpath_parts << cp unless cp.empty?
|
|
132
|
+
lib_jars = Dir.glob("lib/*.jar")
|
|
133
|
+
classpath_parts << lib_jars.join(Platform.classpath_separator) unless lib_jars.empty?
|
|
134
|
+
classpath = classpath_parts.reject(&:empty?).join(Platform.classpath_separator)
|
|
135
|
+
|
|
136
|
+
puts "Running #{test_files.size} JVM test file(s)..."
|
|
137
|
+
puts ""
|
|
138
|
+
|
|
139
|
+
test_files.each do |test_file|
|
|
140
|
+
puts_verbose "Compiling #{test_file}..."
|
|
141
|
+
|
|
142
|
+
Dir.mktmpdir("konpeito-test") do |tmpdir|
|
|
143
|
+
jar_path = File.join(tmpdir, "test.jar")
|
|
144
|
+
|
|
145
|
+
begin
|
|
146
|
+
# Compile to JAR
|
|
147
|
+
build_args = ["--target", "jvm", "-o", jar_path]
|
|
148
|
+
build_args += ["--classpath", classpath] unless classpath.empty?
|
|
149
|
+
config.rbs_paths.each { |p| build_args << "--rbs" << p }
|
|
150
|
+
build_args << test_file
|
|
151
|
+
|
|
152
|
+
Commands::BuildCommand.new(build_args, config: config).run
|
|
153
|
+
|
|
154
|
+
# Run the JAR
|
|
155
|
+
java_cmd = find_java
|
|
156
|
+
run_cmd = if classpath.empty?
|
|
157
|
+
[java_cmd, "-jar", jar_path]
|
|
158
|
+
else
|
|
159
|
+
main_class = File.basename(test_file, ".rb").split("_").map(&:capitalize).join
|
|
160
|
+
cp = "#{jar_path}#{Platform.classpath_separator}#{classpath}"
|
|
161
|
+
[java_cmd, "-cp", cp, main_class]
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
output = `#{run_cmd.map { |s| s.include?(" ") ? "\"#{s}\"" : s }.join(" ")} 2>&1`
|
|
165
|
+
|
|
166
|
+
# Parse PASS:/FAIL: from output
|
|
167
|
+
output.each_line do |line|
|
|
168
|
+
line = line.strip
|
|
169
|
+
if line.start_with?("PASS:")
|
|
170
|
+
passed += 1
|
|
171
|
+
puts " \e[32m#{line}\e[0m" if options[:color]
|
|
172
|
+
puts " #{line}" unless options[:color]
|
|
173
|
+
elsif line.start_with?("FAIL:")
|
|
174
|
+
failed += 1
|
|
175
|
+
puts " \e[31m#{line}\e[0m" if options[:color]
|
|
176
|
+
puts " #{line}" unless options[:color]
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
rescue => e
|
|
180
|
+
errors += 1
|
|
181
|
+
$stderr.puts " ERROR: #{test_file}: #{e.message}"
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Summary
|
|
187
|
+
puts ""
|
|
188
|
+
total = passed + failed
|
|
189
|
+
summary = "#{total} assertions, #{passed} passed, #{failed} failed"
|
|
190
|
+
summary += ", #{errors} errors" if errors > 0
|
|
191
|
+
|
|
192
|
+
if failed > 0 || errors > 0
|
|
193
|
+
puts options[:color] ? "\e[31m#{summary}\e[0m" : summary
|
|
194
|
+
exit 1
|
|
195
|
+
else
|
|
196
|
+
puts options[:color] ? "\e[32m#{summary}\e[0m" : summary
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def find_java
|
|
201
|
+
java_home = config.jvm_java_home
|
|
202
|
+
java_home = ENV["JAVA_HOME"] || Platform.default_java_home if java_home.empty?
|
|
203
|
+
java_path = File.join(java_home, "bin", "java")
|
|
204
|
+
return java_path if File.exist?(java_path)
|
|
205
|
+
|
|
206
|
+
java_in_path = Platform.find_executable("java")
|
|
207
|
+
return java_in_path if java_in_path
|
|
208
|
+
|
|
209
|
+
error("Java not found. Install Java 21+: #{Platform.java_install_hint}")
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def run_tests(test_files)
|
|
213
|
+
puts_verbose "Running #{test_files.size} test file(s)..."
|
|
214
|
+
|
|
215
|
+
# Build minitest command
|
|
216
|
+
cmd = ["ruby"]
|
|
217
|
+
|
|
218
|
+
# Add load paths
|
|
219
|
+
cmd << "-I" << "lib"
|
|
220
|
+
cmd << "-I" << "test"
|
|
221
|
+
cmd << "-I" << "src" if Dir.exist?("src")
|
|
222
|
+
|
|
223
|
+
# Require minitest
|
|
224
|
+
cmd << "-rminitest/autorun"
|
|
225
|
+
|
|
226
|
+
# Add name filter if specified
|
|
227
|
+
if options[:name_pattern]
|
|
228
|
+
cmd << "-e" << "Minitest.run_with_autorun([])"
|
|
229
|
+
cmd << "--" << "--name" << "/#{options[:name_pattern]}/"
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Add test files
|
|
233
|
+
test_files.each { |f| cmd << "-r" << "./#{f}" }
|
|
234
|
+
|
|
235
|
+
# Add final execution trigger if no name pattern
|
|
236
|
+
unless options[:name_pattern]
|
|
237
|
+
cmd << "-e" << ""
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
puts_verbose "Running: #{cmd.join(' ')}"
|
|
241
|
+
|
|
242
|
+
# Execute tests
|
|
243
|
+
success = system(*cmd)
|
|
244
|
+
exit(success ? 0 : 1)
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Konpeito
|
|
4
|
+
module Commands
|
|
5
|
+
# Watch command - watch for file changes and recompile
|
|
6
|
+
class WatchCommand < BaseCommand
|
|
7
|
+
def self.command_name
|
|
8
|
+
"watch"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.description
|
|
12
|
+
"Watch for file changes and recompile automatically"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def run
|
|
16
|
+
parse_options!
|
|
17
|
+
|
|
18
|
+
unless listen_available?
|
|
19
|
+
error("The 'listen' gem is required for watch mode. Install it with 'gem install listen'.")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
require "listen"
|
|
23
|
+
|
|
24
|
+
@source_file = args.first
|
|
25
|
+
if @source_file && !File.exist?(@source_file)
|
|
26
|
+
error("File not found: #{@source_file}")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
start_watching
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
protected
|
|
33
|
+
|
|
34
|
+
def default_options
|
|
35
|
+
{
|
|
36
|
+
verbose: false,
|
|
37
|
+
color: $stderr.tty?,
|
|
38
|
+
output: config.build_output,
|
|
39
|
+
format: config.build_format,
|
|
40
|
+
paths: config.watch_paths,
|
|
41
|
+
extensions: config.watch_extensions,
|
|
42
|
+
clear: true
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def setup_option_parser(opts)
|
|
47
|
+
opts.on("-o", "--output FILE", "Output file name") do |file|
|
|
48
|
+
options[:output] = file
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
opts.on("-w", "--watch PATH", "Additional paths to watch (can be used multiple times)") do |path|
|
|
52
|
+
options[:paths] << path
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
opts.on("--no-clear", "Do not clear screen before each rebuild") do
|
|
56
|
+
options[:clear] = false
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
super
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def banner
|
|
63
|
+
<<~BANNER.chomp
|
|
64
|
+
Usage: konpeito watch [options] [source.rb]
|
|
65
|
+
|
|
66
|
+
Examples:
|
|
67
|
+
konpeito watch src/main.rb Watch and recompile
|
|
68
|
+
konpeito watch -w lib src/main.rb Watch additional paths
|
|
69
|
+
BANNER
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
def listen_available?
|
|
75
|
+
require "listen"
|
|
76
|
+
true
|
|
77
|
+
rescue LoadError
|
|
78
|
+
false
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def start_watching
|
|
82
|
+
watch_paths = options[:paths].select { |p| Dir.exist?(p) }
|
|
83
|
+
|
|
84
|
+
if watch_paths.empty?
|
|
85
|
+
watch_paths = ["."]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
timestamp = Time.now.strftime("%H:%M:%S")
|
|
89
|
+
emit("Watching", "#{watch_paths.join(', ')} [#{options[:extensions].join(', ')}]")
|
|
90
|
+
$stderr.puts ""
|
|
91
|
+
|
|
92
|
+
# Initial build
|
|
93
|
+
if @source_file
|
|
94
|
+
rebuild
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Start watching
|
|
98
|
+
extensions_pattern = /\.(#{options[:extensions].join('|')})$/
|
|
99
|
+
|
|
100
|
+
listener = Listen.to(*watch_paths) do |modified, added, removed|
|
|
101
|
+
changed_files = (modified + added + removed).select { |f| f.match?(extensions_pattern) }
|
|
102
|
+
|
|
103
|
+
unless changed_files.empty?
|
|
104
|
+
$stderr.puts ""
|
|
105
|
+
changed_files.each do |f|
|
|
106
|
+
emit("Changed", File.basename(f))
|
|
107
|
+
end
|
|
108
|
+
rebuild
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
listener.start
|
|
113
|
+
|
|
114
|
+
# Keep running
|
|
115
|
+
begin
|
|
116
|
+
sleep
|
|
117
|
+
rescue Interrupt
|
|
118
|
+
$stderr.puts ""
|
|
119
|
+
emit("Stopped", "watch mode")
|
|
120
|
+
listener.stop
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def rebuild
|
|
125
|
+
clear_screen if options[:clear]
|
|
126
|
+
|
|
127
|
+
if @source_file
|
|
128
|
+
compile_single(@source_file)
|
|
129
|
+
else
|
|
130
|
+
compile_all
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def compile_single(source_file)
|
|
135
|
+
output_file = options[:output] || default_output_name(source_file, format: options[:format])
|
|
136
|
+
|
|
137
|
+
emit("Compiling", "#{source_file} (native)")
|
|
138
|
+
|
|
139
|
+
compiler = Compiler.new(
|
|
140
|
+
source_file: source_file,
|
|
141
|
+
output_file: output_file,
|
|
142
|
+
format: options[:format],
|
|
143
|
+
verbose: options[:verbose],
|
|
144
|
+
rbs_paths: config.rbs_paths,
|
|
145
|
+
require_paths: config.require_paths,
|
|
146
|
+
incremental: true
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
compiler.compile
|
|
150
|
+
display_diagnostics(compiler.diagnostics)
|
|
151
|
+
|
|
152
|
+
if compiler.diagnostics.any?(&:error?)
|
|
153
|
+
error_count = compiler.diagnostics.count(&:error?)
|
|
154
|
+
emit_error("Failed", "with #{error_count} error(s)")
|
|
155
|
+
else
|
|
156
|
+
stats = compiler.compile_stats
|
|
157
|
+
if stats
|
|
158
|
+
duration_str = "%.2fs" % stats.duration_s
|
|
159
|
+
emit("Finished", "in #{duration_str} -> #{output_file}")
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
rescue Konpeito::Error => e
|
|
163
|
+
$stderr.puts "Error: #{e.message}"
|
|
164
|
+
emit_error("Failed", "build error")
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def compile_all
|
|
168
|
+
src_files = Dir.glob("src/**/*.rb")
|
|
169
|
+
|
|
170
|
+
if src_files.empty?
|
|
171
|
+
puts "No source files found in src/"
|
|
172
|
+
return
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
success_count = 0
|
|
176
|
+
error_count = 0
|
|
177
|
+
|
|
178
|
+
src_files.each do |source_file|
|
|
179
|
+
begin
|
|
180
|
+
output_file = default_output_name(source_file, format: options[:format])
|
|
181
|
+
compiler = Compiler.new(
|
|
182
|
+
source_file: source_file,
|
|
183
|
+
output_file: output_file,
|
|
184
|
+
format: options[:format],
|
|
185
|
+
verbose: options[:verbose],
|
|
186
|
+
rbs_paths: config.rbs_paths,
|
|
187
|
+
require_paths: config.require_paths,
|
|
188
|
+
incremental: true
|
|
189
|
+
)
|
|
190
|
+
compiler.compile
|
|
191
|
+
|
|
192
|
+
if compiler.diagnostics.any?(&:error?)
|
|
193
|
+
display_diagnostics(compiler.diagnostics)
|
|
194
|
+
error_count += 1
|
|
195
|
+
else
|
|
196
|
+
success_count += 1
|
|
197
|
+
end
|
|
198
|
+
rescue Konpeito::Error => e
|
|
199
|
+
$stderr.puts "Error compiling #{source_file}: #{e.message}"
|
|
200
|
+
error_count += 1
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
puts "Build complete: #{success_count} succeeded, #{error_count} failed"
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def clear_screen
|
|
208
|
+
print "\e[2J\e[H"
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|