Class: Bashcov::Xtrace

Inherits:
Object
  • Object
show all
Defined in:
lib/bashcov/xtrace.rb

Overview

This class manages xtrace output.

See Also:

Constant Summary collapse

DEPTH_CHAR =
String

Character that will be used to indicate the nesting level of

+xtrace+d instructions
"+"
PREFIX =
String

Prefix used in PS4 to identify relevant output

"BASHCOV>"
FIELDS =
Array<String>

A collection of Bash internal variables to expand in the

{PS4}
%w[${LINENO-} ${BASH_SOURCE-} ${PWD-} ${OLDPWD-}].freeze
PS4_START_REGEXP =

Regexp to match the beginning of the ps4. DEPTH_CHAR will be repeated in proportion to the level of Bash call nesting.

/#{Regexp.escape(DEPTH_CHAR)}+#{Regexp.escape(PREFIX)}$/m

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(field_stream) ⇒ Xtrace

Creates a pipe for xtrace output.



57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/bashcov/xtrace.rb', line 57

def initialize(field_stream)
  @field_stream = field_stream

  @read, @write = IO.pipe

  # Tracks coverage for each file under test
  @files ||= {}

  # Stacks for updating working directory changes
  @pwd_stack ||= []
  @oldpwd_stack ||= []
end

Class Attribute Details

.delimiterObject

String

A randomly-generated UUID or the ASCII RS (record separator)

character, depending on whether the current Bash suffers from the
truncated +PS4+ bug. Used for delimiting the fields of the +PS4+.


30
31
32
# File 'lib/bashcov/xtrace.rb', line 30

def delimiter
  @delimiter ||= Bashcov.truncated_ps4? ? "\x1E" : SecureRandom.uuid
end

.ps4String

Returns PS4 variable used for xtrace output. Expands to internal Bash variables BASH_SOURCE, PWD, OLDPWD, and LINENO, delimited by delimiter.

Returns:

  • (String)

    PS4 variable used for xtrace output. Expands to internal Bash variables BASH_SOURCE, PWD, OLDPWD, and LINENO, delimited by delimiter.

See Also:



38
39
40
# File 'lib/bashcov/xtrace.rb', line 38

def ps4
  @ps4 ||= make_ps4(*FIELDS)
end

Class Method Details

.make_ps4(*fields) ⇒ String

Returns a delimiter-separated String suitable for use as PS4.

Returns:

  • (String)

    a delimiter-separated String suitable for use as PS4



44
45
46
47
48
# File 'lib/bashcov/xtrace.rb', line 44

def make_ps4(*fields)
  fields.reduce(DEPTH_CHAR + PREFIX) do |memo, field|
    memo + delimiter + field
  end + delimiter
end

Instance Method Details

#closevoid

This method returns an undefined value.

Closes the pipe for writing.



77
78
79
# File 'lib/bashcov/xtrace.rb', line 77

def close
  @write.close
end

#file_descriptorFixnum

Returns File descriptor of the write end of the pipe.

Returns:

  • (Fixnum)

    File descriptor of the write end of the pipe



71
72
73
# File 'lib/bashcov/xtrace.rb', line 71

def file_descriptor
  @write.fileno
end

#readHash<Pathname, Array<Integer, nil>>

Read fields extracted from Bash’s debugging output

Returns:

  • (Hash<Pathname, Array<Integer, nil>>)

    A hash mapping Bash scripts to Simplecov-style coverage stats



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/bashcov/xtrace.rb', line 84

def read
  @field_stream.read = @read

  field_count = FIELDS.length
  fields = @field_stream.each(
    self.class.delimiter, field_count, PS4_START_REGEXP
  )

  # +take(field_count)+ would be more natural here, but doesn't seem to
  # play nicely with +Enumerator+s backed by +IO+ objects.
  loop do
    break if (hit = (1..field_count).map { fields.next }).empty?
    parse_hit!(*hit)
  end

  @files
end