pot 0.1.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 +15 -0
- data/CREDITS +32 -0
- data/LICENSE +20 -0
- data/README.md +21 -0
- data/bin/pot-console +9 -0
- data/lib/pot.rb +17 -0
- data/lib/pot/actor.rb +34 -0
- data/lib/pot/bundle.rb +66 -0
- data/lib/pot/config.rb +33 -0
- data/lib/pot/console.rb +7 -0
- data/lib/pot/deployment.rb +91 -0
- data/lib/pot/dsl.rb +39 -0
- data/lib/pot/installer.rb +131 -0
- data/lib/pot/installers/apt.rb +52 -0
- data/lib/pot/installers/binary.rb +46 -0
- data/lib/pot/installers/brew.rb +34 -0
- data/lib/pot/installers/deb.rb +41 -0
- data/lib/pot/installers/gem.rb +64 -0
- data/lib/pot/installers/group.rb +15 -0
- data/lib/pot/installers/npm.rb +19 -0
- data/lib/pot/installers/push_text.rb +49 -0
- data/lib/pot/installers/rake.rb +37 -0
- data/lib/pot/installers/replace_text.rb +45 -0
- data/lib/pot/installers/runner.rb +20 -0
- data/lib/pot/installers/source.rb +202 -0
- data/lib/pot/installers/transfer.rb +184 -0
- data/lib/pot/installers/user.rb +15 -0
- data/lib/pot/instance.rb +21 -0
- data/lib/pot/logger.rb +41 -0
- data/lib/pot/package.rb +352 -0
- data/lib/pot/policy.rb +74 -0
- data/lib/pot/role.rb +16 -0
- data/lib/pot/template.rb +20 -0
- data/lib/pot/transports/local.rb +31 -0
- data/lib/pot/transports/ssh.rb +81 -0
- data/lib/pot/verifiers/apt.rb +21 -0
- data/lib/pot/verifiers/brew.rb +21 -0
- data/lib/pot/verifiers/directory.rb +16 -0
- data/lib/pot/verifiers/executable.rb +53 -0
- data/lib/pot/verifiers/file.rb +34 -0
- data/lib/pot/verifiers/process.rb +21 -0
- data/lib/pot/verifiers/ruby.rb +25 -0
- data/lib/pot/verifiers/symlink.rb +30 -0
- data/lib/pot/verifiers/users_groups.rb +33 -0
- data/lib/pot/verify.rb +112 -0
- data/lib/pot/version.rb +13 -0
- metadata +118 -0
@@ -0,0 +1,184 @@
|
|
1
|
+
# Blatantly stole this from Chef
|
2
|
+
class TemplateError < RuntimeError
|
3
|
+
attr_reader :original_exception, :context
|
4
|
+
SOURCE_CONTEXT_WINDOW = 2 unless defined? SOURCE_CONTEXT_WINDOW
|
5
|
+
|
6
|
+
def initialize(original_exception, template, context)
|
7
|
+
@original_exception, @template, @context = original_exception, template, context
|
8
|
+
end
|
9
|
+
|
10
|
+
def message
|
11
|
+
@original_exception.message
|
12
|
+
end
|
13
|
+
|
14
|
+
def line_number
|
15
|
+
@line_number ||= $1.to_i if original_exception.backtrace.find {|line| line =~ /\(erubis\):(\d+)/ }
|
16
|
+
end
|
17
|
+
|
18
|
+
def source_location
|
19
|
+
"on line ##{line_number}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def source_listing
|
23
|
+
return nil if line_number.nil?
|
24
|
+
|
25
|
+
@source_listing ||= begin
|
26
|
+
line_index = line_number - 1
|
27
|
+
beginning_line = line_index <= SOURCE_CONTEXT_WINDOW ? 0 : line_index - SOURCE_CONTEXT_WINDOW
|
28
|
+
source_size = SOURCE_CONTEXT_WINDOW * 2 + 1
|
29
|
+
lines = @template.split(/\n/)
|
30
|
+
contextual_lines = lines[beginning_line, source_size]
|
31
|
+
output = []
|
32
|
+
contextual_lines.each_with_index do |line, index|
|
33
|
+
line_number = (index+beginning_line+1).to_s.rjust(3)
|
34
|
+
output << "#{line_number}: #{line}"
|
35
|
+
end
|
36
|
+
output.join("\n")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_s
|
41
|
+
"\n\n#{self.class} (#{message}) #{source_location}:\n\n" +
|
42
|
+
"#{source_listing}\n\n #{original_exception.backtrace.join("\n ")}\n\n"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
module Pot
|
47
|
+
module Installers
|
48
|
+
# Beware, another strange "installer" coming your way.
|
49
|
+
#
|
50
|
+
# = File transfer installer
|
51
|
+
#
|
52
|
+
# This installer pushes files from the local disk to remote servers.
|
53
|
+
#
|
54
|
+
# == Example Usage
|
55
|
+
#
|
56
|
+
# Installing a nginx.conf onto remote servers
|
57
|
+
#
|
58
|
+
# package :nginx_conf do
|
59
|
+
# transfer 'files/nginx.conf', '/etc/nginx.conf'
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# If you user has access to 'sudo' and theres a file that requires
|
63
|
+
# priveledges, you can pass :sudo => true
|
64
|
+
#
|
65
|
+
# package :nginx_conf do
|
66
|
+
# transfer 'files/nginx.conf', '/etc/nginx.conf', :sudo => true
|
67
|
+
# end
|
68
|
+
#
|
69
|
+
# By default, transfers are recursive and you can move whole directories
|
70
|
+
# via this method. If you wish to disable recursive transfers, you can pass
|
71
|
+
# recursive => false, although it will not be obeyed when using the Vlad actor.
|
72
|
+
#
|
73
|
+
# If you pass the option :render => true, this tells transfer that the source file
|
74
|
+
# is an ERB template to be rendered locally before being transferred (you can declare
|
75
|
+
# variables in the package scope). When render is true, recursive is turned off. Note
|
76
|
+
# you can also explicitly pass locals in to render with the :locals option.
|
77
|
+
#
|
78
|
+
# package :nginx_conf do
|
79
|
+
# nginx_port = 8080
|
80
|
+
# transfer 'files/nginx.conf', '/etc/nginx.conf', :render => true
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# Finally, should you need to run commands before or after the file transfer (making
|
84
|
+
# directories or changing permissions), you can use the pre/post :install directives
|
85
|
+
# and they will be run.
|
86
|
+
class Transfer < Installer
|
87
|
+
attr_accessor :source, :destination #:nodoc:
|
88
|
+
|
89
|
+
def initialize(parent, source, destination, options={}, &block) #:nodoc:
|
90
|
+
super parent, options, &block
|
91
|
+
@source = source
|
92
|
+
@destination = destination
|
93
|
+
# perform the transfer in two steps if we're using sudo
|
94
|
+
if options[:sudo]
|
95
|
+
final = @destination
|
96
|
+
@destination = "/tmp/pod_#{File.basename(@destination)}"
|
97
|
+
post :install, "sudo mv #{@destination} #{final}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def install_commands
|
102
|
+
nil
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.render_template(template, context, prefix)
|
106
|
+
require 'tempfile'
|
107
|
+
require 'erubis'
|
108
|
+
|
109
|
+
begin
|
110
|
+
eruby = Erubis::Eruby.new(template)
|
111
|
+
output = eruby.result(context)
|
112
|
+
rescue Object => e
|
113
|
+
raise TemplateError.new(e, template, context)
|
114
|
+
end
|
115
|
+
|
116
|
+
final_tempfile = Tempfile.new(prefix.to_s)
|
117
|
+
final_tempfile.print(output)
|
118
|
+
final_tempfile.close
|
119
|
+
final_tempfile
|
120
|
+
end
|
121
|
+
|
122
|
+
def render_template(template, context, prefix)
|
123
|
+
self.class.render_template(template, context, prefix)
|
124
|
+
end
|
125
|
+
|
126
|
+
def render_template_file(path, context, prefix)
|
127
|
+
template = File.read(path)
|
128
|
+
tempfile = render_template(template, context, @package.name)
|
129
|
+
tempfile
|
130
|
+
end
|
131
|
+
|
132
|
+
def process(actor) #:nodoc:
|
133
|
+
if Pot.logger.debug?
|
134
|
+
Pot.logger.debug "transfer: #{@source} -> #{@destination}\n"
|
135
|
+
end
|
136
|
+
|
137
|
+
unless Pot.config.testing?
|
138
|
+
pre = pre_commands(:install)
|
139
|
+
unless pre.empty?
|
140
|
+
sequence = pre
|
141
|
+
sequence = sequence.join('; ') if sequence.is_a? Array
|
142
|
+
Pot.logger.info "#{@package.name} pre-transfer commands: #{sequence}\n"
|
143
|
+
actor.execute [pre].flatten
|
144
|
+
end
|
145
|
+
|
146
|
+
recursive = @options[:recursive]
|
147
|
+
|
148
|
+
if options[:render]
|
149
|
+
if options[:locals]
|
150
|
+
context = {}
|
151
|
+
options[:locals].each_pair do |k,v|
|
152
|
+
if v.respond_to?(:call)
|
153
|
+
context[k] = v.call
|
154
|
+
else
|
155
|
+
context[k] = v
|
156
|
+
end
|
157
|
+
end
|
158
|
+
else
|
159
|
+
context = binding()
|
160
|
+
end
|
161
|
+
|
162
|
+
tempfile = render_template_file(@source, context, @package.name)
|
163
|
+
sourcepath = tempfile.path
|
164
|
+
Pot.logger.info "Rendering template #{@source} to temporary file #{sourcepath}"
|
165
|
+
recursive = false
|
166
|
+
else
|
167
|
+
sourcepath = @source
|
168
|
+
end
|
169
|
+
|
170
|
+
Pot.logger.info "--> Transferring #{sourcepath} to #{@destination}"
|
171
|
+
actor.transfer(sourcepath, @destination, recursive)
|
172
|
+
|
173
|
+
post = post_commands(:install)
|
174
|
+
unless post.empty?
|
175
|
+
sequence = post;
|
176
|
+
sequence = sequence.join('; ') if sequence.is_a? Array
|
177
|
+
Pot.logger.info "#{@package.name} post-transfer commands: #{sequence}\n"
|
178
|
+
actor.execute [post].flatten
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Pot
|
2
|
+
module Installers
|
3
|
+
class User < Installer
|
4
|
+
def initialize(package, username, options, &block)
|
5
|
+
super package, &block
|
6
|
+
@username = username
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
protected
|
10
|
+
def install_commands
|
11
|
+
"adduser #{@options[:flags]} #{@username}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/pot/instance.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Pot
|
2
|
+
class Instance
|
3
|
+
REGISTER = {}
|
4
|
+
|
5
|
+
attr_reader :name,
|
6
|
+
:host,
|
7
|
+
:user,
|
8
|
+
:password,
|
9
|
+
:port
|
10
|
+
|
11
|
+
def initialize(name, host, options = {})
|
12
|
+
@name = name
|
13
|
+
@host = host
|
14
|
+
@user = options[:user]
|
15
|
+
@password = options[:password]
|
16
|
+
@port = options[:port]
|
17
|
+
|
18
|
+
REGISTER[name] = self
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/pot/logger.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Pot
|
4
|
+
|
5
|
+
def self.logger
|
6
|
+
@logger ||= Pot::Logger.new
|
7
|
+
end
|
8
|
+
|
9
|
+
class Logger < ::Logger
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
super $stdout
|
13
|
+
self.formatter = proc do |severity, datetime, progname, msg|
|
14
|
+
"#{msg}\n"
|
15
|
+
end
|
16
|
+
# self.level = Logger::ERROR
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def color(code, s)
|
22
|
+
"\033[%sm%s\033[0m"%[code,s]
|
23
|
+
end
|
24
|
+
|
25
|
+
def red(s)
|
26
|
+
color(31, s)
|
27
|
+
end
|
28
|
+
|
29
|
+
def yellow(s)
|
30
|
+
color(33, s)
|
31
|
+
end
|
32
|
+
|
33
|
+
def green(s)
|
34
|
+
color(32, s)
|
35
|
+
end
|
36
|
+
|
37
|
+
def blue(s)
|
38
|
+
color(34, s)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/pot/package.rb
ADDED
@@ -0,0 +1,352 @@
|
|
1
|
+
module Pot
|
2
|
+
# = Packages
|
3
|
+
#
|
4
|
+
# A package defines one or more things to provision onto the server.
|
5
|
+
# There is a lot of flexibility in a way a package is defined but
|
6
|
+
# let me give you a basic example:
|
7
|
+
#
|
8
|
+
# package :ruby do
|
9
|
+
# description 'Ruby MRI'
|
10
|
+
# version '1.8.6'
|
11
|
+
# apt 'ruby'
|
12
|
+
#
|
13
|
+
# verify { has_executable 'ruby' }
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# The above would define a package named 'ruby' and give it a description
|
17
|
+
# and explicitly say its version. It is installed via apt and to verify
|
18
|
+
# the installation was successful pot will check for the executable
|
19
|
+
# 'ruby' being availble. Pretty simple, right?
|
20
|
+
#
|
21
|
+
# <b>Note:</b> Defining a package does not INSTALL it. To install a
|
22
|
+
# package, you must require it in a Pot::Policy block.
|
23
|
+
#
|
24
|
+
# == Pre-Requirements
|
25
|
+
#
|
26
|
+
# Most packages have some sort of pre-requisites in order to be installed.
|
27
|
+
# Pot allows you to define the requirements of the package, which
|
28
|
+
# will be installed before the package itself. An example below:
|
29
|
+
#
|
30
|
+
# package :rubygems do
|
31
|
+
# source 'http://rubyforge.org/rubygems.tgz'
|
32
|
+
# requires :ruby
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# In this case, when rubygems is being installed, Pot will first
|
36
|
+
# provision the server with Ruby to make sure the requirements are met.
|
37
|
+
# In turn, if ruby has requirements, it installs those first, and so on.
|
38
|
+
#
|
39
|
+
# == Verifications
|
40
|
+
#
|
41
|
+
# Most of the time its important to know whether the software you're
|
42
|
+
# attempting to install was installed successfully or not. For this,
|
43
|
+
# Pot provides verifications. Verifications are one or more blocks
|
44
|
+
# which define rules with which Pot can check if it installed
|
45
|
+
# the package successfully. If these verification blocks fail, then
|
46
|
+
# Pot will gracefully stop the entire process. An example below:
|
47
|
+
#
|
48
|
+
# package :rubygems do
|
49
|
+
# source 'http://rubyforge.org/rubygems.tgz'
|
50
|
+
# requires :ruby
|
51
|
+
#
|
52
|
+
# verify { has_executable 'gem' }
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# In addition to verifying an installation was successfully, by default
|
56
|
+
# Pot runs these verifications <em>before</em> the installation to
|
57
|
+
# check if the package is already installed. If the verifications pass
|
58
|
+
# before installing the package, it skips the package. To override this
|
59
|
+
# behavior, set the -f flag on the sprinkle script or set the
|
60
|
+
# :force option to true in Pot.config
|
61
|
+
#
|
62
|
+
# For more information on verifications and to see all the available
|
63
|
+
# verifications, see Pot::Verify
|
64
|
+
#
|
65
|
+
# == Virtual Packages
|
66
|
+
#
|
67
|
+
# Sometimes, there are multiple packages available for a single task. An
|
68
|
+
# example is a database package. It can contain mySQL, postgres, or sqlite!
|
69
|
+
# This is where virtual packages come in handy. They are defined as follows:
|
70
|
+
#
|
71
|
+
# package :sqlite3, :provides => :database do
|
72
|
+
# apt 'sqlite3'
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# The :provides option allows you to reference this package either by :sqlite3
|
76
|
+
# or by :database. But whereas the package name is unique, multiple packages may
|
77
|
+
# share the same provision. If this is the case, when running Pot, the
|
78
|
+
# script will ask you which provision you want to install. At this time, you
|
79
|
+
# can only install one.
|
80
|
+
#
|
81
|
+
# == Meta-Packages
|
82
|
+
#
|
83
|
+
# A package doesn't require an installer. If you want to define a package which
|
84
|
+
# merely encompasses other packages, that is fine too. Example:
|
85
|
+
#
|
86
|
+
# package :meta do
|
87
|
+
# requires :magic_beans
|
88
|
+
# requires :magic_sauce
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
#--
|
92
|
+
# FIXME: Should probably document recommendations.
|
93
|
+
#++
|
94
|
+
class Package
|
95
|
+
REGISTER = {}
|
96
|
+
|
97
|
+
attr_accessor :name,
|
98
|
+
:provides,
|
99
|
+
:installers,
|
100
|
+
:dependencies,
|
101
|
+
:recommends,
|
102
|
+
:verifications
|
103
|
+
|
104
|
+
def initialize(name, metadata = {}, &block)
|
105
|
+
raise 'No package name supplied' unless name
|
106
|
+
|
107
|
+
@name = name
|
108
|
+
@provides = metadata[:provides]
|
109
|
+
@dependencies = []
|
110
|
+
@recommends = []
|
111
|
+
@optional = []
|
112
|
+
@verifications = []
|
113
|
+
@installers = []
|
114
|
+
|
115
|
+
REGISTER[name] = self
|
116
|
+
|
117
|
+
if @provides
|
118
|
+
(REGISTER[@provides] ||= []) << self
|
119
|
+
end
|
120
|
+
|
121
|
+
self.instance_eval &block
|
122
|
+
end
|
123
|
+
|
124
|
+
def description(desc = nil)
|
125
|
+
@description = desc if desc
|
126
|
+
@description
|
127
|
+
end
|
128
|
+
|
129
|
+
def version(ver = nil)
|
130
|
+
@version = ver if ver
|
131
|
+
@version
|
132
|
+
end
|
133
|
+
|
134
|
+
def template(name)
|
135
|
+
Pot::Template.new(self, name)
|
136
|
+
end
|
137
|
+
|
138
|
+
def add_user(username, options={}, &block)
|
139
|
+
@installers << Pot::Installers::User.new(self, username, options, &block)
|
140
|
+
end
|
141
|
+
|
142
|
+
def add_group(group, options={}, &block)
|
143
|
+
@installers << Pot::Installers::Group.new(self, group, options, &block)
|
144
|
+
end
|
145
|
+
|
146
|
+
def freebsd_pkg(*names, &block)
|
147
|
+
@installers << Pot::Installers::FreebsdPkg.new(self, *names, &block)
|
148
|
+
end
|
149
|
+
|
150
|
+
def freebsd_portinstall(port, &block)
|
151
|
+
@installers << Pot::Installers::FreebsdPortinstall.new(self, port, &block)
|
152
|
+
end
|
153
|
+
|
154
|
+
def openbsd_pkg(*names, &block)
|
155
|
+
@installers << Pot::Installers::OpenbsdPkg.new(self, *names, &block)
|
156
|
+
end
|
157
|
+
|
158
|
+
def opensolaris_pkg(*names, &block)
|
159
|
+
@installers << Pot::Installers::OpensolarisPkg.new(self, *names, &block)
|
160
|
+
end
|
161
|
+
|
162
|
+
def bsd_port(port, &block)
|
163
|
+
@installers << Pot::Installers::BsdPort.new(self, port, &block)
|
164
|
+
end
|
165
|
+
|
166
|
+
def mac_port(port, &block)
|
167
|
+
@installers << Pot::Installers::MacPort.new(self, port, &block)
|
168
|
+
end
|
169
|
+
|
170
|
+
def apt(*names, &block)
|
171
|
+
@installers << Pot::Installers::Apt.new(self, *names, &block)
|
172
|
+
end
|
173
|
+
|
174
|
+
def deb(*names, &block)
|
175
|
+
@installers << Pot::Installers::Deb.new(self, *names, &block)
|
176
|
+
end
|
177
|
+
|
178
|
+
def rpm(*names, &block)
|
179
|
+
@installers << Pot::Installers::Rpm.new(self, *names, &block)
|
180
|
+
end
|
181
|
+
|
182
|
+
def yum(*names, &block)
|
183
|
+
@installers << Pot::Installers::Yum.new(self, *names, &block)
|
184
|
+
end
|
185
|
+
|
186
|
+
def zypper(*names, &block)
|
187
|
+
@installers << Pot::Installers::Zypper.new(self, *names, &block)
|
188
|
+
end
|
189
|
+
|
190
|
+
def brew(*names, &block)
|
191
|
+
@installers << Pot::Installers::Brew.new(self, *names, &block)
|
192
|
+
end
|
193
|
+
|
194
|
+
def gem(name, options = {}, &block)
|
195
|
+
@recommends << :rubygems
|
196
|
+
@installers << Pot::Installers::Gem.new(self, name, options, &block)
|
197
|
+
end
|
198
|
+
|
199
|
+
def source(source, options = {}, &block)
|
200
|
+
@recommends << :build_essential # Ubuntu/Debian
|
201
|
+
@installers << Pot::Installers::Source.new(self, source, options, &block)
|
202
|
+
end
|
203
|
+
|
204
|
+
def binary(source, options = {}, &block)
|
205
|
+
@installers << Pot::Installers::Binary.new(self, source, options, &block)
|
206
|
+
end
|
207
|
+
|
208
|
+
def rake(name, options = {}, &block)
|
209
|
+
@installers << Pot::Installers::Rake.new(self, name, options, &block)
|
210
|
+
end
|
211
|
+
|
212
|
+
def thor(name, options = {}, &block)
|
213
|
+
@installers << Pot::Installers::Thor.new(self, name, options, &block)
|
214
|
+
end
|
215
|
+
|
216
|
+
def noop(&block)
|
217
|
+
@installers << Pot::Installers::Runner.new(self, "echo noop", &block)
|
218
|
+
end
|
219
|
+
|
220
|
+
def push_text(text, path, options = {}, &block)
|
221
|
+
@installers << Pot::Installers::PushText.new(self, text, path, options, &block)
|
222
|
+
end
|
223
|
+
|
224
|
+
def replace_text(regex, text, path, options={}, &block)
|
225
|
+
@installers << Pot::Installers::ReplaceText.new(self, regex, text, path, options, &block)
|
226
|
+
end
|
227
|
+
|
228
|
+
def transfer(source, destination, options = {}, &block)
|
229
|
+
@installers << Pot::Installers::Transfer.new(self, source, destination, options, &block)
|
230
|
+
end
|
231
|
+
|
232
|
+
def runner(cmd, options = {}, &block)
|
233
|
+
@installers << Pot::Installers::Runner.new(self, cmd, options, &block)
|
234
|
+
end
|
235
|
+
|
236
|
+
def verify(description = '', &block)
|
237
|
+
@verifications << Pot::Verify.new(self, description, &block)
|
238
|
+
end
|
239
|
+
|
240
|
+
def pacman(*names, &block)
|
241
|
+
@installers << Pot::Installers::Pacman.new(self, *names, &block)
|
242
|
+
end
|
243
|
+
|
244
|
+
def process(actor)
|
245
|
+
Pot.logger.info " * #{name}"
|
246
|
+
return if meta_package?
|
247
|
+
|
248
|
+
# Run a pre-test to see if the software is already installed. If so,
|
249
|
+
# we can skip it, unless we have the force option turned on!
|
250
|
+
unless @verifications.empty? || Pot.config.force
|
251
|
+
begin
|
252
|
+
process_verifications(actor, true)
|
253
|
+
|
254
|
+
Pot.logger.info "--> #{self.name} already installed"
|
255
|
+
return
|
256
|
+
rescue Pot::VerificationFailed => e
|
257
|
+
# Continue
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
@installers.each do |installer|
|
262
|
+
installer.process(actor)
|
263
|
+
end
|
264
|
+
|
265
|
+
process_verifications(actor)
|
266
|
+
end
|
267
|
+
|
268
|
+
def process_verifications(actor, pre = false)
|
269
|
+
return if @verifications.empty?
|
270
|
+
|
271
|
+
if pre
|
272
|
+
Pot.logger.info "--> Checking if #{self.name} is already installed"
|
273
|
+
else
|
274
|
+
Pot.logger.info "--> Verifying #{self.name} was properly installed"
|
275
|
+
end
|
276
|
+
|
277
|
+
@verifications.each do |v|
|
278
|
+
v.process(actor)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def requires(*packages)
|
283
|
+
@dependencies << packages
|
284
|
+
@dependencies.flatten!
|
285
|
+
end
|
286
|
+
|
287
|
+
def recommends(*packages)
|
288
|
+
@recommends << packages
|
289
|
+
@recommends.flatten!
|
290
|
+
end
|
291
|
+
|
292
|
+
def optional(*packages)
|
293
|
+
@optional << packages
|
294
|
+
@optional.flatten!
|
295
|
+
end
|
296
|
+
|
297
|
+
def tree(depth = 1, &block)
|
298
|
+
packages = []
|
299
|
+
|
300
|
+
@recommends.each do |dep|
|
301
|
+
package = REGISTER[dep]
|
302
|
+
next unless package # skip missing recommended packages as they're allowed to not exist
|
303
|
+
block.call(self, package, depth) if block
|
304
|
+
packages << package.tree(depth + 1, &block)
|
305
|
+
end
|
306
|
+
|
307
|
+
@dependencies.each do |dep|
|
308
|
+
package = REGISTER[dep]
|
309
|
+
package = select_package(dep, package) if package.is_a? Array
|
310
|
+
|
311
|
+
raise "Package definition not found for key: #{dep}" unless package
|
312
|
+
block.call(self, package, depth) if block
|
313
|
+
packages << package.tree(depth + 1, &block)
|
314
|
+
end
|
315
|
+
|
316
|
+
packages << self
|
317
|
+
|
318
|
+
@optional.each do |dep|
|
319
|
+
package = REGISTER[dep]
|
320
|
+
next unless package # skip missing optional packages as they're allow to not exist
|
321
|
+
block.call(self, package, depth) if block
|
322
|
+
packages << package.tree(depth + 1, &block)
|
323
|
+
end
|
324
|
+
|
325
|
+
packages
|
326
|
+
end
|
327
|
+
|
328
|
+
def to_s; @name; end
|
329
|
+
|
330
|
+
private
|
331
|
+
|
332
|
+
def select_package(name, packages)
|
333
|
+
if packages.size <= 1
|
334
|
+
package = packages.first
|
335
|
+
else
|
336
|
+
package = choose do |menu|
|
337
|
+
menu.prompt = "Multiple choices exist for virtual package #{name}"
|
338
|
+
menu.choices *packages.collect(&:to_s)
|
339
|
+
end
|
340
|
+
package = REGISTER[package]
|
341
|
+
end
|
342
|
+
|
343
|
+
cloud_info "Selecting #{package.to_s} for virtual package #{name}"
|
344
|
+
|
345
|
+
package
|
346
|
+
end
|
347
|
+
|
348
|
+
def meta_package?
|
349
|
+
@installers.empty?
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|