mitchellh-sprinkle 0.1.5

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.
Files changed (70) hide show
  1. data/CREDITS +16 -0
  2. data/History.txt +4 -0
  3. data/MIT-LICENSE +20 -0
  4. data/Manifest.txt +68 -0
  5. data/README.txt +224 -0
  6. data/Rakefile +4 -0
  7. data/bin/sprinkle +86 -0
  8. data/config/hoe.rb +70 -0
  9. data/config/requirements.rb +17 -0
  10. data/examples/merb/deploy.rb +5 -0
  11. data/examples/rails/README +15 -0
  12. data/examples/rails/deploy.rb +2 -0
  13. data/examples/rails/packages/database.rb +9 -0
  14. data/examples/rails/packages/essential.rb +6 -0
  15. data/examples/rails/packages/rails.rb +28 -0
  16. data/examples/rails/packages/search.rb +11 -0
  17. data/examples/rails/packages/server.rb +28 -0
  18. data/examples/rails/rails.rb +71 -0
  19. data/examples/sprinkle/sprinkle.rb +38 -0
  20. data/lib/sprinkle/actors/actors.rb +17 -0
  21. data/lib/sprinkle/actors/capistrano.rb +117 -0
  22. data/lib/sprinkle/actors/vlad.rb +65 -0
  23. data/lib/sprinkle/configurable.rb +27 -0
  24. data/lib/sprinkle/deployment.rb +73 -0
  25. data/lib/sprinkle/extensions/arbitrary_options.rb +10 -0
  26. data/lib/sprinkle/extensions/array.rb +5 -0
  27. data/lib/sprinkle/extensions/blank_slate.rb +5 -0
  28. data/lib/sprinkle/extensions/dsl_accessor.rb +15 -0
  29. data/lib/sprinkle/extensions/string.rb +10 -0
  30. data/lib/sprinkle/extensions/symbol.rb +7 -0
  31. data/lib/sprinkle/installers/apt.rb +51 -0
  32. data/lib/sprinkle/installers/gem.rb +61 -0
  33. data/lib/sprinkle/installers/installer.rb +120 -0
  34. data/lib/sprinkle/installers/rake.rb +30 -0
  35. data/lib/sprinkle/installers/rpm.rb +37 -0
  36. data/lib/sprinkle/installers/source.rb +179 -0
  37. data/lib/sprinkle/package.rb +127 -0
  38. data/lib/sprinkle/policy.rb +85 -0
  39. data/lib/sprinkle/script.rb +13 -0
  40. data/lib/sprinkle/verifiers/directory.rb +11 -0
  41. data/lib/sprinkle/verifiers/executable.rb +17 -0
  42. data/lib/sprinkle/verifiers/file.rb +11 -0
  43. data/lib/sprinkle/verifiers/symlink.rb +15 -0
  44. data/lib/sprinkle/verify.rb +55 -0
  45. data/lib/sprinkle/version.rb +9 -0
  46. data/lib/sprinkle.rb +32 -0
  47. data/script/destroy +14 -0
  48. data/script/generate +14 -0
  49. data/spec/spec.opts +1 -0
  50. data/spec/spec_helper.rb +17 -0
  51. data/spec/sprinkle/actors/capistrano_spec.rb +170 -0
  52. data/spec/sprinkle/configurable_spec.rb +46 -0
  53. data/spec/sprinkle/deployment_spec.rb +80 -0
  54. data/spec/sprinkle/extensions/array_spec.rb +19 -0
  55. data/spec/sprinkle/extensions/string_spec.rb +21 -0
  56. data/spec/sprinkle/installers/apt_spec.rb +74 -0
  57. data/spec/sprinkle/installers/gem_spec.rb +75 -0
  58. data/spec/sprinkle/installers/installer_spec.rb +151 -0
  59. data/spec/sprinkle/installers/rpm_spec.rb +50 -0
  60. data/spec/sprinkle/installers/source_spec.rb +331 -0
  61. data/spec/sprinkle/package_spec.rb +422 -0
  62. data/spec/sprinkle/policy_spec.rb +126 -0
  63. data/spec/sprinkle/script_spec.rb +51 -0
  64. data/spec/sprinkle/sprinkle_spec.rb +25 -0
  65. data/spec/sprinkle/verify_spec.rb +137 -0
  66. data/sprinkle.gemspec +43 -0
  67. data/tasks/deployment.rake +34 -0
  68. data/tasks/environment.rake +7 -0
  69. data/tasks/rspec.rake +21 -0
  70. metadata +160 -0
@@ -0,0 +1,120 @@
1
+ module Sprinkle
2
+ module Installers
3
+ # The base class which all installers must subclass, this class makes
4
+ # sure all installers share some general features, which are outlined
5
+ # below.
6
+ #
7
+ # = Pre/Post Installation Hooks
8
+ #
9
+ # With all intallation methods you have the ability to specify multiple
10
+ # pre/post installation hooks. This gives you the ability to specify
11
+ # commands to run before and after an installation takes place. All
12
+ # commands by default are sudo'd so there is no need to include "sudo"
13
+ # in the command itself. There are three ways to specify a pre/post hook.
14
+ #
15
+ # First, a single command:
16
+ #
17
+ # pre :install, 'echo "Hello, World!"'
18
+ # post :install, 'rm -rf /'
19
+ #
20
+ # Second, an array of commands:
21
+ #
22
+ # commands = ['echo "First"', 'echo "Then Another"']
23
+ # pre :install, commands
24
+ # post :install, commands
25
+ #
26
+ # Third, a block which returns either a single or multiple commands:
27
+ #
28
+ # pre :install do
29
+ # amount = 7 * 3
30
+ # "echo 'Before we install, lets plant #{amount} magic beans...'"
31
+ # end
32
+ # post :install do
33
+ # ['echo "Now... let's hope they sprout!", 'echo "Indeed they have!"']
34
+ # end
35
+ #
36
+ # = Other Pre/Post Hooks
37
+ #
38
+ # Some installation methods actually grant you more fine grained
39
+ # control of when commands are run rather than a blanket pre :install
40
+ # or post :install. If this is the case, it will be documented on
41
+ # the installation method's corresponding documentation page.
42
+ class Installer
43
+ include Sprinkle::Configurable
44
+ attr_accessor :delivery, :package, :options, :pre, :post #:nodoc:
45
+
46
+ def initialize(package, options = {}, &block) #:nodoc:
47
+ @package = package
48
+ @options = options
49
+ @pre = {}; @post = {}
50
+ self.instance_eval(&block) if block
51
+ end
52
+
53
+ def pre(stage, *commands)
54
+ @pre[stage] ||= []
55
+ @pre[stage] += commands
56
+ @pre[stage] += [yield] if block_given?
57
+ end
58
+
59
+ def post(stage, *commands)
60
+ @post[stage] ||= []
61
+ @post[stage] += commands
62
+ @post[stage] += [yield] if block_given?
63
+ end
64
+
65
+ def process(roles) #:nodoc:
66
+ assert_delivery
67
+
68
+ if logger.debug?
69
+ sequence = install_sequence; sequence = sequence.join('; ') if sequence.is_a? Array
70
+ logger.debug "#{@package.name} install sequence: #{sequence} for roles: #{roles}\n"
71
+ end
72
+
73
+ unless Sprinkle::OPTIONS[:testing]
74
+ logger.info "--> Installing #{package.name} for roles: #{roles}"
75
+ @delivery.process(@package.name, install_sequence, roles)
76
+ end
77
+ end
78
+
79
+ protected
80
+ # More complicated installers that have different stages, and require pre/post commands
81
+ # within stages can override install_sequence and take complete control of the install
82
+ # command sequence construction (eg. source based installer).
83
+ def install_sequence
84
+ commands = pre_commands(:install) + [ install_commands ] + post_commands(:install)
85
+ commands.flatten
86
+ end
87
+
88
+ # A concrete installer (subclass of this virtual class) must override this method
89
+ # and return the commands it needs to run as either a string or an array.
90
+ #
91
+ # <b>Overriding this method is required.</b>
92
+ def install_commands
93
+ raise 'Concrete installers implement this to specify commands to run to install their respective packages'
94
+ end
95
+
96
+ def pre_commands(stage) #:nodoc:
97
+ dress @pre[stage] || [], :pre
98
+ end
99
+
100
+ def post_commands(stage) #:nodoc:
101
+ dress @post[stage] || [], :post
102
+ end
103
+
104
+ # Concrete installers (subclasses of this virtual class) can override this method to
105
+ # specify stage-specific (pre-installation, post-installation, etc.) modifications
106
+ # of commands.
107
+ #
108
+ # An example usage of overriding this would be to prefix all commands for a
109
+ # certain stage to change to a certain directory. An example is given below:
110
+ #
111
+ # def dress(commands, stage)
112
+ # commands.collect { |x| "cd #{magic_beans_path} && #{x}" }
113
+ # end
114
+ #
115
+ # By default, no modifications are made to the commands.
116
+ def dress(commands, stage); commands; end
117
+
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,30 @@
1
+ module Sprinkle
2
+ module Installers
3
+ # = Rake Installer
4
+ #
5
+ # This installer runs a rake command.
6
+ #
7
+ # == Example Usage
8
+ #
9
+ # The following example runs the command "rake spec" on
10
+ # the remote server.
11
+ #
12
+ # package :spec do
13
+ # rake 'spec'
14
+ # end
15
+ #
16
+ class Rake < Installer
17
+ def initialize(parent, commands = [], &block) #:nodoc:
18
+ super parent, &block
19
+ @commands = commands
20
+ end
21
+
22
+ protected
23
+
24
+ def install_commands #:nodoc:
25
+ "rake #{@commands.join(' ')}"
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,37 @@
1
+ module Sprinkle
2
+ module Installers
3
+ # = RPM Package Installer
4
+ #
5
+ # The RPM package installer installs RPM packages.
6
+ #
7
+ # == Example Usage
8
+ #
9
+ # Installing the magic_beans RPM. Its all the craze these days.
10
+ #
11
+ # package :magic_beans do
12
+ # rpm 'magic_beans'
13
+ # end
14
+ #
15
+ # You may also specify multiple rpms as an array:
16
+ #
17
+ # package :magic_beans do
18
+ # rpm %w(magic_beans magic_sauce)
19
+ # end
20
+ class Rpm < Installer
21
+ attr_accessor :packages #:nodoc:
22
+
23
+ def initialize(parent, packages, &block) #:nodoc:
24
+ super parent, &block
25
+ packages = [packages] unless packages.is_a? Array
26
+ @packages = packages
27
+ end
28
+
29
+ protected
30
+
31
+ def install_commands #:nodoc:
32
+ "rpm -Uvh #{@packages.join(' ')}"
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,179 @@
1
+ module Sprinkle
2
+ module Installers
3
+ # = Source Package Installer
4
+ #
5
+ # The source package installer installs software from source.
6
+ # It handles downloading, extracting, configuring, building,
7
+ # and installing software.
8
+ #
9
+ # == Configuration Options
10
+ #
11
+ # The source installer has many configuration options:
12
+ # * <b>prefix</b> - The prefix directory that is configured to.
13
+ # * <b>archives</b> - The location all the files are downloaded to.
14
+ # * <b>builds</b> - The directory the package is extracted to to configure and install
15
+ #
16
+ # == Pre/Post Hooks
17
+ #
18
+ # The source installer defines a myriad of new stages which can be hooked into:
19
+ # * <b>prepare</b> - Prepare is the stage which all the prefix, archives, and build directories are made.
20
+ # * <b>download</b> - Download is the stage which the software package is downloaded.
21
+ # * <b>extract</b> - Extract is the stage which the software package is extracted.
22
+ # * <b>configure</b> - Configure is the stage which the ./configure script is run.
23
+ # * <b>build</b> - Build is the stage in which `make` is called.
24
+ # * <b>install</b> - Install is the stage which `make install` is called.
25
+ #
26
+ # == Example Usage
27
+ #
28
+ # First, a simple package, no configuration:
29
+ #
30
+ # package :magic_beans do
31
+ # source 'http://magicbeansland.com/latest-1.1.1.tar.gz'
32
+ # end
33
+ #
34
+ # Second, specifying exactly where I want my files:
35
+ #
36
+ # package :magic_beans do
37
+ # source 'http://magicbeansland.com/latest-1.1.1.tar.gz' do
38
+ # prefix '/usr/local'
39
+ # archives '/tmp'
40
+ # builds '/tmp/builds'
41
+ # end
42
+ # end
43
+ #
44
+ # Third, specifying some hooks:
45
+ #
46
+ # package :magic_beans do
47
+ # source 'http://magicbeansland.com/latest-1.1.1.tar.gz' do
48
+ # prefix '/usr/local'
49
+ #
50
+ # pre :prepare { 'echo "Here we go folks."' }
51
+ # post :extract { 'echo "I believe..."' }
52
+ # pre :build { 'echo "Cross your fingers!"' }
53
+ # end
54
+ # end
55
+ #
56
+ # As you can see, setting options is as simple as creating a
57
+ # block and calling the option as a method with the value as
58
+ # its parameter.
59
+ class Source < Installer
60
+ attr_accessor :source #:nodoc:
61
+
62
+ def initialize(parent, source, options = {}, &block) #:nodoc:
63
+ @source = source
64
+ super parent, options, &block
65
+ end
66
+
67
+ protected
68
+
69
+ def install_sequence #:nodoc:
70
+ prepare + download + extract + configure + build + install
71
+ end
72
+
73
+ %w( prepare download extract configure build install ).each do |stage|
74
+ define_method stage do
75
+ pre_commands(stage.to_sym) + self.send("#{stage}_commands") + post_commands(stage.to_sym)
76
+ end
77
+ end
78
+
79
+ def prepare_commands #:nodoc:
80
+ raise 'No installation area defined' unless @options[:prefix]
81
+ raise 'No build area defined' unless @options[:builds]
82
+ raise 'No source download area defined' unless @options[:archives]
83
+
84
+ [ "mkdir -p #{@options[:prefix]}",
85
+ "mkdir -p #{@options[:builds]}",
86
+ "mkdir -p #{@options[:archives]}" ]
87
+ end
88
+
89
+ def download_commands #:nodoc:
90
+ [ "wget -cq --directory-prefix='#{@options[:archives]}' #{@source}" ]
91
+ end
92
+
93
+ def extract_commands #:nodoc:
94
+ [ "bash -c 'cd #{@options[:builds]} && #{extract_command} #{@options[:archives]}/#{archive_name}'" ]
95
+ end
96
+
97
+ def configure_commands #:nodoc:
98
+ return [] if custom_install?
99
+
100
+ command = "bash -c 'cd #{build_dir} && ./configure --prefix=#{@options[:prefix]} "
101
+
102
+ extras = {
103
+ :enable => '--enable', :disable => '--disable',
104
+ :with => '--with', :without => '--without'
105
+ }
106
+
107
+ extras.inject(command) { |m, (k, v)| m << create_options(k, v) if options[k]; m }
108
+
109
+ [ command << " > #{@package.name}-configure.log 2>&1'" ]
110
+ end
111
+
112
+ def build_commands #:nodoc:
113
+ return [] if custom_install?
114
+ [ "bash -c 'cd #{build_dir} && make > #{@package.name}-build.log 2>&1'" ]
115
+ end
116
+
117
+ def install_commands #:nodoc:
118
+ return custom_install_commands if custom_install?
119
+ [ "bash -c 'cd #{build_dir} && make install > #{@package.name}-install.log 2>&1'" ]
120
+ end
121
+
122
+ def custom_install? #:nodoc:
123
+ !! @options[:custom_install]
124
+ end
125
+
126
+ # REVISIT: must be better processing of custom install commands somehow? use splat operator?
127
+ def custom_install_commands #:nodoc:
128
+ dress @options[:custom_install], :install
129
+ end
130
+
131
+ protected
132
+
133
+ # dress is overriden from the base Sprinkle::Installers::Installer class so that the command changes
134
+ # directory to the build directory first. Also, the result of the command is logged.
135
+ def dress(commands, stage)
136
+ commands.collect { |command| "bash -c 'cd #{build_dir} && #{command} >> #{@package.name}-#{stage}.log 2>&1'" }
137
+ end
138
+
139
+ private
140
+
141
+ def create_options(key, prefix) #:nodoc:
142
+ @options[key].inject(' ') { |m, option| m << "#{prefix}-#{option} "; m }
143
+ end
144
+
145
+ def extract_command #:nodoc:
146
+ case @source
147
+ when /(tar.gz)|(tgz)$/
148
+ 'tar xzf'
149
+ when /(tar.bz2)|(tb2)$/
150
+ 'tar xjf'
151
+ when /tar$/
152
+ 'tar xf'
153
+ when /zip$/
154
+ 'unzip'
155
+ else
156
+ raise "Unknown source archive format: #{archive_name}"
157
+ end
158
+ end
159
+
160
+ def archive_name #:nodoc:
161
+ name = @source.split('/').last
162
+ raise "Unable to determine archive name for source: #{source}, please update code knowledge" unless name
163
+ name
164
+ end
165
+
166
+ def build_dir #:nodoc:
167
+ "#{@options[:builds]}/#{options[:custom_dir] || base_dir}"
168
+ end
169
+
170
+ def base_dir #:nodoc:
171
+ if @source.split('/').last =~ /(.*)\.(tar\.gz|tgz|tar\.bz2|tb2)/
172
+ return $1
173
+ end
174
+ raise "Unknown base path for source archive: #{@source}, please update code knowledge"
175
+ end
176
+
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,127 @@
1
+ module Sprinkle
2
+ module Package
3
+ PACKAGES = {}
4
+
5
+ def package(name, metadata = {}, &block)
6
+ package = Package.new(name, metadata, &block)
7
+ PACKAGES[name] = package
8
+
9
+ if package.provides
10
+ (PACKAGES[package.provides] ||= []) << package
11
+ end
12
+
13
+ package
14
+ end
15
+
16
+ class Package
17
+ include ArbitraryOptions
18
+ attr_accessor :name, :provides, :installer, :dependencies, :recommends, :verifications
19
+
20
+ def initialize(name, metadata = {}, &block)
21
+ raise 'No package name supplied' unless name
22
+
23
+ @name = name
24
+ @provides = metadata[:provides]
25
+ @dependencies = []
26
+ @recommends = []
27
+ @verifications = []
28
+ self.instance_eval &block
29
+ end
30
+
31
+ def apt(*names, &block)
32
+ @installer = Sprinkle::Installers::Apt.new(self, *names, &block)
33
+ end
34
+
35
+ def rpm(*names, &block)
36
+ @installer = Sprinkle::Installers::Rpm.new(self, *names, &block)
37
+ end
38
+
39
+ def gem(name, options = {}, &block)
40
+ @recommends << :rubygems
41
+ @installer = Sprinkle::Installers::Gem.new(self, name, options, &block)
42
+ end
43
+
44
+ def source(source, options = {}, &block)
45
+ @recommends << :build_essential # Ubuntu/Debian
46
+ @installer = Sprinkle::Installers::Source.new(self, source, options, &block)
47
+ end
48
+
49
+ def verify(description = '', &block)
50
+ @verifications << Sprinkle::Verify.new(self, description, &block)
51
+ end
52
+
53
+ def process(deployment, roles)
54
+ return if meta_package?
55
+
56
+ # Run a pre-test to see if the software is already installed. If so,
57
+ # we can skip it, unless we have the force option turned on!
58
+ unless @verifications.empty? || Sprinkle::OPTIONS[:force]
59
+ begin
60
+ process_verifications(deployment, roles, true)
61
+
62
+ logger.info "--> #{self.name} already installed for roles: #{roles}"
63
+ return
64
+ rescue Sprinkle::VerificationFailed => e
65
+ # Continue
66
+ end
67
+ end
68
+
69
+ @installer.defaults(deployment)
70
+ @installer.process(roles)
71
+
72
+ process_verifications(deployment, roles)
73
+ end
74
+
75
+ def process_verifications(deployment, roles, pre = false)
76
+ if pre
77
+ logger.info "--> Checking if #{self.name} is already installed for roles: #{roles}"
78
+ else
79
+ logger.info "--> Verifying #{self.name} was properly installed for roles: #{roles}"
80
+ end
81
+
82
+ @verifications.each do |v|
83
+ v.defaults(deployment)
84
+ v.process(roles)
85
+ end
86
+ end
87
+
88
+ def requires(*packages)
89
+ @dependencies << packages
90
+ @dependencies.flatten!
91
+ end
92
+
93
+ def recommends(*packages)
94
+ @recommends << packages
95
+ @recommends.flatten!
96
+ end
97
+
98
+ def tree(depth = 1, &block)
99
+ packages = []
100
+
101
+ @recommends.each do |dep|
102
+ package = PACKAGES[dep]
103
+ next unless package # skip missing recommended packages as they can be optional
104
+ block.call(self, package, depth) if block
105
+ packages << package.tree(depth + 1, &block)
106
+ end
107
+
108
+ @dependencies.each do |dep|
109
+ package = PACKAGES[dep]
110
+ raise "Package definition not found for key: #{dep}" unless package
111
+ block.call(self, package, depth) if block
112
+ packages << package.tree(depth + 1, &block)
113
+ end
114
+
115
+ packages << self
116
+ end
117
+
118
+ def to_s; @name; end
119
+
120
+ private
121
+
122
+ def meta_package?
123
+ @installer == nil
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,85 @@
1
+ require 'highline/import'
2
+
3
+ module Sprinkle
4
+ module Policy
5
+ POLICIES = []
6
+
7
+ def policy(name, options = {}, &block)
8
+ p = Policy.new(name, options, &block)
9
+ POLICIES << p
10
+ p
11
+ end
12
+
13
+ class Policy
14
+ attr_reader :name, :packages
15
+
16
+ def initialize(name, metadata = {}, &block)
17
+ raise 'No name provided' unless name
18
+ raise 'No roles provided' unless metadata[:roles]
19
+
20
+ @name = name
21
+ @roles = metadata[:roles]
22
+ @packages = []
23
+ self.instance_eval(&block)
24
+ end
25
+
26
+ def requires(package, options = {})
27
+ @packages << package
28
+ end
29
+
30
+ def to_s; name; end
31
+
32
+ def process(deployment)
33
+ all = []
34
+
35
+ cloud_info "--> Cloud hierarchy for policy #{@name}"
36
+
37
+ @packages.each do |p|
38
+ cloud_info "\nPolicy #{@name} requires package #{p}"
39
+
40
+ package = Sprinkle::Package::PACKAGES[p]
41
+ raise "Package definition not found for key: #{p}" unless package
42
+ package = select_package(p, package) if package.is_a? Array # handle virtual package selection
43
+
44
+ tree = package.tree do |parent, child, depth|
45
+ indent = "\t" * depth; cloud_info "#{indent}Package #{parent.name} requires #{child.name}"
46
+ end
47
+
48
+ all << tree
49
+ end
50
+
51
+ normalize(all) do |package|
52
+ package.process(deployment, @roles)
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def cloud_info(message)
59
+ logger.info(message) if Sprinkle::OPTIONS[:cloud] or logger.debug?
60
+ end
61
+
62
+ def select_package(name, packages)
63
+ if packages.size <= 1
64
+ package = packages.first
65
+ else
66
+ package = choose do |menu|
67
+ menu.prompt = "Multiple choices exist for virtual package #{name}"
68
+ menu.choices *packages.collect(&:to_s)
69
+ end
70
+ package = Sprinkle::Package::PACKAGES[package]
71
+ end
72
+
73
+ cloud_info "Selecting #{package.to_s} for virtual package #{name}"
74
+
75
+ package
76
+ end
77
+
78
+ def normalize(all, &block)
79
+ all = all.flatten.uniq
80
+ cloud_info "\n--> Normalized installation order for all packages: #{all.collect(&:name).join(', ')}"
81
+ all.each &block
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,13 @@
1
+ module Sprinkle
2
+ class Script
3
+ def self.sprinkle(script, filename = '__SCRIPT__')
4
+ powder = new
5
+ powder.instance_eval script, filename
6
+ powder.sprinkle
7
+ end
8
+
9
+ def sprinkle
10
+ @deployment.process if @deployment
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ module Sprinkle
2
+ module Verifiers
3
+ module Directory
4
+ Sprinkle::Verify.register(Sprinkle::Verifiers::Directory)
5
+
6
+ def has_directory(dir)
7
+ @commands << "test -d #{dir}"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ module Sprinkle
2
+ module Verifiers
3
+ module Executable
4
+ Sprinkle::Verify.register(Sprinkle::Verifiers::Executable)
5
+
6
+ def has_executable(path)
7
+ # Be smart: If the path includes a forward slash, we're checking
8
+ # an absolute path. Otherwise, we're checking a global executable
9
+ if path.include?('/')
10
+ @commands << "test -x #{path}"
11
+ else
12
+ @commands << "[ -n \"`which #{path}`\"]"
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ module Sprinkle
2
+ module Verifiers
3
+ module File
4
+ Sprinkle::Verify.register(Sprinkle::Verifiers::File)
5
+
6
+ def has_file(path)
7
+ @commands << "test -f #{path}"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module Sprinkle
2
+ module Verifiers
3
+ module Symlink
4
+ Sprinkle::Verify.register(Sprinkle::Verifiers::Symlink)
5
+
6
+ def has_symlink(symlink, file = nil)
7
+ if file.nil?
8
+ @commands << "test -L #{symlink}"
9
+ else
10
+ @commands << "test '#{file}' = `readlink #{symlink}`"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end