shellify-0.10.0: src/TemplateGeneration.hs
module TemplateGeneration (generateShellDotNixText, generateFlakeText, getRegistryDB) where
import Prelude hiding (lines)
import Constants
import FlakeTemplate
import Options
import ShellifyTemplate
import Data.Bool (bool)
import Data.List (find, sort)
import Data.List.Extra ((!?))
import Data.Maybe (catMaybes, fromMaybe)
import Data.Set (fromList, toList)
import Data.Text (isInfixOf, isPrefixOf, lines, pack, splitOn, Text())
import Development.Shake.Command (cmd, Exit(Exit), Stderr(Stderr), Stdout(Stdout))
import System.Exit (ExitCode (ExitSuccess))
import Text.StringTemplate (newSTMP, render, setAttribute)
generateFlakeText :: Text -> Options -> Maybe Text
generateFlakeText db Options{packages=packages, generateFlake=shouldGenerateFlake} =
bool
Nothing
(Just $ render
$ setAttribute "repo_inputs" repoInputs
$ setAttribute "repos" repos
$ setAttribute "pkgs_decls" pkgsDecls
$ setAttribute "shell_args" shellArgs
$ newSTMP flakeTemplate)
shouldGenerateFlake
where repos = uniq $ getPackageRepo <$> sort packages
repoVars = getPackageRepoVarName <$> repos
repoInputs = repoInput <$> repos
repoInputLine repoName url = repoName <> ".url = \"" <> url <> "\";"
repoInput repoName = repoInputLine repoName .
either
(error "Unexpected output from nix registry call: " <>)
(fromMaybe "PLEASE ENTER input here")
. findFlakeRepoUrl db $ repoName
pkgsVar = (<> "Pkgs")
pkgsVars = pkgsVar <$> repos
pkgsDecls = (\repo -> pkgsDecl (pkgsVar repo) repo) <$> repos
shellArgs = (\(a,b) -> a <> "=" <> b <> ";") <$> zip repoVars pkgsVars
generateShellDotNixText :: Options -> Text
generateShellDotNixText Options{packages=packages, command=command} =
render
$ setAttribute "build_inputs" pkgs
$ setAttribute "parameters" parameters
$ maybe id
(setAttribute "shell_hook")
command
$ newSTMP shellifyTemplate
where pkgs = generateBuildInput <$> sort packages
parameters = uniq $ generateParameters <$> sort packages
generateBuildInput input = (toImportVar . getPackageRepo) input <> "." <> getPackageName input
getPackageRepo input | "#" `isInfixOf` input
= head $ splitOn "#" input
| otherwise
= "nixpkgs"
getPackageName input | "#" `isInfixOf` input
= head $ tail $ splitOn "#" input
| otherwise
= input
toImportVar var | var == "nixpkgs"
= "pkgs"
| otherwise
= var
getPackageRepoVarName "nixpkgs" = "pkgs"
getPackageRepoVarName a = a
generateParameters :: Package -> Text
generateParameters package | "#" `isInfixOf` package
&& not ("nixpkgs#" `isPrefixOf` package)
= getPackageRepo package
generateParameters _ = "pkgs ? import <nixpkgs> {}"
uniq :: Ord a => [a] -> [a]
uniq = toList . fromList
getRegistryDB :: IO (Either Text Text)
getRegistryDB =
do (Stdout out, Stderr err, Exit ex) <- cmd
("nix --extra-experimental-features nix-command --extra-experimental-features flakes registry list" :: String)
return $ bool (Left $ pack err)
(Right $ pack out)
(ex == ExitSuccess)
findFlakeRepoUrl :: Text -> Text -> Either Text (Maybe Text)
findFlakeRepoUrl haystack needle =
fmap repoUrl . find ((needle ==) . repoName) . catMaybes <$> mapM getFlakeRepo (lines haystack)
data FlakeRepo = FlakeRepo {
repoName :: Text
, repoUrl :: Text
}
getFlakeRepo :: Text -> Either Text (Maybe FlakeRepo)
getFlakeRepo line = let expectedField = maybe (Left "unexepected nix registry command format")
Right
. (!?) (splitOn " " line)
urlField = expectedField 2
splitRepoField = splitOn ":" <$> expectedField 1
potentialFlakeName ["flake", b] = Just b
potentialFlakeName _ = Nothing
f x y = (`FlakeRepo` y) <$> potentialFlakeName x
in f <$> splitRepoField <*> urlField