Class: Backup::Pipeline

Inherits:
Object
  • Object
show all
Includes:
Utilities::Helpers
Defined in:
lib/backup/pipeline.rb

Defined Under Namespace

Classes: Error

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializePipeline

Returns a new instance of Pipeline.



11
12
13
14
15
16
# File 'lib/backup/pipeline.rb', line 11

def initialize
  @commands = []
  @success_codes = []
  @errors = []
  @stderr = ''
end

Instance Attribute Details

#errorsObject (readonly)

Returns the value of attribute errors.



9
10
11
# File 'lib/backup/pipeline.rb', line 9

def errors
  @errors
end

#stderrObject (readonly)

Returns the value of attribute stderr.



9
10
11
# File 'lib/backup/pipeline.rb', line 9

def stderr
  @stderr
end

Instance Method Details

#<<(command) ⇒ Object

Commands added using this method will only be considered successful if their exit status is 0.

Use #add if successful exit status codes need to be specified.



35
36
37
# File 'lib/backup/pipeline.rb', line 35

def <<(command)
  add(command, [0])
end

#add(command, success_codes) ⇒ Object

Adds a command to be executed in the pipeline. Each command will be run in the order in which it was added, with it’s output being piped to the next command.

success_codes must be an Array of Integer exit codes that will be considered successful for the command.



25
26
27
28
# File 'lib/backup/pipeline.rb', line 25

def add(command, success_codes)
  @commands << command
  @success_codes << success_codes
end

#error_messagesObject

Returns a multi-line String, reporting all STDERR messages received from the commands in the pipeline (if any), along with the SystemCallError (Errno) message for each command which had a non-zero exit status.



80
81
82
83
84
# File 'lib/backup/pipeline.rb', line 80

def error_messages
  @error_messages ||= (stderr_messages || '') +
      "The following system errors were returned:\n" +
      @errors.map {|err| "#{ err.class }: #{ err.message }" }.join("\n")
end

#runObject

Runs the command line from β€˜#pipeline` and collects STDOUT/STDERR. STDOUT is then parsed to determine the exit status of each command. For each command with a non-zero exit status, a SystemCallError is created and added to @errors. All STDERR output is set in @stderr.

Note that there is no accumulated STDOUT from the commands themselves. Also, the last command should not attempt to write to STDOUT. Any output on STDOUT from the final command will be sent to STDERR. This in itself will not cause #run to fail, but will log warnings when all commands exit with non-zero status.

Use β€˜#success?` to determine if all commands in the pipeline succeeded. If `#success?` returns `false`, use `#error_messages` to get an error report.



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/backup/pipeline.rb', line 53

def run
  Open4.popen4(pipeline) do |pid, stdin, stdout, stderr|
    pipestatus = stdout.read.gsub("\n", '').split(':').sort
    pipestatus.each do |status|
      index, exitstatus = status.split('|').map(&:to_i)
      unless @success_codes[index].include?(exitstatus)
        command = command_name(@commands[index])
        @errors << SystemCallError.new(
          "'#{ command }' returned exit code: #{ exitstatus }", exitstatus
        )
      end
    end
    @stderr = stderr.read.strip
  end
  Logger.warn(stderr_messages) if success? && stderr_messages
rescue Exception => err
  raise Error.wrap(err, 'Pipeline failed to execute')
end

#success?Boolean

Returns:

  • (Boolean)


72
73
74
# File 'lib/backup/pipeline.rb', line 72

def success?
  @errors.empty?
end