module Prick module Build class Parser def self.parse(conn, dir) Parser.new(conn).parse(dir).unit # [parser.unit, parser.schemas] end attr_reader :conn attr_reader :dir attr_reader :unit # attr_reader :schemas def initialize(conn) @conn = conn end def parse(dir) @dir = dir # @schemas = {} parse_directory(nil, dir) self end private # First build unit is a RootBuildNode, the rest are regular BuildNode objects def make_build_unit(parent, path) if @unit BuildNode.new(parent, path) else @unit = RootBuildNode.new(conn, path) end end def parse_directory(parent, dir) build_file = "#{dir}/build.yml".sub(/\/\//, "/") if File.exist? build_file parse_build_file(parent, dir, build_file) else raise Error, "Can't find build.yml in #{dir}" end end def parse_build_file(parent, dir, path) unit = make_build_unit(parent, path) entries = YAML.load(File.read(path)) || [] entries.each { |entry| if entry.is_a?(Hash) entry.each { |key, value| if key == "schema" unit.schema = value elsif key == "standard" unit.pg_graph_ignore_schema = !value elsif key == "refresh" unit.refresh_schema = value else case key when "init"; unit.init_nodes when "term"; unit.term_nodes when "seed"; unit.seed_nodes else raise Error, "Illegal key in #{unit.path}: #{key}" end.concat(Array(value).map { |value| parse_entry(unit, key.to_sym, dir, value) }) end } else node = parse_entry(unit, :decl, dir, entry) if node.kind == :fox unit.seed_nodes << node else unit.decl_nodes << node end end } unit end def parse_file_entry(dir, entry) name = entry.dup name.sub!(/\$ENVIRONMENT/, Prick.state.environment.to_s) name.sub!(/\/$/, "") if name =~ /^(\S+)\s+(.*)$/ # exe file = $1 args = $2.split else file = name end path = "#{dir}/#{file}" [path, name, file, args] end def parse_entry(unit, phase, dir, entry) if entry.is_a?(Hash) entry.size == 1 or raise Error, "sql and module are single-line values" key, value = entry.first case key when "sql" InlineNode.new(unit, phase, unit.path, value) when "call" args = value.split(/\s+/) args.size >= 3 or raise "Illegal number of arguments: #{value}" file, klass, command, args = *args ModuleNode.new(unit, phase, "#{dir}/#{file}", klass, command, args) when "exec" path, name, file, args = parse_file_entry(dir, value) ExeNode.new(unit, phase, path, args) else raise Error, "Illegal key: #{key}" end else path, name, file, args = parse_file_entry(dir, entry) if File.directory? path parse_directory(unit, path) elsif File.file? path case path when /\.sql$/ SqlNode.new(unit, phase, path) when /\.fox$/ FoxNode.new(unit, :seed, path) else if File.executable? path ExeNode.new(unit, phase, path, args) else raise Error, "Unrecognized file type #{File.basename(path)} in #{dir}" end end else raise Error, "Can't find #{name} in #{dir} from #{unit}" end end end end end end