Class: Pro::Indexer

Inherits:
Object
  • Object
show all
Defined in:
lib/pro/indexer.rb

Overview

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

Constant Summary collapse

CACHE_PATH =
File.expand_path("~/.proCache")
INDEXER_LOCK_PATH =
File.expand_path("~/.proCacheLock")

Instance Method Summary collapse

Constructor Details

#initializeIndexer

Returns a new instance of Indexer.



10
11
12
13
# File 'lib/pro/indexer.rb', line 10

def initialize
  @base_dirs = find_base_dirs
  @low_cpu = false
end

Instance Method Details

#build_indexObject

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



58
59
60
61
62
# File 'lib/pro/indexer.rb', line 58

def build_index
  index = scan_into_index
  cache_index(index)
  index
end

#cache_index(index) ⇒ Object

serialize the index to a cache file



65
66
67
68
69
70
# File 'lib/pro/indexer.rb', line 65

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_dirsObject

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



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/pro/indexer.rb', line 133

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

#indexObject



15
16
17
18
19
20
21
22
23
24
25
# 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_processObject



44
45
46
47
48
49
50
51
52
53
# File 'lib/pro/indexer.rb', line 44

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) ⇒ Object

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



92
93
94
95
96
97
98
# File 'lib/pro/indexer.rb', line 92

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) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/pro/indexer.rb', line 100

def index_repos_fast(base)
  Dir.chdir(base)
  res = `find . -name .git`
  # turn the output into a list of repos
  repos = []
  res.each_line do |line|
    next if line.empty?
    git_path = File.expand_path(line.chomp)
    path = File.dirname(git_path)
    repo_name = File.basename(path)
    repos << Repo.new(repo_name,path)
  end
  repos
end

#index_repos_slow(base) ⇒ Object

recursive walk in ruby



116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/pro/indexer.rb', line 116

def index_repos_slow(base)
  STDERR.puts "WARNING: pro is indexing slowly, please install the 'find' command."
  repos = []
  Find.find(base) do |path|
    # dir must exist and be a git repo
    if FileTest.directory?(path) && File.exists?(path+"/.git")
      base_name = File.basename(path)
      repos << Repo.new(base_name,path)
      Find.prune
    end
  end
  repos
end

#read_cacheObject

unserializes the cache file and returns the index object



28
29
30
31
32
33
34
# 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_processObject

spins off a background process to update the cache file



37
38
39
40
41
42
# File 'lib/pro/indexer.rb', line 37

def run_index_process
  p1 = fork {
    index_process unless File.exists?(INDEXER_LOCK_PATH)
  }
  Process.detach(p1)
end

#scan_basesObject

add all git repos in all bases to the index



81
82
83
84
85
86
87
# File 'lib/pro/indexer.rb', line 81

def scan_bases
  bases = {}
  @base_dirs.each do |base|
    bases[base] = index_repos(base)
  end
  bases
end

#scan_into_indexObject

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



75
76
77
78
# File 'lib/pro/indexer.rb', line 75

def scan_into_index
  repos = scan_bases
  Index.new(repos,@base_dirs)
end