class IDL::GenFile

Constants

REGEN_MARKER_DEFAULT

Attributes

content[R]
ext[R]
fullpath[R]
name[R]
path[R]

Public Class Methods

new(path, opts = {}) click to toggle source
# File lib/ridl/genfile.rb, line 95
def initialize(path, opts = {})
  if path
    @path = path
    @fullpath = File.expand_path(path)
    @name = File.basename(path)
    @ext = File.extname(path).sub(/^\./, '')
  else
    @path = @fullpath = @name = @ext = ''
  end
  @options = {
    regenerate: false,
    regen_marker_prefix: '//',
    regen_marker_postfix: nil,
    regen_marker: REGEN_MARKER_DEFAULT,
    regen_keep_header: true,
    output_file: nil,
    create_missing_dir: false
  }.merge(opts)
  if @options[:regenerate] && File.exist?(@fullpath)
    parse_regeneration_content
  else
    @content = Content.new
  end
  @fout = @options[:output_file] || Tempfile.new(@name)
  self.class.__send__(:_push, self)
end
rollback() click to toggle source
# File lib/ridl/genfile.rb, line 63
def self.rollback
  _rollback
end
transaction(&block) click to toggle source
# File lib/ridl/genfile.rb, line 52
def self.transaction(&block)
  _start_transaction
  begin
    block.call if block_given?
    _commit
  ensure
    _rollback # after successful transaction should be nothing left
    _close_transaction
  end
end

Public Instance Methods

<<(txt) click to toggle source
# File lib/ridl/genfile.rb, line 122
def <<(txt)
  @fout << txt if @fout
  self
end
_close_transaction() click to toggle source
# File lib/ridl/genfile.rb, line 28
def _close_transaction
  _stack.pop
  @transaction = _stack.last
end
_commit() click to toggle source
# File lib/ridl/genfile.rb, line 37
     def _commit
       _transaction.reject! { |fgen| fgen.save
true }
     end
_push(fgen) click to toggle source
# File lib/ridl/genfile.rb, line 47
def _push(fgen)
  _transaction << fgen if _transaction
end
_rollback() click to toggle source
# File lib/ridl/genfile.rb, line 42
     def _rollback
       _transaction.reject! { |fgen| fgen.remove
true } if _transaction
     end
_stack() click to toggle source
# File lib/ridl/genfile.rb, line 20
def _stack
  @stack ||= []
end
_start_transaction() click to toggle source
# File lib/ridl/genfile.rb, line 24
def _start_transaction
  _stack << (@transaction = [])
end
_transaction() click to toggle source
# File lib/ridl/genfile.rb, line 33
def _transaction
  @transaction
end
regen_end_marker(sectionid) click to toggle source
# File lib/ridl/genfile.rb, line 131
def regen_end_marker(sectionid)
  "#{@options[:regen_marker_prefix]}#{@options[:regen_marker]} - END : #{sectionid}#{@options[:regen_marker_postfix]}"
end
regen_header_end_marker(sectionid) click to toggle source
# File lib/ridl/genfile.rb, line 135
def regen_header_end_marker(sectionid)
  "#{@options[:regen_marker_prefix]}#{@options[:regen_marker]} - HEADER_END : #{sectionid}#{@options[:regen_marker_postfix]}"
end
regen_start_marker(sectionid) click to toggle source
# File lib/ridl/genfile.rb, line 127
def regen_start_marker(sectionid)
  "#{@options[:regen_marker_prefix]}#{@options[:regen_marker]} - BEGIN : #{sectionid}#{@options[:regen_marker_postfix]}"
end
remove() click to toggle source
# File lib/ridl/genfile.rb, line 201
def remove
  return if @options[:output_file]

  if @fout
    begin
      @fout.close(true)
    rescue
      IDL.log(0, %Q{ERROR: FAILED to clean up temp file #{@fout.path}: #{$!}})
    end
    @fout = nil
  end
end
save() click to toggle source
# File lib/ridl/genfile.rb, line 158
def save
  return if @options[:output_file]

  if @fout
    fgen = @fout
    @fout = nil
    fgen.close(false) # close but do NOT unlink
    if File.exist?(@fullpath)
      # create temporary backup
      ftmp = Tempfile.new(@name)
      ftmp_name = ftmp.path.dup
      ftmp.close(true) # close AND unlink
      FileUtils::mv(@fullpath, ftmp_name) # backup existing file
      # replace original
      begin
        # rename newly generated file
        FileUtils.mv(fgen.path, @fullpath)
        # preserve file mode
        FileUtils.chmod(File.lstat(ftmp_name).mode, @fullpath)
      rescue
        IDL.log(0, %Q{ERROR: FAILED updating #{@path}: #{$!}})
        # restore backup
        FileUtils.mv(ftmp_name, @fullpath)
        raise
      end
      # remove backup
      File.unlink(ftmp_name)
    else
      unless File.directory?(File.dirname(@fullpath))
        unless @options[:create_missing_dir]
          IDL.log(0, %Q{ERROR: Cannot access output folder #{File.dirname(@fullpath)}})
          exit(1)
        end
        FileUtils.mkdir_p(File.dirname(@fullpath))
      end
      # just rename newly generated file
      FileUtils.mv(fgen.path, @fullpath)
      # set default mode for new files
      FileUtils.chmod(0666 - File.umask, @fullpath)
    end
  end
end
write_regen_section(sectionid, options = {}) { || ... } click to toggle source
# File lib/ridl/genfile.rb, line 139
   def write_regen_section(sectionid, options = {})
     indent = options[:indent] || ''
     self << indent << regen_start_marker(sectionid) << "\n" unless options[:header]
     if content.has_section?(sectionid)
       self << content[sectionid].join unless content[sectionid].empty?
     elsif block_given?
       yield # block should yield default content
     elsif default_content = options[:default_content]
       default_content = (Array === default_content) ? default_content : default_content.to_s.split("\n")
       self << (default_content.collect { |l| (s = indent.dup) << l << "\n"
s }.join) unless default_content.empty?
     end
     if options[:header]
       self << indent << regen_header_end_marker(sectionid) << "\n"
     else
       self << indent << regen_end_marker(sectionid) << "\n" unless options[:footer]
     end
   end

Private Instance Methods

parse_regeneration_content() click to toggle source
# File lib/ridl/genfile.rb, line 216
def parse_regeneration_content
  markers_sel = %w{BEGIN END}
  _keep_header = (@options[:regen_keep_header] == true)
  markers_sel << 'HEADER_END' if _keep_header
  regen_marker_re = /#{@options[:regen_marker]}\s+[-]\s+(#{markers_sel.join('|')})\s+:\s+(.+)/
  sections = {}
  section = []
  in_section = _keep_header ? ['HEADER', 0] : nil
  linenr = 0
  File.open(@fullpath) do |fio|
    fio.each do |line|
      linenr += 1
      if regen_marker_re =~ line
        case $1
        when 'BEGIN'
          raise "ERROR: Found unterminated regeneration section starting at #{@path}:#{in_section.last}." if in_section

          in_section = [$2, linenr]
          section = []
        when 'END'
          raise "ERROR: Found unmatched regeneration end at #{@path}:#{linenr}." unless in_section && ($2 == in_section.first)

          sections[$2] = section
          in_section = nil
          section = []
        when 'HEADER_END'
          raise "ERROR: Found illegal header end marker at #{@path}:#{linenr}." unless _keep_header && in_section &&
                                                                                                     ('HEADER' == in_section.first ) && (in_section.last.zero?)

          sections[$2] = section
          in_section = nil
          section = []
        else
          raise "ERROR: Found invalid regeneration marker at #{@path}:#{linenr}."
        end
      elsif in_section
        section << line
      end
    end
  end
  sections[in_section.first] = section if in_section
  @content = Content.new(sections)
end