Skip to content

Commit 560f2bf

Browse files
Run cogs in custom working directory
Cogs that run external commands, like `cmd` and `agent`, or that access files on disk (like `chat`, when we give it the ability to do thing like handle image input/output) may benefit from being configured with an alternate working directory. Note: Roast does not automatically change into the configured working directory when running a cog for which it is specified, because doing so causes issues for parallelization. (If two cogs are running in parallel and each attempts to change the working directory of the main ruby process, then it gets changed for all parallel cogs, leading to unexpected behaviour). Instead cogs that need to interact with the filesystem should use the `working_directory` config value intentionally to operate within that folder *without* changing the working directory of the ruby process.
1 parent 1b1245e commit 560f2bf

File tree

4 files changed

+95
-0
lines changed

4 files changed

+95
-0
lines changed

dsl/working_directory.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# typed: true
2+
# frozen_string_literal: true
3+
4+
#: self as Roast::DSL::Workflow
5+
6+
config do
7+
cmd { print_all! }
8+
cmd(:alt) { working_directory "/tmp" }
9+
cmd(:orig) { use_current_working_directory! }
10+
end
11+
12+
execute do
13+
cmd(:cwd) { "echo Current working directory: `pwd`" }
14+
cmd(:alt) { "echo Alternate working directory: `pwd`" }
15+
cmd(:orig) { "echo Back to originl working directory: `pwd`" }
16+
end

lib/roast/dsl/cog/config.rb

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,71 @@ def abort_on_error?
225225
@values[:exit_on_error] ||= true
226226
end
227227

228+
# Configure the cog to run external commands in the specified working directory
229+
#
230+
# The directory given can be relative or absolute.
231+
# If relative, it will be understood in relation to the directory from which Roast is invoked.
232+
#
233+
# ---
234+
#
235+
# __Important Note__: this configuration option only applies to external commands invoked by a cog
236+
# It does not affect the working directory in which Roast is running.
237+
#
238+
# ---
239+
#
240+
# #### See Also
241+
# - `use_current_working_directory!`
242+
# - `valid_working_directory`
243+
#
244+
#: (String) -> void
245+
def working_directory(directory)
246+
@values[:working_directory] = directory
247+
end
248+
249+
# Configure the cog to run in the directory from which Roast is invoked
250+
#
251+
# ---
252+
#
253+
# __Important Note__: this configuration option only applies to external commands invoked by a cog
254+
# It does not affect the working directory in which Roast is running.
255+
#
256+
# ---
257+
#
258+
# #### See Also
259+
# - `working_directory`
260+
# - `valid_working_directory`
261+
#
262+
#: () -> void
263+
def use_current_working_directory!
264+
@values[:working_directory] = nil
265+
end
266+
267+
# Get the validated, configured value for the working directory path in which the cog should run
268+
#
269+
# A value of `nil` means to use the current working directory.
270+
# This method will raise an `InvalidConfigError` if the path does not exist or is not a directory.
271+
#
272+
# ---
273+
#
274+
# __Important Note__: this configuration option only applies to external commands invoked by a cog
275+
# It does not affect the working directory in which Roast is running.
276+
#
277+
# ---
278+
#
279+
# #### See Also
280+
# - `working_directory`
281+
# - `use_current_working_directory!`
282+
#
283+
#: () -> Pathname?
284+
def valid_working_directory
285+
path = Pathname.new(@values[:working_directory]).expand_path if @values[:working_directory]
286+
return unless path
287+
raise InvalidConfigError, "working directory '#{path}' does not exist'" unless path.exist?
288+
raise InvalidConfigError, "working directory '#{path}' is not a directory'" unless path.directory?
289+
290+
path
291+
end
292+
228293
alias_method(:exit_on_error!, :abort_on_error!)
229294
alias_method(:no_exit_on_error!, :no_abort_on_error!)
230295
alias_method(:continue_on_error!, :no_abort_on_error!)

lib/roast/dsl/cogs/cmd.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ def execute(input)
167167
stdout, stderr, status = CommandRunner #: as untyped
168168
.execute(
169169
[input.command] + input.args,
170+
working_directory: config.valid_working_directory,
170171
stdout_handler: stdout_handler,
171172
stderr_handler: stderr_handler,
172173
)

test/dsl/functional/roast_dsl_examples_test.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,19 @@ class RoastDSLExamplesTest < FunctionalTest
231231
EOF
232232
assert_equal expected_stdout, stdout
233233
end
234+
235+
test "working_directory.rb workflow runs successfully" do
236+
stdout, stderr = in_sandbox :working_directory do
237+
Roast::DSL::Workflow.from_file("dsl/working_directory.rb", EMPTY_PARAMS)
238+
end
239+
assert_empty stderr
240+
expected_stdout = <<~EOF
241+
Current working directory: #{Dir.pwd}
242+
Alternate working directory: /tmp
243+
Back to originl working directory: #{Dir.pwd}
244+
EOF
245+
assert_equal expected_stdout, stdout
246+
end
234247
end
235248
end
236249
end

0 commit comments

Comments
 (0)