Class: Mattock::CommandLine

Inherits:
Object
  • Object
show all
Defined in:
lib/mattock/command-line.rb,
lib/mattock/testing/record-commands.rb,
lib/mattock/testing/mock-command-line.rb,
lib/mattock/command-line/command-run-result.rb

Direct Known Subclasses

CommandChain, ShellEscaped

Defined Under Namespace

Classes: CommandRunResult

Constant Summary collapse

@@commands =
[]

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(executable, *options) {|_self| ... } ⇒ CommandLine

Returns a new instance of CommandLine.

Yields:

  • (_self)

Yield Parameters:



29
30
31
32
33
34
35
36
# File 'lib/mattock/command-line.rb', line 29

def initialize(executable, *options)
  @output_stream = self.class.output_stream || $stderr
  @executable = executable
  @options = options
  @redirections = []
  @env = {}
  yield self if block_given?
end

Class Attribute Details

.command_recording_pathObject

Returns the value of attribute command_recording_path.



15
16
17
# File 'lib/mattock/testing/record-commands.rb', line 15

def command_recording_path
  @command_recording_path
end

.output_streamObject

Returns the value of attribute output_stream.



26
27
28
# File 'lib/mattock/command-line.rb', line 26

def output_stream
  @output_stream
end

Instance Attribute Details

#envObject Also known as: command_environment

Returns the value of attribute env.



38
39
40
# File 'lib/mattock/command-line.rb', line 38

def env
  @env
end

#executableObject

Returns the value of attribute executable.



38
39
40
# File 'lib/mattock/command-line.rb', line 38

def executable
  @executable
end

#nameObject

Returns the value of attribute name.



38
39
40
# File 'lib/mattock/command-line.rb', line 38

def name
  @name
end

#optionsObject

Returns the value of attribute options.



38
39
40
# File 'lib/mattock/command-line.rb', line 38

def options
  @options
end

#output_streamObject

Returns the value of attribute output_stream.



38
39
40
# File 'lib/mattock/command-line.rb', line 38

def output_stream
  @output_stream
end

#redirectionsObject (readonly)

Returns the value of attribute redirections.



39
40
41
# File 'lib/mattock/command-line.rb', line 39

def redirections
  @redirections
end

Class Method Details

.define_chain_op(opname, klass) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/mattock/command-line.rb', line 6

def define_chain_op(opname, klass)
  define_method(opname) do |other|
    unless CommandLine === other
      other = CommandLine.new(*[*other])
    end
    chain = nil
    if klass === self
      chain = self
    else
      chain = klass.new
      chain.add(self)
    end
    chain.add(other)
  end
end

.define_op(opname) ⇒ Object



22
23
24
# File 'lib/mattock/command-line.rb', line 22

def define_op(opname)
  CommandLine.define_chain_op(opname, self)
end

.emit_recordingObject



21
22
23
24
25
26
27
28
29
30
31
# File 'lib/mattock/testing/record-commands.rb', line 21

def emit_recording
  io = $stderr
  if command_recording_path
    io = File.open(command_recording_path, "w")
  else
    io.puts "Set MATTOCK_CMDREC to write to a path"
  end
  @@commands.each do |pair|
    io.puts "[/#{pair[0]}/, #{[pair[1].exit_code, pair[1].streams].inspect}]"
  end
end

.execute(*args) ⇒ Object



28
29
30
# File 'lib/mattock/testing/mock-command-line.rb', line 28

def self.execute(*args)
  fail "Command line executed in specs without 'expect_command' or 'expect_some_commands'"
end

Instance Method Details

#backgroundObject

Run a command in parallel with the parent process - will kill it if it outlasts us



134
135
136
137
138
139
140
141
# File 'lib/mattock/command-line.rb', line 134

def background
  pid, out, err = spawn_process
  Process.detach(pid)
  at_exit do
    kill_process(pid)
  end
  return pid, out, err
end

#collect_result(pid, host_stdout, host_stderr) ⇒ Object



111
112
113
114
115
116
# File 'lib/mattock/command-line.rb', line 111

def collect_result(pid, host_stdout, host_stderr)
  result = CommandRunResult.new(pid, self)
  result.streams = {1 => host_stdout, 2 => host_stderr}
  result.wait
  return result
end

#commandObject



56
57
58
# File 'lib/mattock/command-line.rb', line 56

def command
  ([executable] + options_composition + @redirections).join(" ")
end

#complete(pid, out, err) ⇒ Object



147
148
149
150
# File 'lib/mattock/command-line.rb', line 147

def complete(pid, out, err)
  kill_process(pid)
  collect_result(pid, out, err)
end

#copy_stream_to(from, to) ⇒ Object



78
79
80
# File 'lib/mattock/command-line.rb', line 78

def copy_stream_to(from, to)
  @redirections << "#{from}>&#{to}"
end

#executeObject

If I wasn’t worried about writing my own limited shell, I’d say e.g. Pipeline would be an explicit chain of pipes… which is probably as originally intended :/



121
122
123
# File 'lib/mattock/command-line.rb', line 121

def execute
  collect_result(*spawn_process)
end

#kill_process(pid) ⇒ Object



143
144
145
# File 'lib/mattock/command-line.rb', line 143

def kill_process(pid)
  Process.kill("INT", pid)
end

#must_succeed!Object



170
171
172
# File 'lib/mattock/command-line.rb', line 170

def must_succeed!
  run.must_succeed!
end

#options_compositionObject



66
67
68
# File 'lib/mattock/command-line.rb', line 66

def options_composition
  options
end

#original_executeObject

If I wasn’t worried about writing my own limited shell, I’d say e.g. Pipeline would be an explicit chain of pipes… which is probably as originally intended :/



6
7
8
# File 'lib/mattock/testing/record-commands.rb', line 6

def execute
  collect_result(*spawn_process)
end

#redirect_from(path, stream) ⇒ Object



74
75
76
# File 'lib/mattock/command-line.rb', line 74

def redirect_from(path, stream)
  @redirections << "#{stream}<#{path}"
end

#redirect_stderr(path) ⇒ Object



86
87
88
# File 'lib/mattock/command-line.rb', line 86

def redirect_stderr(path)
  redirect_to(2, path)
end

#redirect_stdin(path) ⇒ Object



90
91
92
# File 'lib/mattock/command-line.rb', line 90

def redirect_stdin(path)
  redirect_from(path, 0)
end

#redirect_stdout(path) ⇒ Object



82
83
84
# File 'lib/mattock/command-line.rb', line 82

def redirect_stdout(path)
  redirect_to(1, path)
end

#redirect_to(stream, path) ⇒ Object



70
71
72
# File 'lib/mattock/command-line.rb', line 70

def redirect_to(stream, path)
  @redirections << "#{stream}>#{path}"
end

#replace_usObject



94
95
96
97
98
# File 'lib/mattock/command-line.rb', line 94

def replace_us
  output_steeam.puts "Ceding execution to: "
  output_stream.puts string_format
  Process.exec(command_environment, command)
end

#report(message, newline = true) ⇒ Object



152
153
154
# File 'lib/mattock/command-line.rb', line 152

def report(message, newline=true)
  output_stream.print(message + (newline ? "\n" : ""))
end

#runObject



156
157
158
159
160
161
162
163
164
# File 'lib/mattock/command-line.rb', line 156

def run
  report string_format + " ", false
  result = execute
  report "=> #{result.exit_code}"
  report result.format_streams if verbose
  return result
ensure
  report "" if verbose
end

#set_env(name, value) ⇒ Object



43
44
45
46
# File 'lib/mattock/command-line.rb', line 43

def set_env(name, value)
  command_environment[name] = value
  return self
end

#spawn_processObject



100
101
102
103
104
105
106
107
108
109
# File 'lib/mattock/command-line.rb', line 100

def spawn_process
  host_stdout, cmd_stdout = IO.pipe
  host_stderr, cmd_stderr = IO.pipe

  pid = Process.spawn(command_environment, command, :out => cmd_stdout, :err => cmd_stderr)
  cmd_stdout.close
  cmd_stderr.close

  return pid, host_stdout, host_stderr
end

#spin_offObject

Run a command in the background. The command can survive the caller



126
127
128
129
130
# File 'lib/mattock/command-line.rb', line 126

def spin_off
  pid, out, err = spawn_process
  Process.detach(pid)
  return pid, out, err
end

#string_formatObject



60
61
62
63
64
# File 'lib/mattock/command-line.rb', line 60

def string_format
  (command_environment.map do |key, value|
    [key, value].join("=")
  end + [command]).join(" ")
end

#succeeds?Boolean

Returns:

  • (Boolean)


166
167
168
# File 'lib/mattock/command-line.rb', line 166

def succeeds?
  run.succeeded?
end

#verboseObject



48
49
50
# File 'lib/mattock/command-line.rb', line 48

def verbose
  ::Rake.verbose && ::Rake.verbose != ::Rake::FileUtilsExt::DEFAULT
end