1
1
module TemplateGeneration (generateShellDotNixText , generateFlakeText , getRegistryDB ) where
2
2
3
- import Prelude hiding (lines )
4
-
5
3
import Constants
6
4
import FlakeTemplate
7
5
import Options
8
6
import ShellifyTemplate
9
7
8
+ import Data.Bifunctor (bimap )
10
9
import Data.Bool (bool )
11
- import Data.List (find , sort )
12
- import Data.List.Extra ((!?) )
13
- import Data.Maybe (catMaybes , fromMaybe )
10
+ import Data.List (find , sort , sortBy , sortOn )
11
+ import Data.Maybe (fromMaybe )
14
12
import Data.Set (fromList , toList )
15
- import Data.Text (isInfixOf , isPrefixOf , lines , pack , splitOn , Text () )
13
+ import Data.Text (Text (), isInfixOf , isPrefixOf , pack , splitOn , unpack )
16
14
import Development.Shake.Command (cmd , Exit (Exit ), Stderr (Stderr ), Stdout (Stdout ))
17
15
import System.Exit (ExitCode (ExitSuccess ))
16
+ import Text.ParserCombinators.Parsec (Parser , char , endBy , eof , many1 , noneOf , parse , string , (<|>) )
18
17
import Text.StringTemplate (newSTMP , render , setAttribute )
19
18
20
19
generateFlakeText :: Text -> Options -> Maybe Text
21
- generateFlakeText db Options {packages= packages, generateFlake= shouldGenerateFlake} =
20
+ generateFlakeText db Options {packages= packages, generateFlake= shouldGenerateFlake, prioritiseLocalPinnedSystem = prioritiseLocalPinnedSystem } =
22
21
bool
23
22
Nothing
24
23
(Just $ render
@@ -28,15 +27,15 @@ generateFlakeText db Options{packages=packages, generateFlake=shouldGenerateFlak
28
27
$ setAttribute " shell_args" shellArgs
29
28
$ newSTMP flakeTemplate)
30
29
shouldGenerateFlake
31
- where repos = uniq $ getPackageRepo <$> sort packages
30
+ where repos = getPackageRepoWrapper packages
32
31
repoVars = getPackageRepoVarName <$> repos
33
32
repoInputs = repoInput <$> repos
34
33
repoInputLine repoName url = repoName <> " .url = \" " <> url <> " \" ;"
35
34
repoInput repoName = repoInputLine repoName .
36
35
either
37
- (error " Unexpected output from nix registry call: " <> )
36
+ (error . ( " Unexpected output from nix registry call: " <> ) )
38
37
(fromMaybe " PLEASE ENTER input here" )
39
- . findFlakeRepoUrl db $ repoName
38
+ . findFlakeRepoUrl prioritiseLocalPinnedSystem db $ repoName
40
39
pkgsVar = (<> " Pkgs" )
41
40
pkgsVars = pkgsVar <$> repos
42
41
pkgsDecls = (\ repo -> pkgsDecl (pkgsVar repo) repo) <$> repos
@@ -52,9 +51,12 @@ generateShellDotNixText Options{packages=packages, command=command} =
52
51
command
53
52
$ newSTMP shellifyTemplate
54
53
where pkgs = generateBuildInput <$> sort packages
55
- parameters = uniq $ generateParameters <$> sort packages
54
+ parameters = generateParametersWrapper packages
56
55
generateBuildInput input = (toImportVar . getPackageRepo) input <> " ." <> getPackageName input
57
56
57
+ getPackageRepoWrapper :: [Package ] -> [Text ]
58
+ getPackageRepoWrapper = uniq . (" nixpkgs" : ) . fmap getPackageRepo . sort
59
+
58
60
getPackageRepo input | " #" `isInfixOf` input
59
61
= head $ splitOn " #" input
60
62
| otherwise
@@ -73,6 +75,9 @@ toImportVar var | var == "nixpkgs"
73
75
getPackageRepoVarName " nixpkgs" = " pkgs"
74
76
getPackageRepoVarName a = a
75
77
78
+ generateParametersWrapper :: [Package ] -> [Text ]
79
+ generateParametersWrapper = uniq . (" pkgs ? import <nixpkgs> {}" : ) . fmap generateParameters . sort
80
+
76
81
generateParameters :: Package -> Text
77
82
generateParameters package | " #" `isInfixOf` package
78
83
&& not (" nixpkgs#" `isPrefixOf` package)
@@ -90,23 +95,40 @@ getRegistryDB =
90
95
(Right $ pack out)
91
96
(ex == ExitSuccess )
92
97
93
- findFlakeRepoUrl :: Text -> Text -> Either Text (Maybe Text )
94
- findFlakeRepoUrl haystack needle =
95
- fmap repoUrl . find ((needle == ) . repoName) . catMaybes <$> mapM getFlakeRepo (lines haystack)
98
+ findFlakeRepoUrl :: Bool -> Text -> Text -> Either String (Maybe Text )
99
+ findFlakeRepoUrl prioritiseLocalPinnedSystem haystack needle =
100
+ bimap ((<>) " Error processing nix registry list output: " . show )
101
+ (fmap repoUrl . find ((needle == ) . repoName)
102
+ . (if prioritiseLocalPinnedSystem then sortOn repoType else sortBy compareRepoEntries))
103
+ $ parse parseRepos " " . unpack $ haystack
104
+
105
+ compareRepoEntries repoA repoB
106
+ | repoHasLocalPinning repoA && not (repoHasLocalPinning repoB) = GT
107
+ | repoHasLocalPinning repoB && not (repoHasLocalPinning repoA) = LT
108
+ | otherwise = repoType repoA `compare` repoType repoB
109
+ where repoHasLocalPinning = isPrefixOf " path:" . repoUrl
110
+
111
+ data RepoType = User | System | Global
112
+ deriving (Eq , Ord )
96
113
97
114
data FlakeRepo = FlakeRepo {
98
115
repoName :: Text
99
116
, repoUrl :: Text
117
+ , repoType :: RepoType
100
118
}
101
119
102
- getFlakeRepo :: Text -> Either Text (Maybe FlakeRepo )
103
- getFlakeRepo line = let expectedField = maybe (Left " unexepected nix registry command format" )
104
- Right
105
- . (!?) (splitOn " " line)
106
- urlField = expectedField 2
107
- splitRepoField = splitOn " :" <$> expectedField 1
108
- potentialFlakeName [" flake" , b] = Just b
109
- potentialFlakeName _ = Nothing
110
- f x y = (`FlakeRepo ` y) <$> potentialFlakeName x
111
- in f <$> splitRepoField <*> urlField
120
+ parseRepos :: Parser [FlakeRepo ]
121
+ parseRepos = do res <- endBy parseLine (char ' \n ' )
122
+ eof
123
+ return res
124
+ where parseLine = do repoType <- parseRepoType
125
+ char ' '
126
+ flakeName <- string " flake:" >> parseParam
127
+ char ' '
128
+ repoUrl <- parseParam
129
+ return $ FlakeRepo (pack flakeName) (pack repoUrl) repoType
130
+ parseParam = many1 (noneOf " \n " )
131
+ parseRepoType = (string " global" >> return Global )
132
+ <|> (string " system" >> return System )
133
+ <|> (string " user" >> return User )
112
134
0 commit comments