class RVM::Shell::AbstractWrapper
Provides the most common functionality expected of a shell wrapper. Namely, implements general utility methods and tools to extract output from a given command but doesn’t actually run any commands itself, leaving that up to concrete implementations.
Usage¶ ↑
Commands are run inside of a shell (usually bash) and can either be exectuted in two situations (each with wrapper methods available) - silently or verbosely.
Silent commands (via run_silently
and run_command
) do exactly as they say - that can modify the environment etc but anything they print (to stdout or stderr) will be discarded.
Verbose commands will run the command and then print the command epilog (which contains the output stastus and the current env in yaml format). This allows us to not only capture all output but to also return the exit status and environment variables in a way that makes persisted shell sessions possible.
Under the hood, run
and run_silently
are the preferred ways of invoking commands - if passed a single command, they’ll run it as is (much like system in ruby) but when given multiple arguments anything after the first will be escaped (e.g. you can hence pass code etc). run
will also parse the results of this epilog into a usable RVM::Shell::Result
object.
run_command
and run_command_silently
do the actual hard work for these behind the scenes, running a string as the shell command. Hence, these two commands are what must be implemented in non-abstract wrappers.
For an example of the shell wrapper functionality in action, see RVM::Environment
which delegates most of the work to a shell wrapper.
Constants
- COMMAND_EPILOG_END
Used to mark the end of the commands epilog.
- COMMAND_EPILOG_START
Used the mark the end of a commands output and the start of the rvm env.
- WRAPPER_LOCATION
The location of the shell file with the epilog function definition.
Attributes
Defines the shell exectuable.
Public Class Methods
Initializes a new shell wrapper, including setting the default setup block. Implementations must override this method but must ensure that they call super to perform the expected standard setup.
# File lib/rvm/shell/abstract_wrapper.rb, line 52 def initialize(sh = 'bash', &setup_block) setup &setup_block @shell_executable = sh end
Public Instance Methods
Returns a given environment variables’ value.
# File lib/rvm/shell/abstract_wrapper.rb, line 96 def [](var_name) run(:true)[var_name] end
Runs the gives command (with optional arguments), returning an RVM::Shell::Result
object, including stdout / stderr streams. Under the hood, uses run_command
to actually process it all.
# File lib/rvm/shell/abstract_wrapper.rb, line 69 def run(command, *arguments) expanded_command = build_cli_call(command, arguments) status, out, err = run_command(expanded_command) Result.new(expanded_command, status, out, err) end
Given a command, it will execute it in the current wrapper and once done, will return:
-
the hash from the epilog output.
-
a string representing stdout.
-
a string representing stderr.
# File lib/rvm/shell/abstract_wrapper.rb, line 86 def run_command(full_command) raise NotImplementedError.new("run_command is only available in concrete implementations") end
Like run_command
, but doesn’t care about output.
# File lib/rvm/shell/abstract_wrapper.rb, line 91 def run_command_silently(full_command) raise NotImplementedError.new("run_command_silently is only available in concrete implementations") end
Wrapper around run_command_silently
that correctly escapes arguments. Essentially, run
but using run_command_silently.
# File lib/rvm/shell/abstract_wrapper.rb, line 77 def run_silently(command, *arguments) run_command_silently build_cli_call(command, arguments) end
Defines a setup block to be run when initiating a wrapper session. Usually used for doing things such as sourcing the rvm file. Please note that the wrapper file is automatically source.
The setup block should be automatically run by wrapper implementations.
# File lib/rvm/shell/abstract_wrapper.rb, line 62 def setup(&blk) @setup_block = blk end
Protected Instance Methods
Checks whether the given command includes a epilog, marked by epilog start and end lines.
# File lib/rvm/shell/abstract_wrapper.rb, line 126 def command_complete?(c) start_index, end_index = c.index(COMMAND_EPILOG_START), c.index(COMMAND_EPILOG_END) start_index && end_index && start_index < end_index end
When called, will use the current environment to source the wrapper scripts as well as invoking the current setup block. as defined on initialization / via setup
.
# File lib/rvm/shell/abstract_wrapper.rb, line 104 def invoke_setup! source_command_wrapper @setup_block.call(self) if @setup_block end
Takes a raw string from a processes STDIO and returns three things:
-
The actual stdout, minus epilogue.
-
YAML output of the process results.
-
Any left over from the STDIO text.
# File lib/rvm/shell/abstract_wrapper.rb, line 135 def raw_stdout_to_parts(c) raise IncompleteCommandError if !command_complete?(c) before, after = c.split(COMMAND_EPILOG_START, 2) epilog, after = after.split(COMMAND_EPILOG_END, 2) return before, YAML.load(epilog.strip), after end
Wraps a command in a way that it prints no output.
# File lib/rvm/shell/abstract_wrapper.rb, line 120 def silent_command(command) "{ #{command}; } >/dev/null 2>&1" end
Uses run_silently
to source the wrapper file.
# File lib/rvm/shell/abstract_wrapper.rb, line 110 def source_command_wrapper run_silently :source, WRAPPER_LOCATION end
Returns a command followed by the call to show the epilog.
# File lib/rvm/shell/abstract_wrapper.rb, line 115 def wrapped_command(command) "#{command}; __rvm_show_command_epilog" end