packages feed

okf-cli-0.7.0.0: src/Okf/Cli/BundleDiscovery.hs

-- | Non-interactive discovery of OKF bundles available to the CLI.
module Okf.Cli.BundleDiscovery
  ( BundleDiscovery (..),
    bundleSearchRootsEnvVar,
    parseBundleSearchRoots,
    bundleSearchRoots,
    discoverAvailableBundles,
  )
where

import Data.List qualified as List
import Data.Text qualified as Text
import Okf.Discovery (defaultDiscoveryOptions, discoverBundleRoots)
import System.Environment (lookupEnv)

-- | The effective search roots and the normalized candidates found below them.
data BundleDiscovery = BundleDiscovery
  { searchRoots :: ![FilePath],
    bundlePaths :: ![FilePath]
  }
  deriving stock (Show, Eq)

-- | Colon-separated search-root environment variable, in the style of @PATH@.
bundleSearchRootsEnvVar :: String
bundleSearchRootsEnvVar = "OKF_BUNDLE_ROOTS"

parseBundleSearchRoots :: String -> [FilePath]
parseBundleSearchRoots raw =
  [ Text.unpack trimmed
  | piece <- Text.splitOn ":" (Text.pack raw),
    let trimmed = Text.strip piece,
    not (Text.null trimmed)
  ]

-- | Where discovery starts. An absent or effectively empty override means the
-- current working directory.
bundleSearchRoots :: IO [FilePath]
bundleSearchRoots = do
  configured <- lookupEnv bundleSearchRootsEnvVar
  pure $ case configured of
    Nothing -> ["."]
    Just raw -> case parseBundleSearchRoots raw of
      [] -> ["."]
      roots -> roots

-- | Discover candidates once, sorting and deduplicating across every root.
discoverAvailableBundles :: IO BundleDiscovery
discoverAvailableBundles = do
  roots <- bundleSearchRoots
  discovered <-
    List.nub . List.sort . concat
      <$> traverse (discoverBundleRoots defaultDiscoveryOptions) roots
  pure BundleDiscovery {searchRoots = roots, bundlePaths = discovered}