Module: Clacky::Utils::SearcherManager
- Defined in:
- lib/clacky/utils/searcher_manager.rb
Overview
Manages user-space search providers in ~/.clacky/searchers/.
Mirrors ParserManager: bundled searchers are copied out of the gem on
first use, and from then on the user-space copy wins, so a user can edit
a searcher (or add their own) without touching the gem and without
losing the change on gem update.
CLI interface contract (all searchers must follow):
<interpreter> <searcher> "<query>" <max_results>
stdout → JSON array of {"title","url","snippet"} objects
stderr → error messages
exit 0 → success
exit 1 → failure
The credential from search.yml arrives as ENV rather
than an argv entry, which would otherwise be world-readable via ps.
Constant Summary collapse
- SEARCHERS_DIR =
File.("~/.clacky/searchers").freeze
- DEFAULT_SEARCHERS_DIR =
File.("../default_searchers", __dir__).freeze
- INTERPRETER_FOR =
{ ".rb" => RbConfig.ruby, ".py" => "python3" }.freeze
Class Method Summary collapse
-
.available ⇒ Array<String>
Names of every installed searcher, for the settings UI to offer.
- .interpreter_for(path) ⇒ Object
-
.path_for(name) ⇒ String?
Resolve a provider name from search.yml to an installed script path.
-
.setup! ⇒ Object
Called at Agent startup (idempotent — safe to run every time).
Class Method Details
.available ⇒ Array<String>
Names of every installed searcher, for the settings UI to offer.
75 76 77 78 79 80 |
# File 'lib/clacky/utils/searcher_manager.rb', line 75 def self.available Dir.glob(File.join(SEARCHERS_DIR, "*")) .select { |p| File.file?(p) && INTERPRETER_FOR.key?(File.extname(p)) } .map { |p| File.basename(p, File.extname(p)) } .sort end |
.interpreter_for(path) ⇒ Object
82 83 84 |
# File 'lib/clacky/utils/searcher_manager.rb', line 82 def self.interpreter_for(path) INTERPRETER_FOR[File.extname(path)] || RbConfig.ruby end |
.path_for(name) ⇒ String?
Resolve a provider name from search.yml to an installed script path.
66 67 68 69 70 71 |
# File 'lib/clacky/utils/searcher_manager.rb', line 66 def self.path_for(name) base = File.basename(name.to_s.strip) return nil if base.empty? Dir.glob(File.join(SEARCHERS_DIR, "#{base}.*")).find { |p| INTERPRETER_FOR.key?(File.extname(p)) } end |
.setup! ⇒ Object
Called at Agent startup (idempotent — safe to run every time).
Upgrade policy matches ParserManager: a bundled searcher only replaces
an installed one when its # VERSION: marker is higher, and the old
copy is backed up so a user can recover their edits.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/clacky/utils/searcher_manager.rb', line 34 def self.setup! FileUtils.mkdir_p(SEARCHERS_DIR) Dir.glob(File.join(DEFAULT_SEARCHERS_DIR, "*")).each do |src| next unless File.file?(src) basename = File.basename(src) next if basename.start_with?(".") || basename.end_with?(".bak") dest = File.join(SEARCHERS_DIR, basename) unless File.exist?(dest) FileUtils.cp(src, dest) FileUtils.chmod(File.stat(src).mode, dest) next end bundled_version = ParserManager.extract_version(src) next unless bundled_version installed_version = ParserManager.extract_version(dest) || 0 next unless bundled_version > installed_version backup = "#{dest}.v#{installed_version}.bak" FileUtils.cp(dest, backup) unless File.exist?(backup) FileUtils.cp(src, dest) FileUtils.chmod(File.stat(src).mode, dest) end end |