require "toolrack" require 'etc' require_relative 'template' require_relative 'command_builder' require_relative 'command_runner' module Hitcher module Docker class Mount attr_accessor :host, :docker def initialize(host = "",docker = "") @host = host @docker = docker end def hashify { host: @host, docker: @docker } end def self.parse(blc) res = [] if not (blc.nil? or blc.empty?) blc.each do |e| if e =~ /mount/ l = e.split(" ") if l.length == 2 else end elsif e =~ /,/ # handle host: /home/xxx/dev, docker: /opt/dev m = Mount.new e.split(",").each do |ee| s = ee.split(":") case s[0].strip when "host" m.host = translate(s[1].strip) when "docker" m.docker = s[1].strip else raise Hitcher::Error, "Unknown mount point key '#{s[0]}'" end end res << m elsif e =~ /:/ # handle host:docker ==> /home/xxx/dev:/opt/dev ee = e.split(":") m = Mount.new m.host = translate(ee[0].strip) m.docker = ee[1].strip res << m end end end res end # parse def self.translate(key) case key.upcase when "$PWD","." Dir.getwd else if key =~ /../ File.expand_path(key) else key end end end end # class Mount class Port attr_accessor :host, :docker def initialize(host = nil, docker = nil) @host = host @docker = docker end def hashify { host: @host, docker: @docker } end end # class Port # # class Dockerfile # class Dockerfile include Antrapol::ToolRack::ConditionUtils attr_reader :cont def parse(blc) @cont = [] if not (blc.nil? or blc.empty?) blc.each do |e| if e =~ /dockerfile/ l = e.split(" ") if l.length == 2 # no parameters else # todo extract parameters end elsif e.strip != "end" @cont << translate(e.strip) end end end end def is_empty? @cont.nil? or @cont.empty? end private def translate(line) if not line.strip.empty? if line =~ /\$USER/ line = line.gsub("$USER", user_info.name) end if line =~ /\$UID/ line = line.gsub("$UID", "#{user_info.uid}") end if line =~ /\$GID/ line = line.gsub("$GID", "#{user_info.gid}") end end line end def user_info if @userInfo.nil? login = Etc.getlogin @userInfo = Etc.getpwnam(login) end @userInfo end end # class Dockerfile ## ## Module Dsl ## module Dsl include Antrapol::ToolRack::ConditionUtils attr_reader :image, :cName, :df, :mounts, :exposes, :interactive_mode, :tty_mode def image_name(name) @image = name end def container_name(name) @cName = name end def block_kw?(kw) ["dockerfile","mount"].include?(kw.to_s) end def handle_block(kw,blc) send(kw,blc) end def dockerfile(blc) @df = Dockerfile.new @df.parse(blc) end def mount(blc) @mounts = Mount.parse(blc) end def interactive(val) @interactive_mode = val end def tty(val) @tty_mode = val end def expose(port) if not port.nil? @exposes = [] if @exposes.nil? po = Port.new if port.to_s =~ /:/ ppo = port.to_s.split(":") po.host = ppo[0] po.docker = ppo[1] else # only single value is given po.docker = port po.host = port end @exposes << po end end # expose ## ## End of DSL ## def command if @builder.nil? @builder = DockerCommandBuilder.new end @builder end def command_executor if @exec.nil? @exec = DockerCommandExecutor.new(self) end @exec end # # Operation # def gen(depth = :all) @logger.debug "Generate output files!" te = Hitcher::Docker::TemplateEngine.new if (depth == :dockerfile or depth == :all) and not @df.nil? te.build_template(:dockerfile, { image: @image, dockerfile: @df.cont }) @logger.debug "Dockerfile generated" end if depth == :build_container or depth == :all te.build_template(:build_container, { image_name: @image }) @logger.debug "build_container generated" end if depth == :run_script or depth == :all # run script mm = @mounts.collect { |m| m.hashify } pp = @exposes.collect { |po| po.hashify } params = { mounts: mm, ports: pp, container_name: @cName, image: @image } params[:interactive] = @interactive_mode if not_empty?(@interactive_mode) params[:tty] = @tty_mode if not_empty?(@tty_mode) te.build_template(:run_container, params) @logger.debug "run_container generated" end if depth == :start_container or depth == :all params = { container_name: @cName } params[:interactive] = @interactive_mode if not_empty?(@interactive_mode) params[:tty] = @tty_mode if not_empty?(@tty_mode) te.build_template(:start_container, params) @logger.debug "start_container generated" end if depth == :container_prompt or depth == :all params = { container_name: @cName } params[:interactive] = @interactive_mode if not_empty?(@interactive_mode) params[:tty] = @tty_mode if not_empty?(@tty_mode) te.build_template(:container_prompt, params) @logger.debug "container_prompt generated" end @logger.debug "Sample script generated successfully" end # generate output files end # module Dsl # initialize dynamically by # DSL method container() class DockerDsl include Hitcher::Docker::Dsl def initialize(opts = { logger: Hitcher::Global.instance.glog }) @logger = opts[:logger] || Hitcher::Global.instance.glog end end # class DockerDsl end end