terraform 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +7 -5
- data/Rakefile +10 -0
- data/lib/terraform.rb +1 -1
- data/lib/terraform/dsl.rb +144 -0
- data/lib/terraform/version.rb +1 -1
- data/terraform.gemspec +4 -1
- data/test/test_helper.rb +24 -0
- data/test/unit/terraform/dsl_test.rb +97 -0
- metadata +43 -9
- data/lib/terraform/terraform_dsl.rb +0 -125
data/README.markdown
CHANGED
@@ -1,11 +1,12 @@
|
|
1
|
-
Terraform is a small goal-oriented DSL for setting up a machine, similar in purpose to Chef and
|
2
|
-
|
1
|
+
Terraform is a small goal-oriented DSL for setting up a machine, similar in purpose to Chef and Puppet. Its
|
2
|
+
design is inspired by Babushka, but it's simpler and tailored specifically for provisioning a machine for a
|
3
|
+
webapp.
|
3
4
|
|
4
5
|
Usage
|
5
6
|
-----
|
6
7
|
|
7
8
|
require "terraform_dsl"
|
8
|
-
include
|
9
|
+
include Terraform::Dsl
|
9
10
|
dep "my library" do
|
10
11
|
met? { (check if your dependency is met) }
|
11
12
|
meet { (install your dependency) }
|
@@ -15,10 +16,11 @@ A more detailed README is coming shortly.
|
|
15
16
|
|
16
17
|
Contribute
|
17
18
|
----------
|
18
|
-
When editing this gem, to test your changes, you can load your local copy of the gem in your project by using
|
19
|
+
When editing this gem, to test your changes, you can load your local copy of the gem in your project by using
|
20
|
+
this in your Gemfile:
|
19
21
|
|
20
22
|
gem "terraform", :path => "~/p/terraform"
|
21
23
|
|
22
24
|
Credits
|
23
25
|
-------
|
24
|
-
Dmac -- thanks for the name!
|
26
|
+
Dmac -- thanks for the name!
|
data/Rakefile
CHANGED
data/lib/terraform.rb
CHANGED
@@ -5,6 +5,6 @@ module Terraform
|
|
5
5
|
# Writes the terraform_dsl.rb to the given file or directory.
|
6
6
|
def self.write_dsl_file(path)
|
7
7
|
path = File.join(path, "terraform_dsl.rb") if File.directory?(path)
|
8
|
-
FileUtils.cp(File.expand_path(File.join(File.dirname(__FILE__), "terraform/
|
8
|
+
FileUtils.cp(File.expand_path(File.join(File.dirname(__FILE__), "terraform/dsl.rb")), path)
|
9
9
|
end
|
10
10
|
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "digest/md5"
|
3
|
+
|
4
|
+
module Terraform
|
5
|
+
module Dsl
|
6
|
+
def dep(name)
|
7
|
+
@dependencies ||= []
|
8
|
+
# If a dep gets required or defined twice, only run it once.
|
9
|
+
return if @dependencies.find { |dep| dep[:name] == name }
|
10
|
+
@dependencies.push(@current_dependency = { :name => name })
|
11
|
+
yield
|
12
|
+
fail_and_exit "Error: no 'met?' block defined for dep '#{name}'." unless @current_dependency[:met?]
|
13
|
+
fail_and_exit "Error: no 'meet' block defined for dep '#{name}'." unless @current_dependency[:meet]
|
14
|
+
end
|
15
|
+
def met?(&block) @current_dependency[:met?] = block end
|
16
|
+
def meet(&block) @current_dependency[:meet] = block end
|
17
|
+
def in_path?(command) `which #{command}`.size > 0 end
|
18
|
+
def fail_and_exit(message) puts message; exit 1 end
|
19
|
+
|
20
|
+
# Runs a command and raises an exception if its exit status was nonzero.
|
21
|
+
# - silent: if false, log the command being run and its stdout. False by default.
|
22
|
+
# - check_exit_code: raises an error if the command had a non-zero exit code. True by default.
|
23
|
+
def shell(command, options = {})
|
24
|
+
silent = (options[:silent] != false)
|
25
|
+
puts command unless silent
|
26
|
+
output = `#{command}`
|
27
|
+
puts output unless output.empty? || silent
|
28
|
+
raise "#{command} had a failure exit status of #{$?.to_i}" unless $?.to_i == 0
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
def satisfy_dependencies
|
33
|
+
STDOUT.sync = true # Ensure that we flush logging output as we go along.
|
34
|
+
@dependencies.each do |dep|
|
35
|
+
unless dep[:met?].call
|
36
|
+
puts "* Dependency #{dep[:name]} is not met. Meeting it."
|
37
|
+
dep[:meet].call
|
38
|
+
fail_and_exit %Q("met?" for #{dep[:name]} is still false after running "meet".) unless dep[:met?].call
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# These are very common tasks which are needed by almost everyone, and so they're bundled with this DSL.
|
45
|
+
#
|
46
|
+
|
47
|
+
def package_installed?(package) `dpkg -s #{package} 2> /dev/null | grep Status`.match(/\sinstalled/) end
|
48
|
+
def install_package(package)
|
49
|
+
# Specify a noninteractive frontend, so dpkg won't prompt you for info. -q is quiet; -y is "answer yes".
|
50
|
+
shell "sudo DEBIAN_FRONTEND=noninteractive apt-get install -qy #{package}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def ensure_packages(*packages) packages.each { |package| ensure_package(package) } end
|
54
|
+
def ensure_package(package)
|
55
|
+
dep "package: #{package}" do
|
56
|
+
met? { package_installed?(package) }
|
57
|
+
meet { install_package(package) }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Ensure an Ubuntu PPA is installed. The argument is the ppa location, in the form ppa:[USER]/[NAME]
|
62
|
+
def ensure_ppa(ppa)
|
63
|
+
ppa_part, location = ppa.split(":", 2)
|
64
|
+
fail_and_exit("PPA location must be of the form ppa:[USER]/[NAME]") unless (ppa_part == "ppa") && location
|
65
|
+
# The python-software-properties package provides the add-apt-repository convenience tool for editing
|
66
|
+
# the list of apt's source repositories.
|
67
|
+
ensure_package("python-software-properties")
|
68
|
+
dep "ppa: #{location}" do
|
69
|
+
met? { !`apt-cache policy 2> /dev/null | grep ppa.launchpad.net/#{location}/`.empty? }
|
70
|
+
meet do
|
71
|
+
shell "sudo add-apt-repository #{ppa}"#, :silent => true
|
72
|
+
shell "sudo apt-get update"#, :silent => true
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def gem_installed?(gem) `gem list '#{gem}'`.include?(gem) end
|
78
|
+
|
79
|
+
def ensure_gem(gem)
|
80
|
+
dep "gem: #{gem}" do
|
81
|
+
met? { gem_installed?(gem) }
|
82
|
+
meet { shell "gem install #{gem} --no-ri --no-rdoc" }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Ensures the file at dest_path is exactly the same as the one in source_path.
|
87
|
+
# Invokes the given block if the file is changed. Use this block to restart a service, for instance.
|
88
|
+
def ensure_file(source_path, dest_path, &on_change)
|
89
|
+
dep "file: #{dest_path}" do
|
90
|
+
met? do
|
91
|
+
raise "This file does not exist: #{source_path}" unless File.exists?(source_path)
|
92
|
+
File.exists?(dest_path) && (Digest::MD5.file(source_path) == Digest::MD5.file(dest_path))
|
93
|
+
end
|
94
|
+
meet do
|
95
|
+
FileUtils.cp(source_path, dest_path)
|
96
|
+
on_change.call if on_change
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# A task which must be run once to be 'met'. For instance, this might be the DB migration script.
|
102
|
+
def ensure_run_once(name, &block)
|
103
|
+
dep "run task once: #{name}" do
|
104
|
+
has_run_once = false
|
105
|
+
met? { has_run_once }
|
106
|
+
meet do
|
107
|
+
yield
|
108
|
+
has_run_once = true
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def ensure_rbenv
|
114
|
+
ensure_package "git-core"
|
115
|
+
dep "rbenv" do
|
116
|
+
met? { in_path?("rbenv") }
|
117
|
+
meet do
|
118
|
+
# These instructions are from https://github.com/sstephenson/rbenv/wiki/Using-rbenv-in-Production
|
119
|
+
shell "wget -q -O - https://raw.github.com/fesplugas/rbenv-installer/master/bin/rbenv-installer | bash"
|
120
|
+
# We need to run rbenv init after install, which adjusts the path. If exec is causing us problems
|
121
|
+
# down the road, we can perhaps simulate running rbenv init without execing.
|
122
|
+
unless ARGV.include?("--forked-after-rbenv") # To guard against an infinite forking loop.
|
123
|
+
exec "bash -c 'source ~/.bashrc; #{$0} --forked-after-rbenv'" # $0 is the current process's name.
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# ruby_version is a rbenv ruby version string like "1.9.2-p290".
|
130
|
+
def ensure_rbenv_ruby(ruby_version)
|
131
|
+
ensure_rbenv
|
132
|
+
ensure_packages "curl", "build-essential", "libxslt1-dev", "libxml2-dev", "libssl-dev"
|
133
|
+
|
134
|
+
dep "rbenv ruby: #{ruby_version}" do
|
135
|
+
met? { `which ruby`.include?("rbenv") && `ruby -v`.include?(ruby_version.gsub("-", "")) }
|
136
|
+
meet do
|
137
|
+
puts "Compiling Ruby will take a few minutes."
|
138
|
+
shell "rbenv install #{ruby_version}"
|
139
|
+
shell "rbenv rehash"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
data/lib/terraform/version.rb
CHANGED
data/terraform.gemspec
CHANGED
@@ -15,6 +15,9 @@ Gem::Specification.new do |s|
|
|
15
15
|
|
16
16
|
s.files = `git ls-files`.split("\n")
|
17
17
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
19
19
|
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_development_dependency "scope", "~> 0.2.3"
|
22
|
+
s.add_development_dependency "rr", "~> 1.0.4"
|
20
23
|
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "bundler/setup"
|
2
|
+
require "minitest/autorun"
|
3
|
+
require "scope"
|
4
|
+
require "rr"
|
5
|
+
require "stringio"
|
6
|
+
|
7
|
+
$:.unshift(File.join(File.dirname(__FILE__), "../lib"))
|
8
|
+
|
9
|
+
module Scope
|
10
|
+
class TestCase
|
11
|
+
include RR::Adapters::MiniTest
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module Kernel
|
16
|
+
def capture_output
|
17
|
+
result = StringIO.new
|
18
|
+
$stdout = result
|
19
|
+
yield
|
20
|
+
result.string
|
21
|
+
ensure
|
22
|
+
$stdout = STDOUT
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "../../test_helper.rb"))
|
2
|
+
require "terraform/dsl"
|
3
|
+
|
4
|
+
class DslTest < Scope::TestCase
|
5
|
+
include Terraform::Dsl
|
6
|
+
|
7
|
+
class ProcessExit < StandardError; end
|
8
|
+
|
9
|
+
# Methods to mock for met? and meet blocks
|
10
|
+
def do_met() end
|
11
|
+
def do_meet() end
|
12
|
+
|
13
|
+
setup do
|
14
|
+
stub(self).fail_and_exit(anything) { raise ProcessExit }
|
15
|
+
end
|
16
|
+
|
17
|
+
context "dep declarations" do
|
18
|
+
should "fail if there is no met? or meet given" do
|
19
|
+
assert_raises(ProcessExit) do
|
20
|
+
dep("no met?") { meet {} }
|
21
|
+
end
|
22
|
+
assert_raises(ProcessExit) do
|
23
|
+
dep("no meet") { met? {} }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
should "not run meet if met? is satisfied" do
|
28
|
+
mock(self).do_met { true }
|
29
|
+
mock(self).do_meet.never
|
30
|
+
dep "foo" do
|
31
|
+
met? { do_met }
|
32
|
+
meet { do_meet }
|
33
|
+
end
|
34
|
+
satisfy_dependencies
|
35
|
+
end
|
36
|
+
|
37
|
+
should "run meet if met? is not satisfied" do
|
38
|
+
met_run = false
|
39
|
+
mock(self).do_met.twice { result = met_run; met_run = true; result }
|
40
|
+
mock(self).do_meet
|
41
|
+
dep "foo" do
|
42
|
+
met? { do_met }
|
43
|
+
meet { do_meet }
|
44
|
+
end
|
45
|
+
message = capture_output { satisfy_dependencies }
|
46
|
+
assert_match /Dependency foo is not met/, message
|
47
|
+
end
|
48
|
+
|
49
|
+
should "only meet a dep once" do
|
50
|
+
met_run = false
|
51
|
+
mock(self).do_met.twice { result = met_run; met_run = true; result }
|
52
|
+
mock(self).do_meet
|
53
|
+
2.times do
|
54
|
+
dep "foo" do
|
55
|
+
met? { do_met }
|
56
|
+
meet { do_meet }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
capture_output { satisfy_dependencies }
|
60
|
+
end
|
61
|
+
|
62
|
+
should "fail if met? still fails after running meet" do
|
63
|
+
mock(self).do_met.twice { false }
|
64
|
+
mock(self).do_meet
|
65
|
+
dep "foo" do
|
66
|
+
met? { do_met }
|
67
|
+
meet { do_meet }
|
68
|
+
end
|
69
|
+
assert_raises(ProcessExit) { capture_output { satisfy_dependencies } }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "ensure_ppa" do
|
74
|
+
should "fail if the PPA name is not the expected form" do
|
75
|
+
assert_raises(ProcessExit) { ensure_ppa("blah") }
|
76
|
+
assert_raises(ProcessExit) { ensure_ppa("http://some.ppa.url") }
|
77
|
+
end
|
78
|
+
|
79
|
+
# TODO(caleb): Add more unit tests. Having trouble coming up with unit tests that don't feel
|
80
|
+
# fragile/artificial. For helpers like these, integration tests of some kind that run on a vagrant box or
|
81
|
+
# something may prove more useful.
|
82
|
+
end
|
83
|
+
|
84
|
+
context "ensure_run_once" do
|
85
|
+
should "run a task exactly once" do
|
86
|
+
mock(self).do_meet.never
|
87
|
+
meet_run = false
|
88
|
+
ensure_run_once("foo") { meet_run = true }
|
89
|
+
dep "run task once: foo" do
|
90
|
+
met? { do_met }
|
91
|
+
meet { do_meet }
|
92
|
+
end
|
93
|
+
capture_output { satisfy_dependencies }
|
94
|
+
assert meet_run
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: terraform
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Phil Crosby
|
@@ -15,10 +15,41 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-03-
|
18
|
+
date: 2012-03-27 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
|
-
dependencies:
|
21
|
-
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: scope
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 17
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 2
|
33
|
+
- 3
|
34
|
+
version: 0.2.3
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rr
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 31
|
46
|
+
segments:
|
47
|
+
- 1
|
48
|
+
- 0
|
49
|
+
- 4
|
50
|
+
version: 1.0.4
|
51
|
+
type: :development
|
52
|
+
version_requirements: *id002
|
22
53
|
description:
|
23
54
|
email:
|
24
55
|
- phil.crosby@gmail.com
|
@@ -34,9 +65,11 @@ files:
|
|
34
65
|
- README.markdown
|
35
66
|
- Rakefile
|
36
67
|
- lib/terraform.rb
|
37
|
-
- lib/terraform/
|
68
|
+
- lib/terraform/dsl.rb
|
38
69
|
- lib/terraform/version.rb
|
39
70
|
- terraform.gemspec
|
71
|
+
- test/test_helper.rb
|
72
|
+
- test/unit/terraform/dsl_test.rb
|
40
73
|
has_rdoc: true
|
41
74
|
homepage: http://github.com/philc/terraform
|
42
75
|
licenses: []
|
@@ -71,5 +104,6 @@ rubygems_version: 1.6.2
|
|
71
104
|
signing_key:
|
72
105
|
specification_version: 3
|
73
106
|
summary: Set up a cold, inhospitable system using Terraform.
|
74
|
-
test_files:
|
75
|
-
|
107
|
+
test_files:
|
108
|
+
- test/test_helper.rb
|
109
|
+
- test/unit/terraform/dsl_test.rb
|
@@ -1,125 +0,0 @@
|
|
1
|
-
# This is small goal-oriented DSL for installing system components, similar in purpose to Chef and Puppet.
|
2
|
-
# Its design is inspired by Babushka but it's simpler and tailored specifically for provisioning a machine
|
3
|
-
# for a webapp.
|
4
|
-
#
|
5
|
-
# Usage:
|
6
|
-
#
|
7
|
-
# require "terraform_dsl"
|
8
|
-
# include TerraformDsl
|
9
|
-
# dep "my library" do
|
10
|
-
# met? { (check if your dependency is met) }
|
11
|
-
# meet { (install your dependency) }
|
12
|
-
# end
|
13
|
-
|
14
|
-
require "fileutils"
|
15
|
-
require "digest/md5"
|
16
|
-
|
17
|
-
module TerraformDsl
|
18
|
-
def dep(name)
|
19
|
-
@dependencies ||= []
|
20
|
-
# If a dep gets required or defined twice, only run it once.
|
21
|
-
return if @dependencies.find { |dep| dep[:name] == name }
|
22
|
-
@dependencies.push(@current_dependency = { :name => name })
|
23
|
-
yield
|
24
|
-
end
|
25
|
-
def met?(&block) @current_dependency[:met?] = block end
|
26
|
-
def meet(&block) @current_dependency[:meet] = block end
|
27
|
-
def in_path?(command) `which #{command}`.size > 0 end
|
28
|
-
def fail_and_exit(message) puts message; exit 1 end
|
29
|
-
|
30
|
-
# Runs a command and raises an exception if its exit status was nonzero.
|
31
|
-
# - silent: if false, log the command being run and its stdout. False by default.
|
32
|
-
# - check_exit_code: raises an error if the command had a non-zero exit code. True by default.
|
33
|
-
def shell(command, options = {})
|
34
|
-
silent = (options[:silent] != false)
|
35
|
-
puts command unless silent
|
36
|
-
output = `#{command}`
|
37
|
-
puts output unless output.empty? || silent
|
38
|
-
raise "#{command} had a failure exit status of #{$?.to_i}" unless $?.to_i == 0
|
39
|
-
true
|
40
|
-
end
|
41
|
-
|
42
|
-
def satisfy_dependencies
|
43
|
-
STDOUT.sync = true # Ensure that we flush logging output as we go along.
|
44
|
-
@dependencies.each do |dep|
|
45
|
-
unless dep[:met?].call
|
46
|
-
puts "* Dependency #{dep[:name]} is not met. Meeting it."
|
47
|
-
dep[:meet].call
|
48
|
-
fail_and_exit %Q("met?" for #{dep[:name]} is still false after running "meet".) unless dep[:met?].call
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
#
|
54
|
-
# These are very common tasks which are needed by almost everyone, and so they're bundled with this DSL.
|
55
|
-
#
|
56
|
-
|
57
|
-
def package_installed?(package) `dpkg -s #{package} 2> /dev/null | grep Status`.match(/\sinstalled/) end
|
58
|
-
def install_package(package)
|
59
|
-
# Specify a noninteractive frontend, so dpkg won't prompt you for info. -q is quiet; -y is "answer yes".
|
60
|
-
shell "sudo DEBIAN_FRONTEND=noninteractive apt-get install -qy #{package}"
|
61
|
-
end
|
62
|
-
|
63
|
-
def ensure_packages(*packages) packages.each { |package| ensure_package(package) } end
|
64
|
-
def ensure_package(package)
|
65
|
-
dep package do
|
66
|
-
met? { package_installed?(package) }
|
67
|
-
meet { install_package(package) }
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def gem_installed?(gem) `gem list '#{gem}'`.include?(gem) end
|
72
|
-
|
73
|
-
def ensure_gem(gem)
|
74
|
-
dep gem do
|
75
|
-
met? { gem_installed?(gem) }
|
76
|
-
meet { shell "gem install #{gem} --no-ri --no-rdoc" }
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
# Ensures the file at dest_path is exactly the same as the one in source_path.
|
81
|
-
# Invokes the given block if the file is changed. Use this block to restart a service, for instance.
|
82
|
-
def ensure_file(source_path, dest_path, &on_change)
|
83
|
-
dep dest_path do
|
84
|
-
met? do
|
85
|
-
raise "This file does not exist: #{source_path}" unless File.exists?(source_path)
|
86
|
-
File.exists?(dest_path) && (Digest::MD5.file(source_path) == Digest::MD5.file(dest_path))
|
87
|
-
end
|
88
|
-
meet do
|
89
|
-
FileUtils.cp(source_path, dest_path)
|
90
|
-
on_change.call if on_change
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def ensure_rbenv
|
96
|
-
ensure_package "git-core"
|
97
|
-
dep "rbenv" do
|
98
|
-
met? { in_path?("rbenv") }
|
99
|
-
meet do
|
100
|
-
# These instructions are from https://github.com/sstephenson/rbenv/wiki/Using-rbenv-in-Production
|
101
|
-
shell "wget -q -O - https://raw.github.com/fesplugas/rbenv-installer/master/bin/rbenv-installer | bash"
|
102
|
-
# We need to run rbenv init after install, which adjusts the path. If exec is causing us problems
|
103
|
-
# down the road, we can perhaps simulate running rbenv init without execing.
|
104
|
-
unless ARGV.include?("--forked-after-rbenv") # To guard against an infinite forking loop.
|
105
|
-
exec "bash -c 'source ~/.bashrc; #{$0} --forked-after-rbenv'" # $0 is the current process's name.
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
# ruby_version is a rbenv ruby version string like "1.9.2-p290".
|
112
|
-
def ensure_rbenv_ruby(ruby_version)
|
113
|
-
ensure_rbenv
|
114
|
-
ensure_packages "curl", "build-essential", "libxslt1-dev", "libxml2-dev", "libssl-dev"
|
115
|
-
|
116
|
-
dep "rbenv ruby #{ruby_version}" do
|
117
|
-
met? { `which ruby`.include?("rbenv") && `ruby -v`.include?(ruby_version.gsub("-", "")) }
|
118
|
-
meet do
|
119
|
-
puts "Compiling Ruby will take a few minutes."
|
120
|
-
shell "rbenv install #{ruby_version}"
|
121
|
-
shell "rbenv rehash"
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|