Class: Hoosegow

Inherits:
Object
  • Object
show all
Defined in:
lib/hoosegow.rb,
lib/hoosegow/docker.rb,
lib/hoosegow/protocol.rb,
lib/hoosegow/exceptions.rb,
lib/hoosegow/image_bundle.rb

Defined Under Namespace

Modules: Protocol Classes: Docker, Error, ImageBuildError, ImageBundle, InmateImportError, InmateRuntimeError

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Hoosegow

Public: Initialize a Hoosegow instance.

options -

:no_proxy     - Development mode. Use this if you don't want to
                setup Docker on your development instance, but
                still need to test rendering files. This is how
                Hoosegow runs inside the Docker container.
:inmate_dir   - Dependency directory to be coppied to the hoosegow
                image. This should include a file called
               `inmate.rb` that defines a Hoosegow::Inmate module.
:image_name   - The name of the Docker image to use. If this isn't
                specified, we will infer the image name from the
                hash the files present.
:ruby_version - The Ruby version to install in the Docker
                container (Default RUBY_VERSION).
:socket       - Path to Unix socket where Docker daemon is
                running. (optional. defaults to
                "/var/run/docker.sock")
:host         - IP or hostname where Docker daemon is running.
                Don't set this if Docker is listening locally on a
                Unix socket.
:port         - TCP port where Docker daemon is running. Don't set
                this if Docker is listening locally on a Unix
                socket.


31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/hoosegow.rb', line 31

def initialize(options = {})
  options         = options.dup
  @no_proxy       = options.delete(:no_proxy)
  @inmate_dir     = options.delete(:inmate_dir) || '/hoosegow/inmate'
  @image_name     = options.delete(:image_name)
  @ruby_version   = options.delete(:ruby_version) || RUBY_VERSION
  @docker_options = options
  load_inmate_methods

  # Don't want to have to require these in the container.
  unless no_proxy?
    require 'tmpdir'
    require 'fileutils'
    require 'open3'
    require 'digest'
  end
end

Instance Method Details

#build_image(&block) ⇒ Object

Public: Build a Docker image from the Dockerfile in the root directory of the gem.

Returns build output text. Raises ImageBuildError if there is a problem.



134
135
136
# File 'lib/hoosegow.rb', line 134

def build_image(&block)
  docker.build_image image_name, image_bundle.tarball, &block
end

#cleanupObject

Public: We create/start a container after every run to reduce latency. This needs to be called before the process ends to cleanup that remaining container.

Returns nothing.



118
119
120
121
# File 'lib/hoosegow.rb', line 118

def cleanup
  docker.stop_container
  docker.delete_container
end

#image_bundleObject

Public: The thing that defines which files go into the docker image tarball.



50
51
52
53
54
55
56
57
# File 'lib/hoosegow.rb', line 50

def image_bundle
  @image_bundle ||=
    Hoosegow::ImageBundle.new.tap do |image|
      image.add(File.expand_path('../../*', __FILE__), :ignore_hidden => true)
      image.add(File.join(@inmate_dir, "*"), :prefix => 'inmate')
      image.ruby_version = @ruby_version
    end
end

#image_exists?Boolean

Check if the Docker image exists.

Returns true/false.

Returns:

  • (Boolean)


126
127
128
# File 'lib/hoosegow.rb', line 126

def image_exists?
  docker.image_exist? image_name
end

#image_nameObject

Private: The name of the docker image to use. If not specified manually, this will be infered from the hash of the tarball.

Returns string image name.



142
143
144
# File 'lib/hoosegow.rb', line 142

def image_name
  @image_name || image_bundle.image_name
end

#load_inmate_methodsObject

Public: Load inmate methods from #inmate_dir/inmate.rb and hook them up to proxied to the Docker container. If we are in the container, the methods are loaded and setup to be called directly.

Returns nothing. Raises InmateImportError if there is a problem.



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/hoosegow.rb', line 87

def load_inmate_methods
  inmate_file = File.join @inmate_dir, 'inmate.rb'

  unless File.exist?(inmate_file)
    raise Hoosegow::InmateImportError, "inmate file doesn't exist"
  end

  require inmate_file

  unless Hoosegow.const_defined?(:Inmate) && Hoosegow::Inmate.is_a?(Module)
    raise Hoosegow::InmateImportError,
      "inmate file doesn't define Hoosegow::Inmate"
  end

  if no_proxy?
    self.extend Hoosegow::Inmate
  else
    inmate_methods = Hoosegow::Inmate.instance_methods
    inmate_methods.each do |name|
      define_singleton_method name do |*args, &block|
        proxy_send name, args, &block
      end
    end
  end
end

#proxy_send(name, args, &block) ⇒ Object

Public: Proxies method call to instance running in a Docker container.

name - The method to call in the Docker instance. args - Arguments that should be passed to the Docker instance method. block - A block that can be yielded to.

See docs/dispatch.md for more information.

Returns the return value from the Docker instance method.



68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/hoosegow.rb', line 68

def proxy_send(name, args, &block)
  proxy = Hoosegow::Protocol::Proxy.new(
    :stdout => $stdout,
    :stderr => $stderr,
    :yield  => block
  )
  encoded_send = proxy.encode_send(name, args)
  docker.run_container(image_name, encoded_send) do |type, msg|
    proxy.receive(type, msg)
  end

  proxy.return_value
end