service/src/service/service_definition.cr

158 lines
3.9 KiB
Crystal

require "yaml"
require "specparser"
class ServiceDefinition
struct Consumes
getter token : String
getter optional : Bool
def initialize(@token)
@optional = false
if @token.match /\?$/
@token = @token.gsub /\?$/, ""
@optional = true
end
end
end
struct Provides
getter token : String
def initialize(@token)
end
end
struct Hook
getter name : String
getter command : String
getter unless_directory : String?
getter unless_file : String?
def initialize(@name, @command, @unless_file = nil, @unless_directory = nil)
end
def initialize(section : SpecParser::Section)
@name = section.content["name"].as_s
@command = section.content["command"].as_s
@unless_directory = section.content["unless-directory"]?
.try &.as_s
@unless_file = section.content["unless-file"]?.try &.as_s
end
end
struct PortDefinition
getter name : String
getter default_value : Int32?
def initialize(string : String)
match = string.match(/([^?=]*)(=([^?]*))?/).not_nil!
@name = match[1]
@default_value = match[3]?.try &.to_i
end
end
class_getter all = [] of ServiceDefinition
getter name : String
getter command : String
getter stop_command : String?
getter directory : String?
getter user : String?
getter provides : String?
getter consumes : Array(Consumes)
getter environment_variables : Array(String)
getter pre_start_hooks : Array(Hook)
getter provides : Array(Provides)
getter port_definitions : Array(PortDefinition)
getter requires_domain = false
def initialize(@name, specs : SpecParser)
sections = specs.sections
specs = specs.assignments
@command = specs["command"].as_s
@stop_command = specs["stop-command"]?.try &.as_s
@directory = specs["directory"]?.try &.as_s
@user = specs["user"]?.try &.as_s
@provides = specs["provides"]?.try &.as_a_or_s.map { |x| Provides.new x } || Array(Provides).new
@consumes = specs["consumes"]?.try &.as_a_or_s.map { |x| Consumes.new x } || Array(Consumes).new
@environment_variables = specs["environment-variables"]?.try &.as_a_or_s || Array(String).new
@port_definitions = specs["ports"]?.try &.as_a_or_s.map { |x| PortDefinition.new x } || Array(PortDefinition).new
# FIXME: as_b?
requires_domain = specs["requires-domain"]?.try &.as_s
case requires_domain
when nil
when "true", "yes"
@requires_domain = true
when "false", "no"
@requires_domain = false
else
STDERR.puts "warning: definition '#{@name}' has a 'requires-domain' entry with an invalid value"
end
@pre_start_hooks = Array(Hook).new
sections.each do |section|
case section.name
when "pre-start"
@pre_start_hooks << Hook.new section
when "directory"
directory = section.options[0]?
name = section.content["name"]?.try &.as_s
if directory.nil?
STDERR.puts "warning: (#{@name}) %directory was not provided a path"
next
end
pre_start_hooks << Hook.new (name || "directory: #{directory}"),
"mkdir -p \"#{directory}\"",
unless_directory: directory
when "configuration"
options = section.options[0].split /[ \t]/
template = options[0]?
target = options[1]?
name = section.content["name"]?.try &.as_s
if template.nil? || target.nil?
STDERR.puts "warning: (#{@name}) %configuration received less than 2 options"
next
end
pre_start_hooks << Hook.new (name || "configuration file: #{template}"),
"gen-config \"#{template}\" \"#{target}\"",
unless_file: target
end
end
end
def self.load(path)
Dir.each_child path do |child|
if child.match /\.spec$/
name = File.basename(child, ".spec")
specs = SpecParser.parse File.read "#{path}/#{child}"
@@all << ServiceDefinition.new name, specs
else
next
end
end
end
def self.get(name) : ServiceDefinition
_def = @@all.find &.name.==(name)
if _def.nil?
raise ::Service::Exception.new "Service '#{name}' does not exist."
end
_def
end
def to_s
name
end
end