packages feed

cartel 0.10.0.2 → 0.12.0.0

raw patch · 21 files changed

+2787/−1685 lines, 21 filesdep +QuickCheckdep +multiargdep +quickpulldep ~timenew-component:exe:cartel-visual-testPVP ok

version bump matches the API change (PVP)

Dependencies added: QuickCheck, multiarg, quickpull, random, transformers

Dependency ranges changed: time

API changes (from Hackage documentation)

- Cartel.Ast: Constraint :: Ordering -> Version -> Constraint
- Cartel.Ast: Flag :: String -> String -> Bool -> Bool -> Flag
- Cartel.Ast: LibExposed :: Bool -> LibraryField
- Cartel.Ast: LibExposedModules :: [String] -> LibraryField
- Cartel.Ast: Library :: [LibraryField] -> Library
- Cartel.Ast: TestType :: TestSuiteType -> TestSuiteField
- Cartel.Ast: Version :: [Int] -> Version
- Cartel.Ast: bmFields :: Benchmark -> [BenchmarkField]
- Cartel.Ast: bmMainIs :: Benchmark -> String
- Cartel.Ast: bmName :: Benchmark -> String
- Cartel.Ast: cBenchmarks :: Cabal -> [Benchmark]
- Cartel.Ast: cExecutables :: Cabal -> [Executable]
- Cartel.Ast: cFlags :: Cabal -> [Flag]
- Cartel.Ast: cLibrary :: Cabal -> Maybe Library
- Cartel.Ast: cProperties :: Cabal -> Properties
- Cartel.Ast: cRepositories :: Cabal -> [Repository]
- Cartel.Ast: cTestSuites :: Cabal -> [TestSuite]
- Cartel.Ast: csComparison :: Constraint -> Ordering
- Cartel.Ast: csVersion :: Constraint -> Version
- Cartel.Ast: data CondTree
- Cartel.Ast: data Flag
- Cartel.Ast: data Language
- Cartel.Ast: flDefault :: Flag -> Bool
- Cartel.Ast: flDescription :: Flag -> String
- Cartel.Ast: flManual :: Flag -> Bool
- Cartel.Ast: flName :: Flag -> String
- Cartel.Ast: ifElse :: CondBlock a -> [a]
- Cartel.Ast: instance Eq CondTree
- Cartel.Ast: instance Eq Flag
- Cartel.Ast: instance Eq Language
- Cartel.Ast: instance Eq Library
- Cartel.Ast: instance Eq Version
- Cartel.Ast: instance Ord CondTree
- Cartel.Ast: instance Ord Flag
- Cartel.Ast: instance Ord Language
- Cartel.Ast: instance Ord Library
- Cartel.Ast: instance Ord Version
- Cartel.Ast: instance Show CondTree
- Cartel.Ast: instance Show Flag
- Cartel.Ast: instance Show Language
- Cartel.Ast: instance Show Library
- Cartel.Ast: instance Show Version
- Cartel.Ast: libFields :: Library -> [LibraryField]
- Cartel.Ast: newtype Library
- Cartel.Ast: newtype Version
- Cartel.Ast: packConstraints :: Package -> Maybe ConstrTree
- Cartel.Ast: packName :: Package -> String
- Cartel.Ast: prAuthor :: Properties -> String
- Cartel.Ast: prBugReports :: Properties -> String
- Cartel.Ast: prBuildType :: Properties -> BuildType
- Cartel.Ast: prCabalVersion :: Properties -> (Int, Int)
- Cartel.Ast: prCategory :: Properties -> String
- Cartel.Ast: prCopyright :: Properties -> String
- Cartel.Ast: prDataDir :: Properties -> String
- Cartel.Ast: prDataFiles :: Properties -> [String]
- Cartel.Ast: prDescription :: Properties -> [String]
- Cartel.Ast: prExtraDocFiles :: Properties -> [String]
- Cartel.Ast: prExtraSourceFiles :: Properties -> [String]
- Cartel.Ast: prExtraTmpFiles :: Properties -> [String]
- Cartel.Ast: prHomepage :: Properties -> String
- Cartel.Ast: prLicense :: Properties -> License
- Cartel.Ast: prLicenseFile :: Properties -> String
- Cartel.Ast: prLicenseFiles :: Properties -> [String]
- Cartel.Ast: prMaintainer :: Properties -> String
- Cartel.Ast: prName :: Properties -> String
- Cartel.Ast: prPackageUrl :: Properties -> String
- Cartel.Ast: prStability :: Properties -> String
- Cartel.Ast: prSynopsis :: Properties -> String
- Cartel.Ast: prTestedWith :: Properties -> [(Compiler, ConstrTree)]
- Cartel.Ast: prVersion :: Properties -> Version
- Cartel.Ast: tsFields :: TestSuite -> [TestSuiteField]
- Cartel.Ast: tsName :: TestSuite -> String
- Cartel.Ast: unVersion :: Version -> [Int]
- Cartel.Empty: class Empty a
- Cartel.Empty: empty :: Empty a => a
- Cartel.Empty: instance Empty Cabal
- Cartel.Empty: instance Empty Flag
- Cartel.Empty: instance Empty Properties
- Cartel.Empty: instance Empty Repository
- Cartel.Render: benchmark :: Benchmark -> String
- Cartel.Render: buildType :: BuildType -> String
- Cartel.Render: cabal :: Cabal -> String
- Cartel.Render: cabalVersion :: (Int, Int) -> String
- Cartel.Render: class Field a
- Cartel.Render: comparison :: Ordering -> String
- Cartel.Render: compiler :: Compiler -> String
- Cartel.Render: condBlock :: Field a => Int -> CondBlock a -> String
- Cartel.Render: condTree :: CondTree -> String
- Cartel.Render: condition :: Condition -> String
- Cartel.Render: constrTree :: ConstrTree -> String
- Cartel.Render: constraint :: Constraint -> String
- Cartel.Render: description :: [String] -> String
- Cartel.Render: executable :: Executable -> String
- Cartel.Render: field :: Field a => Int -> a -> String
- Cartel.Render: flag :: Flag -> String
- Cartel.Render: instance Field BenchmarkField
- Cartel.Render: instance Field BuildInfoField
- Cartel.Render: instance Field ExecutableField
- Cartel.Render: instance Field LibraryField
- Cartel.Render: instance Field TestSuiteField
- Cartel.Render: language :: Language -> String
- Cartel.Render: library :: Library -> String
- Cartel.Render: license :: License -> String
- Cartel.Render: logical :: Logical -> String
- Cartel.Render: package :: Package -> String
- Cartel.Render: properties :: Properties -> String
- Cartel.Render: repoKind :: RepoKind -> String
- Cartel.Render: repository :: Repository -> String
- Cartel.Render: testSuite :: TestSuite -> String
- Cartel.Render: testSuiteType :: TestSuiteType -> String
- Cartel.Render: testedWith :: [(Compiler, ConstrTree)] -> String
- Cartel.Render: vcs :: Vcs -> String
- Cartel.Render: version :: Version -> String
- Cartel.Tools: (&&&) :: LogicTree a => a -> a -> a
- Cartel.Tools: (|||) :: LogicTree a => a -> a -> a
- Cartel.Tools: apiVersion :: String -> [Int] -> Package
- Cartel.Tools: arch :: String -> CondTree
- Cartel.Tools: buildDepends :: Field a => [Package] -> a
- Cartel.Tools: buildInfo :: Field a => BuildInfoField -> a
- Cartel.Tools: buildTools :: Field a => [Package] -> a
- Cartel.Tools: buildable :: Field a => Bool -> a
- Cartel.Tools: cSources :: Field a => [String] -> a
- Cartel.Tools: ccOptions :: Field a => [String] -> a
- Cartel.Tools: cif :: Field a => CondTree -> [a] -> [a] -> a
- Cartel.Tools: class Field a
- Cartel.Tools: class LogicTree a
- Cartel.Tools: closedOpen :: String -> [Int] -> [Int] -> Package
- Cartel.Tools: conditional :: Field a => CondBlock a -> a
- Cartel.Tools: cppOptions :: Field a => [String] -> a
- Cartel.Tools: defaultLanguage :: Field a => Language -> a
- Cartel.Tools: eq :: [Int] -> ConstrTree
- Cartel.Tools: exactly :: String -> [Int] -> Package
- Cartel.Tools: extensions :: Field a => [String] -> a
- Cartel.Tools: extraLibDirs :: Field a => [String] -> a
- Cartel.Tools: extraLibraries :: Field a => [String] -> a
- Cartel.Tools: false :: CondTree
- Cartel.Tools: fileExtensions :: [String]
- Cartel.Tools: flag :: String -> CondTree
- Cartel.Tools: frameworks :: Field a => [String] -> a
- Cartel.Tools: ghcOptions :: Field a => [String] -> a
- Cartel.Tools: ghcProfOptions :: Field a => [String] -> a
- Cartel.Tools: ghcSharedOptions :: Field a => [String] -> a
- Cartel.Tools: gt :: [Int] -> ConstrTree
- Cartel.Tools: gtEq :: [Int] -> ConstrTree
- Cartel.Tools: hsSourceDirs :: Field a => [String] -> a
- Cartel.Tools: hugsOptions :: Field a => [String] -> a
- Cartel.Tools: impl :: Compiler -> Maybe ConstrTree -> CondTree
- Cartel.Tools: includeDirs :: Field a => [String] -> a
- Cartel.Tools: includes :: Field a => [String] -> a
- Cartel.Tools: installIncludes :: Field a => [String] -> a
- Cartel.Tools: instance Field BenchmarkField
- Cartel.Tools: instance Field ExecutableField
- Cartel.Tools: instance Field LibraryField
- Cartel.Tools: instance Field TestSuiteField
- Cartel.Tools: instance LogicTree CondTree
- Cartel.Tools: instance LogicTree ConstrTree
- Cartel.Tools: ldOptions :: Field a => [String] -> a
- Cartel.Tools: lt :: [Int] -> ConstrTree
- Cartel.Tools: ltEq :: [Int] -> ConstrTree
- Cartel.Tools: modules :: FilePath -> IO [String]
- Cartel.Tools: modulesWithExtensions :: [String] -> FilePath -> IO [String]
- Cartel.Tools: nextBreaking :: String -> [Int] -> Package
- Cartel.Tools: nextMajor :: String -> [Int] -> Package
- Cartel.Tools: nhc98Options :: Field a => [String] -> a
- Cartel.Tools: otherModules :: Field a => [String] -> a
- Cartel.Tools: pkgConfigDepends :: Field a => [Package] -> a
- Cartel.Tools: render :: String -> Cabal -> IO ()
- Cartel.Tools: renderString :: String -> ZonedTime -> Version -> Cabal -> String
- Cartel.Tools: system :: String -> CondTree
- Cartel.Tools: true :: CondTree
+ Cartel: (&&&) :: LogicTree a => a -> a -> a
+ Cartel: (|||) :: LogicTree a => a -> a -> a
+ Cartel: DuplicateFlag :: FlagName -> Error
+ Cartel: EmptyFlagName :: Error
+ Cartel: Failed :: String -> Error
+ Cartel: FlagOpts :: String -> Bool -> Bool -> FlagOpts
+ Cartel: Properties :: String -> Version -> Maybe (Word, Word) -> Maybe BuildType -> Maybe License -> String -> [NonEmptyString] -> String -> String -> String -> String -> String -> String -> String -> String -> [String] -> String -> [(Compiler, Constraint)] -> [NonEmptyString] -> String -> [NonEmptyString] -> [NonEmptyString] -> [NonEmptyString] -> Properties
+ Cartel: Repository :: Maybe Vcs -> Maybe RepoKind -> String -> NonEmptyString -> String -> String -> Repository
+ Cartel: agpl :: License
+ Cartel: allRightsReserved :: License
+ Cartel: anyVersion :: Constraint
+ Cartel: apache :: License
+ Cartel: apiVersion :: NonEmptyString -> Version -> Package
+ Cartel: arch :: NonEmptyString -> Condition
+ Cartel: archVcs :: Vcs
+ Cartel: author :: Properties -> String
+ Cartel: bazaar :: Vcs
+ Cartel: benchmark :: NonEmptyString -> [BenchmarkField] -> Section
+ Cartel: betsyToCabalStringIO :: (MonadIO m, Functor m) => Betsy m Cabal -> m (Either Error String)
+ Cartel: blank :: Blank a => a
+ Cartel: bsd2 :: License
+ Cartel: bsd3 :: License
+ Cartel: bsd4 :: License
+ Cartel: bugReports :: Properties -> String
+ Cartel: buildDepends :: HasBuildInfo a => [Package] -> a
+ Cartel: buildTools :: HasBuildInfo a => [Package] -> a
+ Cartel: buildType :: Properties -> Maybe BuildType
+ Cartel: buildable :: HasBuildInfo a => Bool -> a
+ Cartel: cSources :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel: cabal :: Properties -> [LibraryField] -> [Section] -> Cabal
+ Cartel: cabalVersion :: Properties -> Maybe (Word, Word)
+ Cartel: category :: Properties -> String
+ Cartel: ccOptions :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel: class Blank a
+ Cartel: class BuildsExe a
+ Cartel: class BuildsExitcode a
+ Cartel: class HasBuildInfo a
+ Cartel: class LogicTree a
+ Cartel: class Renderable a
+ Cartel: class RenderableIndented a
+ Cartel: closedOpen :: NonEmptyString -> Version -> Version -> Package
+ Cartel: condBlock :: HasBuildInfo a => Condition -> (a, [a]) -> [a] -> a
+ Cartel: configure :: BuildType
+ Cartel: copyright :: Properties -> String
+ Cartel: cppOptions :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel: currentFlags :: Applicative f => Betsy f [(FlagName, FlagOpts)]
+ Cartel: custom :: BuildType
+ Cartel: cvs :: NonEmptyString -> Vcs
+ Cartel: darcs :: Vcs
+ Cartel: data BenchmarkField
+ Cartel: data Betsy m a
+ Cartel: data BuildInfoField
+ Cartel: data BuildType
+ Cartel: data Cabal
+ Cartel: data Compiler
+ Cartel: data Condition
+ Cartel: data Constraint
+ Cartel: data Error
+ Cartel: data ExecutableField
+ Cartel: data FlagName
+ Cartel: data FlagOpts
+ Cartel: data LibraryField
+ Cartel: data License
+ Cartel: data Package
+ Cartel: data Properties
+ Cartel: data RepoKind
+ Cartel: data Repository
+ Cartel: data Section
+ Cartel: data TestSuiteField
+ Cartel: data Vcs
+ Cartel: data Word :: *
+ Cartel: dataDir :: Properties -> String
+ Cartel: dataFiles :: Properties -> [NonEmptyString]
+ Cartel: defaultMain :: Betsy IO (Properties, [LibraryField], [Section]) -> IO ()
+ Cartel: description :: Properties -> [String]
+ Cartel: detailed :: TestSuiteField
+ Cartel: eq :: Version -> Constraint
+ Cartel: exactly :: NonEmptyString -> Version -> Package
+ Cartel: executable :: NonEmptyString -> [ExecutableField] -> Section
+ Cartel: exitcodeFields :: (BuildsExitcode a, BuildsExe a) => NonEmptyString -> [a]
+ Cartel: exitcodeStdio :: BuildsExitcode a => a
+ Cartel: exposed :: Bool -> LibraryField
+ Cartel: exposedModules :: [NonEmptyString] -> LibraryField
+ Cartel: extensions :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel: extraDocFiles :: Properties -> [NonEmptyString]
+ Cartel: extraLibDirs :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel: extraLibraries :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel: extraSourceFiles :: Properties -> [NonEmptyString]
+ Cartel: extraTmpFiles :: Properties -> [NonEmptyString]
+ Cartel: false :: Condition
+ Cartel: fileExtensions :: [String]
+ Cartel: flag :: FlagName -> Condition
+ Cartel: flagDefault :: FlagOpts -> Bool
+ Cartel: flagDescription :: FlagOpts -> String
+ Cartel: flagManual :: FlagOpts -> Bool
+ Cartel: frameworks :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel: ghc :: Compiler
+ Cartel: ghcOptions :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel: ghcProfOptions :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel: ghcSharedOptions :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel: git :: Vcs
+ Cartel: githubHead :: NonEmptyString -> NonEmptyString -> Section
+ Cartel: gpl :: License
+ Cartel: gt :: Version -> Constraint
+ Cartel: gtEq :: Version -> Constraint
+ Cartel: haskell2010 :: HasBuildInfo a => a
+ Cartel: haskell98 :: HasBuildInfo a => a
+ Cartel: helium :: Compiler
+ Cartel: homepage :: Properties -> String
+ Cartel: hsSourceDirs :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel: hugs :: Compiler
+ Cartel: hugsOptions :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel: impl :: Compiler -> Constraint -> Condition
+ Cartel: includeDirs :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel: includes :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel: installIncludes :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel: invert :: Condition -> Condition
+ Cartel: jhc :: Compiler
+ Cartel: ldOptions :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel: lgpl :: License
+ Cartel: lhc :: Compiler
+ Cartel: license :: Properties -> Maybe License
+ Cartel: licenseFile :: Properties -> String
+ Cartel: licenseFiles :: Properties -> [NonEmptyString]
+ Cartel: lt :: Version -> Constraint
+ Cartel: ltEq :: Version -> Constraint
+ Cartel: mainIs :: BuildsExe a => NonEmptyString -> a
+ Cartel: maintainer :: Properties -> String
+ Cartel: make :: BuildType
+ Cartel: makeFlag :: Applicative m => NonEmptyString -> FlagOpts -> Betsy m FlagName
+ Cartel: mercurial :: Vcs
+ Cartel: mit :: License
+ Cartel: modules :: MonadIO m => FilePath -> Betsy m [NonEmptyString]
+ Cartel: modulesWithExtensions :: MonadIO m => [NonEmptyString] -> FilePath -> Betsy m [NonEmptyString]
+ Cartel: monotone :: Vcs
+ Cartel: mpl :: License
+ Cartel: name :: Properties -> String
+ Cartel: nextBreaking :: NonEmptyString -> Version -> Package
+ Cartel: nextMajor :: NonEmptyString -> Version -> Package
+ Cartel: nhc :: Compiler
+ Cartel: nhc98Options :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel: otherLicense :: License
+ Cartel: otherModules :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel: package :: NonEmptyString -> Constraint -> Package
+ Cartel: packageUrl :: Properties -> String
+ Cartel: pkgConfigDepends :: HasBuildInfo a => [Package] -> a
+ Cartel: publicDomain :: License
+ Cartel: render :: Renderable a => a -> String
+ Cartel: renderBetsy :: Functor m => Betsy m Cabal -> m (Either Error String)
+ Cartel: renderIndented :: RenderableIndented a => Int -> a -> String
+ Cartel: repoBranch :: Repository -> String
+ Cartel: repoHead :: RepoKind
+ Cartel: repoKind :: Repository -> Maybe RepoKind
+ Cartel: repoLocation :: Repository -> NonEmptyString
+ Cartel: repoSubdir :: Repository -> String
+ Cartel: repoTag :: Repository -> String
+ Cartel: repoThis :: RepoKind
+ Cartel: repoVcs :: Repository -> Maybe Vcs
+ Cartel: repository :: Repository -> Section
+ Cartel: simple :: BuildType
+ Cartel: stability :: Properties -> String
+ Cartel: svn :: Vcs
+ Cartel: synopsis :: Properties -> String
+ Cartel: system :: NonEmptyString -> Condition
+ Cartel: testModule :: NonEmptyString -> TestSuiteField
+ Cartel: testSuite :: NonEmptyString -> [TestSuiteField] -> Section
+ Cartel: testedWith :: Properties -> [(Compiler, Constraint)]
+ Cartel: true :: Condition
+ Cartel: type NonEmptyString = String
+ Cartel: type Version = [Word]
+ Cartel: unconstrained :: NonEmptyString -> Package
+ Cartel: version :: Properties -> Version
+ Cartel: yhc :: Compiler
+ Cartel.Ast: (&&&) :: LogicTree a => a -> a -> a
+ Cartel.Ast: (|||) :: LogicTree a => a -> a -> a
+ Cartel.Ast: AnyVersion :: Constraint
+ Cartel.Ast: BenchExitCode :: BenchmarkType
+ Cartel.Ast: BenchmarkMainIs :: NonEmptyString -> BenchmarkField
+ Cartel.Ast: BenchmarkType :: BenchmarkType -> BenchmarkField
+ Cartel.Ast: Constrained :: ConstrTree -> Constraint
+ Cartel.Ast: Exposed :: Bool -> LibraryField
+ Cartel.Ast: ExposedModules :: [NonEmptyString] -> LibraryField
+ Cartel.Ast: SecBench :: Benchmark -> Section
+ Cartel.Ast: SecExe :: Executable -> Section
+ Cartel.Ast: SecRepo :: Repository -> Section
+ Cartel.Ast: SecTest :: TestSuite -> Section
+ Cartel.Ast: TestSuiteType :: TestSuiteType -> TestSuiteField
+ Cartel.Ast: agpl :: License
+ Cartel.Ast: allRightsReserved :: License
+ Cartel.Ast: anyVersion :: Constraint
+ Cartel.Ast: apache :: License
+ Cartel.Ast: apiVersion :: NonEmptyString -> Version -> Package
+ Cartel.Ast: arch :: NonEmptyString -> Condition
+ Cartel.Ast: archVcs :: Vcs
+ Cartel.Ast: author :: Properties -> String
+ Cartel.Ast: bazaar :: Vcs
+ Cartel.Ast: benchmark :: NonEmptyString -> [BenchmarkField] -> Section
+ Cartel.Ast: benchmarkFields :: Benchmark -> [BenchmarkField]
+ Cartel.Ast: benchmarkName :: Benchmark -> NonEmptyString
+ Cartel.Ast: blank :: Blank a => a
+ Cartel.Ast: bsd2 :: License
+ Cartel.Ast: bsd3 :: License
+ Cartel.Ast: bsd4 :: License
+ Cartel.Ast: bugReports :: Properties -> String
+ Cartel.Ast: buildDepends :: HasBuildInfo a => [Package] -> a
+ Cartel.Ast: buildInfo :: HasBuildInfo a => BuildInfoField -> a
+ Cartel.Ast: buildTools :: HasBuildInfo a => [Package] -> a
+ Cartel.Ast: buildType :: Properties -> Maybe BuildType
+ Cartel.Ast: buildable :: HasBuildInfo a => Bool -> a
+ Cartel.Ast: cSources :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel.Ast: cabal :: Properties -> [LibraryField] -> [Section] -> Cabal
+ Cartel.Ast: cabalVersion :: Properties -> Maybe (Word, Word)
+ Cartel.Ast: category :: Properties -> String
+ Cartel.Ast: ccOptions :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel.Ast: class Blank a
+ Cartel.Ast: class BuildsExe a
+ Cartel.Ast: class BuildsExitcode a
+ Cartel.Ast: class HasBuildInfo a
+ Cartel.Ast: class LogicTree a
+ Cartel.Ast: closedOpen :: NonEmptyString -> Version -> Version -> Package
+ Cartel.Ast: condBlock :: HasBuildInfo a => Condition -> (a, [a]) -> [a] -> a
+ Cartel.Ast: conditional :: HasBuildInfo a => CondBlock a -> a
+ Cartel.Ast: configure :: BuildType
+ Cartel.Ast: copyright :: Properties -> String
+ Cartel.Ast: cppOptions :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel.Ast: custom :: BuildType
+ Cartel.Ast: cvs :: NonEmptyString -> Vcs
+ Cartel.Ast: darcs :: Vcs
+ Cartel.Ast: data BenchmarkType
+ Cartel.Ast: data CondLeaf
+ Cartel.Ast: data DefaultLanguage
+ Cartel.Ast: data Section
+ Cartel.Ast: dataDir :: Properties -> String
+ Cartel.Ast: dataFiles :: Properties -> [NonEmptyString]
+ Cartel.Ast: description :: Properties -> [String]
+ Cartel.Ast: detailed :: TestSuiteField
+ Cartel.Ast: eq :: Version -> Constraint
+ Cartel.Ast: exactly :: NonEmptyString -> Version -> Package
+ Cartel.Ast: executable :: NonEmptyString -> [ExecutableField] -> Section
+ Cartel.Ast: exitcodeFields :: (BuildsExitcode a, BuildsExe a) => NonEmptyString -> [a]
+ Cartel.Ast: exitcodeStdio :: BuildsExitcode a => a
+ Cartel.Ast: exposed :: Bool -> LibraryField
+ Cartel.Ast: exposedModules :: [NonEmptyString] -> LibraryField
+ Cartel.Ast: extensions :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel.Ast: extraDocFiles :: Properties -> [NonEmptyString]
+ Cartel.Ast: extraLibDirs :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel.Ast: extraLibraries :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel.Ast: extraSourceFiles :: Properties -> [NonEmptyString]
+ Cartel.Ast: extraTmpFiles :: Properties -> [NonEmptyString]
+ Cartel.Ast: false :: Condition
+ Cartel.Ast: fileExtensions :: [String]
+ Cartel.Ast: flag :: FlagName -> Condition
+ Cartel.Ast: frameworks :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel.Ast: ghc :: Compiler
+ Cartel.Ast: ghcOptions :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel.Ast: ghcProfOptions :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel.Ast: ghcSharedOptions :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel.Ast: git :: Vcs
+ Cartel.Ast: githubHead :: NonEmptyString -> NonEmptyString -> Section
+ Cartel.Ast: gpl :: License
+ Cartel.Ast: gt :: Version -> Constraint
+ Cartel.Ast: gtEq :: Version -> Constraint
+ Cartel.Ast: haskell2010 :: HasBuildInfo a => a
+ Cartel.Ast: haskell98 :: HasBuildInfo a => a
+ Cartel.Ast: helium :: Compiler
+ Cartel.Ast: homepage :: Properties -> String
+ Cartel.Ast: hsSourceDirs :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel.Ast: hugs :: Compiler
+ Cartel.Ast: hugsOptions :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel.Ast: ifFalse :: CondBlock a -> [a]
+ Cartel.Ast: impl :: Compiler -> Constraint -> Condition
+ Cartel.Ast: includeDirs :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel.Ast: includes :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel.Ast: installIncludes :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel.Ast: instance Blank Cabal
+ Cartel.Ast: instance Blank Properties
+ Cartel.Ast: instance Blank Repository
+ Cartel.Ast: instance BuildsExe BenchmarkField
+ Cartel.Ast: instance BuildsExe ExecutableField
+ Cartel.Ast: instance BuildsExe TestSuiteField
+ Cartel.Ast: instance BuildsExitcode BenchmarkField
+ Cartel.Ast: instance BuildsExitcode TestSuiteField
+ Cartel.Ast: instance Eq BenchmarkType
+ Cartel.Ast: instance Eq CondLeaf
+ Cartel.Ast: instance Eq DefaultLanguage
+ Cartel.Ast: instance Eq Section
+ Cartel.Ast: instance HasBuildInfo BenchmarkField
+ Cartel.Ast: instance HasBuildInfo ExecutableField
+ Cartel.Ast: instance HasBuildInfo LibraryField
+ Cartel.Ast: instance HasBuildInfo TestSuiteField
+ Cartel.Ast: instance LogicTree Condition
+ Cartel.Ast: instance LogicTree ConstrTree
+ Cartel.Ast: instance LogicTree Constraint
+ Cartel.Ast: instance Ord BenchmarkType
+ Cartel.Ast: instance Ord CondLeaf
+ Cartel.Ast: instance Ord DefaultLanguage
+ Cartel.Ast: instance Ord Section
+ Cartel.Ast: instance Show BenchmarkType
+ Cartel.Ast: instance Show CondLeaf
+ Cartel.Ast: instance Show DefaultLanguage
+ Cartel.Ast: instance Show Section
+ Cartel.Ast: interestingDir :: FilePath -> Bool
+ Cartel.Ast: interestingFile :: [String] -> FilePath -> Bool
+ Cartel.Ast: invert :: Condition -> Condition
+ Cartel.Ast: jhc :: Compiler
+ Cartel.Ast: ldOptions :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel.Ast: lgpl :: License
+ Cartel.Ast: lhc :: Compiler
+ Cartel.Ast: library :: Cabal -> [LibraryField]
+ Cartel.Ast: license :: Properties -> Maybe License
+ Cartel.Ast: licenseFile :: Properties -> String
+ Cartel.Ast: licenseFiles :: Properties -> [NonEmptyString]
+ Cartel.Ast: lt :: Version -> Constraint
+ Cartel.Ast: ltEq :: Version -> Constraint
+ Cartel.Ast: mainIs :: BuildsExe a => NonEmptyString -> a
+ Cartel.Ast: maintainer :: Properties -> String
+ Cartel.Ast: make :: BuildType
+ Cartel.Ast: mercurial :: Vcs
+ Cartel.Ast: mit :: License
+ Cartel.Ast: modules :: MonadIO m => FilePath -> Betsy m [NonEmptyString]
+ Cartel.Ast: modulesIO :: FilePath -> IO [String]
+ Cartel.Ast: modulesInDir :: [String] -> FilePath -> [FilePath] -> IO [[String]]
+ Cartel.Ast: modulesWithExtensions :: MonadIO m => [NonEmptyString] -> FilePath -> Betsy m [NonEmptyString]
+ Cartel.Ast: modulesWithExtensionsIO :: [String] -> FilePath -> IO [String]
+ Cartel.Ast: monotone :: Vcs
+ Cartel.Ast: mpl :: License
+ Cartel.Ast: name :: Properties -> String
+ Cartel.Ast: nextBreaking :: NonEmptyString -> Version -> Package
+ Cartel.Ast: nextMajor :: NonEmptyString -> Version -> Package
+ Cartel.Ast: nhc :: Compiler
+ Cartel.Ast: nhc98Options :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel.Ast: otherLicense :: License
+ Cartel.Ast: otherModules :: HasBuildInfo a => [NonEmptyString] -> a
+ Cartel.Ast: package :: NonEmptyString -> Constraint -> Package
+ Cartel.Ast: packageUrl :: Properties -> String
+ Cartel.Ast: pkgConfigDepends :: HasBuildInfo a => [Package] -> a
+ Cartel.Ast: processFile :: [String] -> FilePath -> [FilePath] -> FilePath -> IO [[String]]
+ Cartel.Ast: properties :: Cabal -> Properties
+ Cartel.Ast: publicDomain :: License
+ Cartel.Ast: repoHead :: RepoKind
+ Cartel.Ast: repoThis :: RepoKind
+ Cartel.Ast: repository :: Repository -> Section
+ Cartel.Ast: sections :: Cabal -> [Section]
+ Cartel.Ast: simple :: BuildType
+ Cartel.Ast: sorter :: [String] -> [String] -> Ordering
+ Cartel.Ast: stability :: Properties -> String
+ Cartel.Ast: svn :: Vcs
+ Cartel.Ast: synopsis :: Properties -> String
+ Cartel.Ast: system :: NonEmptyString -> Condition
+ Cartel.Ast: testModule :: NonEmptyString -> TestSuiteField
+ Cartel.Ast: testSuite :: NonEmptyString -> [TestSuiteField] -> Section
+ Cartel.Ast: testSuiteFields :: TestSuite -> [TestSuiteField]
+ Cartel.Ast: testSuiteName :: TestSuite -> NonEmptyString
+ Cartel.Ast: testedWith :: Properties -> [(Compiler, Constraint)]
+ Cartel.Ast: true :: Condition
+ Cartel.Ast: type Version = [Word]
+ Cartel.Ast: unconstrained :: NonEmptyString -> Package
+ Cartel.Ast: version :: Properties -> Version
+ Cartel.Ast: yhc :: Compiler
+ Cartel.Betsy: DuplicateFlag :: FlagName -> Error
+ Cartel.Betsy: EmptyFlagName :: Error
+ Cartel.Betsy: Failed :: String -> Error
+ Cartel.Betsy: FlagOpts :: String -> Bool -> Bool -> FlagOpts
+ Cartel.Betsy: currentFlags :: Applicative f => Betsy f [(FlagName, FlagOpts)]
+ Cartel.Betsy: data Betsy m a
+ Cartel.Betsy: data Error
+ Cartel.Betsy: data FlagName
+ Cartel.Betsy: data FlagOpts
+ Cartel.Betsy: flagDefault :: FlagOpts -> Bool
+ Cartel.Betsy: flagDescription :: FlagOpts -> String
+ Cartel.Betsy: flagManual :: FlagOpts -> Bool
+ Cartel.Betsy: flagNameHead :: FlagName -> Char
+ Cartel.Betsy: flagNameTail :: FlagName -> String
+ Cartel.Betsy: makeFlag :: Applicative m => NonEmptyString -> FlagOpts -> Betsy m FlagName
+ Cartel.Betsy: runBetsy :: Functor m => Betsy m a -> m (Either Error (a, [(FlagName, FlagOpts)]))
+ Cartel.Betsy.Internal: Betsy :: (State -> m (Either Error (a, State))) -> Betsy m a
+ Cartel.Betsy.Internal: DuplicateFlag :: FlagName -> Error
+ Cartel.Betsy.Internal: EmptyFlagName :: Error
+ Cartel.Betsy.Internal: Failed :: String -> Error
+ Cartel.Betsy.Internal: FlagName :: Char -> String -> FlagName
+ Cartel.Betsy.Internal: FlagOpts :: String -> Bool -> Bool -> FlagOpts
+ Cartel.Betsy.Internal: State :: [(FlagName, FlagOpts)] -> State
+ Cartel.Betsy.Internal: currentFlags :: Applicative f => Betsy f [(FlagName, FlagOpts)]
+ Cartel.Betsy.Internal: data Error
+ Cartel.Betsy.Internal: data FlagName
+ Cartel.Betsy.Internal: data FlagOpts
+ Cartel.Betsy.Internal: data State
+ Cartel.Betsy.Internal: flagDefault :: FlagOpts -> Bool
+ Cartel.Betsy.Internal: flagDescription :: FlagOpts -> String
+ Cartel.Betsy.Internal: flagManual :: FlagOpts -> Bool
+ Cartel.Betsy.Internal: flagNameHead :: FlagName -> Char
+ Cartel.Betsy.Internal: flagNameTail :: FlagName -> String
+ Cartel.Betsy.Internal: instance (Monad m, Functor m) => Applicative (Betsy m)
+ Cartel.Betsy.Internal: instance Eq Error
+ Cartel.Betsy.Internal: instance Eq FlagName
+ Cartel.Betsy.Internal: instance Eq FlagOpts
+ Cartel.Betsy.Internal: instance Eq State
+ Cartel.Betsy.Internal: instance Functor m => Functor (Betsy m)
+ Cartel.Betsy.Internal: instance Monad m => Monad (Betsy m)
+ Cartel.Betsy.Internal: instance MonadIO m => MonadIO (Betsy m)
+ Cartel.Betsy.Internal: instance MonadTrans Betsy
+ Cartel.Betsy.Internal: instance Ord Error
+ Cartel.Betsy.Internal: instance Ord FlagName
+ Cartel.Betsy.Internal: instance Ord FlagOpts
+ Cartel.Betsy.Internal: instance Ord State
+ Cartel.Betsy.Internal: instance Show Error
+ Cartel.Betsy.Internal: instance Show FlagName
+ Cartel.Betsy.Internal: instance Show FlagOpts
+ Cartel.Betsy.Internal: instance Show State
+ Cartel.Betsy.Internal: makeFlag :: Applicative m => NonEmptyString -> FlagOpts -> Betsy m FlagName
+ Cartel.Betsy.Internal: newtype Betsy m a
+ Cartel.Betsy.Internal: renderError :: Error -> String
+ Cartel.Betsy.Internal: runBetsy :: Functor m => Betsy m a -> m (Either Error (a, [(FlagName, FlagOpts)]))
+ Cartel.GenCartelCabal: base :: Package
+ Cartel.GenCartelCabal: commonOptions :: HasBuildInfo a => [a]
+ Cartel.GenCartelCabal: directory :: Package
+ Cartel.GenCartelCabal: filepath :: Package
+ Cartel.GenCartelCabal: libDepends :: [Package]
+ Cartel.GenCartelCabal: main :: IO ()
+ Cartel.GenCartelCabal: multiarg :: Package
+ Cartel.GenCartelCabal: quickcheck :: Package
+ Cartel.GenCartelCabal: quickpull :: Package
+ Cartel.GenCartelCabal: random :: Package
+ Cartel.GenCartelCabal: testDepends :: [Package]
+ Cartel.GenCartelCabal: testOptions :: HasBuildInfo a => [a]
+ Cartel.GenCartelCabal: time :: Package
+ Cartel.GenCartelCabal: transformers :: Package
+ Cartel.Render: Description :: [String] -> Description
+ Cartel.Render: class Renderable a
+ Cartel.Render: class RenderableIndented a
+ Cartel.Render: instance Eq Description
+ Cartel.Render: instance Ord Description
+ Cartel.Render: instance Renderable (Compiler, Constraint)
+ Cartel.Render: instance Renderable (Word, Word)
+ Cartel.Render: instance Renderable BenchmarkType
+ Cartel.Render: instance Renderable Bool
+ Cartel.Render: instance Renderable BuildType
+ Cartel.Render: instance Renderable Compiler
+ Cartel.Render: instance Renderable CondLeaf
+ Cartel.Render: instance Renderable Condition
+ Cartel.Render: instance Renderable ConstrTree
+ Cartel.Render: instance Renderable Constraint
+ Cartel.Render: instance Renderable DefaultLanguage
+ Cartel.Render: instance Renderable FlagName
+ Cartel.Render: instance Renderable License
+ Cartel.Render: instance Renderable Logical
+ Cartel.Render: instance Renderable Ordering
+ Cartel.Render: instance Renderable Package
+ Cartel.Render: instance Renderable RepoKind
+ Cartel.Render: instance Renderable String
+ Cartel.Render: instance Renderable TestSuiteType
+ Cartel.Render: instance Renderable Vcs
+ Cartel.Render: instance Renderable Version
+ Cartel.Render: instance Renderable a => Renderable (Maybe a)
+ Cartel.Render: instance RenderableIndented (FlagName, FlagOpts)
+ Cartel.Render: instance RenderableIndented Benchmark
+ Cartel.Render: instance RenderableIndented BenchmarkField
+ Cartel.Render: instance RenderableIndented BuildInfoField
+ Cartel.Render: instance RenderableIndented Cabal
+ Cartel.Render: instance RenderableIndented Description
+ Cartel.Render: instance RenderableIndented Error
+ Cartel.Render: instance RenderableIndented Executable
+ Cartel.Render: instance RenderableIndented ExecutableField
+ Cartel.Render: instance RenderableIndented LibraryField
+ Cartel.Render: instance RenderableIndented Properties
+ Cartel.Render: instance RenderableIndented Repository
+ Cartel.Render: instance RenderableIndented Section
+ Cartel.Render: instance RenderableIndented TestSuite
+ Cartel.Render: instance RenderableIndented TestSuiteField
+ Cartel.Render: instance RenderableIndented [(FlagName, FlagOpts)]
+ Cartel.Render: instance RenderableIndented a => RenderableIndented (CondBlock a)
+ Cartel.Render: instance Show Description
+ Cartel.Render: newtype Description
+ Cartel.Render: renLibrary :: Int -> [LibraryField] -> String
+ Cartel.Render: render :: Renderable a => a -> String
+ Cartel.Render: renderIndented :: RenderableIndented a => Int -> a -> String
+ Cartel.Types: type NonEmptyString = String
+ Cartel.Version: version :: [Word]
- Cartel.Ast: Arch :: String -> Condition
+ Cartel.Ast: Arch :: NonEmptyString -> CondLeaf
- Cartel.Ast: Benchmark :: String -> String -> [BenchmarkField] -> Benchmark
+ Cartel.Ast: Benchmark :: NonEmptyString -> [BenchmarkField] -> Benchmark
- Cartel.Ast: CBranch :: Logical -> CondTree -> CondTree -> CondTree
+ Cartel.Ast: CBranch :: Logical -> Condition -> Condition -> Condition
- Cartel.Ast: CCOptions :: [String] -> BuildInfoField
+ Cartel.Ast: CCOptions :: [NonEmptyString] -> BuildInfoField
- Cartel.Ast: CFalse :: Condition
+ Cartel.Ast: CFalse :: CondLeaf
- Cartel.Ast: CFlag :: String -> Condition
+ Cartel.Ast: CFlag :: FlagName -> CondLeaf
- Cartel.Ast: CLeaf :: Condition -> CondTree
+ Cartel.Ast: CLeaf :: CondLeaf -> Condition
- Cartel.Ast: CNegate :: CondTree -> CondTree
+ Cartel.Ast: CNegate :: Condition -> Condition
- Cartel.Ast: CPPOptions :: [String] -> BuildInfoField
+ Cartel.Ast: CPPOptions :: [NonEmptyString] -> BuildInfoField
- Cartel.Ast: CSources :: [String] -> BuildInfoField
+ Cartel.Ast: CSources :: [NonEmptyString] -> BuildInfoField
- Cartel.Ast: CTrue :: Condition
+ Cartel.Ast: CTrue :: CondLeaf
- Cartel.Ast: Cabal :: Properties -> [Repository] -> [Flag] -> Maybe Library -> [Executable] -> [TestSuite] -> [Benchmark] -> Cabal
+ Cartel.Ast: Cabal :: Properties -> [LibraryField] -> [Section] -> Cabal
- Cartel.Ast: CondBlock :: CondTree -> [a] -> [a] -> CondBlock a
+ Cartel.Ast: CondBlock :: Condition -> (a, [a]) -> [a] -> CondBlock a
- Cartel.Ast: Cvs :: String -> Vcs
+ Cartel.Ast: Cvs :: NonEmptyString -> Vcs
- Cartel.Ast: DefaultLanguage :: Language -> BuildInfoField
+ Cartel.Ast: DefaultLanguage :: DefaultLanguage -> BuildInfoField
- Cartel.Ast: ExeMainIs :: String -> ExecutableField
+ Cartel.Ast: ExeMainIs :: NonEmptyString -> ExecutableField
- Cartel.Ast: Executable :: String -> [ExecutableField] -> Executable
+ Cartel.Ast: Executable :: NonEmptyString -> [ExecutableField] -> Executable
- Cartel.Ast: Extensions :: [String] -> BuildInfoField
+ Cartel.Ast: Extensions :: [NonEmptyString] -> BuildInfoField
- Cartel.Ast: ExtraLibDirs :: [String] -> BuildInfoField
+ Cartel.Ast: ExtraLibDirs :: [NonEmptyString] -> BuildInfoField
- Cartel.Ast: ExtraLibraries :: [String] -> BuildInfoField
+ Cartel.Ast: ExtraLibraries :: [NonEmptyString] -> BuildInfoField
- Cartel.Ast: Frameworks :: [String] -> BuildInfoField
+ Cartel.Ast: Frameworks :: [NonEmptyString] -> BuildInfoField
- Cartel.Ast: GHCOptions :: [String] -> BuildInfoField
+ Cartel.Ast: GHCOptions :: [NonEmptyString] -> BuildInfoField
- Cartel.Ast: GHCProfOptions :: [String] -> BuildInfoField
+ Cartel.Ast: GHCProfOptions :: [NonEmptyString] -> BuildInfoField
- Cartel.Ast: GHCSharedOptions :: [String] -> BuildInfoField
+ Cartel.Ast: GHCSharedOptions :: [NonEmptyString] -> BuildInfoField
- Cartel.Ast: Haskell2010 :: Language
+ Cartel.Ast: Haskell2010 :: DefaultLanguage
- Cartel.Ast: Haskell98 :: Language
+ Cartel.Ast: Haskell98 :: DefaultLanguage
- Cartel.Ast: HsSourceDirs :: [String] -> BuildInfoField
+ Cartel.Ast: HsSourceDirs :: [NonEmptyString] -> BuildInfoField
- Cartel.Ast: HugsOptions :: [String] -> BuildInfoField
+ Cartel.Ast: HugsOptions :: [NonEmptyString] -> BuildInfoField
- Cartel.Ast: Impl :: (Compiler, Maybe ConstrTree) -> Condition
+ Cartel.Ast: Impl :: Compiler -> Constraint -> CondLeaf
- Cartel.Ast: IncludeDirs :: [String] -> BuildInfoField
+ Cartel.Ast: IncludeDirs :: [NonEmptyString] -> BuildInfoField
- Cartel.Ast: Includes :: [String] -> BuildInfoField
+ Cartel.Ast: Includes :: [NonEmptyString] -> BuildInfoField
- Cartel.Ast: InstallIncludes :: [String] -> BuildInfoField
+ Cartel.Ast: InstallIncludes :: [NonEmptyString] -> BuildInfoField
- Cartel.Ast: LDOptions :: [String] -> BuildInfoField
+ Cartel.Ast: LDOptions :: [NonEmptyString] -> BuildInfoField
- Cartel.Ast: Leaf :: Constraint -> ConstrTree
+ Cartel.Ast: Leaf :: Ordering -> Version -> ConstrTree
- Cartel.Ast: Nhc98Options :: [String] -> BuildInfoField
+ Cartel.Ast: Nhc98Options :: [NonEmptyString] -> BuildInfoField
- Cartel.Ast: OS :: String -> Condition
+ Cartel.Ast: OS :: NonEmptyString -> CondLeaf
- Cartel.Ast: OtherModules :: [String] -> BuildInfoField
+ Cartel.Ast: OtherModules :: [NonEmptyString] -> BuildInfoField
- Cartel.Ast: Package :: String -> Maybe ConstrTree -> Package
+ Cartel.Ast: Package :: NonEmptyString -> Constraint -> Package
- Cartel.Ast: Properties :: String -> Version -> (Int, Int) -> BuildType -> License -> String -> [String] -> String -> String -> String -> String -> String -> String -> String -> String -> [String] -> String -> [(Compiler, ConstrTree)] -> [String] -> String -> [String] -> [String] -> [String] -> Properties
+ Cartel.Ast: Properties :: String -> Version -> Maybe (Word, Word) -> Maybe BuildType -> Maybe License -> String -> [NonEmptyString] -> String -> String -> String -> String -> String -> String -> String -> String -> [String] -> String -> [(Compiler, Constraint)] -> [NonEmptyString] -> String -> [NonEmptyString] -> [NonEmptyString] -> [NonEmptyString] -> Properties
- Cartel.Ast: Repository :: Vcs -> RepoKind -> String -> String -> String -> String -> Repository
+ Cartel.Ast: Repository :: Maybe Vcs -> Maybe RepoKind -> String -> NonEmptyString -> String -> String -> Repository
- Cartel.Ast: TestMainIs :: String -> TestSuiteField
+ Cartel.Ast: TestMainIs :: NonEmptyString -> TestSuiteField
- Cartel.Ast: TestModule :: String -> TestSuiteField
+ Cartel.Ast: TestModule :: NonEmptyString -> TestSuiteField
- Cartel.Ast: TestSuite :: String -> [TestSuiteField] -> TestSuite
+ Cartel.Ast: TestSuite :: NonEmptyString -> [TestSuiteField] -> TestSuite
- Cartel.Ast: condIf :: CondBlock a -> CondTree
+ Cartel.Ast: condIf :: CondBlock a -> Condition
- Cartel.Ast: exeName :: Executable -> String
+ Cartel.Ast: exeName :: Executable -> NonEmptyString
- Cartel.Ast: ifTrue :: CondBlock a -> [a]
+ Cartel.Ast: ifTrue :: CondBlock a -> (a, [a])
- Cartel.Ast: repoKind :: Repository -> RepoKind
+ Cartel.Ast: repoKind :: Repository -> Maybe RepoKind
- Cartel.Ast: repoLocation :: Repository -> String
+ Cartel.Ast: repoLocation :: Repository -> NonEmptyString
- Cartel.Ast: repoVcs :: Repository -> Vcs
+ Cartel.Ast: repoVcs :: Repository -> Maybe Vcs
- Cartel.Render: indentList :: Int -> [String] -> String
+ Cartel.Render: indentList :: Renderable a => Int -> [a] -> String
- Cartel.Render: labeled :: Int -> String -> String -> String
+ Cartel.Render: labeled :: Renderable a => Int -> String -> a -> String
- Cartel.Render: labeledList :: Int -> String -> [String] -> String
+ Cartel.Render: labeledList :: Renderable a => Int -> String -> [a] -> String

Files

LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2014, Omari Norman+Copyright (c) 2014 - 2015, Omari Norman  All rights reserved. 
README.md view
@@ -11,7 +11,11 @@  http://www.github.com/massysett/cartel -## Testing+## Test results -There are no tests for this library.  If you hit any bugs, please-report them in the Github issue tracker so I can fix them.+[![Build Status](https://travis-ci.org/massysett/cartel.svg?branch=master)](https://travis-ci.org/massysett/cartel)++If you have trouble getting Cartel to build, you might try looking at+the test results by clicking on the button above; archived test+results will show you what package dependencies have been used in the+past to build Cartel successfully.
cartel.cabal view
@@ -2,54 +2,118 @@ -- Cartel is available at: -- http://www.github.com/massysett/cartel ----- Script name used to generate: genCabal.hs--- Generated on: 2014-05-30 14:59:50.352284 EDT--- Cartel library version: 0.10.0.0+-- Script name used to generate: GenCartelCabal.hs+-- Generated on: 2015-01-17 18:01:46.377337 EST+-- Cartel library version: 0.12.0.0 name: cartel-version: 0.10.0.2-cabal-version: >= 1.14-build-type: Simple+version: 0.12.0.0+cabal-version: >= 1.16 license: BSD3 license-file: LICENSE-copyright: 2014 Omari Norman+build-type: Simple+copyright: Copyright 2014-2015 Omari Norman author: Omari Norman maintainer: omari@smileystation.com stability: Experimental homepage: http://www.github.com/massysett/cartel-bug-reports: omari@smileystation.com-synopsis: Specify your Cabal files in Haskell+bug-reports: http://www.github.com/massysett/cartel/issues+synopsis: Specify Cabal files in Haskell description:-  By specifying Cabal files in Haskell, you have the power-  of Haskell at your disposal to eliminate redundancies-  and to programatically populate various fields.+  By specifying your Cabal files in Haskell, you have the power+  of Haskell at your disposal to reduce redundancy.  You can+  also read in trees of module names dynamically, which saves+  you from manually maintaining lists of module names.   .   See the documentation in the "Cartel" module for details. category: Distribution-tested-with: GHC == 7.4.1, GHC == 7.6.3, GHC == 7.8.2+tested-with:+    GHC == 7.6.3+  , GHC == 7.8.2 extra-source-files:     README.md-  , genCabal.hs-  , current-versions.txt-  , minimum-versions.txt  Library   exposed-modules:       Cartel     , Cartel.Ast-    , Cartel.Empty+    , Cartel.Betsy+    , Cartel.Betsy.Internal+    , Cartel.GenCartelCabal     , Cartel.Render-    , Cartel.Tools-  exposed: True+    , Cartel.Types+    , Cartel.Version+  default-language: Haskell2010+  ghc-options:+      -Wall+  hs-source-dirs:+      lib   build-depends:       base ((> 4.5.0.0 || == 4.5.0.0) && < 4.8)     , directory ((> 1.1.0.2 || == 1.1.0.2) && < 1.3)     , filepath ((> 1.3.0.0 || == 1.3.0.0) && < 1.4)-    , time ((> 1.4 || == 1.4) && < 1.5)+    , time ((> 1.4 || == 1.4) && < 1.6)+    , transformers ((> 0.4 || == 0.4) && < 0.5)++source-repository head+  type: git+  location: https://github.com/massysett/cartel.git++Executable cartel-visual-test+  if flag(visual)+    buildable: True+    other-modules:+        Cartel.Generators+      , Cartel.Properties+      , Decrees+    hs-source-dirs:+        tests+    build-depends:+        multiarg ((> 0.30.0.0 || == 0.30.0.0) && < 0.31)+      , QuickCheck ((> 2.7 || == 2.7) && < 2.8)+      , random ((> 1.1 || == 1.1) && < 1.2)+      , quickpull ((> 0.4.0.0 || == 0.4.0.0) && < 0.5)+    ghc-options:+        -Wall+    hs-source-dirs:+        lib+    build-depends:+        base ((> 4.5.0.0 || == 4.5.0.0) && < 4.8)+      , directory ((> 1.1.0.2 || == 1.1.0.2) && < 1.3)+      , filepath ((> 1.3.0.0 || == 1.3.0.0) && < 1.4)+      , time ((> 1.4 || == 1.4) && < 1.6)+      , transformers ((> 0.4 || == 0.4) && < 0.5)+  else+    buildable: False+  default-language: Haskell2010+  main-is: cartel-visual-test.hs++Test-Suite cartel-properties+  default-language: Haskell2010   other-modules:-      Paths_cartel-  buildable: True+      Cartel.Generators+    , Cartel.Properties+    , Decrees+  hs-source-dirs:+      tests+  build-depends:+      multiarg ((> 0.30.0.0 || == 0.30.0.0) && < 0.31)+    , QuickCheck ((> 2.7 || == 2.7) && < 2.8)+    , random ((> 1.1 || == 1.1) && < 1.2)+    , quickpull ((> 0.4.0.0 || == 0.4.0.0) && < 0.5)   ghc-options:       -Wall-  default-language: Haskell2010   hs-source-dirs:       lib+  build-depends:+      base ((> 4.5.0.0 || == 4.5.0.0) && < 4.8)+    , directory ((> 1.1.0.2 || == 1.1.0.2) && < 1.3)+    , filepath ((> 1.3.0.0 || == 1.3.0.0) && < 1.4)+    , time ((> 1.4 || == 1.4) && < 1.6)+    , transformers ((> 0.4 || == 0.4) && < 0.5)+  type: exitcode-stdio-1.0+  main-is: cartel-properties.hs++Flag visual+  description: Build cartel-visual-test executable.+  default: False+  manual: True
− current-versions.txt
@@ -1,38 +0,0 @@-This package was tested to work with these dependency-versions and compiler version.-These are the default versions fetched by cabal install.-Tested as of: 2014-05-30 16:15:53.772569 UTC-Path to compiler: ghc-7.8.2-Compiler description: 7.8.2--/opt/ghc/7.8.2/lib/ghc-7.8.2/package.conf.d:-    Cabal-1.18.1.3-    array-0.5.0.0-    base-4.7.0.0-    bin-package-db-0.0.0.0-    binary-0.7.1.0-    rts-1.0-    bytestring-0.10.4.0-    containers-0.5.5.1-    deepseq-1.3.0.2-    directory-1.2.1.0-    filepath-1.3.0.2-    (ghc-7.8.2)-    ghc-prim-0.3.1.0-    (haskell2010-1.1.2.0)-    (haskell98-2.0.0.3)-    hoopl-3.10.0.1-    hpc-0.6.0.1-    integer-gmp-0.5.1.0-    old-locale-1.0.0.6-    old-time-1.1.0.2-    pretty-1.1.1.1-    process-1.2.0.0-    template-haskell-2.9.0.0-    time-1.4.2-    transformers-0.3.0.0-    unix-2.7.0.1--/home/massysett/cartel/sunlight-11214/db:-    cartel-0.10.0.0-
− genCabal.hs
@@ -1,123 +0,0 @@--- | This is a Cartel program used to generate the cabal file for--- Cartel itself.------ You should note in your comments which version of Cartel was used--- when writing the Cartel program; in this case, I used version--- 0.10.0.0.------ There's no huge benefit to using Cartel for small programs or--- libraries; indeed, Cartel itself is small so there's not much--- benefit to using Cartel here other than for pedagogical and--- testing purposes.  Cartel is most useful for big Cabal files with--- lots of redundancy and dozens of modules.-module Main (main) where---- Cartel exports a lot of names; by importing them qualified you--- don't have to worry about clashing with your own names--import qualified Cartel as A---- Package Dependencies------ It can be useful to pull these out and define them in--- top-level values, especially if your Cabal file has many--- redundancies.  That way you can update version numbers in just--- one place rather than throughout your Cabal file (forgetting to--- update all these numbers is a major reason I wrote Cartel.)--base :: A.Package-base = A.closedOpen "base" [4,5,0,0] [4,8]--directory :: A.Package-directory = A.closedOpen "directory" [1,1,0,2] [1,3]--filepath :: A.Package-filepath = A.closedOpen "filepath" [1,3,0,0] [1,4]--time :: A.Package-time = A.closedOpen "time" [1,4] [1,5]--testedWith :: [(A.Compiler, A.ConstrTree)]-testedWith =-  let ghc v = (A.GHC, A.Leaf (A.Constraint EQ (A.Version v)))-  in map ghc [[7,4,1], [7,6,3], [7,8,2]]---- The global package properties.  Build your properties from the--- default 'properties' record rather than the 'Properties'--- constructor to help future-proof your code.--properties :: A.Properties-properties = A.empty-  { A.prName = "cartel"-  , A.prVersion = A.Version [0,10,0,2]-  , A.prCabalVersion = (1, 14)-  , A.prBuildType = A.Simple-  , A.prLicense = A.BSD3-  , A.prLicenseFile = "LICENSE"-  , A.prLicenseFiles = []-  , A.prExtraSourceFiles =-    [ "README.md"-    , "genCabal.hs"-    , "current-versions.txt"-    , "minimum-versions.txt" ]-  , A.prTestedWith = testedWith-  , A.prCopyright = "2014 Omari Norman"-  , A.prAuthor = "Omari Norman"-  , A.prMaintainer = "omari@smileystation.com"-  , A.prStability = "Experimental"-  , A.prHomepage = "http://www.github.com/massysett/cartel"-  , A.prBugReports = "omari@smileystation.com"-  , A.prSynopsis = "Specify your Cabal files in Haskell"-  , A.prDescription =-      [ "By specifying Cabal files in Haskell, you have the power"-      , "of Haskell at your disposal to eliminate redundancies"-      , "and to programatically populate various fields."-      , ""-      , "See the documentation in the \"Cartel\" module for details."-      ]-  , A.prCategory = "Distribution"-  }---- Definition for the library.  It takes a list of modules to export--- as a parameter; this allows the Main function to use a function--- to generate the list of modules rather than you having to specify--- them in a duplicative, error-prone, and boring process.--library-  :: [String]-  -- ^ List of library modules to export-  -> A.Library-library ms = A.Library $-  [ A.LibExposedModules ms-  , A.LibExposed True-  ] -  -  ++ map A.LibInfo--  [ A.BuildDepends [base, directory, filepath, time]-  , A.OtherModules ["Paths_cartel"]-  , A.Buildable True-  , A.GHCOptions ["-Wall"]-  , A.DefaultLanguage A.Haskell2010-  , A.HsSourceDirs ["lib"]-  ]----- Generate the complete Cabal record--cabal-  :: [String]-  -- ^ List of library modules-  -> A.Cabal-cabal mods = A.empty-  { A.cProperties = properties-  , A.cLibrary = Just $ library mods-  }---- To see the result, just run "runhaskell genCabal.hs".  The result--- is printed to standard output.--main :: IO ()-main = do-  modulesToExport <- A.modules "lib"-  A.render "genCabal.hs" $ cabal modulesToExport
lib/Cartel.hs view
@@ -16,42 +16,332 @@ -- of modules and use the result, thus avoiding the need to manually -- update your module lists. ----- A disadvantage to Cartel is that it can be a bit more verbose--- than a vanilla Cabal file.  In addition, you also have to--- remember to generate the new Cabal file whenever you change the--- script that generates your Cabal file.+-- A disadvantage to Cartel is that is more verbose than a vanilla+-- Cabal file.  In addition, you also have to remember to generate the+-- new Cabal file whenever you change the script that generates your+-- Cabal file. ----- Cabal already has an AST that it uses.  Cartel could, perhaps,--- have re-used these structures.  Cartel does not do this for three--- reasons.  First, the Cabal API is a bit untidy, partially because--- it has to do things that Cartel doesn't have to worry about, but--- also because the comments in the Cabal modules themselves--- indicate that the whole thing could use a refactoring.  Second,--- the Cabal developers make no commitment to keep that API stable.--- Third, the Cartel API tries only to replicate format of the--- plain-text Cabal file, which will be much more stable than the--- Cabal API.+-- To the extent possible, Cartel uses the Haskell type system to+-- prevent you from making mistakes in your Cabal file.  For example,+-- the 'Betsy' type prevents you from using 'flag's that you have not+-- declared, and you can't put an 'exposedModules' field in anything+-- but a library.  However, Cartel does not prevent against all+-- errors.  For example, Cartel does nothing to prevent you from+-- applying a function that calls for a 'NonEmptyString' to a string+-- that is, in fact, empty.  Another example is that Cabal requires+-- executables to have a @main-is@ field, but Cartel does not force+-- you to include one.  Ultimately your Cabal file might still have+-- errors that you have to fix by changing the program that generates+-- the file. ----- To get started, first study the "Cartel.Ast" module.  It contains--- the data types that mirror the structure of a Cabal file.  You--- will find that every Cabal feature, including test suites,--- benchmarks, and conditionals, is represented.  Then look at--- "Cartel.Tools", which has short functions to make Cartel easier--- to use.  "Cartel.Render" has functions to transform "Cartel.Ast"--- types to plain text; the necessary bits from here are exported--- through "Cartel.Tools" so you shouldn't need to use this module--- much if at all.+-- Everything you usually need is in this module.  Other Cartel+-- modules contain implementation details.  /See first/ the+-- 'NonEmptyString' type synonym, which has important details on how+-- to regard 'String's and 'NonEmptyString's as you read the+-- documentation.  Also, examine "Cartel.GenCartelCabal", which+-- generates Cartel's own Cabal file using Cartel. ----- Also, examine the genCabal.hs file, which generates Cartel's own--- Cabal file using Cartel.  To test it out, after installing Cartel--- just run "runhaskell genCabal.hs".+-- Hopefully this module's documentation is organized so that+-- top-to-bottom reading will make sense.  module Cartel-  ( module Cartel.Ast-  , module Cartel.Empty-  , module Cartel.Tools+  ( -- * Basic types and classes+    Word+  , NonEmptyString+  , Blank(..)+  , Version++  -- * Sections+  , Section++  -- * Repositories+  -- ** Version control systems+  , Vcs+  , darcs, git, svn, mercurial, bazaar, archVcs, monotone, cvs++  -- ** Repository kinds+  , RepoKind+  , repoHead, repoThis+  -- ** Building repositories+  , Repository(..)+  , githubHead+  , repository++  -- * Logicals+  , LogicTree(..)+  , invert++  -- ** Constraints+  , Constraint+  , lt+  , gt+  , eq+  , ltEq+  , gtEq+  , anyVersion++  -- ** Conditionals+  , Compiler+  , ghc, nhc, yhc, hugs, helium, jhc, lhc+  , Condition+  , system+  , arch+  , impl+  , flag+  , true+  , false+  , condBlock++  -- * Packages+  , Package+  , package++  -- ** Package helpers+  , closedOpen+  , apiVersion+  , nextBreaking+  , nextMajor+  , exactly+  , unconstrained++  -- * Build information++  -- | Libraries, executables, test suites, and benchmarks all share+  -- common fields for build information.  'BuildInfoField' represents+  -- these common fields, and 'HasBuildInfo' is a typeclass encompassing+  -- libraries, executables, test suites, and benchmarks.  You can+  -- build these fields for any of these sections using the functions+  -- and values listed here.+  , BuildInfoField+  , HasBuildInfo+  , haskell98+  , haskell2010+  , buildDepends+  , otherModules+  , hsSourceDirs+  , extensions+  , buildTools+  , buildable+  , ghcOptions+  , ghcProfOptions+  , ghcSharedOptions+  , hugsOptions+  , nhc98Options+  , includes+  , installIncludes+  , includeDirs+  , cSources+  , extraLibraries+  , extraLibDirs+  , ccOptions+  , cppOptions+  , ldOptions+  , pkgConfigDepends+  , frameworks++  -- * BuildsExe+  --+  -- | Benchmarks, test suites, and executables have common fields;+  -- the 'BuildsExe' class captures these.+  , BuildsExe(..)++  -- * Exitcode executables+  --+  -- | Test suites and benchmarks are capable of building things of+  -- type @exitcode-stdio-1.0@; the 'BuildsExitcode' class reflects+  -- this.+  , BuildsExitcode(..)+  , exitcodeFields++  -- * Betsy+  , Betsy++  -- ** Flags+  , FlagName+  , FlagOpts(..)+  , makeFlag+  , currentFlags++  -- * Libraries+  --+  -- | A library consists of one or more 'LibraryField's.  Typically+  -- you will return these fields inside of the 'Betsy' type through+  -- the 'defaultMain' function.  To build a 'LibraryField', you will+  -- mostly use the bindings in the \"Build Information\" section of+  -- this module.  You will also need 'exposedModules' and you might+  -- use 'exposed' and 'condBlock'.+  , LibraryField+  , exposed+  , exposedModules++  -- * Executables+  --+  -- | An executable consists of one more more 'ExecutableField's.+  -- You build an executable by passing one or more 'ExecutableField's+  -- to the 'executable' function.  To get an 'ExecutableField', you+  -- will mostly use the bindings in the \"Build Information\" section+  -- of this module, as well as 'mainIs'.  You might also need+  -- 'condBlock'.+  , ExecutableField+  , executable++  -- * Test suites+  --+  -- | A test suite consists of one more more 'TestSuiteField's.  You+  -- build an test suite by passing one or more 'TestSuiteField's to+  -- the 'testSuite' function.  To get a 'TestSuiteField', you will+  -- mostly use the bindings in the \"Build Information\" section of+  -- this module.  You might also need the 'testModule',+  -- 'exitcodeStdio', 'mainIs', 'detailed', 'condBlock', and+  -- 'exitcodeFields' bindings.+  , detailed+  , TestSuiteField+  , testModule+  , testSuite++  -- * Benchmarks+  -- +  -- | A benchmark consists of one more more 'BenchmarkField's.  You+  -- build an benchmark by passing one or more 'BenchmarkField's to+  -- the 'benchmark' function.  To get an 'BenchmarkField', you will+  -- mostly use the bindings in the \"Build Information\" section of+  -- this module.  You might also need the 'exitcodeStdio',+  -- 'exitcodeFields', and 'condBlock' bindings.+  , BenchmarkField+  , benchmark++  -- * Getting module lists+  , fileExtensions+  , modulesWithExtensions+  , modules++  -- * Properties+  -- ** Build types+  , BuildType+  , simple, configure, make, custom+  -- ** Licenses+  , License+  , gpl, agpl, lgpl, bsd2, bsd3, bsd4, mit, mpl, apache, publicDomain+  , allRightsReserved, otherLicense+  , Properties(..)++  -- * Cabal file+  --+  -- | Usually you will not need this type, as 'defaultMain' produces+  -- a 'Cabal' value for you, but you will need it if you want to use+  -- 'bestyToCabalString'.+  , Cabal+  , cabal++  -- * Generating Cabal files+  -- ** defaultMain - usually all you need+  , defaultMain++  -- ** Other bindings - for more unusual uses+  , Error(..)+  , Renderable(..)+  , RenderableIndented(..)+  , renderBetsy+  , betsyToCabalStringIO+   ) where +-- # begin imports+ import Cartel.Ast-import Cartel.Empty-import Cartel.Tools+import Cartel.Render+import qualified System.IO as IO+import Data.Time+import qualified Cartel.Version+import Data.List (intersperse)+import System.Exit (exitFailure, exitSuccess)+import System.Environment (getProgName)+import Data.Word+import Control.Monad.IO.Class+import Cartel.Betsy+import Cartel.Types++-- # end imports++-- | Pure function to obtain Cabal text.+renderBetsy+  :: Functor m+  => Betsy m Cabal+  -> m (Either Error String)+  -- ^ Returns either an error message or the generated Cabal text.+renderBetsy = fmap k . runBetsy+  where+    k ei = case ei of+      Left e -> Left e+      Right (cbl, fls) -> Right+        . vsep+        $ [ renderIndented 0 cbl+          , renderIndented 0 fls ]++-- | Renders a header for the Cabal file.+header+  :: String+  -- ^ Name of program used+  -> ZonedTime+  -- ^ When this output is being created+  -> String+header nm zt = hdr+  where+    hdr = unlines $+      [ "-- This Cabal file generated using the Cartel library."+      , "-- Cartel is available at:"+      , "-- http://www.github.com/massysett/cartel"+      , "--"+      ] ++ case nm of+            [] -> []+            _ -> ["-- Script name used to generate: " ++ nm]+      +++      [ "-- Generated on: " ++ show zt+      , "-- Cartel library version: " ++ showVer+      ]+    showVer = concat+      . intersperse "."+      . map show+      $ Cartel.Version.version+++-- | Like 'renderBetsy' but also uses 'IO' to prepend a header+-- that has the name of the program that is running this function, and+-- the current date and time.+betsyToCabalStringIO+  :: (MonadIO m, Functor m)+  => Betsy m Cabal+  -> m (Either Error String)+betsyToCabalStringIO wg = do+  ei <- renderBetsy wg+  case ei of+    Left e -> return $ Left e+    Right cbl -> do+      pn <- liftIO getProgName+      zt <- liftIO getZonedTime+      return . Right $ (header pn zt) ++ cbl+++-- | Generates a Cabal file.  If you have no library, just leave the+-- list of 'LibraryField' empty.  Include any and all executables,+-- test suites, benchmarks, and repositories in the list of 'Section'.+-- Ensures that the generated Cabal file also includes any flags you+-- made with 'makeFlag'.  If there is an error (such as a duplicate+-- flag) an error message is printed to standard error and the program+-- invokes 'exitFailure'; otherwise, the generated Cabal file is+-- printed to standard output and the program invokes 'exitSuccess'.+defaultMain+  :: Betsy IO (Properties, [LibraryField], [Section])+  -> IO ()+defaultMain wg = do+  let conv (p, ls, ss) = Cabal p ls ss+  ei <- betsyToCabalStringIO (fmap conv wg)+  case ei of+    Left e -> do+      IO.hPutStrLn IO.stderr . renderIndented 0 $ e+      exitFailure+    Right str -> do+      IO.hSetBinaryMode IO.stdout False+      IO.hSetEncoding IO.stdout IO.utf8+      putStr str+      exitSuccess
lib/Cartel/Ast.hs view
@@ -1,577 +1,1209 @@--- | An abstract syntax tree for Cabal files.  There are thoughts in--- the "Cartel" module documentation on why this wheel is reinvented--- rather than reusing the types already available in the Cabal--- library.------ The 'Cabal' data type represents the root of the Cabal file; all--- other types in this file are ultimately components of the 'Cabal'--- type.------ Much documentation in this module is copied from the--- /Developing Cabal Packages/ guide at------ <http://www.haskell.org/cabal/users-guide/developing-packages.html>--module Cartel.Ast-  (-  -- * Constraint trees-    Logical(..)-  , Version(..)-  , Constraint(..)-  , ConstrTree(..)--  -- * Global package description-  , BuildType(..)-  , License(..)-  , Compiler(..)-  , Properties(..)--  -- * Repositories-  , RepoKind(..)-  , Vcs(..)-  , Repository(..)--  -- * Flags-  , Flag(..)--  -- * Build information-  , Package(..)-  , Language(..)-  , BuildInfoField(..)--  -- * Conditionals-  , Condition(..)-  , CondTree(..)-  , CondBlock(..)--  -- * Libraries-  , LibraryField(..)-  , Library(..)--  -- * Executables-  , ExecutableField(..)-  , Executable(..)--  -- * Test suites-  , TestSuiteType(..)-  , TestSuiteField(..)-  , TestSuite(..)--  -- * Benchmarks-  , BenchmarkField(..)-  , Benchmark(..)--  -- * Cabal-  , Cabal(..)--  ) where---- | A version number.  The Cabal documentation says this--- \"usually\" consists of a sequence of natural numbers separated--- by dots.  Though this suggests that a version number could--- contain something other than natural numbers, in fact the types--- in the Cabal library do not allow anything other than numbers and--- you will get a parse error if you try to use anything else.------ Therefore Cartel's 'Version' type only allows a list of 'Int' in--- a version number.-newtype Version = Version { unVersion :: [Int] }-  deriving (Eq, Ord, Show)--data BuildType-  = Simple-  | Configure-  | Make-  | Custom-  deriving (Eq, Ord, Show)--data License-  = GPL-  | AGPL-  | LGPL-  | BSD2-  | BSD3-  | BSD4-  | MIT-  | MPL-  | Apache-  | PublicDomain-  | AllRightsReserved-  | OtherLicense-  deriving (Eq, Ord, Show)--data Compiler-  = GHC-  | NHC-  | YHC-  | Hugs-  | Helium-  | JHC-  | LHC-  deriving (Eq, Ord, Show)---- | A version constraint; used primarily when specifying the build--- dependencies of a package.  For example, to specify--- @less than version 1.0@, use @Constraint LT (Version [1,0])@.------ There is no way to express @less than or equal to@ or @greater--- than or equal to@; for that, use 'ConstrTree'.-data Constraint = Constraint-  { csComparison :: Ordering-  , csVersion :: Version-  } deriving (Eq, Ord, Show)--data Logical-  = Or-  | And-  deriving (Eq, Ord, Show)---- | Expresses a tree of constraints.  This is how you represent--- more complex dependency relationships.  For example, to represent--- @less than or equal to version 1.0@, use------ >> let one = Version [1,0]--- >> in Branch Or (Constraint LT one) (Constraint EQ one)------ Combinators in "Cartel.Tools" help you build the most common--- cases.-data ConstrTree-  = Leaf Constraint-  | Branch Logical ConstrTree ConstrTree-  deriving (Eq, Ord, Show)---- | Global package properties.  Most of the 'String' fields are--- optional; to leave them blank, use the empty string.  To future--- proof your code, use 'Cartel.Empty.empty', which provides--- this record already filled in with default values (which are--- typically blank.)  Then you only alter the fields you wish to--- fill in.--data Properties = Properties-  { prName :: String-  -- ^ Unique name of package, without the version number--  , prVersion :: Version-  -- ^ Package version number--  , prCabalVersion :: (Int, Int)-  -- ^ Version of Cabal that the package uses; for instance, for-  -- 1.20, use @(1, 20)--  , prBuildType :: BuildType--  , prLicense :: License--  , prLicenseFile :: String-  -- ^ The file containing the precise copyright license--  , prLicenseFiles :: [String]-  -- ^ Multiple license files; use in addition to, or instead of,-  -- 'prLicenseFile'--  , prCopyright :: String-  -- ^ Copyright notice; typically the name of the holder of the-  -- copyright and the year(s) for which copyright is claimed--  , prAuthor :: String-  -- ^ Original package author--  , prMaintainer :: String-  -- ^ Current package maintainer; this is an email address to which-  -- users should send bug reports, feature requests, and patches.--  , prStability :: String-  -- ^ Package stability level, e.g. @alpha@, @stable@, etc.--  , prHomepage :: String-  -- ^ URL of package homepage--  , prBugReports :: String-  -- ^ URL where users should direct bug reports.  Should be either-  -- a @mailto:@ URL for a person or mailing list, or an @http:@ or-  -- @https:@ URL for an online bug tracking system.--  , prPackageUrl :: String-  -- ^ The location of a source bundle for the package.--  , prSynopsis :: String-  -- ^ Short, one-line synopsis of what the package does--  , prDescription :: [String]-  -- ^ Each line of the long description.  Do not include the-  -- newlines themselves.  If you wish to include a blank line,-  -- include a list item that is the empty string; upon rendering, a-  -- single period will be inserted, as Cabal requires when-  -- inputting blank lines.--  , prCategory :: String-  -- ^ A comma-separated list of categories to use on Hackage.--  , prTestedWith :: [(Compiler, ConstrTree)]-  -- ^ Compilers and versions against which the package has been-  -- tested.--  , prDataFiles :: [String]-  -- ^ List of files to be installed for run-time use by the-  -- package.--  , prDataDir :: String-  -- ^ The directory where Cabal looks for data files to install,-  -- relative to the source directory.  By default Cabal looks in-  -- the source directory itself.--  , prExtraSourceFiles :: [String]-  -- ^ List of additional files to be included in source-  -- distributions built with @setup sdist@.  This can use a limited-  -- form of @*@ wildcards in file names.--  , prExtraDocFiles :: [String]-  -- ^ List of additional files to be included in source-  -- distributions, and also copied to the html directory when-  -- Haddock documentation is generated. As with data-files it can-  -- use a limited form of @*@ wildcards in file names.--  , prExtraTmpFiles :: [String]-  -- ^ List of additional files or directories to be removed by-  -- @setup clean@.  These would typically be additional files-  -- created by additional hooks.--  } deriving (Eq, Ord, Show)---- | A field in the @Library@ section of the Cabal file.  A--- @Library@ section can have multiple fields.-data LibraryField-  = LibExposedModules [String]-  -- ^ Exposed modules.  'Cartel.Tools.modules' can help you-  -- generate this.--  | LibExposed Bool-  -- ^ Is the library exposed?  GHC can hide libraries.--  | LibConditional (CondBlock LibraryField)-  -- ^ The @Library@ section can contain conditional blocks.--  | LibInfo BuildInfoField-  -- ^ The @Library@ section can contain build information.-  deriving (Eq, Ord, Show)---- | The entire @Library@ section.-newtype Library = Library-  { libFields :: [LibraryField]-  } deriving (Eq, Ord, Show)---- | A single field in an @Executable@ section.  An @Executable@--- section may have multiple fields.-data ExecutableField--  = ExeMainIs String-  -- ^ @main-is@.  This field is required.--  | ExeConditional (CondBlock ExecutableField)-  -- ^ An @Executable@ section can contain conditional blocks.--  | ExeInfo BuildInfoField-  -- ^ An @Executable@ section can contain one or more build-  -- information fields.--  deriving (Eq, Ord, Show)---- | An entire @Executable@ section.-data Executable = Executable-  { exeName :: String-  -- ^ The name of the executable that Cabal will build.-  , exeFields :: [ExecutableField]-  -- ^ Zero or more fields associated with this executable.-  } deriving (Eq, Ord, Show)---- | What kind of test suite is this?-data TestSuiteType-  = ExitcodeStdio-  -- ^ An @exitcode-stdio-1.0@ test.  The @String@ is the name of-  -- the file containing the executable code.  In this case, the-  -- 'TestMainIs' field is required.--  | Detailed-  -- ^ The @detailed-1.0@ test.  In this case, the 'TestModule'-  -- field is required.-  deriving (Eq, Ord, Show)---- | A single field value in a test suite section.  A single test--- suite section may contain mulitple fields.-data TestSuiteField-  = TestType TestSuiteType-  -- ^ What kind of test this is--  | TestMainIs String-  -- ^ The name of the @.hs@ or @.lhs@ file containing the @Main@-  -- module.  The @.hs@ filename must be listed, even if that file-  -- is generated with a preprocessor.  The file must be relatie to-  -- one of the directories listed in 'HsSourceDirs'.  This field-  -- is required when using 'ExitcodeStdio' and disallowed when-  -- using 'Detailed'.--  | TestModule String-  -- ^ The module exporting the @tests@ symbol.  This field is-  -- required when using 'Detailed' and disallowed when using-  -- 'ExitcodeStdio'.--  | TestConditional (CondBlock TestSuiteField)-  -- ^ A test may contain zero or more conditional blocks.--  | TestInfo BuildInfoField-  -- ^ A test suite can contain build information fields.--  deriving (Eq, Ord, Show)---- | An entire test suite section.-data TestSuite = TestSuite-  { tsName :: String-  -- ^ The executable name of the resulting test suite-  , tsFields :: [TestSuiteField]-  -- ^ Zero or more fields configuring the test.-  } deriving (Eq, Ord, Show)---- | A single field in a @Benchmark@ section.  Because Cabal--- currently supports only one benchmark interface, which is--- @exitcode-stdio-1.0@, all Cartel-generated files using benchmarks--- will have benchmarks of this type.-data BenchmarkField-  = BenchmarkConditional (CondBlock BenchmarkField)-  -- ^ A benchmark can have conditional blocks.-  | BenchmarkInfo BuildInfoField-  -- ^ A benchmark can have build information fields.-  deriving (Eq, Ord, Show)--data Benchmark = Benchmark-  { bmName :: String-  -- ^ The name of the benchmark that will be built-  , bmMainIs :: String-  -- ^ The @.hs@ or @.lhs@ file containing the @Main@ module.-  , bmFields :: [BenchmarkField]-  -- ^ Zero or more benchmark fields.-  } deriving (Eq, Ord, Show)---- | A single package, consisting of a package name and an optional--- set of constraints.  Used when specifying 'BuildDepends',--- 'BuildTools', and 'PkgConfigDepends'.-data Package = Package-  { packName :: String-  , packConstraints :: Maybe ConstrTree-  } deriving (Eq, Ord, Show)---- | Default language.  Currently not documented in Cabal docs, see------ <https://github.com/haskell/cabal/issues/1894>-data Language-  = Haskell98-  | Haskell2010-  deriving (Eq, Ord, Show)---- | A single field of build information.  This can appear in a--- Library, Executable, Test-Suite, or Benchmark.-data BuildInfoField-  = BuildDepends [Package]-  -- ^ A list of packages needed to build this component--  | OtherModules [String]-  -- ^ Modules used but not exposed.  For libraries, these are-  -- hidden modules; for executable, these are auxiliary modules to-  -- be linked with the file in the @main-is@ field.-  ---  -- 'Cartel.Tools.modules' can help greatly with maintenance of-  -- this field.--  | HsSourceDirs [String]-  -- ^ Root directories for the module hierarchy--  | Extensions [String]-  -- ^ Haskell extensions used by every module.--  | BuildTools [Package]-  -- ^ Programs needed to build this package, such as c2hs.--  | Buildable Bool-  -- ^ Is this component buildable?--  | GHCOptions [String]-  | GHCProfOptions [String]-  | GHCSharedOptions [String]-  | HugsOptions [String]-  | Nhc98Options [String]-  | Includes [String]-  -- ^ Header files to be included in any compilations via C.-  -- Applies to both header files that are already installed on the-  -- system and to those coming with the package to be installed.--  | InstallIncludes [String]-  -- ^ Header files to be installed into @$libdir/includes@ when the-  -- package is installed.  These files should be found in relative-  -- to the top of the source tree or relative to one of the-  -- directories listed in @include-dirs@.--  | IncludeDirs [String]-  -- ^ List of diretories to search for header files when dealing-  -- with C compilations.--  | CSources [String]-  -- ^ C sources to be compiled and lined with the Haskell files.--  | ExtraLibraries [String]-  -- ^ Extra libraries to link with.--  | ExtraLibDirs [String]-  -- ^ Directories to search for libraries.--  | CCOptions [String]-  -- ^ C Compiler options.--  | CPPOptions [String]-  -- ^ C Preprocessor options.  Undocumented, see-  -- <https://github.com/haskell/cabal/issues/646>--  | LDOptions [String]-  -- ^ Linker options.--  | PkgConfigDepends [Package]-  -- ^ List of pkg-config packages needed to build this component.--  | Frameworks [String]-  -- ^ OS X frameworks.--  | DefaultLanguage Language-  deriving (Eq, Ord, Show)---- | Conditions to use in the @if@ statement when defining--- conitional blocks.-data Condition-  = OS String-  -- ^ Operating system; tested against @System.Info.os@ on the-  -- target system.--  | Arch String-  -- ^ Argument is matched against @System.Info.arch@ on the target-  -- system.--  | Impl (Compiler, Maybe ConstrTree)-  -- ^ Tests for the configured Haskell implementation.--  | CFlag String-  -- ^ Evaluates to the current assignment of the flag of the given-  -- name.  Flag names are case insensitive.  Testing for flags that-  -- have not been introduced with a flag section is an error.--  | CTrue-  -- ^ Always true.--  | CFalse-  -- ^ Always false.--  deriving (Eq, Ord, Show)---- | Tree of conditions to use in a 'CondBlock'.-data CondTree-  = CLeaf Condition-  | CBranch Logical CondTree CondTree-  | CNegate CondTree-  deriving (Eq, Ord, Show)---- | An @if-then-else@ block.-data CondBlock a = CondBlock-  { condIf :: CondTree-  , ifTrue :: [a]-  , ifElse :: [a]-  } deriving (Eq, Ord, Show)--instance Functor CondBlock where-  fmap f (CondBlock t ts es) = CondBlock t (map f ts) (map f es)---- | What kind of VCS repository is this?-data RepoKind--  = Head-  -- ^ The latest development branch of the repository--  | This-  -- ^ The sources for this release of this package.-  deriving (Eq, Ord, Show)--data Vcs-  = Darcs-  | Git-  | Svn-  | Cvs String-  -- ^ The argument 'String' is the named module-  | Mercurial-  | Bazaar-  | ArchVcs-  | Monotone-  deriving (Eq, Ord, Show)--data Repository = Repository-  { repoVcs :: Vcs-  -- ^ Specifies the version control system in use.--  , repoKind :: RepoKind-  -- ^ Whether this is a @head@, which refers to the latest-  -- development branch of the package, or a @this@, which contains-  -- the sources for this release of the package.--  , repoLocation :: String-  -- ^ A URL giving the location of the repository.  Will vary by-  -- repository type; for git, you may use a @git://@ URL, for-  -- example.  This field is required.--  , repoBranch :: String-  -- ^ For example, CVS, SVN, and git can have multiple branches in-  -- a single repository; darcs cannot.  If you need to specify a-  -- branch, do it here.  This field is optional.--  , repoTag :: String-  -- ^ A repository tag.  It is required for the @this@ repo kind.-  -- It is optional for the @head@ repo kind.  The tag will often be-  -- a version number of some kind and should point the user to the-  -- sources in the repo that correspond to a particular package-  -- version.--  , repoSubdir :: String-  -- ^ Some projects put the sources for multiple packages under a-  -- single source repository. This field lets you specify the-  -- relative path from the root of the repository to the top-  -- directory for the package, ie the directory containing the-  -- package’s .cabal file.-  ---  -- This field is optional. It defaults to empty which corresponds-  -- to the root directory of the repository.--  } deriving (Eq, Ord, Show)---- | A single flag.-data Flag = Flag-  { flName :: String-  -- ^ The name of the flag; other parts of the Cabal file refer to-  -- the flag using this name.--  , flDescription :: String-  -- ^ A description of the flag (typically one line long.)--  , flDefault :: Bool-  -- ^ Default value of this flag.--  , flManual :: Bool-  -- ^ If True, then Cabal will not change this flag's value as it-  -- tries to build the package.  If False, then Cabal will first-  -- try to satisfy dependencies with the default flag value and-  -- then, if that is not possible, with the negated value.--  } deriving (Eq, Ord, Show)---- | Data for the entire Cabal file.-data Cabal = Cabal-  { cProperties :: Properties-  , cRepositories :: [Repository]-  , cFlags :: [Flag]-  , cLibrary :: Maybe Library-  , cExecutables :: [Executable]-  , cTestSuites :: [TestSuite]-  , cBenchmarks :: [Benchmark]-  } deriving (Eq, Ord, Show)+-- | The Cartel abstract syntax tree+--+-- Use this module if you want access to the data constructors in the+-- AST; the functions and values exported through "Cartel" should be+-- enough for most uses.  Use of this module will not violate any+-- invariants; this stuff is in a separate module merely for the sake+-- of tidiness of the documentation in "Cartel".+--+-- Cabal already has an AST that it uses.  Cartel could, perhaps,+-- have re-used these structures.  Cartel does not do this for three+-- reasons.  First, the Cabal API is a bit untidy, partially because+-- it has to do things that Cartel doesn't have to worry about, but+-- also because the comments in the Cabal modules themselves+-- indicate that the whole thing could use a refactoring.  Second,+-- the Cabal developers make no commitment to keep that API stable.+-- Third, the Cartel API tries only to replicate format of the+-- plain-text Cabal file, which will be much more stable than the+-- Cabal API.+module Cartel.Ast where++import qualified Data.Char as C+import qualified System.FilePath as P+import Data.Word+import System.FilePath+import Data.List (sortBy, intersperse)+import Data.Monoid+import qualified System.Directory as D+import Control.Monad.IO.Class+import Cartel.Types+import Cartel.Betsy++-- * Basic types++-- * Blank++-- | Typeclass for things that can be blank.  More specifically,+-- @blank a@ results in an item that, when rendered in a Cabal file,+-- is the null string.  'blank' can be useful to indicate that you+-- have no options, and you can also use it in combination with record+-- syntax when you want to specify just a few options.++class Blank a where+  blank :: a++-- * Repositories++-- | What kind of VCS repository is this?+data RepoKind++  = Head+  -- ^ The latest development branch of the repository++  | This+  -- ^ The sources for this release of this package.+  deriving (Eq, Ord, Show)++repoHead :: RepoKind+repoHead = Head++repoThis :: RepoKind+repoThis = This++-- | Version control systems.+data Vcs+  = Darcs+  | Git+  | Svn+  | Cvs NonEmptyString+  -- ^ The argument 'String' is the named module+  | Mercurial+  | Bazaar+  | ArchVcs+  | Monotone+  deriving (Eq, Ord, Show)++darcs, git, svn, mercurial, bazaar, archVcs, monotone :: Vcs+cvs+  :: NonEmptyString+  -- ^ The named module+  -> Vcs+darcs = Darcs+git = Git+svn = Svn+cvs = Cvs+mercurial = Mercurial+bazaar = Bazaar+archVcs = ArchVcs+monotone = Monotone++-- | A single @repository@ section.+data Repository = Repository+  { repoVcs :: Maybe Vcs+  -- ^ What kind of 'Vcs' this is.  This is required.++  , repoKind :: Maybe RepoKind+  -- ^ The kind of repository ('repoHead' or 'repoThis').  Required.++  , repoTag :: String+  -- ^ Repository tag.  This is required for the 'repoThis' repository+  -- kind and is optional for the 'repoHead' repository kind.++  , repoLocation :: NonEmptyString+  -- ^ URL for the location of the repository--for example, for a+  -- @darcs@ repo this might be @http:\/\/code.haskell.org\/foo\/@; for+  -- git, this might be @git:\/\/github.com\/foo\/bar.git@.++  , repoBranch :: String+  -- ^ The repository branch.++  , repoSubdir :: String+  -- ^ The repository subdirectory.+  } deriving (Eq, Ord, Show)++instance Blank Repository where+  blank = Repository Nothing Nothing "" "" "" ""++-- | Creates a 'Section' that is a 'Repository' for a Github head.+-- For example, for Cartel, use @githubHead \"massysett\" \"cartel\"@.+githubHead+  :: NonEmptyString+  -- ^ The Github account name+  -> NonEmptyString+  -- ^ The Github project name within the account+  -> Section+githubHead acct proj+  = SecRepo $ blank { repoVcs = Just Git+                    , repoKind = Just Head+                    , repoLocation = loc+                    }+  where+    loc = "https://github.com/" ++ acct ++ "/" ++ proj ++ ".git"++-- | Creates a 'Section' for a repository.+repository :: Repository -> Section+repository = SecRepo++-- * Logicals++-- | Condition; for use in a 'CondTree' and ultimately in a+-- 'CondBlock', which implements Cabal's @if-then-else@ feature.+data CondLeaf+  = OS NonEmptyString+  -- ^ Tests if the current operating system is the given name,+  -- case-insensitive+  | Arch NonEmptyString+  -- ^ Tests if the current architecture is the given name,+  -- case-insensitive+  | Impl Compiler Constraint+  -- ^ Tests for the configured Haskell implementation+  | CFlag FlagName+  -- ^ Evalutes to the current assignment of the flag of the given+  -- name.  To get a flag, use 'makeFlag'.+  | CTrue+  -- ^ Always True+  | CFalse+  -- ^ Always False+  deriving (Eq, Ord, Show)++-- | For use in a 'CondTree' or 'ConstrTree'.+data Logical+  = Or+  | And+  deriving (Eq, Ord, Show)++-- | Expresses a tree of constraints.  This is how you represent+-- more complex dependency relationships.  For example, to represent+-- @less than or equal to version 1.0@, use+--+-- >> let one = Version [1,0]+-- >> in Branch Or (Leaf (Constraint LT one)) (Leaf (Constraint EQ one))+data ConstrTree+  = Leaf Ordering Version+  | Branch Logical ConstrTree ConstrTree+  deriving (Eq, Ord, Show)+++-- | Expresses any version constraint, including no version+-- constraint.+data Constraint+  = AnyVersion+  | Constrained ConstrTree+  deriving (Eq, Ord, Show)++-- | Conditions.  Ultimately these are used in a 'CondBlock'.+data Condition+  = CLeaf CondLeaf+  | CBranch Logical Condition Condition+  | CNegate Condition+  deriving (Eq, Ord, Show)++-- | Like 'not', which is what I would have named it but for the+-- conflict.  Only 'Condition's have this sort of operation; Cabal+-- does not have a (documented, at least) way to express this for+-- package constraints.+invert :: Condition -> Condition+invert = CNegate++-- | Conditional blocks.  These implement the @if-then-else@ feature+-- of Cabal files.  You must have at least one thing to do if the+-- condition is True; the if-false block is optional.+data CondBlock a = CondBlock+  { condIf :: Condition+  -- ^ If this condition is true . . . +  , ifTrue :: (a, [a])+  -- ^ . . . then do this . . .+  , ifFalse :: [a]+  -- ^ . . . or if it's false, do this instead.+  } deriving (Eq, Ord, Show)++instance Functor CondBlock where+  fmap f (CondBlock i (t1, ts) flse)+    = CondBlock i (f t1, fmap f ts) (fmap f flse)++class LogicTree a where+  (&&&) :: a -> a -> a+  (|||) :: a -> a -> a++instance LogicTree Constraint where+  AnyVersion &&& x = x+  Constrained x &&& AnyVersion = Constrained x+  Constrained x &&& Constrained y = Constrained (x &&& y)++  AnyVersion ||| _ = AnyVersion+  Constrained _ ||| AnyVersion = AnyVersion+  Constrained x ||| Constrained y = Constrained (x ||| y)++instance LogicTree ConstrTree where+  l &&& r = Branch And l r+  l ||| r = Branch Or l r++instance LogicTree Condition where+  l &&& r = CBranch And l r+  l ||| r = CBranch Or l r++infixr 3 &&&+infixr 2 |||++-- | Less than+lt :: Version -> Constraint+lt = Constrained . Leaf LT++-- | Greater than+gt :: Version -> Constraint+gt = Constrained . Leaf GT++-- | Equal to+eq :: Version -> Constraint+eq = Constrained . Leaf EQ++-- | Less than or equal to+ltEq :: Version -> Constraint+ltEq v = lt v ||| eq v++-- | Greater than or equal to+gtEq :: Version -> Constraint+gtEq v = gt v ||| eq v++-- | Matches any version at all (in a Cabal file, this is represented+-- as an empty string).+anyVersion :: Constraint+anyVersion = AnyVersion+++-- | Creates a package interval that is closed on the left, open on+-- the right.  Useful for the common case under the PVP to specify+-- that you depend on a version that is at least a particular+-- version, but less than another version.+--+-- > closedOpen "bytestring" [0,17] [0,19] ==> bytestring >= 0.17 && < 0.19++closedOpen+  :: NonEmptyString+  -- ^ Package name+  -> Version+  -- ^ Version number for lower bound+  -> Version+  -- ^ Version number for upper bound+  -> Package+  -- ^ Resulting 'Package'+closedOpen n l u = Package n (gtEq l &&& lt u)++-- | Specifies a particular API version.  Useful to lock your+-- package dependencies down to a particular API version.+--+-- > apiVersion "base" [1] ==> base >= 1 && < 2+-- > apiVersion "base" [1,2] ==> base >= 1.2 && < 1.3+-- > apiVersion "base" [1,2,3] ==> base >= 1.2.3 && < 1.2.4++apiVersion :: NonEmptyString -> Version -> Package+apiVersion n v = closedOpen n v u+  where+    u = case v of+      [] -> error "apiVersion: requires a non-empty list argument"+      _ -> init v ++ [succ (last v)]++-- | Depends on the version given, up to the next breaking API+-- change.+--+-- > nextBreaking "base" [4] ==> base >= 4 && < 4.1+-- > nextBreaking "base" [4,1] ==> base >= 4.1 && < 4.2+-- > nextBreaking "base" [4,7,0,0] ==> base >= 4.7.0.0 && < 4.8++nextBreaking+  :: NonEmptyString+  -> Version+  -> Package+nextBreaking n v = closedOpen n v u+  where+    u = case v of+      [] -> error "nextBreaking: requires a non-empty list argument"+      x:[] -> [x, 1]+      x:y:_ -> x : succ y : []++-- | Depends on the version given, up to the next time the first+-- digit increments.  Useful for @base@.+--+-- > nextBreaking "base" [4] ==> base >= 4 && < 5++nextMajor+  :: NonEmptyString+  -> Version+  -> Package+nextMajor n v = closedOpen n v u+  where+    u = case v of+      [] -> error "nextMajor: requires a non-empty list argument"+      x:_ -> succ x : []++-- | Depends on exactly this version only.+--+-- > exactly "base" [4,5,0,0] ==> base ==4.5.0.0++exactly :: NonEmptyString -> Version -> Package+exactly n v = Package n (eq v)++-- | Allows any version of a package.++unconstrained+  :: NonEmptyString+  -- ^ Name of package+  -> Package+unconstrained nm = Package nm anyVersion++-- | Builds @if@ statements.  For example:+--+-- > condition (flag "buildExe") (buildable True, []) [buildable False]+--+-- A little more complicated:+--+-- > condition (flag "buildExe" &&& system "windows")+-- >   (buildable True, []) [buildable False]+condBlock+  :: HasBuildInfo a+  => Condition+  -- ^ Condition to satisfy+  -> (a, [a])+  -- ^ Use these results if condition is true+  -> [a]+  -- ^ Use these results if condition if false+  -> a+condBlock tree ifT ifF =+  conditional $ CondBlock tree ifT ifF++-- | Operating system; tested against @System.Info.os@ on the+-- target system.+system :: NonEmptyString -> Condition+system = CLeaf . OS++-- | Argument is matched against @System.Info.arch@ on the target+-- system.+arch :: NonEmptyString -> Condition+arch = CLeaf . Arch++-- | Tests for the configured Haskell implementation.+impl :: Compiler -> Constraint -> Condition+impl cm cn = CLeaf $ Impl cm cn++-- | Evaluates to the current assignment of the flag of the given+-- name.  Flag names are case insensitive.  Testing for flags that+-- have not been introduced with a flag section is an error.+flag :: FlagName -> Condition+flag = CLeaf . CFlag++-- | Always true.+true :: Condition+true = CLeaf CTrue++-- | Always false.+false :: Condition+false = CLeaf CFalse++-- * Versions++-- | A version number.  The Cabal documentation says this+-- \"usually\" consists of a sequence of natural numbers separated+-- by dots.  Though this suggests that a version number could+-- contain something other than natural numbers, in fact the types+-- in the Cabal library do not allow anything other than numbers and+-- you will get a parse error if you try to use anything else.+--+-- Therefore Cartel's 'Version' type only allows a list of 'Word', as+-- each number cannot be negative.  In addition, this list should+-- never be empty.  However, this is just a type synonym for a list of+-- 'Word', so the type system does not enforce the requirement that+-- this list be non-empty.+type Version = [Word]++-- * Packages++-- | A single package, consisting of a package name and an optional+-- set of constraints.  Used when specifying 'buildDepends',+-- 'buildTools', and 'pkgConfigDepends'.+--+-- Some functions exist to ease the creation of a 'Package'.  For a+-- package with no version constrains, simply do something like+-- @'unconstrained' \"QuickCheck\"@.  Common use cases are+-- covered in the functions in the \"Package Helpers\" section below.+-- For something more complicated, use the functions in the+-- \"Logicals\" sections above, along with the '&&&' and '|||'+-- combinators, to create your own 'Constraint' and then use it with+-- the 'package' function.++data Package = Package NonEmptyString Constraint+  deriving (Eq, Ord, Show)++-- | Builds a 'Package'.+package+  :: NonEmptyString+  -- ^ The name of the package+  -> Constraint+  -- ^ Version constraints.+  -> Package+package = Package++-- * Build information++-- | Default language.  Currently not documented, see+--+-- <https://github.com/haskell/cabal/issues/1894>+data DefaultLanguage+  = Haskell98+  | Haskell2010+  deriving (Eq, Ord, Show)++-- | Sets Haskell 98 as the @default-language@.+--+-- Currently not documented in Cabal, see+--+-- <https://github.com/haskell/cabal/issues/1894>+haskell98 :: HasBuildInfo a => a+haskell98 = buildInfo $ DefaultLanguage Haskell98++-- | Sets Haskell 2010 as the @default-language@.+--+-- Currently not documented in Cabal, see+--+-- <https://github.com/haskell/cabal/issues/1894>+haskell2010 :: HasBuildInfo a => a+haskell2010 = buildInfo $ DefaultLanguage Haskell2010++-- | A single field of build information.  This can appear in a+-- @Library@, 'Executable', 'TestSuite', or 'Benchmark'.+data BuildInfoField+  = BuildDepends [Package]+  -- ^ A list of packages needed to build this component++  | OtherModules [NonEmptyString]+  -- ^ Modules used but not exposed.  For libraries, these are+  -- hidden modules; for executable, these are auxiliary modules to+  -- be linked with the file in the @main-is@ field.+  --+  -- 'Cartel.Tools.modules' can help greatly with maintenance of+  -- this field.++  | HsSourceDirs [NonEmptyString]+  -- ^ Root directories for the module hierarchy++  | Extensions [NonEmptyString]+  -- ^ Haskell extensions used by every module.++  | BuildTools [Package]+  -- ^ Programs needed to build this package, such as c2hs.++  | Buildable Bool+  -- ^ Is this component buildable?++  | GHCOptions [NonEmptyString]+  | GHCProfOptions [NonEmptyString]+  | GHCSharedOptions [NonEmptyString]+  | HugsOptions [NonEmptyString]+  | Nhc98Options [NonEmptyString]+  | Includes [NonEmptyString]+  -- ^ Header files to be included in any compilations via C.+  -- Applies to both header files that are already installed on the+  -- system and to those coming with the package to be installed.++  | InstallIncludes [NonEmptyString]+  -- ^ Header files to be installed into @$libdir/includes@ when the+  -- package is installed.  These files should be found in relative+  -- to the top of the source tree or relative to one of the+  -- directories listed in @include-dirs@.++  | IncludeDirs [NonEmptyString]+  -- ^ List of diretories to search for header files when dealing+  -- with C compilations.++  | CSources [NonEmptyString]+  -- ^ C sources to be compiled and lined with the Haskell files.++  | ExtraLibraries [NonEmptyString]+  -- ^ Extra libraries to link with.++  | ExtraLibDirs [NonEmptyString]+  -- ^ Directories to search for libraries.++  | CCOptions [NonEmptyString]+  -- ^ C Compiler options.++  | CPPOptions [NonEmptyString]+  -- ^ C Preprocessor options.  Undocumented, see+  -- <https://github.com/haskell/cabal/issues/646>++  | LDOptions [NonEmptyString]+  -- ^ Linker options.++  | PkgConfigDepends [Package]+  -- ^ List of pkg-config packages needed to build this component.++  | Frameworks [NonEmptyString]+  -- ^ OS X frameworks.++  | DefaultLanguage DefaultLanguage++  deriving (Eq, Ord, Show)++-- * Libraries++-- | A field in the @Library@ section of the Cabal file.  A+-- @Library@ section can have multiple fields.+data LibraryField+  = ExposedModules [NonEmptyString]+  -- ^ Exposed modules.  'modules' can help you generate this, without+  -- you having to manually list each module and keep the list up to+  -- date.++  | Exposed Bool+  -- ^ Is the library exposed?  GHC can hide libraries.++  | LibConditional (CondBlock LibraryField)+  -- ^ The @Library@ section can contain conditional blocks.++  | LibInfo BuildInfoField+  -- ^ The @Library@ section can contain build information.++  deriving (Eq, Ord, Show)++-- | Whether a library is exposed.  GHC can hide libraries.+exposed :: Bool -> LibraryField+exposed = Exposed++-- | A library's exposed modules.  'modules' can help you generate+-- this, without you having to manually list each module and keep the+-- list up to date.+exposedModules :: [NonEmptyString] -> LibraryField+exposedModules = ExposedModules++-- * Executables++-- | A single field in an 'Executable' section.  An 'Executable'+-- section may have multiple fields.+data ExecutableField+  = ExeConditional (CondBlock ExecutableField)+  -- ^ An 'Executable' section can contain conditional blocks.++  | ExeInfo BuildInfoField+  -- ^ An 'Executable' section can contain one or more build+  -- information fields.++  | ExeMainIs NonEmptyString+  -- ^ The name of the @.hs@ or @.lhs@ file containing the @Main@+  -- module.  Note that it is the @.hs@ filename that must be listed,+  -- even if that file is generated using a preprocessor.  The source+  -- file must be relative to one of the directories listed in+  -- 'hsSourceDirs'.++  deriving (Eq, Ord, Show)++-- | An entire @Executable@ section.+data Executable = Executable+  { exeName :: NonEmptyString+  -- ^ The name of the executable that Cabal will build.+  , exeFields :: [ExecutableField]+  -- ^ An executable can contain zero or more 'ExecutableField's.+  } deriving (Eq, Ord, Show)++-- | Builds a 'Section' for executable files.+executable+  :: NonEmptyString+  -- ^ The name of the executable that Cabal will build.+  -> [ExecutableField]+  -- ^ An executable can contain zero or more 'ExecutableField's.+  -> Section+executable nm fs = SecExe (Executable nm fs)++-- * Test suites++-- | What kind of test suite is this?+data TestSuiteType+  = ExitcodeStdio+  -- ^ An @exitcode-stdio-1.0@ test.  The @String@ is the name of+  -- the file containing the executable code.  In this case, the+  -- @test-main-is@ field is required.++  | Detailed+  -- ^ The @detailed-0.9@ test.  In this case, the @test-module@+  -- field is required.+  deriving (Eq, Ord, Show)++detailed :: TestSuiteField+detailed = TestSuiteType Detailed++-- | A single field value in a 'TestSuite' section.  A single test+-- suite section may contain mulitple fields.+data TestSuiteField+  = TestConditional (CondBlock TestSuiteField)+  -- ^ The 'TestSuite' may contain zero or more conditional blocks.+  | TestInfo BuildInfoField+  -- ^ The 'TestSuite' may contain zero or more build information+  -- fields.+  | TestMainIs NonEmptyString+  -- ^ The name of the @.hs@ or @.lhs@ file containing the @Main@+  -- module.  Note that it is the @.hs@ filename that must be listed,+  -- even if that file is generated using a preprocessor.  The source+  -- file must be relative to one of the directories listed in+  -- 'hsSourceDirs'.+  --+  -- This is required when using 'ExitcodeStdio' and disallowed when+  -- using 'Detailed'.++  | TestSuiteType TestSuiteType+  | TestModule NonEmptyString+  -- ^ The module exporting the @tests@ symbol.  This is required when+  -- using 'Detailed' and disallowed when using 'ExitcodeStdio'.++  deriving (Eq, Ord, Show)++-- | The module exporting the @tests@ symbol.  This is required when+-- using 'Detailed' and disallowed when using 'ExitcodeStdio'.+testModule :: NonEmptyString -> TestSuiteField+testModule = TestModule++-- | An entire @test-suite@ section.+data TestSuite = TestSuite+  { testSuiteName :: NonEmptyString+  -- ^ The executable name for the resulting test suite+  , testSuiteFields :: [TestSuiteField]+  -- ^ Zero or more 'TestSuiteField's.+  } deriving (Eq, Ord, Show)++-- | Builds a 'Section' for test suites.+testSuite+  :: NonEmptyString+  -- ^ The executable name for the resulting test suite+  -> [TestSuiteField]+  -- ^ Zero or more 'TestSuiteField's.+  -> Section+testSuite nm fs = SecTest (TestSuite nm fs)++-- * Benchmarks++data BenchmarkType+  = BenchExitCode+  -- ^ @exitcode-stdio-1.0@, currently the only supported benchmark interface.+  deriving (Eq, Ord, Show)++-- | A single field in a @Benchmark@ section.+data BenchmarkField+  = BenchmarkConditional (CondBlock BenchmarkField)+  | BenchmarkInfo BuildInfoField+  | BenchmarkType BenchmarkType+  | BenchmarkMainIs NonEmptyString+  -- ^ The name of the @.hs@ or @.lhs@ file containing the @Main@+  -- module.  Note that it is the @.hs@ filename that must be listed,+  -- even if that file is generated using a preprocessor.  The source+  -- file must be relative to one of the directories listed in+  -- 'hsSourceDirs'.+  deriving (Eq, Ord, Show)++-- | An entire @Benchmark@ section.+data Benchmark = Benchmark+  { benchmarkName :: NonEmptyString+  -- ^ The name of the executable file that will be the benchmark+  , benchmarkFields :: [BenchmarkField]+  -- ^ Zero or more benchmark fields.+  } deriving (Eq, Ord, Show)++-- | Builds a 'Section' for benchmarks.+benchmark+  :: NonEmptyString+  -- ^ The name of the executable file that will be the benchmark+  -> [BenchmarkField]+  -- ^ Zero or more benchmark fields.+  -> Section+benchmark nm fs = SecBench (Benchmark nm fs)++-- * Overloaded fields++-- | Things that can be an item in a build information field in a+-- Cabal file.+class HasBuildInfo a where++  -- | Takes a conditional block and wraps it in the field type.+  conditional :: CondBlock a -> a++  -- | Takes a build information field and wraps it in the field+  -- type.+  buildInfo :: BuildInfoField -> a++instance HasBuildInfo LibraryField where+  conditional = LibConditional+  buildInfo = LibInfo++instance HasBuildInfo ExecutableField where+  conditional = ExeConditional+  buildInfo = ExeInfo++instance HasBuildInfo TestSuiteField where+  conditional = TestConditional+  buildInfo = TestInfo++instance HasBuildInfo BenchmarkField where+  conditional = BenchmarkConditional+  buildInfo = BenchmarkInfo++-- # Build info helpers++-- ^ A list of packages needed to build this component+buildDepends :: HasBuildInfo a => [Package] -> a+buildDepends = buildInfo . BuildDepends++-- ^ Modules used but not exposed.  For libraries, these are+-- hidden modules; for executable, these are auxiliary modules to+-- be linked with the file in the @main-is@ field.+--+-- 'modules' can help greatly with maintenance of+-- this field.++otherModules :: HasBuildInfo a => [NonEmptyString] -> a+otherModules = buildInfo . OtherModules++-- ^ Root directories for the module hierarchy+hsSourceDirs :: HasBuildInfo a => [NonEmptyString] -> a+hsSourceDirs = buildInfo . HsSourceDirs++-- ^ Haskell extensions used by every module.+extensions :: HasBuildInfo a => [NonEmptyString] -> a+extensions = buildInfo . Extensions++-- | Programs needed to build this package, such as c2hs.+buildTools :: HasBuildInfo a => [Package] -> a+buildTools = buildInfo . BuildTools++-- | Is this component buildable?+buildable :: HasBuildInfo a => Bool -> a+buildable = buildInfo . Buildable++ghcOptions :: HasBuildInfo a => [NonEmptyString] -> a+ghcOptions = buildInfo . GHCOptions++ghcProfOptions :: HasBuildInfo a => [NonEmptyString] -> a+ghcProfOptions = buildInfo . GHCProfOptions++ghcSharedOptions :: HasBuildInfo a => [NonEmptyString] -> a+ghcSharedOptions = buildInfo . GHCSharedOptions++hugsOptions :: HasBuildInfo a => [NonEmptyString] -> a+hugsOptions = buildInfo . HugsOptions++nhc98Options :: HasBuildInfo a => [NonEmptyString] -> a+nhc98Options = buildInfo . Nhc98Options++-- | Header files to be included in any compilations via C.+-- Applies to both header files that are already installed on the+-- system and to those coming with the package to be installed.++includes :: HasBuildInfo a => [NonEmptyString] -> a+includes = buildInfo . Includes++-- | Header files to be installed into @$libdir/includes@ when the+-- package is installed.  These files should be found in relative+-- to the top of the source tree or relative to one of the+-- directories listed in @include-dirs@.+installIncludes :: HasBuildInfo a => [NonEmptyString] -> a+installIncludes = buildInfo . InstallIncludes++-- | List of diretories to search for header files when dealing+-- with C compilations.+includeDirs :: HasBuildInfo a => [NonEmptyString] -> a+includeDirs = buildInfo . IncludeDirs++-- | C sources to be compiled and lined with the Haskell files.+cSources :: HasBuildInfo a => [NonEmptyString] -> a+cSources = buildInfo . CSources++-- | Extra libraries to link with.+extraLibraries :: HasBuildInfo a => [NonEmptyString] -> a+extraLibraries = buildInfo . ExtraLibraries++-- | Directories to search for libraries.+extraLibDirs :: HasBuildInfo a => [NonEmptyString] -> a+extraLibDirs = buildInfo . ExtraLibDirs++-- | C Compiler options.+ccOptions :: HasBuildInfo a => [NonEmptyString] -> a+ccOptions = buildInfo . CCOptions++-- | C Preprocessor options.  Undocumented, see+-- <https://github.com/haskell/cabal/issues/646>+cppOptions :: HasBuildInfo a => [NonEmptyString] -> a+cppOptions = buildInfo . CPPOptions++-- | Linker options.+ldOptions :: HasBuildInfo a => [NonEmptyString] -> a+ldOptions = buildInfo . LDOptions++-- | List of pkg-config packages needed to build this component.+pkgConfigDepends :: HasBuildInfo a => [Package] -> a+pkgConfigDepends = buildInfo . PkgConfigDepends++-- | OS X frameworks.+frameworks :: HasBuildInfo a => [NonEmptyString] -> a+frameworks = buildInfo . Frameworks++-- | Sections that build executables.  These are the 'Executable',+-- 'Benchmark', and 'TestSuite' sections.+class BuildsExe a where+  mainIs :: NonEmptyString -> a+  -- ^ Overloaded function allowing you to use 'mainIs' for an+  -- 'Executable', 'Benchmark', or 'TestSuite' section.++instance BuildsExe ExecutableField where+  mainIs = ExeMainIs++instance BuildsExe TestSuiteField where+  mainIs = TestMainIs++instance BuildsExe BenchmarkField where+  mainIs = BenchmarkMainIs++-- | Sections that build executables that can be @exitcode-stdio-1.0@.+-- These are the 'Benchmark' and 'TestSuite' sections.+class BuildsExitcode a where+  exitcodeStdio :: a+  -- ^ Returns a field that is @exitcode-stdio-1.0@++instance BuildsExitcode TestSuiteField where+  exitcodeStdio = TestSuiteType ExitcodeStdio++instance BuildsExitcode BenchmarkField where+  exitcodeStdio = BenchmarkType BenchExitCode++-- | Builds two fields.  The first indicates that this is an+-- @exitcode-stdio-1.0@ executable; the second is the appropriate+-- @main-is@ field.+exitcodeFields+  :: (BuildsExitcode a, BuildsExe a)+  => NonEmptyString+  -- ^ Value for @main-is@ field+  -> [a]+exitcodeFields m = [exitcodeStdio, mainIs m]++-- * Getting module lists++-- | Gets all Haskell modules in a given directory tree.  Allows you+-- to specify what extensions you are interested in.  For this to work+-- best, you will want to keep all your library modules in their own+-- directory, such as @lib/@.  You can also separate executables and+-- test suites this way.  'hsSourceDirs' will then tell Cabal to use+-- these directories.++modulesWithExtensions+  :: MonadIO m+  => [NonEmptyString]+  -- ^ Look for files that have these extensions.  'fileExtensions'+  -- covers the most common cases.  Files without one of these+  -- extensions are ignored.  Files and directories that do not begin+  -- with an uppercase letter are ignored.  (This also ignores files+  -- that start with a dot.)  Directories with a dot anywhere in the+  -- name are ignored.+  --+  -- Do not include the leading dot with the extension.  For example,+  -- to look for Haskell and literate Haskell files only, use+  --+  -- > ["hs", "lhs"]++  -> FilePath+  -- ^ Start searching within this directory.++  -> Betsy m [NonEmptyString]+  -- ^ A list of Haskell modules in the given directory tree.  The+  -- file contents are not examined; only the file names matter.+  -- Returned as a list of dotted names.++modulesWithExtensions exts fp+  = liftIO $ modulesWithExtensionsIO exts fp+++-- | Same as+--+-- @+-- 'modulesWithExtensions' 'fileExtensions'+-- @+modules+  :: MonadIO m+  => FilePath+  -> Betsy m [NonEmptyString]+modules = modulesWithExtensions fileExtensions++-- | Common extensions of Haskell files and files that are+-- preprocessed into Haskell files.  Includes:+--+-- * hs (Haskell)+--+-- * lhs (literate Haskell)+--+-- * gc (greencard)+--+-- * chs (c2hs)+--+-- * hsc (hsc2hs)+--+-- * y and ly (happy)+--+-- * x (alex)+--+-- * cpphs++fileExtensions :: [String]+fileExtensions =+  [ "hs"+  , "lhs"+  , "gc"+  , "chs"+  , "hsc"+  , "y"+  , "ly"+  , "x"+  , "cpphs"+  ]++interestingFile+  :: [String]+  -- ^ Extensions of module files+  -> FilePath+  -> Bool++interestingFile xs s = case s of+  "" -> False+  x:_+    | not (C.isUpper x) -> False+    | otherwise -> let mayExt = P.takeExtension s+                   in case mayExt of+                       [] -> False+                       _ : ext -> ext `elem` xs++interestingDir :: FilePath -> Bool+interestingDir p = case p of+  [] -> False+  x:_+    | not (C.isUpper x) -> False+    | otherwise -> not $ '.' `elem` p++-- | Gets all Haskell modules in a given directory tree.  Only files+-- with one of the extensions listed in 'fileExtensions' are+-- returned.  Files and directories that do not begin with an+-- uppercase letter are ignored.  (This also ignores files that+-- start with a dot.)  Directories with a dot anywhere in the name+-- are ignored.++modulesIO+  :: FilePath+  -- ^ Start searching within this directory.+  -> IO [String]+  -- ^ A list of Haskell modules in the given directory tree.  The+  -- file contents are not examined; only the file names matter.+  -- Returned as a list of dotted names.+modulesIO = modulesWithExtensionsIO fileExtensions+++-- | Gets all Haskell modules in a given directory tree.  Allows you+-- to specify what extensions you are interested in.++modulesWithExtensionsIO+  :: [String]+  -- ^ Look for files that have one of these extensions.+  -- 'fileExtensions' covers the most common cases.  Files without+  -- one of these extensions are ignored.  Files and directories+  -- that do not begin with an uppercase letter are ignored.  (This+  -- also ignores files that start with a dot.)  Directories with a+  -- dot anywhere in the name are ignored.+  --+  -- Do not include the leading dot with the extension.  For+  -- example, to look for Haskell and literate Haskell files only, use+  --+  -- > ["hs", "lhs"]++  -> FilePath+  -- ^ Start searching within this directory.++  -> IO [String]+  -- ^ A list of Haskell modules in the given directory tree.  The+  -- file contents are not examined; only the file names matter.+  -- Returned as a list of dotted names.++modulesWithExtensionsIO exts start+  = fmap (map modName . sortBy sorter . map reverse)+  $ modulesInDir exts start []+  where+    modName = concat . intersperse "."++sorter :: [String] -> [String] -> Ordering+sorter x y = mconcat (zipWith compare x y) <> compare lenX lenY+  where+    (lenX, lenY) = (length x, length y)++modulesInDir+  :: [String]+  -- ^ Extensions of module files+  -> FilePath+  -- Search is rooted in this directory+  -> [FilePath]+  -- ^ Stack of directories we're in+  -> IO [[String]]+  -- ^ Returns a list of modules in this directory.+modulesInDir exts start dirs = do+  cs <- D.getDirectoryContents (start </> P.joinPath (reverse dirs))+  fmap concat . mapM (processFile exts start dirs) $ cs++processFile+  :: [String]+  -- ^ Extensions of module files+  -> FilePath+  -- ^ Search is rooted in this directory+  -> [FilePath]+  -- Stack of directories we're in, including current directory+  -> FilePath+  -- ^ Interesting file under investigation+  -> IO [[String]]+processFile exts start dirs this = do+  isDir <- D.doesDirectoryExist+    (start </> (P.joinPath . reverse $ this : dirs))+  if isDir+    then if interestingDir this+          then modulesInDir exts start (this : dirs)+          else return []+    else return $ if interestingFile exts this+          then [(P.dropExtension this : dirs)]+          else []++-- * Section++-- | A single section in a Cabal file; this may be a source+-- repository, executable, test suite, or benchmark.  You build a+-- 'Section' with the 'repository', 'executable', 'testSuite', and+-- 'benchmark' functions.+data Section+  = SecRepo Repository+  | SecExe Executable+  | SecTest TestSuite+  | SecBench Benchmark+  deriving (Eq, Ord, Show)++-- * Properties++data BuildType+  = Simple+  | Configure+  | Make+  | Custom+  deriving (Eq, Ord, Show)++simple, configure, make, custom :: BuildType+simple = Simple+configure = Configure+make = Make+custom = Custom++data License+  = GPL+  | AGPL+  | LGPL+  | BSD2+  | BSD3+  | BSD4+  | MIT+  | MPL+  | Apache+  | PublicDomain+  | AllRightsReserved+  | OtherLicense+  deriving (Eq, Ord, Show)++gpl, agpl, lgpl, bsd2, bsd3, bsd4, mit, mpl, apache, publicDomain,+  allRightsReserved, otherLicense :: License++gpl = GPL+agpl = AGPL+lgpl = LGPL+bsd2 = BSD2+bsd3 = BSD3+bsd4 = BSD4+mit = MIT+mpl = MPL+apache = Apache+publicDomain = PublicDomain+allRightsReserved = AllRightsReserved+otherLicense = OtherLicense++data Compiler+  = GHC+  | NHC+  | YHC+  | Hugs+  | Helium+  | JHC+  | LHC+  deriving (Eq, Ord, Show)++ghc, nhc, yhc, hugs, helium, jhc, lhc :: Compiler+ghc = GHC+nhc = NHC+yhc = YHC+hugs = Hugs+helium = Helium+jhc = JHC+lhc = LHC++-- | Global package properties.+data Properties = Properties+  { name :: String+  , version :: Version+  , cabalVersion :: Maybe (Word, Word)+  , buildType :: Maybe BuildType+  , license :: Maybe License+  , licenseFile :: String+  , licenseFiles :: [NonEmptyString]+  , copyright :: String+  , author :: String+  , maintainer :: String+  , stability :: String+  , homepage :: String+  , bugReports :: String+  , packageUrl :: String+  , synopsis :: String+  , description :: [String]+  , category :: String+  -- ^ According to the \"Developing Cabal Packages\" document, this+  -- should simply be an email address.+  , testedWith :: [(Compiler, Constraint)]+  , dataFiles :: [NonEmptyString]+  , dataDir :: String+  , extraSourceFiles :: [NonEmptyString]+  , extraDocFiles :: [NonEmptyString]+  , extraTmpFiles :: [NonEmptyString]+  } deriving (Eq, Ord, Show)++instance Blank Properties where+  blank = Properties+    { name = ""+    , version = []+    , cabalVersion = Nothing+    , buildType = Nothing+    , license = Nothing+    , licenseFile = ""+    , licenseFiles = []+    , copyright = ""+    , author = ""+    , maintainer = ""+    , stability = ""+    , homepage = ""+    , bugReports = ""+    , packageUrl = ""+    , synopsis = ""+    , description = []+    , category = ""+    , testedWith = []+    , dataFiles = []+    , dataDir = ""+    , extraSourceFiles = []+    , extraDocFiles = []+    , extraTmpFiles = []+    }++-- * Cabal++-- | Represents an entire Cabal file.+data Cabal = Cabal+  { properties :: Properties+  , library :: [LibraryField]+  , sections :: [Section]+  } deriving (Eq, Ord, Show)++-- | Creates a 'Cabal' value when applied to package properties, any+-- applicable library fields, and any sections.+cabal :: Properties -> [LibraryField] -> [Section] -> Cabal+cabal = Cabal++instance Blank Cabal where+  blank = Cabal blank [] []
+ lib/Cartel/Betsy.hs view
@@ -0,0 +1,15 @@+-- | Public interface for 'Betsy', the Cartel flag maker.  Simply+-- re-exports safe bindings from "Cartel.Betsy.Internal".+module Cartel.Betsy+  ( FlagName+  , flagNameHead+  , flagNameTail+  , FlagOpts(..)+  , Betsy+  , Error(..)+  , runBetsy+  , makeFlag+  , currentFlags+  ) where++import Cartel.Betsy.Internal
+ lib/Cartel/Betsy/Internal.hs view
@@ -0,0 +1,132 @@+-- | Internal workings of 'Betsy', the Cartel flag maker.  Use of this+-- module may break 'Betsy' invariants.+module Cartel.Betsy.Internal where++import Control.Monad+import Control.Monad.IO.Class+import Control.Monad.Trans.Class+import Cartel.Types+import Control.Applicative++-- | Errors that may result from running a 'Betsy' computation.+data Error+  = DuplicateFlag FlagName+  -- ^ The user requested creation of a duplicate flag.+  | Failed String+  -- ^ 'fail' was invoked.+  | EmptyFlagName+  -- ^ The user requested creation of a flag with an empty name.+  deriving (Eq, Ord, Show)++renderError :: Error -> String+renderError e = unlines $+  "Error while attempting to generate Cabal file from Cartel source."+  : case e of+      DuplicateFlag (FlagName c cs) ->+        ["Duplicated flag: " ++ (c:cs)]+      Failed s -> ["The \"fail\" function was invoked: " ++ s]+      EmptyFlagName -> ["Empty flag name"]++-- | Internal state maintained in the 'Betsy' type.+data State = State [(FlagName, FlagOpts)]+  deriving (Eq, Ord, Show)++-- | Computations that can create and use Cabal flags.  Use of this+-- type, along with the 'Cartel.defaultMain' function ensures that any+-- 'FlagName' you use has been properly set up by using 'makeFlag'.+-- That way, you don't use flags in a 'Cartel.flag' without actually+-- declaring the flag.  When 'Cartel.defaultMain' creates your Cabal+-- file, it will print the necessary @Flag@ sections.+--+-- 'Betsy' is parameterized on a type, @m@.  When this type is a+-- monad, 'Betsy' is also a monad, allowing you to use use the usual+-- monad combinators and @do@ notation.  'Betsy' is also a monad transformer.++newtype Betsy m a = Betsy (State -> m (Either Error (a, State)))++instance Monad m => Monad (Betsy m) where+  return a = Betsy $ \s -> return (Right (a, s))+  (Betsy l) >>= f = Betsy $ \s -> do+    ei <- l s+    case ei of+      Left e -> return (Left e)+      Right (g, s') -> do+        let Betsy r = f g+        r s'+  fail s = Betsy $ \_ -> return (Left (Failed s))++instance Functor m => Functor (Betsy m) where+  fmap f (Betsy k) = Betsy $ fmap (fmap f') k+    where+      f' ei = fmap (\(a, s) -> (f a, s)) ei++instance (Monad m, Functor m) => Applicative (Betsy m) where+  pure = return+  (<*>) = ap++instance MonadTrans Betsy where+  lift k = Betsy $ \st -> do+    a <- k+    return $ Right (a, st)++instance MonadIO m => MonadIO (Betsy m) where+  liftIO = lift . liftIO++-- ** Flags++-- | Options for flags, except for the flag's name.+data FlagOpts = FlagOpts+  { flagDescription :: String+  -- ^ A one-line description of what the flag does; this is optional.+  , flagDefault :: Bool+  -- ^ Is this flag on or off by default?+  , flagManual :: Bool+  -- ^ If a flag is manual, Cabal will not change its value.  If a+  -- flag is not manual, Cabal will change its value automatically to+  -- attempt to satisfy the package's dependencies.+  } deriving (Eq, Ord, Show)++-- | The name of a flag.  Only 'makeFlag' creates flags; it will+-- return a 'FlagName' to you.  You can then use that 'FlagName' in a+-- conditional using 'Cartel.flag'.+data FlagName = FlagName+  { flagNameHead :: Char+  , flagNameTail :: String+  } deriving (Eq, Ord, Show)++-- | Creates new flags.+makeFlag+  :: Applicative m+  => NonEmptyString+  -- ^ Name of flag+  -> FlagOpts+  -- ^ Options for the flag+  -> Betsy m FlagName+  -- ^ This operation will fail if there is already a flag with the+  -- name you gave.+makeFlag nes opts = Betsy $ \(State fls) -> pure $+  case nes of+    [] -> Left EmptyFlagName+    x:xs ->+      let nm = FlagName x xs+      in case lookup nm fls of+          Nothing ->+            let st' = State ((nm, opts) : fls)+            in Right (nm, st')+          Just _ -> Left (DuplicateFlag nm)++runBetsy+  :: Functor m+  => Betsy m a+  -> m (Either Error (a, [(FlagName, FlagOpts)]))+  -- ^ Returns 'Left' if the making of a flag failed.  Otherwise,+  -- returns the result of the computation, along with a list of all+  -- flags made.+runBetsy (Betsy f) = fmap (fmap g) $ f (State [])+  where+    g (a, State ls) = (a, ls)+++-- | Returns a list of all flags made so far.+currentFlags :: Applicative f => Betsy f [(FlagName, FlagOpts)]+currentFlags = Betsy $ \(State ls) -> pure (Right (ls, State ls))
− lib/Cartel/Empty.hs
@@ -1,79 +0,0 @@--- | Default values for the data types in "Cartel.Ast".  These--- defaults are genrally filled in with blank values.  Use these--- default values where you can; by doing so you help future-proof--- your code.  Use the empty value as a starting point and fill in--- the components of the record that you need.-module Cartel.Empty where--import qualified Cartel.Ast as A--class Empty a where-  empty :: a---- | A default 'A.Properties'.  'A.prCabalVersion' is @(1, 14)@ to--- specify Cabal version 1.14; 'A.prBuildType' is 'A.Simple', and--- 'A.prLicense' is 'A.BSD3'.  All other items are either the empty--- 'String' or the empty list, including the 'A.prVersion', which is--- left empty.-instance Empty A.Properties where-  empty = A.Properties-    { A.prName = ""-    , A.prVersion = A.Version []-    , A.prCabalVersion = (1, 14)-    , A.prBuildType = A.Simple-    , A.prLicense = A.BSD3-    , A.prLicenseFile = ""-    , A.prLicenseFiles = []-    , A.prCopyright = ""-    , A.prAuthor = ""-    , A.prMaintainer = ""-    , A.prStability = ""-    , A.prHomepage = ""-    , A.prBugReports = ""-    , A.prPackageUrl = ""-    , A.prSynopsis = ""-    , A.prDescription = []-    , A.prCategory = ""-    , A.prTestedWith = []-    , A.prDataFiles = []-    , A.prDataDir = ""-    , A.prExtraSourceFiles = []-    , A.prExtraDocFiles = []-    , A.prExtraTmpFiles = []-    }---- | A default 'A.Cabal'.  'empty' is used for 'A.cProperties',--- and 'A.cLibrary' is 'Nothing'; all other lists are empty.-instance Empty A.Cabal where-  empty = A.Cabal-    { A.cProperties = empty-    , A.cRepositories = []-    , A.cFlags = []-    , A.cLibrary = Nothing-    , A.cExecutables = []-    , A.cTestSuites = []-    , A.cBenchmarks = []-    }---- | A default 'A.Repository'.  The VCS type is 'A.Git' and the--- repository kind is 'A.Head'.  All other values are the empty--- string.-instance Empty A.Repository where-  empty = A.Repository-    { A.repoVcs = A.Git-    , A.repoKind = A.Head-    , A.repoLocation = ""-    , A.repoBranch = ""-    , A.repoTag = ""-    , A.repoSubdir = ""-    }---- | A default 'A.Flag'.  'A.flName' and 'A.flDescription' are--- empty; 'A.flDefault' is 'True', and 'A.flManual' is 'False'.-instance Empty A.Flag where-  empty = A.Flag-    { A.flName = ""-    , A.flDescription = ""-    , A.flDefault = True-    , A.flManual = False-    }
+ lib/Cartel/GenCartelCabal.hs view
@@ -0,0 +1,117 @@+-- | This program generates Cartel's own Cabal file.  It's included+-- here in the library to provide a live, type-checked, compilable+-- example.  You will want to look at the source code itself, as the+-- Haddocks won't show you much.++module Cartel.GenCartelCabal where++import Cartel+import qualified Cartel.Version++-- Dependencies++base :: Package+base = closedOpen "base" [4,5,0,0] [4,8]++directory :: Package+directory = closedOpen "directory" [1,1,0,2] [1,3]++filepath :: Package+filepath = closedOpen "filepath" [1,3,0,0] [1,4]++time :: Package+time = closedOpen "time" [1,4] [1,6]++quickcheck :: Package+quickcheck = nextBreaking "QuickCheck" [2,7]++random :: Package+random = closedOpen "random" [1,1] [1,2]++transformers :: Package+transformers = nextBreaking "transformers" [0,4]++multiarg :: Package+multiarg = nextBreaking "multiarg" [0,30,0,0]++quickpull :: Package+quickpull = nextBreaking "quickpull" [0,4,0,0]++libDepends :: [Package]+libDepends =+  [ base, directory, filepath, time, transformers ]++testDepends :: [Package]+testDepends = [ multiarg, quickcheck, random, quickpull ]++commonOptions :: HasBuildInfo a => [a]+commonOptions =+  [ ghcOptions ["-Wall"]+  , hsSourceDirs ["lib"]+  , buildDepends libDepends+  ]++testOptions :: HasBuildInfo a => [a]+testOptions+  = hsSourceDirs ["tests"]+  : buildDepends testDepends+  : commonOptions++main :: IO ()+main = defaultMain $ do+  libModules <- modules "lib"+  flagVisual <- makeFlag "visual"+    (FlagOpts { flagDescription = "Build cartel-visual-test executable."+              , flagDefault = False+              , flagManual = True+              })+  testMods <- modules "tests"+  return+    ( blank+      { name = "cartel"+        , version = Cartel.Version.version+        , buildType = Just simple+        , category = "Distribution"+        , maintainer = "omari@smileystation.com"+        , synopsis = "Specify Cabal files in Haskell"+        , description =+            [ "By specifying your Cabal files in Haskell, you have the power"+            , "of Haskell at your disposal to reduce redundancy.  You can"+            , "also read in trees of module names dynamically, which saves"+            , "you from manually maintaining lists of module names."+            , ""+            , "See the documentation in the \"Cartel\" module for details."+            ]+        , license = Just bsd3+        , licenseFile = "LICENSE"+        , copyright = "Copyright 2014-2015 Omari Norman"+        , author = "Omari Norman"+        , stability = "Experimental"+        , cabalVersion = Just (1,16)+        , homepage = "http://www.github.com/massysett/cartel"+        , bugReports = "http://www.github.com/massysett/cartel/issues"+        , testedWith = let f v = (ghc, eq v)+                       in map f [[7,6,3], [7,8,2]]+        , extraSourceFiles = ["README.md"]+      }+    , exposedModules libModules : haskell2010 : commonOptions++    , [ githubHead "massysett" "cartel"+      , executable "cartel-visual-test"+        [ condBlock (flag flagVisual)+          ( buildable True+          , otherModules testMods : testOptions+          )+          [ buildable False+          ]+        , haskell2010+        , mainIs "cartel-visual-test.hs"+        ]+      , testSuite "cartel-properties"+        $ haskell2010 +        : otherModules testMods +        : testOptions+        ++ exitcodeFields "cartel-properties.hs"+        +      ]+    )
lib/Cartel/Render.hs view
@@ -1,17 +1,23 @@--- | Functions to render the data types in "Cartel.Ast".  You--- shouldn't need anything from this module; the main rendering--- function is also exported from "Cartel".+{-# LANGUAGE FlexibleInstances #-}+-- | Reducing a Cartel AST to flat Cabal text; essentially a+-- pretty-printer. module Cartel.Render where -import qualified Cartel.Ast as A+import Data.Word+import Cartel.Betsy+import Cartel.Ast import Data.List (intersperse) +-- | Separate two strings with a space, but only if both strings are+-- not empty. (<+>) :: String -> String -> String l <+> r   | null l = r   | null r = l   | otherwise = l ++ " " ++ r +-- | Concatenate several vertically.  Unlike 'unlines', does not add a+-- newline when an item is 'null' or when the accumulator is 'null'. vsep :: [String] -> String vsep = foldr f ""   where@@ -23,38 +29,52 @@ indentAmt :: Int indentAmt = 2 +-- | Indents a line of text; adds a newline at the end. indent :: Int -> String -> String indent i s = replicate (i * indentAmt) ' ' ++ s ++ "\n" -indentList :: Int -> [String] -> String+-- | Creates a comma-separated indented representation for a list of+-- items, such as a list of filenames or modules.  Each line ends with+-- a newline.+indentList+  :: Renderable a+  => Int+  -- ^ Indentation level.+  -> [a]+  -> String indentList i ls = case ls of   [] -> ""   x:[] -> line1 x   x:xs -> concat $ line1 x : map lineRest xs   where-    line1 s = replicate (i * indentAmt + 2) ' ' ++ s ++ "\n"-    lineRest s = replicate (i * indentAmt) ' ' ++ ", " ++ s ++ "\n"+    line1 s = replicate (i * indentAmt + 2) ' ' ++ render s ++ "\n"+    lineRest s = replicate (i * indentAmt) ' '+      ++ ", " ++ render s ++ "\n"  labeled-  :: Int+  :: Renderable a+  => Int   -- ^ Indentation   -> String   -- ^ Label-  -> String+  -> a   -- ^ Text   -> String   -- ^ Result, with a newline.  Empty if the text to show is also   -- empty. labeled i l t-  | null t = ""-  | otherwise = indent i (l ++ ": " ++ t)+  | null txt = ""+  | otherwise = indent i (l ++ ": " ++ txt)+  where+    txt = render t  labeledList-  :: Int+  :: Renderable a+  => Int   -- ^ Indentation   -> String   -- ^ Label-  -> [String]+  -> [a]   -- ^ List   -> String   -- ^ Result, with newlines.  Empty if the list is empty.@@ -62,277 +82,305 @@   | null ts = ""   | otherwise = indent i (l ++ ":") ++ indentList (i + 1) ts -version :: A.Version -> String-version = concat . intersperse "." . map show . A.unVersion+-- | Render an item.  The rendered text shall contain no newlines.+class Renderable a where+  render :: a -> String -license :: A.License -> String-license = show+instance Renderable String where+  render = id -buildType :: A.BuildType -> String-buildType = show+instance Renderable a => Renderable (Maybe a) where+  render = maybe "" render -compiler :: A.Compiler -> String-compiler = show+-- | Render an item.  The rendered text must contain a newline at the+-- end of each line and must end with a newline.  The leftmost line of+-- the rendered text shall be indented by the given number of+-- indentation levels (the number of spaces in each level is set by+-- 'indentAmt').+--+-- If there are no lines to indent, return an empty string.+class RenderableIndented a where+  renderIndented :: Int -> a -> String -comparison :: Ordering -> String-comparison a = case a of-  LT -> "<"-  GT -> ">"-  EQ -> "==" -constraint :: A.Constraint -> String-constraint a = comparison (A.csComparison a) <+>-  version (A.csVersion a)+instance RenderableIndented Error where+  renderIndented i e = concatMap (indent i) $+    "Error while attempting to generate Cabal file from Cartel source."+    : case e of+        DuplicateFlag nm ->+          ["Duplicated flag: " ++ (flagNameHead nm : flagNameTail nm)]+        Failed s -> ["The \"fail\" function was invoked: " ++ s]+        EmptyFlagName -> ["Empty flag name"] -logical :: A.Logical -> String-logical a = case a of-  A.Or -> "||"-  A.And -> "&&"+instance Renderable BuildType where+  render = show -constrTree :: A.ConstrTree -> String-constrTree a = case a of-  A.Leaf c -> constraint c-  A.Branch c l r -> "(" ++ constrTree l-    <+> logical c <+> constrTree r ++ ")"+instance Renderable License where+  render = show -cabalVersion :: (Int, Int) -> String-cabalVersion (a, b) = ">= " ++ show a ++ "." ++ show b+instance Renderable Compiler where+  render = show -description :: [String] -> String-description ls-  | null ls = ""-  | otherwise = concatMap f ls-  where-    f s-      | null s = "  .\n"-      | otherwise = "  " ++ s ++ "\n"+instance Renderable Ordering where+  render LT = "<"+  render GT = ">"+  render EQ = "==" -testedWith :: [(A.Compiler, A.ConstrTree)] -> String-testedWith = concat . intersperse ", " . map f-  where-    f (cmp, cst) = compiler cmp <+> constrTree cst+instance Renderable Version where+  render = concat . intersperse "." . map show -properties :: A.Properties -> String-properties p-  = lbl "name" (A.prName p)-  ++ lbl "version" (version . A.prVersion $ p)-  ++ lbl "cabal-version" (cabalVersion . A.prCabalVersion $ p)-  ++ lbl "build-type" (buildType . A.prBuildType $ p)-  ++ lbl "license" (license . A.prLicense $ p)-  ++ lbl "license-file" (A.prLicenseFile p)-  ++ lst "license-files" (A.prLicenseFiles p)-  ++ lbl "copyright" (A.prCopyright p)-  ++ lbl "author" (A.prAuthor p)-  ++ lbl "maintainer" (A.prMaintainer p)-  ++ lbl "stability" (A.prStability p)-  ++ lbl "homepage" (A.prHomepage p)-  ++ lbl "bug-reports" (A.prBugReports p)-  ++ lbl "package-url" (A.prPackageUrl p)-  ++ lbl "synopsis" (A.prSynopsis p)-  ++ let desc = description . A.prDescription $ p-         lbld | null desc = ""-              | otherwise = "description:\n" ++ desc-     in lbld-  ++ lbl "category" (A.prCategory p)-  ++ lbl "tested-with" (testedWith . A.prTestedWith $ p)-  ++ lst "data-files" (A.prDataFiles p)-  ++ lbl "data-dir" (A.prDataDir p)-  ++ lst "extra-source-files" (A.prExtraSourceFiles p)-  ++ lst "extra-doc-files" (A.prExtraDocFiles p)-  ++ lst "extra-tmp-files" (A.prExtraTmpFiles p)-  where-    lbl = labeled 0-    lst = labeledList 0+instance Renderable Constraint where+  render AnyVersion = ""+  render (Constrained t) = render t -class Field a where-  field :: Int -> a -> String+instance Renderable Logical where+  render Or = "||"+  render And = "&&" -instance Field A.LibraryField where-  field i f = case f of-    A.LibExposedModules xs -> labeledList i "exposed-modules" xs-    A.LibExposed b -> labeled i "exposed" (show b)-    A.LibConditional b -> condBlock i b-    A.LibInfo b -> field i b+instance Renderable ConstrTree where+  render (Leaf o v) = render o <+> render v+  render (Branch c l r) = "(" ++ render l+    <+> render c <+> render r ++ ")" -library :: A.Library -> String-library (A.Library l) = "Library\n"-  ++ concatMap (field 1) l+instance Renderable (Word, Word) where+  render (a, b) = ">= " ++ show a ++ "." ++ show b -instance Field A.ExecutableField where-  field i f = case f of-    A.ExeMainIs s -> labeled i "main-is" s-    A.ExeConditional b -> condBlock i b-    A.ExeInfo b -> field i b+newtype Description = Description [String]+  deriving (Eq, Ord, Show) -executable :: A.Executable -> String-executable (A.Executable n fs) =-  "Executable " ++ n ++ "\n"-  ++ concatMap (field 1) fs+instance RenderableIndented Description where+  renderIndented i (Description ls)+    | null ls = ""+    | otherwise = concatMap f ls+    where+      f s+        | null s = indent i "."+        | otherwise = indent i s -testSuiteType :: A.TestSuiteType -> String-testSuiteType t = case t of-  A.ExitcodeStdio -> "exitcode-stdio-1.0"-  A.Detailed -> "detailed-1.0"+instance Renderable (Compiler, Constraint) where+  render (cmp, cst) = render cmp <+> render cst -instance Field A.TestSuiteField where-  field i t = case t of-    A.TestType a -> labeled i "type" (testSuiteType a)-    A.TestMainIs s -> labeled i "main-is" s-    A.TestModule s -> labeled i "test-module" s-    A.TestConditional b -> condBlock i b-    A.TestInfo b -> field i b+instance Renderable FlagName where+  render nm = flagNameHead nm : flagNameTail nm -testSuite :: A.TestSuite -> String-testSuite (A.TestSuite n fs) =-  "Test-Suite " ++ n ++ "\n"-  ++ concatMap (field 1) fs+instance RenderableIndented (FlagName, FlagOpts) where+  renderIndented i (nm, (FlagOpts desc df man)) =+    indent i ("Flag " ++ render nm)+    ++ labeled next "description" desc+    ++ labeled next "default" df+    ++ labeled next "manual" man+    where+      next = i + 1 -instance Field A.BenchmarkField where-  field i b = case b of-    A.BenchmarkConditional s -> condBlock i s-    A.BenchmarkInfo a -> field i a+instance RenderableIndented [(FlagName, FlagOpts)] where+  renderIndented i = vsep . map (renderIndented i) -benchmark :: A.Benchmark -> String-benchmark (A.Benchmark n mi fs) =-  "Benchmark " ++ n ++ "\n"-  ++ labeled 1 "main-is" mi-  ++ labeled 1 "interface" "exitcode-stdio-1.0"-  ++ concatMap (field 1) fs+instance Renderable CondLeaf where+  render a = case a of+    OS s -> "os(" ++ s ++ ")"+    Arch s -> "arch(" ++ s ++ ")"+    Impl cmp constr -> "impl(" ++ s ++ ")"+      where+        s = render cmp <+> render constr+    CFlag f -> "flag(" ++ render f ++ ")"+    CTrue -> "true"+    CFalse -> "false" -condBlock :: Field a => Int -> A.CondBlock a -> String-condBlock i b =-  indent i ("if " ++ condTree (A.condIf b))-  ++ concatMap (field (i + 1)) (A.ifTrue b)-  ++ elses-  where-    elses | null (A.ifElse b) = ""-          | otherwise = indent i "else"-              ++ concatMap (field (i + 1)) (A.ifElse b)+instance Renderable RepoKind where+  render Head = "head"+  render This = "this" -package :: A.Package -> String-package p =-  A.packName p <+> maybe "" constrTree (A.packConstraints p)+instance Renderable Vcs where+  render x = case x of+    Darcs -> "darcs"+    Git -> "git"+    Svn -> "svn"+    Cvs _ -> "cvs"+    Mercurial -> "mercurial"+    Bazaar -> "bazaar"+    ArchVcs -> "arch"+    Monotone -> "monotone" -language :: A.Language -> String-language = show+instance RenderableIndented Repository where+  renderIndented i r =+    indent i ("source-repository " ++ render (repoKind r))+    ++ lbl "type" (repoVcs r)+    ++ lbl "location" (repoLocation r)+    ++ lbl "module" mdle+    ++ lbl "branch" (repoBranch r)+    ++ lbl "tag" (repoTag r)+    ++ lbl "subdir" (repoSubdir r)+    where+      mdle = case repoVcs r of+        Just (Cvs s) -> s+        _ -> ""+      lbl x = labeled (i + 1) x -instance Field A.BuildInfoField where-  field i fld = case fld of-    A.BuildDepends ps ->-      labeledList i "build-depends" . map package $ ps-    A.OtherModules ls ->-      labeledList i "other-modules" ls-    A.HsSourceDirs ls ->-      labeledList i "hs-source-dirs" ls-    A.Extensions ls ->-      labeledList i "extensions" ls-    A.BuildTools ps ->-      labeledList i "build-tools" . map package $ ps-    A.Buildable b ->-      labeled i "buildable" . show $ b-    A.GHCOptions ps ->-      labeledList i "ghc-options" ps-    A.GHCProfOptions ps ->-      labeledList i "ghc-prof-options" ps-    A.GHCSharedOptions ps ->-      labeledList i "ghc-shared-options" ps-    A.HugsOptions ps ->-      labeledList i "hugs-options" ps-    A.Nhc98Options ps ->-      labeledList i "nhc98-options" ps-    A.Includes ps ->-      labeledList i "includes" ps-    A.InstallIncludes ps ->-      labeledList i "install-includes" ps-    A.IncludeDirs ps ->-      labeledList i "include-dirs" ps-    A.CSources ps ->-      labeledList i "c-sources" ps-    A.ExtraLibraries ps ->-      labeledList i "extra-libraries" ps-    A.ExtraLibDirs ps ->-      labeledList i "extra-lib-dirs" ps-    A.CCOptions ps ->-      labeledList i "cc-options" ps-    A.CPPOptions ps ->-      labeledList i "cpp-options" ps-    A.LDOptions ps ->-      labeledList i "ld-options" ps-    A.PkgConfigDepends ps ->-      labeledList i "pkgconfig-depends" . map package $ ps-    A.Frameworks ps ->-      labeledList i "frameworks" ps-    A.DefaultLanguage l-      -> labeled i "default-language" . language $ l+instance Renderable Package where+ render (Package nm cs)+   = nm <+> render cs+  +instance Renderable Bool where+  render = show -condition :: A.Condition -> String-condition a = case a of-  A.OS s -> "os(" ++ s ++ ")"-  A.Arch s -> "arch(" ++ s ++ ")"-  A.Impl (cmp, mayC) -> "impl(" ++ s ++ ")"+instance Renderable DefaultLanguage where+  render = show++instance RenderableIndented BuildInfoField where+  renderIndented i fld = case fld of+    BuildDepends ls -> lst "build-depends" ls+    OtherModules ls -> lst "other-modules" ls+    HsSourceDirs ls -> lst "hs-source-dirs" ls+    Extensions ls -> lst "extensions" ls+    BuildTools ls -> lst "build-tools" ls+    Buildable b -> lbl "buildable" b+    GHCOptions ls -> lst "ghc-options" ls+    GHCProfOptions ls -> lst "ghc-prof-options" ls+    GHCSharedOptions ls -> lst "ghc-shared-options" ls+    HugsOptions ls -> lst "hugs-options" ls+    Nhc98Options ls -> lst "nhc98-options" ls+    Includes ls -> lst "includes" ls+    InstallIncludes ls -> lst "install-includes" ls+    IncludeDirs ls -> lst "include-dirs" ls+    CSources ls -> lst "c-sources" ls+    ExtraLibraries ls -> lst "extra-libraries" ls+    ExtraLibDirs ls -> lst "extra-lib-dirs" ls+    CCOptions ls -> lst "cc-options" ls+    CPPOptions ls -> lst "cpp-options" ls+    LDOptions ls -> lst "ld-options" ls+    PkgConfigDepends ls -> lst "pkgconfig-depends" ls+    Frameworks ls -> lst "frameworks" ls+    DefaultLanguage df -> lbl "default-language" df     where-      s = compiler cmp <+> cond-      cond = maybe "" constrTree mayC-  A.CFlag f -> "flag(" ++ f ++ ")"-  A.CTrue -> "true"-  A.CFalse -> "false"+      -- don't do @lst = labeledList i@ - monomorphism restriction+      lst l = labeledList i l+      lbl l = labeled i l -condTree :: A.CondTree -> String-condTree a = case a of-  A.CLeaf c -> condition c-  A.CBranch b l r -> "(" ++ condTree l <+> logical b <+> condTree r-    ++ ")"-  A.CNegate t -> "!(" ++ condTree t ++ ")"+instance RenderableIndented LibraryField where+  renderIndented i fld = case fld of+    ExposedModules ls -> lst "exposed-modules" ls+    Exposed b -> lbl "exposed" b+    LibConditional b -> renderIndented i b+    LibInfo b -> renderIndented i b+    where+      lst l = labeledList i l+      lbl l = labeled i l -flag :: A.Flag -> String-flag (A.Flag nm desc dflt man) = concat (line1:lineRest)-  where-    line1 = "Flag " ++ nm ++ "\n"-    lineRest = map (indent 1)-      [ "Description: " ++ desc-      , "Default: " ++ show dflt-      , "Manual: " ++ show man-      ]+instance Renderable Condition where+  render tree = case tree of+    CLeaf c -> render c+    CBranch c l r -> ("(" ++ render l)+      <+> render c <+> (render r ++ ")")+    CNegate t -> "!(" ++ render t ++ ")" -vcs :: A.Vcs -> String-vcs a = case a of-  A.Darcs -> "darcs"-  A.Git -> "git"-  A.Svn -> "svn"-  A.Cvs _ -> "cvs"-  A.Mercurial -> "mercurial"-  A.Bazaar -> "bazaar"-  A.ArchVcs -> "arch"-  A.Monotone -> "monotone"+instance RenderableIndented a => RenderableIndented (CondBlock a) where+  renderIndented i (CondBlock cond (y1, ys) nos) =+    indent i ("if" <+> render cond)+    ++ renderIndented (i + 1) y1+    ++ concatMap (renderIndented (i + 1)) ys+    ++ elses+    where+      elses | null nos = ""+            | otherwise = indent i "else"+                ++ concatMap (renderIndented (i + 1)) nos -repoKind :: A.RepoKind -> String-repoKind a = case a of-  A.Head -> "head"-  A.This -> "this"+instance RenderableIndented ExecutableField where+  renderIndented i fld = case fld of+    ExeConditional b -> renderIndented i b+    ExeInfo b -> renderIndented i b+    ExeMainIs m -> labeled i "main-is" m -repository :: A.Repository -> String-repository r =-  "source-repository " ++ repoKind (A.repoKind r) ++ "\n"-  ++ lbl "type" (vcs . A.repoVcs $ r)-  ++ lbl "location" (A.repoLocation r)-  ++ lbl "module" mdle-  ++ lbl "branch" (A.repoBranch r)-  ++ lbl "tag" (A.repoTag r)-  ++ lbl "subdir" (A.repoSubdir r)-  where-    mdle = case A.repoVcs r of-      A.Cvs s -> s-      _ -> ""-    lbl = labeled 1+instance RenderableIndented Executable where+  renderIndented i (Executable nm flds) =+    indent i ("Executable " ++ nm)+    ++ concatMap (renderIndented next) flds+    where+      next = i + 1 -cabal :: A.Cabal -> String-cabal d = vsep-  [ properties . A.cProperties $ d-  , vsep . map repository . A.cRepositories $ d-  , vsep . map flag . A.cFlags $ d-  , maybe "" library . A.cLibrary $ d-  , vsep . map executable . A.cExecutables $ d-  , vsep . map testSuite . A.cTestSuites $ d-  , vsep . map benchmark . A.cBenchmarks $ d-  ]+instance Renderable TestSuiteType where+  render ExitcodeStdio = "exitcode-stdio-1.0"+  render Detailed = "detailed-0.9"++instance RenderableIndented TestSuiteField where+  renderIndented i fld = case fld of+    TestConditional c -> renderIndented i c+    TestInfo b -> renderIndented i b+    TestMainIs m -> labeled i "main-is" m+    TestSuiteType t -> labeled i "type" t+    TestModule m -> labeled i "test-module" m++instance RenderableIndented TestSuite where+  renderIndented i (TestSuite n flds) =+    indent i ("Test-Suite " ++ n)+    ++ concatMap (renderIndented next) flds+    where+      next = i + 1++instance Renderable BenchmarkType where+  render BenchExitCode = "exitcode-stdio-1.0"++instance RenderableIndented BenchmarkField where+  renderIndented i (BenchmarkConditional b) = renderIndented i b+  renderIndented i (BenchmarkInfo b) = renderIndented i b+  renderIndented i (BenchmarkMainIs b) = labeled i "main-is" b+  renderIndented i (BenchmarkType b) = labeled i "type" b++instance RenderableIndented Benchmark where+  renderIndented i (Benchmark nm flds) =+    indent i ("Benchmark " ++ nm)+    ++ concatMap (renderIndented next) flds+    where+      next = i + 1++instance RenderableIndented Properties where+  renderIndented i c =+    lbl "name" (name c)+    ++ lbl "version" (version c)+    ++ lbl "cabal-version" (maybe "" render . cabalVersion $ c)+    ++ lbl "license" (maybe "" render . license $ c)+    ++ lbl "license-file" (licenseFile c)+    ++ lst "license-files" (licenseFiles c)+    ++ lbl "build-type" (maybe "" render . buildType $ c)+    ++ lbl "copyright" (copyright c)+    ++ lbl "author" (author c)+    ++ lbl "maintainer" (maintainer c)+    ++ lbl "stability" (stability c)+    ++ lbl "homepage" (homepage c)+    ++ lbl "bug-reports" (bugReports c)+    ++ lbl "package-url" (packageUrl c)+    ++ lbl "synopsis" (synopsis c)+    ++ indent i "description:"+    ++ renderIndented (i + 1) (Description . description $ c)+    ++ lbl "category" (category c)+    ++ labeledList i "tested-with" (testedWith c)+    ++ lst "data-files" (dataFiles c)+    ++ lbl "data-dir" (dataDir c)+    ++ lst "extra-source-files" (extraSourceFiles c)+    ++ lst "extra-doc-files" (extraDocFiles c)+    ++ lst "extra-tmp-files" (extraTmpFiles c)+    where+      lbl l = labeled i l+      lst l = labeledList i l++renLibrary :: Int -> [LibraryField] -> String+renLibrary _ [] = ""+renLibrary lvl xs = indent lvl "Library"+  ++ concatMap (renderIndented (lvl + 1)) xs++instance RenderableIndented Section where+  renderIndented i s = case s of+    SecRepo x -> ren x+    SecExe x -> ren x+    SecTest x -> ren x+    SecBench x -> ren x+    where+      ren x = renderIndented i x++instance RenderableIndented Cabal where+  renderIndented i (Cabal prop lib secs)+    = vsep $ ren prop+           : renLibrary 0 lib+           : map ren secs+    where+      ren x = renderIndented i x 
− lib/Cartel/Tools.hs
@@ -1,519 +0,0 @@-module Cartel.Tools-  ( -- * Logic trees-    LogicTree(..)-  -    -- * Building constraints--    -- | Helpers to build many common version constraints.--    -- ** Building constraint trees-  , lt-  , gt-  , eq-  , ltEq-  , gtEq--  -- ** Building package specifications-  , closedOpen-  , apiVersion-  , nextBreaking-  , nextMajor-  , exactly--  -- * Field class-  , Field(..)--  -- ** Conditionals-  , cif-  , system-  , arch-  , impl-  , flag-  , true-  , false--  -- ** Build info builders-  , buildDepends-  , otherModules-  , hsSourceDirs-  , extensions-  , buildTools-  , buildable-  , ghcOptions-  , ghcProfOptions-  , ghcSharedOptions-  , hugsOptions-  , nhc98Options-  , includes-  , installIncludes-  , includeDirs-  , cSources-  , extraLibraries-  , extraLibDirs-  , ccOptions-  , cppOptions-  , ldOptions-  , pkgConfigDepends-  , frameworks-  , defaultLanguage--  -- * Rendering a cabal file-  , render-  , renderString--  -- * Getting a list of all modules in a directory tree-  , modules-  , fileExtensions-  , modulesWithExtensions-  ) where--import qualified Cartel.Ast as A-import qualified Cartel.Render as R-import qualified System.Directory as D-import qualified System.FilePath as P-import System.FilePath ((</>))-import qualified Data.Char as C-import Data.List (intersperse, sortBy)-import Data.Monoid-import qualified Data.Version as V-import Data.Time-import qualified Paths_cartel-import qualified System.IO as IO--class LogicTree a where-  (&&&) :: a -> a -> a-  (|||) :: a -> a -> a--infixr 3 &&&-infixr 2 |||--instance LogicTree A.ConstrTree where-  l &&& r = A.Branch A.And l r-  l ||| r = A.Branch A.Or l r--instance LogicTree A.CondTree where-  l &&& r = A.CBranch A.And l r-  l ||| r = A.CBranch A.Or l r---lt :: [Int] -> A.ConstrTree-lt = A.Leaf . A.Constraint LT . A.Version--gt :: [Int] -> A.ConstrTree-gt = A.Leaf . A.Constraint GT . A.Version--eq :: [Int] -> A.ConstrTree-eq = A.Leaf . A.Constraint EQ . A.Version--ltEq :: [Int] -> A.ConstrTree-ltEq v = lt v ||| eq v--gtEq :: [Int] -> A.ConstrTree-gtEq v = gt v ||| eq v---- | Creates a package interval that is closed on the left, open on--- the right.  Useful for the common case under the PVP to specify--- that you depend on a version that is at least a particular--- version, but less than another version.------ > closedOpen "bytestring" [0,17] [0,19] ==> bytestring >= 0.17 && < 0.19--closedOpen-  :: String-  -- ^ Package name-  -> [Int]-  -- ^ Version number for lower bound-  -> [Int]-  -- ^ Version number for upper bound-  -> A.Package-  -- ^ Resulting contraints-closedOpen n l u = A.Package n $ Just (gtEq l &&& lt u)---- | Specifies a particular API version.  Useful to lock your--- package dependencies down to a particular API version.------ > apiVersion "base" [1] ==> base >= 1 && < 2--- > apiVersion "base" [1,2] ==> base >= 1.2 && < 1.3--- > apiVersion "base" [1,2,3] ==> base >= 1.2.3 && < 1.2.4--apiVersion :: String -> [Int] -> A.Package-apiVersion n v = closedOpen n v u-  where-    u = case v of-      [] -> error "apiVersion: requires a non-empty list argument"-      _ -> init v ++ [succ (last v)]---- | Depends on the version given, up to the next breaking API--- change.------ > nextBreaking "base" [4] ==> base >= 4 && < 4.1--- > nextBreaking "base" [4,1] ==> base >= 4.1 && < 4.2--- > nextBreaking "base" [4,7,0,0] ==> base >= 4.7.0.0 && < 4.8--nextBreaking-  :: String-  -> [Int]-  -> A.Package-nextBreaking n v = closedOpen n v u-  where-    u = case v of-      [] -> error "nextBreaking: requires a non-empty list argument"-      x:[] -> [x, 1]-      x:y:_ -> x : succ y : []---- | Depends on the version given, up to the next time the first--- digit increments.  Useful for @base@.------ > nextBreaking "base" [4] ==> base >= 4 && < 5--nextMajor-  :: String-  -> [Int]-  -> A.Package-nextMajor n v = closedOpen n v u-  where-    u = case v of-      [] -> error "nextMajor: requires a non-empty list argument"-      x:_ -> succ x : []---- | Depends on exactly this version only.------ > exactly "base" [4,5,0,0] ==> base ==4.5.0.0--exactly :: String -> [Int] -> A.Package-exactly n v = A.Package n (Just $ eq v)---- | Common extensions of Haskell files and files that are--- preprocessed into Haskell files.  Includes:------ * hs (Haskell)------ * lhs (literate Haskell)------ * gc (greencard)------ * chs (c2hs)------ * hsc (hsc2hs)------ * y and ly (happy)------ * x (alex)------ * cpphs--fileExtensions :: [String]-fileExtensions =-  [ "hs"-  , "lhs"-  , "gc"-  , "chs"-  , "hsc"-  , "y"-  , "ly"-  , "x"-  , "cpphs"-  ]--interestingFile-  :: [String]-  -- ^ Extensions of module files-  -> FilePath-  -> Bool--interestingFile xs s = case s of-  "" -> False-  x:_-    | not (C.isUpper x) -> False-    | otherwise -> let mayExt = P.takeExtension s-                   in case mayExt of-                       [] -> False-                       _ : ext -> ext `elem` xs--interestingDir :: FilePath -> Bool-interestingDir p = case p of-  [] -> False-  x:_-    | not (C.isUpper x) -> False-    | otherwise -> not $ '.' `elem` p---- | Gets all Haskell modules in a given directory tree.  Only files--- with one of the extensions listed in 'fileExtensions' are--- returned.  Files and directories that do not begin with an--- uppercase letter are ignored.  (This also ignores files that--- start with a dot.)  Directories with a dot anywhere in the name--- are ignored.--modules-  :: FilePath-  -- ^ Start searching within this directory.-  -> IO [String]-  -- ^ A list of Haskell modules in the given directory tree.  The-  -- file contents are not examined; only the file names matter.-  -- Returned as a list of dotted names.-modules = modulesWithExtensions fileExtensions----- | Gets all Haskell modules in a given directory tree.  Allows you--- to specify what extensions you are interested in.--modulesWithExtensions-  :: [String]-  -- ^ Look for files that have one of these extensions.-  -- 'fileExtensions' covers the most common cases.  Files without-  -- one of these extensions are ignored.  Files and directories-  -- that do not begin with an uppercase letter are ignored.  (This-  -- also ignores files that start with a dot.)  Directories with a-  -- dot anywhere in the name are ignored.--  -> FilePath-  -- ^ Start searching within this directory.--  -> IO [String]-  -- ^ A list of Haskell modules in the given directory tree.  The-  -- file contents are not examined; only the file names matter.-  -- Returned as a list of dotted names.--modulesWithExtensions exts start-  = fmap (map modName . sortBy sorter . map reverse)-  $ modulesInDir exts start []-  where-    modName = concat . intersperse "."--sorter :: [String] -> [String] -> Ordering-sorter x y = mconcat (zipWith compare x y) <> compare lenX lenY-  where-    (lenX, lenY) = (length x, length y)--modulesInDir-  :: [String]-  -- ^ Extensions of module files-  -> FilePath-  -- Search is rooted in this directory-  -> [FilePath]-  -- ^ Stack of directories we're in-  -> IO [[String]]-  -- ^ Returns a list of modules in this directory.-modulesInDir exts start dirs = do-  cs <- D.getDirectoryContents (start </> P.joinPath (reverse dirs))-  fmap concat . mapM (processFile exts start dirs) $ cs--processFile-  :: [String]-  -- ^ Extensions of module files-  -> FilePath-  -- ^ Search is rooted in this directory-  -> [FilePath]-  -- Stack of directories we're in, including current directory-  -> FilePath-  -- ^ Interesting file under investigation-  -> IO [[String]]-processFile exts start dirs this = do-  isDir <- D.doesDirectoryExist-    (start </> (P.joinPath . reverse $ this : dirs))-  if isDir-    then if interestingDir this-          then modulesInDir exts start (this : dirs)-          else return []-    else return $ if interestingFile exts this-          then [(P.dropExtension this : dirs)]-          else []---- | Things that can be an item in a field in a Cabal file.-class Field a where--  -- | Takes a conditional block and wraps it in the field type.-  conditional :: A.CondBlock a -> a--  -- | Takes a build information field and wraps it in the field-  -- type.-  buildInfo :: A.BuildInfoField -> a--instance Field A.LibraryField where-  conditional = A.LibConditional-  buildInfo = A.LibInfo--instance Field A.ExecutableField where-  conditional = A.ExeConditional-  buildInfo = A.ExeInfo--instance Field A.TestSuiteField where-  conditional = A.TestConditional-  buildInfo = A.TestInfo--instance Field A.BenchmarkField where-  conditional = A.BenchmarkConditional-  buildInfo = A.BenchmarkInfo---- # Build info helpers-buildDepends :: Field a => [A.Package] -> a-buildDepends = buildInfo . A.BuildDepends--otherModules :: Field a => [String] -> a-otherModules = buildInfo . A.OtherModules--hsSourceDirs :: Field a => [String] -> a-hsSourceDirs = buildInfo . A.HsSourceDirs--extensions :: Field a => [String] -> a-extensions = buildInfo . A.Extensions--buildTools :: Field a => [A.Package] -> a-buildTools = buildInfo . A.BuildTools--buildable :: Field a => Bool -> a-buildable = buildInfo . A.Buildable--ghcOptions :: Field a => [String] -> a-ghcOptions = buildInfo . A.GHCOptions--ghcProfOptions :: Field a => [String] -> a-ghcProfOptions = buildInfo . A.GHCProfOptions--ghcSharedOptions :: Field a => [String] -> a-ghcSharedOptions = buildInfo . A.GHCSharedOptions--hugsOptions :: Field a => [String] -> a-hugsOptions = buildInfo . A.HugsOptions--nhc98Options :: Field a => [String] -> a-nhc98Options = buildInfo . A.Nhc98Options--includes :: Field a => [String] -> a-includes = buildInfo . A.Includes--installIncludes :: Field a => [String] -> a-installIncludes = buildInfo . A.InstallIncludes--includeDirs :: Field a => [String] -> a-includeDirs = buildInfo . A.IncludeDirs--cSources :: Field a => [String] -> a-cSources = buildInfo . A.CSources--extraLibraries :: Field a => [String] -> a-extraLibraries = buildInfo . A.ExtraLibraries--extraLibDirs :: Field a => [String] -> a-extraLibDirs = buildInfo . A.ExtraLibDirs--ccOptions :: Field a => [String] -> a-ccOptions = buildInfo . A.CCOptions--cppOptions :: Field a => [String] -> a-cppOptions = buildInfo . A.CPPOptions--ldOptions :: Field a => [String] -> a-ldOptions = buildInfo . A.LDOptions--pkgConfigDepends :: Field a => [A.Package] -> a-pkgConfigDepends = buildInfo . A.PkgConfigDepends--frameworks :: Field a => [String] -> a-frameworks = buildInfo . A.Frameworks--defaultLanguage :: Field a => A.Language -> a-defaultLanguage = buildInfo . A.DefaultLanguage---- | Builds @if@ statements.  Use with the following functions, such--- as 'flag', to make it easy to build conditional blocks.  For--- example:------ > cif (flag "buildExe") [buildable True] [buildable False]------ A little more complicated:------ > cif (flag "buildExe" &&& system "windows")--- >   [buildable True] [buildable False]-cif-  :: Field a-  => A.CondTree-  -- ^ Condition to satisfy-  -> [a]-  -- ^ Use these results if condition is true-  -> [a]-  -- ^ Use these results if condition if false-  -> a-cif tree ifTrue ifFalse =-  conditional $ A.CondBlock tree ifTrue ifFalse---- | Operating system; tested against @System.Info.os@ on the--- target system.-system :: String -> A.CondTree-system = A.CLeaf . A.OS---- | Argument is matched against @System.Info.arch@ on the target--- system.-arch :: String -> A.CondTree-arch = A.CLeaf . A.Arch---- | Tests for the configured Haskell implementation.-impl :: A.Compiler -> Maybe A.ConstrTree -> A.CondTree-impl cm cn = A.CLeaf $ A.Impl (cm, cn)---- | Evaluates to the current assignment of the flag of the given--- name.  Flag names are case insensitive.  Testing for flags that--- have not been introduced with a flag section is an error.-flag :: String -> A.CondTree-flag = A.CLeaf . A.CFlag---- | Always true.-true :: A.CondTree-true = A.CLeaf A.CTrue---- | Always false.-false :: A.CondTree-false = A.CLeaf A.CFalse----- | Renders a 'A.Cabal' data type as a string.-renderString-  :: String-  -- ^ Name of program used-  -> ZonedTime-  -- ^ When this output is being created-  -> V.Version-  -- ^ Cartel package version-  -> A.Cabal-  -> String-renderString nm zt ver cbl = hdr ++ R.cabal cbl-  where-    hdr = unlines $-      [ "-- This Cabal file generated using the Cartel library."-      , "-- Cartel is available at:"-      , "-- http://www.github.com/massysett/cartel"-      , "--"-      ] ++ case nm of-            [] -> []-            _ -> ["-- Script name used to generate: " ++ nm]-      ++-      [ "-- Generated on: " ++ show zt-      , "-- Cartel library version: " ++ showVer-      ]-    showVer = concat-      . intersperse "."-      . map show-      . V.versionBranch-      $ ver---- | Render a Cabal file to standard output.  The output will have--- comments at the beginning indicating that it was built with--- Cartel, and what version of the Cartel library was used, and when--- the output was produced, along with (optionally) the filename of--- the program used to produce the output.------ Ensures that the output is UTF-8, as required by Cabal.-render-  :: String-  -- ^ The name of the program used to produce this output.  Put the-  -- name of your script here so it can appear in the output.  This-  -- is optional; to omit it, use the empty string here.--  -> A.Cabal-  -> IO ()-render nm cbl = do-  zt <- getZonedTime-  IO.hSetBinaryMode IO.stdout False-  IO.hSetEncoding IO.stdout IO.utf8-  putStr $ renderString nm zt Paths_cartel.version cbl-
+ lib/Cartel/Types.hs view
@@ -0,0 +1,13 @@+module Cartel.Types where++-- | A non-empty string.  This string should never be empty.  It is+-- used where, for example, a field in a Cabal file is required to+-- have a value and that value cannot be empty.  In contrast, Cartel+-- uses an ordinary 'String' for values that can be empty.+--+-- This is only a type synonym, so nothing in the type system enforces+-- that these strings must be non-empty.  Typically though, Cabal will+-- give you grief about the file that Cartel generates if you used an+-- empty value for a 'NonEmptyString'.+type NonEmptyString = String+
+ lib/Cartel/Version.hs view
@@ -0,0 +1,14 @@+-- | The current version for the Cartel library.  Having this in a+-- separate module allows for the "Cartel.GenCartelCabal" module to+-- exist.  Without this module, I'd have to rely on the @Paths_cartel@+-- module to exist, which introduces some nasty bootstrapping issues+-- for "Cartel.GenCartelCabal" or, alternatively, some nasty circular+-- dependency issues if this value were included directly into+-- "Cartel.GenCartelCabal".++module Cartel.Version where++import Data.Word++version :: [Word]+version = [0,12,0,0]
− minimum-versions.txt
@@ -1,38 +0,0 @@-This package was tested to work with these dependency-versions and compiler version.-These are the minimum versions given in the .cabal file.-Tested as of: 2014-05-30 16:15:53.772569 UTC-Path to compiler: ghc-7.4.1-Compiler description: 7.4.1--/opt/ghc/7.4.1/lib/ghc-7.4.1/package.conf.d:-    Cabal-1.14.0-    array-0.4.0.0-    base-4.5.0.0-    bin-package-db-0.0.0.0-    binary-0.5.1.0-    bytestring-0.9.2.1-    containers-0.4.2.1-    deepseq-1.3.0.0-    directory-1.1.0.2-    extensible-exceptions-0.1.1.4-    filepath-1.3.0.0-    (ghc-7.4.1)-    ghc-prim-0.2.0.0-    (haskell2010-1.1.0.1)-    (haskell98-2.0.0.1)-    hoopl-3.8.7.3-    hpc-0.5.1.1-    integer-gmp-0.4.0.0-    old-locale-1.0.0.4-    old-time-1.1.0.0-    pretty-1.1.1.0-    process-1.1.0.1-    rts-1.0-    template-haskell-2.7.0.0-    time-1.4-    unix-2.5.1.0--/home/massysett/cartel/sunlight-11214/db:-    cartel-0.10.0.0-
+ tests/Cartel/Generators.hs view
@@ -0,0 +1,373 @@+{-# LANGUAGE TypeSynonymInstances #-}+module Cartel.Generators where++import Cartel+import Cartel.Betsy+import Control.Applicative+import Control.Monad.Trans.State+import Control.Monad.Trans.Class+import System.Random (StdGen, random, randomR, Random(..), mkStdGen)+import Control.Monad.Trans.Reader+import Control.Monad++type Gen = ReaderT Word (Betsy (State StdGen))++class Arbitrary a where+  arbitrary :: Gen a++getSize :: Gen Word+getSize = ask++resize :: Word -> Gen a -> Gen a+resize w = withReaderT (const w)++getStdGen :: Gen StdGen+getStdGen = lift . lift $ get++setStdGen :: StdGen -> Gen ()+setStdGen = lift . lift . put++choose :: Random a => (a, a) -> Gen a+choose pair = do+  g <- getStdGen+  let (r, g') = randomR pair g+  setStdGen g'+  return r++chooseDefault :: Random a => Gen a+chooseDefault = do+  g <- getStdGen+  let (r, g') = random g+  setStdGen g'+  return r++frequency :: [(Int, Gen a)] -> Gen a+frequency [] = error "frequency used with empty list"+frequency xs0 = choose (1, tot) >>= (`pick` xs0)+  where+    tot = sum (map fst xs0)+    pick n ((k, x):xs)+      | n <= k = x+      | otherwise = pick (n - k) xs+    pick _ _ = error "pick used with empty list"++elements :: [a] -> Gen a+elements [] = error "elements used with empty list"+elements xs = (xs !!) `fmap` choose (0, length xs - 1)++oneOf :: [Gen a] -> Gen a+oneOf = join . elements++instance Arbitrary Bool where+  arbitrary = chooseDefault++instance Arbitrary Word where+  arbitrary = choose (0, 255)++instance Arbitrary a => Arbitrary (Maybe a) where+  arbitrary = frequency [(3, fmap Just arbitrary), (1, return Nothing)]++instance Arbitrary a => Arbitrary [a] where+  arbitrary = do+    sz <- getSize+    c <- choose (0, sz)+    replicateM (fromIntegral c) arbitrary++instance Arbitrary Char where+  arbitrary = choose ('a', 'z')++genNonEmptyString :: Gen NonEmptyString+genNonEmptyString = liftM2 (:) arbitrary (resize 5 arbitrary)++instance Arbitrary Vcs where+  arbitrary = oneOf $ fmap cvs genNonEmptyString+    : map return [ darcs, git, svn, mercurial,+                   bazaar, archVcs, monotone]++instance Arbitrary RepoKind where+  arbitrary = elements [repoHead, repoThis]++instance Arbitrary Repository where+  arbitrary = Repository <$> arbitrary <*> arbitrary <*> arbitrary+    <*> genNonEmptyString <*> arbitrary <*> arbitrary++listOf :: Gen a -> Gen [a]+listOf g = do+  sz <- getSize+  len <- choose (0, sz)+  replicateM (fromIntegral len) g++genNonEmptyList :: Gen a -> Gen [a]+genNonEmptyList g = liftM2 (:) g (listOf g)++genVersion :: Gen Version+genVersion = resize 3 (genNonEmptyList (choose (0, 99)))++instance Arbitrary Constraint where+  arbitrary = do+    sz <- getSize+    lvls <- choose (0, sz)+    go lvls+    where+      go lvl | lvl == 0 = oneOf+                [ fmap lt genVersion+                , fmap gt genVersion+                , fmap eq genVersion+                , return anyVersion+                ]+             | otherwise = do+                l <- next+                r <- next+                op <- elements [ (&&&), (|||) ]+                return $ l `op` r+        where+          next = choose (0, lvl - 1) >>= go++instance Arbitrary Compiler where+  arbitrary = elements [ ghc, nhc, yhc, hugs, helium, jhc, lhc ]++instance Arbitrary Condition where+  arbitrary = do+    sz <- getSize+    lvls <- choose (0, sz)+    goCondition lvls++goCondition :: Word -> Gen Condition+goCondition lvl+  | lvl == 0 = lift currentFlags >>= lowest+  | otherwise = upper+  where+    lowest [] = nonFlagLevel+    lowest xs = elements (fmap fst xs) >>= withFlagLevel+    nonFlagLevel = oneOf [ fmap system genNonEmptyString+                         , fmap arch genNonEmptyString+                         , liftM2 impl arbitrary arbitrary+                         , return true+                         , return false+                         ]+    withFlagLevel fl = frequency+      [ (2, nonFlagLevel), (1, return $ flag fl)]+    upper = frequency [(2, binary), (1, inverted)]+      where+        next = choose (0, lvl - 1) >>= goCondition+        inverted = fmap invert next+        binary = do+          op <- elements [(&&&), (|||)]+          liftM2 op next next++genCondBlock :: (Arbitrary a, HasBuildInfo a) => Gen a+genCondBlock = liftM3 condBlock arbitrary+  (liftM2 (,) arbitrary arbitrary) arbitrary++instance Arbitrary Package where+  arbitrary = liftM2 package genNonEmptyString arbitrary++genBuildInfo :: HasBuildInfo a => Gen a+genBuildInfo = oneOf+  [ return haskell98+  , return haskell2010+  , fmap buildDepends arbitrary+  , fmap otherModules neslist+  , fmap hsSourceDirs neslist+  , fmap extensions neslist+  , fmap buildTools (genNonEmptyList arbitrary)+  , fmap buildable arbitrary+  , fmap ghcOptions neslist+  , fmap ghcProfOptions neslist+  , fmap ghcSharedOptions neslist+  , fmap hugsOptions neslist+  , fmap nhc98Options neslist+  , fmap includes neslist+  , fmap installIncludes neslist+  , fmap includeDirs neslist+  , fmap cSources neslist+  , fmap extraLibraries neslist+  , fmap ccOptions neslist+  , fmap cppOptions neslist+  , fmap ldOptions neslist+  , fmap pkgConfigDepends (genNonEmptyList arbitrary)+  , fmap frameworks neslist+  ]+  where+    neslist = genNonEmptyList genNonEmptyString++genMainIs :: BuildsExe a => Gen a+genMainIs = fmap mainIs genNonEmptyString++instance Arbitrary FlagOpts where+  arbitrary = liftM3 FlagOpts arbitrary arbitrary arbitrary++addFlagsToState+  :: Word+  -- ^ How many flags?+  -> Gen ()+addFlagsToState nFlags = do+  let mkf = do+        nm <- genNonEmptyString+        opts <- arbitrary+        _ <- lift (makeFlag nm opts)+        return ()+  _ <- replicateM (fromIntegral nFlags) mkf+  return ()++downsize :: Gen a -> Gen a+downsize g = do+  sz <- getSize+  resize (sz - 1) g++instance Arbitrary LibraryField where+  arbitrary = getSize >>= f+    where+      nonNestGens =+        [ (6, genBuildInfo)+        , (1, fmap exposed arbitrary)+        , (1, fmap exposedModules (genNonEmptyList genNonEmptyString))+        ]+      f sz | sz == 0 = nonNest+           | otherwise = nest+        where+          nonNest = frequency nonNestGens+          nest = downsize . frequency $+            (1, genCondBlock) : nonNestGens+++instance Arbitrary ExecutableField where+  arbitrary = getSize >>= f+    where+      nonNestGens =+        [ (6, genBuildInfo)+        , (1, genMainIs)+        ]+      nestGens = (1, genCondBlock) : nonNestGens+      f sz | sz == 0 = frequency nonNestGens+           | otherwise = downsize $ frequency nestGens++instance Arbitrary TestSuiteField where+  arbitrary = getSize >>= f+    where+      nonNestGens =+        [ (7, genBuildInfo)+        , (1, fmap testModule genNonEmptyString)+        , (1, pure exitcodeStdio)+        , (1, pure detailed)+        , (1, genMainIs)+        ]+      nestGens = (1, genCondBlock) : nonNestGens+      f sz | sz == 0 = frequency nonNestGens+           | otherwise = downsize $ frequency nestGens++instance Arbitrary BenchmarkField where+  arbitrary = getSize >>= f+    where+      nonNest =+        [ (6, genBuildInfo)+        , (1, return exitcodeStdio)+        ]+      nest = (1, genCondBlock) : nonNest+      f sz | sz == 0 = frequency nonNest+           | otherwise = downsize $ frequency nest++instance Arbitrary BuildType where+  arbitrary = elements [simple, configure, make, custom]++instance Arbitrary License where+  arbitrary = elements [ gpl, agpl, lgpl, bsd2, bsd3, bsd4, mit, mpl,+                         apache, publicDomain, allRightsReserved,+                         otherLicense ]++instance (Arbitrary a, Arbitrary b) => Arbitrary (a, b) where+  arbitrary = liftM2 (,) arbitrary arbitrary++instance Arbitrary Properties where+  arbitrary = Properties+    <$> genNonEmptyString -- name+    <*> genVersion -- version+    <*> arbitrary -- cabalVersion+    <*> arbitrary -- buildType+    <*> arbitrary -- license+    <*> arbitrary -- licenseFile+    <*> listOf genNonEmptyString -- licenseFiles+    <*> arbitrary -- copyright+    <*> arbitrary -- author+    <*> arbitrary+    <*> arbitrary+    <*> arbitrary+    <*> arbitrary -- bugReports+    <*> arbitrary+    <*> arbitrary+    <*> arbitrary -- description+    <*> arbitrary+    <*> arbitrary+    <*> listOf genNonEmptyString -- dataFiles+    <*> arbitrary+    <*> listOf genNonEmptyString+    <*> listOf genNonEmptyString+    <*> listOf genNonEmptyString -- extraTmpFiles++instance Arbitrary Section where+  arbitrary = frequency [(3, nonRepo), (1, repo)]+    where+      nonRepo = oneOf+        [ liftM2 executable genNonEmptyString arbitrary+        , liftM2 testSuite genNonEmptyString arbitrary+        , liftM2 benchmark genNonEmptyString arbitrary+        ]+      repo = fmap repository arbitrary++instance Arbitrary Cabal where+  arbitrary = do+    sz <- getSize+    nFlags <- choose (0, sz)+    addFlagsToState nFlags+    liftM3 cabal arbitrary arbitrary arbitrary++-- | Generates Cabal text given a size parameter and int to generate a+-- seed.  Read the function from the bottom up:+--+-- * generates a random computation in ReaderT+--+-- * runs the ReaderT with the given size, resulting in a 'Betsy'+--+-- * renders the 'Betsy', which results in a State computation with+-- the 'StdGen' as the state+--+-- * runs the State computation with an initialized generator,+-- resulting in a pair (a, s), where @s@ is the resulting state and+-- @a@ is an Either+--+-- * gets the Either, discards the resulting state, resulting in an+-- @Either Error String@+--+-- * transforms the @Error@ to a string+genCabalText+  :: Word+  -- ^ Size+  -> Int+  -- ^ Random seed+  -> Either String String+  -- ^ Either an error message, or the Cabal text.+genCabalText sz sd+  = either (Left . renderIndented 0) (Right . id)+  . fst+  . flip runState (mkStdGen sd)+  . renderBetsy+  . flip runReaderT sz+  $ arbitrary++genResult+  :: Gen a+  -- ^ Generator+  -> Word+  -- ^ How many flags?+  -> Word+  -- ^ Size+  -> Int+  -- ^ Random seed+  -> Either String a+genResult gen nFlags sz sd+  = either (Left . renderIndented 0) (Right . fst)+  . fst+  . flip runState (mkStdGen sd)+  . runBetsy+  . flip runReaderT sz+  $ (addFlagsToState nFlags >> gen)
+ tests/Cartel/Properties.hs view
@@ -0,0 +1,83 @@+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}++-- | Cartel properties.  For the time being, most (maybe all) of these+-- properties test the generators, rather than Cartel itself.  I had+-- to debug generators that were stuck in an infinite loop.+module Cartel.Properties where++import Cartel+import Control.Monad+import Test.QuickCheck+import qualified Cartel.Generators as G++seconds :: Int -> Int+seconds = (* 10 ^ (6 :: Int))++newtype Little = Little Word+  deriving (Eq, Ord, Show)++instance Arbitrary Little where+  arbitrary = sized f+    where+      f sz = fmap Little (choose (0, min (fromIntegral sz) 10))++completesInSecs+  :: Show a+  => Int+  -- ^ How many seconds+  -> G.Gen a+  -> Little+  -- ^ How many flags+  -> Little+  -- ^ Size+  -> Int+  -- ^ Seed+  -> Property+completesInSecs time gen (Little nFlags) (Little sz) sd+  = within (seconds time) $+  length (show (G.genResult gen nFlags sz sd)) >= 0++prop_vcsCompletesInSecs = completesInSecs 10 (G.arbitrary :: G.Gen Vcs)++prop_constraintCompletesInSecs = completesInSecs 10+  (G.arbitrary :: G.Gen Constraint)++mainIsCompletesInSecs a = completesInSecs 10 (G.genMainIs `asTypeOf` a)++prop_conditionCompletesInSecs = completesInSecs 10+  (G.arbitrary :: G.Gen Condition)++buildInfoCompletesInSecs a = completesInSecs 10 (G.genBuildInfo `asTypeOf` a)++-- ExecutableField contents++prop_buildInfoExeCompletesInSecs = buildInfoCompletesInSecs+  (undefined :: G.Gen ExecutableField)++prop_condBlockExeCompletesInSecs = completesInSecs 10+  (G.genCondBlock :: G.Gen ExecutableField)++prop_exeMainIsCompletesInSecs = mainIsCompletesInSecs+  (undefined :: G.Gen ExecutableField)++prop_cabalCompletesInSecs = completesInSecs 10+  (G.arbitrary :: G.Gen Cabal)++prop_propertiesCompletesInSecs = completesInSecs 10+  (G.arbitrary :: G.Gen Properties)++prop_repositoryCompletesInSecs = completesInSecs 10+  (G.arbitrary :: G.Gen Repository)++prop_sectionCompletesInSecs = completesInSecs 10+  (G.arbitrary :: G.Gen Section)++prop_executableCompletesInSecs = completesInSecs 10+  (liftM2 executable G.genNonEmptyString G.arbitrary)++prop_benchmarkCompletesInSecs = completesInSecs 10+  (liftM2 benchmark G.genNonEmptyString G.arbitrary)++prop_testSuiteCompletesInSecs = completesInSecs 10+  (liftM2 testSuite G.genNonEmptyString G.arbitrary)+
+ tests/Decrees.hs view
@@ -0,0 +1,26 @@+-- | This module generated by the Quickpull package.+-- Quickpull is available at:+-- <http://www.github.com/massysett/quickpull>++module Decrees where++import Quickpull+import qualified Cartel.Properties++decrees :: [Decree]+decrees =++  [ Decree ( Meta {modDesc = ModDesc {modPath = "tests/Cartel/Properties.hs", modName = ["Cartel","Properties"]}, linenum = 40, qName = "prop_vcsCompletesInSecs"} ) ( Single Cartel.Properties.prop_vcsCompletesInSecs )+  , Decree ( Meta {modDesc = ModDesc {modPath = "tests/Cartel/Properties.hs", modName = ["Cartel","Properties"]}, linenum = 42, qName = "prop_constraintCompletesInSecs"} ) ( Single Cartel.Properties.prop_constraintCompletesInSecs )+  , Decree ( Meta {modDesc = ModDesc {modPath = "tests/Cartel/Properties.hs", modName = ["Cartel","Properties"]}, linenum = 47, qName = "prop_conditionCompletesInSecs"} ) ( Single Cartel.Properties.prop_conditionCompletesInSecs )+  , Decree ( Meta {modDesc = ModDesc {modPath = "tests/Cartel/Properties.hs", modName = ["Cartel","Properties"]}, linenum = 54, qName = "prop_buildInfoExeCompletesInSecs"} ) ( Single Cartel.Properties.prop_buildInfoExeCompletesInSecs )+  , Decree ( Meta {modDesc = ModDesc {modPath = "tests/Cartel/Properties.hs", modName = ["Cartel","Properties"]}, linenum = 57, qName = "prop_condBlockExeCompletesInSecs"} ) ( Single Cartel.Properties.prop_condBlockExeCompletesInSecs )+  , Decree ( Meta {modDesc = ModDesc {modPath = "tests/Cartel/Properties.hs", modName = ["Cartel","Properties"]}, linenum = 60, qName = "prop_exeMainIsCompletesInSecs"} ) ( Single Cartel.Properties.prop_exeMainIsCompletesInSecs )+  , Decree ( Meta {modDesc = ModDesc {modPath = "tests/Cartel/Properties.hs", modName = ["Cartel","Properties"]}, linenum = 63, qName = "prop_cabalCompletesInSecs"} ) ( Single Cartel.Properties.prop_cabalCompletesInSecs )+  , Decree ( Meta {modDesc = ModDesc {modPath = "tests/Cartel/Properties.hs", modName = ["Cartel","Properties"]}, linenum = 66, qName = "prop_propertiesCompletesInSecs"} ) ( Single Cartel.Properties.prop_propertiesCompletesInSecs )+  , Decree ( Meta {modDesc = ModDesc {modPath = "tests/Cartel/Properties.hs", modName = ["Cartel","Properties"]}, linenum = 69, qName = "prop_repositoryCompletesInSecs"} ) ( Single Cartel.Properties.prop_repositoryCompletesInSecs )+  , Decree ( Meta {modDesc = ModDesc {modPath = "tests/Cartel/Properties.hs", modName = ["Cartel","Properties"]}, linenum = 72, qName = "prop_sectionCompletesInSecs"} ) ( Single Cartel.Properties.prop_sectionCompletesInSecs )+  , Decree ( Meta {modDesc = ModDesc {modPath = "tests/Cartel/Properties.hs", modName = ["Cartel","Properties"]}, linenum = 75, qName = "prop_executableCompletesInSecs"} ) ( Single Cartel.Properties.prop_executableCompletesInSecs )+  , Decree ( Meta {modDesc = ModDesc {modPath = "tests/Cartel/Properties.hs", modName = ["Cartel","Properties"]}, linenum = 78, qName = "prop_benchmarkCompletesInSecs"} ) ( Single Cartel.Properties.prop_benchmarkCompletesInSecs )+  , Decree ( Meta {modDesc = ModDesc {modPath = "tests/Cartel/Properties.hs", modName = ["Cartel","Properties"]}, linenum = 81, qName = "prop_testSuiteCompletesInSecs"} ) ( Single Cartel.Properties.prop_testSuiteCompletesInSecs )+  ]
+ tests/cartel-properties.hs view
@@ -0,0 +1,7 @@+module Main where++import Quickpull+import Decrees++main :: IO ()+main = defaultMain decrees
+ tests/cartel-visual-test.hs view
@@ -0,0 +1,81 @@+-- | Generates random Cabal text.  The program takes two arguments.+-- The first is a size parameter.  This should be a non-negative+-- integer.  Bigger sizes will result in bigger results generated.+-- The second argument is the random seed.  It should be any integer.+-- Different seeds should generate different results.+module Main where++import Data.Word+import Cartel.Generators+import System.Environment+import Data.Either+import Text.Read (readMaybe)+import System.Random+import System.Exit+import qualified System.IO as IO+import Multiarg++maxSize :: Word+maxSize = 10++help :: (String -> String)+help pn = unlines+  [ pn ++ " - generates random Cabal text."+  , "Options:"+  , "  --size INT - runs generator with the given size."+  , "               INT must be non-negative.  Larger INT will"+  , "               result in larger results."+  , "  --seed INT - runs generator with the given seed."+  , "  Without these options, a random seed is chosen, and"+  , "  a random size between 0 and " ++ show maxSize ++ " is chosen."+  ]++opts :: [OptSpec (IO (Either Word Int))]+opts =+  [ optSpec "" ["size"] (OneArg (fmap Left . readVal))+  , optSpec "" ["seed"] (OneArg (fmap Right . readVal))+  ]++failOnPosArg :: IO a+failOnPosArg = do+  pn <- getProgName+  fail $ pn ++ " does not accept positional arguments."++finalOptions :: [Either Word Int] -> IO (Word, Int)+finalOptions ls = do+  let (ws, is) = partitionEithers ls+  sz <- case safeLast ws of+    Nothing -> randomRIO (0, maxSize)+    Just x -> return x+  sd <- case safeLast is of+    Nothing -> randomIO+    Just x -> return x+  return (sz, sd)++safeLast :: [a] -> Maybe a+safeLast xs+  | null xs = Nothing+  | otherwise = Just . last $ xs++readVal :: Read a => String -> IO a+readVal s = maybe (fail $ "could not read string: " ++ s) return+  . readMaybe $ s++main :: IO ()+main = do+  eithersActs <- parseCommandLine help opts (const failOnPosArg)+  eithers <- sequence eithersActs+  (sz, sd) <- finalOptions eithers+  case genCabalText sz sd of+    Left e -> do+      IO.hPutStrLn IO.stderr "could not generate Cabal text."+      IO.hPutStr IO.stderr e+      exitFailure+    Right g -> printHeader sz sd >> putStr g >> exitSuccess++printHeader :: Word -> Int -> IO ()+printHeader sz sd = putStr $ unlines+  [ replicate 50 '-'+  , "-- below - size: " ++ show sz ++ " seed: " ++ show sd+  , replicate 50 '-'+  ]