taski 0.2.0 → 0.2.2
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/.standard.yml +9 -0
- data/README.md +112 -195
- data/Rakefile +7 -1
- data/examples/README.md +57 -0
- data/examples/{complex_example.rb → advanced_patterns.rb} +31 -21
- data/examples/progress_demo.rb +166 -0
- data/examples/{readme_example.rb → quick_start.rb} +15 -4
- data/examples/tree_demo.rb +80 -0
- data/lib/taski/dependency_analyzer.rb +18 -8
- data/lib/taski/exceptions.rb +4 -4
- data/lib/taski/logger.rb +213 -0
- data/lib/taski/progress_display.rb +356 -0
- data/lib/taski/reference.rb +3 -3
- data/lib/taski/task/base.rb +54 -3
- data/lib/taski/task/define_api.rb +36 -7
- data/lib/taski/task/dependency_resolver.rb +39 -11
- data/lib/taski/task/exports_api.rb +1 -1
- data/lib/taski/task/instance_management.rb +75 -20
- data/lib/taski/utils.rb +107 -0
- data/lib/taski/version.rb +1 -1
- data/lib/taski.rb +7 -5
- data/sig/taski.rbs +39 -2
- metadata +12 -6
- data/Steepfile +0 -20
@@ -0,0 +1,166 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Taski Progress Display Demo
|
5
|
+
#
|
6
|
+
# This comprehensive example demonstrates all progress display features:
|
7
|
+
# 1. Basic spinner animation with success/failure indicators
|
8
|
+
# 2. Output capture with 5-line tail display
|
9
|
+
# 3. Real-world build scenario with external command simulation
|
10
|
+
# 4. TTY detection for clean file output
|
11
|
+
#
|
12
|
+
# Run: ruby examples/progress_demo.rb
|
13
|
+
# Try: ruby examples/progress_demo.rb > build.log 2>&1 && cat build.log
|
14
|
+
|
15
|
+
require_relative "../lib/taski"
|
16
|
+
|
17
|
+
puts "🎯 Taski Progress Display Demo"
|
18
|
+
puts "=" * 50
|
19
|
+
|
20
|
+
# SECTION 1: Basic Spinner Animation
|
21
|
+
puts "\n📍 SECTION 1: Basic Spinner & Success/Failure Indicators"
|
22
|
+
puts "-" * 50
|
23
|
+
|
24
|
+
class ConfigTask < Taski::Task
|
25
|
+
exports :database_url, :cache_url
|
26
|
+
|
27
|
+
def build
|
28
|
+
sleep 0.8
|
29
|
+
@database_url = "postgres://localhost/myapp"
|
30
|
+
@cache_url = "redis://localhost:6379"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class DatabaseTask < Taski::Task
|
35
|
+
exports :connection
|
36
|
+
|
37
|
+
def build
|
38
|
+
sleep 1.2
|
39
|
+
@connection = "Connected to #{ConfigTask.database_url}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class ApplicationTask < Taski::Task
|
44
|
+
exports :status
|
45
|
+
|
46
|
+
def build
|
47
|
+
sleep 1.0
|
48
|
+
db = DatabaseTask.connection
|
49
|
+
@status = "App ready! #{db}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
ApplicationTask.build
|
54
|
+
puts "🎉 Application Status: #{ApplicationTask.status}"
|
55
|
+
|
56
|
+
# SECTION 2: Output Capture Demo
|
57
|
+
puts "\n📍 SECTION 2: Output Capture with 5-Line Tail"
|
58
|
+
puts "-" * 50
|
59
|
+
|
60
|
+
class VerboseTask < Taski::Task
|
61
|
+
exports :result
|
62
|
+
|
63
|
+
def build
|
64
|
+
puts "Starting task initialization..."
|
65
|
+
sleep 0.3
|
66
|
+
|
67
|
+
puts "Loading configuration files..."
|
68
|
+
puts "Connecting to database..."
|
69
|
+
puts "Connection established: localhost:5432"
|
70
|
+
sleep 0.3
|
71
|
+
|
72
|
+
puts "Running initial checks..."
|
73
|
+
puts "Checking schema version..."
|
74
|
+
puts "Schema is up to date"
|
75
|
+
puts "Performing data validation..."
|
76
|
+
puts "Validating user records..."
|
77
|
+
puts "Validating product records..."
|
78
|
+
puts "All validations passed"
|
79
|
+
sleep 0.4
|
80
|
+
|
81
|
+
puts "Task completed successfully!"
|
82
|
+
@result = "All operations completed"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
VerboseTask.build
|
87
|
+
puts "📊 Verbose Task Result: #{VerboseTask.result}"
|
88
|
+
|
89
|
+
# SECTION 3: Production Build Scenario
|
90
|
+
puts "\n📍 SECTION 3: Production Build Scenario"
|
91
|
+
puts "-" * 50
|
92
|
+
|
93
|
+
class CompileTask < Taski::Task
|
94
|
+
exports :result
|
95
|
+
|
96
|
+
def build
|
97
|
+
puts "Starting compilation process..."
|
98
|
+
sleep 0.8
|
99
|
+
|
100
|
+
puts "Checking source files..."
|
101
|
+
puts "Found: main.c, utils.c, config.h"
|
102
|
+
sleep 0.6
|
103
|
+
|
104
|
+
puts "Running gcc compilation..."
|
105
|
+
puts "gcc -Wall -O2 -c main.c"
|
106
|
+
puts "gcc -Wall -O2 -c utils.c"
|
107
|
+
puts "main.c: In function 'main':"
|
108
|
+
puts "main.c:42: warning: unused variable 'temp'"
|
109
|
+
puts "utils.c: In function 'parse_config':"
|
110
|
+
puts "utils.c:15: warning: implicit declaration of function 'strcpy'"
|
111
|
+
sleep 0.8
|
112
|
+
|
113
|
+
puts "Linking objects..."
|
114
|
+
puts "gcc -o myapp main.o utils.o"
|
115
|
+
puts "Compilation successful!"
|
116
|
+
|
117
|
+
@result = "myapp binary created"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class TestTask < Taski::Task
|
122
|
+
exports :test_result
|
123
|
+
|
124
|
+
def build
|
125
|
+
puts "Running test suite..."
|
126
|
+
sleep 0.2
|
127
|
+
|
128
|
+
(1..8).each do |i|
|
129
|
+
puts "Test #{i}/8: #{["PASS", "PASS", "FAIL", "PASS", "PASS", "PASS", "PASS", "PASS"][i - 1]}"
|
130
|
+
sleep 0.4
|
131
|
+
end
|
132
|
+
|
133
|
+
puts "Test summary: 7/8 passed, 1 failed"
|
134
|
+
@test_result = "Tests completed with 1 failure"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
CompileTask.build
|
139
|
+
puts "📦 Compilation: #{CompileTask.result}"
|
140
|
+
|
141
|
+
TestTask.build
|
142
|
+
puts "🧪 Test Result: #{TestTask.test_result}"
|
143
|
+
|
144
|
+
# SECTION 4: Error Handling Demo
|
145
|
+
puts "\n📍 SECTION 4: Error Handling Demo"
|
146
|
+
puts "-" * 50
|
147
|
+
|
148
|
+
class FailingTask < Taski::Task
|
149
|
+
def build
|
150
|
+
puts "Attempting network connection..."
|
151
|
+
sleep 1.0 # Watch it spin before failing
|
152
|
+
puts "Connection timeout after 30 seconds"
|
153
|
+
puts "Retrying connection..."
|
154
|
+
sleep 0.5
|
155
|
+
raise StandardError, "Network connection failed!"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
begin
|
160
|
+
FailingTask.build
|
161
|
+
rescue Taski::TaskBuildError => e
|
162
|
+
puts "🛡️ Error handled gracefully: #{e.message}"
|
163
|
+
end
|
164
|
+
|
165
|
+
puts "\n✨ Demo Complete!"
|
166
|
+
puts "Note: Rich spinner display only appears in terminals, not when output is redirected."
|
@@ -1,7 +1,19 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
#
|
2
|
+
# frozen_string_literal: true
|
3
3
|
|
4
|
-
|
4
|
+
# Taski Quick Start Guide
|
5
|
+
#
|
6
|
+
# This example demonstrates the fundamentals of Taski:
|
7
|
+
# - Task definition with the Exports API
|
8
|
+
# - Automatic dependency resolution
|
9
|
+
# - Simple task execution
|
10
|
+
#
|
11
|
+
# Run: ruby examples/quick_start.rb
|
12
|
+
|
13
|
+
require_relative "../lib/taski"
|
14
|
+
|
15
|
+
puts "🚀 Taski Quick Start"
|
16
|
+
puts "=" * 30
|
5
17
|
|
6
18
|
# Simple static dependency using Exports API
|
7
19
|
class DatabaseSetup < Taski::Task
|
@@ -24,7 +36,6 @@ class APIServer < Taski::Task
|
|
24
36
|
end
|
25
37
|
|
26
38
|
# Execute - dependencies are resolved automatically
|
27
|
-
puts "=== Quick Start Example ==="
|
28
39
|
APIServer.build
|
29
40
|
|
30
|
-
puts "\
|
41
|
+
puts "\n✅ Result: APIServer running on port #{APIServer.port}"
|
@@ -0,0 +1,80 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Tree Display Demo
|
5
|
+
#
|
6
|
+
# This example demonstrates the tree display functionality that shows
|
7
|
+
# task dependency relationships in a visual tree format.
|
8
|
+
#
|
9
|
+
# Run: ruby examples/tree_demo.rb
|
10
|
+
|
11
|
+
require_relative "../lib/taski"
|
12
|
+
|
13
|
+
puts "🌲 Taski Tree Display Demo"
|
14
|
+
puts "=" * 40
|
15
|
+
|
16
|
+
# Create a dependency chain for demonstration
|
17
|
+
class Database < Taski::Task
|
18
|
+
exports :connection_string
|
19
|
+
|
20
|
+
def build
|
21
|
+
@connection_string = "postgres://localhost/myapp"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Cache < Taski::Task
|
26
|
+
exports :redis_url
|
27
|
+
|
28
|
+
def build
|
29
|
+
@redis_url = "redis://localhost:6379"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class Config < Taski::Task
|
34
|
+
exports :settings
|
35
|
+
|
36
|
+
def build
|
37
|
+
@settings = {
|
38
|
+
database: Database.connection_string,
|
39
|
+
cache: Cache.redis_url,
|
40
|
+
port: 3000
|
41
|
+
}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Logger < Taski::Task
|
46
|
+
exports :log_level
|
47
|
+
|
48
|
+
def build
|
49
|
+
@log_level = "info"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class WebServer < Taski::Task
|
54
|
+
exports :server_instance
|
55
|
+
|
56
|
+
def build
|
57
|
+
@server_instance = "WebServer configured with #{Config.settings[:database]} and #{Logger.log_level}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class Application < Taski::Task
|
62
|
+
def build
|
63
|
+
puts "Starting application..."
|
64
|
+
puts "Web server: #{WebServer.server_instance}"
|
65
|
+
puts "Config: #{Config.settings}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
puts "\n📊 Application Dependency Tree:"
|
70
|
+
puts Application.tree
|
71
|
+
|
72
|
+
puts "\n🔍 Individual Component Trees:"
|
73
|
+
puts "\nWebServer dependencies:"
|
74
|
+
puts WebServer.tree
|
75
|
+
|
76
|
+
puts "\nConfig dependencies:"
|
77
|
+
puts Config.tree
|
78
|
+
|
79
|
+
puts "\n▶️ Building Application (to verify dependencies work):"
|
80
|
+
Application.build
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "prism"
|
4
4
|
|
5
5
|
module Taski
|
6
6
|
module DependencyAnalyzer
|
@@ -19,13 +19,19 @@ module Taski
|
|
19
19
|
result = Prism.parse_file(file_path)
|
20
20
|
|
21
21
|
unless result.success?
|
22
|
-
|
22
|
+
Taski.logger.error("Parse errors in source file",
|
23
|
+
file: file_path,
|
24
|
+
errors: result.errors.map(&:message),
|
25
|
+
method: "#{klass}##{method_name}")
|
23
26
|
return []
|
24
27
|
end
|
25
28
|
|
26
29
|
# Handle warnings if present
|
27
30
|
if result.warnings.any?
|
28
|
-
warn
|
31
|
+
Taski.logger.warn("Parse warnings in source file",
|
32
|
+
file: file_path,
|
33
|
+
warnings: result.warnings.map(&:message),
|
34
|
+
method: "#{klass}##{method_name}")
|
29
35
|
end
|
30
36
|
|
31
37
|
dependencies = []
|
@@ -39,10 +45,17 @@ module Taski
|
|
39
45
|
|
40
46
|
dependencies.uniq
|
41
47
|
rescue IOError, SystemCallError => e
|
42
|
-
|
48
|
+
Taski.logger.error("Failed to read source file",
|
49
|
+
file: file_path,
|
50
|
+
error: e.message,
|
51
|
+
method: "#{klass}##{method_name}")
|
43
52
|
[]
|
44
53
|
rescue => e
|
45
|
-
|
54
|
+
Taski.logger.error("Failed to analyze method dependencies",
|
55
|
+
class: klass.name,
|
56
|
+
method: method_name,
|
57
|
+
error: e.message,
|
58
|
+
error_class: e.class.name)
|
46
59
|
[]
|
47
60
|
end
|
48
61
|
end
|
@@ -151,12 +164,9 @@ module Taski
|
|
151
164
|
else
|
152
165
|
child_name
|
153
166
|
end
|
154
|
-
else
|
155
|
-
nil
|
156
167
|
end
|
157
168
|
end
|
158
169
|
end
|
159
|
-
|
160
170
|
end
|
161
171
|
end
|
162
172
|
end
|
data/lib/taski/exceptions.rb
CHANGED
@@ -2,13 +2,13 @@
|
|
2
2
|
|
3
3
|
module Taski
|
4
4
|
# Custom exceptions for Taski framework
|
5
|
-
|
5
|
+
|
6
6
|
# Raised when circular dependencies are detected between tasks
|
7
7
|
class CircularDependencyError < StandardError; end
|
8
|
-
|
8
|
+
|
9
9
|
# Raised when task analysis fails (e.g., constant resolution errors)
|
10
10
|
class TaskAnalysisError < StandardError; end
|
11
|
-
|
11
|
+
|
12
12
|
# Raised when task building fails during execution
|
13
13
|
class TaskBuildError < StandardError; end
|
14
|
-
end
|
14
|
+
end
|
data/lib/taski/logger.rb
ADDED
@@ -0,0 +1,213 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Taski
|
4
|
+
# Enhanced logging functionality for Taski framework
|
5
|
+
# Provides structured logging with multiple levels and context information
|
6
|
+
class Logger
|
7
|
+
# Log levels in order of severity
|
8
|
+
LEVELS = {debug: 0, info: 1, warn: 2, error: 3}.freeze
|
9
|
+
|
10
|
+
# @param level [Symbol] Minimum log level to output (:debug, :info, :warn, :error)
|
11
|
+
# @param output [IO] Output destination (default: $stdout)
|
12
|
+
# @param format [Symbol] Log format (:simple, :structured, :json)
|
13
|
+
def initialize(level: :info, output: $stdout, format: :structured)
|
14
|
+
@level = level
|
15
|
+
@output = output
|
16
|
+
@format = format
|
17
|
+
@start_time = Time.now
|
18
|
+
end
|
19
|
+
|
20
|
+
# Log debug message with optional context
|
21
|
+
# @param message [String] Log message
|
22
|
+
# @param context [Hash] Additional context information
|
23
|
+
def debug(message, **context)
|
24
|
+
log(:debug, message, context)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Log info message with optional context
|
28
|
+
# @param message [String] Log message
|
29
|
+
# @param context [Hash] Additional context information
|
30
|
+
def info(message, **context)
|
31
|
+
log(:info, message, context)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Log warning message with optional context
|
35
|
+
# @param message [String] Log message
|
36
|
+
# @param context [Hash] Additional context information
|
37
|
+
def warn(message, **context)
|
38
|
+
log(:warn, message, context)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Log error message with optional context
|
42
|
+
# @param message [String] Log message
|
43
|
+
# @param context [Hash] Additional context information
|
44
|
+
def error(message, **context)
|
45
|
+
log(:error, message, context)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Log task build start event
|
49
|
+
# @param task_name [String] Name of the task being built
|
50
|
+
# @param dependencies [Array] List of task dependencies
|
51
|
+
# @param args [Hash] Build arguments for parametrized builds
|
52
|
+
def task_build_start(task_name, dependencies: [], args: nil)
|
53
|
+
context = {
|
54
|
+
task: task_name,
|
55
|
+
dependencies: dependencies.size,
|
56
|
+
dependency_names: dependencies.map { |dep| dep.is_a?(Hash) ? dep[:klass].inspect : dep.inspect }
|
57
|
+
}
|
58
|
+
context[:args] = args if args && !args.empty?
|
59
|
+
|
60
|
+
info("Task build started", **context)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Log task build completion event
|
64
|
+
# @param task_name [String] Name of the task that was built
|
65
|
+
# @param duration [Float] Build duration in seconds
|
66
|
+
def task_build_complete(task_name, duration: nil)
|
67
|
+
context = {task: task_name}
|
68
|
+
context[:duration_ms] = (duration * 1000).round(2) if duration
|
69
|
+
info("Task build completed", **context)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Log task build failure event
|
73
|
+
# @param task_name [String] Name of the task that failed
|
74
|
+
# @param error [Exception] The error that occurred
|
75
|
+
# @param duration [Float] Duration before failure in seconds
|
76
|
+
def task_build_failed(task_name, error:, duration: nil)
|
77
|
+
context = {
|
78
|
+
task: task_name,
|
79
|
+
error_class: error.class.name,
|
80
|
+
error_message: error.message
|
81
|
+
}
|
82
|
+
context[:duration_ms] = (duration * 1000).round(2) if duration
|
83
|
+
context[:backtrace] = error.backtrace&.first(3) if error.backtrace
|
84
|
+
error("Task build failed", **context)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Log dependency resolution event
|
88
|
+
# @param task_name [String] Name of the task resolving dependencies
|
89
|
+
# @param resolved_count [Integer] Number of dependencies resolved
|
90
|
+
def dependency_resolved(task_name, resolved_count:)
|
91
|
+
debug("Dependencies resolved",
|
92
|
+
task: task_name,
|
93
|
+
resolved_dependencies: resolved_count)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Log circular dependency detection
|
97
|
+
# @param cycle_path [Array] The circular dependency path
|
98
|
+
def circular_dependency_detected(cycle_path)
|
99
|
+
error("Circular dependency detected",
|
100
|
+
cycle: cycle_path.map { |klass| klass.name || klass.inspect },
|
101
|
+
cycle_length: cycle_path.size)
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
# Core logging method
|
107
|
+
# @param level [Symbol] Log level
|
108
|
+
# @param message [String] Log message
|
109
|
+
# @param context [Hash] Additional context
|
110
|
+
def log(level, message, context)
|
111
|
+
return unless should_log?(level)
|
112
|
+
|
113
|
+
case @format
|
114
|
+
when :simple
|
115
|
+
log_simple(level, message, context)
|
116
|
+
when :structured
|
117
|
+
log_structured(level, message, context)
|
118
|
+
when :json
|
119
|
+
log_json(level, message, context)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Check if message should be logged based on current level
|
124
|
+
# @param level [Symbol] Message level to check
|
125
|
+
# @return [Boolean] True if message should be logged
|
126
|
+
def should_log?(level)
|
127
|
+
LEVELS[@level] <= LEVELS[level]
|
128
|
+
end
|
129
|
+
|
130
|
+
# Simple log format: [LEVEL] message
|
131
|
+
def log_simple(level, message, context)
|
132
|
+
@output.puts "[#{level.upcase}] #{message}"
|
133
|
+
end
|
134
|
+
|
135
|
+
# Structured log format with timestamp and context
|
136
|
+
def log_structured(level, message, context)
|
137
|
+
timestamp = Time.now.strftime("%Y-%m-%d %H:%M:%S.%3N")
|
138
|
+
elapsed = ((Time.now - @start_time) * 1000).round(1)
|
139
|
+
|
140
|
+
line = "[#{timestamp}] [#{elapsed}ms] #{level.to_s.upcase.ljust(5)} Taski: #{message}"
|
141
|
+
|
142
|
+
unless context.empty?
|
143
|
+
context_parts = context.map do |key, value|
|
144
|
+
"#{key}=#{format_value(value)}"
|
145
|
+
end
|
146
|
+
line += " (#{context_parts.join(", ")})"
|
147
|
+
end
|
148
|
+
|
149
|
+
@output.puts line
|
150
|
+
end
|
151
|
+
|
152
|
+
# JSON log format for structured logging systems
|
153
|
+
def log_json(level, message, context)
|
154
|
+
require "json"
|
155
|
+
|
156
|
+
log_entry = {
|
157
|
+
timestamp: Time.now.iso8601(3),
|
158
|
+
level: level.to_s,
|
159
|
+
logger: "taski",
|
160
|
+
message: message,
|
161
|
+
elapsed_ms: ((Time.now - @start_time) * 1000).round(1)
|
162
|
+
}.merge(context)
|
163
|
+
|
164
|
+
@output.puts JSON.generate(log_entry)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Format values for structured logging
|
168
|
+
def format_value(value)
|
169
|
+
case value
|
170
|
+
when String
|
171
|
+
(value.length > 50) ? "#{value[0..47]}..." : value
|
172
|
+
when Array
|
173
|
+
(value.size > 5) ? "[#{value[0..4].join(", ")}, ...]" : value.inspect
|
174
|
+
when Hash
|
175
|
+
(value.size > 3) ? "{#{value.keys[0..2].join(", ")}, ...}" : value.inspect
|
176
|
+
else
|
177
|
+
value.inspect
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
class << self
|
183
|
+
# Get the current logger instance
|
184
|
+
# @return [Logger] Current logger instance
|
185
|
+
def logger
|
186
|
+
@logger ||= Logger.new
|
187
|
+
end
|
188
|
+
|
189
|
+
# Get the current progress display instance (always enabled)
|
190
|
+
# @return [ProgressDisplay] Current progress display instance
|
191
|
+
def progress_display
|
192
|
+
@progress_display ||= ProgressDisplay.new(force_enable: ENV["TASKI_FORCE_PROGRESS"] == "1")
|
193
|
+
end
|
194
|
+
|
195
|
+
# Configure the logger with new settings
|
196
|
+
# @param level [Symbol] Log level (:debug, :info, :warn, :error)
|
197
|
+
# @param output [IO] Output destination
|
198
|
+
# @param format [Symbol] Log format (:simple, :structured, :json)
|
199
|
+
def configure_logger(level: :info, output: $stdout, format: :structured)
|
200
|
+
@logger = Logger.new(level: level, output: output, format: format)
|
201
|
+
end
|
202
|
+
|
203
|
+
# Set logger to quiet mode (only errors)
|
204
|
+
def quiet!
|
205
|
+
@logger = Logger.new(level: :error, output: @logger&.instance_variable_get(:@output) || $stdout)
|
206
|
+
end
|
207
|
+
|
208
|
+
# Set logger to verbose mode (all messages)
|
209
|
+
def verbose!
|
210
|
+
@logger = Logger.new(level: :debug, output: @logger&.instance_variable_get(:@output) || $stdout)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|