Skip to content
This repository
Browse code

magical gem -> apt dependencies

  • Loading branch information...
commit 68ce73f803c9e45ccc356534a8de2a054be31439 1 parent 1b07f60
Jesse Newland authored March 13, 2009
2  lib/moonshine/manifest/rails.rb
@@ -15,6 +15,8 @@ def validate_platform
15 15
   end
16 16
   recipe :validate_platform
17 17
 
  18
+  configure(:apt_gems => YAML.load_file(File.join(File.dirname(__FILE__), 'rails', 'apt_gems.yml')))
  19
+
18 20
   require File.join(File.dirname(__FILE__), 'rails', 'passenger.rb')
19 21
   include Moonshine::Manifest::Rails::Passenger
20 22
   require File.join(File.dirname(__FILE__), 'rails', 'mysql.rb')
20  lib/moonshine/manifest/rails/apt_gems.yml
... ...
@@ -0,0 +1,20 @@
  1
+mysql:
  2
+- libmysqlclient15-dev
  3
+sqlite3-ruby:
  4
+- sqlite3
  5
+- libsqlite3-dev
  6
+nokogiri:
  7
+- libxml2-dev
  8
+- libxslt1-dev
  9
+rmagick:
  10
+- imagemagick
  11
+- libmagick9-dev
  12
+paperclip:
  13
+- imagemagick
  14
+- libmagick9-dev
  15
+thoughtbot-paperclip:
  16
+- imagemagick
  17
+- libmagick9-dev
  18
+mini_magick:
  19
+- imagemagick
  20
+- libmagick9-dev
3  lib/moonshine/manifest/rails/mysql.rb
@@ -26,8 +26,7 @@ def mysql_server
26 26
 
27 27
   # Install the <tt>mysql</tt> rubygem and dependencies
28 28
   def mysql_gem
29  
-    package "libmysqlclient15-dev", :ensure => :installed
30  
-    package "mysql", :ensure => :installed, :provider => :gem, :require => package("libmysqlclient15-dev")
  29
+    gem('mysql')
31 30
   end
32 31
 
33 32
   # GRANT the database user specified in the current <tt>database_environment</tt>
103  lib/moonshine/manifest/rails/rails.rb
@@ -76,26 +76,10 @@ def rails_gems
76 76
     exec 'rails_gems', :command => 'true'
77 77
     return unless configuration[:gems]
78 78
     configuration[:gems].each do |gem|
79  
-      hash = {
80  
-        :provider => :gem,
81  
-        :before   => exec('rails_gems')
82  
-      }
83  
-      hash.merge!(:source => gem[:source]) if gem[:source]
84  
-      exact_dep = gem[:version] ? Gem::Dependency.new(gem[:name], gem[:version]) : Gem::Dependency.new(gem[:name], '>0')
85  
-      matches = Gem.source_index.search(exact_dep)
86  
-      installed_spec = matches.first
87  
-      if installed_spec
88  
-        #it's already loaded, let's just specify that we want it installed
89  
-        hash.merge!(:ensure => :installed)
90  
-      elsif gem[:version]
91  
-        #if it's not installed and version specified, we require that version
92  
-        hash.merge!(:ensure => gem[:version])
93  
-      else
94  
-        #otherwise we don't care
95  
-        hash.merge!(:ensure => :installed)
96  
-      end
97  
-      #finally create the dependency
98  
-      package(gem[:name], hash)
  79
+      gem(gem[:name], {
  80
+        :version => gem[:version],
  81
+        :source => gem[:source]
  82
+      })
99 83
     end
100 84
   end
101 85
 
@@ -131,8 +115,85 @@ def rails_directories
131 115
   end
132 116
 
133 117
 private
  118
+  # Creates package("#{name}") with <tt>:provider</tt> set to <tt>:gem</tt>.
  119
+  # The given <tt>options[:version]</tt> requirement is tweaked to ensure
  120
+  # gems aren't reinstalled on each run. <tt>options[:source]</tt> does what
  121
+  # you'd expect, as well.
  122
+  #
  123
+  # === Gem Package Dependencies
  124
+  #
  125
+  # System dependencies are loaded if any exist for the gem or any of it's
  126
+  # gem dependencies in <tt>apt_gems.yml</tt>. For example, calling
  127
+  # <tt>gem('webrat')</tt> knows to install <tt>libxml2-dev</tt> and
  128
+  # <tt>libxslt1-dev</tt> because those are defined as dependencies for
  129
+  # <tt>nokogiri</tt>.
  130
+  #
  131
+  # To define system dependencies not include in moonshine:
  132
+  #
  133
+  #   class UrManifest < ShadowPuppet::Manifest
  134
+  #     configure(:apt_gems => {
  135
+  #       :fakegem => [
  136
+  #         'package1',
  137
+  #         'package2
  138
+  #       ]
  139
+  #     })
  140
+  #   end
  141
+  #
  142
+  # If you were then to require the installation of <tt>fakegem</tt> <strong>
  143
+  # or any gem that depends on <tt>fakegem</tt></strong>, <tt>package1</tt>
  144
+  # and <tt>package2</tt> would be installed first via apt.
  145
+  def gem(name, options = {})
  146
+    hash = {
  147
+      :provider => :gem,
  148
+      :before   => exec('rails_gems'),
  149
+    }
  150
+    hash.merge!(:source => options[:source]) if options[:source]
  151
+    #fixup the version required
  152
+    exact_dep = Gem::Dependency.new(name, options[:version] || '>0')
  153
+    matches = Gem.source_index.search(exact_dep)
  154
+    installed_spec = matches.first
  155
+    if installed_spec
  156
+      #it's already loaded, let's just specify that we want it installed
  157
+      hash.merge!(:ensure => :installed)
  158
+    else
  159
+      if options[:version]
  160
+        #if it's not installed and version specified, we require that version
  161
+        hash.merge!(:ensure => options[:version])
  162
+      else
  163
+        #otherwise we don't care
  164
+        hash.merge!(:ensure => :installed)
  165
+      end
  166
+      hash = append_system_dependecies(exact_dep, hash)
  167
+    end
  168
+    hash.delete(:version)
  169
+    package(name, hash)
  170
+  end
  171
+
  172
+  def append_system_dependecies(exact_dep, hash) #:nodoc:
  173
+    #fixup the requires key to be an array
  174
+    if hash[:require] && !hash[:require].is_a?(Array)
  175
+      hash[:require] = [hash[:require]]
  176
+    end
  177
+    hash[:require] = [] unless hash[:require]
  178
+    # load this gems' dependencies. we don't create packages for em, we just
  179
+    # check them against the system dependency map
  180
+    specs = Gem::SpecFetcher.fetcher.fetch exact_dep
  181
+    spec = specs.first.first
  182
+    deps = spec.dependencies
  183
+    deps << exact_dep
  184
+    deps.each do |dep|
  185
+      (configuration[:apt_gems][dep.name.to_sym] || []).each do |apt|
  186
+        package apt, :ensure => :installed
  187
+        hash[:require] << package(apt)
  188
+      end
  189
+    end
  190
+    hash.delete(:require) if hash[:require] == []
  191
+    hash
  192
+  rescue
  193
+    hash
  194
+  end
134 195
 
135  
-  # Creates exec('rake #name') that runs in <tt>rails root</tt> of the rails
  196
+  # Creates exec("rake #name") that runs in <tt>rails root</tt> of the rails
136 197
   # app, with RAILS_ENV properly set
137 198
   def rake(name, options = {})
138 199
     exec("rake #{name}", {
11  lib/moonshine/manifest/rails/sqlite3.rb
@@ -2,16 +2,7 @@ module Moonshine::Manifest::Rails::Sqlite3
2 2
 
3 3
   # Install the sqlite3 gem and it's dependencies
4 4
   def sqlite3
5  
-    package 'sqlite3', :ensure => :installed
6  
-    package 'libsqlite3-dev', :ensure => :installed
7  
-    package 'sqlite3-ruby',
8  
-      :ensure => :installed,
9  
-      :provider => :gem,
10  
-      :require => [
11  
-        package('sqlite3'),
12  
-        package('libsqlite3-dev')
13  
-      ],
14  
-      :before => exec('rails_gems')
  5
+    gem 'sqlite3-ruby', :before => exec('rails_gems')
15 6
   end
16 7
 
17 8
 end
27  test/moonshine/manifest/rails_test.rb
... ...
@@ -1,5 +1,20 @@
1 1
 require File.dirname(__FILE__) + '/../../test_helper.rb'
2 2
 
  3
+#mock out the gem source index to fake like passenger is installed, but
  4
+#nothing else
  5
+module Gem  #:nodoc:
  6
+  class SourceIndex  #:nodoc:
  7
+    alias_method :orig_search, :search
  8
+    def search(gem_pattern, platform_only = false)
  9
+      if gem_pattern.name.to_s =~ /passenger/
  10
+        orig_search(gem_pattern, platform_only)
  11
+      else
  12
+        []
  13
+      end
  14
+    end
  15
+  end
  16
+end
  17
+
3 18
 class Moonshine::Manifest::RailsTest < Test::Unit::TestCase
4 19
 
5 20
   def setup
@@ -21,6 +36,18 @@ def test_loads_gems_from_config_hash
21 36
     end
22 37
   end
23 38
 
  39
+  def test_magically_loads_gem_dependencies
  40
+    @manifest.configure(:gems => [ 
  41
+      { :name => 'webrat' },
  42
+      { :name => 'thoughtbot-paperclip', :source => 'http://gems.github.com/' }
  43
+    ])
  44
+    @manifest.rails_gems
  45
+    assert_not_nil @manifest.puppet_resources[Puppet::Type::Package]['webrat']
  46
+    assert_not_nil @manifest.puppet_resources[Puppet::Type::Package]['thoughtbot-paperclip']
  47
+    assert_not_nil @manifest.puppet_resources[Puppet::Type::Package]['libxml2-dev']
  48
+    assert_not_nil @manifest.puppet_resources[Puppet::Type::Package]['imagemagick']
  49
+  end
  50
+
24 51
   def test_creates_directories
25 52
     config = {
26 53
       :application => 'foo',

0 notes on commit 68ce73f

Please sign in to comment.
Something went wrong with that request. Please try again.