argon 0.4.1.0 → 0.4.2.0
raw patch · 13 files changed
+267/−166 lines, 13 filesdep +dirstreamdep +ghc-bootdep +system-filepathdep −pipes-filesdep ~Cabaldep ~aesondep ~ansi-terminal
Dependencies added: dirstream, ghc-boot, system-filepath
Dependencies removed: pipes-files
Dependency ranges changed: Cabal, aeson, ansi-terminal, base, bytestring, containers, directory, filepath, ghc, ghc-paths, ghc-syb-utils, hlint, hspec, lens-simple, pipes, pipes-bytestring, pipes-group, pipes-safe, syb
Files
- README.md +46/−2
- argon.cabal +40/−32
- src/Argon.hs +1/−2
- src/Argon/Cabal.hs +16/−28
- src/Argon/Parser.hs +10/−9
- src/Argon/Types.hs +2/−3
- src/Argon/Visitor.hs +29/−17
- src/Argon/Walker.hs +24/−9
- stack-7.8.yaml +0/−15
- stack.yaml +4/−13
- test/ArgonSpec.hs +59/−36
- test/data/test-old.cabal +18/−0
- test/data/test-other.cabal +18/−0
README.md view
@@ -42,8 +42,52 @@ #### GHC compatibility -Argon is compatible with GHC 7.8 and 7.10, it's tested against those versions-only.+Argon is compatible with GHC version 8.0.2 and above. In the+[releases](https://github.com/rubik/argon/releases) page you can find binaries+for older versions of `argon` which support GHC versions 7.8 and 7.10.++### About the complexity being measured++`argon` will compute the [cyclomatic+complexity](https://en.wikipedia.org/wiki/Cyclomatic_complexity) of Haskell+functions, which is the number of decisions in a block of code plus 1. For+instance the following function:++```haskell+func n = case n of+ 2 -> 3+ 4 -> 6+ _ -> 42+```++has a cyclomatic complexity of 3.++The boolean operators `&&` and `||` also affect the this number. For instance+the following function:++```haskell+g n = n < 68 && n `mod` 3 == 2 && n > 49+```+has a cyclomatic complexity of 3.++As a last example, the following function:++```haskell+func n = case n of+ 2 -> 3+ 4 -> 6+ _ -> if 0 < n+ then 7+ else 8+```++has a cyclomatic complexity of 5.++Cyclomatic complexity provides a very shallow metric of code complexity: a high+cyclomatic complexity number does not necessarily mean that the function is+complex, and conversely, a low number does not necessarily indicate that the+function is simple. However, this number it can be useful for highlighting+potential maintainability issues. ### Running
argon.cabal view
@@ -1,5 +1,5 @@ name: argon-version: 0.4.1.0+version: 0.4.2.0 synopsis: Measure your code's complexity homepage: http://github.com/rubik/argon bug-reports: http://github.com/rubik/argon/issues@@ -10,7 +10,7 @@ copyright: 2015 Michele Lacchia category: Development, Static Analysis build-type: Simple-cabal-version: >=1.18+cabal-version: 1.18 description: Argon performs static analysis on your code in order to compute cyclomatic complexity. It is a quantitative measure of the number of linearly@@ -21,7 +21,6 @@ JSON. extra-source-files: stack.yaml- stack-7.8.yaml README.md CHANGELOG.md USAGE.txt@@ -33,7 +32,7 @@ test/tree/*.txt test/tree/sub/*.hs test/tree/sub2/*.hs-tested-with: GHC >= 7.8 && < 8+tested-with: GHC >= 8.0.2 && < 9 library hs-source-dirs: src@@ -49,24 +48,31 @@ Argon.SYB.Utils Argon.Walker build-depends: base >=4.7 && <5- , ansi-terminal >=0.6- , aeson >=0.8- , bytestring >=0.10- , pipes >=4.1- , pipes-group >=1.0- , pipes-files >=0.1- , pipes-safe >=2.2- , pipes-bytestring >=2.1- , lens-simple >=0.1- , ghc >=7.8 && <8- , ghc-paths >=0.1- , ghc-syb-utils >=0.2- , syb >=0.4- , Cabal >=1.18- , containers >=0.5- , directory >=1.2+ , ansi-terminal+ , aeson+ , bytestring+ , pipes+ , pipes-group+ , pipes-safe+ , pipes-bytestring+ , lens-simple+ , ghc+ , ghc-boot+ , ghc-paths+ , ghc-syb-utils+ , syb+ , Cabal+ , containers+ , directory+ , system-filepath+ , dirstream+ , filepath default-language: Haskell2010 ghc-options: -Wall+ -Wcompat+ -Wincomplete-record-updates+ -Wincomplete-uni-patterns+ -Wredundant-constraints if impl(ghc < 7.8) buildable: False @@ -89,16 +95,18 @@ main-is: Spec.hs other-modules: ArgonSpec build-depends: base >=4.7 && <5- , argon -any- , ansi-terminal >=0.6- , ghc >=7.8 && <8- , aeson >=0.8- , hspec >=2.1- , QuickCheck -any- , filepath >=1.3- , pipes >=4.1- , pipes-safe >=2.2- ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N+ , argon+ , ansi-terminal+ , ghc+ , aeson+ , hspec+ , QuickCheck+ , filepath+ , pipes+ , pipes-safe+ ghc-options: -Wall+ -threaded -rtsopts -with-rtsopts=-N+ default-language: Haskell2010 if impl(ghc < 7.8) buildable: False@@ -107,8 +115,8 @@ type: exitcode-stdio-1.0 hs-source-dirs: test main-is: HLint.hs- build-depends: base ==4.*- , hlint ==1.*+ build-depends: base >=4.7 && <5+ , hlint default-language: Haskell2010 ghc-options: -Wall
src/Argon.hs view
@@ -23,7 +23,6 @@ , analyze , parseModule , parseExts- , flagsMap -- * Manipulating results , order , filterResults@@ -40,7 +39,7 @@ import Argon.Parser (LModule, analyze, parseModule) import Argon.Results (order, filterResults, filterNulls, exportStream)-import Argon.Cabal (flagsMap, parseExts)+import Argon.Cabal (parseExts) import Argon.Types import Argon.Loc import Argon.Walker (allFiles)
src/Argon/Cabal.hs view
@@ -1,46 +1,34 @@ {-# LANGUAGE CPP #-}-module Argon.Cabal (flagsMap, parseExts)+module Argon.Cabal (parseExts) where -import Data.Maybe (mapMaybe)-import Data.Map.Strict (Map)-import qualified Data.Map.Strict as M+import Data.List (nub) #if __GLASGOW_HASKELL__ < 710-import Control.Applicative ((<$>))-#else-import Control.Arrow ((&&&))+import Control.Applicative ((<$>)) #endif -import qualified DynFlags as GHC-import qualified Language.Haskell.Extension as Dist-import qualified Distribution.Verbosity as Dist import qualified Distribution.PackageDescription as Dist import qualified Distribution.PackageDescription.Parse as Dist+import qualified Distribution.Verbosity as Dist+import qualified Language.Haskell.Extension as Dist --- | A 'Map' from extensions names to extensions flags-flagsMap :: Map String GHC.ExtensionFlag-flagsMap = M.fromList $ map specToPair GHC.xFlags- -- | Parse the given Cabal file generate a list of GHC extension flags. The -- extension names are read from the default-extensions field in the library -- section.-parseExts :: FilePath -> IO [GHC.ExtensionFlag]+parseExts :: FilePath -> IO [String]+#if __GLASGOW_HASKELL__ < 802 parseExts path = extract <$> Dist.readPackageDescription Dist.silent path+#else+parseExts path = extract <$> Dist.readGenericPackageDescription Dist.silent path+#endif where extract pkg = maybe [] extFromBI $- (Dist.libBuildInfo . Dist.condTreeData) <$> Dist.condLibrary pkg+ Dist.libBuildInfo . Dist.condTreeData <$> Dist.condLibrary pkg -extFromBI :: Dist.BuildInfo -> [GHC.ExtensionFlag]-extFromBI = mapMaybe (get . toString) . Dist.defaultExtensions- where get = flip M.lookup flagsMap- toString (Dist.UnknownExtension ext) = ext+extFromBI :: Dist.BuildInfo -> [String]+extFromBI binfo = map toString . nub $ allExts+ where toString (Dist.UnknownExtension ext) = ext toString (Dist.EnableExtension ext) = show ext toString (Dist.DisableExtension ext) = show ext--#if __GLASGOW_HASKELL__ < 710-specToPair :: (String, GHC.ExtensionFlag, a) -> (String, GHC.ExtensionFlag)-specToPair (a, b, _) = (a, b)-#else-specToPair :: GHC.FlagSpec GHC.ExtensionFlag -> (String, GHC.ExtensionFlag)-specToPair = GHC.flagSpecName &&& GHC.flagSpecFlag-#endif+ allExts = concatMap ($ binfo)+ [Dist.defaultExtensions, Dist.otherExtensions, Dist.oldExtensions]
src/Argon/Parser.hs view
@@ -2,7 +2,6 @@ module Argon.Parser (LModule, analyze, parseModule) where -import Data.List (foldl') import Control.Monad (void) import qualified Control.Exception as E @@ -11,6 +10,7 @@ import qualified Lexer as GHC import qualified Parser as GHC import qualified DynFlags as GHC+import qualified GHC.LanguageExtensions as GHC import qualified HeaderInfo as GHC import qualified MonadUtils as GHC import qualified Outputable as GHC@@ -61,7 +61,7 @@ parseModuleWithCpp conf cppOptions file = GHC.runGhc (Just libdir) $ do dflags <- initDynFlags conf file- let useCpp = GHC.xopt GHC.Opt_Cpp dflags+ let useCpp = GHC.xopt GHC.Cpp dflags (fileContents, dflags1) <- if useCpp then getPreprocessedSrcDirect cppOptions file@@ -86,15 +86,16 @@ initDynFlags :: GHC.GhcMonad m => Config -> FilePath -> m GHC.DynFlags initDynFlags conf file = do dflags0 <- GHC.getSessionDynFlags- src_opts <- GHC.liftIO $ GHC.getOptionsFromFile dflags0 file- (dflags1, _, _) <- GHC.parseDynamicFilePragma dflags0 src_opts- let cabalized = foldl' GHC.xopt_set dflags1 $ exts conf- let dflags2 = cabalized { GHC.log_action = customLogAction }- void $ GHC.setSessionDynFlags dflags2- return dflags2+ (dflags1,_,_) <- GHC.parseDynamicFlagsCmdLine dflags0+ [GHC.L GHC.noSrcSpan ("-X" ++ e) | e <- exts conf]+ src_opts <- GHC.liftIO $ GHC.getOptionsFromFile dflags1 file+ (dflags2, _, _) <- GHC.parseDynamicFilePragma dflags1 src_opts+ let dflags3 = dflags2 { GHC.log_action = customLogAction }+ void $ GHC.setSessionDynFlags dflags3+ return dflags3 customLogAction :: GHC.LogAction-customLogAction dflags severity srcSpan _ m =+customLogAction dflags _ severity srcSpan _ m = case severity of GHC.SevFatal -> throwError GHC.SevError -> throwError
src/Argon/Types.hs view
@@ -15,7 +15,6 @@ import Data.Typeable import Control.Exception (Exception) -import qualified DynFlags as GHC import Argon.Loc @@ -38,8 +37,8 @@ data Config = Config { -- | Minimum complexity a block has to have to be shown in results. minCC :: Int- -- | Path to the main Cabal file- , exts :: [GHC.ExtensionFlag]+ -- | Extension to activate+ , exts :: [String] -- | Header files to be automatically included before preprocessing , headers :: [FilePath] -- | Additional include directories for the C preprocessor
src/Argon/Visitor.hs view
@@ -1,16 +1,17 @@+{-# LANGUAGE CPP #-} module Argon.Visitor (funcsCC) where -import Data.Generics (Data, Typeable, mkQ)-import Argon.SYB.Utils (Stage(..), everythingStaged)-import Control.Arrow ((&&&))+import Argon.SYB.Utils (Stage (..), everythingStaged)+import Control.Arrow ((&&&))+import Data.Generics (Data, mkQ) import qualified GHC-import qualified RdrName as GHC-import qualified OccName as GHC+import qualified OccName as GHC+import qualified RdrName as GHC -import Argon.Loc-import Argon.Types (ComplexityBlock(..))+import Argon.Loc+import Argon.Types (ComplexityBlock (..)) type Exp = GHC.HsExpr GHC.RdrName type Function = GHC.HsBindLR GHC.RdrName GHC.RdrName@@ -18,16 +19,16 @@ -- | Compute cyclomatic complexity of every function binding in the given AST.-funcsCC :: (Data from, Typeable from) => from -> [ComplexityBlock]+funcsCC :: (Data from) => from -> [ComplexityBlock] funcsCC = map funCC . getBinds funCC :: Function -> ComplexityBlock funCC f = CC (getLocation $ GHC.fun_id f, getFuncName f, complexity f) -getBinds :: (Data from, Typeable from) => from -> [Function]+getBinds :: (Data from) => from -> [Function] getBinds = everythingStaged Parser (++) [] $ mkQ [] visit where visit fun@GHC.FunBind {} = [fun]- visit _ = []+ visit _ = [] getLocation :: GHC.Located a -> Loc getLocation = srcSpanToLoc . GHC.getLoc@@ -39,11 +40,17 @@ complexity f = let matches = getMatches f query = everythingStaged Parser (+) 0 $ 0 `mkQ` visit visit = uncurry (+) . (visitExp &&& visitOp)- in length matches + sumWith query matches+ in length matches + sumWith getGRHSsFromMatch matches + sumWith query matches getMatches :: Function -> [GHC.LMatch GHC.RdrName MatchBody]-getMatches = GHC.mg_alts . GHC.fun_matches+getMatches = GHC.unLoc . GHC.mg_alts . GHC.fun_matches +getGRHSsFromMatch :: GHC.LMatch GHC.RdrName MatchBody -> Int+getGRHSsFromMatch match = length (getGRHSs' match) - 1+ where+ getGRHSs' :: GHC.LMatch GHC.RdrName MatchBody -> [GHC.LGRHS GHC.RdrName MatchBody]+ getGRHSs' = GHC.grhssGRHSs . GHC.m_grhss . GHC.unLoc+ getName :: GHC.RdrName -> String getName = GHC.occNameString . GHC.rdrNameOcc @@ -51,15 +58,20 @@ sumWith f = sum . map f visitExp :: Exp -> Int-visitExp GHC.HsIf {} = 1+visitExp GHC.HsIf {} = 1 visitExp (GHC.HsMultiIf _ alts) = length alts - 1-visitExp (GHC.HsLamCase _ alts) = length (GHC.mg_alts alts) - 1-visitExp (GHC.HsCase _ alts) = length (GHC.mg_alts alts) - 1-visitExp _ = 0+#if __GLASGOW_HASKELL__ < 802+visitExp (GHC.HsCase _ alts) = length (GHC.unLoc . GHC.mg_alts $ alts) - 1+visitExp (GHC.HsLamCase _ alts) = length (GHC.unLoc . GHC.mg_alts $ alts) - 1+#else+visitExp (GHC.HsLamCase mg) = length (GHC.unLoc . GHC.mg_alts $ mg) - 1+visitExp (GHC.HsCase _ mg) = length (GHC.unLoc . GHC.mg_alts $ mg) - 1+#endif+visitExp _ = 0 visitOp :: Exp -> Int visitOp (GHC.OpApp _ (GHC.L _ (GHC.HsVar op)) _ _) =- case getName op of+ case getName (GHC.unLoc op) of "||" -> 1 "&&" -> 1 _ -> 0
src/Argon/Walker.hs view
@@ -1,14 +1,17 @@+{-# LANGUAGE OverloadedStrings #-} module Argon.Walker (allFiles) where -import Pipes-import Pipes.Files-import Pipes.Safe-import qualified Pipes.Prelude as P-import Data.Monoid ((<>))-import Data.List (isSuffixOf)-import System.Directory (doesFileExist)-+import Data.DirStream (childOf)+import Data.List (isSuffixOf)+import Filesystem.Path.CurrentOS (decodeString, encodeString)+import Pipes (ListT, MonadIO, Producer, each,+ every, liftIO, (>->))+import qualified Pipes.Prelude as P+import Pipes.Safe+import System.Directory (doesDirectoryExist, doesFileExist,+ pathIsSymbolicLink)+import System.FilePath (takeExtension) -- | Starting from a path, generate a sequence of paths corresponding -- to Haskell files. The filesystem is traversed depth-first.@@ -16,4 +19,16 @@ allFiles path = do isFile <- liftIO $ doesFileExist path if isFile then each [path] >-> P.filter (".hs" `isSuffixOf`)- else find path (glob "*.hs" <> regular)+ else every $ hsFilesIn path++-- | List the regular files in a directory.+hsFilesIn :: MonadSafe m => FilePath -> ListT m FilePath+hsFilesIn path = do+ child <- encodeString <$> childOf (decodeString path)+ isDir <- liftIO $ doesDirectoryExist child+ isSymLink <- liftIO $ pathIsSymbolicLink child+ if isDir && not isSymLink+ then hsFilesIn child+ else if not isSymLink && takeExtension child == ".hs"+ then return child+ else mempty
− stack-7.8.yaml
@@ -1,15 +0,0 @@-flags: {}-extra-package-dbs: []-packages:-- '.'-extra-deps:-- docopt-0.7.0.4-- syb-0.4.4-- ghc-7.8.4-- lens-simple-0.1.0.8-- lens-family-1.2.0-- pipes-files-0.1.1-- hierarchy-0.3.1-- posix-paths-0.2.1.0-- free-4.12.1-resolver: lts-2.22
stack.yaml view
@@ -1,13 +1,4 @@-flags: {}-extra-package-dbs: []-packages:-- '.'-extra-deps:-- docopt-0.7.0.4-- hierarchy-0.3.1-- pipes-files-0.1.1-- posix-paths-0.2.1.0-- aeson-0.11.0.0-- fail-4.9.0.0-- semigroups-0.16.2.2-resolver: lts-5.2+resolver: lts-11.6++extra-deps: [dirstream-1.0.3]+
test/ArgonSpec.hs view
@@ -1,28 +1,33 @@ {-# OPTIONS_GHC -fno-warn-orphans #-}-{-# LANGUAGE CPP #-}+{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} module ArgonSpec (spec) where -import Data.List (sort, isPrefixOf)-import Data.Aeson (encode)-import Text.Printf (printf)+import Data.Aeson (encode)+import Data.List (sort)+import GHC.Stack (HasCallStack)+import Text.Printf (printf) #if __GLASGOW_HASKELL__ < 710-import Control.Applicative ((<$>), (<*>))+import Control.Applicative ((<$>), (<*>)) #endif-import Test.Hspec-import Test.QuickCheck-import System.FilePath ((</>))-import System.IO.Unsafe (unsafePerformIO)-import System.Console.ANSI-import qualified SrcLoc as GHC-import qualified FastString as GHC-import Pipes---import Pipes.Safe (SafeT, runSafeT)-import qualified Pipes.Prelude as P+import qualified FastString as GHC+import Pipes (Producer, (>->), each)+import qualified SrcLoc as GHC+import System.Console.ANSI (Color (..), ConsoleIntensity(BoldIntensity), setSGRCode,+ SGR(SetColor, SetConsoleIntensity),+ ConsoleLayer(Foreground), ColorIntensity(Dull))+import System.FilePath ((</>))+import System.IO.Unsafe (unsafePerformIO)+import Test.Hspec (describe, it, Expectation, shouldBe,+ shouldContain, Spec, expectationFailure,+ shouldReturn)+import Test.QuickCheck (Arbitrary, arbitrary, shrink, property, elements)+import qualified Pipes.Prelude as P+import Data.Foldable (traverse_) -import Argon+import Argon instance Arbitrary ComplexityBlock where arbitrary = (\a b c -> CC (a, b, c)) <$> arbitrary@@ -31,7 +36,7 @@ shrink (CC t) = map CC $ shrink t instance Arbitrary OutputMode where-+ arbitrary = elements [BareText, Colored, JSON] ones :: Loc ones = (1, 1)@@ -43,17 +48,20 @@ realSpan a b = GHC.mkSrcSpan (mkLoc a b) $ mkLoc (-a) (b + 24) where mkLoc = GHC.mkSrcLoc (GHC.mkFastString "real loc") -errStartsWith :: String -> (FilePath, AnalysisResult) -> Bool-errStartsWith _ (_, Right _) = False-errStartsWith p (_, Left msg) = p `isPrefixOf` msg+shouldContainErrors :: HasCallStack => FilePath -> [String] -> Expectation+shouldContainErrors f errs = do+ r <- analyze defaultConfig (path f)+ case r of+ (_, Right _) -> expectationFailure $ "Test did not fail" ++ show r+ (_, Left msg) -> traverse_ (msg `shouldContain`) errs path :: String -> FilePath path f = "test" </> "data" </> f -shouldAnalyze :: String -> AnalysisResult -> Expectation+shouldAnalyze :: HasCallStack => String -> AnalysisResult -> Expectation shouldAnalyze f = shouldAnalyzeC (f, defaultConfig) -shouldAnalyzeC :: (String, Config) -> AnalysisResult -> Expectation+shouldAnalyzeC :: HasCallStack => (String, Config) -> AnalysisResult -> Expectation shouldAnalyzeC (f, config) r = analyze config p `shouldReturn` (p, r) where p = path f @@ -138,26 +146,27 @@ "arrows.hs" `shouldAnalyze` Right [CC (lo 7, "getAnchor", 1)] describe "errors" $ do it "catches syntax errors" $- "syntaxerror.hs" `shouldAnalyze`- Left ("2:1 parse error (possibly incorrect indentation" ++- " or mismatched brackets)")+ "syntaxerror.hs" `shouldContainErrors`+ ["parse error (possibly incorrect indentation or mismatched brackets)"] it "catches syntax errors (missing CPP)" $ "missingcpp.hs" `shouldAnalyze`+#if __GLASGOW_HASKELL__ < 800 Left "1:2 lexical error at character 'i'"+#else+ Left "1:1 parse error on input \8216#\8217"+#endif+#if __GLASGOW_HASKELL__ < 800+-- The analysis of "missingmacros.hs" will succeed in newest GHC versions. it "catches syntax errors (missing cabal macros)" $- unsafePerformIO (analyze defaultConfig (path "missingmacros.hs"))- `shouldSatisfy`- errStartsWith ("2:0 error: missing binary operator " ++- "before token ")+ "missingmacros.hs" `shouldContainErrors`+ ["error: missing binary operator before token "]+#endif it "catches syntax errors (missing include dir)" $- unsafePerformIO (analyze defaultConfig (path "missingincluded.hs"))- `shouldSatisfy`- errStartsWith ("2:0 fatal error: necessaryInclude.h: "- ++ "No such file or directory")+ "missingincluded.hs" `shouldContainErrors`+ ["fatal error", "necessaryInclude.h"] it "catches CPP parsing errors" $- unsafePerformIO (analyze defaultConfig (path "cpp-error.hs"))- `shouldSatisfy`- errStartsWith "2:0 error: unterminated #else"+ "cpp-error.hs" `shouldContainErrors`+ ["error: unterminated"] describe "config" $ do it "reads default extensions from Cabal file" $ ("missingcpp.hs", unsafePerformIO@@ -165,10 +174,24 @@ return $ defaultConfig { exts = loadedExts })) `shouldAnalyzeC` Right [CC (lo 4, "f", 1)]+ it "reads other extensions from Cabal file" $+ ("missingcpp.hs", unsafePerformIO+ (do loadedExts <- parseExts $ path "test-other.cabal"+ return $ defaultConfig { exts = loadedExts }))+ `shouldAnalyzeC`+ Right [CC (lo 4, "f", 1)]+ it "reads old extensions from Cabal file" $+ ("missingcpp.hs", unsafePerformIO+ (do loadedExts <- parseExts $ path "test-old.cabal"+ return $ defaultConfig { exts = loadedExts }))+ `shouldAnalyzeC`+ Right [CC (lo 4, "f", 1)]+#if __GLASGOW_HASKELL__ < 800 it "includes Cabal macros for preprocessing" $ ( "missingmacros.hs" , defaultConfig { headers = [path "cabal_macros.h"] } ) `shouldAnalyzeC` Right [CC (lo 3, "f", 2)]+#endif it "includes directory from include-dir for preprocessing" $ ( "missingincluded.hs" , defaultConfig { includeDirs = [path "include"] }
+ test/data/test-old.cabal view
@@ -0,0 +1,18 @@+name: ftw+version: 0.0+author: Michele Lacchia+build-type: Simple+cabal-version: >=1.18++library+ hs-source-dirs: .+ extensions: CPP+ build-depends: base >=4.7 && <5+ default-language: Haskell2010+ ghc-options: -Wall+ if impl(ghc < 7.8)+ buildable: False++source-repository head+ type: git+ location: https://github.com/rubik/argon
+ test/data/test-other.cabal view
@@ -0,0 +1,18 @@+name: ftw+version: 0.0+author: Michele Lacchia+build-type: Simple+cabal-version: >=1.18++library+ hs-source-dirs: .+ other-extensions: CPP+ build-depends: base >=4.7 && <5+ default-language: Haskell2010+ ghc-options: -Wall+ if impl(ghc < 7.8)+ buildable: False++source-repository head+ type: git+ location: https://github.com/rubik/argon