From fde9f69a642597e633d63c8379b4b6412a9073c6 Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Thu, 18 Aug 2016 17:59:12 -0400 Subject: [PATCH] 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. --- src/Unused/ResultsClassifier/Config.hs | 19 ++++---- test/Unused/LikelihoodCalculatorSpec.hs | 23 +++++----- test/Unused/ParserSpec.hs | 6 +-- test/Unused/ResponseFilterSpec.hs | 59 ++++++++++++------------- unused.cabal | 4 +- 5 files changed, 55 insertions(+), 56 deletions(-) diff --git a/src/Unused/ResultsClassifier/Config.hs b/src/Unused/ResultsClassifier/Config.hs index 82d55c9..6a7bb2e 100644 --- a/src/Unused/ResultsClassifier/Config.hs +++ b/src/Unused/ResultsClassifier/Config.hs @@ -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" diff --git a/test/Unused/LikelihoodCalculatorSpec.hs b/test/Unused/LikelihoodCalculatorSpec.hs index 521bb40..4934586 100644 --- a/test/Unused/LikelihoodCalculatorSpec.hs +++ b/test/Unused/LikelihoodCalculatorSpec.hs @@ -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 diff --git a/test/Unused/ParserSpec.hs b/test/Unused/ParserSpec.hs index e462b3e..3795612 100644 --- a/test/Unused/ParserSpec.hs +++ b/test/Unused/ParserSpec.hs @@ -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 [] diff --git a/test/Unused/ResponseFilterSpec.hs b/test/Unused/ResponseFilterSpec.hs index 8501f0c..0aeb2be 100644 --- a/test/Unused/ResponseFilterSpec.hs +++ b/test/Unused/ResponseFilterSpec.hs @@ -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") diff --git a/unused.cabal b/unused.cabal index 90385cd..0793fff 100644 --- a/unused.cabal +++ b/unused.cabal @@ -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