Compare commits

...

47 Commits

Author SHA1 Message Date
Juan Pedro Villa Isaza
ceffd422d9 Add CNAME 2020-02-16 18:04:09 -05:00
Juan Pedro Villa Isaza
00f903d7ac Bump version to 0.4.0 (Cabal file) 2020-02-16 17:58:17 -05:00
Juan Pedro Villa Isaza
9a122b2961 Bump version to 0.4.0 2020-02-16 17:55:33 -05:00
Juan Pedro Villa Isaza
3f72d89232 Switch to named field puns and pure 2020-02-16 17:55:08 -05:00
Juan Pedro Villa Isaza
4473ab4341 Move executable to app (2) 2020-02-16 17:34:23 -05:00
Juan Pedro Villa Isaza
9a17f87eee Move executable to app 2020-02-16 17:33:23 -05:00
Juan Pedro Villa Isaza
15af251f38 Add generated Cabal file 2020-02-16 11:32:32 -05:00
Juan Pedro Villa Isaza
055192d887 Remove CircleCI configuration 2020-02-16 11:32:22 -05:00
Juan Pedro Villa Isaza
72cb001e07 Add Jekyll configuration 2020-02-16 11:29:40 -05:00
Juan Pedro Villa Isaza
6b0eea666e
Configure GitHub Actions (#24) 2020-02-16 11:18:11 -05:00
Juan Pedro Villa Isaza
fc1fd98e8a Update CircleCI configuration 2020-02-15 08:16:14 -05:00
Juan Pedro Villa Isaza
ba5a60ea7e Add stack.yaml.lock 2020-02-15 08:16:01 -05:00
Juan Pedro Villa Isaza
265fa6e773 Apply HLint suggestions 2020-02-15 08:12:21 -05:00
Juan Pedro Villa Isaza
2f3f9a72ec Remove http-conduit 2020-02-15 08:07:20 -05:00
Juan Pedro Villa Isaza
73ffa34491 Use hpack in cache key 2019-02-06 06:30:48 -05:00
Juan Pedro Villa Isaza
5a7e9a4ecf Use hpack (close #20) 2019-02-05 18:08:01 -05:00
Juan Pedro Villa Isaza
0f039d2198 Bump version to 0.3.0 2019-02-05 16:09:17 -05:00
Juan Pedro Villa Isaza
ec8412b4ca Use Stack (executable) to get licenses 2019-02-05 16:01:07 -05:00
Juan Pedro Villa Isaza
4f4d41d986 Use ls dependencies instead of list-dependencies (close #22) 2019-02-05 15:22:10 -05:00
Juan Pedro Villa Isaza
8d029d1e5c
Update CircleCI badge to shield 2019-02-02 16:23:40 -05:00
Juan Pedro Villa Isaza
0a9c185f83
Remove docs/index.html 2019-02-02 16:21:03 -05:00
Juan Pedro Villa Isaza
10a0b5d5b6
Update CircleCI 2.0 caching strategy (#19) 2018-05-29 08:44:00 -05:00
Juan Pedro Villa Isaza
e760e686f4
Migrate to CircleCI 2.0 (#18) 2018-05-28 17:41:16 -05:00
Juan Pedro Villa Isaza
bc596ae093 Set resolver to LTS 11.11 2018-05-28 16:45:14 -05:00
Juan Pedro Villa Isaza
15864d942c Bump version to 0.2.2 2018-01-16 17:47:37 -05:00
Juan Pedro Villa Isaza
558fe3ddc0 Allow http-conduit 2.3 2018-01-16 17:39:19 -05:00
Juan Pedro Villa Isaza
2ffc6d1ace Use CircleCI's preinstalled Stack 2017-07-24 09:30:09 -05:00
Juan Pedro Villa Isaza
999c503d59 Bump version to 0.2.1 2017-07-24 09:26:51 -05:00
Juan Pedro Villa Isaza
7bbb36099a Allow base 4.10 and Cabal 2.0 2017-07-24 09:25:49 -05:00
Juan Pedro Villa Isaza
f95f13e23b Add link to Open Source Guide [skip ci] 2017-02-17 12:53:13 -05:00
Juan Pedro Villa Isaza
3c75a4966a Add verbosity flags 2016-09-24 11:45:03 -05:00
Juan Pedro Villa Isaza
72f3659db1 Add links to Stackage [skip ci] 2016-09-20 19:24:34 -05:00
Juan Pedro Villa Isaza
c4610123a5 Bump version to 0.2.0 2016-09-18 17:19:48 -05:00
Juan Pedro Villa Isaza
e3ae5e8a31 Add a CHANGELOG [skip ci] 2016-09-18 17:17:14 -05:00
Juan Pedro Villa Isaza
3dcded9a03 Complete the README [skip ci] 2016-09-18 16:46:19 -05:00
Juan Pedro Villa Isaza
b27fa39109 Add Cabal files to the gitignore file [skip ci] 2016-09-18 13:04:47 -05:00
Juan Pedro Villa Isaza
c4843515cc Set the Stack resolver to lts-7.0 2016-09-17 09:27:29 -05:00
Juan Pedro Villa Isaza
7d47ab993c Add a title to the README [skip ci] 2016-09-11 17:55:33 -05:00
Juan Pedro Villa Isaza
f545a4c170 Allow use if stack.yaml file is found 2016-09-10 18:20:40 -05:00
Juan Pedro Villa Isaza
ec640bb8ff Add a report of errors 2016-09-10 17:56:01 -05:00
Juan Pedro Villa Isaza
f6735cb872 Replace HTTP with http-conduit (close #9) 2016-09-10 17:23:32 -05:00
Juan Pedro Villa Isaza
2558a0579e Add command line arguments (cmdargs) 2016-08-20 16:18:55 -05:00
Juan Pedro Villa Isaza
835ac70815 Add licensor library 2016-08-20 14:23:19 -05:00
Juan Pedro Villa Isaza
4cd27b1a15 Add license to README [skip ci] 2016-08-17 20:27:09 -05:00
Juan Pedro Villa Isaza
bf17683ad6 Add docs/index.html [skip ci] 2016-08-17 20:14:15 -05:00
Juan Pedro Villa Isaza
1c39127263 Configure CircleCI 2016-08-13 15:45:10 -05:00
Juan Pedro Villa Isaza
62e5a17feb Add status badge [skip ci] 2016-08-13 15:31:59 -05:00
15 changed files with 708 additions and 230 deletions

20
.github/workflows/main.yml vendored Normal file
View File

@ -0,0 +1,20 @@
name: Main
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Cache dependencies
uses: actions/cache@v1
with:
path: ~/.stack
key: stack-${{ hashFiles('stack.yaml.lock') }}
- name: Install GHC
run: stack setup
- name: Build dependencies
run: stack build --only-dependencies
- name: Build package
run: stack build

3
.gitignore vendored
View File

@ -1 +1,4 @@
Gemfile.lock
_site/
.stack-work/

36
CHANGELOG.md Normal file
View File

@ -0,0 +1,36 @@
# 0.4.0 (2020-02-16)
## Enhancements
- Use hpack
# 0.3.0 (2019-02-05)
## Enhancements
- Use Stack (executable) to get licenses (ec8412b)
- Use `ls dependencies` instead of `list-dependencies` (4f4d41d)
## Bugs
- Fix incorrect license if package matches a Hackage package (#23)
# 0.2.2 (2018-01-16)
- Allow http-conduit 2.3 (558fe3d)
# 0.2.1 (2017-07-24)
- Allow base 4.10 and Cabal 2.0 (7bbb360)
# 0.2.0 (2016-09-18)
## Enhancements
- Allow use in multi-package project (f545a4c)
- Handle exceptions (ec640bb)
- Replace HTTP with http-conduit (f6735cb)
- Add command line arguments (2558a05)
- Add a library (835ac70)
# 0.1.0 (2016-08-13)

1
CNAME Normal file
View File

@ -0,0 +1 @@
licensor.jpvillaisaza.co

3
Gemfile Normal file
View File

@ -0,0 +1,3 @@
source "https://rubygems.org/"
gem "github-pages"

188
Main.hs
View File

@ -1,188 +0,0 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RecordWildCards #-}
module Main
( main
)
where
-- base
import Control.Monad
import Data.List
import Data.Monoid ((<>))
import qualified System.Exit as Exit
import System.IO
-- Cabal
import Distribution.License
import Distribution.Package
import Distribution.PackageDescription
import Distribution.PackageDescription.Parse
import Distribution.Simple.Utils
import Distribution.Text
import Distribution.Verbosity
-- containers
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Set (Set)
import qualified Data.Set as Set
-- directory
import System.Directory
-- HTTP
import Network.HTTP
( getRequest
, getResponseBody
, simpleHTTP
)
-- process
import System.Process
-- |
--
--
newtype License' = License' { _getLicense :: License }
deriving (Eq, Read, Show, Text)
-- |
--
--
instance Ord License' where
compare =
comparing display
-- |
--
--
main :: IO ()
main = do
maybePackage <- getPackage
pid <-
case maybePackage of
Nothing ->
Exit.die "Error: No Cabal file found."
Just PackageDescription{..} -> do
putStrLn $
"Package: "
<> display package
<> " ("
<> "License: "
<> display license
<> ")"
return package
maybeDependencies <- getDependencies
case maybeDependencies of
Nothing ->
Exit.die "Error: ..."
Just dependencies -> do
dependenciesByLicense <-
fmap (Set.map display) <$> orderPackagesByLicense pid dependencies
forM_ (Map.keys dependenciesByLicense) $
\license ->
let
n = dependenciesByLicense Map.! license
in do
putStrLn "-----"
putStrLn $
show (Set.size n)
<> (if Set.size n == 1 then " package " else " packages ")
<> "licensed under "
<> display license
<> ": "
<> intercalate ", " (Set.toList n)
-- |
--
--
getPackage :: IO (Maybe PackageDescription)
getPackage = do
currentDirectory <- getCurrentDirectory
fmap getPackageDescription <$> findPackageDesc currentDirectory
>>= either (const (return Nothing)) (fmap Just)
-- |
--
--
getPackageDescription :: FilePath -> IO PackageDescription
getPackageDescription =
fmap packageDescription . readPackageDescription silent
-- |
--
--
getDependencies :: IO (Maybe (Set PackageIdentifier))
getDependencies =
fmap Set.fromList . sequence . fmap simpleParse . lines
<$> readProcess "stack" ["list-dependencies", "--separator", "-"] ""
-- |
--
--
getPackageLicense :: PackageIdentifier -> IO License'
getPackageLicense p@PackageIdentifier{..} = do
let
url =
"http://hackage.haskell.org/package/"
<> display p
<> "/"
<> unPackageName pkgName
<> ".cabal"
pd <- simpleHTTP (getRequest url) >>= getResponseBody
(file, handle) <- openTempFile "/tmp" "licensor"
hClose handle
writeFile file pd
PackageDescription{license} <- getPackageDescription file
hClose handle
removeFile file
return (License' license)
-- |
--
--
orderPackagesByLicense
:: PackageIdentifier
-> Set PackageIdentifier
-> IO (Map License' (Set PackageIdentifier))
orderPackagesByLicense p =
let
insertPackage package orderedPackages' = do
license <- getPackageLicense package
orderedPackages <- orderedPackages'
return $
if p == package
then
orderedPackages
else
Map.insertWith
Set.union
license
(Set.singleton package)
orderedPackages
in
foldr insertPackage (pure mempty)

172
README.md
View File

@ -1 +1,171 @@
# licensor
# The not so great automatic Haskell licensor
[![][2]](https://www.stackage.org/lts/package/licensor)
[![][3]](https://www.stackage.org/nightly/package/licensor)
[2]: https://www.stackage.org/package/licensor/badge/lts
[3]: https://www.stackage.org/package/licensor/badge/nightly
Licensor is a program that generates a report of the dependencies and
transitive dependencies of a Haskell project and their licenses.
## Description
Choosing a license for a software project or determining whether a
particular dependency can be added to a project can be projects
themselves. Unless starting from scratch, programmers should consider
the licenses of the dependencies and transitive dependencies of their
projects to make informed decisions and avoid license compatibility
issues.
Of course, this is just a starting point. "Beyond (...) general
observations, it is difficult, if not impossible, to provide precise
guidance about what licenses may or may not be compatible with each
other. (...) Programmers who are considering combining code governed
by two or more different licenses should proceed cautiously" (Andrew
M. St. Laurent).
## Disclaimer
Licensor is not a lawyer and does not provide legal advice.
For more information about licenses and license compatibility issues,
read the text of the licenses or consult with a lawyer before making
any decision.
## Related programs
Licensor is not the only license compatibility helper for Haskell:
- Licensor uses a Cabal library and Stack program approach for
detecting licenses and listing dependencies, respectively. For a
Cabal library and program approach, consider using
the [cabal-dependency-licenses][rp-01] program.
[rp-01]: https://hackage.haskell.org/package/cabal-dependency-licenses
## Installation and usage
To install Licensor, use Cabal:
```
$ cabal update && cabal install licensor
```
Then, run the `licensor` executable inside a Haskell project:
```
$ licensor
```
To see the license report for Licensor, clone the repository:
```
$ git clone https://github.com/jpvillaisaza/licensor
```
And run `licensor` inside the project:
```
$ cd licensor/ && licensor
```
Or build and run `licensor` inside the project:
```
$ cd licensor/ && stack build --exec licensor
```
For more information, run `licensor --help`:
```
licensor 0.4.0
licensor [OPTIONS]
Common flags:
-? --help Display help message
-V --version Print version information
--numeric-version Print just the version number
-v --verbose Loud verbosity
-q --quiet Quiet verbosity
```
## Notes
### Dependencies
Licensor uses the Stack program to list dependencies for a Haskell
project. A future enhancement could be to use the Stack library.
### Licenses and license detection
Licensor uses the Cabal library to detect the license of a Haskell
project and its dependencies (including transitive dependencies). To
do so, it uses the license field in the package description. A future
enhancement could be to use both the license and licence file fields
in the package description.
Cabal provides an enumeration of common open source and free software
licenses. These are the licenses that appear in the reports generated
by Licensor:
License | Description
------------------------- | -------------------------
GPL | GNU General Public License
AGPL | GNU Affero General Public License
LGPL | GNU Lesser General Public License
BSD2 | BSD 2-Clause License
BSD3 | BSD 3-Clause License
BSD4 | BSD 4-Clause License
MIT | MIT License
ISC | ISC License
MPL | Mozilla Public License
Apache | Apache License
PublicDomain | Public domain
AllRightsReserved | All rights reserved
UnspecifiedLicense | Unspecified license (All rights reserved)
OtherLicense | Other license
UnknownLicense | Unknown license
## Contribution guidelines
Feel free to create issues for reporting bugs and suggesting
enhancements, or to fork the repository and open a pull request.
## License
Licensor is licensed under the MIT License.
See [LICENSE.md](LICENSE.md).
### License report
Licensor (0.4.0) depends on the following libraries:
Library | License
------------------------- | -------------------------
base | BSD3
Cabal | BSD3
cmdargs | BSD3
containers | BSD3
directory | BSD3
process | BSD3
And the following licenses (including transitive dependencies):
License | Number of libraries
------------------------- | -------------------------
BSD3 | 20
(Tested with Licensor 0.4.0, Stack 2.1.3, and LTS Haskell 11.11.)
## Additional resources
- [Choose a License](https://choosealicense.com/)
- [The Legal Side of Open Source](https://opensource.guide/legal/)
- [License compatibility][ar-01]
- [Understanding open source and free software licensing][ar-02]
(Andrew M. St. Laurent)
[ar-01]: https://en.wikipedia.org/wiki/License_compatibility
[ar-02]: http://www.oreilly.com/openbook/osfreesoft/book/

View File

@ -1,11 +0,0 @@
module Main
( main
)
where
import Distribution.Simple (defaultMain)
main :: IO ()
main =
defaultMain

18
_config.yml Normal file
View File

@ -0,0 +1,18 @@
exclude:
- app/
- CHANGELOG.md
- Gemfile
- Gemfile.lock
- LICENSE.md
- licensor.cabal
- package.yaml
- src/
- package.yaml
- stack.yaml
- stack.yaml.lock
plugins:
- jekyll-readme-index
readme_index:
remove_originals: true

131
app/Main.hs Normal file
View File

@ -0,0 +1,131 @@
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE NamedFieldPuns #-}
----------------------------------------------------------------------
-- |
-- Module: Main
-- Description:
--
--
--
----------------------------------------------------------------------
module Main
( main
)
where
-- licensor
import Licensor
-- base
import Control.Monad
import Data.List
import Data.Monoid ((<>))
import qualified Data.Version as Version
import System.Environment
import qualified System.Exit as Exit
-- Cabal
import Distribution.PackageDescription
import Distribution.Text
-- cmdargs
import System.Console.CmdArgs
-- containers
import qualified Data.Map.Strict as Map
import qualified Data.Set as Set
-- directory
import System.Directory (doesFileExist)
-- |
--
--
data LiArgs =
LiArgs
{
}
deriving (Data)
-- |
--
--
liArgs :: String -> Mode (CmdArgs LiArgs)
liArgs s =
cmdArgsMode $
LiArgs
{
}
&= program s
&= summary (unwords ["licensor", Version.showVersion version])
&= verbosity
-- |
--
--
main :: IO ()
main = do
LiArgs <- cmdArgsRun . liArgs =<< getProgName
quiet <- fmap not isNormal
maybePackage <- getPackage
pid <-
case maybePackage of
Nothing -> do
stack <- doesFileExist "stack.yaml"
if stack
then do
putStrLn "Found stack.yaml..."
pure Nothing
else
Exit.die "Error: No Cabal file found."
Just PackageDescription { license, package } -> do
putStrLn $
"Package: "
<> display package
<> " ("
<> "License: "
<> display license
<> ")"
pure (Just package)
maybeDependencies <- getDependencies
maybeLicenses <- getLicenses
case (maybeDependencies, maybeLicenses) of
(Just dependencies, Just licenses) -> do
(dependenciesByLicense', failed) <-
orderPackagesByLicense quiet pid licenses dependencies
let dependenciesByLicense = fmap (Set.map display) dependenciesByLicense'
forM_ (Map.keys dependenciesByLicense) $
\license ->
let
n = dependenciesByLicense Map.! license
in do
putStrLn "-----"
putStrLn $
show (Set.size n)
<> (if Set.size n == 1 then " package " else " packages ")
<> "licensed under "
<> display license
<> ": "
<> intercalate ", " (Set.toList n)
unless (null failed) $ do
putStr "Failed: "
print failed
_ ->
Exit.die "Error: ..."

View File

@ -1,34 +1,61 @@
name: licensor
version: 0.1.0
synopsis: A license compatibility helper
description: A license compatibility helper.
homepage: https://github.com/jpvillaisaza/licensor
bug-reports: https://github.com/jpvillaisaza/licensor/issues
license: MIT
license-file: LICENSE.md
author: Juan Pedro Villa Isaza <jpvillaisaza@gmail.com>
maintainer: Juan Pedro Villa Isaza <jpvillaisaza@gmail.com>
copyright: 2016 Juan Pedro Villa Isaza
category: Distribution
extra-source-files: README.md
build-type: Simple
cabal-version: >= 1.10
cabal-version: 1.12
executable licensor
main-is:
Main.hs
build-depends:
base >= 4.8 && < 5.0
, Cabal >= 1.22 && < 1.25
, containers
, directory
, HTTP >= 4000.3 && < 4000.4
, process
default-language:
Haskell2010
ghc-options:
-Wall -threaded -rtsopts -with-rtsopts=-N
-- This file has been generated from package.yaml by hpack version 0.31.2.
--
-- see: https://github.com/sol/hpack
--
-- hash: b5e0234d196e96476a6a70c11798ae1dd4fd24ca9ce1c11ea74d6b3422604fc8
name: licensor
version: 0.4.0
synopsis: A license compatibility helper
description: A license compatibility helper.
category: Distribution
stability: Experimental
homepage: https://jpvillaisaza.co/licensor
bug-reports: https://github.com/jpvillaisaza/licensor/issues
author: Juan Pedro Villa Isaza <jpvillaisaza@gmail.com>
maintainer: Juan Pedro Villa Isaza <jpvillaisaza@gmail.com>
copyright: 2016 Juan Pedro Villa Isaza
license: MIT
license-file: LICENSE.md
build-type: Simple
extra-source-files:
CHANGELOG.md
README.md
source-repository head
type: git
location: https://github.com/jpvillaisaza/licensor
library
exposed-modules:
Licensor
other-modules:
Paths_licensor
hs-source-dirs:
src
ghc-options: -Wall
build-depends:
Cabal >=1.22 && <2.1
, base >=4.8 && <4.11
, containers
, directory
, process
default-language: Haskell2010
executable licensor
main-is: Main.hs
other-modules:
Paths_licensor
hs-source-dirs:
app
ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N
build-depends:
Cabal >=1.22 && <2.1
, base >=4.8 && <4.11
, cmdargs >=0.10 && <0.11
, containers
, directory
, licensor
default-language: Haskell2010

49
package.yaml Normal file
View File

@ -0,0 +1,49 @@
name: licensor
version: 0.4.0
synopsis: A license compatibility helper
description: A license compatibility helper.
category: Distribution
stability: Experimental
github: jpvillaisaza/licensor
homepage: https://jpvillaisaza.co/licensor
author: Juan Pedro Villa Isaza <jpvillaisaza@gmail.com>
maintainer: Juan Pedro Villa Isaza <jpvillaisaza@gmail.com>
copyright: 2016 Juan Pedro Villa Isaza
license-file: LICENSE.md
extra-source-files:
- CHANGELOG.md
- README.md
dependencies:
- Cabal >= 1.22 && < 2.1
- base >= 4.8 && < 4.11
- containers
- directory
ghc-options:
- -Wall
library:
source-dirs:
src
dependencies:
- process
executable:
source-dirs:
app
main:
Main.hs
dependencies:
- cmdargs >= 0.10 && < 0.11
- licensor
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N

207
src/Licensor.hs Normal file
View File

@ -0,0 +1,207 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ScopedTypeVariables #-}
----------------------------------------------------------------------
-- |
-- Module: Licensor
-- Description:
--
--
--
----------------------------------------------------------------------
module Licensor
( LiLicense(..)
, LiPackage(..)
, getDependencies
, getLicenses
, getPackage
, orderPackagesByLicense
, version
)
where
-- base
import qualified Control.Exception as Exception
import Control.Monad (unless)
import Data.Version (Version)
-- Cabal
import Distribution.License (License)
import Distribution.Package (PackageIdentifier(..), PackageName)
import Distribution.PackageDescription (PackageDescription, packageDescription)
import Distribution.PackageDescription.Parse (readGenericPackageDescription)
import Distribution.Simple.Utils (comparing, findPackageDesc)
import Distribution.Text (Text, display, simpleParse)
import Distribution.Verbosity (silent)
-- containers
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Set (Set)
import qualified Data.Set as Set
-- directory
import System.Directory (getCurrentDirectory)
-- licensor
import qualified Paths_licensor
-- process
import System.Process (readProcess)
-- |
--
--
newtype LiLicense = LiLicense { getLicense :: License }
deriving (Eq, Read, Show, Text)
-- |
--
--
instance Ord LiLicense where
compare =
comparing display
-- |
--
--
data LiPackage =
LiPackage
{ liPackageId :: PackageIdentifier
, liPackageDependencies :: Set LiPackage
, liPackageLicense :: License
}
-- |
--
--
getPackage :: IO (Maybe PackageDescription)
getPackage = do
currentDirectory <- getCurrentDirectory
fmap getPackageDescription <$> findPackageDesc currentDirectory
>>= either (const (pure Nothing)) (fmap Just)
-- |
--
--
getPackageDescription :: FilePath -> IO PackageDescription
getPackageDescription =
fmap packageDescription . readGenericPackageDescription silent
-- |
--
--
getDependencies :: IO (Maybe (Set PackageIdentifier))
getDependencies = do
eitherDeps <-
Exception.try $ readProcess "stack" ["ls", "dependencies", "--separator", "-"] ""
case eitherDeps of
Left (_ :: IOError) ->
pure Nothing
Right deps ->
pure $ Set.fromList <$> traverse simpleParse (lines deps)
getLicenses :: IO (Maybe [(PackageName, License)])
getLicenses = do
eitherDeps <-
Exception.try $ readProcess "stack" ["ls", "dependencies", "--license"] ""
case eitherDeps of
Left (_ :: IOError) ->
pure Nothing
Right deps ->
pure $ traverse toNameLicense (lines deps)
where
toNameLicense dep =
case words dep of
[name, license] ->
(,) <$> simpleParse name <*> simpleParse license
_ ->
Nothing
-- |
--
--
getPackageLicense
:: Bool
-> PackageIdentifier
-> [(PackageName, License)]
-> IO (Maybe LiLicense)
getPackageLicense quiet packageIdentifier licenses = do
unless quiet (putStr $ display packageIdentifier ++ "...")
case lookup (pkgName packageIdentifier) licenses of
Just license -> do
unless quiet (putStrLn $ display license)
pure $ Just (LiLicense license)
Nothing ->
pure Nothing
-- |
--
--
orderPackagesByLicense
:: Bool
-> Maybe PackageIdentifier
-> [(PackageName, License)]
-> Set PackageIdentifier
-> IO (Map LiLicense (Set PackageIdentifier), Set PackageIdentifier)
orderPackagesByLicense quiet maybeP licenses =
let
cond =
maybe (const False) (==) maybeP
insertPackage package orderedPackages' = do
maybeLicense <- getPackageLicense quiet package licenses
(orderedPackages, failed) <- orderedPackages'
pure $
if cond package
then
(orderedPackages, failed)
else
case maybeLicense of
Nothing ->
( orderedPackages, Set.insert package failed
)
Just license ->
( Map.insertWith
Set.union
license
(Set.singleton package)
orderedPackages
, failed
)
in
foldr insertPackage (pure (mempty, mempty))
-- |
--
--
version :: Version
version =
Paths_licensor.version

View File

@ -1 +1 @@
resolver: lts-6.11
resolver: lts-11.11

12
stack.yaml.lock Normal file
View File

@ -0,0 +1,12 @@
# This file was autogenerated by Stack.
# You should not edit this file by hand.
# For more information, please see the documentation at:
# https://docs.haskellstack.org/en/stable/lock_files
packages: []
snapshots:
- completed:
size: 507599
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/11/11.yaml
sha256: 5ec0a1ff4dadde524eb529784556bcc32014422fd1e1ed91231c59f001e92ca9
original: lts-11.11