overlay 1.1.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.rdoc +47 -7
- data/app/controllers/overlay/github_controller.rb +4 -7
- data/lib/overlay/configuration.rb +103 -9
- data/lib/overlay/engine.rb +1 -1
- data/lib/overlay/github.rb +183 -63
- data/lib/overlay/subscriber.rb +1 -0
- data/lib/overlay/version.rb +1 -1
- data/spec/configuration_spec.rb +145 -0
- data/spec/controllers/overlay/github_controller_spec.rb +10 -4
- data/spec/dummy/log/test.log +1527 -252
- data/spec/github_spec.rb +223 -65
- data/spec/spec_helper.rb +3 -0
- metadata +33 -7
- data/app/assets/stylesheets/overlay/application.css +0 -13
- data/app/helpers/overlay/application_helper.rb +0 -4
- data/app/views/layouts/overlay/application.html.erb +0 -14
- data/spec/dummy/log/development.log +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e7cf4853cb51c3c998a8b0d89691dd7fe769b71
|
4
|
+
data.tar.gz: a3a51bcfb29b2d56ebd16b25547c609476506afd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5dae53b5bd7073acba446d4a605341b473139bef5e763582946bf9173251474e29ce523cd65bb9e6e6cc074c6a58b0e966c8bc093ee44d4892b8717172ca43e6
|
7
|
+
data.tar.gz: 4e7f06ee20f890721b59bd548b1e1ffee3d9b75da166206518314ac52563157d94750878e1b1f8e0f043f7202129f711da8a86591c6a1dcb3e68a63cf5a6e0de
|
data/README.rdoc
CHANGED
@@ -1,15 +1,55 @@
|
|
1
|
-
|
1
|
+
Overlay
|
2
|
+
====================
|
2
3
|
|
3
|
-
|
4
|
+
Rails engine that allows for overlaying external templates onto an existing Rails application. Overlayed directories are prepended to the view path to allow overwriting of deployed templates.
|
4
5
|
|
5
|
-
|
6
|
+
Features
|
7
|
+
====================
|
6
8
|
|
7
|
-
|
9
|
+
GithubRepo Features
|
10
|
+
---------------------
|
8
11
|
|
9
|
-
|
12
|
+
* Overlay separate directories in a single repo to specific places in your Rails application.
|
13
|
+
* Update files in realtime utilizing self registering post commit webhooks on github.
|
14
|
+
* Run code on file update via the GithubRepo #after_process_hook block.
|
15
|
+
* Utilize an OverlayPublisher application and a redis server to centralize hook management and publish changes to a fleet of servers.
|
10
16
|
|
11
|
-
|
17
|
+
Installation
|
18
|
+
====================
|
12
19
|
|
13
|
-
|
20
|
+
Add the gem to your Gemfile:
|
21
|
+
|
22
|
+
gem 'overlay'
|
23
|
+
|
24
|
+
Configuration
|
25
|
+
====================
|
26
|
+
|
27
|
+
Add an initializer to your Rails `config/initializers` directory. This file should configure your repositories and launch the initial overlay. Here is a sample initializer:
|
28
|
+
|
29
|
+
require 'overlay'
|
30
|
+
|
31
|
+
Overlay.configure do |config|
|
32
|
+
config.relative_root_url = Rails.application.config.relative_url_root
|
33
|
+
|
34
|
+
github_repo = Overlay::GithubRepo.new(
|
35
|
+
'repo_org',
|
36
|
+
'repo_name',
|
37
|
+
'repo_user_user:repo_password',
|
38
|
+
'source_root_directory',
|
39
|
+
'source_destination_path'
|
40
|
+
)
|
41
|
+
config.repositories << repo_config
|
42
|
+
end
|
43
|
+
|
44
|
+
# Overlay files after rails is initialized
|
45
|
+
#
|
46
|
+
Rails.application.config.after_initialize do
|
47
|
+
Overlay::Github.instance.process_overlays
|
48
|
+
end
|
49
|
+
|
50
|
+
Usage
|
51
|
+
====================
|
52
|
+
|
53
|
+
Once Overlay is configured, on startup, a process will be forked to run the initial pull-down of files from the repository. Overlay will update specific files on change in the repo through use of Github webhooks.
|
14
54
|
|
15
55
|
This project rocks and uses MIT-LICENSE.
|
@@ -1,18 +1,15 @@
|
|
1
|
-
require_dependency "overlay/application_controller"
|
2
|
-
|
3
1
|
module Overlay
|
4
|
-
class GithubController < ApplicationController
|
2
|
+
class GithubController < Overlay::ApplicationController
|
5
3
|
def update
|
6
4
|
render nothing: true
|
7
5
|
|
8
6
|
Overlay.configuration.repositories.each do |repo_config|
|
9
7
|
next unless repo_config.class == GithubRepo
|
10
|
-
branch = repo_config
|
8
|
+
branch = repo_config.branch
|
11
9
|
|
12
10
|
if (params[:repository] && params[:ref])
|
13
|
-
if (params[:repository][:name] == repo_config
|
14
|
-
|
15
|
-
Overlay::Github.overlay_repo repo_config
|
11
|
+
if (params[:repository][:name] == repo_config.repo) && (params[:ref] == "refs/heads/#{branch}")
|
12
|
+
Overlay::Github.instance.process_hook(params, repo_config)
|
16
13
|
end
|
17
14
|
end
|
18
15
|
end
|
@@ -1,16 +1,15 @@
|
|
1
|
+
|
1
2
|
module Overlay
|
2
3
|
VALID_OPTIONS_KEYS = [
|
3
|
-
:site,
|
4
|
-
:endpoint,
|
5
|
-
:repo,
|
6
|
-
:user,
|
7
|
-
:auth,
|
8
4
|
:repositories,
|
9
5
|
:host_name,
|
10
6
|
:host_port,
|
11
7
|
:relative_root_url
|
12
8
|
].freeze
|
13
9
|
|
10
|
+
# Exceptions
|
11
|
+
class RequiredParameterError < StandardError; end
|
12
|
+
|
14
13
|
class << self
|
15
14
|
attr_accessor :configuration
|
16
15
|
end
|
@@ -28,11 +27,106 @@ module Overlay
|
|
28
27
|
end
|
29
28
|
|
30
29
|
def reset
|
31
|
-
|
32
|
-
@endpoint = 'https://api.github.com'
|
33
|
-
@repositories = Set.new
|
30
|
+
@repositories = Set.new
|
34
31
|
end
|
35
32
|
end
|
36
33
|
|
37
|
-
|
34
|
+
# Configure a github repository. Required parameters:
|
35
|
+
# :org,
|
36
|
+
# :repo,
|
37
|
+
# :auth,
|
38
|
+
# :root_source_path,
|
39
|
+
# :root_dest_path
|
40
|
+
|
41
|
+
# Optional parameters:
|
42
|
+
# :branch,
|
43
|
+
# :use_publisher
|
44
|
+
# :registration_address
|
45
|
+
# :redis_server
|
46
|
+
# :redis_port
|
47
|
+
# :endpoint,
|
48
|
+
# :site,
|
49
|
+
class GithubRepo
|
50
|
+
attr_accessor :root_source_path, :root_dest_path, :branch
|
51
|
+
attr_accessor :use_publisher, :redis_server, :redis_port, :registration_server
|
52
|
+
attr_reader :repo, :org, :auth, :endpoint, :site
|
53
|
+
|
54
|
+
# Internal repo api hook
|
55
|
+
attr_accessor :github_api
|
56
|
+
|
57
|
+
REQUIRED_PARAMS = [:org, :repo, :auth, :root_source_path]
|
58
|
+
REQUIRED_PUBLISHER_PARAMS = [:redis_server, :redis_port, :registration_server]
|
59
|
+
|
60
|
+
def initialize(org, repo, auth, root_source_path, root_dest_path)
|
61
|
+
@org = org
|
62
|
+
@repo = repo
|
63
|
+
@auth = auth
|
64
|
+
@root_source_path = root_source_path
|
65
|
+
@root_dest_path = root_dest_path
|
66
|
+
@branch = 'master'
|
67
|
+
@use_publisher = false
|
68
|
+
|
69
|
+
# Quick sanity check
|
70
|
+
validate
|
71
|
+
|
72
|
+
# Create a hook to the Github API
|
73
|
+
initialize_api
|
74
|
+
end
|
75
|
+
|
76
|
+
def endpoint=(endpoint_addr)
|
77
|
+
@endpoint = endpoint_addr
|
78
|
+
|
79
|
+
# re-initialize api
|
80
|
+
initialize_api
|
81
|
+
end
|
82
|
+
|
83
|
+
def site=(site_addr)
|
84
|
+
@site = site_addr
|
85
|
+
|
86
|
+
# re-initialize api
|
87
|
+
initialize_api
|
88
|
+
end
|
89
|
+
|
90
|
+
# Make sure that this configuration has all required parameters
|
91
|
+
def validate
|
92
|
+
REQUIRED_PARAMS.each do |param|
|
93
|
+
raise RequiredParameterError, "Overlay GithubRepo missing required paramater: #{param}" if (send(param).nil? || send(param).empty?)
|
94
|
+
end
|
95
|
+
|
96
|
+
# If we are using a publisher, check required publisher params
|
97
|
+
if @use_publisher
|
98
|
+
REQUIRED_PUBLISHER_PARAMS.each do |param|
|
99
|
+
raise RequiredParameterError, "Overlay GithubRepo missing required paramater: #{param}" if (send(param).nil?)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Add code to be called after processing a hook
|
105
|
+
def after_process_hook(&hook)
|
106
|
+
raise ArgumentError, "No block given" unless block_given?
|
107
|
+
@post_hook = hook
|
108
|
+
end
|
109
|
+
|
110
|
+
# Run post_hook code
|
111
|
+
def post_hook
|
112
|
+
@post_hook.call unless @post_hook.nil?
|
113
|
+
end
|
114
|
+
|
115
|
+
# Retrieve API hook to repo
|
116
|
+
def initialize_api
|
117
|
+
::Github.reset!
|
118
|
+
::Github.configure do |github_config|
|
119
|
+
github_config.endpoint = @endpoint if @endpoint
|
120
|
+
github_config.site = @site if @site
|
121
|
+
github_config.basic_auth = @auth
|
122
|
+
github_config.repo = @repo
|
123
|
+
github_config.org = @org
|
124
|
+
github_config.adapter = :net_http
|
125
|
+
github_config.ssl = {:verify => false}
|
126
|
+
end
|
127
|
+
|
128
|
+
@github_api = ::Github::Repos.new
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
38
132
|
end
|
data/lib/overlay/engine.rb
CHANGED
data/lib/overlay/github.rb
CHANGED
@@ -1,40 +1,104 @@
|
|
1
1
|
require 'github_api'
|
2
2
|
require 'fileutils'
|
3
3
|
require 'socket'
|
4
|
-
|
4
|
+
require 'singleton'
|
5
|
+
require 'redis'
|
6
|
+
|
7
|
+
# The github class is responsible for managing overlaying
|
8
|
+
# directories in a Github repo on the current application.
|
9
|
+
# Call to action is based on either a webhook call to the github controller
|
10
|
+
# or a publish event to a redis key.
|
11
|
+
#
|
5
12
|
module Overlay
|
6
13
|
class Github
|
14
|
+
include Singleton
|
7
15
|
include Overlay::Engine.routes.url_helpers
|
16
|
+
|
17
|
+
attr_accessor :subscribed_configs
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@subscribed_configs = []
|
21
|
+
end
|
22
|
+
|
8
23
|
# Cycle through all configured repositories and overlay
|
9
|
-
#
|
10
|
-
|
24
|
+
# This function should be called only at initialization time as it causes a
|
25
|
+
# full overlay to be run
|
26
|
+
def process_overlays
|
11
27
|
# This can be called in an application initializer which will
|
12
28
|
# load anytime the environment is loaded. Make sure we are prepared to run
|
13
29
|
# this.
|
14
30
|
#
|
15
31
|
return unless (config.host_port || ENV['SERVER_HOST_PORT'] || defined? Rails::Server)
|
16
32
|
|
17
|
-
# Configure github api
|
18
|
-
configure
|
19
|
-
|
20
33
|
Overlay.configuration.repositories.each do |repo_config|
|
21
34
|
next unless repo_config.class == GithubRepo
|
22
35
|
|
23
|
-
#
|
24
|
-
|
25
|
-
|
36
|
+
# Register this server's endpoint as a webhook or subscribe
|
37
|
+
# to a redis pub/sub
|
38
|
+
if repo_config.use_publisher
|
39
|
+
publisher_subscribe(repo_config)
|
40
|
+
else
|
41
|
+
register_web_hook(repo_config)
|
42
|
+
end
|
26
43
|
|
27
|
-
|
44
|
+
# Now that all the set-up is done, for a process
|
45
|
+
# to overlay the repo.
|
46
|
+
fork_it(:overlay_repo, repo_config)
|
47
|
+
end
|
48
|
+
end
|
28
49
|
|
29
|
-
|
50
|
+
# Take a hook hash and process each changelist.
|
51
|
+
# For every file updated, clone it back to us.
|
52
|
+
def process_hook hook, repo_config
|
53
|
+
# Grab the commit array
|
54
|
+
commits = hook['commits']
|
55
|
+
|
56
|
+
# We don't care if there aren't commits
|
57
|
+
return if commits.nil?
|
58
|
+
|
59
|
+
commits.each do |commit|
|
60
|
+
# There will be three entries in each commit with file paths: added, removed, and modified.
|
61
|
+
added_files = commit['added']
|
62
|
+
added_files.each do |file|
|
63
|
+
# Do we care?
|
64
|
+
if my_file?(file, repo_config)
|
65
|
+
Rails.logger.info "Overlay found added file in hook: #{file}"
|
66
|
+
|
67
|
+
# Make sure that the directory is in place
|
68
|
+
FileUtils.mkdir_p(destination_path(File.dirname(file), repo_config))
|
69
|
+
clone_file(file, repo_config)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
modified_files = commit['added']
|
74
|
+
modified_files.each do |file|
|
75
|
+
# Do we care?
|
76
|
+
if my_file?(file, repo_config)
|
77
|
+
Rails.logger.info "Overlay found modified file in hook: #{file}"
|
78
|
+
clone_file(file, repo_config)
|
79
|
+
end
|
80
|
+
end
|
30
81
|
|
31
|
-
|
82
|
+
removed_files = commit['added']
|
83
|
+
removed_files.each do |file|
|
84
|
+
# Do we care?
|
85
|
+
if my_file?(file, repo_config)
|
86
|
+
Rails.logger.info "Overlay found deleted file in hook: #{file}"
|
87
|
+
File.delete(destination_path(file, repo_config))
|
88
|
+
end
|
89
|
+
end
|
32
90
|
end
|
91
|
+
|
92
|
+
# Call post hook code
|
93
|
+
repo_config.post_hook
|
33
94
|
end
|
34
95
|
|
96
|
+
private
|
97
|
+
|
35
98
|
# Register our listener on the repo
|
36
99
|
#
|
37
|
-
def
|
100
|
+
def register_web_hook(repo_config)
|
101
|
+
Rails.logger.info "Overlay register webhook for repo: org => #{repo_config.org}, repo => #{repo_config.repo}"
|
38
102
|
# Make sure our routes are loaded
|
39
103
|
Rails.application.reload_routes!
|
40
104
|
|
@@ -44,46 +108,78 @@ module Overlay
|
|
44
108
|
path = Overlay::Engine.routes.url_for({:controller=>"overlay/github", :action=>"update", :only_path => true})
|
45
109
|
uri = ActionDispatch::Http::URL::url_for({:host => host, :port => port, :path => "#{config.relative_root_url}#{path}"})
|
46
110
|
|
111
|
+
github_api = repo_config.github_api
|
112
|
+
|
47
113
|
# Retrieve current web hooks
|
48
|
-
current_hooks =
|
114
|
+
current_hooks = github_api.hooks.list(repo_config.org, repo_config.repo).response.body
|
49
115
|
if current_hooks.find {|hook| hook.config.url == uri}.nil?
|
50
116
|
# register hook
|
51
|
-
|
117
|
+
github_api.hooks.create(repo_config.org, repo_config.repo, name: 'web', active: true, config: {:url => uri, :content_type => 'json'})
|
52
118
|
end
|
53
119
|
end
|
54
120
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
121
|
+
# Retrieve Subscribe to a OverlayPublisher redis key
|
122
|
+
# Fork a process that subscribes to the redis key and processes updates.
|
123
|
+
def publisher_subscribe repo_config
|
124
|
+
return unless @subscribed_configs.find_index(repo_config).nil?
|
125
|
+
|
126
|
+
# Validate our settings
|
127
|
+
repo_config.validate
|
128
|
+
|
129
|
+
# Register this repo with the manager
|
130
|
+
uri = URI.parse(repo_config.registration_server)
|
131
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
132
|
+
request = Net::HTTP::Post.new("/register")
|
133
|
+
request.add_field('Content-Type', 'application/json')
|
134
|
+
request.body = {
|
135
|
+
'organization' => repo_config.org,
|
136
|
+
'repo' => repo_config.repo,
|
137
|
+
'auth' => repo_config.auth,
|
138
|
+
'endpoint' => repo_config.endpoint,
|
139
|
+
'site' => repo_config.site
|
140
|
+
}.to_json
|
141
|
+
|
142
|
+
response = http.request(request)
|
143
|
+
|
144
|
+
# Retrieve publish key
|
145
|
+
publish_key = JSON.parse(response.read_body)['publish_key']
|
146
|
+
|
147
|
+
Rails.logger.info "Overlay subscribing to redis channel: #{publish_key}"
|
148
|
+
|
149
|
+
# Subscribe to redis channel
|
150
|
+
fork_it(:subscribe_to_channel, publish_key, repo_config)
|
151
|
+
|
152
|
+
@subscribed_configs << repo_config
|
153
|
+
end
|
154
|
+
|
155
|
+
# Overlay all the files specifiec by the repo_config. This
|
156
|
+
# process can be long_running so we fork. We should only be running
|
157
|
+
# this method in initialization of the application.
|
158
|
+
def overlay_repo repo_config
|
159
|
+
Rails.logger.info "Overlay started processing repo with config #{repo_config.inspect}"
|
160
|
+
|
161
|
+
# Get our root entries
|
162
|
+
root = repo_config.root_source_path || '/'
|
163
|
+
|
164
|
+
# If we have a root defined, jump right into it
|
165
|
+
if root != '/'
|
166
|
+
overlay_directory(root, repo_config)
|
167
|
+
else
|
168
|
+
root_entries = repo_config.github_api.contents.get(repo_config.org, repo_config.repo, root, ref: repo_config.branch).response.body
|
169
|
+
|
170
|
+
# We aren't pulling anything out of root. Cycle through directories and overlay
|
171
|
+
root_entries.each do |entry|
|
172
|
+
if entry.type == 'dir'
|
173
|
+
overlay_directory(entry.path, repo_config)
|
75
174
|
end
|
76
175
|
end
|
77
|
-
Rails.logger.info "Finished processing repo with config #{repo_config.inspect}"
|
78
176
|
end
|
177
|
+
Rails.logger.info "Overlay finished processing repo with config #{repo_config.inspect}"
|
79
178
|
end
|
80
179
|
|
81
|
-
def
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
FileUtils.mkdir_p "#{root_path}/#{dynamic_path}"
|
86
|
-
directory_entries = github_repo.contents.get(repo_config[:user], repo_config[:repo], path, ref: repo_config[:branch]).response.body
|
180
|
+
def overlay_directory path, repo_config
|
181
|
+
FileUtils.mkdir_p destination_path(path, repo_config)
|
182
|
+
directory_entries = repo_config.github_api.contents.get(repo_config.org, repo_config.repo, path, ref: repo_config.branch).response.body
|
87
183
|
|
88
184
|
directory_entries.each do |entry|
|
89
185
|
if entry.type == 'dir'
|
@@ -94,36 +190,60 @@ module Overlay
|
|
94
190
|
end
|
95
191
|
end
|
96
192
|
|
97
|
-
def
|
98
|
-
|
99
|
-
|
193
|
+
def clone_file path, repo_config
|
194
|
+
file = repo_config.github_api.contents.get(repo_config.org, repo_config.repo, path, ref: repo_config.branch).response.body.content
|
195
|
+
File.open(destination_path(path, repo_config), "wb") { |f| f.write(Base64.decode64(file)) }
|
196
|
+
Rails.logger.info "Overlay cloned file: #{path}"
|
197
|
+
end
|
198
|
+
|
199
|
+
# Fork a new process and subscribe to a redis channel
|
200
|
+
def subscribe_to_channel key, repo_config
|
201
|
+
redis = Redis.new(:timeout => 30, :host => repo_config.redis_server, :port => repo_config.redis_port)
|
202
|
+
|
203
|
+
# This key is going to receive a publish event
|
204
|
+
# for any changes to the target repo. We need to verify
|
205
|
+
# that the payload references our branch and our watch direstory
|
206
|
+
redis.subscribe(key) do |on|
|
207
|
+
on.message do |channel, msg|
|
208
|
+
Rails.logger.info "Overlay received publish event for channel #{publish_key} with payload: #{msg}"
|
209
|
+
hook = JSON.parse(msg)
|
210
|
+
|
211
|
+
# Make sure this is the branch we are watching
|
212
|
+
if (hook['ref'] == "refs/heads/#{repo_config.branch}")
|
213
|
+
Rails.logger.info "Overlay enqueueing Github hook processing job for repo: #{repo_config.repo} and branch: #{repo_config.branch}"
|
214
|
+
process_hook(hook, repo_config)
|
215
|
+
Rails.logger.info "Overlay done processing job for repo: #{repo_config.repo} and branch: #{repo_config.branch}"
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
100
220
|
|
101
|
-
|
102
|
-
|
221
|
+
def my_file? file_path, repo_config
|
222
|
+
return true if repo_config.root_dest_path.empty?
|
223
|
+
file_path.starts_with?(repo_config.root_source_path)
|
103
224
|
end
|
104
225
|
|
105
|
-
|
226
|
+
def root_path repo_config
|
227
|
+
repo_config.root_dest_path.empty? ? "#{Rails.application.root}" : "#{Rails.application.root}/#{repo_config.root_dest_path}"
|
228
|
+
end
|
106
229
|
|
107
|
-
def
|
108
|
-
|
230
|
+
def destination_path file_path, repo_config
|
231
|
+
raise "The file #{file_path} isn't handled by this repo with root path: #{repo_config.root_source_path}" unless my_file?(file_path, repo_config)
|
232
|
+
dynamic_path = file_path.partition(repo_config.root_source_path).last
|
233
|
+
return "#{root_path(repo_config)}#{dynamic_path}"
|
109
234
|
end
|
110
235
|
|
111
|
-
def
|
112
|
-
|
236
|
+
def config
|
237
|
+
@overlay_config ||= Overlay.configuration
|
113
238
|
end
|
114
239
|
|
115
|
-
#
|
116
|
-
def
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
::Github.configure do |github_config|
|
121
|
-
github_config.endpoint = config.endpoint if config.endpoint
|
122
|
-
github_config.site = config.site if config.site
|
123
|
-
github_config.basic_auth = config.auth
|
124
|
-
github_config.adapter = :net_http
|
125
|
-
github_config.ssl = {:verify => false}
|
240
|
+
# Process the passed in function symbol and args in a fork
|
241
|
+
def fork_it method, *args
|
242
|
+
pid = Process.fork do
|
243
|
+
send(method, *args)
|
244
|
+
Process.exit
|
126
245
|
end
|
246
|
+
Process.detach(pid)
|
127
247
|
end
|
128
248
|
end
|
129
249
|
end
|