taski 0.3.1 → 0.4.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 +4 -4
- data/.gem_rbs_collection/ast/2.4/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/ast/2.4/ast.rbs +73 -0
- data/.gem_rbs_collection/minitest/5.25/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/abstract_reporter.rbs +52 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/assertion.rbs +17 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/assertions.rbs +590 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/backtrace_filter.rbs +23 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/bench_spec.rbs +102 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/benchmark.rbs +259 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/composite_reporter.rbs +25 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/compress.rbs +13 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/error_on_warning.rbs +3 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/expectation.rbs +2 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/expectations.rbs +21 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/guard.rbs +64 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/mock.rbs +64 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/parallel/executor.rbs +46 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/parallel/test/class_methods.rbs +5 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/parallel/test.rbs +3 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/parallel.rbs +2 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/pride_io.rbs +62 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/pride_lol.rbs +19 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/progress_reporter.rbs +11 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/reportable.rbs +53 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/reporter.rbs +5 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/result.rbs +28 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/runnable.rbs +163 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/skip.rbs +6 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/spec/dsl/instance_methods.rbs +48 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/spec/dsl.rbs +129 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/spec.rbs +11 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/statistics_reporter.rbs +81 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/summary_reporter.rbs +18 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/test/lifecycle_hooks.rbs +92 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/test.rbs +69 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/unexpected_error.rbs +12 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/unexpected_warning.rbs +6 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/unit/test_case.rbs +3 -0
- data/.gem_rbs_collection/minitest/5.25/minitest/unit.rbs +4 -0
- data/.gem_rbs_collection/minitest/5.25/minitest.rbs +115 -0
- data/.gem_rbs_collection/parallel/1.20/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/parallel/1.20/parallel.rbs +86 -0
- data/.gem_rbs_collection/parser/3.2/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/parser/3.2/manifest.yaml +7 -0
- data/.gem_rbs_collection/parser/3.2/parser.rbs +193 -0
- data/.gem_rbs_collection/parser/3.2/polyfill.rbs +4 -0
- data/.gem_rbs_collection/rainbow/3.0/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/rainbow/3.0/global.rbs +7 -0
- data/.gem_rbs_collection/rainbow/3.0/presenter.rbs +209 -0
- data/.gem_rbs_collection/rainbow/3.0/rainbow.rbs +5 -0
- data/.gem_rbs_collection/rake/13.0/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/rake/13.0/manifest.yaml +2 -0
- data/.gem_rbs_collection/rake/13.0/rake.rbs +39 -0
- data/.gem_rbs_collection/regexp_parser/2.8/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/regexp_parser/2.8/regexp_parser.rbs +17 -0
- data/.gem_rbs_collection/rubocop/1.57/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/rubocop/1.57/rubocop.rbs +129 -0
- data/.gem_rbs_collection/rubocop-ast/1.30/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/rubocop-ast/1.30/rubocop-ast.rbs +771 -0
- data/.gem_rbs_collection/simplecov/0.22/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/simplecov/0.22/simplecov.rbs +54 -0
- data/README.md +138 -247
- data/Steepfile +19 -0
- data/docs/advanced-features.md +625 -0
- data/docs/api-guide.md +509 -0
- data/docs/error-handling.md +684 -0
- data/examples/README.md +95 -42
- data/examples/context_demo.rb +112 -0
- data/examples/data_pipeline_demo.rb +231 -0
- data/examples/parallel_progress_demo.rb +72 -0
- data/examples/quick_start.rb +4 -4
- data/examples/reexecution_demo.rb +127 -0
- data/examples/{section_configuration.rb → section_demo.rb} +49 -60
- data/lib/taski/context.rb +52 -0
- data/lib/taski/execution/coordinator.rb +63 -0
- data/lib/taski/execution/parallel_progress_display.rb +201 -0
- data/lib/taski/execution/registry.rb +72 -0
- data/lib/taski/execution/task_wrapper.rb +255 -0
- data/lib/taski/section.rb +26 -254
- data/lib/taski/static_analysis/analyzer.rb +34 -0
- data/lib/taski/static_analysis/dependency_graph.rb +90 -0
- data/lib/taski/static_analysis/visitor.rb +114 -0
- data/lib/taski/task.rb +173 -0
- data/lib/taski/version.rb +1 -1
- data/lib/taski.rb +45 -39
- data/rbs_collection.lock.yaml +116 -0
- data/rbs_collection.yaml +19 -0
- data/sig/taski.rbs +269 -62
- metadata +97 -32
- data/examples/advanced_patterns.rb +0 -119
- data/examples/progress_demo.rb +0 -166
- data/examples/tree_demo.rb +0 -205
- data/lib/taski/dependency_analyzer.rb +0 -232
- data/lib/taski/exceptions.rb +0 -17
- data/lib/taski/logger.rb +0 -158
- data/lib/taski/logging/formatter_factory.rb +0 -34
- data/lib/taski/logging/formatter_interface.rb +0 -19
- data/lib/taski/logging/json_formatter.rb +0 -26
- data/lib/taski/logging/simple_formatter.rb +0 -16
- data/lib/taski/logging/structured_formatter.rb +0 -44
- data/lib/taski/progress/display_colors.rb +0 -17
- data/lib/taski/progress/display_manager.rb +0 -117
- data/lib/taski/progress/output_capture.rb +0 -105
- data/lib/taski/progress/spinner_animation.rb +0 -49
- data/lib/taski/progress/task_formatter.rb +0 -25
- data/lib/taski/progress/task_status.rb +0 -38
- data/lib/taski/progress/terminal_controller.rb +0 -35
- data/lib/taski/progress_display.rb +0 -57
- data/lib/taski/reference.rb +0 -40
- data/lib/taski/task/base.rb +0 -91
- data/lib/taski/task/define_api.rb +0 -156
- data/lib/taski/task/dependency_resolver.rb +0 -73
- data/lib/taski/task/exports_api.rb +0 -29
- data/lib/taski/task/instance_management.rb +0 -201
- data/lib/taski/tree_colors.rb +0 -91
- data/lib/taski/utils/dependency_resolver_helper.rb +0 -85
- data/lib/taski/utils/tree_display_helper.rb +0 -68
- data/lib/taski/utils.rb +0 -107
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "tsort"
|
|
4
|
+
|
|
5
|
+
module Taski
|
|
6
|
+
module StaticAnalysis
|
|
7
|
+
# Builds a complete dependency graph from a root task class
|
|
8
|
+
# and provides topological sorting with cycle detection.
|
|
9
|
+
class DependencyGraph
|
|
10
|
+
include TSort
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
@graph = {}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Build dependency graph starting from root task class
|
|
17
|
+
# @param root_task_class [Class] The root task class to analyze
|
|
18
|
+
# @return [DependencyGraph] self for method chaining
|
|
19
|
+
def build_from(root_task_class)
|
|
20
|
+
collect_dependencies(root_task_class)
|
|
21
|
+
self
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Get topologically sorted task classes (dependencies first)
|
|
25
|
+
# @return [Array<Class>] Sorted task classes
|
|
26
|
+
# @raise [TSort::Cyclic] If circular dependency is detected
|
|
27
|
+
def sorted
|
|
28
|
+
tsort
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Check if the graph contains circular dependencies
|
|
32
|
+
# @return [Boolean] true if circular dependencies exist
|
|
33
|
+
def cyclic?
|
|
34
|
+
tsort
|
|
35
|
+
false
|
|
36
|
+
rescue TSort::Cyclic
|
|
37
|
+
true
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Get strongly connected components (useful for debugging cycles)
|
|
41
|
+
# @return [Array<Array<Class>>] Groups of mutually dependent classes
|
|
42
|
+
def strongly_connected_components
|
|
43
|
+
each_strongly_connected_component.to_a
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Get task classes involved in cycles
|
|
47
|
+
# @return [Array<Array<Class>>] Only components with size > 1 (cycles)
|
|
48
|
+
def cyclic_components
|
|
49
|
+
strongly_connected_components.select { |component| component.size > 1 }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Get all task classes in the graph
|
|
53
|
+
# @return [Array<Class>] All registered task classes
|
|
54
|
+
def all_tasks
|
|
55
|
+
@graph.keys
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Get direct dependencies for a task class
|
|
59
|
+
# @param task_class [Class] The task class
|
|
60
|
+
# @return [Set<Class>] Direct dependencies
|
|
61
|
+
def dependencies_for(task_class)
|
|
62
|
+
@graph.fetch(task_class, Set.new)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# TSort interface: iterate over all nodes
|
|
66
|
+
def tsort_each_node(&block)
|
|
67
|
+
@graph.each_key(&block)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# TSort interface: iterate over children (dependencies) of a node
|
|
71
|
+
def tsort_each_child(node, &block)
|
|
72
|
+
@graph.fetch(node, Set.new).each(&block)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
# Recursively collect all dependencies starting from a task class
|
|
78
|
+
def collect_dependencies(task_class)
|
|
79
|
+
return if @graph.key?(task_class)
|
|
80
|
+
|
|
81
|
+
dependencies = Analyzer.analyze(task_class)
|
|
82
|
+
@graph[task_class] = dependencies
|
|
83
|
+
|
|
84
|
+
dependencies.each do |dep_class|
|
|
85
|
+
collect_dependencies(dep_class)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "prism"
|
|
4
|
+
|
|
5
|
+
module Taski
|
|
6
|
+
module StaticAnalysis
|
|
7
|
+
class Visitor < Prism::Visitor
|
|
8
|
+
attr_reader :dependencies
|
|
9
|
+
|
|
10
|
+
def initialize(target_task_class)
|
|
11
|
+
super()
|
|
12
|
+
@target_task_class = target_task_class
|
|
13
|
+
@dependencies = Set.new
|
|
14
|
+
@in_target_run_method = false
|
|
15
|
+
@current_namespace_path = []
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def visit_class_node(node)
|
|
19
|
+
within_namespace(extract_constant_name(node.constant_path)) { super }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def visit_module_node(node)
|
|
23
|
+
within_namespace(extract_constant_name(node.constant_path)) { super }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def visit_def_node(node)
|
|
27
|
+
if node.name == :run && in_target_class?
|
|
28
|
+
@in_target_run_method = true
|
|
29
|
+
super
|
|
30
|
+
@in_target_run_method = false
|
|
31
|
+
else
|
|
32
|
+
super
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def visit_call_node(node)
|
|
37
|
+
detect_task_dependency(node) if @in_target_run_method
|
|
38
|
+
super
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def within_namespace(name)
|
|
44
|
+
@current_namespace_path.push(name)
|
|
45
|
+
yield
|
|
46
|
+
ensure
|
|
47
|
+
@current_namespace_path.pop
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def in_target_class?
|
|
51
|
+
@current_namespace_path.join("::") == @target_task_class.name
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def extract_constant_name(node)
|
|
55
|
+
node.slice
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def detect_task_dependency(node)
|
|
59
|
+
return unless node.receiver
|
|
60
|
+
|
|
61
|
+
constant_name = extract_receiver_constant(node.receiver)
|
|
62
|
+
resolve_and_add_dependency(constant_name) if constant_name
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def extract_receiver_constant(receiver)
|
|
66
|
+
case receiver
|
|
67
|
+
when Prism::ConstantReadNode, Prism::ConstantPathNode
|
|
68
|
+
receiver.slice
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def resolve_and_add_dependency(constant_name)
|
|
73
|
+
task_class = resolve_constant(constant_name)
|
|
74
|
+
@dependencies.add(task_class) if task_class && valid_dependency?(task_class)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def resolve_constant(constant_name)
|
|
78
|
+
Object.const_get(constant_name)
|
|
79
|
+
rescue NameError
|
|
80
|
+
resolve_with_namespace_prefix(constant_name)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def resolve_with_namespace_prefix(constant_name)
|
|
84
|
+
return nil if @current_namespace_path.empty?
|
|
85
|
+
|
|
86
|
+
@current_namespace_path.length.downto(0) do |i|
|
|
87
|
+
prefix = @current_namespace_path.take(i).join("::")
|
|
88
|
+
full_name = prefix.empty? ? constant_name : "#{prefix}::#{constant_name}"
|
|
89
|
+
|
|
90
|
+
begin
|
|
91
|
+
return Object.const_get(full_name)
|
|
92
|
+
rescue NameError
|
|
93
|
+
next
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
nil
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def valid_dependency?(klass)
|
|
101
|
+
klass.is_a?(Class) &&
|
|
102
|
+
(is_parallel_task?(klass) || is_parallel_section?(klass))
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def is_parallel_task?(klass)
|
|
106
|
+
defined?(Taski::Task) && klass < Taski::Task
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def is_parallel_section?(klass)
|
|
110
|
+
defined?(Taski::Section) && klass < Taski::Section
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
data/lib/taski/task.rb
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "static_analysis/analyzer"
|
|
4
|
+
require_relative "execution/registry"
|
|
5
|
+
require_relative "execution/coordinator"
|
|
6
|
+
require_relative "execution/task_wrapper"
|
|
7
|
+
|
|
8
|
+
module Taski
|
|
9
|
+
class Task
|
|
10
|
+
class << self
|
|
11
|
+
def exports(*export_methods)
|
|
12
|
+
@exported_methods = export_methods
|
|
13
|
+
|
|
14
|
+
export_methods.each do |method|
|
|
15
|
+
define_instance_reader(method)
|
|
16
|
+
define_class_accessor(method)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def exported_methods
|
|
21
|
+
@exported_methods ||= []
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Each call creates a fresh TaskWrapper instance for re-execution support.
|
|
25
|
+
# Use class methods (e.g., MyTask.result) for cached single execution.
|
|
26
|
+
def new
|
|
27
|
+
Execution::TaskWrapper.new(
|
|
28
|
+
super,
|
|
29
|
+
registry: registry,
|
|
30
|
+
coordinator: coordinator
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def cached_dependencies
|
|
35
|
+
@dependencies_cache ||= StaticAnalysis::Analyzer.analyze(self)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def clear_dependency_cache
|
|
39
|
+
@dependencies_cache = nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def run
|
|
43
|
+
Taski::Context.set_root_task(self)
|
|
44
|
+
validate_no_circular_dependencies!
|
|
45
|
+
cached_wrapper.run
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def clean
|
|
49
|
+
Taski::Context.set_root_task(self)
|
|
50
|
+
validate_no_circular_dependencies!
|
|
51
|
+
cached_wrapper.clean
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def registry
|
|
55
|
+
Taski.global_registry
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def coordinator
|
|
59
|
+
@coordinator ||= Execution::Coordinator.new(
|
|
60
|
+
registry: registry,
|
|
61
|
+
analyzer: StaticAnalysis::Analyzer
|
|
62
|
+
)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def reset!
|
|
66
|
+
registry.reset!
|
|
67
|
+
Taski.reset_global_registry!
|
|
68
|
+
Taski::Context.reset!
|
|
69
|
+
@coordinator = nil
|
|
70
|
+
@circular_dependency_checked = false
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def tree
|
|
74
|
+
build_tree(self, "", Set.new)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
def build_tree(task_class, prefix, visited)
|
|
80
|
+
result = "#{task_class.name}\n"
|
|
81
|
+
return result if visited.include?(task_class)
|
|
82
|
+
|
|
83
|
+
visited.add(task_class)
|
|
84
|
+
dependencies = task_class.cached_dependencies.to_a
|
|
85
|
+
|
|
86
|
+
dependencies.each_with_index do |dep, index|
|
|
87
|
+
is_last = (index == dependencies.size - 1)
|
|
88
|
+
result += format_dependency_branch(dep, prefix, is_last, visited)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
result
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def format_dependency_branch(dep, prefix, is_last, visited)
|
|
95
|
+
connector, extension = tree_connector_chars(is_last)
|
|
96
|
+
dep_tree = build_tree(dep, "#{prefix}#{extension}", visited)
|
|
97
|
+
|
|
98
|
+
result = "#{prefix}#{connector}"
|
|
99
|
+
lines = dep_tree.lines
|
|
100
|
+
result += lines.first
|
|
101
|
+
lines.drop(1).each { |line| result += line }
|
|
102
|
+
result
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def tree_connector_chars(is_last)
|
|
106
|
+
if is_last
|
|
107
|
+
["└── ", " "]
|
|
108
|
+
else
|
|
109
|
+
["├── ", "│ "]
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Use allocate + initialize instead of new to avoid infinite loop
|
|
114
|
+
# since new is overridden to return TaskWrapper
|
|
115
|
+
def cached_wrapper
|
|
116
|
+
registry.get_or_create(self) do
|
|
117
|
+
task_instance = allocate
|
|
118
|
+
task_instance.send(:initialize)
|
|
119
|
+
Execution::TaskWrapper.new(
|
|
120
|
+
task_instance,
|
|
121
|
+
registry: registry,
|
|
122
|
+
coordinator: coordinator
|
|
123
|
+
)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def define_instance_reader(method)
|
|
128
|
+
undef_method(method) if method_defined?(method)
|
|
129
|
+
|
|
130
|
+
define_method(method) do
|
|
131
|
+
# @type self: Task
|
|
132
|
+
instance_variable_get("@#{method}")
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def define_class_accessor(method)
|
|
137
|
+
singleton_class.undef_method(method) if singleton_class.method_defined?(method)
|
|
138
|
+
|
|
139
|
+
define_singleton_method(method) do
|
|
140
|
+
Taski::Context.set_root_task(self)
|
|
141
|
+
validate_no_circular_dependencies!
|
|
142
|
+
cached_wrapper.get_exported_value(method)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def validate_no_circular_dependencies!
|
|
147
|
+
return if @circular_dependency_checked
|
|
148
|
+
|
|
149
|
+
graph = StaticAnalysis::DependencyGraph.new.build_from(self)
|
|
150
|
+
cyclic_components = graph.cyclic_components
|
|
151
|
+
|
|
152
|
+
if cyclic_components.any?
|
|
153
|
+
raise Taski::CircularDependencyError.new(cyclic_components)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
@circular_dependency_checked = true
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def run
|
|
161
|
+
raise NotImplementedError, "Subclasses must implement the run method"
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def clean
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def reset!
|
|
168
|
+
self.class.exported_methods.each do |method|
|
|
169
|
+
instance_variable_set("@#{method}", nil)
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
data/lib/taski/version.rb
CHANGED
data/lib/taski.rb
CHANGED
|
@@ -1,46 +1,52 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "monitor"
|
|
4
|
-
|
|
5
|
-
# Load core components
|
|
6
3
|
require_relative "taski/version"
|
|
7
|
-
require_relative "taski/
|
|
8
|
-
require_relative "taski/
|
|
9
|
-
require_relative "taski/
|
|
10
|
-
require_relative "taski/
|
|
11
|
-
require_relative "taski/
|
|
12
|
-
require_relative "taski/
|
|
13
|
-
require_relative "taski/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
require_relative "taski/task/base"
|
|
17
|
-
require_relative "taski/task/exports_api"
|
|
18
|
-
require_relative "taski/task/define_api"
|
|
19
|
-
require_relative "taski/task/instance_management"
|
|
20
|
-
require_relative "taski/task/dependency_resolver"
|
|
21
|
-
|
|
22
|
-
# Load Section class
|
|
4
|
+
require_relative "taski/static_analysis/analyzer"
|
|
5
|
+
require_relative "taski/static_analysis/visitor"
|
|
6
|
+
require_relative "taski/static_analysis/dependency_graph"
|
|
7
|
+
require_relative "taski/execution/registry"
|
|
8
|
+
require_relative "taski/execution/coordinator"
|
|
9
|
+
require_relative "taski/execution/task_wrapper"
|
|
10
|
+
require_relative "taski/execution/parallel_progress_display"
|
|
11
|
+
require_relative "taski/context"
|
|
12
|
+
require_relative "taski/task"
|
|
23
13
|
require_relative "taski/section"
|
|
24
14
|
|
|
25
15
|
module Taski
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
#
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
16
|
+
class TaskAbortException < StandardError
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Raised when circular dependencies are detected between tasks
|
|
20
|
+
class CircularDependencyError < StandardError
|
|
21
|
+
attr_reader :cyclic_tasks
|
|
22
|
+
|
|
23
|
+
# @param cyclic_tasks [Array<Array<Class>>] Groups of mutually dependent task classes
|
|
24
|
+
def initialize(cyclic_tasks)
|
|
25
|
+
@cyclic_tasks = cyclic_tasks
|
|
26
|
+
task_names = cyclic_tasks.map { |group| group.map(&:name).join(" <-> ") }.join(", ")
|
|
27
|
+
super("Circular dependency detected: #{task_names}")
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.global_registry
|
|
32
|
+
@global_registry ||= Execution::Registry.new
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.reset_global_registry!
|
|
36
|
+
@global_registry = nil
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.progress_display
|
|
40
|
+
return nil unless progress_enabled?
|
|
41
|
+
@progress_display ||= Execution::ParallelProgressDisplay.new
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.progress_enabled?
|
|
45
|
+
ENV["TASKI_PROGRESS"] == "1" || ENV["TASKI_FORCE_PROGRESS"] == "1"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.reset_progress_display!
|
|
49
|
+
@progress_display&.stop
|
|
50
|
+
@progress_display = nil
|
|
51
|
+
end
|
|
46
52
|
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
path: ".gem_rbs_collection"
|
|
3
|
+
gems:
|
|
4
|
+
- name: ast
|
|
5
|
+
version: '2.4'
|
|
6
|
+
source:
|
|
7
|
+
type: git
|
|
8
|
+
name: ruby/gem_rbs_collection
|
|
9
|
+
revision: 3a33fa6f8e486f880c80ca401f2be1c1f621cf11
|
|
10
|
+
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
11
|
+
repo_dir: gems
|
|
12
|
+
- name: fileutils
|
|
13
|
+
version: '0'
|
|
14
|
+
source:
|
|
15
|
+
type: stdlib
|
|
16
|
+
- name: io-console
|
|
17
|
+
version: '0'
|
|
18
|
+
source:
|
|
19
|
+
type: stdlib
|
|
20
|
+
- name: json
|
|
21
|
+
version: '0'
|
|
22
|
+
source:
|
|
23
|
+
type: stdlib
|
|
24
|
+
- name: minitest
|
|
25
|
+
version: '5.25'
|
|
26
|
+
source:
|
|
27
|
+
type: git
|
|
28
|
+
name: ruby/gem_rbs_collection
|
|
29
|
+
revision: 3a33fa6f8e486f880c80ca401f2be1c1f621cf11
|
|
30
|
+
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
31
|
+
repo_dir: gems
|
|
32
|
+
- name: parallel
|
|
33
|
+
version: '1.20'
|
|
34
|
+
source:
|
|
35
|
+
type: git
|
|
36
|
+
name: ruby/gem_rbs_collection
|
|
37
|
+
revision: 3a33fa6f8e486f880c80ca401f2be1c1f621cf11
|
|
38
|
+
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
39
|
+
repo_dir: gems
|
|
40
|
+
- name: parser
|
|
41
|
+
version: '3.2'
|
|
42
|
+
source:
|
|
43
|
+
type: git
|
|
44
|
+
name: ruby/gem_rbs_collection
|
|
45
|
+
revision: 3a33fa6f8e486f880c80ca401f2be1c1f621cf11
|
|
46
|
+
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
47
|
+
repo_dir: gems
|
|
48
|
+
- name: pp
|
|
49
|
+
version: '0'
|
|
50
|
+
source:
|
|
51
|
+
type: stdlib
|
|
52
|
+
- name: prettyprint
|
|
53
|
+
version: '0'
|
|
54
|
+
source:
|
|
55
|
+
type: stdlib
|
|
56
|
+
- name: prism
|
|
57
|
+
version: 1.6.0
|
|
58
|
+
source:
|
|
59
|
+
type: rubygems
|
|
60
|
+
- name: rainbow
|
|
61
|
+
version: '3.0'
|
|
62
|
+
source:
|
|
63
|
+
type: git
|
|
64
|
+
name: ruby/gem_rbs_collection
|
|
65
|
+
revision: 3a33fa6f8e486f880c80ca401f2be1c1f621cf11
|
|
66
|
+
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
67
|
+
repo_dir: gems
|
|
68
|
+
- name: rake
|
|
69
|
+
version: '13.0'
|
|
70
|
+
source:
|
|
71
|
+
type: git
|
|
72
|
+
name: ruby/gem_rbs_collection
|
|
73
|
+
revision: 3a33fa6f8e486f880c80ca401f2be1c1f621cf11
|
|
74
|
+
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
75
|
+
repo_dir: gems
|
|
76
|
+
- name: rdoc
|
|
77
|
+
version: '0'
|
|
78
|
+
source:
|
|
79
|
+
type: stdlib
|
|
80
|
+
- name: regexp_parser
|
|
81
|
+
version: '2.8'
|
|
82
|
+
source:
|
|
83
|
+
type: git
|
|
84
|
+
name: ruby/gem_rbs_collection
|
|
85
|
+
revision: 3a33fa6f8e486f880c80ca401f2be1c1f621cf11
|
|
86
|
+
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
87
|
+
repo_dir: gems
|
|
88
|
+
- name: rubocop
|
|
89
|
+
version: '1.57'
|
|
90
|
+
source:
|
|
91
|
+
type: git
|
|
92
|
+
name: ruby/gem_rbs_collection
|
|
93
|
+
revision: 3a33fa6f8e486f880c80ca401f2be1c1f621cf11
|
|
94
|
+
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
95
|
+
repo_dir: gems
|
|
96
|
+
- name: rubocop-ast
|
|
97
|
+
version: '1.30'
|
|
98
|
+
source:
|
|
99
|
+
type: git
|
|
100
|
+
name: ruby/gem_rbs_collection
|
|
101
|
+
revision: 3a33fa6f8e486f880c80ca401f2be1c1f621cf11
|
|
102
|
+
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
103
|
+
repo_dir: gems
|
|
104
|
+
- name: simplecov
|
|
105
|
+
version: '0.22'
|
|
106
|
+
source:
|
|
107
|
+
type: git
|
|
108
|
+
name: ruby/gem_rbs_collection
|
|
109
|
+
revision: 3a33fa6f8e486f880c80ca401f2be1c1f621cf11
|
|
110
|
+
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
111
|
+
repo_dir: gems
|
|
112
|
+
- name: tsort
|
|
113
|
+
version: '0'
|
|
114
|
+
source:
|
|
115
|
+
type: stdlib
|
|
116
|
+
gemfile_lock_path: Gemfile.lock
|
data/rbs_collection.yaml
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Download sources
|
|
2
|
+
sources:
|
|
3
|
+
- type: git
|
|
4
|
+
name: ruby/gem_rbs_collection
|
|
5
|
+
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
6
|
+
revision: main
|
|
7
|
+
repo_dir: gems
|
|
8
|
+
|
|
9
|
+
# You can specify local directories as sources also.
|
|
10
|
+
# - type: local
|
|
11
|
+
# path: path/to/your/local/repository
|
|
12
|
+
|
|
13
|
+
# A directory to install the downloaded RBSs
|
|
14
|
+
path: .gem_rbs_collection
|
|
15
|
+
|
|
16
|
+
# gems:
|
|
17
|
+
# # If you want to avoid installing rbs files for gems, you can specify them here.
|
|
18
|
+
# - name: GEM_NAME
|
|
19
|
+
# ignore: true
|