{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ViewPatterns #-}

-- | Copyright: (c) 2021 berberman
-- SPDX-License-Identifier: MIT
-- Maintainer: berberman <[email protected]>
-- Stability: experimental
-- Portability: portable
--
-- This module contains a type class 'ToNixExpr' and some its instances associated with either Haskell
-- primitive types or our "NvFetcher.Types".
module NvFetcher.NixExpr
  ( NixExpr,
    ToNixExpr (..),
  )
where

import Data.Coerce (coerce)
import qualified Data.List.NonEmpty as NE
import Data.Text (Text)
import qualified Data.Text as T
import NeatInterpolation (trimming)
import NvFetcher.Types
import NvFetcher.Utils (asString)

-- | Types can be converted into nix expr
class ToNixExpr a where
  toNixExpr :: a -> NixExpr

instance ToNixExpr (NixFetcher Fresh) where
  toNixExpr :: NixFetcher 'Fresh -> NixExpr
toNixExpr = NixExpr -> NixFetcher 'Fresh -> NixExpr
forall (k :: FetchStatus). NixExpr -> NixFetcher k -> NixExpr
nixFetcher NixExpr
"lib.fakeSha256"

instance ToNixExpr (NixFetcher Fetched) where
  toNixExpr :: NixFetcher 'Fetched -> NixExpr
toNixExpr NixFetcher 'Fetched
f = NixExpr -> NixFetcher 'Fetched -> NixExpr
forall (k :: FetchStatus). NixExpr -> NixFetcher k -> NixExpr
nixFetcher (NixExpr -> NixExpr
asString (NixExpr -> NixExpr) -> NixExpr -> NixExpr
forall a b. (a -> b) -> a -> b
$ Checksum -> NixExpr
coerce (Checksum -> NixExpr) -> Checksum -> NixExpr
forall a b. (a -> b) -> a -> b
$ NixFetcher 'Fetched -> FetchResult 'Fetched
forall (k :: FetchStatus). NixFetcher k -> FetchResult k
_sha256 NixFetcher 'Fetched
f) NixFetcher 'Fetched
f

instance ToNixExpr Bool where
  toNixExpr :: Bool -> NixExpr
toNixExpr Bool
True = NixExpr
"true"
  toNixExpr Bool
False = NixExpr
"false"

instance ToNixExpr a => ToNixExpr [a] where
  toNixExpr :: [a] -> NixExpr
toNixExpr [a]
xs = (NixExpr -> a -> NixExpr) -> NixExpr -> [a] -> NixExpr
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl (\NixExpr
acc a
x -> NixExpr
acc NixExpr -> NixExpr -> NixExpr
forall a. Semigroup a => a -> a -> a
<> NixExpr
" " NixExpr -> NixExpr -> NixExpr
forall a. Semigroup a => a -> a -> a
<> a -> NixExpr
forall a. ToNixExpr a => a -> NixExpr
toNixExpr a
x) NixExpr
"[" [a]
xs NixExpr -> NixExpr -> NixExpr
forall a. Semigroup a => a -> a -> a
<> NixExpr
" ]"

instance ToNixExpr a => ToNixExpr (NE.NonEmpty a) where
  toNixExpr :: NonEmpty a -> NixExpr
toNixExpr = [a] -> NixExpr
forall a. ToNixExpr a => a -> NixExpr
toNixExpr ([a] -> NixExpr) -> (NonEmpty a -> [a]) -> NonEmpty a -> NixExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty a -> [a]
forall a. NonEmpty a -> [a]
NE.toList

instance {-# OVERLAPS #-} ToNixExpr String where
  toNixExpr :: String -> NixExpr
toNixExpr = String -> NixExpr
T.pack (String -> NixExpr) -> (String -> String) -> String -> NixExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
forall a. Show a => a -> String
show

instance ToNixExpr NixExpr where
  toNixExpr :: NixExpr -> NixExpr
toNixExpr = NixExpr -> NixExpr
forall a. a -> a
id

instance ToNixExpr Version where
  toNixExpr :: Version -> NixExpr
toNixExpr = Version -> NixExpr
coerce

nixFetcher :: Text -> NixFetcher k -> NixExpr
nixFetcher :: NixExpr -> NixFetcher k -> NixExpr
nixFetcher NixExpr
sha256 = \case
  FetchGit
    { _sha256 :: forall (k :: FetchStatus). NixFetcher k -> FetchResult k
_sha256 = FetchResult k
_,
      _rev :: forall (k :: FetchStatus). NixFetcher k -> Version
_rev = NixExpr -> NixExpr
asString (NixExpr -> NixExpr) -> (Version -> NixExpr) -> Version -> NixExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Version -> NixExpr
forall a. ToNixExpr a => a -> NixExpr
toNixExpr -> NixExpr
rev,
      _fetchSubmodules :: forall (k :: FetchStatus). NixFetcher k -> Bool
_fetchSubmodules = Bool -> NixExpr
forall a. ToNixExpr a => a -> NixExpr
toNixExpr -> NixExpr
fetchSubmodules,
      _deepClone :: forall (k :: FetchStatus). NixFetcher k -> Bool
_deepClone = Bool -> NixExpr
forall a. ToNixExpr a => a -> NixExpr
toNixExpr -> NixExpr
deepClone,
      _leaveDotGit :: forall (k :: FetchStatus). NixFetcher k -> Bool
_leaveDotGit = Bool -> NixExpr
forall a. ToNixExpr a => a -> NixExpr
toNixExpr -> NixExpr
leaveDotGit,
      _furl :: forall (k :: FetchStatus). NixFetcher k -> NixExpr
_furl = NixExpr -> NixExpr
asString -> NixExpr
url
    } ->
      [trimming|
          fetchgit {
            url = $url;
            rev = $rev;
            fetchSubmodules = $fetchSubmodules;
            deepClone = $deepClone;
            leaveDotGit = $leaveDotGit;
            sha256 = $sha256;
          }
    |]
  FetchGitHub
    { _sha256 :: forall (k :: FetchStatus). NixFetcher k -> FetchResult k
_sha256 = FetchResult k
_,
      _rev :: forall (k :: FetchStatus). NixFetcher k -> Version
_rev = NixExpr -> NixExpr
asString (NixExpr -> NixExpr) -> (Version -> NixExpr) -> Version -> NixExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Version -> NixExpr
forall a. ToNixExpr a => a -> NixExpr
toNixExpr -> NixExpr
rev,
      _fetchSubmodules :: forall (k :: FetchStatus). NixFetcher k -> Bool
_fetchSubmodules = Bool -> NixExpr
forall a. ToNixExpr a => a -> NixExpr
toNixExpr -> NixExpr
fetchSubmodules,
      _deepClone :: forall (k :: FetchStatus). NixFetcher k -> Bool
_deepClone = Bool -> NixExpr
forall a. ToNixExpr a => a -> NixExpr
toNixExpr -> NixExpr
deepClone,
      _leaveDotGit :: forall (k :: FetchStatus). NixFetcher k -> Bool
_leaveDotGit = Bool -> NixExpr
forall a. ToNixExpr a => a -> NixExpr
toNixExpr -> NixExpr
leaveDotGit,
      _fowner :: forall (k :: FetchStatus). NixFetcher k -> NixExpr
_fowner = NixExpr -> NixExpr
asString -> NixExpr
owner,
      _frepo :: forall (k :: FetchStatus). NixFetcher k -> NixExpr
_frepo = NixExpr -> NixExpr
asString -> NixExpr
repo
    } ->
      -- TODO: fix fetchFromGitHub in Nixpkgs so that deepClone and
      -- leaveDotGit won't get passed to fetchzip
      if (NixExpr
deepClone NixExpr -> NixExpr -> Bool
forall a. Eq a => a -> a -> Bool
== NixExpr
"true") Bool -> Bool -> Bool
|| (NixExpr
leaveDotGit NixExpr -> NixExpr -> Bool
forall a. Eq a => a -> a -> Bool
== NixExpr
"true")
      then [trimming|
               fetchFromGitHub ({
                 owner = $owner;
                 repo = $repo;
                 rev = $rev;
                 fetchSubmodules = $fetchSubmodules;
                 deepClone = $deepClone;
                 leaveDotGit = $leaveDotGit;
                 sha256 = $sha256;
               })
         |]
      else [trimming|
               fetchFromGitHub ({
                 owner = $owner;
                 repo = $repo;
                 rev = $rev;
                 fetchSubmodules = $fetchSubmodules;
                 sha256 = $sha256;
               })
         |]
  (FetchUrl (NixExpr -> NixExpr
asString -> NixExpr
url) FetchResult k
_) ->
    [trimming|
          fetchurl {
            url = $url;
            sha256 = $sha256;
          }
    |]

instance ToNixExpr ExtractSrcQ where
  toNixExpr :: ExtractSrcQ -> NixExpr
toNixExpr (ExtractSrcQ NixFetcher 'Fetched
fetcher NonEmpty String
files) = NixFetcher 'Fetched -> NonEmpty String -> NixExpr
extractFiles NixFetcher 'Fetched
fetcher NonEmpty String
files

extractFiles :: NixFetcher Fetched -> NE.NonEmpty FilePath -> NixExpr
extractFiles :: NixFetcher 'Fetched -> NonEmpty String -> NixExpr
extractFiles (NixFetcher 'Fetched -> NixExpr
forall a. ToNixExpr a => a -> NixExpr
toNixExpr -> NixExpr
fetcherExpr) (NonEmpty String -> NixExpr
forall a. ToNixExpr a => a -> NixExpr
toNixExpr -> NixExpr
fileNames) =
  [trimming|
    let
      drv = import (pkgs.writeText "src" ''
        pkgs: {
          src = pkgs.$fetcherExpr;
        }
      '');
      fileNames = $fileNames;
      toFile = f: builtins.readFile ((drv pkgs).src + "/" + f);
    in builtins.listToAttrs (builtins.map (x: {
      name = x;
      value = toFile x;
    }) fileNames)
  |]