Changeset 439 for EcnlProtoTool/trunk/mruby-2.1.1/minirake
- Timestamp:
- Jul 9, 2020, 8:51:43 AM (4 years ago)
- Location:
- EcnlProtoTool/trunk/mruby-2.1.1
- Files:
-
- 1 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
EcnlProtoTool/trunk/mruby-2.1.1/minirake
r331 r439 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 7 require 'getoptlong' 8 require 'fileutils' 9 10 class 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 55 end 56 57 module 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 Time.now 117 end 118 119 # Class Methods ---------------------------------------------------- 120 121 class << self 122 123 # Clear the task list. This cause rake to immediately forget all 124 # the tasks that have been assigned. (Normally used in the unit 125 # tests.) 126 def clear 127 TASKS.clear 128 RULES.clear 129 end 130 131 # List of all defined tasks. 132 def tasks 133 TASKS.keys.sort.collect { |tn| Task[tn] } 134 end 135 136 # Return a task with the given name. If the task is not currently 137 # known, try to synthesize one from the defined rules. If no 138 # rules are found, but an existing file matches the task name, 139 # assume it is a file task with no dependencies or actions. 140 def [](task_name) 141 task_name = task_name.to_s 142 if task_name.end_with?(":") 143 task_name = task_name.slice(0, task_name.length - 1) 144 end 145 if task = TASKS[task_name] 146 return task 147 end 148 if task = enhance_with_matching_rule(task_name) 149 return task 150 end 151 if File.exist?(task_name) 152 return FileTask.define_task(task_name) 153 end 154 fail "Don't know how to rake #{task_name}" 155 end 156 157 # Define a task given +args+ and an option block. If a rule with 158 # the given name already exists, the prerequisites and actions are 159 # added to the existing task. 160 def define_task(args, &block) 161 task_name, deps = resolve_args(args) 162 lookup(task_name).enhance([deps].flatten, &block) 163 end 164 165 # Define a rule for synthesizing tasks. 166 def create_rule(args, &block) 167 pattern, deps = resolve_args(args) 168 pattern = Regexp.new(Regexp.quote(pattern) + '$') if String === pattern 169 RULES << [pattern, deps, block] 170 end 171 172 173 # Lookup a task. Return an existing task if found, otherwise 174 # create a task of the current type. 175 def lookup(task_name) 176 name = task_name.to_s 177 TASKS[name] ||= self.new(name) 178 end 179 180 # If a rule can be found that matches the task name, enhance the 181 # task with the prerequisites and actions from the rule. Set the 182 # source attribute of the task appropriately for the rule. Return 183 # the enhanced task or nil of no rule was found. 184 def enhance_with_matching_rule(task_name) 185 RULES.each do |pattern, extensions, block| 186 if pattern.match(task_name) 187 ext = extensions.first 188 deps = extensions[1..-1] 189 case ext 190 when String 191 source = task_name.sub(/\.[^.]*$/, ext) 192 when Proc 193 source = ext.call(task_name) 194 else 195 fail "Don't know how to handle rule dependent: #{ext.inspect}" 196 end 197 if File.exist?(source) 198 task = FileTask.define_task({task_name => [source]+deps}, &block) 199 task.source = source 200 return task 201 end 202 end 203 end 204 nil 205 end 206 207 private 208 209 # Resolve the arguments for a task/rule. 210 def resolve_args(args) 211 case args 212 when Hash 213 fail "Too Many Task Names: #{args.keys.join(' ')}" if args.size > 1 214 fail "No Task Name Given" if args.size < 1 215 task_name = args.keys[0] 216 deps = args[task_name] 217 deps = [deps] if (String===deps) || (Regexp===deps) || (Proc===deps) 218 else 219 task_name = args 220 deps = [] 221 end 222 [task_name, deps] 223 end 224 end 225 end 226 227 228 ###################################################################### 229 class FileTask < Task 230 # Is this file task needed? Yes if it doesn't exist, or if its time 231 # stamp is out of date. 232 def needed? 233 return true unless File.exist?(name) 234 prerequisites = @prerequisites.collect{ |n| n.is_a?(Proc) ? n.call(name) : n }.flatten 235 latest_prereq = prerequisites.collect{|n| Task[n].timestamp}.max 236 return false if latest_prereq.nil? 237 timestamp < latest_prereq 238 end 239 240 # Time stamp for file task. 241 def timestamp 242 return Time.at(0) unless File.exist?(name) 243 stat = File::stat(name.to_s) 244 stat.directory? ? Time.at(0) : stat.mtime 245 end 246 end 247 248 module DSL 249 # Declare a basic task. 250 def task(args, &block) 251 MiniRake::Task.define_task(args, &block) 252 end 253 254 # Declare a file task. 255 def file(args, &block) 256 MiniRake::FileTask.define_task(args, &block) 257 end 258 259 # Declare a set of files tasks to create the given directories on 260 # demand. 261 def directory(args, &block) 262 MiniRake::FileTask.define_task(args) do |t| 263 block.call(t) unless block.nil? 264 dir = args.is_a?(Hash) ? args.keys.first : args 265 (dir.split(File::SEPARATOR) + ['']).inject do |acc, part| 266 (acc + File::SEPARATOR).tap do |d| 267 Dir.mkdir(d) unless File.exists? d 268 end + part 269 end 270 end 271 end 272 273 # Declare a rule for auto-tasks. 274 def rule(args, &block) 275 MiniRake::Task.create_rule(args, &block) 276 end 277 278 # Write a message to standard out if $verbose is enabled. 279 def log(msg) 280 print " " if $trace && $verbose 281 puts msg if $verbose 282 end 283 284 # Run the system command +cmd+. 285 def sh(cmd) 286 puts cmd if $verbose 287 system(cmd) or fail "Command Failed: [#{cmd}]" 288 end 289 290 def desc(text) 291 end 292 end 293 end 294 295 Rake = MiniRake 296 extend MiniRake::DSL 297 298 299 ###################################################################### 300 # Task Definition Functions ... 301 302 ###################################################################### 303 # Rake main application object. When invoking +rake+ from the command 304 # line, a RakeApp object is created and run. 305 # 306 class RakeApp 307 RAKEFILES = ['rakefile', 'Rakefile'] 308 309 OPTIONS = [ 310 ['--dry-run', '-n', GetoptLong::NO_ARGUMENT, 311 "Do a dry run without executing actions."], 312 ['--help', '-H', GetoptLong::NO_ARGUMENT, 313 "Display this help message."], 314 ['--libdir', '-I', GetoptLong::REQUIRED_ARGUMENT, 315 "Include LIBDIR in the search path for required modules."], 316 ['--nosearch', '-N', GetoptLong::NO_ARGUMENT, 317 "Do not search parent directories for the Rakefile."], 318 ['--quiet', '-q', GetoptLong::NO_ARGUMENT, 319 "Do not log messages to standard output (default)."], 320 ['--rakefile', '-f', GetoptLong::REQUIRED_ARGUMENT, 321 "Use FILE as the rakefile."], 322 ['--require', '-r', GetoptLong::REQUIRED_ARGUMENT, 323 "Require MODULE before executing rakefile."], 324 ['--tasks', '-T', GetoptLong::NO_ARGUMENT, 325 "Display the tasks and dependencies, then exit."], 326 ['--pull-gems','-p', GetoptLong::NO_ARGUMENT, 327 "Pull all git mrbgems."], 328 ['--trace', '-t', GetoptLong::NO_ARGUMENT, 329 "Turn on invoke/execute tracing."], 330 ['--usage', '-h', GetoptLong::NO_ARGUMENT, 331 "Display usage."], 332 ['--verbose', '-v', GetoptLong::NO_ARGUMENT, 333 "Log message to standard output."], 334 ['--directory', '-C', GetoptLong::REQUIRED_ARGUMENT, 335 "Change executing directory of rakefiles."] 336 ] 337 338 # Create a RakeApp object. 339 def initialize 340 @rakefile = nil 341 @nosearch = false 342 end 343 344 # True if one of the files in RAKEFILES is in the current directory. 345 # If a match is found, it is copied into @rakefile. 346 def have_rakefile 347 RAKEFILES.each do |fn| 348 if File.exist?(fn) 349 @rakefile = fn 350 return true 351 end 352 end 353 return false 354 end 355 356 # Display the program usage line. 357 def usage 358 puts "rake [-f rakefile] {options} targets..." 359 end 360 361 # Display the rake command line help. 362 def help 363 usage 364 puts 365 puts "Options are ..." 366 puts 367 OPTIONS.sort.each do |long, short, mode, desc| 368 if mode == GetoptLong::REQUIRED_ARGUMENT 369 if desc =~ /\b([A-Z]{2,})\b/ 370 long = long + "=#{$1}" 371 end 372 end 373 printf " %-20s (%s)\n", long, short 374 printf " %s\n", desc 375 end 376 end 377 378 # Display the tasks and dependencies. 379 def display_tasks 380 MiniRake::Task.tasks.each do |t| 381 puts "#{t.class} #{t.name}" 382 t.prerequisites.each { |pre| puts " #{pre}" } 383 end 384 end 385 386 # Return a list of the command line options supported by the 387 # program. 388 def command_line_options 389 OPTIONS.collect { |lst| lst[0..-2] } 390 end 391 392 # Do the option defined by +opt+ and +value+. 393 def do_option(opt, value) 394 case opt 395 when '--dry-run' 396 $dryrun = true 397 $trace = true 398 when '--help' 399 help 400 exit 401 when '--libdir' 402 $:.push(value) 403 when '--nosearch' 404 @nosearch = true 405 when '--quiet' 406 $verbose = false 407 when '--rakefile' 408 RAKEFILES.clear 409 RAKEFILES << value 410 when '--require' 411 require value 412 when '--tasks' 413 $show_tasks = true 414 when '--pull-gems' 415 $pull_gems = true 416 when '--trace' 417 $trace = true 418 when '--usage' 419 usage 420 exit 421 when '--verbose' 422 $verbose = true 423 when '--version' 424 puts "rake, version #{RAKEVERSION}" 425 exit 426 when '--directory' 427 Dir.chdir value 428 else 429 fail "Unknown option: #{opt}" 430 end 431 end 432 433 # Read and handle the command line options. 434 def handle_options 435 $verbose = false 436 $pull_gems = false 437 opts = GetoptLong.new(*command_line_options) 438 opts.each { |opt, value| do_option(opt, value) } 439 end 440 441 # Run the +rake+ application. 442 def run 443 handle_options 444 begin 445 here = Dir.pwd 446 while ! have_rakefile 447 Dir.chdir("..") 448 if Dir.pwd == here || @nosearch 449 fail "No Rakefile found (looking for: #{RAKEFILES.join(', ')})" 450 end 451 here = Dir.pwd 452 end 453 tasks = [] 454 ARGV.each do |task_name| 455 if /^(\w+)=(.*)/.match(task_name) 456 ENV[$1] = $2 457 else 458 tasks << task_name 459 end 460 end 461 puts "(in #{Dir.pwd})" 462 $rakefile = @rakefile 463 load @rakefile 464 if $show_tasks 465 display_tasks 466 else 467 tasks.push("default") if tasks.size == 0 468 tasks.each do |task_name| 469 MiniRake::Task[task_name].invoke 470 end 471 end 472 rescue Exception => ex 473 puts "rake aborted!" 474 puts ex.message 475 if $trace 476 puts ex.backtrace.join("\n") 477 else 478 puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || "" 479 end 480 exit 1 481 end 482 end 483 end 484 485 if __FILE__ == $0 then 486 RakeApp.new.run 487 end 1 #! /usr/bin/env ruby 2 exec "rake", *ARGV
Note:
See TracChangeset
for help on using the changeset viewer.