Class: Eql::CliTable

Inherits:
Object
  • Object
show all
Defined in:
lib/eql/cli.rb

Constant Summary collapse

EQL_CLI_COLUMN_SEP =
'-'
EQL_CLI_WRAPPED_INDENT =
'  '

Class Method Summary collapse

Class Method Details

.get_filter(lines = [], columnsep = EQL_CLI_COLUMN_SEP) ⇒ Object

Returns a Regexp object matching column widths determined by examining our column seperator line



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/eql/cli.rb', line 101

def get_filter(lines = [], columnsep = EQL_CLI_COLUMN_SEP) #:nodoc:
  last = filter = nil

  lines.each do |line|
    # assume just whitespace and columnsep means our column headers were on the
    # previous line
    if line =~ %r{^[#{columnsep} ]+$}

      # okay this is fun
      tmp = String.new
      column_width = 0

      # walk through the line
      line.length.times do |pos|
        # collecting column width based on seperator
        if line[pos].chr == columnsep
          column_width += 1
        # end of column, but!
        elsif line[pos].chr == ' '
          # check our headers above us, sometimes the column header is
          # larger than the field seperator as in 'show volume' eg:
          #
          # Name            Size       SnapShots Status         Permission Connections TP
          # --------------- ---------- --------- -------------- ---------- ----------- -
          # shared          750GB      5         online         read-write 1           N
          mark = pos
          # enlarge the filter to capture the header as well, makes for a
          # proper attribute name later when we form the object
          while mark+1 <= last.length and last[mark].chr != ' '
            column_width += 1
            mark += 1
          end
          tmp << "(.{#{column_width}}) "
          column_width = 0
        end
      end
      tmp.chop!
      # hooray!
      filter = %r{#{tmp}}
      break
    end

    last = line
  end

  filter
end

.get_headers(lines = [], filter = nil, columnsep = EQL_CLI_COLUMN_SEP) ⇒ Object

:nodoc:



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/eql/cli.rb', line 205

def get_headers(lines = [], filter = nil, columnsep = EQL_CLI_COLUMN_SEP) #:nodoc:
  last = nil

  if filter.nil?
    filter = get_filter(lines)
  end

  lines.each do |line|
    # assume just whitespace and columnsep means our column headers were on the
    # previous line
    if line =~ %r{^[#{columnsep} ]+$}
      ret = filter.match(last).to_a
      ret.shift
      return ret
    end
     
    last = line
  end
end

.parse(raw_output) ⇒ Object

take string or array of raw cli output which includes a typical equallogic table, process it and return an array of openstruct objects or yield each one eg:

CliTable.parse(raw(“show volume”)

input is pretty sensitive to format changes



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/eql/cli.rb', line 37

def parse(raw_output)
  table = raw_output

  if raw_output.kind_of?(String)
    table = raw_output.split("\n")
  end

  result = []

  # Drop truely empty lines because some commands output them
  # eg: volume select <vol> show access
  table.each do |line|
    if line.strip.length == 0
      table.delete(line)
    end
  end

  # Drop command
  table.shift
  # and prompt
  table.pop

  table = unwrap(table)

  # Grab headers
  # No multi line headers from what I see 
  headers = table.shift

  # Convert them to simple symbols
  attributes = []
  headers.each do |h|
      # cleanup whitespace
      prep = h
      prep.strip!
      prep.downcase!
      prep.gsub!(%r{\s}, '_')
      attributes << prep.to_sym
  end
  
  # drop the header separator line
  table.shift

  # Now each row of output gets converted to its own object
  tmp = {}
  table.each do |line|
    i = 0
    line.each do |column|
      tmp[attributes[i]] = column.strip
      i += 1
    end
  
    row = OpenStruct.new(tmp)
    if block_given?
      yield row
    else
      result << row
    end
  end
  
  result
end

.unwrap(lines = [], filter = nil, indented = EQL_CLI_WRAPPED_INDENT) ⇒ Object

break table into arrays of unwrapped data, yield array in block or return all arrays



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/eql/cli.rb', line 151

def unwrap(lines = [], filter = nil, indented = EQL_CLI_WRAPPED_INDENT) #:nodoc:
  previous_columns = nil
  rows = []
 
  if filter.nil?
    filter = get_filter(lines)
  end
 
  collecting = true
  # reversed seemed easier to parse
  lines.reverse.each do |line|
    # get our columns and drop the 'match all' entry
    columns = filter.match(line).to_a
    columns.shift
  
    # step through the columns
    i = 0
    columns.each do |field|
      # wrapped entries begin with indentation, its the only way to tell
      # they are wrapped.
      if field =~ %r{^#{indented}}
        # we are building a line
        collecting = true
      else
        # assume its done
        collecting = false
      end
      if previous_columns.nil? == false and previous_columns[i].nil? == false
        # append the last lines data to this new one, drop the indendation
        columns[i] << previous_columns[i][(indented.length)..(previous_columns[i].length)]
      end
      i += 1
    end
  
    # collect finished lines and reset 
    if collecting == false
      rows << columns 
      previous_columns = nil
    else
      previous_columns = columns
    end
  end
  
  rows.reverse!
  
  if block_given?
    rows.each do |row|
      yield row
    end
  else
    rows
  end
end