jannishuebl/orchparty

View on GitHub
lib/orchparty/dsl_parser_kubernetes.rb

Summary

Maintainability
C
1 day
Test Coverage
require 'pathname'
require 'securerandom'
module Orchparty
  module Kubernetes
    class DSLParser
      attr_reader :filename

      def initialize(filename)
        @filename = filename
      end

      def parse
        file_content = File.read(filename)
        builder = RootBuilder.new
        builder.instance_eval(file_content, filename)
        builder._build
      end
    end

    class Builder
      def self.build(*args, block)
        builder = self.new(*args)
        builder.instance_eval(&block) if block
        builder._build
      end

      def assign_or_merge(node, key, value)
        if node[key]
          node[key] = node[key].deep_merge_concat(value)
        else
          node[key] = value
        end
      end
    end

    class RootBuilder < Builder

      def initialize
        @root = AST.root
      end

      def import(rel_file)
        old_file_path = Pathname.new(caller[0][/[^:]+/]).parent
        rel_file_path = Pathname.new rel_file
        new_file_path = old_file_path + rel_file_path
        file_content = File.read(new_file_path)
        instance_eval(file_content, new_file_path.expand_path.to_s)
      end

      def application(name, &block)
        @root.applications[name] = ApplicationBuilder.build(name, block)
        self
      end

      def mixin(name, &block)
        @root._mixins[name] = MixinBuilder.build(name, block)
        self
      end

      def _build
        @root
      end
    end

    class MixinBuilder < Builder

      def initialize(name)
        @mixin = AST.mixin(name: name)
      end

      def template(path)
        chart_name = "_mixin_temp_name"
        unless @mixin.services[chart_name]
          @mixin.services[chart_name] = AST.chart(name: chart_name, _type: "chart" )
          @mixin._service_order << chart_name
        end
        chart = @mixin.services[chart_name]
        chart.template = path
        self
      end

      def service(name, &block)

        chart_name = "_mixin_temp_name"
        unless @mixin.services[chart_name]
          @mixin.services[chart_name] = AST.chart(name: chart_name, _type: "chart" )
          @mixin._service_order << chart_name
        end
        chart = @mixin.services[chart_name]

        result = ServiceBuilder.build(name, "chart-service", block)

        name = "chart-#{chart.name}-#{name}"
        @mixin.services[name] = result
        @mixin._service_order << name
        chart._services << name
        self
      end

      def helm(name, &block)
        result = ServiceBuilder.build(name, "helm", block)
        @mixin.services[name] = result
        @mixin._mixins[name] = result
        self
      end


      def apply(name, &block)
        result = ServiceBuilder.build(name, "apply", block)
        @mixin.services[name] = result
        @mixin._mixins[name] = result
        self
      end

      def mixin(name, &block)
        @mixin._mixins[name] = ServiceMixinBuilder.build(name, block)
      end

      def volumes(&block)
        @mixin.volumes = HashBuilder.build(block)
      end

      def networks(&block)
        @mixin.networks = HashBuilder.build(block)
      end

      def _build
        @mixin
      end
    end

    class ApplicationBuilder < Builder

      def initialize(name)
        @application = AST.application(name: name)
      end

      def mix(name)
        @application._mix << name
      end

      def mixin(name, &block)
        @application._mixins[name] = ApplicationMixinBuilder.build(block)
        self
      end

      def all(&block)
        @application.all = AllBuilder.build(block)
        self
      end

      def variables(&block)
        @application._variables = VariableBuilder.build(block)
        self
      end

      def volumes(&block)
        @application.volumes = HashBuilder.build(block)
        self
      end

      def helm(name, &block)
        result = ServiceBuilder.build(name, "helm", block)
        @application.services[name] = result
        @application._service_order << name
        self
      end

      def label(&block)
        name = SecureRandom.hex
        result = ServiceWithoutNameBuilder.build("label", block)
        @application.services[name] = result
        @application._service_order << name
        self
      end

      def apply(name, &block)
        result = ServiceBuilder.build(name, "apply", block)
        @application.services[name] = result
        @application._service_order << name
        self
      end

      def secret_generic(name, &block)
        result = ServiceBuilder.build(name, "secret_generic", block)
        @application.services[name] = result
        @application._service_order << name
        self
      end

      def wait(&block)
        name = SecureRandom.hex
        result = ServiceBuilder.build(name, "wait", block)
        @application.services[name] = result
        @application._service_order << name
        self
      end

      def chart(name, &block)
        @application.services[name] = ChartBuilder.build(name, @application, "chart", block)
        @application._service_order << name
        self
      end

      def template(path)
        chart_name = @application.name
        unless @application.services[chart_name]
          @application.services[chart_name] = AST.chart(name: chart_name, _type: "chart" )
          @application._service_order << chart_name
        end
        chart = @application.services[chart_name]
        chart.template = path
        self
      end

      def service(name, &block)

        chart_name = @application.name
        unless @application.services[chart_name]
          @application.services[chart_name] = AST.chart(name: chart_name, _type: "chart" )
          @application._service_order << chart_name
        end
        chart = @application.services[chart_name]

        result = ServiceBuilder.build(name, "chart-service", block)

        name = "chart-#{chart.name}-#{name}"
        @application.services[name] = result
        @application._service_order << name
        chart._services << name
        self
      end

      def _build
        @application
      end
    end

    class HashBuilder < Builder

      def method_missing(_, *values, &block)
        if block_given?
          value = HashBuilder.build(block)
          if values.count == 1
            @hash ||= AST.hash
            @hash[values.first.to_sym] = value
          else
            @hash ||= AST.array
            @hash << value
          end
        else
          value = values.first
          if value.is_a? Hash
            @hash ||= AST.hash
            key, value = value.first
            @hash[key.to_sym] = value
          else
            @hash ||= AST.array
            @hash << value
          end
        end
        self
      end

      def _build
        @hash
      end
    end

    class VariableBuilder < HashBuilder
      def _build
        super || {}
      end
    end

    class CommonBuilder < Builder

      def initialize(node)
        @node = node
      end

      def mix(name)
        @node._mix << name
      end

      def method_missing(name, *values, &block)
        if block_given?
          assign_or_merge(@node, name,  HashBuilder.build(block))
        else
          assign_or_merge(@node, name, values.first)
        end
      end

      def _build
        @node
      end

      def variables(&block)
        @node._variables ||= {}
        @node._variables = @node._variables.merge(VariableBuilder.build(block))
        self
      end
    end

    class AllBuilder < CommonBuilder
      def initialize
        super AST.all
      end
    end

    class ApplicationMixinBuilder < CommonBuilder
      def initialize
        super AST.application_mixin
      end
    end

    class ServiceWithoutNameBuilder < CommonBuilder

      def initialize( type)
        super AST.service(_type: type)
      end
    end

    class ServiceBuilder < CommonBuilder

      def initialize(name, type)
        super AST.service(name: name, _type: type)
      end
    end

    class ServiceMixinBuilder < CommonBuilder

      def initialize(name)
        super AST.service(name: name)
      end
    end

    class ChartBuilder < CommonBuilder
      def initialize(name, application, type)
        super AST.chart(name: name, _type: type )
        @application = application
      end

      def service(name, &block)
        result = ServiceBuilder.build(name, "chart-service", block)

        name = "chart-#{@node.name}-#{name}"
        @application.services[name] = result
        @application._service_order << name
        @node._services << name
        self
      end
    end
  end
end