Class: Lich::Common::FrontendLocator

Inherits:
Object
  • Object
show all
Defined in:
documented/common/frontend_locator.rb

Overview

Resolves installed frontend executables from the shared Frontend catalog. It has no GTK dependency and is safe for GUI, CLI, and --no-gtk startup.

Defined Under Namespace

Classes: Resolution

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(platform_key: Frontend.platform_key, environment: ENV, logger: nil, application_roots: ['/Applications', '~/Applications'], wine: (Wine) ? Wine : nil)) ⇒ FrontendLocator

Returns a new instance of FrontendLocator.

Parameters:

  • platform_key (Symbol) (defaults to: Frontend.platform_key) —

    canonical host classification

  • environment (Hash) (defaults to: ENV) —

    environment used for path expansion/PATH

  • logger (#call, nil) (defaults to: nil) —

    receives handled discovery warning strings

  • application_roots (Array<String>) (defaults to: ['/Applications', '~/Applications']) —

    macOS application directories

  • wine (Module, nil) (defaults to: (Wine) ? Wine : nil)) —

    injected Wine integration provider



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'documented/common/frontend_locator.rb', line 95

def initialize(
  platform_key: Frontend.platform_key,
  environment: ENV,
  logger: nil,
  application_roots: ['/Applications', '~/Applications'],
  wine: (defined?(Wine) ? Wine : nil)
)
  @platform_key = Frontend.validate_platform_key!(platform_key)
  @environment = environment
  @logger = logger || method(:default_log)
  @application_roots = application_roots
  @wine = wine
  @cache = {}
  # Always acquire the cache mutex before the application-index mutex
  # when both are needed. resolve(refresh: true) relies on this order.
  @cache_mutex = Mutex.new
  @application_index = nil
  @application_index_mutex = Mutex.new
end

Class Method Details

.available(gui_selectable: nil, refresh: false) ⇒ Array<Resolution>

Returns resolutions for installed catalog entries.

Parameters:

  • gui_selectable (Boolean, nil) (defaults to: nil) —

    catalog presentation filter

  • refresh (Boolean) (defaults to: false) —

    clear cached results before discovery

Returns:



42
43
44
# File 'documented/common/frontend_locator.rb', line 42

def available(gui_selectable: nil, refresh: false)
  default.available(gui_selectable: gui_selectable, refresh: refresh)
end

.compatibility_location(frontend_id) ⇒ String?

Backward-compatible directory result used by Lich.seek.

Parameters:

  • frontend_id (String, Symbol)

Returns:



76
77
78
79
80
81
# File 'documented/common/frontend_locator.rb', line 76

def compatibility_location(frontend_id)
  resolution = resolve(frontend_id)
  resolution && File.dirname(resolution.executable_path)
rescue ArgumentError
  nil
end

.launchable?(frontend_id, refresh: false) ⇒ Boolean

Returns whether a frontend has a native launcher on this platform and its required executable is installed. Unlike selectable?, this does not apply graphical presentation metadata.

Parameters:

  • frontend_id (String, Symbol) —

    registered frontend identifier

  • refresh (Boolean) (defaults to: false) —

    bypass the process-local discovery cache

Returns:

  • (Boolean)


63
64
65
# File 'documented/common/frontend_locator.rb', line 63

def launchable?(frontend_id, refresh: false)
  default.launchable?(frontend_id, refresh: refresh)
end

.refresh! ⇒ void

This method returns an undefined value.

Clears process-local discovery results. No settings are persisted.



69
70
71
# File 'documented/common/frontend_locator.rb', line 69

def refresh!
  default.refresh!
end

.resolve(frontend_id, override: nil, refresh: false) ⇒ Resolution?

Resolves a known frontend to a launchable executable.

Parameters:

  • frontend_id (String, Symbol) —

    registered frontend identifier

  • override (String, nil) (defaults to: nil) —

    explicit executable path for this call

  • refresh (Boolean) (defaults to: false) —

    bypass the process-local discovery cache

Returns:

  • (Resolution, nil) —

    nil when the frontend is not installed

Raises:

  • (ArgumentError) —

    for blank/unknown identifiers or invalid overrides



33
34
35
# File 'documented/common/frontend_locator.rb', line 33

def resolve(frontend_id, override: nil, refresh: false)
  default.resolve(frontend_id, override: override, refresh: refresh)
end

.selectable?(frontend_id, refresh: false) ⇒ Boolean

Returns whether a frontend is both installed and supported by the graphical launcher on this platform.

Parameters:

  • frontend_id (String, Symbol) —

    registered frontend identifier

  • refresh (Boolean) (defaults to: false) —

    bypass the process-local discovery cache

Returns:

  • (Boolean)


52
53
54
# File 'documented/common/frontend_locator.rb', line 52

def selectable?(frontend_id, refresh: false)
  default.selectable?(frontend_id, refresh: refresh)
end

Instance Method Details

#available(gui_selectable: nil, refresh: false) ⇒ Array<Resolution>

Returns resolutions for all frontends with installed executables.

Examples:

FrontendLocator.available
# => [
#      #<struct Resolution frontend_id=:storm, executable_path="/usr/bin/StormFront", source=:path>,
#      #<struct Resolution frontend_id=:avalon, executable_path="/Applications/Avalon.app/Contents/MacOS/Avalon", source=:application>
#    ]

Parameters:

  • gui_selectable (Boolean, nil) (defaults to: nil) —

    when true, filters to frontends marked gui_selectable and supported on this platform; when nil or false, returns all installed frontends

  • refresh (Boolean) (defaults to: false) —

    clears the process-local discovery cache before scanning

Returns:

  • (Array<Resolution>) —

    array of frontend resolutions, possibly empty



155
156
157
158
159
160
161
162
# File 'documented/common/frontend_locator.rb', line 155

def available(gui_selectable: nil, refresh: false)
  refresh! if refresh
  definitions = Frontend.definitions(gui_selectable: gui_selectable)
  definitions = definitions.select { |definition| gui_platform_supported?(definition) } if gui_selectable
  definitions.filter_map do |definition|
    resolve(definition[:id])
  end
end

#launchable?(frontend_id, refresh: false) ⇒ Boolean

Returns true when a frontend has native launcher support on this platform and its executable is installed.

Differs from #selectable? by not applying graphical presentation filters—a frontend may be launchable but not selectable in the GUI.

Examples:

FrontendLocator.launchable?(:storm) #=> true

Parameters:

  • frontend_id (String, Symbol) —

    registered frontend identifier

  • refresh (Boolean) (defaults to: false) —

    bypasses the process-local discovery cache

Returns:

  • (Boolean)


189
190
191
192
193
194
195
# File 'documented/common/frontend_locator.rb', line 189

def launchable?(frontend_id, refresh: false)
  definition = Frontend.definition_for(frontend_id)
  return false unless native_launcher_supported?(definition)
  return true if definition.dig(:metadata, :launcher_adapter) == :embedded

  !resolve(definition[:id], refresh: refresh).nil?
end

#refresh! ⇒ void

This method returns an undefined value.

Clears the process-local discovery cache. No settings are persisted.



200
201
202
203
204
# File 'documented/common/frontend_locator.rb', line 200

def refresh!
  @cache_mutex.synchronize { @cache.clear }
  @application_index_mutex.synchronize { @application_index = nil }
  nil
end

#resolve(frontend_id, override: nil, refresh: false) ⇒ Resolution?

Resolves a known frontend to a launchable executable.

Parameters:

  • frontend_id (String, Symbol) —

    registered frontend identifier

  • override (String, nil) (defaults to: nil) —

    explicit executable path for this call

  • refresh (Boolean) (defaults to: false) —

    bypass the process-local discovery cache

Returns:

  • (Resolution, nil) —

    nil when the frontend is not installed

Raises:

  • (ArgumentError) —

    for blank or unknown identifiers and invalid overrides



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'documented/common/frontend_locator.rb', line 122

def resolve(frontend_id, override: nil, refresh: false)
  definition = Frontend.definition_for(frontend_id)
  return resolve_override(definition, override) unless override.nil?

  configured = definition.dig(:metadata, :configured_executable)
  if configured
    configured_resolution = resolve_configured(definition, configured)
    return configured_resolution if configured_resolution
  end

  @cache_mutex.synchronize do
    if refresh
      @cache.delete(definition[:id])
      @application_index_mutex.synchronize { @application_index = nil }
    end
    return @cache[definition[:id]] if @cache.key?(definition[:id])
  end

  discovered = discover(definition)
  @cache_mutex.synchronize { @cache[definition[:id]] = discovered }
end

#selectable?(frontend_id, refresh: false) ⇒ Boolean

Returns true when a frontend is both installed and marked for graphical launcher presentation on this platform.

Examples:

FrontendLocator.selectable?(:storm) #=> true
FrontendLocator.selectable?(:nonexistent) #=> false

Parameters:

  • frontend_id (String, Symbol) —

    registered frontend identifier

  • refresh (Boolean) (defaults to: false) —

    bypasses the process-local discovery cache

Returns:

  • (Boolean)


172
173
174
175
176
177
178
# File 'documented/common/frontend_locator.rb', line 172

def selectable?(frontend_id, refresh: false)
  definition = Frontend.definition_for(frontend_id)
  return false unless definition.dig(:metadata, :gui_selectable)
  return false unless gui_platform_supported?(definition)

  !resolve(definition[:id], refresh: refresh).nil?
end