class CFA::AugeasParser

@example read, print, modify and serialize again

require "cfa/augeas_parser"

parser = CFA::AugeasParser.new("Sysconfig.lns")
parser.file_name = "/etc/default/grub" # for error reporting
data = parser.parse(File.read("/etc/default/grub"))

puts data["GRUB_DISABLE_OS_PROBER"]
data["GRUB_DISABLE_OS_PROBER"] = "true"
puts parser.serialize(data)

Attributes

file_name[RW]

@return [String] optional, used for error reporting

Public Class Methods

new(lens) click to toggle source

@param lens [String] a lens name, like “Sysconfig.lns”

# File lib/cfa/augeas_parser.rb, line 378
def initialize(lens)
  @lens = lens
  @file_name = nil
end

Public Instance Methods

empty() click to toggle source

@return [AugeasTree] an empty tree that can be filled

for future serialization
# File lib/cfa/augeas_parser.rb, line 426
def empty
  AugeasTree.new
end
parse(raw_string) click to toggle source

@param raw_string [String] a string to be parsed @return [AugeasTree] the parsed data

# File lib/cfa/augeas_parser.rb, line 385
def parse(raw_string)
  require "cfa/augeas_parser/reader"
  # Workaround for augeas lenses that don't handle files
  # without a trailing newline (bsc#1064623, bsc#1074891, bsc#1080051
  # and gh#hercules-team/augeas#547)
  raw_string += "\n" unless raw_string.end_with?("\n")
  @old_content = raw_string

  # open augeas without any autoloading and it should not touch disk and
  # load lenses as needed only
  root = load_path = nil
  Augeas.open(root, load_path, Augeas::NO_MODL_AUTOLOAD) do |aug|
    aug.set("/input", raw_string)
    report_error(aug, :parsing, file_name, raw_string) \
      unless aug.text_store(@lens, "/input", "/store")

    return AugeasReader.read(aug, "/store")
  end
end
serialize(data) click to toggle source

@param data [AugeasTree] the data to be serialized @return [String] a string to be written

# File lib/cfa/augeas_parser.rb, line 407
def serialize(data)
  require "cfa/augeas_parser/writer"
  # open augeas without any autoloading and it should not touch disk and
  # load lenses as needed only
  root = load_path = nil
  Augeas.open(root, load_path, Augeas::NO_MODL_AUTOLOAD) do |aug|
    aug.set("/input", @old_content || "")
    aug.text_store(@lens, "/input", "/store") if @old_content
    AugeasWriter.new(aug).write("/store", data)

    res = aug.text_retrieve(@lens, "/input", "/store", "/output")
    report_error(aug, :serializing, file_name, data) unless res

    return aug.get("/output")
  end
end

Private Instance Methods

aug_get_error(aug) click to toggle source
# File lib/cfa/augeas_parser.rb, line 467
def aug_get_error(aug)
  {
    message: aug.get("/augeas/text/store/error/message"),
    line:    aug.get("/augeas/text/store/error/line"),
    char:    aug.get("/augeas/text/store/error/char"), # column
    # file, line+column range, like
    # "/usr/share/augeas/lenses/dist/hosts.aug:23.12-.42:"
    lens:    aug.get("/augeas/text/store/error/lens")
  }
end
report_activity_error!(args, activity, data) click to toggle source
# File lib/cfa/augeas_parser.rb, line 454
def report_activity_error!(args, activity, data)
  case activity
  when :parsing
    args[:file_content] = data
    raise AugeasParsingError, args
  when :serializing
    args[:aug_tree] = data
    raise AugeasSerializingError, args
  else
    raise ArgumentError, "invalid activity #{activity.inspect}"
  end
end
report_error(aug, activity, file_name, data = nil) click to toggle source

@param aug [::Augeas] @param activity [:parsing, :serializing] for better error messages @param file_name [String,nil] a file name @param data [AugeasTree, String] used data so augeas tree for

serializing or file content for parsing
# File lib/cfa/augeas_parser.rb, line 437
def report_error(aug, activity, file_name, data = nil)
  report_internal_error!(aug)

  file_name ||= "(unknown file)"
  args = aug_get_error(aug)
  args[:file] = file_name
  report_activity_error!(args, activity, data)
end
report_internal_error!(aug) click to toggle source
# File lib/cfa/augeas_parser.rb, line 446
def report_internal_error!(aug)
  error = aug.error
  # zero is no error, so there's a problem in the lens
  return if error[:code].zero?

  raise AugeasInternalError.new(error[:message], error[:details])
end