From 618837e50ce689f917281ce464779bec8ed6188b Mon Sep 17 00:00:00 2001
From: Adam Salter <adam@codebright.net>
Date: Sun, 27 Jul 2008 23:59:49 +1000
Subject: [PATCH] added system-wide .rake functionality

---
 lib/rake.rb              |   43 ++++++++++++++++++++++++++++++++++++++++---
 test/test_application.rb |   32 ++++++++++++++++++++++++++++++++
 2 files changed, 72 insertions(+), 3 deletions(-)

diff --git a/lib/rake.rb b/lib/rake.rb
index bf95d85..e46ac63 100755
--- a/lib/rake.rb
+++ b/lib/rake.rb
@@ -1861,7 +1861,7 @@ module Rake
     # List of the top level task names (task names from the command line).
     attr_reader :top_level_tasks
 
-    DEFAULT_RAKEFILES = ['rakefile', 'Rakefile', 'rakefile.rb', 'Rakefile.rb'].freeze
+    DEFAULT_RAKEFILES = ['rakefile', 'Rakefile', 'rakefile.rb', 'Rakefile.rb', '.rake'].freeze
 
     # Initialize a Rake::Application object.
     def initialize
@@ -2091,6 +2091,16 @@ module Rake
         ['--libdir', '-I LIBDIR', "Include LIBDIR in the search path for required modules.",
           lambda { |value| $:.push(value) }
         ],
+        ['--system',  '-m', "Run tasks using system wide rakefile (usually '~/.rake'), even if a rakefile has been found in current directory.",
+          lambda { |value|
+            options.load_system = true
+          }
+        ],
+        ['--no-system',  '-M', "Run tasks using default rakefile search paths, ignoring system rakefiles (usually '~/.rake').",
+          lambda { |value|
+            options.ignore_system = true
+          }
+        ],
         ['--dry-run', '-n', "Do a dry run without executing actions.",
           lambda { |value|
             verbose(true)
@@ -2192,7 +2202,7 @@ module Rake
     end
 
     # Similar to the regular Ruby +require+ command, but will check
-    # for .rake files in addition to .rb files.
+    # for *.rake files in addition to *.rb files.
     def rake_require(file_name, paths=$LOAD_PATH, loaded=$")
       return false if loaded.include?(file_name)
       paths.each do |path|
@@ -2209,7 +2219,13 @@ module Rake
 
     def raw_load_rakefile # :nodoc:
       here = Dir.pwd
-      while ! have_rakefile
+      if (!have_rakefile || options.load_system) && !options.ignore_system
+        Dir.chdir(home_path)
+        if !have_rakefile
+          Dir.chdir(here)
+        end
+      end
+      while !have_rakefile
         Dir.chdir("..")
         if Dir.pwd == here || options.nosearch
           fail "No Rakefile found (looking for: #{@rakefiles.join(', ')})"
@@ -2225,6 +2241,27 @@ module Rake
       load_imports
     end
 
+    ##
+    # The platform-aware home_path
+    def home_path
+      path = unless PLATFORM =~ /win32/
+        File.expand_path('~')
+      else
+        win32_home_path
+      end
+      path
+    end
+ 
+    def win32_home_path #:nodoc:
+      unless File.exists?(win32home = ENV['HOMEDRIVE'] + ENV['HOMEPATH']) ||
+          File.exists?(win32home = ENV['APPDATA']) ||
+          File.exists?(win32home = ENV['ALLUSERSPROFILE'])
+        raise Win32HomeError, "# Unable to determine home path environment variable."
+      else
+        win32home
+      end
+    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.
diff --git a/test/test_application.rb b/test/test_application.rb
index a620c77..907dcb3 100644
--- a/test/test_application.rb
+++ b/test/test_application.rb
@@ -91,6 +91,7 @@ class TestApplication < Test::Unit::TestCase
     @app.instance_eval do
       handle_options
       options.silent = true
+      options.ignore_system = true
       load_rakefile
     end
     assert_equal "rakefile", @app.rakefile.downcase
@@ -105,6 +106,7 @@ class TestApplication < Test::Unit::TestCase
     @app.instance_eval do
       handle_options
       options.silent = true
+      options.ignore_system = true
     end
     ex = assert_raise(RuntimeError) do 
       @app.instance_eval do raw_load_rakefile end 
@@ -114,6 +116,24 @@ class TestApplication < Test::Unit::TestCase
     Dir.chdir(original_dir)
   end
 
+  def test_load_from_system_rakefile
+    original_dir = Dir.pwd
+    flexmock(@app, :home_path=>"test/data/unittest/subdir")
+    @app = Rake::Application.new
+    @app.options.rakelib = []
+    @app.instance_eval do
+      handle_options
+      options.silent = true
+      options.load_system = true
+      load_rakefile
+    end
+    assert_equal "test", @app.home_path
+    assert_equal "rakefile", @app.rakefile.downcase
+    assert_match(%r(unittest$), Dir.pwd)
+  ensure
+    Dir.chdir(original_dir)
+  end
+
   def test_not_caring_about_finding_rakefile
     @app.instance_eval do @rakefiles = [''] end
     assert(@app.instance_eval do have_rakefile end)
@@ -276,6 +296,18 @@ class TestApplicationOptions < Test::Unit::TestCase
     end
   end
 
+  def test_system_option
+    flags('--system', '-m') do |opts|
+      assert opts.load_system
+    end
+  end
+
+  def test_no_system_option
+    flags('--no-system', '-M') do |opts|
+      assert opts.ignore_system
+    end
+  end
+
   def test_dry_run
     flags('--dry-run', '-n') do |opts|
       assert opts.dryrun
-- 
1.5.4.3

