packages feed

nvfetcher-0.4.0.0: app/Config/PackageFetcher.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ViewPatterns #-}

module Config.PackageFetcher (fetcherCodec) where

import Data.Coerce (coerce)
import Data.Default (Default, def)
import Data.Foldable (asum)
import Data.Maybe (fromMaybe)
import qualified Data.Text as T
import GHC.Generics (Generic)
import Lens.Micro
import Lens.Micro.Extras (view)
import NvFetcher.NixFetcher
import NvFetcher.Types
import NvFetcher.Types.Lens
import Toml

unsupportError :: a
unsupportError = error "serialization is unsupported"

fetcherCodec :: TomlCodec PackageFetcher
fetcherCodec =
  asum
    [ gitHubCodec,
      pypiCodec,
      openVsxCodec,
      vscodeMarketplaceCodec,
      gitCodec,
      urlCodec
    ]

--------------------------------------------------------------------------------

data GitOptions = GitOptions
  { goDeepClone :: Maybe Bool,
    goFetchSubmodules :: Maybe Bool,
    goLeaveDotGit :: Maybe Bool
  }
  deriving (Eq, Generic, Default)

gitOptionsCodec :: TomlCodec GitOptions
gitOptionsCodec =
  GitOptions
    <$> dioptional (bool "git.deepClone") .= goDeepClone
    <*> dioptional (bool "git.fetchSubmodules") .= goFetchSubmodules
    <*> dioptional (bool "git.leaveDotGit") .= goLeaveDotGit

_GitOptions :: Traversal' (NixFetcher f) GitOptions
_GitOptions f x@FetchGit {..} =
  ( \GitOptions {..} ->
      x
        & deepClone .~ fromMaybe False goDeepClone
        & fetchSubmodules .~ fromMaybe False goFetchSubmodules
        & leaveDotGit .~ fromMaybe False goLeaveDotGit
  )
    <$> f (GitOptions (Just _deepClone) (Just _fetchSubmodules) (Just _leaveDotGit))
_GitOptions _ x@FetchUrl {} = pure x

--------------------------------------------------------------------------------

gitHubICodec :: TomlCodec PackageFetcher
gitHubICodec =
  textBy
    unsupportError
    ( \t -> case T.split (== '/') t of
        [owner, repo] -> Right $ gitHubFetcher (owner, repo)
        _ -> Left "unexpected github fetcher: it should be something like [owner]/[repo]"
    )
    "fetch.github"

gitHubCodec :: TomlCodec PackageFetcher
gitHubCodec =
  dimap
    ( \f -> let fake = f "$ver" in (f, fromMaybe def $ fake ^? _GitOptions)
    )
    (\(f, g) v -> f v & _GitOptions .~ g)
    $ (,) <$> gitHubICodec .= view _1 <*> gitOptionsCodec .= view _2

--------------------------------------------------------------------------------
gitICodec :: TomlCodec PackageFetcher
gitICodec =
  textBy
    unsupportError
    (Right . gitFetcher)
    "fetch.git"

gitCodec :: TomlCodec PackageFetcher
gitCodec =
  dimap
    ( \f -> let fake = f "$ver" in (f, fromMaybe def $ fake ^? _GitOptions)
    )
    (\(f, g) v -> f v & _GitOptions .~ g)
    $ (,) <$> gitICodec .= view _1 <*> gitOptionsCodec .= view _2

--------------------------------------------------------------------------------
pypiCodec :: TomlCodec PackageFetcher
pypiCodec =
  Toml.textBy
    unsupportError
    (Right . pypiFetcher)
    "fetch.pypi"

--------------------------------------------------------------------------------

openVsxCodec :: TomlCodec PackageFetcher
openVsxCodec =
  textBy
    unsupportError
    ( \t -> case T.split (== '.') t of
        -- assume we can't have '.' in extension's name
        [publisher, extName] -> Right $ openVsxFetcher (publisher, extName)
        _ -> Left "unexpected openvsx fetcher: it should be something like [publisher]/[extName]"
    )
    "fetch.openvsx"

--------------------------------------------------------------------------------

vscodeMarketplaceCodec :: TomlCodec PackageFetcher
vscodeMarketplaceCodec =
  textBy
    unsupportError
    ( \t -> case T.split (== '.') t of
        -- assume we can't have '.' in extension's name
        [publisher, extName] -> Right $ vscodeMarketplaceFetcher (publisher, extName)
        _ -> Left "unexpected vscode marketplace fetcher: it should be something like [publisher]/[extName]"
    )
    "fetch.vsmarketplace"

--------------------------------------------------------------------------------
urlCodec :: TomlCodec PackageFetcher
urlCodec =
  Toml.textBy
    unsupportError
    (\t -> Right $ \(coerce -> v) -> urlFetcher $ T.replace "$ver" v t)
    "fetch.url"