module Pione module Component # InvalidPackageError raises when the package is something bad. class InvalidPackageError < StandardError attr_reader :package def initialize(package, msg) @package = package @msg = msg end def message @msg end end # Package is a container of rules, script, scenario, and etc. class Package include SimpleIdentity attr_reader :info attr_reader :bin attr_reader :scenarios attr_reader :documents attr_reader :rules attr_reader :params forward_as_key :@info, "PackageName", :name # @param info [Hash] # package information table # @param bin [Location] # package bin directory # @param scenarios [Array<PackageScenario>] # scenarios # @param documents [Array<Document>] # PIONE documents def initialize(info, bin, scenarios, documents) @info = info @bin = bin @scenarios = scenarios @documents = documents build_rules build_params end # Return the package entry rule. # # @return [Rule] # entry rule def main @rules["&%s:Main" % name].tap{|x| x.condition.params.merge!(@params)} end # Return the named rule. # # @param [String] name # rule path # @return [Rule] # the rule def [](name) @rules[name].params.merge!(@params) @rules[name] end # Return root rule. # # @param prams [Parameters] # root parameters # @return [RootRule] # root rule def root_rule(params) Component::RootRule.new(main, @params.merge(params)) end # Upload the package files to the location. # # @return [void] def upload(dest) if @bin.exist? # upload bin files @bin.entries.each do |entry| entry.copy(dest + name + "bin" + entry.basename) end end end # Find scenario that have the name. # # @param name [String] # scenario name # @return [PackageScenario] # the scenario def find_scenario(name) if name == :anything @scenarios.first else @scenarios.find {|scenario| scenario.name == name} end end private # Build rules from all documents in the package. def build_rules @rules = {} @documents.each do |doc| doc.rules.each do |name, rule| unless @rules[name] @rules[name] = rule else raise InvalidPackage.new(self, "duplicated rules: %s" % name) end end end end # Build parameters from all documents in the package. def build_params @params = Model::Parameters.empty @documents.each do |doc| doc.params.each do |param| @params.merge!(param) end end end end # PackageReader is a reader for packages. class PackageReader # @param location [Location] # package location def initialize(location) @location = location end # Read the package. # # @return [Package] # the package def read infos = read_package_info bin = @location + "bin" scenarios = find_scenarios documents = find_documents(infos["PackageName"]) Package.new(infos, bin, scenarios, documents) end private # Read the informations from the package location. # # @return [Hash] # package information table def read_package_info YAML.load((@location + "package.yml").read) rescue Location::NotFound raise InvalidPackageError.new(self, "package.yml not found in %s" % @location.uri) end # Find scenarios from the package location. # # @return [Array<PackageScenario>] # scenarios def find_scenarios if (@location + "scenario" + "scenario.yml").exist? [PackageScenarioReader.read(@location + "scenario")] else if (@location + "scenario").exist? and (@location + "scenario").directory? (@location + "scenario").entries.map do |scenario| PackageScenarioReader.read(scenario) end.compact else [] end end end # Find documents from the packcage location. # # @return [Array<Document>] # documents def find_documents(package_name) @location.entries.select do |entry| entry.file? and entry.path.extname == ".pione" end.map {|entry| Document.load(entry, package_name) } end end # PackageScenario is a class for expected scenario of rule's behavior. class PackageScenario include SimpleIdentity attr_reader :location attr_reader :info forward_as_key :@info, "ScenarioName", :name # @param location [BasicLocation] # scenario location # @param info [Hash] # scenario information table def initialize(location, info) @location = location @info = info end # Return the input location. If the scenario doesn't have input location, # return nil. # # @return [BasicLocation] # the input location def input input_location = @location + "input" input_location if input_location.exist? end # Return the output location. # # @return [BasicLocation] # the output location def output @location + "output" end end # PackageScenarioReader is a reader for loading scenarios. class PackageScenarioReader def self.read(location) new(location).read end # @param location [Location] # the scenario location def initialize(location) @location = location end # Read scenario files. # # @return [PackageScenario] # the scenario def read begin info = read_scenario_informations PackageScenario.new(@location, info) rescue nil end end private # Read scenario information table. # # @return [Hash] # scenario information table def read_scenario_informations path = @location + "scenario.yml" if path.exist? YAML.load(path.read) else {"ScenarioName" => @location.basename} end end end end end