Module: CommandLine
- Defined in:
- lib/dtr/command_line.rb
Defined Under Namespace
Classes: ExecutionError, OptionError
Constant Summary collapse
- QUOTE_REPLACEMENT =
(Platform.family == "mswin32") ? "\"" : "\\\""
- LESS_THAN_REPLACEMENT =
(Platform.family == "mswin32") ? "<" : "\\<"
Class Method Summary collapse
- .e(cmd, options, &proc) ⇒ Object
-
.execute(cmd, options = {}, &proc) ⇒ Object
Executes
cmd
. - .full_cmd(cmd, options, &proc) ⇒ Object
- .verify_exit_code(cmd, full_cmd, options) ⇒ Object
Class Method Details
.e(cmd, options, &proc) ⇒ Object
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/dtr/command_line.rb', line 144 def e(cmd, , &proc) full_cmd = full_cmd(cmd, , &proc) [:env].each{|k,v| ENV[k]=v} begin STDOUT.puts "#{Platform.prompt} #{cmd}" if [:stdout].nil? IO.popen(full_cmd, [:mode]) do |io| if(block_given?) proc.call(io) else io.each_line do |line| STDOUT.puts line if [:stdout].nil? end end end rescue Errno::ENOENT => e unless [:stderr].nil? File.open([:stderr], "a") {|io| io.write(e.)} else STDERR.puts e. STDERR.puts e.backtrace.join("\n") end raise ExecutionError.new(cmd, full_cmd, [:dir] || Dir.pwd.untaint, nil, e.) ensure verify_exit_code(cmd, full_cmd, ) end end |
.execute(cmd, options = {}, &proc) ⇒ Object
Executes cmd
. If the :stdout
and :stderr
options are specified, a line consisting of a prompt (including cmd
) will be appended to the respective output streams will be appended to those files, followed by the output itself. Example:
CommandLine.execute("echo hello world", {:stdout => "stdout.log", :stderr => "stderr.log"})
will result in the following being written to stdout.log:
/Users/aslakhellesoy/scm/buildpatterns/repos/damagecontrol/trunk aslakhellesoy$ echo hello world
hello world
-and to stderr.log:
/Users/aslakhellesoy/scm/buildpatterns/repos/damagecontrol/trunk aslakhellesoy$ echo hello world
If a block is passed, the stdout io will be yielded to it (as with IO.popen). In this case the output will not be written to the stdout file (even if it’s specified):
/Users/aslakhellesoy/scm/buildpatterns/repos/damagecontrol/trunk aslakhellesoy$ echo hello world
[output captured and therefore not logged]
If the exitstatus of the command is different from the value specified by the :exitstatus
option (which defaults to 0) then an ExecutionError is raised, its message containing the last 400 bytes of stderr (provided :stderr
was specified)
You can also specify the :dir
option, which will cause the command to be executed in that directory (default is current directory).
You can also specify a hash of environment variables in :env
, which will add additional environment variables to the default environment.
Finally, you can specify several commands within one by separating them with ‘&&’ (as you would in a shell). This will result in several lines to be appended to the log (as if you had executed the commands separately).
See the unit test for more examples.
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/dtr/command_line.rb', line 83 def execute(cmd, ={}, &proc) raise "Can't have newline in cmd" if cmd =~ /\n/ = { :dir => Dir.pwd.untaint, :env => {}, :mode => 'r', :exitstatus => 0 }.merge() [:stdout] = %{"#{File.([:stdout])}"}.untaint if [:stdout] [:stderr] = %{"#{File.([:stderr])}"}.untaint if [:stderr] if [:dir].nil? e(cmd, , &proc) else Dir.chdir([:dir]) do e(cmd, , &proc) end end end |
.full_cmd(cmd, options, &proc) ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/dtr/command_line.rb', line 108 def full_cmd(cmd, , &proc) commands = cmd.split("&&").collect{|c| c.strip} stdout_opt = [:stdout] ? ">> #{[:stdout]}" : "" stderr_opt = [:stderr] ? "2>> #{[:stderr]}" : "" capture_info_command = (block_given? && [:stdout])? "echo [output captured and therefore not logged] >> #{[:stdout]} && " : "" full_cmd = commands.collect do |c| escaped_command = c.gsub(/"/, QUOTE_REPLACEMENT).gsub(/</, LESS_THAN_REPLACEMENT) stdout_prompt_command = [:stdout] ? "echo #{Platform.prompt} #{escaped_command} >> #{[:stdout]} && " : "" stderr_prompt_command = [:stderr] ? "echo #{Platform.prompt} #{escaped_command} >> #{[:stderr]} && " : "" redirected_command = block_given? ? "#{c} #{stderr_opt}" : "#{c} #{stdout_opt} #{stderr_opt}" stdout_prompt_command + capture_info_command + stderr_prompt_command + redirected_command end.join(" && ") full_cmd.untaint end |
.verify_exit_code(cmd, full_cmd, options) ⇒ Object
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/dtr/command_line.rb', line 126 def verify_exit_code(cmd, full_cmd, ) if($?.exitstatus != [:exitstatus]) = "#{[:stderr]} doesn't exist" if [:stderr] && File.exist?([:stderr]) File.open([:stderr]) do |errio| begin errio.seek(-1200, IO::SEEK_END) rescue Errno::EINVAL # ignore - it just means we didn't have 400 bytes. end = errio.read end end raise ExecutionError.new(cmd, full_cmd, [:dir] || Dir.pwd, $?.exitstatus, ) end end |