taski 0.7.1 → 0.8.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/CHANGELOG.md +38 -0
- data/README.md +11 -9
- data/examples/README.md +3 -3
- data/examples/args_demo.rb +21 -20
- data/lib/taski/args.rb +2 -8
- data/lib/taski/env.rb +17 -0
- data/lib/taski/execution/task_wrapper.rb +12 -2
- data/lib/taski/task.rb +27 -10
- data/lib/taski/test_helper/mock_registry.rb +3 -1
- data/lib/taski/test_helper.rb +35 -3
- data/lib/taski/version.rb +1 -1
- data/lib/taski.rb +43 -5
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f7677c0f3995a7c61b5850fb25c82c60626287584e5c7f918939ededc045e9ea
|
|
4
|
+
data.tar.gz: d470969c88a4df51503487aacdf2c6261b65e6ed75ee3c7cc2ff744dfd750365
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5f93d9e7d10f7104851266f0252ec4365d445a90d3a25b885f289df5d8caafbe9f9250ff9236e4cca0791749100c83c46735a8e98e5c1b675662199ba7a0e547
|
|
7
|
+
data.tar.gz: eb4fb9f806cdd5097e0d3321d4cda9e3df183d4850c4aa8161ba09b71666444166f05b5e795b330227076d85f7410adbe2fc4f1e2b19c66d007ff1632d354f97
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.8.0] - 2026-01-23
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- `Taski::Env` class for system-managed execution environment information ([#125](https://github.com/ahogappa/taski/pull/125))
|
|
14
|
+
- Access via `Taski.env.working_directory`, `Taski.env.started_at`, `Taski.env.root_task`
|
|
15
|
+
- `args` and `workers` parameters to `Task.new` for direct task instantiation ([#125](https://github.com/ahogappa/taski/pull/125))
|
|
16
|
+
- `mock_env` helper in `TestHelper` for mocking environment in tests ([#125](https://github.com/ahogappa/taski/pull/125))
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
- Separate system attributes from `Taski.args` to `Taski.env` ([#125](https://github.com/ahogappa/taski/pull/125))
|
|
20
|
+
- `Taski.args` now holds only user-defined options passed via `run(args: {...})`
|
|
21
|
+
- `Taski.env` holds system-managed execution environment (`root_task`, `started_at`, `working_directory`)
|
|
22
|
+
|
|
23
|
+
## [0.7.1] - 2026-01-22
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
- `Taski::TestHelper` module for mocking task dependencies in unit tests ([#123](https://github.com/ahogappa/taski/pull/123))
|
|
27
|
+
- `mock_task(TaskClass, key: value)` to mock exported values without running tasks
|
|
28
|
+
- `assert_task_accessed` / `refute_task_accessed` for verifying dependency access
|
|
29
|
+
- Support for both Minitest and RSpec test frameworks
|
|
30
|
+
- Simple one-line progress display mode (`Taski.progress_mode = :simple`) as an alternative to tree display ([#112](https://github.com/ahogappa/taski/pull/112))
|
|
31
|
+
- Configure via `TASKI_PROGRESS_MODE` environment variable or `Taski.progress_mode` API
|
|
32
|
+
- Display captured task output (up to 30 lines) in AggregateError messages for better debugging ([#109](https://github.com/ahogappa/taski/pull/109))
|
|
33
|
+
- Background polling thread in TaskOutputRouter to ensure pipes are drained reliably ([#122](https://github.com/ahogappa/taski/pull/122))
|
|
34
|
+
- `Taski.with_args` helper method for safe argument lifecycle management ([#110](https://github.com/ahogappa/taski/pull/110))
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
- Progress display now uses alternate screen buffer and shows summary line after completion ([#107](https://github.com/ahogappa/taski/pull/107))
|
|
38
|
+
- Eliminate screen flickering in tree progress display with in-place overwrite rendering ([#121](https://github.com/ahogappa/taski/pull/121))
|
|
39
|
+
- Extract `BaseProgressDisplay` class for shared progress display functionality ([#117](https://github.com/ahogappa/taski/pull/117))
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
- Wait for running dependencies in nested executor to prevent deadlock ([#106](https://github.com/ahogappa/taski/pull/106))
|
|
43
|
+
- Preserve namespace path when following method calls in static analysis ([#108](https://github.com/ahogappa/taski/pull/108))
|
|
44
|
+
- Prevent race condition in `Taski.args` lifecycle during concurrent execution ([#110](https://github.com/ahogappa/taski/pull/110))
|
|
45
|
+
- Ensure progress display cleanup on interrupt (Ctrl+C) ([#107](https://github.com/ahogappa/taski/pull/107))
|
|
46
|
+
- Always enable output in PlainProgressDisplay ([#117](https://github.com/ahogappa/taski/pull/117))
|
|
47
|
+
|
|
10
48
|
## [0.7.0] - 2025-12-23
|
|
11
49
|
|
|
12
50
|
### Added
|
data/README.md
CHANGED
|
@@ -203,14 +203,14 @@ Pass custom options and access execution context from any task:
|
|
|
203
203
|
```ruby
|
|
204
204
|
class DeployTask < Taski::Task
|
|
205
205
|
def run
|
|
206
|
-
# User-defined options
|
|
206
|
+
# User-defined options (Taski.args)
|
|
207
207
|
env = Taski.args[:env]
|
|
208
208
|
debug = Taski.args.fetch(:debug, false)
|
|
209
209
|
|
|
210
|
-
# Runtime information
|
|
211
|
-
puts "Working directory: #{Taski.
|
|
212
|
-
puts "Started at: #{Taski.
|
|
213
|
-
puts "Root task: #{Taski.
|
|
210
|
+
# Runtime environment information (Taski.env)
|
|
211
|
+
puts "Working directory: #{Taski.env.working_directory}"
|
|
212
|
+
puts "Started at: #{Taski.env.started_at}"
|
|
213
|
+
puts "Root task: #{Taski.env.root_task}"
|
|
214
214
|
puts "Deploying to: #{env}"
|
|
215
215
|
end
|
|
216
216
|
end
|
|
@@ -219,13 +219,15 @@ end
|
|
|
219
219
|
DeployTask.run(args: { env: "production", debug: true })
|
|
220
220
|
```
|
|
221
221
|
|
|
222
|
-
Args API:
|
|
222
|
+
Args API (user-defined options):
|
|
223
223
|
- `Taski.args[:key]` - Get option value (nil if not set)
|
|
224
224
|
- `Taski.args.fetch(:key, default)` - Get with default value
|
|
225
225
|
- `Taski.args.key?(:key)` - Check if option exists
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
- `Taski.
|
|
226
|
+
|
|
227
|
+
Env API (execution environment):
|
|
228
|
+
- `Taski.env.working_directory` - Execution directory
|
|
229
|
+
- `Taski.env.started_at` - Execution start time
|
|
230
|
+
- `Taski.env.root_task` - First task class called
|
|
229
231
|
|
|
230
232
|
### Execution Model
|
|
231
233
|
|
data/examples/README.md
CHANGED
|
@@ -46,9 +46,9 @@ ruby examples/args_demo.rb
|
|
|
46
46
|
- User-defined options via `run(args: {...})`
|
|
47
47
|
- `Taski.args[:key]` for option access
|
|
48
48
|
- `Taski.args.fetch(:key, default)` for defaults
|
|
49
|
-
- `Taski.
|
|
50
|
-
- `Taski.
|
|
51
|
-
- `Taski.
|
|
49
|
+
- `Taski.env.working_directory`
|
|
50
|
+
- `Taski.env.started_at`
|
|
51
|
+
- `Taski.env.root_task`
|
|
52
52
|
|
|
53
53
|
---
|
|
54
54
|
|
data/examples/args_demo.rb
CHANGED
|
@@ -1,35 +1,36 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
# Taski Args API Example
|
|
4
|
+
# Taski Args & Env API Example
|
|
5
5
|
#
|
|
6
|
-
# This example demonstrates the Args
|
|
7
|
-
# -
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
6
|
+
# This example demonstrates the Args and Env APIs:
|
|
7
|
+
# - Taski.env: Execution environment information
|
|
8
|
+
# - working_directory: Where execution started
|
|
9
|
+
# - started_at: When execution began
|
|
10
|
+
# - root_task: The first task class that was called
|
|
11
|
+
# - Taski.args: User-defined options passed via run(args: {...})
|
|
11
12
|
#
|
|
12
13
|
# Run: ruby examples/args_demo.rb
|
|
13
14
|
|
|
14
15
|
require_relative "../lib/taski"
|
|
15
16
|
|
|
16
|
-
puts "Taski Args API Example"
|
|
17
|
+
puts "Taski Args & Env API Example"
|
|
17
18
|
puts "=" * 40
|
|
18
19
|
|
|
19
|
-
# Task that uses
|
|
20
|
+
# Task that uses env information for logging
|
|
20
21
|
class SetupTask < Taski::Task
|
|
21
22
|
exports :setup_info
|
|
22
23
|
|
|
23
24
|
def run
|
|
24
25
|
puts "Setup running..."
|
|
25
|
-
puts " Working directory: #{Taski.
|
|
26
|
-
puts " Started at: #{Taski.
|
|
27
|
-
puts " Root task: #{Taski.
|
|
26
|
+
puts " Working directory: #{Taski.env.working_directory}"
|
|
27
|
+
puts " Started at: #{Taski.env.started_at}"
|
|
28
|
+
puts " Root task: #{Taski.env.root_task}"
|
|
28
29
|
puts " Environment: #{Taski.args[:env]}"
|
|
29
30
|
|
|
30
31
|
@setup_info = {
|
|
31
|
-
directory: Taski.
|
|
32
|
-
timestamp: Taski.
|
|
32
|
+
directory: Taski.env.working_directory,
|
|
33
|
+
timestamp: Taski.env.started_at,
|
|
33
34
|
env: Taski.args[:env]
|
|
34
35
|
}
|
|
35
36
|
end
|
|
@@ -40,8 +41,8 @@ class FileProcessor < Taski::Task
|
|
|
40
41
|
exports :output_path
|
|
41
42
|
|
|
42
43
|
def run
|
|
43
|
-
# Use
|
|
44
|
-
base_dir = Taski.
|
|
44
|
+
# Use env to determine output location
|
|
45
|
+
base_dir = Taski.env.working_directory
|
|
45
46
|
env = Taski.args.fetch(:env, "development")
|
|
46
47
|
@output_path = File.join(base_dir, "tmp", env, "output.txt")
|
|
47
48
|
|
|
@@ -55,7 +56,7 @@ class TimingTask < Taski::Task
|
|
|
55
56
|
exports :duration_info
|
|
56
57
|
|
|
57
58
|
def run
|
|
58
|
-
start_time = Taski.
|
|
59
|
+
start_time = Taski.env.started_at
|
|
59
60
|
current_time = Time.now
|
|
60
61
|
elapsed = current_time - start_time
|
|
61
62
|
|
|
@@ -76,7 +77,7 @@ class MainTask < Taski::Task
|
|
|
76
77
|
|
|
77
78
|
def run
|
|
78
79
|
puts "\nMainTask executing..."
|
|
79
|
-
puts " Root task is: #{Taski.
|
|
80
|
+
puts " Root task is: #{Taski.env.root_task}"
|
|
80
81
|
puts " Environment: #{Taski.args[:env]}"
|
|
81
82
|
|
|
82
83
|
# Access dependencies
|
|
@@ -88,7 +89,7 @@ class MainTask < Taski::Task
|
|
|
88
89
|
setup: setup,
|
|
89
90
|
output_path: output,
|
|
90
91
|
timing: timing,
|
|
91
|
-
root_task: Taski.
|
|
92
|
+
root_task: Taski.env.root_task.to_s
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
puts "\nExecution Summary:"
|
|
@@ -114,5 +115,5 @@ puts "-" * 40
|
|
|
114
115
|
puts MainTask.tree
|
|
115
116
|
|
|
116
117
|
puts "\n" + "=" * 40
|
|
117
|
-
puts "Args API demonstration complete!"
|
|
118
|
-
puts "Note: Args provides
|
|
118
|
+
puts "Args & Env API demonstration complete!"
|
|
119
|
+
puts "Note: Args provides user options, Env provides execution environment info."
|
data/lib/taski/args.rb
CHANGED
|
@@ -4,18 +4,12 @@ require "monitor"
|
|
|
4
4
|
|
|
5
5
|
module Taski
|
|
6
6
|
# Runtime arguments accessible from any task.
|
|
7
|
-
# Holds user-defined options
|
|
7
|
+
# Holds user-defined options passed by the user at execution time.
|
|
8
8
|
# Args is immutable after creation - options cannot be modified during task execution.
|
|
9
9
|
class Args
|
|
10
|
-
attr_reader :started_at, :working_directory, :root_task
|
|
11
|
-
|
|
12
10
|
# @param options [Hash] User-defined options (immutable after creation)
|
|
13
|
-
|
|
14
|
-
def initialize(options:, root_task:)
|
|
11
|
+
def initialize(options:)
|
|
15
12
|
@options = options.dup.freeze
|
|
16
|
-
@root_task = root_task
|
|
17
|
-
@started_at = Time.now
|
|
18
|
-
@working_directory = Dir.pwd
|
|
19
13
|
end
|
|
20
14
|
|
|
21
15
|
# Get a user-defined option value
|
data/lib/taski/env.rb
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Taski
|
|
4
|
+
# Runtime execution environment information.
|
|
5
|
+
# Holds system-managed metadata that is set automatically during task execution.
|
|
6
|
+
# Env is immutable after creation.
|
|
7
|
+
class Env
|
|
8
|
+
attr_reader :root_task, :started_at, :working_directory
|
|
9
|
+
|
|
10
|
+
# @param root_task [Class] The root task class that initiated execution
|
|
11
|
+
def initialize(root_task:)
|
|
12
|
+
@root_task = root_task
|
|
13
|
+
@started_at = Time.now
|
|
14
|
+
@working_directory = Dir.pwd
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -38,10 +38,12 @@ module Taski
|
|
|
38
38
|
# @param [Object] task - The task instance being wrapped.
|
|
39
39
|
# @param [Object] registry - The registry used to query abort status and coordinate execution.
|
|
40
40
|
# @param [Object, nil] execution_context - Optional execution context used to trigger and report execution and cleanup.
|
|
41
|
-
|
|
41
|
+
# @param [Hash, nil] args - User-defined arguments for Task.new usage.
|
|
42
|
+
def initialize(task, registry:, execution_context: nil, args: nil)
|
|
42
43
|
@task = task
|
|
43
44
|
@registry = registry
|
|
44
45
|
@execution_context = execution_context
|
|
46
|
+
@args = args
|
|
45
47
|
@result = nil
|
|
46
48
|
@clean_result = nil
|
|
47
49
|
@error = nil
|
|
@@ -261,10 +263,18 @@ module Taski
|
|
|
261
263
|
##
|
|
262
264
|
# Ensures args are set during block execution, then resets if they weren't set before.
|
|
263
265
|
# This allows Task.new.run usage without requiring explicit args setup.
|
|
266
|
+
# If args are already set (e.g., from Task.run class method), just yields the block.
|
|
267
|
+
# Uses stored @args if set (from Task.new), otherwise uses empty hash.
|
|
264
268
|
# @yield The block to execute with args lifecycle management
|
|
265
269
|
# @return [Object] The result of the block
|
|
266
270
|
def with_args_lifecycle(&block)
|
|
267
|
-
|
|
271
|
+
# If args are already set, just execute the block
|
|
272
|
+
return yield if Taski.args
|
|
273
|
+
|
|
274
|
+
options = @args || {}
|
|
275
|
+
Taski.send(:with_env, root_task: @task.class) do
|
|
276
|
+
Taski.send(:with_args, options: options, &block)
|
|
277
|
+
end
|
|
268
278
|
end
|
|
269
279
|
|
|
270
280
|
##
|
data/lib/taski/task.rb
CHANGED
|
@@ -50,11 +50,24 @@ module Taski
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
##
|
|
53
|
-
# Creates a
|
|
54
|
-
# Use class methods (e.g., MyTask.
|
|
53
|
+
# Creates a task instance for manual execution control.
|
|
54
|
+
# Use class methods (e.g., MyTask.run) for simple execution.
|
|
55
|
+
# @param args [Hash] User-defined arguments accessible via Taski.args.
|
|
56
|
+
# @param workers [Integer, nil] Number of worker threads for parallel execution.
|
|
55
57
|
# @return [Execution::TaskWrapper] A new wrapper for this task.
|
|
56
|
-
def new
|
|
57
|
-
|
|
58
|
+
def new(args: {}, workers: nil)
|
|
59
|
+
validate_workers!(workers)
|
|
60
|
+
fresh_registry = Execution::Registry.new
|
|
61
|
+
task_instance = allocate
|
|
62
|
+
task_instance.__send__(:initialize)
|
|
63
|
+
wrapper = Execution::TaskWrapper.new(
|
|
64
|
+
task_instance,
|
|
65
|
+
registry: fresh_registry,
|
|
66
|
+
execution_context: Execution::ExecutionContext.current,
|
|
67
|
+
args: args.merge(_workers: workers)
|
|
68
|
+
)
|
|
69
|
+
fresh_registry.register(self, wrapper)
|
|
70
|
+
wrapper
|
|
58
71
|
end
|
|
59
72
|
|
|
60
73
|
##
|
|
@@ -138,9 +151,11 @@ module Taski
|
|
|
138
151
|
# @return [Object] The result of the block
|
|
139
152
|
def with_execution_setup(args:, workers:)
|
|
140
153
|
validate_workers!(workers)
|
|
141
|
-
Taski.
|
|
142
|
-
|
|
143
|
-
|
|
154
|
+
Taski.send(:with_env, root_task: self) do
|
|
155
|
+
Taski.send(:with_args, options: args.merge(_workers: workers)) do
|
|
156
|
+
validate_no_circular_dependencies!
|
|
157
|
+
yield fresh_wrapper
|
|
158
|
+
end
|
|
144
159
|
end
|
|
145
160
|
end
|
|
146
161
|
|
|
@@ -199,9 +214,11 @@ module Taski
|
|
|
199
214
|
wrapper.get_exported_value(method)
|
|
200
215
|
else
|
|
201
216
|
# Outside execution - fresh execution (top-level call)
|
|
202
|
-
Taski.
|
|
203
|
-
|
|
204
|
-
|
|
217
|
+
Taski.send(:with_env, root_task: self) do
|
|
218
|
+
Taski.send(:with_args, options: {}) do
|
|
219
|
+
validate_no_circular_dependencies!
|
|
220
|
+
fresh_wrapper.get_exported_value(method)
|
|
221
|
+
end
|
|
205
222
|
end
|
|
206
223
|
end
|
|
207
224
|
end
|
|
@@ -38,12 +38,14 @@ module Taski
|
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
# Clears all registered mocks.
|
|
41
|
+
# Clears all registered mocks and resets args/env.
|
|
42
42
|
# Should be called in test setup/teardown.
|
|
43
43
|
def reset!
|
|
44
44
|
@mutex.synchronize do
|
|
45
45
|
@mocks = {}
|
|
46
46
|
end
|
|
47
|
+
Taski.reset_args!
|
|
48
|
+
Taski.reset_env!
|
|
47
49
|
end
|
|
48
50
|
end
|
|
49
51
|
end
|
data/lib/taski/test_helper.rb
CHANGED
|
@@ -43,9 +43,11 @@ module Taski
|
|
|
43
43
|
end
|
|
44
44
|
wrapper.get_exported_value(method)
|
|
45
45
|
else
|
|
46
|
-
Taski.
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
Taski.send(:with_env, root_task: self) do
|
|
47
|
+
Taski.send(:with_args, options: {}) do
|
|
48
|
+
validate_no_circular_dependencies!
|
|
49
|
+
fresh_wrapper.get_exported_value(method)
|
|
50
|
+
end
|
|
49
51
|
end
|
|
50
52
|
end
|
|
51
53
|
end
|
|
@@ -110,6 +112,36 @@ module Taski
|
|
|
110
112
|
end
|
|
111
113
|
end
|
|
112
114
|
|
|
115
|
+
# Sets mock args for the duration of the test.
|
|
116
|
+
# This allows testing code that depends on Taski.args without running full task execution.
|
|
117
|
+
# Args are automatically cleared when MockRegistry.reset! is called (in test teardown).
|
|
118
|
+
# @param options [Hash] User-defined options to include in args
|
|
119
|
+
# @return [Taski::Args] The created args instance
|
|
120
|
+
#
|
|
121
|
+
# @example
|
|
122
|
+
# mock_args(env: "test", debug: true)
|
|
123
|
+
# assert_equal "test", Taski.args[:env]
|
|
124
|
+
def mock_args(**options)
|
|
125
|
+
Taski.reset_args!
|
|
126
|
+
Taski.send(:start_args, options: options)
|
|
127
|
+
Taski.args
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Sets mock env for the duration of the test.
|
|
131
|
+
# This allows testing code that depends on Taski.env without running full task execution.
|
|
132
|
+
# Env is automatically cleared when MockRegistry.reset! is called (in test teardown).
|
|
133
|
+
# @param root_task [Class] The root task class (defaults to nil for testing)
|
|
134
|
+
# @return [Taski::Env] The created env instance
|
|
135
|
+
#
|
|
136
|
+
# @example
|
|
137
|
+
# mock_env(root_task: MyTask)
|
|
138
|
+
# assert_equal MyTask, Taski.env.root_task
|
|
139
|
+
def mock_env(root_task: nil)
|
|
140
|
+
Taski.reset_env!
|
|
141
|
+
Taski.send(:start_env, root_task: root_task)
|
|
142
|
+
Taski.env
|
|
143
|
+
end
|
|
144
|
+
|
|
113
145
|
# Registers a mock for a task class with specified return values.
|
|
114
146
|
# @param task_class [Class] A Taski::Task or Taski::Section subclass
|
|
115
147
|
# @param values [Hash{Symbol => Object}] Method names mapped to return values
|
data/lib/taski/version.rb
CHANGED
data/lib/taski.rb
CHANGED
|
@@ -14,6 +14,7 @@ require_relative "taski/execution/tree_progress_display"
|
|
|
14
14
|
require_relative "taski/execution/simple_progress_display"
|
|
15
15
|
require_relative "taski/execution/plain_progress_display"
|
|
16
16
|
require_relative "taski/args"
|
|
17
|
+
require_relative "taski/env"
|
|
17
18
|
|
|
18
19
|
module Taski
|
|
19
20
|
class TaskAbortException < StandardError
|
|
@@ -138,6 +139,7 @@ module Taski
|
|
|
138
139
|
end
|
|
139
140
|
|
|
140
141
|
@args_monitor = Monitor.new
|
|
142
|
+
@env_monitor = Monitor.new
|
|
141
143
|
|
|
142
144
|
# Get the current runtime arguments
|
|
143
145
|
# @return [Args, nil] The current args or nil if no task is running
|
|
@@ -145,13 +147,50 @@ module Taski
|
|
|
145
147
|
@args_monitor.synchronize { @args }
|
|
146
148
|
end
|
|
147
149
|
|
|
150
|
+
# Get the current execution environment
|
|
151
|
+
# @return [Env, nil] The current env or nil if no task is running
|
|
152
|
+
def self.env
|
|
153
|
+
@env_monitor.synchronize { @env }
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Start new execution environment (internal use only)
|
|
157
|
+
# @api private
|
|
158
|
+
# @return [Boolean] true if this call created the env, false if env already existed
|
|
159
|
+
def self.start_env(root_task:)
|
|
160
|
+
@env_monitor.synchronize do
|
|
161
|
+
return false if @env
|
|
162
|
+
@env = Env.new(root_task: root_task)
|
|
163
|
+
true
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Reset the execution environment (internal use only)
|
|
168
|
+
# @api private
|
|
169
|
+
def self.reset_env!
|
|
170
|
+
@env_monitor.synchronize { @env = nil }
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Execute a block with env lifecycle management.
|
|
174
|
+
# Creates env if it doesn't exist, and resets it only if this call created it.
|
|
175
|
+
# This prevents race conditions in concurrent execution.
|
|
176
|
+
#
|
|
177
|
+
# @param root_task [Class] The root task class
|
|
178
|
+
# @yield The block to execute with env available
|
|
179
|
+
# @return [Object] The result of the block
|
|
180
|
+
def self.with_env(root_task:)
|
|
181
|
+
created_env = start_env(root_task: root_task)
|
|
182
|
+
yield
|
|
183
|
+
ensure
|
|
184
|
+
reset_env! if created_env
|
|
185
|
+
end
|
|
186
|
+
|
|
148
187
|
# Start new runtime arguments (internal use only)
|
|
149
188
|
# @api private
|
|
150
189
|
# @return [Boolean] true if this call created the args, false if args already existed
|
|
151
|
-
def self.start_args(options
|
|
190
|
+
def self.start_args(options:)
|
|
152
191
|
@args_monitor.synchronize do
|
|
153
192
|
return false if @args
|
|
154
|
-
@args = Args.new(options: options
|
|
193
|
+
@args = Args.new(options: options)
|
|
155
194
|
true
|
|
156
195
|
end
|
|
157
196
|
end
|
|
@@ -167,11 +206,10 @@ module Taski
|
|
|
167
206
|
# This prevents race conditions in concurrent execution.
|
|
168
207
|
#
|
|
169
208
|
# @param options [Hash] User-defined options
|
|
170
|
-
# @param root_task [Class] The root task class
|
|
171
209
|
# @yield The block to execute with args available
|
|
172
210
|
# @return [Object] The result of the block
|
|
173
|
-
def self.with_args(options
|
|
174
|
-
created_args = start_args(options: options
|
|
211
|
+
def self.with_args(options:)
|
|
212
|
+
created_args = start_args(options: options)
|
|
175
213
|
yield
|
|
176
214
|
ensure
|
|
177
215
|
reset_args! if created_args
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: taski
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- ahogappa
|
|
@@ -72,6 +72,7 @@ files:
|
|
|
72
72
|
- examples/tree_progress_demo.rb
|
|
73
73
|
- lib/taski.rb
|
|
74
74
|
- lib/taski/args.rb
|
|
75
|
+
- lib/taski/env.rb
|
|
75
76
|
- lib/taski/execution/base_progress_display.rb
|
|
76
77
|
- lib/taski/execution/execution_context.rb
|
|
77
78
|
- lib/taski/execution/executor.rb
|