source: EcnlProtoTool/trunk/mruby-1.2.0/minirake@ 286

Last change on this file since 286 was 270, checked in by coas-nagasima, 7 years ago

mruby版ECNLプロトタイピング・ツールを追加

File size: 13.2 KB
Line 
1#!/usr/bin/env ruby
2
3# Original is https://github.com/jimweirich/rake/
4# Copyright (c) 2003 Jim Weirich
5# License: MIT-LICENSE
6
7require 'getoptlong'
8require 'fileutils'
9
10class String
11 def ext(newext='')
12 return self.dup if ['.', '..'].include? self
13 if newext != ''
14 newext = (newext =~ /^\./) ? newext : ("." + newext)
15 end
16 self.chomp(File.extname(self)) << newext
17 end
18
19 def pathmap(spec=nil, &block)
20 return self if spec.nil?
21 result = ''
22 spec.scan(/%\{[^}]*\}-?\d*[sdpfnxX%]|%-?\d+d|%.|[^%]+/) do |frag|
23 case frag
24 when '%f'
25 result << File.basename(self)
26 when '%n'
27 result << File.basename(self).ext
28 when '%d'
29 result << File.dirname(self)
30 when '%x'
31 result << File.extname(self)
32 when '%X'
33 result << self.ext
34 when '%p'
35 result << self
36 when '%s'
37 result << (File::ALT_SEPARATOR || File::SEPARATOR)
38 when '%-'
39 # do nothing
40 when '%%'
41 result << "%"
42 when /%(-?\d+)d/
43 result << pathmap_partial($1.to_i)
44 when /^%\{([^}]*)\}(\d*[dpfnxX])/
45 patterns, operator = $1, $2
46 result << pathmap('%' + operator).pathmap_replace(patterns, &block)
47 when /^%/
48 fail ArgumentError, "Unknown pathmap specifier #{frag} in '#{spec}'"
49 else
50 result << frag
51 end
52 end
53 result
54 end
55end
56
57module MiniRake
58 class Task
59 TASKS = Hash.new
60 RULES = Array.new
61
62 # List of prerequisites for a task.
63 attr_reader :prerequisites
64
65 # Source dependency for rule synthesized tasks. Nil if task was not
66 # sythesized from a rule.
67 attr_accessor :source
68
69 # Create a task named +task_name+ with no actions or prerequisites..
70 # use +enhance+ to add actions and prerequisites.
71 def initialize(task_name)
72 @name = task_name
73 @prerequisites = []
74 @actions = []
75 end
76
77 # Enhance a task with prerequisites or actions. Returns self.
78 def enhance(deps=nil, &block)
79 @prerequisites |= deps if deps
80 @actions << block if block_given?
81 self
82 end
83
84 # Name of the task.
85 def name
86 @name.to_s
87 end
88
89 # Invoke the task if it is needed. Prerequites are invoked first.
90 def invoke
91 puts "Invoke #{name} (already=[#{@already_invoked}], needed=[#{needed?}])" if $trace
92 return if @already_invoked
93 @already_invoked = true
94 prerequisites = @prerequisites.collect{ |n| n.is_a?(Proc) ? n.call(name) : n }.flatten
95 prerequisites.each { |n| Task[n].invoke }
96 execute if needed?
97 end
98
99 # Execute the actions associated with this task.
100 def execute
101 puts "Execute #{name}" if $trace
102 self.class.enhance_with_matching_rule(name) if @actions.empty?
103 unless $dryrun
104 @actions.each { |act| act.call(self) }
105 end
106 end
107
108 # Is this task needed?
109 def needed?
110 true
111 end
112
113 # Timestamp for this task. Basic tasks return the current time for
114 # their time stamp. Other tasks can be more sophisticated.
115 def timestamp
116 prerequisites = @prerequisites.collect{ |n| n.is_a?(Proc) ? n.call(name) : n }.flatten
117 prerequisites.collect { |n| Task[n].timestamp }.max || Time.now
118 end
119
120 # Class Methods ----------------------------------------------------
121
122 class << self
123
124 # Clear the task list. This cause rake to immediately forget all
125 # the tasks that have been assigned. (Normally used in the unit
126 # tests.)
127 def clear
128 TASKS.clear
129 RULES.clear
130 end
131
132 # List of all defined tasks.
133 def tasks
134 TASKS.keys.sort.collect { |tn| Task[tn] }
135 end
136
137 # Return a task with the given name. If the task is not currently
138 # known, try to synthesize one from the defined rules. If no
139 # rules are found, but an existing file matches the task name,
140 # assume it is a file task with no dependencies or actions.
141 def [](task_name)
142 task_name = task_name.to_s
143 if task = TASKS[task_name]
144 return task
145 end
146 if task = enhance_with_matching_rule(task_name)
147 return task
148 end
149 if File.exist?(task_name)
150 return FileTask.define_task(task_name)
151 end
152 fail "Don't know how to rake #{task_name}"
153 end
154
155 # Define a task given +args+ and an option block. If a rule with
156 # the given name already exists, the prerequisites and actions are
157 # added to the existing task.
158 def define_task(args, &block)
159 task_name, deps = resolve_args(args)
160 lookup(task_name).enhance([deps].flatten, &block)
161 end
162
163 # Define a rule for synthesizing tasks.
164 def create_rule(args, &block)
165 pattern, deps = resolve_args(args)
166 pattern = Regexp.new(Regexp.quote(pattern) + '$') if String === pattern
167 RULES << [pattern, deps, block]
168 end
169
170
171 # Lookup a task. Return an existing task if found, otherwise
172 # create a task of the current type.
173 def lookup(task_name)
174 name = task_name.to_s
175 TASKS[name] ||= self.new(name)
176 end
177
178 # If a rule can be found that matches the task name, enhance the
179 # task with the prerequisites and actions from the rule. Set the
180 # source attribute of the task appropriately for the rule. Return
181 # the enhanced task or nil of no rule was found.
182 def enhance_with_matching_rule(task_name)
183 RULES.each do |pattern, extensions, block|
184 if pattern.match(task_name)
185 ext = extensions.first
186 deps = extensions[1..-1]
187 case ext
188 when String
189 source = task_name.sub(/\.[^.]*$/, ext)
190 when Proc
191 source = ext.call(task_name)
192 else
193 fail "Don't know how to handle rule dependent: #{ext.inspect}"
194 end
195 if File.exist?(source)
196 task = FileTask.define_task({task_name => [source]+deps}, &block)
197 task.source = source
198 return task
199 end
200 end
201 end
202 nil
203 end
204
205 private
206
207 # Resolve the arguments for a task/rule.
208 def resolve_args(args)
209 case args
210 when Hash
211 fail "Too Many Task Names: #{args.keys.join(' ')}" if args.size > 1
212 fail "No Task Name Given" if args.size < 1
213 task_name = args.keys[0]
214 deps = args[task_name]
215 deps = [deps] if (String===deps) || (Regexp===deps) || (Proc===deps)
216 else
217 task_name = args
218 deps = []
219 end
220 [task_name, deps]
221 end
222 end
223 end
224
225
226 ######################################################################
227 class FileTask < Task
228 # Is this file task needed? Yes if it doesn't exist, or if its time
229 # stamp is out of date.
230 def needed?
231 return true unless File.exist?(name)
232 prerequisites = @prerequisites.collect{ |n| n.is_a?(Proc) ? n.call(name) : n }.flatten
233 latest_prereq = prerequisites.collect{|n| Task[n].timestamp}.max
234 return false if latest_prereq.nil?
235 timestamp < latest_prereq
236 end
237
238 # Time stamp for file task.
239 def timestamp
240 stat = File::stat(name.to_s)
241 stat.directory? ? Time.at(0) : stat.mtime
242 end
243 end
244
245 module DSL
246 # Declare a basic task.
247 def task(args, &block)
248 MiniRake::Task.define_task(args, &block)
249 end
250
251 # Declare a file task.
252 def file(args, &block)
253 MiniRake::FileTask.define_task(args, &block)
254 end
255
256 # Declare a set of files tasks to create the given directories on
257 # demand.
258 def directory(args, &block)
259 MiniRake::FileTask.define_task(args) do |t|
260 block.call(t) unless block.nil?
261 dir = args.is_a?(Hash) ? args.keys.first : args
262 (dir.split(File::SEPARATOR) + ['']).inject do |acc, part|
263 (acc + File::SEPARATOR).tap do |d|
264 Dir.mkdir(d) unless File.exists? d
265 end + part
266 end
267 end
268 end
269
270 # Declare a rule for auto-tasks.
271 def rule(args, &block)
272 MiniRake::Task.create_rule(args, &block)
273 end
274
275 # Write a message to standard out if $verbose is enabled.
276 def log(msg)
277 print " " if $trace && $verbose
278 puts msg if $verbose
279 end
280
281 # Run the system command +cmd+.
282 def sh(cmd)
283 puts cmd if $verbose
284 system(cmd) or fail "Command Failed: [#{cmd}]"
285 end
286
287 def desc(text)
288 end
289 end
290end
291
292Rake = MiniRake
293extend MiniRake::DSL
294
295
296######################################################################
297# Task Definition Functions ...
298
299######################################################################
300# Rake main application object. When invoking +rake+ from the command
301# line, a RakeApp object is created and run.
302#
303class RakeApp
304 RAKEFILES = ['rakefile', 'Rakefile']
305
306 OPTIONS = [
307 ['--dry-run', '-n', GetoptLong::NO_ARGUMENT,
308 "Do a dry run without executing actions."],
309 ['--help', '-H', GetoptLong::NO_ARGUMENT,
310 "Display this help message."],
311 ['--libdir', '-I', GetoptLong::REQUIRED_ARGUMENT,
312 "Include LIBDIR in the search path for required modules."],
313 ['--nosearch', '-N', GetoptLong::NO_ARGUMENT,
314 "Do not search parent directories for the Rakefile."],
315 ['--quiet', '-q', GetoptLong::NO_ARGUMENT,
316 "Do not log messages to standard output (default)."],
317 ['--rakefile', '-f', GetoptLong::REQUIRED_ARGUMENT,
318 "Use FILE as the rakefile."],
319 ['--require', '-r', GetoptLong::REQUIRED_ARGUMENT,
320 "Require MODULE before executing rakefile."],
321 ['--tasks', '-T', GetoptLong::NO_ARGUMENT,
322 "Display the tasks and dependencies, then exit."],
323 ['--pull-gems','-p', GetoptLong::NO_ARGUMENT,
324 "Pull all git mrbgems."],
325 ['--trace', '-t', GetoptLong::NO_ARGUMENT,
326 "Turn on invoke/execute tracing."],
327 ['--usage', '-h', GetoptLong::NO_ARGUMENT,
328 "Display usage."],
329 ['--verbose', '-v', GetoptLong::NO_ARGUMENT,
330 "Log message to standard output."],
331 ['--directory', '-C', GetoptLong::REQUIRED_ARGUMENT,
332 "Change executing directory of rakefiles."]
333 ]
334
335 # Create a RakeApp object.
336 def initialize
337 @rakefile = nil
338 @nosearch = false
339 end
340
341 # True if one of the files in RAKEFILES is in the current directory.
342 # If a match is found, it is copied into @rakefile.
343 def have_rakefile
344 RAKEFILES.each do |fn|
345 if File.exist?(fn)
346 @rakefile = fn
347 return true
348 end
349 end
350 return false
351 end
352
353 # Display the program usage line.
354 def usage
355 puts "rake [-f rakefile] {options} targets..."
356 end
357
358 # Display the rake command line help.
359 def help
360 usage
361 puts
362 puts "Options are ..."
363 puts
364 OPTIONS.sort.each do |long, short, mode, desc|
365 if mode == GetoptLong::REQUIRED_ARGUMENT
366 if desc =~ /\b([A-Z]{2,})\b/
367 long = long + "=#{$1}"
368 end
369 end
370 printf " %-20s (%s)\n", long, short
371 printf " %s\n", desc
372 end
373 end
374
375 # Display the tasks and dependencies.
376 def display_tasks
377 MiniRake::Task.tasks.each do |t|
378 puts "#{t.class} #{t.name}"
379 t.prerequisites.each { |pre| puts " #{pre}" }
380 end
381 end
382
383 # Return a list of the command line options supported by the
384 # program.
385 def command_line_options
386 OPTIONS.collect { |lst| lst[0..-2] }
387 end
388
389 # Do the option defined by +opt+ and +value+.
390 def do_option(opt, value)
391 case opt
392 when '--dry-run'
393 $dryrun = true
394 $trace = true
395 when '--help'
396 help
397 exit
398 when '--libdir'
399 $:.push(value)
400 when '--nosearch'
401 @nosearch = true
402 when '--quiet'
403 $verbose = false
404 when '--rakefile'
405 RAKEFILES.clear
406 RAKEFILES << value
407 when '--require'
408 require value
409 when '--tasks'
410 $show_tasks = true
411 when '--pull-gems'
412 $pull_gems = true
413 when '--trace'
414 $trace = true
415 when '--usage'
416 usage
417 exit
418 when '--verbose'
419 $verbose = true
420 when '--version'
421 puts "rake, version #{RAKEVERSION}"
422 exit
423 when '--directory'
424 Dir.chdir value
425 else
426 fail "Unknown option: #{opt}"
427 end
428 end
429
430 # Read and handle the command line options.
431 def handle_options
432 $verbose = false
433 $pull_gems = false
434 opts = GetoptLong.new(*command_line_options)
435 opts.each { |opt, value| do_option(opt, value) }
436 end
437
438 # Run the +rake+ application.
439 def run
440 handle_options
441 begin
442 here = Dir.pwd
443 while ! have_rakefile
444 Dir.chdir("..")
445 if Dir.pwd == here || @nosearch
446 fail "No Rakefile found (looking for: #{RAKEFILES.join(', ')})"
447 end
448 here = Dir.pwd
449 end
450 tasks = []
451 ARGV.each do |task_name|
452 if /^(\w+)=(.*)/.match(task_name)
453 ENV[$1] = $2
454 else
455 tasks << task_name
456 end
457 end
458 puts "(in #{Dir.pwd})"
459 $rakefile = @rakefile
460 load @rakefile
461 if $show_tasks
462 display_tasks
463 else
464 tasks.push("default") if tasks.size == 0
465 tasks.each do |task_name|
466 MiniRake::Task[task_name].invoke
467 end
468 end
469 rescue Exception => ex
470 puts "rake aborted!"
471 puts ex.message
472 if $trace
473 puts ex.backtrace.join("\n")
474 else
475 puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
476 end
477 exit 1
478 end
479 end
480end
481
482if __FILE__ == $0 then
483 RakeApp.new.run
484end
Note: See TracBrowser for help on using the repository browser.