summaryrefslogtreecommitdiff
path: root/Biz/Bild/Meta.hs
blob: 5549cb328cb1003296bbc97ea1e3727f5284d76f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE NoImplicitPrelude #-}

-- | Small module for extracting metadata from the comments of modules.
module Biz.Bild.Meta where

import Alpha
import qualified Data.Aeson as Aeson
import qualified Data.Char as Char
import qualified Data.Set as Set
import qualified Data.Text as Text
import qualified Text.Regex.Applicative as Regex

-- | A third-party dependency. This gets mapped to some name in nixpkgs,
-- prefixed by package set like @haskellPackages@ or
-- @python3Packages@. Currently this prefix is implicit, but it should be added
-- here as part of a tuple or something.
type Dep = String

-- | This is a system-level requirement, the string gets mapped to a name in
-- nixpkgs at the top level, like @pkgs.thing@. If I add the package set prefix to 'Dep', then this can just become literally @(Sys, "thing")@.
type Sys = String

-- | An arbitrary compiler argument that may get added to the compilation
-- command. Should be used sparingly, and not all builds will support this.
type Arg = String

data Out = Lib String | Bin String | None
  deriving (Show, Eq)

instance Aeson.ToJSON Out where
  toJSON =
    Aeson.String <. Text.pack <. \case
      Bin a -> a
      Lib a -> a
      None -> ""

data Parsed = Parsed
  { pdep :: Set Dep,
    parg :: Set Arg,
    pout :: Out,
    psys :: Set Sys
  }

detect :: Ord a => Regex.RE Char a -> [Text] -> Set a
detect m cl =
  cl
    /> Text.unpack
    /> Regex.match m
    |> catMaybes
    |> Set.fromList

-- | 'Out' is always singular, so it gets a special function
detectOut :: Regex.RE Char Out -> [Text] -> Out
detectOut m cl =
  cl
    /> Text.unpack
    /> Regex.match m
    |> catMaybes
    |> head
    |> fromMaybe None

detectAll :: [Char] -> [Text] -> Parsed
detectAll m cl = Parsed {..}
  where
    pout = detectOut (out m <|> lib m) cl
    detect_ re = detect (re m) cl
    pdep = detect_ dep
    psys = detect_ sys
    parg = detect_ arg

dep :: [Char] -> Regex.RE Char Dep
dep comment =
  Regex.string (comment ++ " : dep ")
    *> Regex.many (Regex.psym (not <. Char.isSpace))

sys :: [Char] -> Regex.RE Char Dep
sys comment =
  Regex.string (comment ++ " : sys ")
    *> Regex.many (Regex.psym (not <. Char.isSpace))

out :: [Char] -> Regex.RE Char Out
out comment =
  Regex.string (comment ++ " : out ")
    *> Regex.many (Regex.psym (/= ' '))
    /> Bin

lib :: [Char] -> Regex.RE Char Out
lib comment =
  Regex.string (comment ++ " : lib ")
    *> Regex.many (Regex.psym (/= ' '))
    /> Lib

arg :: [Char] -> Regex.RE Char Arg
arg comment =
  Regex.string (comment ++ " : arg ")
    *> Regex.many Regex.anySym