Replace Cabal-managed config loading with FileEmbed

This uses the file-embed package and TemplateHaskell to load custom
configuration during compilation instead of loading it at runtime.
This commit is contained in:
Joshua Clayton 2016-08-18 17:59:12 -04:00
parent 8b50f5dd68
commit fde9f69a64
No known key found for this signature in database
GPG Key ID: 5B6558F77E9A8118
5 changed files with 55 additions and 56 deletions

View File

@ -1,31 +1,32 @@
{-# LANGUAGE TemplateHaskell #-}
module Unused.ResultsClassifier.Config
( loadConfig
, loadAllConfigurations
) where
import qualified Data.Bifunctor as BF
import qualified Data.ByteString as BS
import qualified Data.Either as E
import qualified Data.FileEmbed as FE
import qualified Data.Yaml as Y
import qualified Paths_unused as Paths
import qualified System.Directory as D
import System.FilePath ((</>))
import Unused.ResultsClassifier.Types (LanguageConfiguration, ParseConfigError(..))
import Unused.Util (safeReadFile)
loadConfig :: IO (Either String [LanguageConfiguration])
loadConfig = do
configFileName <- Paths.getDataFileName ("data" </> "config.yml")
loadConfig :: Either String [LanguageConfiguration]
loadConfig = Y.decodeEither defaultConfigFile
either
(const $ Left "default config not found")
Y.decodeEither
<$> safeReadFile configFileName
defaultConfigFile :: BS.ByteString
defaultConfigFile = $(FE.embedFile "data/config.yml")
loadAllConfigurations :: IO (Either [ParseConfigError] [LanguageConfiguration])
loadAllConfigurations = do
homeDir <- D.getHomeDirectory
defaultConfig <- addSourceToLeft "default config" <$> loadConfig
let defaultConfig = addSourceToLeft "default config" loadConfig
localConfig <- loadConfigFromFile ".unused.yml"
userConfig <- loadConfigFromFile $ homeDir </> ".unused.yml"

View File

@ -16,10 +16,10 @@ spec = parallel $
describe "calculateLikelihood" $ do
it "prefers language-specific checks first" $ do
let railsMatches = [ TermMatch "ApplicationController" "app/controllers/application_controller.rb" Nothing 1 ]
removalLikelihood' railsMatches `shouldReturn` Low
removalLikelihood' railsMatches `shouldBe` Low
let elixirMatches = [ TermMatch "AwesomeView" "web/views/awesome_view.ex" Nothing 1 ]
removalLikelihood' elixirMatches `shouldReturn` Low
removalLikelihood' elixirMatches `shouldBe` Low
it "weighs widely-used methods as low likelihood" $ do
let matches = [ TermMatch "full_name" "app/models/user.rb" Nothing 4
@ -28,19 +28,19 @@ spec = parallel $
, TermMatch "full_name" "spec/models/user_spec.rb" Nothing 10
]
removalLikelihood' matches `shouldReturn` Low
removalLikelihood' matches `shouldBe` Low
it "weighs only-occurs-once methods as high likelihood" $ do
let matches = [ TermMatch "obscure_method" "app/models/user.rb" Nothing 1 ]
removalLikelihood' matches `shouldReturn` High
removalLikelihood' matches `shouldBe` High
it "weighs methods that seem to only be tested and never used as high likelihood" $ do
let matches = [ TermMatch "obscure_method" "app/models/user.rb" Nothing 1
, TermMatch "obscure_method" "spec/models/user_spec.rb" Nothing 5
]
removalLikelihood' matches `shouldReturn` High
removalLikelihood' matches `shouldBe` High
it "weighs methods that seem to only be tested and used in one other area as medium likelihood" $ do
let matches = [ TermMatch "obscure_method" "app/models/user.rb" Nothing 1
@ -49,14 +49,15 @@ spec = parallel $
, TermMatch "obscure_method" "spec/controllers/user_controller_spec.rb" Nothing 5
]
removalLikelihood' matches `shouldReturn` Medium
removalLikelihood' matches `shouldBe` Medium
it "doesn't mis-categorize allowed terms from different languages" $ do
let matches = [ TermMatch "t" "web/models/foo.ex" Nothing 1 ]
removalLikelihood' matches `shouldReturn` High
removalLikelihood' matches `shouldBe` High
removalLikelihood' :: [TermMatch] -> IO RemovalLikelihood
removalLikelihood' ms = do
(Right config) <- loadConfig
return $ rLikelihood $ trRemoval $ calculateLikelihood config $ resultsFromMatches ms
removalLikelihood' :: [TermMatch] -> RemovalLikelihood
removalLikelihood' =
rLikelihood . trRemoval . calculateLikelihood config . resultsFromMatches
where
(Right config) = loadConfig

View File

@ -23,7 +23,7 @@ spec = parallel $
let r2Matches = [ TermMatch "other" "app/path/other.rb" Nothing 1 ]
let r2Results = TermResults "other" ["other"] r2Matches (Occurrences 0 0) (Occurrences 1 1) (Occurrences 1 1) (Removal High "occurs once") Nothing
(Right config) <- loadConfig
let (Right config) = loadConfig
let result = parseResults config $ SearchResults $ r1Matches ++ r2Matches
@ -50,7 +50,7 @@ spec = parallel $
]
(Right config) <- loadConfig
let (Right config) = loadConfig
let searchResults = r1Matches ++ r2Matches
let result = parseResults config $ SearchResults searchResults
@ -60,6 +60,6 @@ spec = parallel $
Map.fromList [ ("admin?|be_admin", results) ]
it "handles empty input" $ do
(Right config) <- loadConfig
let (Right config) = loadConfig
let result = parseResults config $ SearchResults []
result `shouldBe` Map.fromList []

View File

@ -19,114 +19,114 @@ spec = parallel $ do
let match = TermMatch "ApplicationController" "app/controllers/application_controller.rb" Nothing 1
let result = resultsFromMatches [match]
railsAutoLowLikelihood result `shouldReturn` True
railsAutoLowLikelihood result `shouldBe` True
it "allows helpers" $ do
let match = TermMatch "ApplicationHelper" "app/helpers/application_helper.rb" Nothing 1
let result = resultsFromMatches [match]
railsAutoLowLikelihood result `shouldReturn` True
railsAutoLowLikelihood result `shouldBe` True
it "allows migrations" $ do
let match = TermMatch "CreateUsers" "db/migrate/20160101120000_create_users.rb" Nothing 1
let result = resultsFromMatches [match]
railsAutoLowLikelihood result `shouldReturn` True
railsAutoLowLikelihood result `shouldBe` True
it "disallows service objects" $ do
let match = TermMatch "CreatePostWithNotifications" "app/services/create_post_with_notifications.rb" Nothing 1
let result = resultsFromMatches [match]
railsAutoLowLikelihood result `shouldReturn` False
railsAutoLowLikelihood result `shouldBe` False
it "disallows methods" $ do
let match = TermMatch "my_method" "app/services/create_post_with_notifications.rb" Nothing 1
let result = resultsFromMatches [match]
railsAutoLowLikelihood result `shouldReturn` False
railsAutoLowLikelihood result `shouldBe` False
it "disallows models that occur in migrations" $ do
let model = TermMatch "User" "app/models/user.rb" Nothing 1
let migration = TermMatch "User" "db/migrate/20160101120000_create_users.rb" Nothing 1
let result = resultsFromMatches [model, migration]
railsAutoLowLikelihood result `shouldReturn` False
railsAutoLowLikelihood result `shouldBe` False
it "allows matches intermixed with other results" $ do
let appToken = TermMatch "ApplicationHelper" "app/helpers/application_helper.rb" Nothing 1
let testToken = TermMatch "ApplicationHelper" "spec/helpers/application_helper_spec.rb" Nothing 10
let result = resultsFromMatches [appToken, testToken]
railsAutoLowLikelihood result `shouldReturn` True
railsAutoLowLikelihood result `shouldBe` True
describe "elixirAutoLowLikelihood" $ do
it "disallows controllers" $ do
let match = TermMatch "PageController" "web/controllers/page_controller.rb" Nothing 1
let result = resultsFromMatches [match]
elixirAutoLowLikelihood result `shouldReturn` False
elixirAutoLowLikelihood result `shouldBe` False
it "allows views" $ do
let match = TermMatch "PageView" "web/views/page_view.rb" Nothing 1
let result = resultsFromMatches [match]
elixirAutoLowLikelihood result `shouldReturn` True
elixirAutoLowLikelihood result `shouldBe` True
it "allows migrations" $ do
let match = TermMatch "CreateUsers" "priv/repo/migrations/20160101120000_create_users.exs" Nothing 1
let result = resultsFromMatches [match]
elixirAutoLowLikelihood result `shouldReturn` True
elixirAutoLowLikelihood result `shouldBe` True
it "allows tests" $ do
let match = TermMatch "UserTest" "test/models/user_test.exs" Nothing 1
let result = resultsFromMatches [match]
elixirAutoLowLikelihood result `shouldReturn` True
elixirAutoLowLikelihood result `shouldBe` True
it "allows Mixfile" $ do
let match = TermMatch "Mixfile" "mix.exs" Nothing 1
let result = resultsFromMatches [match]
elixirAutoLowLikelihood result `shouldReturn` True
elixirAutoLowLikelihood result `shouldBe` True
it "allows __using__" $ do
let match = TermMatch "__using__" "web/web.ex" Nothing 1
let result = resultsFromMatches [match]
elixirAutoLowLikelihood result `shouldReturn` True
elixirAutoLowLikelihood result `shouldBe` True
it "disallows service modules" $ do
let match = TermMatch "CreatePostWithNotifications" "web/services/create_post_with_notifications.ex" Nothing 1
let result = resultsFromMatches [match]
elixirAutoLowLikelihood result `shouldReturn` False
elixirAutoLowLikelihood result `shouldBe` False
it "disallows functions" $ do
let match = TermMatch "my_function" "web/services/create_post_with_notifications.ex" Nothing 1
let result = resultsFromMatches [match]
elixirAutoLowLikelihood result `shouldReturn` False
elixirAutoLowLikelihood result `shouldBe` False
it "allows matches intermixed with other results" $ do
let appToken = TermMatch "UserView" "web/views/user_view.ex" Nothing 1
let testToken = TermMatch "UserView" "test/views/user_view_test.exs" Nothing 10
let result = resultsFromMatches [appToken, testToken]
elixirAutoLowLikelihood result `shouldReturn` True
elixirAutoLowLikelihood result `shouldBe` True
describe "haskellAutoLowLikelihood" $ do
it "allows instance" $ do
let match = TermMatch "instance" "src/Lib/Types.hs" Nothing 1
let result = resultsFromMatches [match]
haskellAutoLowLikelihood result `shouldReturn` True
haskellAutoLowLikelihood result `shouldBe` True
it "allows items in the *.cabal file" $ do
let match = TermMatch "Lib.SomethingSpec" "lib.cabal" Nothing 1
let result = resultsFromMatches [match]
haskellAutoLowLikelihood result `shouldReturn` True
haskellAutoLowLikelihood result `shouldBe` True
describe "autoLowLikelihood" $
it "doesn't qualify as low when no matchers are present in a language config" $ do
@ -136,18 +136,17 @@ spec = parallel $ do
autoLowLikelihood languageConfig result `shouldBe` False
configByName :: String -> IO LanguageConfiguration
configByName s = do
(Right config) <- loadConfig
let (Just config') = find ((==) s . lcName) config
configByName :: String -> LanguageConfiguration
configByName s = config'
where
(Right config) = loadConfig
(Just config') = find ((==) s . lcName) config
return config'
railsAutoLowLikelihood :: TermResults -> Bool
railsAutoLowLikelihood = autoLowLikelihood (configByName "Rails")
railsAutoLowLikelihood :: TermResults -> IO Bool
railsAutoLowLikelihood r = (`autoLowLikelihood` r) <$> configByName "Rails"
elixirAutoLowLikelihood :: TermResults -> Bool
elixirAutoLowLikelihood = autoLowLikelihood (configByName "Phoenix")
elixirAutoLowLikelihood :: TermResults -> IO Bool
elixirAutoLowLikelihood r = (`autoLowLikelihood` r) <$> configByName "Phoenix"
haskellAutoLowLikelihood :: TermResults -> IO Bool
haskellAutoLowLikelihood r = (`autoLowLikelihood` r) <$> configByName "Haskell"
haskellAutoLowLikelihood :: TermResults -> Bool
haskellAutoLowLikelihood = autoLowLikelihood (configByName "Haskell")

View File

@ -12,7 +12,6 @@ category: CLI
build-type: Simple
-- extra-source-files:
cabal-version: >=1.10
data-files: data/config.yml
library
hs-source-dirs: src
@ -60,7 +59,6 @@ library
, Unused.CLI.ProgressIndicator
, Unused.CLI.ProgressIndicator.Internal
, Unused.CLI.ProgressIndicator.Types
other-modules: Paths_unused
build-depends: base >= 4.7 && < 5
, process
, containers
@ -81,6 +79,7 @@ library
, transformers
, megaparsec
, inflections
, file-embed
ghc-options: -Wall
default-language: Haskell2010
@ -114,7 +113,6 @@ test-suite unused-test
, Unused.UtilSpec
, Unused.Cache.FindArgsFromIgnoredPathsSpec
, Unused.AliasesSpec
, Paths_unused
ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall
default-language: Haskell2010