class Thor::Runner

def self.globs_for(path)

def self.globs_for(path)
  ["#{path}/Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/*.thor"]
end

def self.thor_root

def self.thor_root
  File.join(ENV["HOME"] || ENV["APPDATA"], ".thor")
end

def self.thor_root_glob

def self.thor_root_glob
  # On Windows thor_root will be something like this:
  #
  #   C:\Documents and Settings\james\.thor
  #
  # If we don't #gsub the \ character, Dir.glob will fail.
  Dir["#{thor_root.gsub(/\\/, '/')}/**/*"]
end

def display_klasses(with_modules = false, klasses = Thor.subclasses)

def display_klasses(with_modules = false, klasses = Thor.subclasses)
  klasses -= [Thor, Thor::Runner] unless with_modules
  raise Error, "No Thor tasks available" if klasses.empty?
  
  if with_modules && !(yaml = thor_yaml).empty?
    max_name = yaml.max {|(xk,xv),(yk,yv)| xk.to_s.size <=> yk.to_s.size }.first.size
    modules_label = "Modules"
    namespaces_label = "Namespaces"
    column_width = [max_name + 4, modules_label.size + 1].max
    
    print "%-#{column_width}s" % modules_label
    puts namespaces_label
    print "%-#{column_width}s" % ("-" * modules_label.size)
    puts "-" * namespaces_label.size
    
    yaml.each do |name, info|
      print "%-#{column_width}s" % name
      puts info[:constants].map {|c| Thor::Util.constant_to_thor_path(c)}.join(", ")
    end
  
    puts
  end
  
  # Calculate the largest base class name
  max_base = klasses.max do |x,y| 
    Thor::Util.constant_to_thor_path(x.name).size <=> Thor::Util.constant_to_thor_path(y.name).size
  end.name.size
  
  # Calculate the size of the largest option description
  max_left_item = klasses.max do |x,y| 
    (x.maxima.usage + x.maxima.opt).to_i <=> (y.maxima.usage + y.maxima.opt).to_i
  end
  
  max_left = max_left_item.maxima.usage + max_left_item.maxima.opt
  
  unless klasses.empty?
    puts # add some spacing
    klasses.each { |k| display_tasks(k, max_base, max_left); }
  else
    puts "\033[1;34mNo Thor tasks available\033[0m"
  end
end  

def display_tasks(klass, max_base, max_left)

def display_tasks(klass, max_base, max_left)
  if klass.tasks.values.length > 1
    
    base = Thor::Util.constant_to_thor_path(klass.name)
    
    if base.to_a.empty?
      base = 'default' 
      puts "\033[1;35m#{base}\033[0m"
    else
      puts "\033[1;34m#{base}\033[0m"
    end
    puts "-" * base.length
    
    klass.tasks.each true do |name, task|
      format_string = "%-#{max_left + max_base + 5}s"
      print format_string % task.formatted_usage(true)
      puts task.description
    end
    
    unless klass.opts.empty?
      puts "\nglobal options: #{Options.new(klass.opts)}"
    end
    
    puts # add some spacing
  end
end

def help(task = nil)

Override Thor#help so we can give info about not-yet-loaded tasks
def help(task = nil)
  initialize_thorfiles(task) if task && task.include?(?:)
  super
end

def initialize_thorfiles(relevant_to = nil)

def initialize_thorfiles(relevant_to = nil)
  thorfiles(relevant_to).each {|f| load_thorfile f unless Thor.subclass_files.keys.include?(File.expand_path(f))}
end

def install(name)

def install(name)
  initialize_thorfiles
  begin
    contents = open(name).read
  rescue OpenURI::HTTPError
    raise Error, "Error opening URI `#{name}'"
  rescue Errno::ENOENT
    raise Error, "Error opening file `#{name}'"
  end
  
  is_uri = File.exist?(name) ? false : true
  
  puts "Your Thorfile contains: "
  puts contents
  print "Do you wish to continue [y/N]? "
  response = Readline.readline
  
  return false unless response =~ /^\s*y/i
  
  constants = Thor::Util.constants_in_contents(contents)
  
  # name = name =~ /\.thor$/ || is_uri ? name : "#{name}.thor"
  
  as = options["as"] || begin
    first_line = contents.split("\n")[0]
    (match = first_line.match(/\s*#\s*module:\s*([^\n]*)/)) ? match[1].strip : nil
  end
      
  if !as
    print "Please specify a name for #{name} in the system repository [#{name}]: "
    as = Readline.readline
    as = name if as.empty?
  end
  
  FileUtils.mkdir_p thor_root
  
  yaml_file = File.join(thor_root, "thor.yml")
  FileUtils.touch(yaml_file)
  yaml = thor_yaml
  
  location = (options[:relative] || is_uri) ? name : File.expand_path(name)
  yaml[as] = {:filename => Digest::MD5.hexdigest(name + as), :location => location, :constants => constants}
  
  save_yaml(yaml)
  
  puts "Storing thor file in your system repository"
  
  File.open(File.join(thor_root, yaml[as][:filename]), "w") do |file|
    file.puts contents
  end
  
  yaml[as][:filename] # Indicate sucess
end

def installed

def installed
  thor_root_glob.each do |f|
    next if f =~ /thor\.yml$/
    load_thorfile f unless Thor.subclass_files.keys.include?(File.expand_path(f))
  end
  klasses = Thor.subclasses
  klasses -= [Thor, Thor::Runner] unless options['internal']
  display_klasses(true, klasses)
end

def list(search = "")

def list(search = "")
  initialize_thorfiles
  search = ".*#{search}" if options["substring"]
  search = /^#{search}.*/i
  group  = options[:group] || 'standard'
  
  classes = Thor.subclasses.select do |k| 
    (options[:all] || k.group_name == group) && 
    Thor::Util.constant_to_thor_path(k.name) =~ search
  end
  display_klasses(false, classes)
end

def load_thorfile(path)

def load_thorfile(path)
  begin
    load path
  rescue Object => e
    $stderr.puts "WARNING: unable to load thorfile #{path.inspect}: #{e.message}"
  end
end

def method_missing(meth, *args)

def method_missing(meth, *args)
  meth = meth.to_s
  super(meth.to_sym, *args) unless meth.include? ?:
  initialize_thorfiles(meth)
  task = Thor[meth]
  task.parse task.klass.new, ARGV[1..-1]
end

def save_yaml(yaml)

def save_yaml(yaml)
  yaml_file = File.join(thor_root, "thor.yml")
  File.open(yaml_file, "w") {|f| f.puts yaml.to_yaml }
end

def thor_root

def thor_root
  self.class.thor_root
end

def thor_root_glob

def thor_root_glob
  self.class.thor_root_glob
end

def thor_yaml

def thor_yaml
  yaml_file = File.join(thor_root, "thor.yml")
  yaml = YAML.load_file(yaml_file) if File.exists?(yaml_file)
  yaml || {}
end

def thorfiles(relevant_to = nil)

def thorfiles(relevant_to = nil)
  path = Dir.pwd
  thorfiles = []
  
  # Look for Thorfile or *.thor in the current directory or a parent directory, until the root
  while thorfiles.empty?
    thorfiles = Thor::Runner.globs_for(path).map {|g| Dir[g]}.flatten
    path = File.dirname(path)
    break if path == "/"
  end
  # We want to load system-wide Thorfiles first
  # so the local Thorfiles will override them.
  (relevant_to ? thorfiles_relevant_to(relevant_to) :
   thor_root_glob) + thorfiles - ["#{thor_root}/thor.yml"]
end

def thorfiles_relevant_to(meth)

def thorfiles_relevant_to(meth)
  klass_str = Thor::Util.to_constant(meth.split(":")[0...-1].join(":"))
  thor_yaml.select do |k, v|
    v[:constants] && v[:constants].include?(klass_str)
  end.map { |k, v| File.join(thor_root, "#{v[:filename]}") }
end

def uninstall(name)

def uninstall(name)
  yaml = thor_yaml
  raise Error, "Can't find module `#{name}'" unless yaml[name]
  
  puts "Uninstalling #{name}."
  
  file = File.join(thor_root, "#{yaml[name][:filename]}")
  File.delete(file)
  yaml.delete(name)
  save_yaml(yaml)
  
  puts "Done."
end

def update(name)

def update(name)
  yaml = thor_yaml
  raise Error, "Can't find module `#{name}'" if !yaml[name] || !yaml[name][:location]
  puts "Updating `#{name}' from #{yaml[name][:location]}"
  old_filename = yaml[name][:filename]
  self.options = self.options.merge("as" => name)
  filename = install(yaml[name][:location])
  unless filename == old_filename
    File.delete(File.join(thor_root, old_filename))
  end
end