[R] |
name |
The name of the application (typically ‘rake’)
|
[R] |
original_dir |
The original directory where rake was invoked.
|
[R] |
rakefile |
Name of the actual rakefile used.
|
[R] |
top_level_tasks |
List of the top level task names (task names from the command line).
|
Included modules
31: def initialize
32: super
33: @name = 'rake'
34: @rakefiles = DEFAULT_RAKEFILES.dup
35: @rakefile = nil
36: @pending_imports = []
37: @imported = []
38: @loaders = {}
39: @default_loader = Rake::DefaultLoader.new
40: @original_dir = Dir.pwd
41: @top_level_tasks = []
42: add_loader('rb', DefaultLoader.new)
43: add_loader('rf', DefaultLoader.new)
44: add_loader('rake', DefaultLoader.new)
45: @tty_output = STDOUT.tty?
46: end
Add a file to the list of files to be imported.
541: def add_import(fn)
542: @pending_imports << fn
543: end
Add a loader to handle imported files ending in the extension ext.
97: def add_loader(ext, loader)
98: ext = ".#{ext}" unless ext =~ /^\./
99: @loaders[ext] = loader
100: end
Collect the list of tasks on the command line. If no tasks are given,
return a list containing only the default task. Environmental assignments
are processed at this time as well.
528: def collect_tasks
529: @top_level_tasks = []
530: ARGV.each do |arg|
531: if arg =~ /^(\w+)=(.*)$/
532: ENV[$1] = $2
533: else
534: @top_level_tasks << arg unless arg =~ /^-/
535: end
536: end
537: @top_level_tasks.push("default") if @top_level_tasks.size == 0
538: end
Warn about deprecated use of top level constant names.
560: def const_warning(const_name)
561: @const_warning ||= false
562: if ! @const_warning
563: $stderr.puts %{WARNING: Deprecated reference to top-level constant '#{const_name}' } +
564: %{found at: #{rakefile_location}}
565: $stderr.puts %{ Use --classic-namespace on rake command}
566: $stderr.puts %{ or 'require "rake/classic_namespace"' in Rakefile}
567: end
568: @const_warning = true
569: end
Display the error message that caused the exception.
144: def display_error_message(ex)
145: $stderr.puts "#{name} aborted!"
146: $stderr.puts ex.message
147: if options.trace
148: $stderr.puts ex.backtrace.join("\n")
149: else
150: $stderr.puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
151: end
152: $stderr.puts "Tasks: #{ex.chain}" if has_chain?(ex)
153: $stderr.puts "(See full trace by running task with --trace)" unless options.trace
154: end
Display the tasks and prerequisites
265: def display_prerequisites
266: tasks.each do |t|
267: puts "#{name} #{t.name}"
268: t.prerequisites.each { |pre| puts " #{pre}" }
269: end
270: end
Display the tasks and comments.
193: def display_tasks_and_comments
194: displayable_tasks = tasks.select { |t|
195: t.comment && t.name =~ options.show_task_pattern
196: }
197: case options.show_tasks
198: when :tasks
199: width = displayable_tasks.collect { |t| t.name_with_args.length }.max || 10
200: max_column = truncate_output? ? terminal_width - name.size - width - 7 : nil
201: displayable_tasks.each do |t|
202: printf "#{name} %-#{width}s # %s\n",
203: t.name_with_args, max_column ? truncate(t.comment, max_column) : t.comment
204: end
205: when :describe
206: displayable_tasks.each do |t|
207: puts "#{name} #{t.name_with_args}"
208: t.full_comment.split("\n").each do |line|
209: puts " #{line}"
210: end
211: puts
212: end
213: when :lines
214: displayable_tasks.each do |t|
215: t.locations.each do |loc|
216: printf "#{name} %-30s %s\n",t.name_with_args, loc
217: end
218: end
219: else
220: fail "Unknown show task mode: '#{options.show_tasks}'"
221: end
222: end
Calculate the dynamic width of the
236: def dynamic_width
237: @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
238: end
240: def dynamic_width_stty
241: %x{stty size 2>/dev/null}.split[1].to_i
242: end
244: def dynamic_width_tput
245: %x{tput cols 2>/dev/null}.to_i
246: end
456: def find_rakefile_location
457: here = Dir.pwd
458: while ! (fn = have_rakefile)
459: Dir.chdir("..")
460: if Dir.pwd == here || options.nosearch
461: return nil
462: end
463: here = Dir.pwd
464: end
465: [fn, here]
466: ensure
467: Dir.chdir(Rake.original_dir)
468: end
Read and handle the command line options.
409: def handle_options
410: options.rakelib = ['rakelib']
411: options.top_level_dsl = true
412:
413: OptionParser.new do |opts|
414: opts.banner = "rake [-f rakefile] {options} targets..."
415: opts.separator ""
416: opts.separator "Options are ..."
417:
418: opts.on_tail("-h", "--help", "-H", "Display this help message.") do
419: puts opts
420: exit
421: end
422:
423: standard_rake_options.each { |args| opts.on(*args) }
424: opts.environment('RAKEOPT')
425: end.parse!
426:
427: Rake::DSL.include_in_top_scope if options.top_level_dsl
428:
429:
430:
431: if options.classic_namespace
432: $show_tasks = options.show_tasks
433: $show_prereqs = options.show_prereqs
434: $trace = options.trace
435: $dryrun = options.dryrun
436: $silent = options.silent
437: end
438: end
True if one of the files in RAKEFILES is in the current directory. If a
match is found, it is copied into @rakefile.
164: def have_rakefile
165: @rakefiles.each do |fn|
166: if File.exist?(fn)
167: others = Dir.glob(fn, File::FNM_CASEFOLD)
168: return others.size == 1 ? others.first : fn
169: elsif fn == ''
170: return fn
171: end
172: end
173: return nil
174: end
Initialize the command line parameters and app name.
67: def init(app_name='rake')
68: standard_exception_handling do
69: @name = app_name
70: handle_options
71: collect_tasks
72: end
73: end
private
—————————————————————-
109: def invoke_task(task_string)
110: name, args = parse_task_string(task_string)
111: t = self[name]
112: t.invoke(*args)
113: end
Load the pending list of imported files.
546: def load_imports
547: while fn = @pending_imports.shift
548: next if @imported.member?(fn)
549: if fn_task = lookup(fn)
550: fn_task.invoke
551: end
552: ext = File.extname(fn)
553: loader = @loaders[ext] || @default_loader
554: loader.load(fn)
555: @imported << fn
556: end
557: end
Find the rakefile and then load it and any pending imports.
76: def load_rakefile
77: standard_exception_handling do
78: raw_load_rakefile
79: end
80: end
103: def options
104: @options ||= OpenStruct.new
105: end
115: def parse_task_string(string)
116: if string =~ /^([^\[]+)(\[(.*)\])$/
117: name = $1
118: args = $3.split(/\s*,\s*/)
119: else
120: name = string
121: args = []
122: end
123: [name, args]
124: end
Similar to the regular Ruby require command, but will check for
*.rake files in addition to *.rb files.
442: def rake_require(file_name, paths=$LOAD_PATH, loaded=$")
443: fn = file_name + ".rake"
444: return false if loaded.include?(fn)
445: paths.each do |path|
446: full_path = File.join(path, fn)
447: if File.exist?(full_path)
448: Rake::Environment.load_rakefile(full_path)
449: loaded << fn
450: return true
451: end
452: end
453: fail LoadError, "Can't find #{file_name}"
454: end
571: def rakefile_location
572: begin
573: fail
574: rescue RuntimeError => ex
575: ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
576: end
577: end
Run the Rake application. The run
method performs the following three steps:
If you wish to build a custom rake command, you should call init on your application. The
define any tasks. Finally, call top_level to run your top level tasks.
58: def run
59: standard_exception_handling do
60: init
61: load_rakefile
62: top_level
63: end
64: end
Provide standard execption handling for the given block.
127: def standard_exception_handling
128: begin
129: yield
130: rescue SystemExit => ex
131:
132: raise
133: rescue OptionParser::InvalidOption => ex
134: $stderr.puts ex.message
135: exit(false)
136: rescue Exception => ex
137:
138: display_error_message(ex)
139: exit(false)
140: end
141: end
A list of all the standard options
used in rake, suitable for passing to OptionParser.
274: def standard_rake_options
275: [
276: ['--classic-namespace', '-C', "Put Task and FileTask in the top level namespace",
277: lambda { |value|
278: require 'rake/classic_namespace'
279: options.classic_namespace = true
280: }
281: ],
282: ['--describe', '-D [PATTERN]', "Describe the tasks (matching optional PATTERN), then exit.",
283: lambda { |value|
284: options.show_tasks = :describe
285: options.show_task_pattern = Regexp.new(value || '')
286: TaskManager.record_task_metadata = true
287: }
288: ],
289: ['--dry-run', '-n', "Do a dry run without executing actions.",
290: lambda { |value|
291: Rake.verbose(true)
292: Rake.nowrite(true)
293: options.dryrun = true
294: options.trace = true
295: }
296: ],
297: ['--execute', '-e CODE', "Execute some Ruby code and exit.",
298: lambda { |value|
299: eval(value)
300: exit
301: }
302: ],
303: ['--execute-print', '-p CODE', "Execute some Ruby code, print the result, then exit.",
304: lambda { |value|
305: puts eval(value)
306: exit
307: }
308: ],
309: ['--execute-continue', '-E CODE',
310: "Execute some Ruby code, then continue with normal task processing.",
311: lambda { |value| eval(value) }
312: ],
313: ['--libdir', '-I LIBDIR', "Include LIBDIR in the search path for required modules.",
314: lambda { |value| $:.push(value) }
315: ],
316: ['--prereqs', '-P', "Display the tasks and dependencies, then exit.",
317: lambda { |value| options.show_prereqs = true }
318: ],
319: ['--quiet', '-q', "Do not log messages to standard output.",
320: lambda { |value| Rake.verbose(false) }
321: ],
322: ['--rakefile', '-f [FILE]', "Use FILE as the rakefile.",
323: lambda { |value|
324: value ||= ''
325: @rakefiles.clear
326: @rakefiles << value
327: }
328: ],
329: ['--rakelibdir', '--rakelib', '-R RAKELIBDIR',
330: "Auto-import any .rake files in RAKELIBDIR. (default is 'rakelib')",
331: lambda { |value| options.rakelib = value.split(':') }
332: ],
333: ['--require', '-r MODULE', "Require MODULE before executing rakefile.",
334: lambda { |value|
335: begin
336: require value
337: rescue LoadError => ex
338: begin
339: rake_require value
340: rescue LoadError => ex2
341: raise ex
342: end
343: end
344: }
345: ],
346: ['--rules', "Trace the rules resolution.",
347: lambda { |value| options.trace_rules = true }
348: ],
349: ['--no-search', '--nosearch', '-N', "Do not search parent directories for the Rakefile.",
350: lambda { |value| options.nosearch = true }
351: ],
352: ['--silent', '-s', "Like --quiet, but also suppresses the 'in directory' announcement.",
353: lambda { |value|
354: Rake.verbose(false)
355: options.silent = true
356: }
357: ],
358: ['--system', '-g',
359: "Using system wide (global) rakefiles (usually '~/.rake/*.rake').",
360: lambda { |value| options.load_system = true }
361: ],
362: ['--no-system', '--nosystem', '-G',
363: "Use standard project Rakefile search paths, ignore system wide rakefiles.",
364: lambda { |value| options.ignore_system = true }
365: ],
366: ['--tasks', '-T [PATTERN]', "Display the tasks (matching optional PATTERN) with descriptions, then exit.",
367: lambda { |value|
368: options.show_tasks = :tasks
369: options.show_task_pattern = Regexp.new(value || '')
370: Rake::TaskManager.record_task_metadata = true
371: }
372: ],
373: ['--no-top-level-dsl', '-X', "Do no put Rake DSL commands in the top level scope.",
374: lambda { |value|
375: options.top_level_dsl = ! value
376: }
377: ],
378: ['--top-level-dsl', "Put Rake DSL commands in the top level scope (default).",
379: lambda { |value|
380: options.top_level_dsl = value
381: }
382: ],
383: ['--trace', '-t', "Turn on invoke/execute tracing, enable full backtrace.",
384: lambda { |value|
385: options.trace = true
386: Rake.verbose(true)
387: }
388: ],
389: ['--verbose', '-v', "Log message to standard output.",
390: lambda { |value| Rake.verbose(true) }
391: ],
392: ['--version', '-V', "Display the program version.",
393: lambda { |value|
394: puts "rake, version #{RAKEVERSION}"
395: exit
396: }
397: ],
398: ['--where', '-W [PATTERN]', "Describe the tasks (matching optional PATTERN), then exit.",
399: lambda { |value|
400: options.show_tasks = :lines
401: options.show_task_pattern = Regexp.new(value || '')
402: Rake::TaskManager.record_task_metadata = true
403: }
404: ],
405: ]
406: end
The directory path containing the system wide rakefiles.
502: def system_dir
503: @system_dir ||=
504: begin
505: if ENV['RAKE_SYSTEM']
506: ENV['RAKE_SYSTEM']
507: else
508: standard_system_dir
509: end
510: end
511: end
224: def terminal_width
225: if ENV['RAKE_COLUMNS']
226: result = ENV['RAKE_COLUMNS'].to_i
227: else
228: result = unix? ? dynamic_width : 80
229: end
230: (result < 10) ? 80 : result
231: rescue
232: 80
233: end
Run the top level tasks of a Rake application.
83: def top_level
84: standard_exception_handling do
85: if options.show_tasks
86: display_tasks_and_comments
87: elsif options.show_prereqs
88: display_prerequisites
89: else
90: top_level_tasks.each { |task_name| invoke_task(task_name) }
91: end
92: end
93: end
256: def truncate(string, width)
257: if string.length <= width
258: string
259: else
260: ( string[0, width-3] || "" ) + "..."
261: end
262: end
We will truncate output if we are
outputting to a TTY or if we‘ve been given an explicit column width
to honor
188: def truncate_output?
189: tty_output? || ENV['RAKE_COLUMNS']
190: end
Override the detected TTY output state (mostly for testing)
182: def tty_output=( tty_output_state )
183: @tty_output = tty_output_state
184: end
True if we are outputting to TTY, false otherwise
177: def tty_output?
178: @tty_output
179: end
248: def unix?
249: Config::CONFIG['host_os'] =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i
250: end
252: def windows?
253: Win32.windows?
254: end