1 {-# LANGUAGE OverloadedStrings #-}
2 module Main
(main
) where
4 import Control
.Lens
(imap
)
5 import Data
.Aeson
(FromJSON
(..), eitherDecode
, withObject
, (.:))
6 import Data
.List
(sortOn
)
7 import Data
.Text
(Text
)
8 import Data
.Traversable
(for
)
10 import qualified Data
.ByteString
.Lazy
as LBS
11 import qualified Data
.Set
as Set
12 import qualified Data
.Text
as T
13 import qualified Options
.Applicative
as O
14 import qualified Zinza
as Z
18 data Opts
= Opts
FilePath (PerV
FilePath) FilePath
21 main
= generate
=<< O
.execParser opts
where
22 opts
= O
.info
(O
.helper
<*> parser
) $ mconcat
24 , O
.progDesc
"Generate SPDX LicenseExceptionId module"
27 parser
:: O
.Parser Opts
28 parser
= Opts
<$> template
<*> licensesAll
<*> output
40 template
= O
.strArgument
$ mconcat
41 [ O
.metavar
"SPDX.LicenseExceptionId.template.hs"
42 , O
.help
"Module template file"
45 licenses ver
= O
.strArgument
$ mconcat
46 [ O
.metavar
$ "exceptions" ++ ver
++ ".json"
47 , O
.help
"Exceptions JSON. https://github.com/spdx/license-list-data"
50 output
= O
.strArgument
$ mconcat
51 [ O
.metavar
"Output.hs"
52 , O
.help
"Output file"
55 generate
:: Opts
-> IO ()
56 generate
(Opts tmplFile fns out
) = do
57 lss
<- for fns
$ \fn
-> either fail pure
. eitherDecode
=<< LBS
.readFile fn
58 template
<- Z
.parseAndCompileTemplateIO tmplFile
59 output
<- generate
' lss template
60 writeFile out
(header
<> "\n" <> output
)
61 putStrLn $ "Generated file " ++ out
65 -> (Input
-> IO String)
67 generate
' lss template
= template
$ Input
68 { inputLicenseIds
= licenseIds
69 , inputLicenses
= licenseValues
70 , inputLicenseList_all
= mkLicenseList
(== allVers
)
71 , inputLicenseList_perv
= tabulate
$ \ver
-> mkLicenseList
72 (\vers
-> vers
/= allVers
&& Set
.member ver vers
)
75 constructorNames
:: [(Text
, License
, Set
.Set SPDXLicenseListVersion
)]
77 = map (\(l
, tags
) -> (toConstructorName
$ licenseId l
, l
, tags
))
78 $ combine licenseId
$ \ver
-> filterDeprecated
$ unLL
$ index ver lss
80 filterDeprecated
= filter (not . licenseDeprecated
)
82 licenseValues
:: [InputLicense
]
83 licenseValues
= flip map constructorNames
$ \(c
, l
, _
) -> InputLicense
85 , ilId
= textShow
(licenseId l
)
86 , ilName
= textShow
(licenseName l
)
87 , ilIsOsiApproved
= False -- not used in exceptions
88 , ilIsFsfLibre
= False -- not used in exceptions
92 licenseIds
= T
.intercalate
"\n" $ flip imap constructorNames
$ \i
(c
, l
, vers
) ->
93 let pfx
= if i
== 0 then " = " else " | "
95 | vers
== allVers
= ""
96 |
otherwise = foldMap
(\v -> ", " <> prettyVer v
) vers
97 in pfx
<> c
<> " -- ^ @" <> licenseId l
<> "@, " <> licenseName l
<> versInfo
99 mkLicenseList
:: (Set
.Set SPDXLicenseListVersion
-> Bool) -> Text
100 mkLicenseList p
= mkList
[ n |
(n
, _
, vers
) <- constructorNames
, p vers
]
102 -------------------------------------------------------------------------------
104 -------------------------------------------------------------------------------
106 data License
= License
108 , licenseName
:: !Text
109 , licenseDeprecated
:: !Bool
113 instance FromJSON License
where
114 parseJSON
= withObject
"License" $ \obj
-> License
115 <$> obj
.: "licenseExceptionId"
116 <*> fmap (T
.map fixSpace
) (obj
.: "name")
117 <*> obj
.: "isDeprecatedLicenseId"
122 newtype LicenseList
= LL
{ unLL
:: [License
] }
125 instance FromJSON LicenseList
where
126 parseJSON
= withObject
"Exceptions list" $ \obj
->
127 LL
. sortOn
(OrdT
. T
.toLower . licenseId
)
128 <$> obj
.: "exceptions"