class Pro::Indexer

creates an index object from cache or by searching the file system

Constants

CACHE_PATH
INDEXER_LOCK_PATH

Public Class Methods

new() click to toggle source
# File lib/pro/indexer.rb, line 10
def initialize
  @base_dirs = find_base_dirs
  @low_cpu = false
end

Public Instance Methods

build_index() click to toggle source

scan the base directories for git repos and build an index then cache it returns an index

# File lib/pro/indexer.rb, line 63
def build_index
  index = scan_into_index
  cache_index(index)
  index
end
cache_index(index) click to toggle source

serialize the index to a cache file

# File lib/pro/indexer.rb, line 70
def cache_index(index)
  # TODO: atomic rename. Right now we just hope.
  File.open(CACHE_PATH, 'w' ) do |out|
    YAML::dump( index, out )
  end
end
find_base_dirs() click to toggle source

Finds the base directory where repos are kept Checks the environment variable PRO_BASE and the file .proBase

# File lib/pro/indexer.rb, line 152
def find_base_dirs()
  bases = []
  # check environment first
  base = ENV['PRO_BASE']
  bases << base if base
  # next check proBase file
  path = ENV['HOME'] + "/.proBase"
  if File.exists?(path)
    # read lines of the pro base file
    bases += IO.read(path).split("\n").map {|p| File.expand_path(p.strip)}
  end
  # strip bases that do not exist
  # I know about select! but it doesn't exist in 1.8
  bases = bases.select {|b| File.exists?(b)}
  # if no bases then return home
  bases << ENV['HOME'] if bases.empty?
  bases
end
index() click to toggle source
# File lib/pro/indexer.rb, line 15
def index
  # most of the time the cache should exist
  if res = read_cache
    # index in the background for next time.
    run_index_process
  else
    STDERR.puts "Indexing... This should only happen after updating.".red
    res = build_index
  end
  res
end
index_process() click to toggle source
# File lib/pro/indexer.rb, line 49
def index_process
  @low_cpu = true
  # create lock so no work duplicated
  begin
    File.open(INDEXER_LOCK_PATH, "w") {}
    build_index
  ensure
    File.delete(INDEXER_LOCK_PATH)
  end
end
index_repos(base) click to toggle source

find all repos in a certain base directory returns an array of Repo objects

# File lib/pro/indexer.rb, line 97
def index_repos(base)
  if system("which find > /dev/null")
    index_repos_fast(base)
  else
    index_repos_slow(base)
  end
end
index_repos_fast(base) click to toggle source
# File lib/pro/indexer.rb, line 105
def index_repos_fast(base)
  Dir.chdir(base)
  git_paths = `find . -name .git`.lines
  # additionally, index repos symlinked directly from a base root
  dirs     = `find -L . -maxdepth 1 -type d`.lines
  symlinks = `find    . -maxdepth 1 -type l`.lines
  # intersect those two results
  dir_sl = dirs & symlinks
  dir_sl_git_paths = dir_sl.
    map {|path| path.chomp + '/.git'}.
    select {|path| File.exists?(path)}
  # turn the command outputs into a list of repos
  repos = []
  (git_paths + dir_sl_git_paths).each do |git_path|
    next if git_path.empty?
    git_path = File.expand_path(git_path.chomp)
    path = File.dirname(git_path)
    repo_name = File.basename(path)
    repos << Repo.new(repo_name,path)
  end
  repos
end
index_repos_slow(base) click to toggle source

recursive walk in ruby

# File lib/pro/indexer.rb, line 129
def index_repos_slow(base)
  STDERR.puts "WARNING: pro is indexing slowly, please install the 'find' command."
  repos = []
  Find.find(base) do |path|
    target = path
    # additionally, index repos symlinked directly from a base root
    if FileTest.symlink?(path)
      next if File.dirname(path) != base
      target = File.readlink(path)
    end
    # dir must exist and be a git repo
    if FileTest.directory?(target) && File.exists?(path+"/.git")
      base_name = File.basename(path)
      repos << Repo.new(base_name,path)
      Find.prune
    end
  end
  repos
end
read_cache() click to toggle source

unserializes the cache file and returns the index object

# File lib/pro/indexer.rb, line 28
def read_cache
  return nil unless File.readable_real?(CACHE_PATH)
  index = YAML::load_file(CACHE_PATH)
  return nil unless index.created_version == Pro::VERSION
  return nil unless index.base_dirs == @base_dirs
  index
end
run_index_process() click to toggle source

spins off a background process to update the cache file

# File lib/pro/indexer.rb, line 37
def run_index_process
  readme, writeme = IO.pipe
  p1 = fork {
    # Stop cd function from blocking on fork
    STDOUT.reopen(writeme)
    readme.close

    index_process unless File.exists?(INDEXER_LOCK_PATH)
  }
  Process.detach(p1)
end
scan_bases() click to toggle source

add all git repos in all bases to the index

# File lib/pro/indexer.rb, line 86
def scan_bases
  bases = {}
  @base_dirs.each do |base|
    bases[base] = index_repos(base)
  end
  bases
end
scan_into_index() click to toggle source

compile base directories and scan them use this info to create an index object and return it

# File lib/pro/indexer.rb, line 80
def scan_into_index
  repos = scan_bases
  Index.new(repos,@base_dirs)
end