Changesets can be listed by changeset number.
The Git repository is here.
- Revision:
- 373
- Log:
Initial import of Radiant 0.9.1, which is now packaged as a gem. This is an
import of the tagged 0.9.1 source checked out from GitHub, which isn't quite
the same as the gem distribution - but it doesn't seem to be available in an
archived form and the installed gem already has modifications, so this is
the closest I can get.
- Author:
- rool
- Date:
- Mon Mar 21 13:40:05 +0000 2011
- Size:
- 11159 Bytes
1 | require File.dirname(__FILE__) + '/scm/scm' |
2 | require File.dirname(__FILE__) + '/scm/git' |
3 | require File.dirname(__FILE__) + '/scm/svn' |
4 | |
5 | require 'open-uri' |
6 | require 'fileutils' |
7 | |
8 | module Rails |
9 | class TemplateRunner |
10 | attr_reader :root |
11 | attr_writer :logger |
12 | |
13 | def initialize(template, root = '') # :nodoc: |
14 | @root = File.expand_path(File.directory?(root) ? root : File.join(Dir.pwd, root)) |
15 | |
16 | log 'applying', "template: #{template}" |
17 | |
18 | load_template(template) |
19 | |
20 | log 'applied', "#{template}" |
21 | end |
22 | |
23 | def load_template(template) |
24 | begin |
25 | code = open(template).read |
26 | in_root { self.instance_eval(code) } |
27 | rescue LoadError, Errno::ENOENT => e |
28 | raise "The template [#{template}] could not be loaded. Error: #{e}" |
29 | end |
30 | end |
31 | |
32 | # Create a new file in the Rails project folder. Specify the |
33 | # relative path from RAILS_ROOT. Data is the return value of a block |
34 | # or a data string. |
35 | # |
36 | # ==== Examples |
37 | # |
38 | # file("lib/fun_party.rb") do |
39 | # hostname = ask("What is the virtual hostname I should use?") |
40 | # "vhost.name = #{hostname}" |
41 | # end |
42 | # |
43 | # file("config/apach.conf", "your apache config") |
44 | # |
45 | def file(filename, data = nil, log_action = true, &block) |
46 | log 'file', filename if log_action |
47 | dir, file = [File.dirname(filename), File.basename(filename)] |
48 | |
49 | inside(dir) do |
50 | File.open(file, "w") do |f| |
51 | if block_given? |
52 | f.write(block.call) |
53 | else |
54 | f.write(data) |
55 | end |
56 | end |
57 | end |
58 | end |
59 | |
60 | # Install a plugin. You must provide either a Subversion url or Git url. |
61 | # For a Git-hosted plugin, you can specify if it should be added as a submodule instead of cloned. |
62 | # |
63 | # ==== Examples |
64 | # |
65 | # plugin 'restful-authentication', :git => 'git://github.com/technoweenie/restful-authentication.git' |
66 | # plugin 'restful-authentication', :git => 'git://github.com/technoweenie/restful-authentication.git', :submodule => true |
67 | # plugin 'restful-authentication', :svn => 'svn://svnhub.com/technoweenie/restful-authentication/trunk' |
68 | # |
69 | def plugin(name, options) |
70 | log 'plugin', name |
71 | |
72 | if options[:git] && options[:submodule] |
73 | in_root do |
74 | Git.run("submodule add #{options[:git]} vendor/plugins/#{name}") |
75 | end |
76 | elsif options[:git] || options[:svn] |
77 | in_root do |
78 | run_ruby_script("script/plugin install #{options[:svn] || options[:git]}", false) |
79 | end |
80 | else |
81 | log "! no git or svn provided for #{name}. skipping..." |
82 | end |
83 | end |
84 | |
85 | # Adds an entry into config/environment.rb for the supplied gem : |
86 | def gem(name, options = {}) |
87 | log 'gem', name |
88 | env = options.delete(:env) |
89 | |
90 | gems_code = "config.gem '#{name}'" |
91 | |
92 | if options.any? |
93 | opts = options.inject([]) {|result, h| result << [":#{h[0]} => #{h[1].inspect.gsub('"',"'")}"] }.sort.join(", ") |
94 | gems_code << ", #{opts}" |
95 | end |
96 | |
97 | environment gems_code, :env => env |
98 | end |
99 | |
100 | # Adds a line inside the Initializer block for config/environment.rb. Used by #gem |
101 | # If options :env is specified, the line is appended to the corresponding |
102 | # file in config/environments/#{env}.rb |
103 | def environment(data = nil, options = {}, &block) |
104 | sentinel = 'Rails::Initializer.run do |config|' |
105 | |
106 | data = block.call if !data && block_given? |
107 | |
108 | in_root do |
109 | if options[:env].nil? |
110 | gsub_file 'config/environment.rb', /(#{Regexp.escape(sentinel)})/mi do |match| |
111 | "#{match}\n " << data |
112 | end |
113 | else |
114 | Array.wrap(options[:env]).each do|env| |
115 | append_file "config/environments/#{env}.rb", "\n#{data}" |
116 | end |
117 | end |
118 | end |
119 | end |
120 | |
121 | # Run a command in git. |
122 | # |
123 | # ==== Examples |
124 | # |
125 | # git :init |
126 | # git :add => "this.file that.rb" |
127 | # git :add => "onefile.rb", :rm => "badfile.cxx" |
128 | # |
129 | def git(command = {}) |
130 | in_root do |
131 | if command.is_a?(Symbol) |
132 | log 'running', "git #{command}" |
133 | Git.run(command.to_s) |
134 | else |
135 | command.each do |command, options| |
136 | log 'running', "git #{command} #{options}" |
137 | Git.run("#{command} #{options}") |
138 | end |
139 | end |
140 | end |
141 | end |
142 | |
143 | # Create a new file in the vendor/ directory. Code can be specified |
144 | # in a block or a data string can be given. |
145 | # |
146 | # ==== Examples |
147 | # |
148 | # vendor("sekrit.rb") do |
149 | # sekrit_salt = "#{Time.now}--#{3.years.ago}--#{rand}--" |
150 | # "salt = '#{sekrit_salt}'" |
151 | # end |
152 | # |
153 | # vendor("foreign.rb", "# Foreign code is fun") |
154 | # |
155 | def vendor(filename, data = nil, &block) |
156 | log 'vendoring', filename |
157 | file("vendor/#{filename}", data, false, &block) |
158 | end |
159 | |
160 | # Create a new file in the lib/ directory. Code can be specified |
161 | # in a block or a data string can be given. |
162 | # |
163 | # ==== Examples |
164 | # |
165 | # lib("crypto.rb") do |
166 | # "crypted_special_value = '#{rand}--#{Time.now}--#{rand(1337)}--'" |
167 | # end |
168 | # |
169 | # lib("foreign.rb", "# Foreign code is fun") |
170 | # |
171 | def lib(filename, data = nil, &block) |
172 | log 'lib', filename |
173 | file("lib/#{filename}", data, false, &block) |
174 | end |
175 | |
176 | # Create a new Rakefile with the provided code (either in a block or a string). |
177 | # |
178 | # ==== Examples |
179 | # |
180 | # rakefile("bootstrap.rake") do |
181 | # project = ask("What is the UNIX name of your project?") |
182 | # |
183 | # <<-TASK |
184 | # namespace :#{project} do |
185 | # task :bootstrap do |
186 | # puts "i like boots!" |
187 | # end |
188 | # end |
189 | # TASK |
190 | # end |
191 | # |
192 | # rakefile("seed.rake", "puts 'im plantin ur seedz'") |
193 | # |
194 | def rakefile(filename, data = nil, &block) |
195 | log 'rakefile', filename |
196 | file("lib/tasks/#{filename}", data, false, &block) |
197 | end |
198 | |
199 | # Create a new initializer with the provided code (either in a block or a string). |
200 | # |
201 | # ==== Examples |
202 | # |
203 | # initializer("globals.rb") do |
204 | # data = "" |
205 | # |
206 | # ['MY_WORK', 'ADMINS', 'BEST_COMPANY_EVAR'].each do |
207 | # data << "#{const} = :entp" |
208 | # end |
209 | # |
210 | # data |
211 | # end |
212 | # |
213 | # initializer("api.rb", "API_KEY = '123456'") |
214 | # |
215 | def initializer(filename, data = nil, &block) |
216 | log 'initializer', filename |
217 | file("config/initializers/#{filename}", data, false, &block) |
218 | end |
219 | |
220 | # Generate something using a generator from Rails or a plugin. |
221 | # The second parameter is the argument string that is passed to |
222 | # the generator or an Array that is joined. |
223 | # |
224 | # ==== Example |
225 | # |
226 | # generate(:authenticated, "user session") |
227 | # |
228 | def generate(what, *args) |
229 | log 'generating', what |
230 | argument = args.map(&:to_s).flatten.join(" ") |
231 | |
232 | in_root { run_ruby_script("script/generate #{what} #{argument}", false) } |
233 | end |
234 | |
235 | # Executes a command |
236 | # |
237 | # ==== Example |
238 | # |
239 | # inside('vendor') do |
240 | # run('ln -s ~/edge rails') |
241 | # end |
242 | # |
243 | def run(command, log_action = true) |
244 | log 'executing', "#{command} from #{Dir.pwd}" if log_action |
245 | `#{command}` |
246 | end |
247 | |
248 | # Executes a ruby script (taking into account WIN32 platform quirks) |
249 | def run_ruby_script(command, log_action = true) |
250 | ruby_command = RUBY_PLATFORM=~ /win32/ ? 'ruby ' : '' |
251 | run("#{ruby_command}#{command}", log_action) |
252 | end |
253 | |
254 | # Runs the supplied rake task |
255 | # |
256 | # ==== Example |
257 | # |
258 | # rake("db:migrate") |
259 | # rake("db:migrate", :env => "production") |
260 | # rake("gems:install", :sudo => true) |
261 | # |
262 | def rake(command, options = {}) |
263 | log 'rake', command |
264 | env = options[:env] || 'development' |
265 | sudo = options[:sudo] ? 'sudo ' : '' |
266 | in_root { run("#{sudo}rake #{command} RAILS_ENV=#{env}", false) } |
267 | end |
268 | |
269 | # Just run the capify command in root |
270 | # |
271 | # ==== Example |
272 | # |
273 | # capify! |
274 | # |
275 | def capify! |
276 | log 'capifying' |
277 | in_root { run('capify .', false) } |
278 | end |
279 | |
280 | # Add Rails to /vendor/rails |
281 | # |
282 | # ==== Example |
283 | # |
284 | # freeze! |
285 | # |
286 | def freeze!(args = {}) |
287 | log 'vendor', 'rails edge' |
288 | in_root { run('rake rails:freeze:edge', false) } |
289 | end |
290 | |
291 | # Make an entry in Rails routing file conifg/routes.rb |
292 | # |
293 | # === Example |
294 | # |
295 | # route "map.root :controller => :welcome" |
296 | # |
297 | def route(routing_code) |
298 | log 'route', routing_code |
299 | sentinel = 'ActionController::Routing::Routes.draw do |map|' |
300 | |
301 | in_root do |
302 | gsub_file 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |match| |
303 | "#{match}\n #{routing_code}\n" |
304 | end |
305 | end |
306 | end |
307 | |
308 | protected |
309 | |
310 | # Get a user's input |
311 | # |
312 | # ==== Example |
313 | # |
314 | # answer = ask("Should I freeze the latest Rails?") |
315 | # freeze! if ask("Should I freeze the latest Rails?") == "yes" |
316 | # |
317 | def ask(string) |
318 | log '', string |
319 | STDIN.gets.strip |
320 | end |
321 | |
322 | # Do something in the root of the Rails application or |
323 | # a provided subfolder; the full path is yielded to the block you provide. |
324 | # The path is set back to the previous path when the method exits. |
325 | def inside(dir = '', &block) |
326 | folder = File.join(root, dir) |
327 | FileUtils.mkdir_p(folder) unless File.exist?(folder) |
328 | FileUtils.cd(folder) { block.arity == 1 ? yield(folder) : yield } |
329 | end |
330 | |
331 | def in_root |
332 | FileUtils.cd(root) { yield } |
333 | end |
334 | |
335 | # Helper to test if the user says yes(y)? |
336 | # |
337 | # ==== Example |
338 | # |
339 | # freeze! if yes?("Should I freeze the latest Rails?") |
340 | # |
341 | def yes?(question) |
342 | answer = ask(question).downcase |
343 | answer == "y" || answer == "yes" |
344 | end |
345 | |
346 | # Helper to test if the user does NOT say yes(y)? |
347 | # |
348 | # ==== Example |
349 | # |
350 | # capify! if no?("Will you be using vlad to deploy your application?") |
351 | # |
352 | def no?(question) |
353 | !yes?(question) |
354 | end |
355 | |
356 | # Run a regular expression replacement on a file |
357 | # |
358 | # ==== Example |
359 | # |
360 | # gsub_file 'app/controllers/application_controller.rb', /#\s*(filter_parameter_logging :password)/, '\1' |
361 | # |
362 | def gsub_file(relative_destination, regexp, *args, &block) |
363 | path = destination_path(relative_destination) |
364 | content = File.read(path).gsub(regexp, *args, &block) |
365 | File.open(path, 'wb') { |file| file.write(content) } |
366 | end |
367 | |
368 | # Append text to a file |
369 | # |
370 | # ==== Example |
371 | # |
372 | # append_file 'config/environments/test.rb', 'config.gem "rspec"' |
373 | # |
374 | def append_file(relative_destination, data) |
375 | path = destination_path(relative_destination) |
376 | File.open(path, 'ab') { |file| file.write(data) } |
377 | end |
378 | |
379 | def destination_path(relative_destination) |
380 | File.join(root, relative_destination) |
381 | end |
382 | |
383 | def log(action, message = '') |
384 | logger.log(action, message) |
385 | end |
386 | |
387 | def logger |
388 | @logger ||= Rails::Generator::Base.logger |
389 | end |
390 | |
391 | def logger |
392 | @logger ||= if defined?(Rails::Generator::Base) |
393 | Rails::Generator::Base.logger |
394 | else |
395 | require 'rails_generator/simple_logger' |
396 | Rails::Generator::SimpleLogger.new(STDOUT) |
397 | end |
398 | end |
399 | |
400 | end |
401 | end |