milkshake 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Simon Menke
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,60 @@
1
+ = Milkshake
2
+
3
+ Milkshake allows you to compose rails apps from several other rails apps specially packed as gems.
4
+
5
+ == Creating a host application
6
+
7
+ To create a new host application you must use the <tt>create.host</tt> command.
8
+
9
+ $ milkshake create.host my_host_applications
10
+ Rails app successfully created!
11
+ Rails app successfully cleaned!
12
+ Milkshake successfully installed!
13
+ Rails app successfully stripped!
14
+ $ ls my_host_applications
15
+ config db log public script tmp
16
+
17
+ The most important part of the host application is the <tt>config/milkshake.yml</tt> file.
18
+
19
+ gems:
20
+ my-gem:
21
+ version: 0.2.38
22
+ lib: my_gem
23
+ source: http://www.github.com
24
+
25
+ After changing the <tt>milkshake.yml</tt> or updating some gems you must touch <tt>tmp/relink.txt</tt> and restart your app server (touch <tt>tmp/restart.txt</tt> for passenger).
26
+
27
+ == Creating a gem application
28
+
29
+ Gem applications can be packaged as gems and can be linked back into host applications.
30
+
31
+ $ milkshake create.gem my_gem_applications
32
+ # anwser the questions milkshake asks you
33
+
34
+ == Installation
35
+
36
+ # you need gemcutter first
37
+ $ sudo gem install gemcutter
38
+ $ sudo gem tumble
39
+ # then just install milkshake
40
+ $ sudo gem install milkshake
41
+
42
+ == Wish list
43
+
44
+ * link rake tasks from [gem path]/lib/tasks (is this needed?)
45
+ * migrate down when removing (or downgrading) a gem.
46
+
47
+ == Note on Patches/Pull Requests
48
+
49
+ * Fork the project.
50
+ * Make your feature addition or bug fix.
51
+ * Add tests for it. This is important so I don't break it in a
52
+ future version unintentionally.
53
+ * Commit, do not mess with rakefile, version, or history.
54
+ (if you want to have your own version, that is fine but
55
+ bump version in a commit by itself I can ignore when I pull)
56
+ * Send me a pull request. Bonus points for topic branches.
57
+
58
+ == Copyright
59
+
60
+ Copyright (c) 2009 Simon Menke. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,56 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "milkshake"
8
+ gem.summary = %Q{Make composite rails applications}
9
+ gem.description = %Q{Compose rails applications using several smaller rails applications}
10
+ gem.email = "simon@mrhenry.be"
11
+ gem.homepage = "http://github.com/simonmenke/milkshake"
12
+ gem.authors = ["Simon Menke"]
13
+ gem.add_development_dependency "thoughtbot-shoulda"
14
+ gem.add_development_dependency "yard"
15
+ gem.add_runtime_dependency 'thor'
16
+ gem.add_runtime_dependency 'snapshots'
17
+ gem.files += FileList['lib/**/*.rb'] + FileList['templates/**/*']
18
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
19
+ end
20
+ Jeweler::GemcutterTasks.new
21
+ rescue LoadError
22
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
23
+ end
24
+
25
+ require 'rake/testtask'
26
+ Rake::TestTask.new(:test) do |test|
27
+ test.libs << 'lib' << 'test'
28
+ test.pattern = 'test/**/*_test.rb'
29
+ test.verbose = true
30
+ end
31
+
32
+ begin
33
+ require 'rcov/rcovtask'
34
+ Rcov::RcovTask.new do |test|
35
+ test.libs << 'test'
36
+ test.pattern = 'test/**/*_test.rb'
37
+ test.verbose = true
38
+ end
39
+ rescue LoadError
40
+ task :rcov do
41
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
42
+ end
43
+ end
44
+
45
+ task :test => :check_dependencies
46
+
47
+ task :default => :test
48
+
49
+ begin
50
+ require 'yard'
51
+ YARD::Rake::YardocTask.new
52
+ rescue LoadError
53
+ task :yardoc do
54
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
55
+ end
56
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/bin/milkshake ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'milkshake'
5
+ rescue LoadError
6
+ $:.unshift File.join(File.dirname(__FILE__), *%w[ .. lib ])
7
+ retry
8
+ end
9
+
10
+ Milkshake::App.start
@@ -0,0 +1,223 @@
1
+
2
+ module Milkshake
3
+ class App
4
+ module Actions
5
+ private
6
+
7
+ def install_rails!(path)
8
+ override_app_path! path
9
+ assert_new_app_path!
10
+
11
+ system(%{rails "#{self.options.app}" > /dev/null})
12
+ good_say('Rails app successfully created!')
13
+
14
+ goto_rails do
15
+ if File.file?('config/locales/en.yml')
16
+ File.unlink('config/locales/en.yml')
17
+ end
18
+ if File.file?('public/index.html')
19
+ File.unlink('public/index.html')
20
+ end
21
+ if File.file?('public/images/rails.png')
22
+ File.unlink('public/images/rails.png')
23
+ end
24
+ if File.file?('public/javascripts/controls.js')
25
+ File.unlink('public/javascripts/controls.js')
26
+ end
27
+ if File.file?('public/javascripts/dragdrop.js')
28
+ File.unlink('public/javascripts/dragdrop.js')
29
+ end
30
+ if File.file?('public/javascripts/effects.js')
31
+ File.unlink('public/javascripts/effects.js')
32
+ end
33
+ if File.file?('public/javascripts/prototype.js')
34
+ File.unlink('public/javascripts/prototype.js')
35
+ end
36
+
37
+ Milkshake::Template.evaluate('routes.rb'
38
+ ).write_to('config/routes.rb')
39
+ end
40
+
41
+ good_say('Rails app successfully cleaned!')
42
+ end
43
+
44
+ def install_app!
45
+ goto_rails do
46
+
47
+ Milkshake::Template.evaluate('preinitializer.rb'
48
+ ).write_to('config/preinitializer.rb')
49
+
50
+ unless File.file?('config/milkshake.yml')
51
+ Milkshake::Template.evaluate('milkshake.yml'
52
+ ).write_to('config/milkshake.yml')
53
+ end
54
+
55
+ end
56
+
57
+ good_say('Milkshake successfully installed!')
58
+ end
59
+
60
+ def install_gem!(name)
61
+ assert_valid_gem_name! name
62
+
63
+ goto_rails do
64
+
65
+ Milkshake::Template.evaluate('jeweler.rake',
66
+ :name => name,
67
+ :author => ask_unless_given(
68
+ 'Author', self.options.author, self.class.default_author),
69
+ :email => ask_unless_given(
70
+ 'Email', self.options.email, self.class.default_email),
71
+ :summary => ask_unless_given(
72
+ 'Summary', self.options.summary, 'FIX_ME_SUMMARY'),
73
+ :description => ask_unless_given(
74
+ 'Description', self.options.description, 'FIX_ME_DESCRIPTION'),
75
+ :website => ask_unless_given(
76
+ 'Website', self.options.website, 'FIX_ME_WEBSITE')
77
+ ).write_to('lib/tasks/jeweler.rake')
78
+
79
+ FileUtils.mkdir_p('rails/initializers')
80
+ FileUtils.touch('rails/init.rb')
81
+ FileUtils.rm_rf('app/controllers/application_controller.rb') rescue nil
82
+ FileUtils.rm_rf('app/helpers/application_helper.rb') rescue nil
83
+
84
+ if self.options.git or shell.yes?('Initialize git? [yN]:')
85
+ system(%{ git init > /dev/null })
86
+
87
+ Milkshake::Template.evaluate('gitignore'
88
+ ).write_to('.gitignore')
89
+
90
+ system(%{ git add . > /dev/null })
91
+ system(%{ git commit -m "First import" > /dev/null })
92
+ end
93
+ end
94
+
95
+ good_say('Jeweler successfully installed!')
96
+ end
97
+
98
+ def install_host!
99
+ goto_rails do |rails_root|
100
+ (rails_root + 'README').unlink rescue nil
101
+ (rails_root + 'Rakefile').unlink rescue nil
102
+ (rails_root + 'app').rmtree rescue nil
103
+ (rails_root + 'config/locales').rmtree rescue nil
104
+ (rails_root + 'db/seeds.rb').unlink rescue nil
105
+ (rails_root + 'doc').rmtree rescue nil
106
+ (rails_root + 'lib').rmtree rescue nil
107
+ (rails_root + 'public/images').rmtree rescue nil
108
+ (rails_root + 'public/javascripts').rmtree rescue nil
109
+ (rails_root + 'public/stylesheets').rmtree rescue nil
110
+ (rails_root + 'test').rmtree rescue nil
111
+ (rails_root + 'vendor').rmtree rescue nil
112
+ end
113
+
114
+ good_say('Rails app successfully stripped!')
115
+ end
116
+
117
+ def ensure_extrernalized_data!(shared_path)
118
+ shared_path = pathname_for(shared_path)
119
+ if shared_path.exist?
120
+ link_externalized_data! shared_path
121
+ else
122
+ externalize_data! shared_path
123
+ end
124
+ end
125
+
126
+ def externalize_data!(shared_path)
127
+ shared_path = pathname_for(shared_path)
128
+
129
+ goto_rails do |rails_path|
130
+
131
+ if (rails_path + 'config/settings').symlink?
132
+ bad_say("The data of this rails app seems to be already extracted!")
133
+ end
134
+
135
+ assert_new_shared_path! shared_path
136
+ shared_path.mkpath
137
+
138
+ (rails_path + 'public/system').mkpath
139
+ (rails_path + 'config/settings').mkpath
140
+
141
+ swap_and_make_symlink!(
142
+ rails_path + 'db',
143
+ shared_path + 'private')
144
+
145
+ swap_and_make_symlink!(
146
+ rails_path + 'log',
147
+ shared_path + 'log')
148
+
149
+ swap_and_make_symlink!(
150
+ rails_path + 'public/system',
151
+ shared_path + 'public')
152
+
153
+ swap_and_make_symlink!(
154
+ rails_path + 'config/settings',
155
+ shared_path + 'settings')
156
+
157
+ swap_and_make_symlink!(
158
+ rails_path + 'config/milkshake.yml',
159
+ shared_path + 'settings/milkshake.yml')
160
+
161
+ swap_and_make_symlink!(
162
+ rails_path + 'config/database.yml',
163
+ shared_path + 'settings/database.yml')
164
+
165
+ end
166
+
167
+ if self.options.git or shell.yes?('Initialize git? [yN]:')
168
+ Dir.chdir(shared_path.to_s) do
169
+ system(%{ git init > /dev/null })
170
+
171
+ Milkshake::Template.evaluate('gitignore_for_data'
172
+ ).write_to('.gitignore')
173
+
174
+ system(%{ git add . > /dev/null })
175
+ system(%{ git commit -m "First snapshot" > /dev/null })
176
+ end
177
+ end
178
+
179
+ good_say('Data files successfully externalized!')
180
+ end
181
+
182
+ def link_externalized_data!(shared_path)
183
+ shared_path = pathname_for(shared_path)
184
+ assert_shared_path! shared_path
185
+
186
+ goto_rails do |rails_path|
187
+
188
+ (rails_path + 'db').rmtree
189
+ make_symlink!(
190
+ rails_path + 'db',
191
+ shared_path + 'private')
192
+
193
+ (rails_path + 'log').rmtree
194
+ make_symlink!(
195
+ rails_path + 'log',
196
+ shared_path + 'log')
197
+
198
+ (rails_path + 'public/system').rmtree
199
+ make_symlink!(
200
+ rails_path + 'public/system',
201
+ shared_path + 'public')
202
+
203
+ (rails_path + 'config/settings').rmtree
204
+ make_symlink!(
205
+ rails_path + 'config/settings',
206
+ shared_path + 'settings')
207
+
208
+ (rails_path + 'config/milkshake.yml').unlink
209
+ make_symlink!(
210
+ rails_path + 'config/milkshake.yml',
211
+ shared_path + 'settings/milkshake.yml')
212
+
213
+ (rails_path + 'config/database.yml').unlink
214
+ make_symlink!(
215
+ rails_path + 'config/database.yml',
216
+ shared_path + 'settings/database.yml')
217
+
218
+ end
219
+ end
220
+
221
+ end
222
+ end
223
+ end
@@ -0,0 +1,48 @@
1
+
2
+ module Milkshake
3
+ class App
4
+ module Defaults
5
+
6
+ def default_author
7
+ @default_author ||= begin
8
+ name = %x[git config --get user.name].chomp
9
+ name = 'FIX_ME_AUTHOR' if name.nil? or name.empty?
10
+ name
11
+ end
12
+ end
13
+
14
+ def default_email
15
+ @default_email ||= begin
16
+ email = %x[git config --get user.email].chomp
17
+ email = 'FIX_ME_EMAIL' if email.nil? or email.empty?
18
+ email
19
+ end
20
+ end
21
+
22
+ def default_environment
23
+ @default_environment ||= begin
24
+ ENV['RAILS_ENV'] || 'development'
25
+ end
26
+ end
27
+
28
+ def default_summary
29
+ 'FIX_ME_SUMMARY'
30
+ end
31
+
32
+ def default_description
33
+ 'FIX_ME_DESCRIPTION'
34
+ end
35
+
36
+ def default_website
37
+ 'FIX_ME_WEBSITE'
38
+ end
39
+
40
+ def rename_task(names={})
41
+ names.each do |old_name, new_name|
42
+ self.tasks[new_name.to_s] = self.tasks.delete(old_name.to_s)
43
+ end
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,113 @@
1
+
2
+ module Milkshake
3
+ class App
4
+ module Helpers
5
+ private
6
+
7
+ def load_environment!
8
+ Object.const_set('RAILS_ROOT', rails_root) rescue nil
9
+ ENV['RAILS_ENV'] = environment
10
+ $rails_rake_task = true
11
+ require(File.join(RAILS_ROOT, 'config', 'environment'))
12
+ end
13
+
14
+ def rails_root
15
+ return @rails_root if @rails_root
16
+
17
+ root_path = self.options.app
18
+ root_path = File.expand_path(root_path)
19
+
20
+ unless File.directory?(root_path) and File.file?(File.join(root_path, 'config', 'environment.rb'))
21
+ bad_say("This is not a rails application!\n#{root_path}")
22
+ end
23
+
24
+ @rails_root = root_path
25
+ end
26
+
27
+ def goto_rails(path=nil)
28
+ Dir.chdir(path || rails_root) do
29
+ yield(Pathname.pwd)
30
+ end
31
+ end
32
+
33
+ def environment
34
+ self.options.environment
35
+ end
36
+
37
+ def good_say(msg)
38
+ shell.say(msg, Thor::Shell::Color::GREEN)
39
+ end
40
+
41
+ def bad_say(msg, exit=true)
42
+ shell.say(msg, Thor::Shell::Color::RED)
43
+ exit(1) if exit
44
+ end
45
+
46
+ def ask_with_default(statement, default=nil, color=nil)
47
+ if default
48
+ answer = shell.ask(statement+" [#{default}]:", color)
49
+ answer = default if answer.nil? or answer.strip.empty?
50
+ answer.strip
51
+ else
52
+ shell.ask(statement, color)
53
+ end
54
+ end
55
+
56
+ def ask_unless_given(statement, value=nil, default=nil, color=nil)
57
+ if !value.nil? and value != default
58
+ value
59
+ else
60
+ ask_with_default(statement, default, color)
61
+ end
62
+ end
63
+
64
+ def assert_valid_gem_name!(name)
65
+ unless name =~ /^[a-zA-Z0-9_-]+$/
66
+ bad_say "please specify a valid gem name (/^[a-zA-Z0-9_-]+$/)"
67
+ end
68
+ end
69
+
70
+ def assert_new_app_path!
71
+ if File.exist?(self.options.app)
72
+ bad_say("This path already exists!\n#{self.options.app}")
73
+ end
74
+ end
75
+
76
+ def assert_new_shared_path!(path)
77
+ if path.exist?
78
+ bad_say("This path already exists!\n#{path}")
79
+ end
80
+ end
81
+
82
+ def assert_shared_path!(path)
83
+ unless path.exist?
84
+ bad_say("This path already exists!\n#{path}")
85
+ end
86
+ end
87
+
88
+ def pathname_for(path, expand=true)
89
+ path = Pathname.new(path) unless Pathname === path
90
+ path = path.expand_path
91
+ path
92
+ end
93
+
94
+ def override_app_path!(path)
95
+ path = File.expand_path(path)
96
+ @options = @options.dup
97
+ @options['app'] = path
98
+ end
99
+
100
+ def make_symlink!(old_path, new_path)
101
+ Dir.chdir(old_path.dirname.to_s) do
102
+ old_path.basename.make_symlink(new_path.relative_path_from(old_path.dirname))
103
+ end
104
+ end
105
+
106
+ def swap_and_make_symlink!(old_path, new_path)
107
+ old_path.rename(new_path)
108
+ make_symlink! old_path, new_path
109
+ end
110
+
111
+ end
112
+ end
113
+ end