packages feed

haskell-ci 0.1.0.0 → 0.2

raw patch · 48 files changed

+4216/−2357 lines, 48 filesdep +HsYAMLdep +base-compatdep +generic-lensdep ~Cabaldep ~Diffdep ~ShellChecknew-component:exe:haskell-cinew-uploaderPVP ok

version bump matches the API change (PVP)

Dependencies added: HsYAML, base-compat, generic-lens, microlens, optparse-applicative, parsec, pretty, text

Dependency ranges changed: Cabal, Diff, ShellCheck, ansi-terminal, base, bytestring, containers, deepseq, directory, filepath, tasty-golden, transformers

API changes (from Hackage documentation)

- MakeTravisYml: Error :: String -> Diagnostic
- MakeTravisYml: Failure :: [e] -> Result e a
- MakeTravisYml: Info :: String -> Diagnostic
- MakeTravisYml: Options :: [String] -> Maybe FilePath -> [String] -> Maybe FilePath -> Config -> Config -> Options
- MakeTravisYml: Success :: [e] -> a -> Result e a
- MakeTravisYml: Warn :: String -> Diagnostic
- MakeTravisYml: [optCollections] :: Options -> [String]
- MakeTravisYml: [optConfigMorphism] :: Options -> Config -> Config
- MakeTravisYml: [optConfig] :: Options -> Maybe FilePath
- MakeTravisYml: [optOsx] :: Options -> [String]
- MakeTravisYml: [optOutput] :: Options -> Maybe FilePath
- MakeTravisYml: data Diagnostic
- MakeTravisYml: data Options
- MakeTravisYml: data Result e a
- MakeTravisYml: defOptions :: Options
- MakeTravisYml: formatDiagnostic :: Diagnostic -> String
- MakeTravisYml: formatDiagnostics :: [Diagnostic] -> String
- MakeTravisYml: instance (GHC.Classes.Eq e, GHC.Classes.Eq a) => GHC.Classes.Eq (MakeTravisYml.Result e a)
- MakeTravisYml: instance (GHC.Show.Show e, GHC.Show.Show a) => GHC.Show.Show (MakeTravisYml.Result e a)
- MakeTravisYml: instance Data.Foldable.Foldable MakeTravisYml.Project
- MakeTravisYml: instance Data.Traversable.Traversable MakeTravisYml.Project
- MakeTravisYml: instance GHC.Base.Functor (MakeTravisYml.Result e)
- MakeTravisYml: instance GHC.Base.Functor MakeTravisYml.Project
- MakeTravisYml: instance GHC.Base.Monoid a => GHC.Base.Monoid (MakeTravisYml.Result e a)
- MakeTravisYml: instance GHC.Base.Monoid a => GHC.Base.Semigroup (MakeTravisYml.Result e a)
- MakeTravisYml: instance GHC.Classes.Eq MakeTravisYml.Diagnostic
- MakeTravisYml: instance GHC.Classes.Eq MakeTravisYml.FilePathGlob
- MakeTravisYml: instance GHC.Classes.Eq MakeTravisYml.FilePathGlobRel
- MakeTravisYml: instance GHC.Classes.Eq MakeTravisYml.FilePathRoot
- MakeTravisYml: instance GHC.Classes.Eq MakeTravisYml.Fold
- MakeTravisYml: instance GHC.Classes.Eq MakeTravisYml.GlobPiece
- MakeTravisYml: instance GHC.Classes.Eq MakeTravisYml.Package
- MakeTravisYml: instance GHC.Classes.Ord MakeTravisYml.Fold
- MakeTravisYml: instance GHC.Enum.Bounded MakeTravisYml.Fold
- MakeTravisYml: instance GHC.Enum.Enum MakeTravisYml.Fold
- MakeTravisYml: instance GHC.Show.Show MakeTravisYml.Config
- MakeTravisYml: instance GHC.Show.Show MakeTravisYml.ConstraintSet
- MakeTravisYml: instance GHC.Show.Show MakeTravisYml.Diagnostic
- MakeTravisYml: instance GHC.Show.Show MakeTravisYml.FilePathGlob
- MakeTravisYml: instance GHC.Show.Show MakeTravisYml.FilePathGlobRel
- MakeTravisYml: instance GHC.Show.Show MakeTravisYml.FilePathRoot
- MakeTravisYml: instance GHC.Show.Show MakeTravisYml.Fold
- MakeTravisYml: instance GHC.Show.Show MakeTravisYml.GlobPiece
- MakeTravisYml: instance GHC.Show.Show MakeTravisYml.Package
- MakeTravisYml: instance GHC.Show.Show a => GHC.Show.Show (MakeTravisYml.Project a)
- MakeTravisYml: main :: IO ()
- MakeTravisYml: options :: [OptDescr (Result Diagnostic (Options -> Options))]
- MakeTravisYml: parseOptsNoCommands :: [String] -> IO (Options, [String], FilePath, [String])
- MakeTravisYml: travisFromConfigFile :: MonadIO m => ([String], Options) -> FilePath -> [String] -> YamlWriter m ()
- MakeTravisYml: type MakeTravisOutput = Result Diagnostic [String]
+ HaskellCI: Error :: String -> Diagnostic
+ HaskellCI: Failure :: [e] -> Result e a
+ HaskellCI: Info :: String -> Diagnostic
+ HaskellCI: Options :: [String] -> Maybe FilePath -> Maybe FilePath -> (Config -> Config) -> Options
+ HaskellCI: Success :: [e] -> a -> Result e a
+ HaskellCI: Warn :: String -> Diagnostic
+ HaskellCI: [optCollections] :: Options -> [String]
+ HaskellCI: [optConfigMorphism] :: Options -> Config -> Config
+ HaskellCI: [optConfig] :: Options -> Maybe FilePath
+ HaskellCI: [optOutput] :: Options -> Maybe FilePath
+ HaskellCI: data Diagnostic
+ HaskellCI: data Options
+ HaskellCI: data Result e a
+ HaskellCI: defaultOptions :: Options
+ HaskellCI: formatDiagnostic :: Diagnostic -> String
+ HaskellCI: formatDiagnostics :: [Diagnostic] -> String
+ HaskellCI: main :: IO ()
+ HaskellCI: parseTravis :: [String] -> IO (FilePath, Options)
+ HaskellCI: travisFromConfigFile :: MonadIO m => [String] -> Options -> FilePath -> YamlWriter m ()
+ HaskellCI: type MakeTravisOutput = Result Diagnostic [String]
+ HaskellCI.Cli: CommandDumpConfig :: Command
+ HaskellCI.Cli: CommandListGHC :: Command
+ HaskellCI.Cli: CommandRegenerate :: Command
+ HaskellCI.Cli: CommandTravis :: FilePath -> Command
+ HaskellCI.Cli: Options :: [String] -> Maybe FilePath -> Maybe FilePath -> (Config -> Config) -> Options
+ HaskellCI.Cli: [optCollections] :: Options -> [String]
+ HaskellCI.Cli: [optConfigMorphism] :: Options -> Config -> Config
+ HaskellCI.Cli: [optConfig] :: Options -> Maybe FilePath
+ HaskellCI.Cli: [optOutput] :: Options -> Maybe FilePath
+ HaskellCI.Cli: cliParserInfo :: ParserInfo (Command, Options)
+ HaskellCI.Cli: data Command
+ HaskellCI.Cli: data Options
+ HaskellCI.Cli: defaultOptions :: Options
+ HaskellCI.Cli: instance GHC.Base.Semigroup HaskellCI.Cli.Options
+ HaskellCI.Cli: instance GHC.Show.Show HaskellCI.Cli.Command
+ HaskellCI.Cli: optionsP :: Parser Options
+ HaskellCI.Cli: parseTravis :: [String] -> IO (FilePath, Options)
+ HaskellCI.Config: Config :: Maybe Version -> Maybe Jobs -> !TestedWithJobs -> !CopyFields -> [String] -> !Bool -> !Bool -> !Bool -> [Installed] -> !VersionRange -> !VersionRange -> !VersionRange -> !VersionRange -> !VersionRange -> !Bool -> [String] -> [String] -> Maybe String -> Set Fold -> !Bool -> !Bool -> Map Version String -> !VersionRange -> !Bool -> Set Version -> Set String -> !DoctestConfig -> !HLintConfig -> [ConstraintSet] -> [PrettyField] -> Config
+ HaskellCI.Config: Env :: Map Version String -> Env
+ HaskellCI.Config: [cfgAllowFailures] :: Config -> !VersionRange
+ HaskellCI.Config: [cfgApt] :: Config -> Set String
+ HaskellCI.Config: [cfgBenchmarks] :: Config -> !VersionRange
+ HaskellCI.Config: [cfgCabalInstallVersion] :: Config -> Maybe Version
+ HaskellCI.Config: [cfgCache] :: Config -> !Bool
+ HaskellCI.Config: [cfgCheck] :: Config -> !Bool
+ HaskellCI.Config: [cfgConstraintSets] :: Config -> [ConstraintSet]
+ HaskellCI.Config: [cfgCopyFields] :: Config -> !CopyFields
+ HaskellCI.Config: [cfgDoctest] :: Config -> !DoctestConfig
+ HaskellCI.Config: [cfgEnv] :: Config -> Map Version String
+ HaskellCI.Config: [cfgFolds] :: Config -> Set Fold
+ HaskellCI.Config: [cfgGhcHead] :: Config -> !Bool
+ HaskellCI.Config: [cfgHLint] :: Config -> !HLintConfig
+ HaskellCI.Config: [cfgHaddock] :: Config -> !VersionRange
+ HaskellCI.Config: [cfgInstallDeps] :: Config -> !Bool
+ HaskellCI.Config: [cfgInstalled] :: Config -> [Installed]
+ HaskellCI.Config: [cfgIrcChannels] :: Config -> [String]
+ HaskellCI.Config: [cfgJobs] :: Config -> Maybe Jobs
+ HaskellCI.Config: [cfgLastInSeries] :: Config -> !Bool
+ HaskellCI.Config: [cfgLocalGhcOptions] :: Config -> [String]
+ HaskellCI.Config: [cfgNoTestsNoBench] :: Config -> !VersionRange
+ HaskellCI.Config: [cfgNoise] :: Config -> !Bool
+ HaskellCI.Config: [cfgOnlyBranches] :: Config -> [String]
+ HaskellCI.Config: [cfgOsx] :: Config -> Set Version
+ HaskellCI.Config: [cfgPostgres] :: Config -> !Bool
+ HaskellCI.Config: [cfgProjectName] :: Config -> Maybe String
+ HaskellCI.Config: [cfgRawProject] :: Config -> [PrettyField]
+ HaskellCI.Config: [cfgTestedWith] :: Config -> !TestedWithJobs
+ HaskellCI.Config: [cfgTests] :: Config -> !VersionRange
+ HaskellCI.Config: [cfgUnconstrainted] :: Config -> !VersionRange
+ HaskellCI.Config: configGrammar :: (OptionsGrammar g, Applicative (g Config), Applicative (g DoctestConfig), Applicative (g HLintConfig)) => g Config Config
+ HaskellCI.Config: data Config
+ HaskellCI.Config: defaultCabalInstallVersion :: Maybe Version
+ HaskellCI.Config: emptyConfig :: Config
+ HaskellCI.Config: instance Distribution.Compat.Newtype.Newtype HaskellCI.Config.Env (Data.Map.Internal.Map Distribution.Types.Version.Version GHC.Base.String)
+ HaskellCI.Config: instance Distribution.Parsec.Class.Parsec HaskellCI.Config.Env
+ HaskellCI.Config: instance Distribution.Pretty.Pretty HaskellCI.Config.Env
+ HaskellCI.Config: instance GHC.Generics.Generic HaskellCI.Config.Config
+ HaskellCI.Config: instance GHC.Show.Show HaskellCI.Config.Config
+ HaskellCI.Config: newtype Env
+ HaskellCI.Config: parseConfigFile :: [Field Position] -> ParseResult Config
+ HaskellCI.Config: parseName :: Position -> [SectionArg Position] -> ParseResult String
+ HaskellCI.Config: parseNameBS :: Position -> [SectionArg Position] -> ParseResult ByteString
+ HaskellCI.Config: readConfigFile :: MonadIO m => FilePath -> m Config
+ HaskellCI.Config.ConstraintSet: ConstraintSet :: String -> VersionRange -> [String] -> Bool -> ConstraintSet
+ HaskellCI.Config.ConstraintSet: [csConstraints] :: ConstraintSet -> [String]
+ HaskellCI.Config.ConstraintSet: [csGhcVersions] :: ConstraintSet -> VersionRange
+ HaskellCI.Config.ConstraintSet: [csName] :: ConstraintSet -> String
+ HaskellCI.Config.ConstraintSet: [csRunTests] :: ConstraintSet -> Bool
+ HaskellCI.Config.ConstraintSet: constraintSetGrammar :: (FieldGrammar g, Applicative (g ConstraintSet)) => String -> g ConstraintSet ConstraintSet
+ HaskellCI.Config.ConstraintSet: data ConstraintSet
+ HaskellCI.Config.ConstraintSet: emptyConstraintSet :: String -> ConstraintSet
+ HaskellCI.Config.ConstraintSet: instance GHC.Generics.Generic HaskellCI.Config.ConstraintSet.ConstraintSet
+ HaskellCI.Config.ConstraintSet: instance GHC.Show.Show HaskellCI.Config.ConstraintSet.ConstraintSet
+ HaskellCI.Config.CopyFields: CopyFieldsAll :: CopyFields
+ HaskellCI.Config.CopyFields: CopyFieldsNone :: CopyFields
+ HaskellCI.Config.CopyFields: CopyFieldsSome :: CopyFields
+ HaskellCI.Config.CopyFields: data CopyFields
+ HaskellCI.Config.CopyFields: instance Distribution.Parsec.Class.Parsec HaskellCI.Config.CopyFields.CopyFields
+ HaskellCI.Config.CopyFields: instance Distribution.Pretty.Pretty HaskellCI.Config.CopyFields.CopyFields
+ HaskellCI.Config.CopyFields: instance GHC.Classes.Eq HaskellCI.Config.CopyFields.CopyFields
+ HaskellCI.Config.CopyFields: instance GHC.Classes.Ord HaskellCI.Config.CopyFields.CopyFields
+ HaskellCI.Config.CopyFields: instance GHC.Enum.Bounded HaskellCI.Config.CopyFields.CopyFields
+ HaskellCI.Config.CopyFields: instance GHC.Enum.Enum HaskellCI.Config.CopyFields.CopyFields
+ HaskellCI.Config.CopyFields: instance GHC.Show.Show HaskellCI.Config.CopyFields.CopyFields
+ HaskellCI.Config.CopyFields: showCopyFields :: CopyFields -> String
+ HaskellCI.Config.Doctest: DoctestConfig :: !Bool -> [String] -> !VersionRange -> DoctestConfig
+ HaskellCI.Config.Doctest: [cfgDoctestEnabled] :: DoctestConfig -> !Bool
+ HaskellCI.Config.Doctest: [cfgDoctestOptions] :: DoctestConfig -> [String]
+ HaskellCI.Config.Doctest: [cfgDoctestVersion] :: DoctestConfig -> !VersionRange
+ HaskellCI.Config.Doctest: data DoctestConfig
+ HaskellCI.Config.Doctest: defaultDoctestVersion :: VersionRange
+ HaskellCI.Config.Doctest: doctestConfigGrammar :: (OptionsGrammar g, Applicative (g DoctestConfig)) => g DoctestConfig DoctestConfig
+ HaskellCI.Config.Doctest: instance GHC.Generics.Generic HaskellCI.Config.Doctest.DoctestConfig
+ HaskellCI.Config.Doctest: instance GHC.Show.Show HaskellCI.Config.Doctest.DoctestConfig
+ HaskellCI.Config.Dump: DG :: [String] -> DumpGrammar s a
+ HaskellCI.Config.Dump: [runDG] :: DumpGrammar s a -> [String]
+ HaskellCI.Config.Dump: instance Distribution.FieldGrammar.Class.FieldGrammar HaskellCI.Config.Dump.DumpGrammar
+ HaskellCI.Config.Dump: instance GHC.Base.Applicative (HaskellCI.Config.Dump.DumpGrammar s)
+ HaskellCI.Config.Dump: instance GHC.Base.Functor (HaskellCI.Config.Dump.DumpGrammar s)
+ HaskellCI.Config.Dump: instance HaskellCI.OptionsGrammar.OptionsGrammar HaskellCI.Config.Dump.DumpGrammar
+ HaskellCI.Config.Dump: newtype DumpGrammar s a
+ HaskellCI.Config.Folds: FoldBuild :: Fold
+ HaskellCI.Config.Folds: FoldBuildEverything :: Fold
+ HaskellCI.Config.Folds: FoldBuildInstalled :: Fold
+ HaskellCI.Config.Folds: FoldCheck :: Fold
+ HaskellCI.Config.Folds: FoldConstraintSets :: Fold
+ HaskellCI.Config.Folds: FoldDoctest :: Fold
+ HaskellCI.Config.Folds: FoldHLint :: Fold
+ HaskellCI.Config.Folds: FoldHaddock :: Fold
+ HaskellCI.Config.Folds: FoldSDist :: Fold
+ HaskellCI.Config.Folds: FoldStackage :: Fold
+ HaskellCI.Config.Folds: FoldTest :: Fold
+ HaskellCI.Config.Folds: FoldUnpack :: Fold
+ HaskellCI.Config.Folds: Folds :: Set Fold -> Folds
+ HaskellCI.Config.Folds: [getFolds] :: Folds -> Set Fold
+ HaskellCI.Config.Folds: data Fold
+ HaskellCI.Config.Folds: instance Distribution.Compat.Newtype.Newtype HaskellCI.Config.Folds.Folds (Data.Set.Internal.Set HaskellCI.Config.Folds.Fold)
+ HaskellCI.Config.Folds: instance Distribution.Parsec.Class.Parsec HaskellCI.Config.Folds.Folds
+ HaskellCI.Config.Folds: instance Distribution.Pretty.Pretty HaskellCI.Config.Folds.Folds
+ HaskellCI.Config.Folds: instance GHC.Classes.Eq HaskellCI.Config.Folds.Fold
+ HaskellCI.Config.Folds: instance GHC.Classes.Ord HaskellCI.Config.Folds.Fold
+ HaskellCI.Config.Folds: instance GHC.Enum.Bounded HaskellCI.Config.Folds.Fold
+ HaskellCI.Config.Folds: instance GHC.Enum.Enum HaskellCI.Config.Folds.Fold
+ HaskellCI.Config.Folds: instance GHC.Show.Show HaskellCI.Config.Folds.Fold
+ HaskellCI.Config.Folds: newtype Folds
+ HaskellCI.Config.Folds: possibleFolds :: [Fold]
+ HaskellCI.Config.Folds: showFold :: Fold -> String
+ HaskellCI.Config.HLint: HLintConfig :: !Bool -> !HLintJob -> !Maybe FilePath -> [String] -> !VersionRange -> HLintConfig
+ HaskellCI.Config.HLint: HLintJob :: Version -> HLintJob
+ HaskellCI.Config.HLint: HLintJobLatest :: HLintJob
+ HaskellCI.Config.HLint: [cfgHLintEnabled] :: HLintConfig -> !Bool
+ HaskellCI.Config.HLint: [cfgHLintJob] :: HLintConfig -> !HLintJob
+ HaskellCI.Config.HLint: [cfgHLintOptions] :: HLintConfig -> [String]
+ HaskellCI.Config.HLint: [cfgHLintVersion] :: HLintConfig -> !VersionRange
+ HaskellCI.Config.HLint: [cfgHLintYaml] :: HLintConfig -> !Maybe FilePath
+ HaskellCI.Config.HLint: data HLintConfig
+ HaskellCI.Config.HLint: data HLintJob
+ HaskellCI.Config.HLint: defaultHLintVersion :: VersionRange
+ HaskellCI.Config.HLint: hlintConfigGrammar :: (OptionsGrammar g, Applicative (g HLintConfig)) => g HLintConfig HLintConfig
+ HaskellCI.Config.HLint: instance Distribution.Parsec.Class.Parsec HaskellCI.Config.HLint.HLintJob
+ HaskellCI.Config.HLint: instance Distribution.Pretty.Pretty HaskellCI.Config.HLint.HLintJob
+ HaskellCI.Config.HLint: instance GHC.Classes.Eq HaskellCI.Config.HLint.HLintJob
+ HaskellCI.Config.HLint: instance GHC.Generics.Generic HaskellCI.Config.HLint.HLintConfig
+ HaskellCI.Config.HLint: instance GHC.Show.Show HaskellCI.Config.HLint.HLintConfig
+ HaskellCI.Config.HLint: instance GHC.Show.Show HaskellCI.Config.HLint.HLintJob
+ HaskellCI.Config.Installed: Add :: PackageName -> Installed
+ HaskellCI.Config.Installed: InstalledAll :: Installed
+ HaskellCI.Config.Installed: InstalledDiff :: Set PackageName -> InstalledNormalised
+ HaskellCI.Config.Installed: InstalledNone :: Installed
+ HaskellCI.Config.Installed: InstalledOnly :: Set PackageName -> InstalledNormalised
+ HaskellCI.Config.Installed: Remove :: PackageName -> Installed
+ HaskellCI.Config.Installed: data Installed
+ HaskellCI.Config.Installed: data InstalledNormalised
+ HaskellCI.Config.Installed: instance Distribution.Parsec.Class.Parsec HaskellCI.Config.Installed.Installed
+ HaskellCI.Config.Installed: instance Distribution.Pretty.Pretty HaskellCI.Config.Installed.Installed
+ HaskellCI.Config.Installed: instance GHC.Classes.Eq HaskellCI.Config.Installed.Installed
+ HaskellCI.Config.Installed: instance GHC.Show.Show HaskellCI.Config.Installed.Installed
+ HaskellCI.Config.Installed: instance GHC.Show.Show HaskellCI.Config.Installed.InstalledNormalised
+ HaskellCI.Config.Installed: normaliseInstalled :: [Installed] -> InstalledNormalised
+ HaskellCI.Config.Jobs: BothJobs :: Int -> Int -> Jobs
+ HaskellCI.Config.Jobs: CabalJobs :: Int -> Jobs
+ HaskellCI.Config.Jobs: GhcJobs :: Int -> Jobs
+ HaskellCI.Config.Jobs: cabalJobs :: Jobs -> Maybe Int
+ HaskellCI.Config.Jobs: data Jobs
+ HaskellCI.Config.Jobs: ghcJobs :: Jobs -> Maybe Int
+ HaskellCI.Config.Jobs: instance Distribution.Parsec.Class.Parsec HaskellCI.Config.Jobs.Jobs
+ HaskellCI.Config.Jobs: instance Distribution.Pretty.Pretty HaskellCI.Config.Jobs.Jobs
+ HaskellCI.Config.Jobs: instance GHC.Show.Show HaskellCI.Config.Jobs.Jobs
+ HaskellCI.Extras: afterInfix :: Eq a => [a] -> [a] -> Maybe [a]
+ HaskellCI.Extras: afterPrefix :: Eq a => [a] -> [a] -> Maybe [a]
+ HaskellCI.Extras: findMaybe :: (a -> Maybe b) -> [a] -> Maybe b
+ HaskellCI.GHC: dispGhcVersion :: Maybe Version -> String
+ HaskellCI.GHC: ghcAlpha :: Maybe Version
+ HaskellCI.GHC: ghcMajVer :: Version -> (Int, Int)
+ HaskellCI.GHC: knownGhcVersions :: [Version]
+ HaskellCI.GHC: previewGHC :: Maybe Version -> Bool
+ HaskellCI.Glob: FilePathGlob :: FilePathRoot -> FilePathGlobRel -> FilePathGlob
+ HaskellCI.Glob: FilePathHomeDir :: FilePathRoot
+ HaskellCI.Glob: FilePathRelative :: FilePathRoot
+ HaskellCI.Glob: FilePathRoot :: FilePath -> FilePathRoot
+ HaskellCI.Glob: GlobDir :: Glob -> FilePathGlobRel -> FilePathGlobRel
+ HaskellCI.Glob: GlobDirTrailing :: FilePathGlobRel
+ HaskellCI.Glob: GlobFile :: Glob -> FilePathGlobRel
+ HaskellCI.Glob: Literal :: String -> GlobPiece
+ HaskellCI.Glob: Union :: [Glob] -> GlobPiece
+ HaskellCI.Glob: WildCard :: GlobPiece
+ HaskellCI.Glob: data FilePathGlob
+ HaskellCI.Glob: data FilePathGlobRel
+ HaskellCI.Glob: data FilePathRoot
+ HaskellCI.Glob: data GlobPiece
+ HaskellCI.Glob: expandRelGlob :: MonadIO m => FilePath -> FilePathGlobRel -> m [FilePath]
+ HaskellCI.Glob: instance GHC.Classes.Eq HaskellCI.Glob.FilePathGlob
+ HaskellCI.Glob: instance GHC.Classes.Eq HaskellCI.Glob.FilePathGlobRel
+ HaskellCI.Glob: instance GHC.Classes.Eq HaskellCI.Glob.FilePathRoot
+ HaskellCI.Glob: instance GHC.Classes.Eq HaskellCI.Glob.GlobPiece
+ HaskellCI.Glob: instance GHC.Show.Show HaskellCI.Glob.FilePathGlob
+ HaskellCI.Glob: instance GHC.Show.Show HaskellCI.Glob.FilePathGlobRel
+ HaskellCI.Glob: instance GHC.Show.Show HaskellCI.Glob.FilePathRoot
+ HaskellCI.Glob: instance GHC.Show.Show HaskellCI.Glob.GlobPiece
+ HaskellCI.Glob: isGlobEscapedChar :: Char -> Bool
+ HaskellCI.Glob: matchGlob :: Glob -> FilePath -> Bool
+ HaskellCI.Glob: parseFilePathGlobRel :: ReadP r FilePathGlobRel
+ HaskellCI.Glob: parseGlob :: ReadP r Glob
+ HaskellCI.Glob: type Glob = [GlobPiece]
+ HaskellCI.MakeTravisOutput: Error :: String -> Diagnostic
+ HaskellCI.MakeTravisOutput: Failure :: [e] -> Result e a
+ HaskellCI.MakeTravisOutput: Info :: String -> Diagnostic
+ HaskellCI.MakeTravisOutput: Row :: String -> Row
+ HaskellCI.MakeTravisOutput: RowErr :: String -> Row
+ HaskellCI.MakeTravisOutput: RowSkip :: Row
+ HaskellCI.MakeTravisOutput: Success :: [e] -> a -> Result e a
+ HaskellCI.MakeTravisOutput: Warn :: String -> Diagnostic
+ HaskellCI.MakeTravisOutput: blank :: Row
+ HaskellCI.MakeTravisOutput: comment :: String -> Row
+ HaskellCI.MakeTravisOutput: data Diagnostic
+ HaskellCI.MakeTravisOutput: data Result e a
+ HaskellCI.MakeTravisOutput: data Row
+ HaskellCI.MakeTravisOutput: foldedTellStrLns :: Monad m => Fold -> String -> Set Fold -> YamlWriter m () -> YamlWriter m ()
+ HaskellCI.MakeTravisOutput: foldedTellStrLns' :: Monad m => Fold -> String -> String -> Set Fold -> YamlWriter m () -> YamlWriter m ()
+ HaskellCI.MakeTravisOutput: formatDiagnostic :: Diagnostic -> String
+ HaskellCI.MakeTravisOutput: formatDiagnostics :: [Diagnostic] -> String
+ HaskellCI.MakeTravisOutput: instance (GHC.Classes.Eq e, GHC.Classes.Eq a) => GHC.Classes.Eq (HaskellCI.MakeTravisOutput.Result e a)
+ HaskellCI.MakeTravisOutput: instance (GHC.Show.Show e, GHC.Show.Show a) => GHC.Show.Show (HaskellCI.MakeTravisOutput.Result e a)
+ HaskellCI.MakeTravisOutput: instance Data.String.IsString HaskellCI.MakeTravisOutput.Row
+ HaskellCI.MakeTravisOutput: instance GHC.Base.Functor (HaskellCI.MakeTravisOutput.Result e)
+ HaskellCI.MakeTravisOutput: instance GHC.Base.Monoid a => GHC.Base.Monoid (HaskellCI.MakeTravisOutput.Result e a)
+ HaskellCI.MakeTravisOutput: instance GHC.Base.Monoid a => GHC.Base.Semigroup (HaskellCI.MakeTravisOutput.Result e a)
+ HaskellCI.MakeTravisOutput: instance GHC.Classes.Eq HaskellCI.MakeTravisOutput.Diagnostic
+ HaskellCI.MakeTravisOutput: instance GHC.Show.Show HaskellCI.MakeTravisOutput.Diagnostic
+ HaskellCI.MakeTravisOutput: putStrLnErr :: Monad m => String -> YamlWriter m a
+ HaskellCI.MakeTravisOutput: putStrLnErrs :: Monad m => [String] -> YamlWriter m ()
+ HaskellCI.MakeTravisOutput: putStrLnInfo :: Monad m => String -> YamlWriter m ()
+ HaskellCI.MakeTravisOutput: putStrLnWarn :: Monad m => String -> YamlWriter m ()
+ HaskellCI.MakeTravisOutput: rawRow :: String -> Row
+ HaskellCI.MakeTravisOutput: sequenceRows :: [Row] -> Either String [String]
+ HaskellCI.MakeTravisOutput: sh :: String -> Row
+ HaskellCI.MakeTravisOutput: sh' :: [Integer] -> String -> Row
+ HaskellCI.MakeTravisOutput: shForJob :: Set Version -> VersionRange -> String -> Row
+ HaskellCI.MakeTravisOutput: shImpl :: String -> String
+ HaskellCI.MakeTravisOutput: success :: a -> Result e a
+ HaskellCI.MakeTravisOutput: tellStrLn :: Monad m => String -> YamlWriter m ()
+ HaskellCI.MakeTravisOutput: tellStrLns :: Monad m => [Row] -> YamlWriter m ()
+ HaskellCI.MakeTravisOutput: tellStrLnsRaw :: Monad m => [String] -> YamlWriter m ()
+ HaskellCI.MakeTravisOutput: type MakeTravisOutput = Result Diagnostic [String]
+ HaskellCI.MakeTravisOutput: type YamlWriter m a = MaybeT (WriterT MakeTravisOutput m) a
+ HaskellCI.Newtypes: AlaSet :: Set a -> AlaSet sep b a
+ HaskellCI.Newtypes: HeadVersion :: Maybe Version -> HeadVersion
+ HaskellCI.Newtypes: Int' :: Int -> Int'
+ HaskellCI.Newtypes: NoCommas :: String -> NoCommas
+ HaskellCI.Newtypes: PackageLocation :: String -> PackageLocation
+ HaskellCI.Newtypes: Range :: VersionRange -> Range
+ HaskellCI.Newtypes: [getAlaSet] :: AlaSet sep b a -> Set a
+ HaskellCI.Newtypes: [getHeadVersion] :: HeadVersion -> Maybe Version
+ HaskellCI.Newtypes: alaSet :: sep -> Set a -> AlaSet sep (Identity a) a
+ HaskellCI.Newtypes: alaSet' :: sep -> (a -> b) -> Set a -> AlaSet sep b a
+ HaskellCI.Newtypes: class Sep sep
+ HaskellCI.Newtypes: instance (Distribution.Compat.Newtype.Newtype b a, GHC.Classes.Ord a, HaskellCI.Newtypes.Sep sep, Distribution.Parsec.Class.Parsec b) => Distribution.Parsec.Class.Parsec (HaskellCI.Newtypes.AlaSet sep b a)
+ HaskellCI.Newtypes: instance (Distribution.Compat.Newtype.Newtype b a, HaskellCI.Newtypes.Sep sep, Distribution.Pretty.Pretty b) => Distribution.Pretty.Pretty (HaskellCI.Newtypes.AlaSet sep b a)
+ HaskellCI.Newtypes: instance Distribution.Compat.Newtype.Newtype (HaskellCI.Newtypes.AlaSet sep wrapper a) (Data.Set.Internal.Set a)
+ HaskellCI.Newtypes: instance Distribution.Compat.Newtype.Newtype HaskellCI.Newtypes.HeadVersion (GHC.Maybe.Maybe Distribution.Types.Version.Version)
+ HaskellCI.Newtypes: instance Distribution.Compat.Newtype.Newtype HaskellCI.Newtypes.Int' GHC.Types.Int
+ HaskellCI.Newtypes: instance Distribution.Compat.Newtype.Newtype HaskellCI.Newtypes.NoCommas [GHC.Types.Char]
+ HaskellCI.Newtypes: instance Distribution.Compat.Newtype.Newtype HaskellCI.Newtypes.PackageLocation [GHC.Types.Char]
+ HaskellCI.Newtypes: instance Distribution.Compat.Newtype.Newtype HaskellCI.Newtypes.Range Distribution.Types.VersionRange.VersionRange
+ HaskellCI.Newtypes: instance Distribution.Parsec.Class.Parsec HaskellCI.Newtypes.HeadVersion
+ HaskellCI.Newtypes: instance Distribution.Parsec.Class.Parsec HaskellCI.Newtypes.Int'
+ HaskellCI.Newtypes: instance Distribution.Parsec.Class.Parsec HaskellCI.Newtypes.NoCommas
+ HaskellCI.Newtypes: instance Distribution.Parsec.Class.Parsec HaskellCI.Newtypes.PackageLocation
+ HaskellCI.Newtypes: instance Distribution.Parsec.Class.Parsec HaskellCI.Newtypes.Range
+ HaskellCI.Newtypes: instance Distribution.Pretty.Pretty HaskellCI.Newtypes.HeadVersion
+ HaskellCI.Newtypes: instance Distribution.Pretty.Pretty HaskellCI.Newtypes.Int'
+ HaskellCI.Newtypes: instance Distribution.Pretty.Pretty HaskellCI.Newtypes.NoCommas
+ HaskellCI.Newtypes: instance Distribution.Pretty.Pretty HaskellCI.Newtypes.PackageLocation
+ HaskellCI.Newtypes: instance Distribution.Pretty.Pretty HaskellCI.Newtypes.Range
+ HaskellCI.Newtypes: instance HaskellCI.Newtypes.Sep Distribution.Parsec.Newtypes.CommaFSep
+ HaskellCI.Newtypes: instance HaskellCI.Newtypes.Sep Distribution.Parsec.Newtypes.CommaVCat
+ HaskellCI.Newtypes: instance HaskellCI.Newtypes.Sep Distribution.Parsec.Newtypes.NoCommaFSep
+ HaskellCI.Newtypes: newtype AlaSet sep b a
+ HaskellCI.Newtypes: newtype HeadVersion
+ HaskellCI.Newtypes: newtype Int'
+ HaskellCI.Newtypes: newtype NoCommas
+ HaskellCI.Newtypes: newtype PackageLocation
+ HaskellCI.Newtypes: newtype Range
+ HaskellCI.Newtypes: parseSep :: (Sep sep, CabalParsing m) => Proxy sep -> m a -> m [a]
+ HaskellCI.Newtypes: prettySep :: Sep sep => Proxy sep -> [Doc] -> Doc
+ HaskellCI.Optimization: OptimizationLevel :: Int -> Optimization
+ HaskellCI.Optimization: OptimizationOff :: Optimization
+ HaskellCI.Optimization: OptimizationOn :: Optimization
+ HaskellCI.Optimization: data Optimization
+ HaskellCI.Optimization: instance Distribution.Parsec.Class.Parsec HaskellCI.Optimization.Optimization
+ HaskellCI.Optimization: instance Distribution.Pretty.Pretty HaskellCI.Optimization.Optimization
+ HaskellCI.Optimization: instance GHC.Classes.Eq HaskellCI.Optimization.Optimization
+ HaskellCI.Optimization: instance GHC.Show.Show HaskellCI.Optimization.Optimization
+ HaskellCI.OptionsGrammar: (^^^) :: () => a -> (a -> b) -> b
+ HaskellCI.OptionsGrammar: class FieldGrammar p => OptionsGrammar p
+ HaskellCI.OptionsGrammar: help :: OptionsGrammar p => String -> p s a -> p s a
+ HaskellCI.OptionsGrammar: infixl 5 ^^^
+ HaskellCI.OptionsGrammar: instance HaskellCI.OptionsGrammar.OptionsGrammar Distribution.FieldGrammar.Parsec.ParsecFieldGrammar
+ HaskellCI.OptionsGrammar: metahelp :: OptionsGrammar p => String -> String -> p s a -> p s a
+ HaskellCI.OptionsGrammar: rangeField :: OptionsGrammar p => FieldName -> ALens' s VersionRange -> VersionRange -> p s VersionRange
+ HaskellCI.OptparseGrammar: data OptparseGrammar s a
+ HaskellCI.OptparseGrammar: instance Distribution.FieldGrammar.Class.FieldGrammar HaskellCI.OptparseGrammar.OptparseGrammar
+ HaskellCI.OptparseGrammar: instance GHC.Base.Applicative (HaskellCI.OptparseGrammar.OptparseGrammar s)
+ HaskellCI.OptparseGrammar: instance GHC.Base.Functor (HaskellCI.OptparseGrammar.OptparseGrammar s)
+ HaskellCI.OptparseGrammar: instance HaskellCI.OptionsGrammar.OptionsGrammar HaskellCI.OptparseGrammar.OptparseGrammar
+ HaskellCI.OptparseGrammar: runOptparseGrammar :: OptparseGrammar s a -> Parser (s -> s)
+ HaskellCI.Package: Pkg :: String -> VersionRange -> FilePath -> GenericPackageDescription -> Package
+ HaskellCI.Package: [pkgDir] :: Package -> FilePath
+ HaskellCI.Package: [pkgGpd] :: Package -> GenericPackageDescription
+ HaskellCI.Package: [pkgJobs] :: Package -> VersionRange
+ HaskellCI.Package: [pkgName] :: Package -> String
+ HaskellCI.Package: data Package
+ HaskellCI.Package: instance GHC.Classes.Eq HaskellCI.Package.Package
+ HaskellCI.Package: instance GHC.Show.Show HaskellCI.Package.Package
+ HaskellCI.ParsecError: renderParseError :: FilePath -> ByteString -> [PError] -> [PWarning] -> String
+ HaskellCI.ParsecUtils: readAndParseFile :: ([Field Position] -> ParseResult a) -> FilePath -> IO a
+ HaskellCI.Project: Project :: [a] -> [String] -> [String] -> Bool -> Maybe Int -> Optimization -> [SourceRepo] -> [PrettyField] -> Project a
+ HaskellCI.Project: [prjAllowNewer] :: Project a -> [String]
+ HaskellCI.Project: [prjConstraints] :: Project a -> [String]
+ HaskellCI.Project: [prjMaxBackjumps] :: Project a -> Maybe Int
+ HaskellCI.Project: [prjOptimization] :: Project a -> Optimization
+ HaskellCI.Project: [prjOrigFields] :: Project a -> [PrettyField]
+ HaskellCI.Project: [prjPackages] :: Project a -> [a]
+ HaskellCI.Project: [prjReorderGoals] :: Project a -> Bool
+ HaskellCI.Project: [prjSourceRepos] :: Project a -> [SourceRepo]
+ HaskellCI.Project: data Project a
+ HaskellCI.Project: emptyProject :: Project [a]
+ HaskellCI.Project: instance Data.Foldable.Foldable HaskellCI.Project.Project
+ HaskellCI.Project: instance Data.Traversable.Traversable HaskellCI.Project.Project
+ HaskellCI.Project: instance GHC.Base.Functor HaskellCI.Project.Project
+ HaskellCI.Project: instance GHC.Generics.Generic (HaskellCI.Project.Project a)
+ HaskellCI.Project: instance GHC.Show.Show a => GHC.Show.Show (HaskellCI.Project.Project a)
+ HaskellCI.Project: parseProjectFile :: FilePath -> ByteString -> Either String (Project String)
+ HaskellCI.TestedWith: TestedWithAny :: TestedWithJobs
+ HaskellCI.TestedWith: TestedWithUniform :: TestedWithJobs
+ HaskellCI.TestedWith: checkVersions :: TestedWithJobs -> Project (Package, Set Version) -> Either [String] (Set Version, Project Package)
+ HaskellCI.TestedWith: data TestedWithJobs
+ HaskellCI.TestedWith: instance Distribution.Parsec.Class.Parsec HaskellCI.TestedWith.TestedWithJobs
+ HaskellCI.TestedWith: instance Distribution.Pretty.Pretty HaskellCI.TestedWith.TestedWithJobs
+ HaskellCI.TestedWith: instance GHC.Classes.Eq HaskellCI.TestedWith.TestedWithJobs
+ HaskellCI.TestedWith: instance GHC.Show.Show HaskellCI.TestedWith.TestedWithJobs
+ HaskellCI.Version: equivVersionRanges :: VersionRange -> VersionRange -> Bool
+ HaskellCI.Version: ghcVersionPredicate :: VersionRange -> String
+ HaskellCI.Version: ghcVersionToString :: Version -> String

Files

− Main.hs
@@ -1,2 +0,0 @@-module Main (main) where-import MakeTravisYml (main)
+ cli/Main.hs view
@@ -0,0 +1,2 @@+module Main (main) where+import HaskellCI (main)
fixtures/cabal.haskell-ci view
@@ -1,8 +1,11 @@ -- Most settings can be given as command line arguments--- Config file is convinient if you maintain large amount of packages+-- Config file is convenient if you maintain large amount of packages  jobs: 2:2 +-- Add GHC head job+ghc-head: True+ -- travis Caching -- cache: True @@ -21,9 +24,8 @@ -- no-tests-no-bench: True  -- By default `installed` constraints are used for packages--- in global db. Unconstrained step is a build without them.--- Note: solver might or might not pick newer versions.--- unconstrained-step: True+-- in global db. We can modify which constraints are used.+installed: +all -Cabal  -- Options for local packages local-ghc-options: -Werror@@ -48,6 +50,9 @@ doctest-options: --fast -- doctest-version: ==0.13.* +-- macOS job+osx: 8.4.4+ -- Constraint sets -- Package will be build with different constraints. -- This is useful to check compatibility with older versions of dependencies.@@ -55,3 +60,9 @@ constraint-set deepseq-1.4   ghc: (>= 7.8 && <7.10) || == 8.2.2   constraints: deepseq ==1.4.*++-- Include these fields "as is" in generated cabal.project+raw-project+  keep-going: False+  package bytestring+    tests: False
+ fixtures/cabal.project.copy-fields.all view
@@ -0,0 +1,15 @@+packages:+  servant/+  servant-client/+  servant-docs/+  servant-server/++package servant+  tests: False++constraints: foundation >= 0.14++allow-newer:+  servant-js:servant+allow-newer:+  servant-js:servant-foreign
+ fixtures/cabal.project.copy-fields.all.stderr view
@@ -0,0 +1,1 @@+*INFO* Generating Travis-CI config for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3
+ fixtures/cabal.project.copy-fields.all.travis.yml view
@@ -0,0 +1,164 @@+# This Travis job script has been generated by a script via+#+#   haskell-ci '-o' 'cabal.project.empty-line.travis.yml' '--copy-fields=all' 'cabal.project.empty-line'+#+# For more information, see https://github.com/haskell-CI/haskell-ci+#+# version: 0.2+#+language: c+dist: xenial++git:+  submodules: false  # whether to recursively clone submodules++cache:+  directories:+    - $HOME/.cabal/packages+    - $HOME/.cabal/store++before_cache:+  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log+  # remove files that are regenerated by 'cabal update'+  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*+  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx++  - rm -rfv $CABALHOME/packages/head.hackage++matrix:+  include:+    - compiler: "ghc-8.6.3"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.6.3], sources: [hvr-ghc]}}+    - compiler: "ghc-8.6.2"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.6.2], sources: [hvr-ghc]}}+    - compiler: "ghc-8.6.1"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.6.1], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.4"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.4], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.3"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.3], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.2"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.2], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.1"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.1], sources: [hvr-ghc]}}+    - compiler: "ghc-8.2.2"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.2.2], sources: [hvr-ghc]}}+    - compiler: "ghc-8.2.1"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.2.1], sources: [hvr-ghc]}}+    - compiler: "ghc-8.0.2"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.0.2], sources: [hvr-ghc]}}+    - compiler: "ghc-8.0.1"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.0.1], sources: [hvr-ghc]}}+    - compiler: "ghc-7.10.3"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.10.3], sources: [hvr-ghc]}}+    - compiler: "ghc-7.10.2"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.10.2], sources: [hvr-ghc]}}+    - compiler: "ghc-7.10.1"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.10.1], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.4"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.4], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.3"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.3], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.2"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.2], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.1"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.1], sources: [hvr-ghc]}}++before_install:+  - HC=/opt/ghc/bin/${CC}+  - HCPKG=${HC/ghc/ghc-pkg}+  - unset CC+  - CABAL=/opt/ghc/bin/cabal+  - CABALHOME=$HOME/.cabal+  - export PATH="$CABALHOME/bin:$PATH"+  - ROOTDIR=$(pwd)+  - HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\1 * 10000 + \2 * 100 + \3/') ))+  - echo $HCNUMVER++install:+  - ${CABAL} --version+  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"+  - TEST=--enable-tests+  - BENCH=--enable-benchmarks+  - GHCHEAD=${GHCHEAD-false}+  - travis_retry ${CABAL} update -v+  - sed -i.bak 's/^jobs:/-- jobs:/' $CABALHOME/config+  - rm -fv cabal.project cabal.project.local+  - grep -Ev -- '^\s*--' $CABALHOME/config | grep -Ev '^\s*$'+  - rm -f cabal.project+  - touch cabal.project+  - "printf 'packages: \"servant\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-client\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-docs\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-server\"\\n' >> cabal.project"+  - echo 'package servant' >> cabal.project+  - "echo '  tests: False' >> cabal.project"+  - "echo 'constraints: foundation >= 0.14' >> cabal.project"+  - "echo 'allow-newer: servant-js:servant' >> cabal.project"+  - "echo 'allow-newer: servant-js:servant-foreign' >> cabal.project"+  - "printf 'write-ghc-environment-files: always\\n' >> cabal.project"+  - touch cabal.project.local+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"+  - cat cabal.project || true+  - cat cabal.project.local || true+  - if [ -f "servant/configure.ac" ]; then (cd "servant" && autoreconf -i); fi+  - if [ -f "servant-client/configure.ac" ]; then (cd "servant-client" && autoreconf -i); fi+  - if [ -f "servant-docs/configure.ac" ]; then (cd "servant-docs" && autoreconf -i); fi+  - if [ -f "servant-server/configure.ac" ]; then (cd "servant-server" && autoreconf -i); fi+  - rm -f cabal.project.freeze+  - ${CABAL} new-freeze -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project.copy-fields.all" --dry+  - "cat \"cabal.project.copy-fields.all.freeze\" | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"+  - rm  "cabal.project.copy-fields.all.freeze"+  - ${CABAL} new-build -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project.copy-fields.all" --dep -j2 all+  - ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks --project-file="cabal.project.copy-fields.all" --dep -j2 all+  - rm -rf .ghc.environment.* "servant"/dist "servant-client"/dist "servant-docs"/dist "servant-server"/dist+  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)++# Here starts the actual work to be performed for the package under test;+# any command which exits with a non-zero exit code causes the build to fail.+script:+  # test that source-distributions can be generated+  - ${CABAL} new-sdist all+  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/+  - cd ${DISTDIR} || false+  - find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \;+  - rm -f cabal.project+  - touch cabal.project+  - "printf 'packages: \"servant-*/*.cabal\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-client-*/*.cabal\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-docs-*/*.cabal\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-server-*/*.cabal\"\\n' >> cabal.project"+  - echo 'package servant' >> cabal.project+  - "echo '  tests: False' >> cabal.project"+  - "echo 'constraints: foundation >= 0.14' >> cabal.project"+  - "echo 'allow-newer: servant-js:servant' >> cabal.project"+  - "echo 'allow-newer: servant-js:servant-foreign' >> cabal.project"+  - "printf 'write-ghc-environment-files: always\\n' >> cabal.project"+  - touch cabal.project.local+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"+  - cat cabal.project || true+  - cat cabal.project.local || true+  # this builds all libraries and executables (without tests/benchmarks)+  - ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks all++  # build & run tests, build benchmarks+  - ${CABAL} new-build -w ${HC} ${TEST} ${BENCH} all+  - if [ "x$TEST" = "x--enable-tests" ]; then ${CABAL} new-test -w ${HC} ${TEST} ${BENCH} all; fi++  # cabal check+  - (cd servant-* && ${CABAL} check)+  - (cd servant-client-* && ${CABAL} check)+  - (cd servant-docs-* && ${CABAL} check)+  - (cd servant-server-* && ${CABAL} check)++  # haddock+  - ${CABAL} new-haddock -w ${HC} ${TEST} ${BENCH} all++  # Build without installed constraints for packages in global-db+  - rm -f cabal.project.local; ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks all;++# REGENDATA ["-o","cabal.project.empty-line.travis.yml","--copy-fields=all","cabal.project.empty-line"]+# EOF
+ fixtures/cabal.project.copy-fields.none view
@@ -0,0 +1,15 @@+packages:+  servant/+  servant-client/+  servant-docs/+  servant-server/++package servant+  tests: False++constraints: foundation >= 0.14++allow-newer:+  servant-js:servant+allow-newer:+  servant-js:servant-foreign
+ fixtures/cabal.project.copy-fields.none.stderr view
@@ -0,0 +1,1 @@+*INFO* Generating Travis-CI config for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3
+ fixtures/cabal.project.copy-fields.none.travis.yml view
@@ -0,0 +1,154 @@+# This Travis job script has been generated by a script via+#+#   haskell-ci '-o' 'cabal.project.empty-line.travis.yml' '--copy-fields=none' 'cabal.project.empty-line'+#+# For more information, see https://github.com/haskell-CI/haskell-ci+#+# version: 0.2+#+language: c+dist: xenial++git:+  submodules: false  # whether to recursively clone submodules++cache:+  directories:+    - $HOME/.cabal/packages+    - $HOME/.cabal/store++before_cache:+  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log+  # remove files that are regenerated by 'cabal update'+  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*+  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx++  - rm -rfv $CABALHOME/packages/head.hackage++matrix:+  include:+    - compiler: "ghc-8.6.3"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.6.3], sources: [hvr-ghc]}}+    - compiler: "ghc-8.6.2"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.6.2], sources: [hvr-ghc]}}+    - compiler: "ghc-8.6.1"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.6.1], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.4"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.4], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.3"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.3], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.2"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.2], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.1"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.1], sources: [hvr-ghc]}}+    - compiler: "ghc-8.2.2"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.2.2], sources: [hvr-ghc]}}+    - compiler: "ghc-8.2.1"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.2.1], sources: [hvr-ghc]}}+    - compiler: "ghc-8.0.2"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.0.2], sources: [hvr-ghc]}}+    - compiler: "ghc-8.0.1"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.0.1], sources: [hvr-ghc]}}+    - compiler: "ghc-7.10.3"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.10.3], sources: [hvr-ghc]}}+    - compiler: "ghc-7.10.2"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.10.2], sources: [hvr-ghc]}}+    - compiler: "ghc-7.10.1"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.10.1], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.4"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.4], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.3"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.3], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.2"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.2], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.1"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.1], sources: [hvr-ghc]}}++before_install:+  - HC=/opt/ghc/bin/${CC}+  - HCPKG=${HC/ghc/ghc-pkg}+  - unset CC+  - CABAL=/opt/ghc/bin/cabal+  - CABALHOME=$HOME/.cabal+  - export PATH="$CABALHOME/bin:$PATH"+  - ROOTDIR=$(pwd)+  - HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\1 * 10000 + \2 * 100 + \3/') ))+  - echo $HCNUMVER++install:+  - ${CABAL} --version+  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"+  - TEST=--enable-tests+  - BENCH=--enable-benchmarks+  - GHCHEAD=${GHCHEAD-false}+  - travis_retry ${CABAL} update -v+  - sed -i.bak 's/^jobs:/-- jobs:/' $CABALHOME/config+  - rm -fv cabal.project cabal.project.local+  - grep -Ev -- '^\s*--' $CABALHOME/config | grep -Ev '^\s*$'+  - rm -f cabal.project+  - touch cabal.project+  - "printf 'packages: \"servant\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-client\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-docs\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-server\"\\n' >> cabal.project"+  - "printf 'write-ghc-environment-files: always\\n' >> cabal.project"+  - touch cabal.project.local+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"+  - cat cabal.project || true+  - cat cabal.project.local || true+  - if [ -f "servant/configure.ac" ]; then (cd "servant" && autoreconf -i); fi+  - if [ -f "servant-client/configure.ac" ]; then (cd "servant-client" && autoreconf -i); fi+  - if [ -f "servant-docs/configure.ac" ]; then (cd "servant-docs" && autoreconf -i); fi+  - if [ -f "servant-server/configure.ac" ]; then (cd "servant-server" && autoreconf -i); fi+  - rm -f cabal.project.freeze+  - ${CABAL} new-freeze -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project.copy-fields.none" --dry+  - "cat \"cabal.project.copy-fields.none.freeze\" | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"+  - rm  "cabal.project.copy-fields.none.freeze"+  - ${CABAL} new-build -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project.copy-fields.none" --dep -j2 all+  - ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks --project-file="cabal.project.copy-fields.none" --dep -j2 all+  - rm -rf .ghc.environment.* "servant"/dist "servant-client"/dist "servant-docs"/dist "servant-server"/dist+  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)++# Here starts the actual work to be performed for the package under test;+# any command which exits with a non-zero exit code causes the build to fail.+script:+  # test that source-distributions can be generated+  - ${CABAL} new-sdist all+  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/+  - cd ${DISTDIR} || false+  - find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \;+  - rm -f cabal.project+  - touch cabal.project+  - "printf 'packages: \"servant-*/*.cabal\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-client-*/*.cabal\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-docs-*/*.cabal\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-server-*/*.cabal\"\\n' >> cabal.project"+  - "printf 'write-ghc-environment-files: always\\n' >> cabal.project"+  - touch cabal.project.local+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"+  - cat cabal.project || true+  - cat cabal.project.local || true+  # this builds all libraries and executables (without tests/benchmarks)+  - ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks all++  # build & run tests, build benchmarks+  - ${CABAL} new-build -w ${HC} ${TEST} ${BENCH} all+  - if [ "x$TEST" = "x--enable-tests" ]; then ${CABAL} new-test -w ${HC} ${TEST} ${BENCH} all; fi++  # cabal check+  - (cd servant-* && ${CABAL} check)+  - (cd servant-client-* && ${CABAL} check)+  - (cd servant-docs-* && ${CABAL} check)+  - (cd servant-server-* && ${CABAL} check)++  # haddock+  - ${CABAL} new-haddock -w ${HC} ${TEST} ${BENCH} all++  # Build without installed constraints for packages in global-db+  - rm -f cabal.project.local; ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks all;++# REGENDATA ["-o","cabal.project.empty-line.travis.yml","--copy-fields=none","cabal.project.empty-line"]+# EOF
+ fixtures/cabal.project.copy-fields.some view
@@ -0,0 +1,15 @@+packages:+  servant/+  servant-client/+  servant-docs/+  servant-server/++package servant+  tests: False++constraints: foundation >= 0.14++allow-newer:+  servant-js:servant+allow-newer:+  servant-js:servant-foreign
+ fixtures/cabal.project.copy-fields.some.stderr view
@@ -0,0 +1,1 @@+*INFO* Generating Travis-CI config for testing for GHC versions: 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3
+ fixtures/cabal.project.copy-fields.some.travis.yml view
@@ -0,0 +1,160 @@+# This Travis job script has been generated by a script via+#+#   haskell-ci '-o' 'cabal.project.empty-line.travis.yml' '--copy-fields=some' 'cabal.project.empty-line'+#+# For more information, see https://github.com/haskell-CI/haskell-ci+#+# version: 0.2+#+language: c+dist: xenial++git:+  submodules: false  # whether to recursively clone submodules++cache:+  directories:+    - $HOME/.cabal/packages+    - $HOME/.cabal/store++before_cache:+  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log+  # remove files that are regenerated by 'cabal update'+  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*+  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx++  - rm -rfv $CABALHOME/packages/head.hackage++matrix:+  include:+    - compiler: "ghc-8.6.3"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.6.3], sources: [hvr-ghc]}}+    - compiler: "ghc-8.6.2"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.6.2], sources: [hvr-ghc]}}+    - compiler: "ghc-8.6.1"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.6.1], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.4"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.4], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.3"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.3], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.2"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.2], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.1"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.1], sources: [hvr-ghc]}}+    - compiler: "ghc-8.2.2"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.2.2], sources: [hvr-ghc]}}+    - compiler: "ghc-8.2.1"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.2.1], sources: [hvr-ghc]}}+    - compiler: "ghc-8.0.2"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.0.2], sources: [hvr-ghc]}}+    - compiler: "ghc-8.0.1"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.0.1], sources: [hvr-ghc]}}+    - compiler: "ghc-7.10.3"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.10.3], sources: [hvr-ghc]}}+    - compiler: "ghc-7.10.2"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.10.2], sources: [hvr-ghc]}}+    - compiler: "ghc-7.10.1"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.10.1], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.4"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.4], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.3"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.3], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.2"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.2], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.1"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.1], sources: [hvr-ghc]}}++before_install:+  - HC=/opt/ghc/bin/${CC}+  - HCPKG=${HC/ghc/ghc-pkg}+  - unset CC+  - CABAL=/opt/ghc/bin/cabal+  - CABALHOME=$HOME/.cabal+  - export PATH="$CABALHOME/bin:$PATH"+  - ROOTDIR=$(pwd)+  - HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\1 * 10000 + \2 * 100 + \3/') ))+  - echo $HCNUMVER++install:+  - ${CABAL} --version+  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"+  - TEST=--enable-tests+  - BENCH=--enable-benchmarks+  - GHCHEAD=${GHCHEAD-false}+  - travis_retry ${CABAL} update -v+  - sed -i.bak 's/^jobs:/-- jobs:/' $CABALHOME/config+  - rm -fv cabal.project cabal.project.local+  - grep -Ev -- '^\s*--' $CABALHOME/config | grep -Ev '^\s*$'+  - rm -f cabal.project+  - touch cabal.project+  - "printf 'packages: \"servant\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-client\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-docs\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-server\"\\n' >> cabal.project"+  - "echo 'constraints: foundation >= 0.14' >> cabal.project"+  - "echo 'allow-newer: servant-js:servant' >> cabal.project"+  - "echo 'allow-newer: servant-js:servant-foreign' >> cabal.project"+  - "printf 'write-ghc-environment-files: always\\n' >> cabal.project"+  - touch cabal.project.local+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"+  - cat cabal.project || true+  - cat cabal.project.local || true+  - if [ -f "servant/configure.ac" ]; then (cd "servant" && autoreconf -i); fi+  - if [ -f "servant-client/configure.ac" ]; then (cd "servant-client" && autoreconf -i); fi+  - if [ -f "servant-docs/configure.ac" ]; then (cd "servant-docs" && autoreconf -i); fi+  - if [ -f "servant-server/configure.ac" ]; then (cd "servant-server" && autoreconf -i); fi+  - rm -f cabal.project.freeze+  - ${CABAL} new-freeze -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project.copy-fields.some" --dry+  - "cat \"cabal.project.copy-fields.some.freeze\" | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"+  - rm  "cabal.project.copy-fields.some.freeze"+  - ${CABAL} new-build -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project.copy-fields.some" --dep -j2 all+  - ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks --project-file="cabal.project.copy-fields.some" --dep -j2 all+  - rm -rf .ghc.environment.* "servant"/dist "servant-client"/dist "servant-docs"/dist "servant-server"/dist+  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)++# Here starts the actual work to be performed for the package under test;+# any command which exits with a non-zero exit code causes the build to fail.+script:+  # test that source-distributions can be generated+  - ${CABAL} new-sdist all+  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/+  - cd ${DISTDIR} || false+  - find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \;+  - rm -f cabal.project+  - touch cabal.project+  - "printf 'packages: \"servant-*/*.cabal\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-client-*/*.cabal\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-docs-*/*.cabal\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-server-*/*.cabal\"\\n' >> cabal.project"+  - "echo 'constraints: foundation >= 0.14' >> cabal.project"+  - "echo 'allow-newer: servant-js:servant' >> cabal.project"+  - "echo 'allow-newer: servant-js:servant-foreign' >> cabal.project"+  - "printf 'write-ghc-environment-files: always\\n' >> cabal.project"+  - touch cabal.project.local+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"+  - cat cabal.project || true+  - cat cabal.project.local || true+  # this builds all libraries and executables (without tests/benchmarks)+  - ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks all++  # build & run tests, build benchmarks+  - ${CABAL} new-build -w ${HC} ${TEST} ${BENCH} all+  - if [ "x$TEST" = "x--enable-tests" ]; then ${CABAL} new-test -w ${HC} ${TEST} ${BENCH} all; fi++  # cabal check+  - (cd servant-* && ${CABAL} check)+  - (cd servant-client-* && ${CABAL} check)+  - (cd servant-docs-* && ${CABAL} check)+  - (cd servant-server-* && ${CABAL} check)++  # haddock+  - ${CABAL} new-haddock -w ${HC} ${TEST} ${BENCH} all++  # Build without installed constraints for packages in global-db+  - rm -f cabal.project.local; ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks all;++# REGENDATA ["-o","cabal.project.empty-line.travis.yml","--copy-fields=some","cabal.project.empty-line"]+# EOF
fixtures/cabal.project.empty-line.stderr view
@@ -1,1 +1,1 @@-*INFO* Generating Travis-CI config for testing for GHC versions: head 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.6.1+*INFO* Generating Travis-CI config for testing for GHC versions: head 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3
fixtures/cabal.project.empty-line.travis.yml view
@@ -1,11 +1,13 @@ # This Travis job script has been generated by a script via #-#   runghc make_travis_yml_2.hs '--ghc-head' 'cabal.project.empty-line'+#   haskell-ci '-o' 'cabal.project.empty-line.travis.yml' '--ghc-head' 'cabal.project.empty-line' # # For more information, see https://github.com/haskell-CI/haskell-ci #+# version: 0.2+# language: c-sudo: false+dist: xenial  git:   submodules: false  # whether to recursively clone submodules@@ -16,134 +18,124 @@     - $HOME/.cabal/store  before_cache:-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log+  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log   # remove files that are regenerated by 'cabal update'-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.*-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/*.json-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.cache-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar.idx+  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*+  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx -  - rm -rfv $HOME/.cabal/packages/head.hackage+  - rm -rfv $CABALHOME/packages/head.hackage  matrix:   include:+    - compiler: "ghc-8.6.3"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.6.3], sources: [hvr-ghc]}}+    - compiler: "ghc-8.6.2"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.6.2], sources: [hvr-ghc]}}     - compiler: "ghc-8.6.1"-      env: GHCHEAD=true-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.6.1], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.6.1], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.4"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.4], sources: [hvr-ghc]}}     - compiler: "ghc-8.4.3"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.4.3], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.3], sources: [hvr-ghc]}}     - compiler: "ghc-8.4.2"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.4.2], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.2], sources: [hvr-ghc]}}     - compiler: "ghc-8.4.1"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.4.1], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.1], sources: [hvr-ghc]}}     - compiler: "ghc-8.2.2"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.2.2], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.2.2], sources: [hvr-ghc]}}     - compiler: "ghc-8.2.1"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.2.1], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.2.1], sources: [hvr-ghc]}}     - compiler: "ghc-8.0.2"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.0.2], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.0.2], sources: [hvr-ghc]}}     - compiler: "ghc-8.0.1"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.0.1], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.0.1], sources: [hvr-ghc]}}     - compiler: "ghc-7.10.3"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.10.3], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.10.3], sources: [hvr-ghc]}}     - compiler: "ghc-7.10.2"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.10.2], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.10.2], sources: [hvr-ghc]}}     - compiler: "ghc-7.10.1"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.10.1], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.10.1], sources: [hvr-ghc]}}     - compiler: "ghc-7.8.4"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.4], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.4], sources: [hvr-ghc]}}     - compiler: "ghc-7.8.3"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.3], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.3], sources: [hvr-ghc]}}     - compiler: "ghc-7.8.2"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.2], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.2], sources: [hvr-ghc]}}     - compiler: "ghc-7.8.1"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.1], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.1], sources: [hvr-ghc]}}     - compiler: "ghc-head"       env: GHCHEAD=true       addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-head], sources: [hvr-ghc]}}    allow_failures:     - compiler: "ghc-head"-    - compiler: "ghc-8.6.1"  before_install:-  - HC=${CC}+  - HC=/opt/ghc/bin/${CC}   - HCPKG=${HC/ghc/ghc-pkg}   - unset CC+  - CABAL=/opt/ghc/bin/cabal+  - CABALHOME=$HOME/.cabal+  - export PATH="$CABALHOME/bin:$PATH"   - ROOTDIR=$(pwd)-  - mkdir -p $HOME/.local/bin-  - "PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$HOME/local/bin:$PATH"   - HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\1 * 10000 + \2 * 100 + \3/') ))   - echo $HCNUMVER  install:-  - cabal --version+  - ${CABAL} --version   - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"-  - BENCH=${BENCH---enable-benchmarks}-  - TEST=${TEST---enable-tests}-  - HADDOCK=${HADDOCK-true}-  - UNCONSTRAINED=${UNCONSTRAINED-true}-  - NOINSTALLEDCONSTRAINTS=${NOINSTALLEDCONSTRAINTS-false}+  - TEST=--enable-tests+  - BENCH=--enable-benchmarks   - GHCHEAD=${GHCHEAD-false}-  - travis_retry cabal update -v-  - "sed -i.bak 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config"+  - travis_retry ${CABAL} update -v+  - sed -i.bak 's/^jobs:/-- jobs:/' $CABALHOME/config   - rm -fv cabal.project cabal.project.local   # Overlay Hackage Package Index for GHC HEAD: https://github.com/hvr/head.hackage   - |     if $GHCHEAD; then-      sed -i 's/-- allow-newer: .*/allow-newer: *:base/' ${HOME}/.cabal/config-      for pkg in $($HCPKG list --simple-output); do pkg=$(echo $pkg | sed 's/-[^-]*$//'); sed -i "s/allow-newer: /allow-newer: *:$pkg, /" ${HOME}/.cabal/config; done+      sed -i 's/-- allow-newer: .*/allow-newer: *:base/' $CABALHOME/config+      for pkg in $($HCPKG list --simple-output); do pkg=$(echo $pkg | sed 's/-[^-]*$//'); sed -i "s/allow-newer: /allow-newer: *:$pkg, /" $CABALHOME/config; done -      echo 'repository head.hackage'                                                        >> ${HOME}/.cabal/config-      echo '   url: http://head.hackage.haskell.org/'                                       >> ${HOME}/.cabal/config-      echo '   secure: True'                                                                >> ${HOME}/.cabal/config-      echo '   root-keys: 07c59cb65787dedfaef5bd5f987ceb5f7e5ebf88b904bbd4c5cbdeb2ff71b740' >> ${HOME}/.cabal/config-      echo '              2e8555dde16ebd8df076f1a8ef13b8f14c66bad8eafefd7d9e37d0ed711821fb' >> ${HOME}/.cabal/config-      echo '              8f79fd2389ab2967354407ec852cbe73f2e8635793ac446d09461ffb99527f6e' >> ${HOME}/.cabal/config-      echo '   key-threshold: 3'                                                            >> ${HOME}/.cabal.config+      echo 'repository head.hackage'                                                        >> $CABALHOME/config+      echo '   url: http://head.hackage.haskell.org/'                                       >> $CABALHOME/config+      echo '   secure: True'                                                                >> $CABALHOME/config+      echo '   root-keys: 07c59cb65787dedfaef5bd5f987ceb5f7e5ebf88b904bbd4c5cbdeb2ff71b740' >> $CABALHOME/config+      echo '              2e8555dde16ebd8df076f1a8ef13b8f14c66bad8eafefd7d9e37d0ed711821fb' >> $CABALHOME/config+      echo '              8f79fd2389ab2967354407ec852cbe73f2e8635793ac446d09461ffb99527f6e' >> $CABALHOME/config+      echo '   key-threshold: 3'                                                            >> $CABALHOME.config -      grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'+      grep -Ev -- '^\s*--' $CABALHOME/config | grep -Ev '^\s*$' -      cabal new-update head.hackage -v+      ${CABAL} new-update head.hackage -v     fi-  - grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'-  - "printf 'packages: \"servant\" \"servant-client\" \"servant-docs\" \"servant-server\"\\n' > cabal.project"+  - grep -Ev -- '^\s*--' $CABALHOME/config | grep -Ev '^\s*$'+  - rm -f cabal.project+  - touch cabal.project+  - "printf 'packages: \"servant\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-client\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-docs\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-server\"\\n' >> cabal.project"   - "echo 'constraints: foundatiion >= 0.14' >> cabal.project"-  - "echo 'allow-newer: servant-js:servant, servant-js:servant-foreign' >> cabal.project"+  - "echo 'allow-newer: servant-js:servant' >> cabal.project"+  - "echo 'allow-newer: servant-js:servant-foreign' >> cabal.project"+  - "printf 'write-ghc-environment-files: always\\n' >> cabal.project"   - touch cabal.project.local-  - "if ! $NOINSTALLEDCONSTRAINTS; then for pkg in $($HCPKG list --simple-output); do echo $pkg  | grep -vw -- servant | grep -vw -- servant-client | grep -vw -- servant-docs | grep -vw -- servant-server | sed 's/^/constraints: /' | sed 's/-[^-]*$/ installed/' >> cabal.project.local; done; fi"+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"   - cat cabal.project || true   - cat cabal.project.local || true-  - if [ -f "servant/configure.ac" ]; then-      (cd "servant" && autoreconf -i);-    fi-  - if [ -f "servant-client/configure.ac" ]; then-      (cd "servant-client" && autoreconf -i);-    fi-  - if [ -f "servant-docs/configure.ac" ]; then-      (cd "servant-docs" && autoreconf -i);-    fi-  - if [ -f "servant-server/configure.ac" ]; then-      (cd "servant-server" && autoreconf -i);-    fi+  - if [ -f "servant/configure.ac" ]; then (cd "servant" && autoreconf -i); fi+  - if [ -f "servant-client/configure.ac" ]; then (cd "servant-client" && autoreconf -i); fi+  - if [ -f "servant-docs/configure.ac" ]; then (cd "servant-docs" && autoreconf -i); fi+  - if [ -f "servant-server/configure.ac" ]; then (cd "servant-server" && autoreconf -i); fi   - rm -f cabal.project.freeze-  - cabal new-build -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project.empty-line" --dep -j2 all-  - cabal new-build -w ${HC} --disable-tests --disable-benchmarks --project-file="cabal.project.empty-line" --dep -j2 all+  - ${CABAL} new-freeze -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project.empty-line" --dry+  - "cat \"cabal.project.empty-line.freeze\" | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"+  - rm  "cabal.project.empty-line.freeze"+  - ${CABAL} new-build -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project.empty-line" --dep -j2 all+  - ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks --project-file="cabal.project.empty-line" --dep -j2 all   - rm -rf .ghc.environment.* "servant"/dist "servant-client"/dist "servant-docs"/dist "servant-server"/dist   - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX) @@ -151,39 +143,42 @@ # any command which exits with a non-zero exit code causes the build to fail. script:   # test that source-distributions can be generated-  - (cd "servant" && cabal sdist)-  - (cd "servant-client" && cabal sdist)-  - (cd "servant-docs" && cabal sdist)-  - (cd "servant-server" && cabal sdist)-  - mv "servant"/dist/servant-*.tar.gz "servant-client"/dist/servant-client-*.tar.gz "servant-docs"/dist/servant-docs-*.tar.gz "servant-server"/dist/servant-server-*.tar.gz ${DISTDIR}/+  - ${CABAL} new-sdist all+  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/   - cd ${DISTDIR} || false   - find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \;-  - "printf 'packages: servant-*/*.cabal servant-client-*/*.cabal servant-docs-*/*.cabal servant-server-*/*.cabal\\n' > cabal.project"+  - rm -f cabal.project+  - touch cabal.project+  - "printf 'packages: \"servant-*/*.cabal\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-client-*/*.cabal\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-docs-*/*.cabal\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-server-*/*.cabal\"\\n' >> cabal.project"   - "echo 'constraints: foundatiion >= 0.14' >> cabal.project"-  - "echo 'allow-newer: servant-js:servant, servant-js:servant-foreign' >> cabal.project"+  - "echo 'allow-newer: servant-js:servant' >> cabal.project"+  - "echo 'allow-newer: servant-js:servant-foreign' >> cabal.project"+  - "printf 'write-ghc-environment-files: always\\n' >> cabal.project"   - touch cabal.project.local-  - "if ! $NOINSTALLEDCONSTRAINTS; then for pkg in $($HCPKG list --simple-output); do echo $pkg  | grep -vw -- servant | grep -vw -- servant-client | grep -vw -- servant-docs | grep -vw -- servant-server | sed 's/^/constraints: /' | sed 's/-[^-]*$/ installed/' >> cabal.project.local; done; fi"+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | grep -vE -- '^(servant|servant-client|servant-docs|servant-server)$' | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"   - cat cabal.project || true   - cat cabal.project.local || true   # this builds all libraries and executables (without tests/benchmarks)-  - cabal new-build -w ${HC} --disable-tests --disable-benchmarks all+  - ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks all    # build & run tests, build benchmarks-  - cabal new-build -w ${HC} ${TEST} ${BENCH} all-  - if [ "x$TEST" = "x--enable-tests" ]; then cabal new-test -w ${HC} ${TEST} ${BENCH} all; fi+  - ${CABAL} new-build -w ${HC} ${TEST} ${BENCH} all+  - if [ "x$TEST" = "x--enable-tests" ]; then ${CABAL} new-test -w ${HC} ${TEST} ${BENCH} all; fi    # cabal check-  - (cd servant-* && cabal check)-  - (cd servant-client-* && cabal check)-  - (cd servant-docs-* && cabal check)-  - (cd servant-server-* && cabal check)+  - (cd servant-* && ${CABAL} check)+  - (cd servant-client-* && ${CABAL} check)+  - (cd servant-docs-* && ${CABAL} check)+  - (cd servant-server-* && ${CABAL} check)    # haddock-  - rm -rf ./dist-newstyle-  - if $HADDOCK; then cabal new-haddock -w ${HC} ${TEST} ${BENCH} all; else echo "Skipping haddock generation";fi+  - ${CABAL} new-haddock -w ${HC} ${TEST} ${BENCH} all    # Build without installed constraints for packages in global-db-  - if $UNCONSTRAINED; then rm -f cabal.project.local; echo cabal new-build -w ${HC} --disable-tests --disable-benchmarks all; else echo "Not building without installed constraints"; fi+  - rm -f cabal.project.local; ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks all; -# REGENDATA ["--ghc-head","cabal.project.empty-line"]+# REGENDATA ["-o","cabal.project.empty-line.travis.yml","--ghc-head","cabal.project.empty-line"] # EOF
fixtures/cabal.project.messy.stderr view
@@ -1,1 +1,1 @@-*INFO* Generating Travis-CI config for testing for GHC versions: head 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.6.1+*INFO* Generating Travis-CI config for testing for GHC versions: head 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.4.4 8.6.1 8.6.2 8.6.3
fixtures/cabal.project.messy.travis.yml view
@@ -1,11 +1,13 @@ # This Travis job script has been generated by a script via #-#   runghc make_travis_yml_2.hs '--ghc-head' 'cabal.project.messy'+#   haskell-ci '-o' 'cabal.project.messy.travis.yml' '--ghc-head' '--apt=fftw3-dev' '--installed=-all +deepseq' 'cabal.project.messy' # # For more information, see https://github.com/haskell-CI/haskell-ci #+# version: 0.2+# language: c-sudo: false+dist: xenial  git:   submodules: false  # whether to recursively clone submodules@@ -16,132 +18,121 @@     - $HOME/.cabal/store  before_cache:-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log+  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log   # remove files that are regenerated by 'cabal update'-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.*-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/*.json-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.cache-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar.idx+  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*+  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx -  - rm -rfv $HOME/.cabal/packages/head.hackage+  - rm -rfv $CABALHOME/packages/head.hackage  matrix:   include:+    - compiler: "ghc-8.6.3"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.6.3,fftw3-dev], sources: [hvr-ghc]}}+    - compiler: "ghc-8.6.2"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.6.2,fftw3-dev], sources: [hvr-ghc]}}     - compiler: "ghc-8.6.1"-      env: GHCHEAD=true-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.6.1], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.6.1,fftw3-dev], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.4"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.4,fftw3-dev], sources: [hvr-ghc]}}     - compiler: "ghc-8.4.3"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.4.3], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.3,fftw3-dev], sources: [hvr-ghc]}}     - compiler: "ghc-8.4.2"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.4.2], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.2,fftw3-dev], sources: [hvr-ghc]}}     - compiler: "ghc-8.4.1"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.4.1], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.1,fftw3-dev], sources: [hvr-ghc]}}     - compiler: "ghc-8.2.2"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.2.2], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.2.2,fftw3-dev], sources: [hvr-ghc]}}     - compiler: "ghc-8.2.1"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.2.1], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.2.1,fftw3-dev], sources: [hvr-ghc]}}     - compiler: "ghc-8.0.2"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.0.2], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.0.2,fftw3-dev], sources: [hvr-ghc]}}     - compiler: "ghc-8.0.1"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.0.1], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.0.1,fftw3-dev], sources: [hvr-ghc]}}     - compiler: "ghc-7.10.3"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.10.3], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.10.3,fftw3-dev], sources: [hvr-ghc]}}     - compiler: "ghc-7.10.2"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.10.2], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.10.2,fftw3-dev], sources: [hvr-ghc]}}     - compiler: "ghc-7.10.1"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.10.1], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.10.1,fftw3-dev], sources: [hvr-ghc]}}     - compiler: "ghc-7.8.4"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.4], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.4,fftw3-dev], sources: [hvr-ghc]}}     - compiler: "ghc-7.8.3"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.3], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.3,fftw3-dev], sources: [hvr-ghc]}}     - compiler: "ghc-7.8.2"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.2], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.2,fftw3-dev], sources: [hvr-ghc]}}     - compiler: "ghc-7.8.1"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.1], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-7.8.1,fftw3-dev], sources: [hvr-ghc]}}     - compiler: "ghc-head"       env: GHCHEAD=true-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-head], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-head,fftw3-dev], sources: [hvr-ghc]}}    allow_failures:     - compiler: "ghc-head"-    - compiler: "ghc-8.6.1"  before_install:-  - HC=${CC}+  - HC=/opt/ghc/bin/${CC}   - HCPKG=${HC/ghc/ghc-pkg}   - unset CC+  - CABAL=/opt/ghc/bin/cabal+  - CABALHOME=$HOME/.cabal+  - export PATH="$CABALHOME/bin:$PATH"   - ROOTDIR=$(pwd)-  - mkdir -p $HOME/.local/bin-  - "PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$HOME/local/bin:$PATH"   - HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\1 * 10000 + \2 * 100 + \3/') ))   - echo $HCNUMVER  install:-  - cabal --version+  - ${CABAL} --version   - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"-  - BENCH=${BENCH---enable-benchmarks}-  - TEST=${TEST---enable-tests}-  - HADDOCK=${HADDOCK-true}-  - UNCONSTRAINED=${UNCONSTRAINED-true}-  - NOINSTALLEDCONSTRAINTS=${NOINSTALLEDCONSTRAINTS-false}+  - TEST=--enable-tests+  - BENCH=--enable-benchmarks   - GHCHEAD=${GHCHEAD-false}-  - travis_retry cabal update -v-  - "sed -i.bak 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config"+  - travis_retry ${CABAL} update -v+  - sed -i.bak 's/^jobs:/-- jobs:/' $CABALHOME/config   - rm -fv cabal.project cabal.project.local   # Overlay Hackage Package Index for GHC HEAD: https://github.com/hvr/head.hackage   - |     if $GHCHEAD; then-      sed -i 's/-- allow-newer: .*/allow-newer: *:base/' ${HOME}/.cabal/config-      for pkg in $($HCPKG list --simple-output); do pkg=$(echo $pkg | sed 's/-[^-]*$//'); sed -i "s/allow-newer: /allow-newer: *:$pkg, /" ${HOME}/.cabal/config; done+      sed -i 's/-- allow-newer: .*/allow-newer: *:base/' $CABALHOME/config+      for pkg in $($HCPKG list --simple-output); do pkg=$(echo $pkg | sed 's/-[^-]*$//'); sed -i "s/allow-newer: /allow-newer: *:$pkg, /" $CABALHOME/config; done -      echo 'repository head.hackage'                                                        >> ${HOME}/.cabal/config-      echo '   url: http://head.hackage.haskell.org/'                                       >> ${HOME}/.cabal/config-      echo '   secure: True'                                                                >> ${HOME}/.cabal/config-      echo '   root-keys: 07c59cb65787dedfaef5bd5f987ceb5f7e5ebf88b904bbd4c5cbdeb2ff71b740' >> ${HOME}/.cabal/config-      echo '              2e8555dde16ebd8df076f1a8ef13b8f14c66bad8eafefd7d9e37d0ed711821fb' >> ${HOME}/.cabal/config-      echo '              8f79fd2389ab2967354407ec852cbe73f2e8635793ac446d09461ffb99527f6e' >> ${HOME}/.cabal/config-      echo '   key-threshold: 3'                                                            >> ${HOME}/.cabal.config+      echo 'repository head.hackage'                                                        >> $CABALHOME/config+      echo '   url: http://head.hackage.haskell.org/'                                       >> $CABALHOME/config+      echo '   secure: True'                                                                >> $CABALHOME/config+      echo '   root-keys: 07c59cb65787dedfaef5bd5f987ceb5f7e5ebf88b904bbd4c5cbdeb2ff71b740' >> $CABALHOME/config+      echo '              2e8555dde16ebd8df076f1a8ef13b8f14c66bad8eafefd7d9e37d0ed711821fb' >> $CABALHOME/config+      echo '              8f79fd2389ab2967354407ec852cbe73f2e8635793ac446d09461ffb99527f6e' >> $CABALHOME/config+      echo '   key-threshold: 3'                                                            >> $CABALHOME.config -      grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'+      grep -Ev -- '^\s*--' $CABALHOME/config | grep -Ev '^\s*$' -      cabal new-update head.hackage -v+      ${CABAL} new-update head.hackage -v     fi-  - grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'-  - "printf 'packages: \"servant\" \"servant-client\" \"servant-docs\" \"servant-server\"\\n' > cabal.project"+  - grep -Ev -- '^\s*--' $CABALHOME/config | grep -Ev '^\s*$'+  - rm -f cabal.project+  - touch cabal.project+  - "printf 'packages: \"servant\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-client\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-docs\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-server\"\\n' >> cabal.project"+  - "printf 'write-ghc-environment-files: always\\n' >> cabal.project"   - touch cabal.project.local-  - "if ! $NOINSTALLEDCONSTRAINTS; then for pkg in $($HCPKG list --simple-output); do echo $pkg  | grep -vw -- servant | grep -vw -- servant-client | grep -vw -- servant-docs | grep -vw -- servant-server | sed 's/^/constraints: /' | sed 's/-[^-]*$/ installed/' >> cabal.project.local; done; fi"+  - "for pkg in deepseq; do echo \"constraints: $pkg installed\" >> cabal.project >> cabal.project.local; done"   - cat cabal.project || true   - cat cabal.project.local || true-  - if [ -f "servant/configure.ac" ]; then-      (cd "servant" && autoreconf -i);-    fi-  - if [ -f "servant-client/configure.ac" ]; then-      (cd "servant-client" && autoreconf -i);-    fi-  - if [ -f "servant-docs/configure.ac" ]; then-      (cd "servant-docs" && autoreconf -i);-    fi-  - if [ -f "servant-server/configure.ac" ]; then-      (cd "servant-server" && autoreconf -i);-    fi+  - if [ -f "servant/configure.ac" ]; then (cd "servant" && autoreconf -i); fi+  - if [ -f "servant-client/configure.ac" ]; then (cd "servant-client" && autoreconf -i); fi+  - if [ -f "servant-docs/configure.ac" ]; then (cd "servant-docs" && autoreconf -i); fi+  - if [ -f "servant-server/configure.ac" ]; then (cd "servant-server" && autoreconf -i); fi   - rm -f cabal.project.freeze-  - cabal new-build -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project.messy" --dep -j2 all-  - cabal new-build -w ${HC} --disable-tests --disable-benchmarks --project-file="cabal.project.messy" --dep -j2 all+  - ${CABAL} new-freeze -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project.messy" --dry+  - "cat \"cabal.project.messy.freeze\" | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"+  - rm  "cabal.project.messy.freeze"+  - ${CABAL} new-build -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project.messy" --dep -j2 all+  - ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks --project-file="cabal.project.messy" --dep -j2 all   - rm -rf .ghc.environment.* "servant"/dist "servant-client"/dist "servant-docs"/dist "servant-server"/dist   - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX) @@ -149,37 +140,39 @@ # any command which exits with a non-zero exit code causes the build to fail. script:   # test that source-distributions can be generated-  - (cd "servant" && cabal sdist)-  - (cd "servant-client" && cabal sdist)-  - (cd "servant-docs" && cabal sdist)-  - (cd "servant-server" && cabal sdist)-  - mv "servant"/dist/servant-*.tar.gz "servant-client"/dist/servant-client-*.tar.gz "servant-docs"/dist/servant-docs-*.tar.gz "servant-server"/dist/servant-server-*.tar.gz ${DISTDIR}/+  - ${CABAL} new-sdist all+  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/   - cd ${DISTDIR} || false   - find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \;-  - "printf 'packages: servant-*/*.cabal servant-client-*/*.cabal servant-docs-*/*.cabal servant-server-*/*.cabal\\n' > cabal.project"+  - rm -f cabal.project+  - touch cabal.project+  - "printf 'packages: \"servant-*/*.cabal\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-client-*/*.cabal\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-docs-*/*.cabal\"\\n' >> cabal.project"+  - "printf 'packages: \"servant-server-*/*.cabal\"\\n' >> cabal.project"+  - "printf 'write-ghc-environment-files: always\\n' >> cabal.project"   - touch cabal.project.local-  - "if ! $NOINSTALLEDCONSTRAINTS; then for pkg in $($HCPKG list --simple-output); do echo $pkg  | grep -vw -- servant | grep -vw -- servant-client | grep -vw -- servant-docs | grep -vw -- servant-server | sed 's/^/constraints: /' | sed 's/-[^-]*$/ installed/' >> cabal.project.local; done; fi"+  - "for pkg in deepseq; do echo \"constraints: $pkg installed\" >> cabal.project >> cabal.project.local; done"   - cat cabal.project || true   - cat cabal.project.local || true   # this builds all libraries and executables (without tests/benchmarks)-  - cabal new-build -w ${HC} --disable-tests --disable-benchmarks all+  - ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks all    # build & run tests, build benchmarks-  - cabal new-build -w ${HC} ${TEST} ${BENCH} all-  - if [ "x$TEST" = "x--enable-tests" ]; then cabal new-test -w ${HC} ${TEST} ${BENCH} all; fi+  - ${CABAL} new-build -w ${HC} ${TEST} ${BENCH} all+  - if [ "x$TEST" = "x--enable-tests" ]; then ${CABAL} new-test -w ${HC} ${TEST} ${BENCH} all; fi    # cabal check-  - (cd servant-* && cabal check)-  - (cd servant-client-* && cabal check)-  - (cd servant-docs-* && cabal check)-  - (cd servant-server-* && cabal check)+  - (cd servant-* && ${CABAL} check)+  - (cd servant-client-* && ${CABAL} check)+  - (cd servant-docs-* && ${CABAL} check)+  - (cd servant-server-* && ${CABAL} check)    # haddock-  - rm -rf ./dist-newstyle-  - if $HADDOCK; then cabal new-haddock -w ${HC} ${TEST} ${BENCH} all; else echo "Skipping haddock generation";fi+  - ${CABAL} new-haddock -w ${HC} ${TEST} ${BENCH} all    # Build without installed constraints for packages in global-db-  - if $UNCONSTRAINED; then rm -f cabal.project.local; echo cabal new-build -w ${HC} --disable-tests --disable-benchmarks all; else echo "Not building without installed constraints"; fi+  - rm -f cabal.project.local; ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks all; -# REGENDATA ["--ghc-head","cabal.project.messy"]+# REGENDATA ["-o","cabal.project.messy.travis.yml","--ghc-head","--apt=fftw3-dev","--installed=-all +deepseq","cabal.project.messy"] # EOF
fixtures/haskell-ci.cabal view
@@ -1,16 +1,15 @@-cabal-version:       1.18-name:                haskell-ci-version:             0.1.0.0--synopsis:            Cabal package script generator for Travis-CI+cabal-version:      2.2+name:               haskell-ci+version:            0.2+synopsis:           Cabal package script generator for Travis-CI description:-  Script generator (@make-travis-yml@) for [Travis-CI](https://travis-ci.org/) for continuous-integration testing of Haskell Cabal packages.+  Script generator (@haskell-ci@) for [Travis-CI](https://travis-ci.org/) for continuous-integration testing of Haskell Cabal packages.   .   Included features (not limited to):   .   * Multiple GHC support   * Dependency caching-  * cabal.project support (see [Nix-style local builds documentation](http://cabal.readthedocs.io/en/latest/nix-local-build-overview.html)+  * cabal.project support (see [Nix-style local builds documentation](https://cabal.readthedocs.io/en/latest/nix-local-build-overview.html))   * Runs tests and builds benchmarks   * Generates Haddocks   * macOS (OSX) support@@ -18,104 +17,157 @@   .   === Quick Start Guide   .-  Add a @tested-with@ line to your @.cabal@ file (e.g. @tested-with: GHC == 8.0.2 || == 8.2.2@) and then run @make-travis-yml yourpackage.cabal -o .travis.yml@ to generate the Travis-CI job script.+  Add a @tested-with@ line to your @.cabal@ file (e.g. @tested-with: GHC == 8.0.2 || == 8.2.2@) and then run @haskell-ci yourpackage.cabal -o .travis.yml@ to generate the Travis-CI job script.   .-  See @make-travis-yml --help@ for more information.+  See @haskell-ci --help@ for more information. -  -homepage:            http://haskell-ci.rtfd.org/-bug-reports:         https://github.com/haskell-CI/haskell-ci/issues-license:             BSD3-license-file:        LICENSE-author:              Herbert Valerio Riedel, Oleg Grenrus-maintainer:          hvr@gnu.org-category:            Development-build-type:          Simple-tested-with:-  GHC == 7.8.4,-  GHC == 7.10.3,-  GHC == 8.0.2,-  GHC == 8.2.2,-  GHC == 8.4.3,-  GHC == 8.6.1+homepage:           https://haskell-ci.rtfd.org/+bug-reports:        https://github.com/haskell-CI/haskell-ci/issues+license:            BSD-3-Clause+license-file:       LICENSE+author:             Herbert Valerio Riedel, Oleg Grenrus+maintainer:         hvr@gnu.org+category:           Development+build-type:         Simple+tested-with:        GHC ==8.6.3 || ==8.4.4 || ==8.2.2 || ==8.0.2 extra-source-files:   fixtures/cabal.haskell-ci-  fixtures/haskell-ci.cabal-  fixtures/haskell-ci.cabal.stderr-  fixtures/haskell-ci.cabal.travis.yml-  fixtures/cabal.project.empty-line-  fixtures/cabal.project.empty-line.stderr-  fixtures/cabal.project.empty-line.travis.yml   fixtures/cabal.project.fail-versions   fixtures/cabal.project.fail-versions.stderr+  fixtures/haskell-ci.cabal+  fixtures/cabal.project.empty-line   fixtures/cabal.project.messy+  fixtures/cabal.project.copy-fields.all+  fixtures/cabal.project.copy-fields.some+  fixtures/cabal.project.copy-fields.none+  fixtures/haskell-ci.cabal.stderr+  fixtures/cabal.project.empty-line.stderr   fixtures/cabal.project.messy.stderr+  fixtures/cabal.project.copy-fields.all.stderr+  fixtures/cabal.project.copy-fields.some.stderr+  fixtures/cabal.project.copy-fields.none.stderr+  fixtures/haskell-ci.cabal.travis.yml+  fixtures/cabal.project.empty-line.travis.yml   fixtures/cabal.project.messy.travis.yml-  fixtures/doc/tutorial/tutorial.cabal+  fixtures/cabal.project.copy-fields.all.travis.yml+  fixtures/cabal.project.copy-fields.some.travis.yml+  fixtures/cabal.project.copy-fields.none.travis.yml   fixtures/servant-client-core/*.cabal   fixtures/servant-client/*.cabal   fixtures/servant-docs/*.cabal   fixtures/servant-foreign/*.cabal   fixtures/servant-server/*.cabal   fixtures/servant/*.cabal+  fixtures/doc/tutorial/tutorial.cabal  source-repository head-  type: git+  type:     git   location: https://github.com/haskell-CI/haskell-ci.git  flag ShellCheck   default: True-  manual: True+  manual:  True -library-  exposed-modules:     MakeTravisYml-  ghc-options:         -Wall-  if impl(ghc >= 8.0)-    ghc-options:-      -Wcompat-      -Wnoncanonical-monad-instances-      -Wnoncanonical-monadfail-instances-  hs-source-dirs:      src-  other-extensions:    CPP, ViewPatterns, NamedFieldPuns-  build-depends:       base         >= 4.7  && < 4.12-                     , Cabal        == 1.18.*-                                 || == 1.20.*-                                 || == 1.22.*-                                 || == 1.24.*-                                 || == 2.0.*-                                 || == 2.2.*-                     , containers   >= 0.4  && < 0.6-                     , directory    >= 1.1  && < 1.4-                     , filepath     >= 1.2  && < 1.5-                     , transformers >= 0.3  && < 0.6-                     , deepseq      >= 1.3  && < 1.5-  default-language:    Haskell2010+library haskell-ci-internal+  exposed-modules:+    HaskellCI+    HaskellCI.Cli+    HaskellCI.Config+    HaskellCI.Config.ConstraintSet+    HaskellCI.Config.CopyFields+    HaskellCI.Config.Doctest+    HaskellCI.Config.Dump+    HaskellCI.Config.Folds+    HaskellCI.Config.HLint+    HaskellCI.Config.Installed+    HaskellCI.Config.Jobs+    HaskellCI.Extras+    HaskellCI.GHC+    HaskellCI.Glob+    HaskellCI.MakeTravisOutput+    HaskellCI.Newtypes+    HaskellCI.Optimization+    HaskellCI.OptionsGrammar+    HaskellCI.OptparseGrammar+    HaskellCI.Package+    HaskellCI.ParsecError+    HaskellCI.ParsecUtils+    HaskellCI.Project+    HaskellCI.TestedWith+    HaskellCI.Version +  -- vendored from Cabal development version+  other-modules:      Distribution.Fields.Pretty+  ghc-options:+    -Wall -Wcompat -Wnoncanonical-monad-instances+    -Wnoncanonical-monadfail-instances++  hs-source-dirs:     src+  default-extensions:+    DeriveFoldable+    DeriveFunctor+    DeriveGeneric+    DeriveTraversable++  other-extensions:+    CPP+    NamedFieldPuns+    OverloadedLabels+    ViewPatterns++  build-depends:+    , base          >=4.9      && <4.13+    , bytestring    ^>=0.10.8.1+    , Cabal         ^>=2.4+    , containers    ^>=0.5.7.1 || ^>=0.6.0.1+    , deepseq       ^>=1.4.2.0+    , directory     ^>=1.3.0.0+    , filepath      ^>=1.4.1.1+    , parsec        ^>=3.1.13.0+    , pretty        ^>=1.1.3.3+    , text          ^>=1.2.3.0+    , transformers  ^>=0.5.2.0++  -- other dependencies+  build-depends:+    , base-compat           ^>=0.10.5+    , generic-lens          ^>=1.1.0.0+    , HsYAML                ^>=0.1.1.3+    , microlens             ^>=0.4.10+    , optparse-applicative  ^>=0.14.3.0++  default-language:   Haskell2010+   -- ShellCheck. Would need newer transformers for older GHC-  if flag(ShellCheck) && impl(ghc >= 7.10 && <8.5)-    build-depends: ShellCheck == 0.5.0+  if (flag(shellcheck) && impl(ghc >=7.10 && <8.7))+    build-depends: ShellCheck ==0.6.0 -executable make-travis-yml-  main-is:             Main.hs-  ghc-options:         -Wall-  build-depends:       base, haskell-ci-  default-language:    Haskell2010+executable haskell-ci+  main-is:          Main.hs+  ghc-options:      -Wall+  hs-source-dirs:   cli+  build-depends:+    , base+    , haskell-ci-internal +  default-language: Haskell2010+ test-suite golden-  type:                exitcode-stdio-1.0-  main-is:             Tests.hs-  hs-source-dirs:      test-  build-depends:       haskell-ci-                       -- inherited constraints via lib:haskell-ci-                     , base-                     , bytestring-                     , directory-                     , filepath-                     , transformers-                       -- dependencies needing explicit constraints-                     , tasty         >= 1.0      && < 1.2-                     , tasty-golden  >= 2.3.1.1  && < 2.4-                     , ansi-terminal >= 0.8.0.2  && <0.9-                     , Diff          >= 0.3.4    && < 0.4+  type:             exitcode-stdio-1.0+  main-is:          Tests.hs+  hs-source-dirs:   test+  build-depends:+    , ansi-terminal        ^>=0.8.0.2+    , base+    , bytestring+    , Diff                 ^>=0.3.4+    , directory+    , filepath+    , haskell-ci-internal+    , tasty                >=1.0     && <1.2+    , tasty-golden         ^>=2.3.1.1+    , transformers -  default-language:    Haskell2010+  -- inherited constraints via lib:haskell-ci+  -- dependencies needing explicit constraints+  default-language: Haskell2010
fixtures/haskell-ci.cabal.stderr view
@@ -1,1 +1,2 @@-*INFO* Generating Travis-CI config for testing for GHC versions: 7.8.4 7.10.3 8.0.2 8.2.2 8.4.3 8.6.1+*INFO* Generating Travis-CI config for testing for GHC versions: head 8.0.2 8.2.2 8.4.4 8.6.3+*INFO* Also OSX jobs for: 8.4.4
fixtures/haskell-ci.cabal.travis.yml view
@@ -1,11 +1,13 @@ # This Travis job script has been generated by a script via #-#   runghc make_travis_yml_2.hs '-o' '.travis.yml' '--config=cabal.haskell-ci' 'haskell-ci.cabal'+#   haskell-ci '--output=.travis.yml' '--config=cabal.haskell-ci' 'haskell-ci.cabal' # # For more information, see https://github.com/haskell-CI/haskell-ci #+# version: 0.2+# language: c-sudo: false+dist: xenial  git:   submodules: false  # whether to recursively clone submodules@@ -18,100 +20,104 @@   directories:     - $HOME/.cabal/packages     - $HOME/.cabal/store+    - $HOME/.ghc-install  before_cache:-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log+  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log   # remove files that are regenerated by 'cabal update'-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.*-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/*.json-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.cache-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar-  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar.idx+  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*+  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx -  - rm -rfv $HOME/.cabal/packages/head.hackage+  - rm -rfv $CABALHOME/packages/head.hackage  matrix:   include:-    - compiler: "ghc-8.6.1"-      env: GHCHEAD=true-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.6.1], sources: [hvr-ghc]}}-    - compiler: "ghc-8.4.3"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.4.3], sources: [hvr-ghc]}}+    - compiler: "ghc-8.6.3"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.6.3], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.4"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.4], sources: [hvr-ghc]}}     - compiler: "ghc-8.2.2"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.2.2], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.2.2], sources: [hvr-ghc]}}     - compiler: "ghc-8.0.2"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.0.2], sources: [hvr-ghc]}}-    - compiler: "ghc-7.10.3"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.10.3], sources: [hvr-ghc]}}-    - compiler: "ghc-7.8.4"-    # env: TEST=--disable-tests BENCH=--disable-benchmarks-      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.4], sources: [hvr-ghc]}}+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.0.2], sources: [hvr-ghc]}}+    - compiler: "ghc-head"+      env: GHCHEAD=true+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-head], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.4"+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.4], sources: [hvr-ghc]}}+      os: osx    allow_failures:-    - compiler: "ghc-8.6.1"+    - compiler: "ghc-head"  before_install:-  - HC=${CC}+  - HC=/opt/ghc/bin/${CC}   - HCPKG=${HC/ghc/ghc-pkg}   - unset CC+  - CABAL=/opt/ghc/bin/cabal+  - CABALHOME=$HOME/.cabal+  - export PATH="$CABALHOME/bin:$PATH"   - ROOTDIR=$(pwd)-  - mkdir -p $HOME/.local/bin-  - "PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$HOME/local/bin:$PATH"+  - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; brew upgrade python@3; curl https://haskell.futurice.com/haskell-on-macos.py | python3 - --make-dirs --install-dir=$HOME/.ghc-install --cabal-alias=head install cabal-install-head ${TRAVIS_COMPILER}; fi+  - if [ "$TRAVIS_OS_NAME" = "osx" ]; then HC=$HOME/.ghc-install/ghc/bin/$TRAVIS_COMPILER; HCPKG=${HC/ghc/ghc-pkg}; CABAL=$HOME/.ghc-install/ghc/bin/cabal; fi   - HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\1 * 10000 + \2 * 100 + \3/') ))   - echo $HCNUMVER  install:-  - cabal --version+  - ${CABAL} --version   - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"-  - BENCH=${BENCH---enable-benchmarks}-  - TEST=${TEST---enable-tests}-  - HADDOCK=${HADDOCK-true}-  - UNCONSTRAINED=${UNCONSTRAINED-true}-  - NOINSTALLEDCONSTRAINTS=${NOINSTALLEDCONSTRAINTS-false}+  - TEST=--enable-tests+  - BENCH=--enable-benchmarks   - GHCHEAD=${GHCHEAD-false}-  - travis_retry cabal update -v-  - "sed -i.bak 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config"+  - travis_retry ${CABAL} update -v+  - sed -i.bak 's/^jobs:/-- jobs:/' $CABALHOME/config   - rm -fv cabal.project cabal.project.local-  - "sed -i.bak 's/^-- jobs:.*/jobs: 2/' ${HOME}/.cabal/config"-  - "if [ $HCNUMVER -ge 70800 ]; then sed -i.bak 's/-- ghc-options:.*/ghc-options: -j2/' ${HOME}/.cabal/config; fi"+  - "sed -i.bak 's/^-- jobs:.*/jobs: 2/' $CABALHOME/config"+  - "sed -i.bak 's/-- ghc-options:.*/ghc-options: -j2/' $CABALHOME/config"   # Overlay Hackage Package Index for GHC HEAD: https://github.com/hvr/head.hackage   - |     if $GHCHEAD; then-      sed -i 's/-- allow-newer: .*/allow-newer: *:base/' ${HOME}/.cabal/config-      for pkg in $($HCPKG list --simple-output); do pkg=$(echo $pkg | sed 's/-[^-]*$//'); sed -i "s/allow-newer: /allow-newer: *:$pkg, /" ${HOME}/.cabal/config; done+      sed -i 's/-- allow-newer: .*/allow-newer: *:base/' $CABALHOME/config+      for pkg in $($HCPKG list --simple-output); do pkg=$(echo $pkg | sed 's/-[^-]*$//'); sed -i "s/allow-newer: /allow-newer: *:$pkg, /" $CABALHOME/config; done -      echo 'repository head.hackage'                                                        >> ${HOME}/.cabal/config-      echo '   url: http://head.hackage.haskell.org/'                                       >> ${HOME}/.cabal/config-      echo '   secure: True'                                                                >> ${HOME}/.cabal/config-      echo '   root-keys: 07c59cb65787dedfaef5bd5f987ceb5f7e5ebf88b904bbd4c5cbdeb2ff71b740' >> ${HOME}/.cabal/config-      echo '              2e8555dde16ebd8df076f1a8ef13b8f14c66bad8eafefd7d9e37d0ed711821fb' >> ${HOME}/.cabal/config-      echo '              8f79fd2389ab2967354407ec852cbe73f2e8635793ac446d09461ffb99527f6e' >> ${HOME}/.cabal/config-      echo '   key-threshold: 3'                                                            >> ${HOME}/.cabal.config+      echo 'repository head.hackage'                                                        >> $CABALHOME/config+      echo '   url: http://head.hackage.haskell.org/'                                       >> $CABALHOME/config+      echo '   secure: True'                                                                >> $CABALHOME/config+      echo '   root-keys: 07c59cb65787dedfaef5bd5f987ceb5f7e5ebf88b904bbd4c5cbdeb2ff71b740' >> $CABALHOME/config+      echo '              2e8555dde16ebd8df076f1a8ef13b8f14c66bad8eafefd7d9e37d0ed711821fb' >> $CABALHOME/config+      echo '              8f79fd2389ab2967354407ec852cbe73f2e8635793ac446d09461ffb99527f6e' >> $CABALHOME/config+      echo '   key-threshold: 3'                                                            >> $CABALHOME.config -      grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'+      grep -Ev -- '^\s*--' $CABALHOME/config | grep -Ev '^\s*$' -      cabal new-update head.hackage -v+      ${CABAL} new-update head.hackage -v     fi-  - grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'-  - if [ $HCNUMVER -ge 80000 ]; then cabal new-install -w ${HC} -j2 --symlink-bindir=$HOME/.local/bin doctest --constraint='doctest ==0.16.*'; fi-  - if [ $HCNUMVER -eq 80403 ]; then cabal new-install -w ${HC} -j2 --symlink-bindir=$HOME/.local/bin hlint --constraint='hlint ==2.1.*'; fi-  - "printf 'packages: \".\"\\n' > cabal.project"+  - grep -Ev -- '^\s*--' $CABALHOME/config | grep -Ev '^\s*$'+  - ${CABAL} new-install -w ${HC} -j2 doctest --constraint='doctest ==0.16.*'+  - if [ $HCNUMVER -eq 80603 ] ; then ${CABAL} new-install -w ${HC} -j2 hlint --constraint='hlint ==2.1.*' ; fi+  - rm -f cabal.project+  - touch cabal.project+  - "printf 'packages: \".\"\\n' >> cabal.project"   - echo 'package haskell-ci' >> cabal.project   - "echo '  ghc-options: -Werror' >> cabal.project"+  - "printf 'write-ghc-environment-files: always\\n' >> cabal.project"+  - "echo 'keep-going: False' >> cabal.project"+  - echo 'package bytestring' >> cabal.project+  - "echo '  tests: False' >> cabal.project"   - touch cabal.project.local-  - "if ! $NOINSTALLEDCONSTRAINTS; then for pkg in $($HCPKG list --simple-output); do echo $pkg  | grep -vw -- haskell-ci | sed 's/^/constraints: /' | sed 's/-[^-]*$/ installed/' >> cabal.project.local; done; fi"+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | grep -vE -- '^(Cabal|haskell-ci)$' | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"   - cat cabal.project || true   - cat cabal.project.local || true-  - if [ -f "./configure.ac" ]; then-      (cd "." && autoreconf -i);-    fi+  - if [ -f "./configure.ac" ]; then (cd "." && autoreconf -i); fi   - rm -f cabal.project.freeze-  - cabal new-build -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project" --dep -j2 all-  - cabal new-build -w ${HC} --disable-tests --disable-benchmarks --project-file="cabal.project" --dep -j2 all+  - ${CABAL} new-freeze -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project" --dry+  - "cat \"cabal.project.freeze\" | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"+  - rm  "cabal.project.freeze"+  - ${CABAL} new-build -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project" --dep -j2 all+  - ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks --project-file="cabal.project" --dep -j2 all   - rm -rf .ghc.environment.* "."/dist   - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX) @@ -119,48 +125,51 @@ # any command which exits with a non-zero exit code causes the build to fail. script:   # test that source-distributions can be generated-  - (cd "." && cabal sdist)-  - mv "."/dist/haskell-ci-*.tar.gz ${DISTDIR}/+  - ${CABAL} new-sdist all+  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/   - cd ${DISTDIR} || false   - find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \;-  - "printf 'packages: haskell-ci-*/*.cabal\\n' > cabal.project"+  - rm -f cabal.project+  - touch cabal.project+  - "printf 'packages: \"haskell-ci-*/*.cabal\"\\n' >> cabal.project"   - echo 'package haskell-ci' >> cabal.project   - "echo '  ghc-options: -Werror' >> cabal.project"+  - "printf 'write-ghc-environment-files: always\\n' >> cabal.project"+  - "echo 'keep-going: False' >> cabal.project"+  - echo 'package bytestring' >> cabal.project+  - "echo '  tests: False' >> cabal.project"   - touch cabal.project.local-  - "if ! $NOINSTALLEDCONSTRAINTS; then for pkg in $($HCPKG list --simple-output); do echo $pkg  | grep -vw -- haskell-ci | sed 's/^/constraints: /' | sed 's/-[^-]*$/ installed/' >> cabal.project.local; done; fi"+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | grep -vE -- '^(Cabal|haskell-ci)$' | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"   - cat cabal.project || true   - cat cabal.project.local || true   # this builds all libraries and executables (without tests/benchmarks)-  - cabal new-build -w ${HC} --disable-tests --disable-benchmarks all+  - ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks all    # build & run tests, build benchmarks-  - cabal new-build -w ${HC} ${TEST} ${BENCH} all-  - if [ "x$TEST" = "x--enable-tests" ]; then cabal new-test -w ${HC} ${TEST} ${BENCH} all; fi+  - ${CABAL} new-build -w ${HC} ${TEST} ${BENCH} all+  - if [ "x$TEST" = "x--enable-tests" ]; then ${CABAL} new-test -w ${HC} ${TEST} ${BENCH} all; fi    # doctest-  - if [ $HCNUMVER -ge 80000 ]; then (cd haskell-ci-* && doctest --fast src); fi+  - (cd haskell-ci-* && doctest --fast -XDeriveFoldable -XDeriveFunctor -XDeriveGeneric -XDeriveTraversable src)    # hlint-  - if [ $HCNUMVER -eq 80403 ]; then (cd haskell-ci-* && hlint -h ${ROOTDIR}/.hlint.yaml src); fi+  - if [ $HCNUMVER -eq 80603 ] ; then (cd haskell-ci-* && hlint -h ${ROOTDIR}/.hlint.yaml -XDeriveFoldable -XDeriveFunctor -XDeriveGeneric -XDeriveTraversable src) ; fi+  - if [ $HCNUMVER -eq 80603 ] ; then (cd haskell-ci-* && hlint -h ${ROOTDIR}/.hlint.yaml cli) ; fi    # cabal check-  - (cd haskell-ci-* && cabal check)--  # haddock-  - rm -rf ./dist-newstyle-  - if $HADDOCK; then cabal new-haddock -w ${HC} ${TEST} ${BENCH} all; else echo "Skipping haddock generation";fi+  - (cd haskell-ci-* && ${CABAL} check)    # Build without installed constraints for packages in global-db-  - if $UNCONSTRAINED; then rm -f cabal.project.local; echo cabal new-build -w ${HC} --disable-tests --disable-benchmarks all; else echo "Not building without installed constraints"; fi+  - rm -f cabal.project.local; ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks all;    # Constraint sets   - rm -rf cabal.project.local    # Constraint set deepseq-1.4   - echo Constraint set deepseq-1.4 && echo -en 'travis_fold:start:constraint-sets-deepseq-1.4\\r'-  - if [ $HCNUMVER -ge 70800 ] && [ $HCNUMVER -lt 71000 ]  ||  [ $HCNUMVER -eq 80202 ]; then cabal new-build -w ${HC} --disable-tests --disable-benchmarks --constraint='deepseq ==1.4.*' all; else echo skipping...; fi+  - if [ $HCNUMVER -ge 70800 ] && [ $HCNUMVER -lt 71000 ]  ||  [ $HCNUMVER -eq 80202 ] ; then ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks  --constraint='deepseq ==1.4.*' all ; fi    - echo -en 'travis_fold:end:constraint-sets-deepseq-1.4\\r' -# REGENDATA ["-o",".travis.yml","--config=cabal.haskell-ci","haskell-ci.cabal"]+# REGENDATA ["--output=.travis.yml","--config=cabal.haskell-ci","haskell-ci.cabal"] # EOF
haskell-ci.cabal view
@@ -1,16 +1,15 @@-cabal-version:       1.18-name:                haskell-ci-version:             0.1.0.0--synopsis:            Cabal package script generator for Travis-CI+cabal-version:      2.2+name:               haskell-ci+version:            0.2+synopsis:           Cabal package script generator for Travis-CI description:-  Script generator (@make-travis-yml@) for [Travis-CI](https://travis-ci.org/) for continuous-integration testing of Haskell Cabal packages.+  Script generator (@haskell-ci@) for [Travis-CI](https://travis-ci.org/) for continuous-integration testing of Haskell Cabal packages.   .   Included features (not limited to):   .   * Multiple GHC support   * Dependency caching-  * cabal.project support (see [Nix-style local builds documentation](http://cabal.readthedocs.io/en/latest/nix-local-build-overview.html)+  * cabal.project support (see [Nix-style local builds documentation](https://cabal.readthedocs.io/en/latest/nix-local-build-overview.html))   * Runs tests and builds benchmarks   * Generates Haddocks   * macOS (OSX) support@@ -18,104 +17,157 @@   .   === Quick Start Guide   .-  Add a @tested-with@ line to your @.cabal@ file (e.g. @tested-with: GHC == 8.0.2 || == 8.2.2@) and then run @make-travis-yml yourpackage.cabal -o .travis.yml@ to generate the Travis-CI job script.+  Add a @tested-with@ line to your @.cabal@ file (e.g. @tested-with: GHC == 8.0.2 || == 8.2.2@) and then run @haskell-ci yourpackage.cabal -o .travis.yml@ to generate the Travis-CI job script.   .-  See @make-travis-yml --help@ for more information.+  See @haskell-ci --help@ for more information. -  -homepage:            http://haskell-ci.rtfd.org/-bug-reports:         https://github.com/haskell-CI/haskell-ci/issues-license:             BSD3-license-file:        LICENSE-author:              Herbert Valerio Riedel, Oleg Grenrus-maintainer:          hvr@gnu.org-category:            Development-build-type:          Simple-tested-with:-  GHC == 7.8.4,-  GHC == 7.10.3,-  GHC == 8.0.2,-  GHC == 8.2.2,-  GHC == 8.4.3,-  GHC == 8.6.1+homepage:           https://haskell-ci.rtfd.org/+bug-reports:        https://github.com/haskell-CI/haskell-ci/issues+license:            BSD-3-Clause+license-file:       LICENSE+author:             Herbert Valerio Riedel, Oleg Grenrus+maintainer:         hvr@gnu.org+category:           Development+build-type:         Simple+tested-with:        GHC ==8.6.3 || ==8.4.4 || ==8.2.2 || ==8.0.2 extra-source-files:   fixtures/cabal.haskell-ci-  fixtures/haskell-ci.cabal-  fixtures/haskell-ci.cabal.stderr-  fixtures/haskell-ci.cabal.travis.yml-  fixtures/cabal.project.empty-line-  fixtures/cabal.project.empty-line.stderr-  fixtures/cabal.project.empty-line.travis.yml   fixtures/cabal.project.fail-versions   fixtures/cabal.project.fail-versions.stderr+  fixtures/haskell-ci.cabal+  fixtures/cabal.project.empty-line   fixtures/cabal.project.messy+  fixtures/cabal.project.copy-fields.all+  fixtures/cabal.project.copy-fields.some+  fixtures/cabal.project.copy-fields.none+  fixtures/haskell-ci.cabal.stderr+  fixtures/cabal.project.empty-line.stderr   fixtures/cabal.project.messy.stderr+  fixtures/cabal.project.copy-fields.all.stderr+  fixtures/cabal.project.copy-fields.some.stderr+  fixtures/cabal.project.copy-fields.none.stderr+  fixtures/haskell-ci.cabal.travis.yml+  fixtures/cabal.project.empty-line.travis.yml   fixtures/cabal.project.messy.travis.yml-  fixtures/doc/tutorial/tutorial.cabal+  fixtures/cabal.project.copy-fields.all.travis.yml+  fixtures/cabal.project.copy-fields.some.travis.yml+  fixtures/cabal.project.copy-fields.none.travis.yml   fixtures/servant-client-core/*.cabal   fixtures/servant-client/*.cabal   fixtures/servant-docs/*.cabal   fixtures/servant-foreign/*.cabal   fixtures/servant-server/*.cabal   fixtures/servant/*.cabal+  fixtures/doc/tutorial/tutorial.cabal  source-repository head-  type: git+  type:     git   location: https://github.com/haskell-CI/haskell-ci.git  flag ShellCheck   default: True-  manual: True+  manual:  True -library-  exposed-modules:     MakeTravisYml-  ghc-options:         -Wall-  if impl(ghc >= 8.0)-    ghc-options:-      -Wcompat-      -Wnoncanonical-monad-instances-      -Wnoncanonical-monadfail-instances-  hs-source-dirs:      src-  other-extensions:    CPP, ViewPatterns, NamedFieldPuns-  build-depends:       base         >= 4.7  && < 4.12-                     , Cabal        == 1.18.*-                                 || == 1.20.*-                                 || == 1.22.*-                                 || == 1.24.*-                                 || == 2.0.*-                                 || == 2.2.*-                     , containers   >= 0.4  && < 0.6-                     , directory    >= 1.1  && < 1.4-                     , filepath     >= 1.2  && < 1.5-                     , transformers >= 0.3  && < 0.6-                     , deepseq      >= 1.3  && < 1.5-  default-language:    Haskell2010+library haskell-ci-internal+  exposed-modules:+    HaskellCI+    HaskellCI.Cli+    HaskellCI.Config+    HaskellCI.Config.ConstraintSet+    HaskellCI.Config.CopyFields+    HaskellCI.Config.Doctest+    HaskellCI.Config.Dump+    HaskellCI.Config.Folds+    HaskellCI.Config.HLint+    HaskellCI.Config.Installed+    HaskellCI.Config.Jobs+    HaskellCI.Extras+    HaskellCI.GHC+    HaskellCI.Glob+    HaskellCI.MakeTravisOutput+    HaskellCI.Newtypes+    HaskellCI.Optimization+    HaskellCI.OptionsGrammar+    HaskellCI.OptparseGrammar+    HaskellCI.Package+    HaskellCI.ParsecError+    HaskellCI.ParsecUtils+    HaskellCI.Project+    HaskellCI.TestedWith+    HaskellCI.Version +  -- vendored from Cabal development version+  other-modules:      Distribution.Fields.Pretty+  ghc-options:+    -Wall -Wcompat -Wnoncanonical-monad-instances+    -Wnoncanonical-monadfail-instances++  hs-source-dirs:     src+  default-extensions:+    DeriveFoldable+    DeriveFunctor+    DeriveGeneric+    DeriveTraversable++  other-extensions:+    CPP+    NamedFieldPuns+    OverloadedLabels+    ViewPatterns++  build-depends:+    , base          >=4.9      && <4.13+    , bytestring    ^>=0.10.8.1+    , Cabal         ^>=2.4+    , containers    ^>=0.5.7.1 || ^>=0.6.0.1+    , deepseq       ^>=1.4.2.0+    , directory     ^>=1.3.0.0+    , filepath      ^>=1.4.1.1+    , parsec        ^>=3.1.13.0+    , pretty        ^>=1.1.3.3+    , text          ^>=1.2.3.0+    , transformers  ^>=0.5.2.0++  -- other dependencies+  build-depends:+    , base-compat           ^>=0.10.5+    , generic-lens          ^>=1.1.0.0+    , HsYAML                ^>=0.1.1.3+    , microlens             ^>=0.4.10+    , optparse-applicative  ^>=0.14.3.0++  default-language:   Haskell2010+   -- ShellCheck. Would need newer transformers for older GHC-  if flag(ShellCheck) && impl(ghc >= 7.10 && <8.5)-    build-depends: ShellCheck == 0.5.0+  if (flag(shellcheck) && impl(ghc >=7.10 && <8.7))+    build-depends: ShellCheck ==0.6.0 -executable make-travis-yml-  main-is:             Main.hs-  ghc-options:         -Wall-  build-depends:       base, haskell-ci-  default-language:    Haskell2010+executable haskell-ci+  main-is:          Main.hs+  ghc-options:      -Wall+  hs-source-dirs:   cli+  build-depends:+    , base+    , haskell-ci-internal +  default-language: Haskell2010+ test-suite golden-  type:                exitcode-stdio-1.0-  main-is:             Tests.hs-  hs-source-dirs:      test-  build-depends:       haskell-ci-                       -- inherited constraints via lib:haskell-ci-                     , base-                     , bytestring-                     , directory-                     , filepath-                     , transformers-                       -- dependencies needing explicit constraints-                     , tasty         >= 1.0      && < 1.2-                     , tasty-golden  >= 2.3.1.1  && < 2.4-                     , ansi-terminal >= 0.8.0.2  && <0.9-                     , Diff          >= 0.3.4    && < 0.4+  type:             exitcode-stdio-1.0+  main-is:          Tests.hs+  hs-source-dirs:   test+  build-depends:+    , ansi-terminal        ^>=0.8.0.2+    , base+    , bytestring+    , Diff                 ^>=0.3.4+    , directory+    , filepath+    , haskell-ci-internal+    , tasty                >=1.0     && <1.2+    , tasty-golden         ^>=2.3.1.1+    , transformers -  default-language:    Haskell2010+  -- inherited constraints via lib:haskell-ci+  -- dependencies needing explicit constraints+  default-language: Haskell2010
+ src/Distribution/Fields/Pretty.hs view
@@ -0,0 +1,134 @@+{-# LANGUAGE BangPatterns #-}+-- | Cabal-like file AST types: 'Field', 'Section' etc,+--+-- This (intermediate) data type is used for pretty-printing.+--+-- @since 3.0.0.0+--+module Distribution.Fields.Pretty (+    -- * Fields+    PrettyField (..),+    showFields,+    showFields',+    -- * Transformation from 'P.Field'+    fromParsecFields,+    genericFromParsecFields,+    prettyFieldLines,+    prettySectionArgs,+    ) where++import Data.Functor.Identity       (Identity (..))+import Distribution.Pretty         (showToken)++import Distribution.Parsec.Field (FieldName)+import Distribution.Simple.Utils (fromUTF8BS)++import qualified Distribution.Parsec.Parser as P++import qualified Data.ByteString  as BS+import qualified Text.PrettyPrint as PP++data PrettyField+    = PrettyField FieldName PP.Doc+    | PrettySection FieldName [PP.Doc] [PrettyField]+  deriving Show++-- | Prettyprint a list of fields.+showFields :: [PrettyField] -> String+showFields = showFields' 4++-- | 'showFields' with user specified indentation.+showFields' :: Int -> [PrettyField] -> String+showFields' n = unlines . renderFields indent where+    -- few hardcoded, "unrolled"  variants.+    indent | n == 4    = indent4+           | n == 2    = indent2+           | otherwise = (replicate (max n 1) ' ' ++)++    indent4 :: String -> String+    indent4 [] = []+    indent4 xs = ' ' : ' ' : ' ' : ' ' : xs++    indent2 :: String -> String+    indent2 [] = []+    indent2 xs = ' ' : ' ' : xs++renderFields :: (String -> String) -> [PrettyField] -> [String]+renderFields indent fields = flattenBlocks $ map (renderField indent len) fields+  where+    len = maxNameLength 0 fields++    maxNameLength !acc []                          = acc+    maxNameLength !acc (PrettyField name _ : rest) = maxNameLength (max acc (BS.length name)) rest+    maxNameLength !acc (PrettySection {}   : rest) = maxNameLength acc rest++-- | Block of lines,+-- Boolean parameter tells whether block should be surrounded by empty lines+data Block = Block Bool [String]++flattenBlocks :: [Block] -> [String]+flattenBlocks = go0 where+    go0 [] = []+    go0 (Block surr strs : blocks) = strs ++ go surr blocks++    go _surr' [] = []+    go  surr' (Block surr strs : blocks) = ins $ strs ++ go surr blocks where+        ins | surr' || surr = ("" :)+            | otherwise     = id++renderField :: (String -> String) -> Int -> PrettyField -> Block+renderField indent fw (PrettyField name doc) = Block False $ case lines narrow of+    []           -> [ name' ++ ":" ]+    [singleLine] | length singleLine < 60+                 -> [ name' ++ ": " ++ replicate (fw - length name') ' ' ++ narrow ]+    _            -> (name' ++ ":") : map indent (lines (PP.render doc))+  where+    name' = fromUTF8BS name+    narrow = PP.renderStyle narrowStyle doc++    narrowStyle :: PP.Style+    narrowStyle = PP.style { PP.lineLength = PP.lineLength PP.style - fw }++renderField indent _ (PrettySection name args fields) = Block True $+    PP.render (PP.hsep $ PP.text (fromUTF8BS name) : args)+    :+    map indent (renderFields indent fields)++-------------------------------------------------------------------------------+-- Transform from Parsec.Field+-------------------------------------------------------------------------------++genericFromParsecFields+    :: Applicative f+    => (FieldName -> [P.FieldLine ann] -> f PP.Doc)     -- ^ transform field contents+    -> (FieldName -> [P.SectionArg ann] -> f [PP.Doc])  -- ^ transform section arguments+    -> [P.Field ann]+    -> f [PrettyField]+genericFromParsecFields f g = goMany where+    goMany = traverse go++    go (P.Field (P.Name _ann name) fls)          = PrettyField name <$> f name fls+    go (P.Section (P.Name _ann name) secargs fs) = PrettySection name <$> g name secargs <*> goMany fs++-- | Used in 'fromParsecFields'.+prettyFieldLines :: FieldName -> [P.FieldLine ann] -> PP.Doc+prettyFieldLines _ fls = PP.vcat+    [ PP.text $ fromUTF8BS bs+    | P.FieldLine _ bs <- fls+    ]++-- | Used in 'fromParsecFields'.+prettySectionArgs :: FieldName -> [P.SectionArg ann] -> [PP.Doc]+prettySectionArgs _ = map $ \sa -> case sa of+    P.SecArgName _ bs  -> showToken $ fromUTF8BS bs+    P.SecArgStr _ bs   -> showToken $ fromUTF8BS bs+    P.SecArgOther _ bs -> PP.text $ fromUTF8BS bs++-- | Simple variant of 'genericFromParsecField'+fromParsecFields :: [P.Field ann] -> [PrettyField]+fromParsecFields = runIdentity . genericFromParsecFields+    (Identity .: prettyFieldLines)+    (Identity .: prettySectionArgs)+  where+    (.:) :: (a -> b) -> (c -> d -> a) -> (c -> d -> b)+    (f .: g) x y = f (g x y)
+ src/HaskellCI.hs view
@@ -0,0 +1,1029 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedLabels #-}++-- | New-style @.travis.yml@ script generator using cabal 1.24's nix-style+-- tech-preview facilities.+--+-- See also <https://github.com/haskell-CI/haskell-ci>+--+-- NB: This code deliberately avoids relying on non-standard packages and+--     is expected to compile/work with at least GHC 7.0 through GHC 8.0+module HaskellCI (+    main,+    -- * for tests+    Result (..),+    Diagnostic (..),+    parseTravis,+    formatDiagnostic, formatDiagnostics,+    travisFromConfigFile, MakeTravisOutput, Options (..), defaultOptions,+    ) where++import Prelude ()+import Prelude.Compat++import Control.DeepSeq (force)+import Control.Exception (evaluate)+import Control.Monad (when, unless, liftM, forM_, mzero)+import qualified Data.ByteString as BS+import qualified Data.Foldable as F+import qualified Data.Traversable as T+import Data.Function+import Data.List+import Data.Maybe+import Data.Set (Set)+import qualified Data.Set as S+import qualified Data.Map as M+import System.Directory (doesDirectoryExist, doesFileExist)+import System.Exit+import System.FilePath.Posix ((</>), takeDirectory, takeFileName, takeExtension)+import System.IO+import Control.Monad.IO.Class+import Control.Monad.Trans.Maybe+import System.Environment (getArgs)+import Control.Monad.Trans.Writer+import Text.Read (readMaybe)+import Distribution.Compat.ReadP (readP_to_S)+++import qualified Options.Applicative         as O++import Distribution.Compiler (CompilerFlavor(..))+import Distribution.Package hiding (Package, pkgName)+import qualified Distribution.Package as Pkg+import Distribution.PackageDescription (GenericPackageDescription,packageDescription, testedWith, package, condLibrary, condTestSuites)+import Distribution.PackageDescription.Configuration (flattenPackageDescription)+import qualified Distribution.PackageDescription as PD+import qualified Distribution.ParseUtils as PU+import Distribution.Text+import Distribution.Version+#if MIN_VERSION_Cabal(2,2,0)+import Distribution.PackageDescription.Parsec (readGenericPackageDescription)+#elif MIN_VERSION_Cabal(2,0,0)+import Distribution.PackageDescription.Parse (readGenericPackageDescription)+#else+import Distribution.PackageDescription.Parse (readPackageDescription)+import Distribution.Verbosity (Verbosity)+#endif++import qualified Distribution.FieldGrammar                    as C+import qualified Distribution.Fields.Pretty                   as C+import qualified Distribution.PackageDescription.FieldGrammar as C+import qualified Distribution.Types.SourceRepo                as C+import qualified Distribution.Types.VersionRange              as C+import qualified Text.PrettyPrint                             as PP++++#if MIN_VERSION_base(4,9,0)+import Data.Semigroup (Semigroup (..))+#else+import Data.Monoid ((<>))+#endif++-- lens+import Lens.Micro+import Data.Generics.Labels () -- IsLabel (->) ...++import qualified Distribution.Types.BuildInfo.Lens          as L+import qualified Distribution.Types.PackageDescription.Lens as L++import HaskellCI.Cli+import HaskellCI.Config+import HaskellCI.Config.CopyFields+import HaskellCI.Config.ConstraintSet+import HaskellCI.Config.Doctest+import HaskellCI.Config.Dump+import HaskellCI.Config.Folds+import HaskellCI.Config.HLint+import HaskellCI.Config.Installed+import HaskellCI.Config.Jobs+import HaskellCI.Extras+import HaskellCI.GHC+import HaskellCI.Glob+import HaskellCI.MakeTravisOutput+import HaskellCI.Optimization+import HaskellCI.Package+import HaskellCI.Project+import HaskellCI.TestedWith+import HaskellCI.Version++#ifndef CURRENT_PACKAGE_VERSION+#define CURRENT_PACKAGE_VERSION "???"+#endif++-------------------------------------------------------------------------------+-- Main+-------------------------------------------------------------------------------++main :: IO ()+main = do+    argv0 <- getArgs+    (cmd, opts) <- O.execParser cliParserInfo+    case cmd of+        CommandListGHC -> do+            putStrLn $ "Supported GHC versions:"+            forM_ groupedVersions $ \(v, vs) -> do+                putStr $ prettyMajVersion v ++ ": "+                putStrLn $ intercalate ", " (map display vs)+        CommandDumpConfig -> do+            putStr $ unlines $ runDG configGrammar++        CommandRegenerate -> do+            let fp = ".travis.yml" -- make configurable?+            contents <- readFile fp+            case findArgv (lines contents) of+                Nothing     -> do+                    hPutStrLn stderr $ "Error: expected REGENDATA line in " ++ fp+                    exitFailure+                Just argv   -> do+                    (f, opts') <- parseTravis argv+                    doTravis argv f (opts' <> opts)+        CommandTravis f -> doTravis argv0 f opts+  where+    findArgv :: [String] -> Maybe [String]+    findArgv ls = do+        l <- findMaybe (afterInfix "REGENDATA") ls+        readMaybe l++    groupedVersions :: [(Version, [Version])]+    groupedVersions = map ((\vs -> (head vs, vs)) . sortBy (flip compare))+                    . groupBy ((==) `on` ghcMajVer)+                    $ sort knownGhcVersions++    prettyMajVersion :: Version -> String+    prettyMajVersion v+        | Just v == ghcAlpha = "alpha"+        | otherwise = case ghcMajVer v of (x,y) -> show x ++ "." ++ show y++doTravis :: [String] -> FilePath -> Options -> IO ()+doTravis args path opts = do+    runYamlWriter (optOutput opts) $ travisFromConfigFile args opts path++runYamlWriter :: Maybe FilePath -> YamlWriter IO () -> IO ()+runYamlWriter mfp m = do+    result <- execWriterT (runMaybeT m)+    case result of+        Failure (formatDiagnostics -> errors) -> hPutStr stderr errors >> exitFailure+        Success (formatDiagnostics -> warnings) (unlines -> contents) -> do+            contents' <- evaluate (force contents)+            hPutStr stderr warnings+            case mfp of+                Nothing -> putStr contents'+                Just fp -> writeFile fp contents'++travisFromConfigFile+    :: MonadIO m+    => [String]+    -> Options+    -> FilePath+    -> YamlWriter m ()+travisFromConfigFile args opts path = do+    cabalFiles <- getCabalFiles+    config' <- maybe (return emptyConfig) readConfigFile (optConfig opts)+    let config = optConfigMorphism opts config'+    pkgs <- T.mapM (configFromCabalFile config opts) cabalFiles+    (ghcs, prj) <- case checkVersions (cfgTestedWith config) pkgs of+        Right x     -> return x+        Left errors -> putStrLnErrs errors >> mzero+    genTravisFromConfigs args opts isCabalProject config prj ghcs+  where+    isCabalProject :: Maybe FilePath+    isCabalProject+        | "cabal.project" `isPrefixOf` takeFileName path = Just path+        | otherwise = Nothing++    getCabalFiles :: MonadIO m => YamlWriter m (Project FilePath)+    getCabalFiles+        | isNothing isCabalProject = return $ emptyProject & #prjPackages .~ [path]+        | otherwise = do+            contents <- liftIO $ BS.readFile path+            pkgs <- either putStrLnErr return $ parseProjectFile path contents+            over #prjPackages concat `liftM` T.mapM findProjectPackage pkgs++    rootdir = takeDirectory path++    -- See findProjectPackages in cabal-install codebase+    -- this is simple variant.+    findProjectPackage :: MonadIO m => String -> YamlWriter m [FilePath]+    findProjectPackage pkglocstr = do+        mfp <- checkisFileGlobPackage pkglocstr `mplusMaybeT`+               checkIsSingleFilePackage pkglocstr+        maybe (putStrLnErr $ "bad package location: " ++ pkglocstr) return mfp++    checkIsSingleFilePackage pkglocstr = do+        let abspath = rootdir </> pkglocstr+        isFile <- liftIO $ doesFileExist abspath+        isDir  <- liftIO $ doesDirectoryExist abspath+        if | isFile && takeExtension pkglocstr == ".cabal" -> return (Just [abspath])+           | isDir -> checkisFileGlobPackage (pkglocstr </> "*.cabal")+           | otherwise -> return Nothing++    -- if it looks like glob, glob+    checkisFileGlobPackage pkglocstr =+        case filter (null . snd) $ readP_to_S parseFilePathGlobRel pkglocstr of+            [(g, "")] -> do+                files <- liftIO $ expandRelGlob rootdir g+                let files' = filter ((== ".cabal") . takeExtension) files+                -- if nothing is matched, skip.+                if null files' then return Nothing else return (Just files')+            _         -> return Nothing++    mplusMaybeT :: Monad m => m (Maybe a) -> m (Maybe a) -> m (Maybe a)+    mplusMaybeT ma mb = do+        mx <- ma+        case mx of+            Nothing -> mb+            Just x  -> return (Just x)++configFromCabalFile+    :: MonadIO m => Config ->  Options -> FilePath -> YamlWriter m (Package, Set Version)+configFromCabalFile cfg opts cabalFile = do+    gpd <- liftIO $ readGenericPackageDescription maxBound cabalFile++    let compilers = testedWith $ packageDescription gpd+        pkgNameStr = display $ Pkg.pkgName $ package $ packageDescription gpd++    let unknownComps = nub [ c | (c,_) <- compilers, c /= GHC ]+        ghcVerConstrs = [ vc | (GHC,vc) <- compilers ]+        ghcVerConstrs' = simplifyVersionRange $ foldr unionVersionRanges noVersion ghcVerConstrs+        twoDigitGhcVerConstrs = mapMaybe isTwoDigitGhcVersion ghcVerConstrs :: [Version]+        specificGhcVers = nub $ mapMaybe isSpecificVersion ghcVerConstrs++    unless (null twoDigitGhcVerConstrs) $ do+        putStrLnWarn $ "'tested-with:' uses two digit GHC versions (which don't match any existing GHC version): " ++ intercalate ", " (map display twoDigitGhcVerConstrs)+        putStrLnInfo $ "Either use wild-card format, for example 'tested-with: GHC ==7.10.*' or a specific existing version 'tested-with: GHC ==7.10.3'"++    when (null compilers) $ do+        putStrLnErr (unlines $+                     [ "empty or missing top-level 'tested-with:' definition in " ++ cabalFile ++ " file; example definition:"+                     , ""+                     , "tested-with: " ++ intercalate ", " [ "GHC==" ++ display v | v <- lastStableGhcVers ]+                     ])++    unless (null unknownComps) $ do+        putStrLnWarn $ "ignoring unsupported compilers mentioned in tested-with: " ++ show unknownComps++    when (null ghcVerConstrs) $ do+        putStrLnErr "'tested-with:' doesn't mention any 'GHC' version"++    when (isNoVersion ghcVerConstrs') $ do+        putStrLnErr "'tested-with:' describes an empty version range for 'GHC'"++    when (isAnyVersion ghcVerConstrs') $ do+        putStrLnErr "'tested-with:' allows /any/ 'GHC' version"++    let unknownGhcVers = sort $ specificGhcVers \\ knownGhcVersions++    unless (null unknownGhcVers) $ do+        putStrLnErr ("'tested-with:' specifically refers to unknown 'GHC' versions: "+                     ++ intercalate ", " (map display unknownGhcVers) ++ "\n"+                     ++ "Known GHC versions: " ++ intercalate ", " (map display knownGhcVersions))++    let knownGhcVersions'+            | cfgLastInSeries cfg = filterLastMajor knownGhcVersions+            | otherwise           = knownGhcVersions++    let testedGhcVersions = filter (`withinRange` ghcVerConstrs') knownGhcVersions'++    when (null testedGhcVersions) $ do+        putStrLnErr "no known GHC version is allowed by the 'tested-with' specification"++    forM_ (optCollections opts) $ \c -> do+        let v = collToGhcVer c+        unless (v `elem` testedGhcVersions) $+            putStrLnErr $ unlines+               [ "collection " ++ c ++ " requires GHC " ++ display v+               , "add 'tested-width: GHC == " ++ display v ++ "' to your .cabal file"+               ]++    let pkg = Pkg pkgNameStr anyVersion (takeDirectory cabalFile) gpd++    return (pkg, S.fromList testedGhcVersions)+  where+    lastStableGhcVers+        = nubBy ((==) `on` ghcMajVer)+        $ sortBy (flip compare)+        $ filter (not . previewGHC . Just)+        $ knownGhcVersions++    isTwoDigitGhcVersion :: VersionRange -> Maybe Version+    isTwoDigitGhcVersion vr = isSpecificVersion vr >>= t+      where+        t v | [_,_] <- versionNumbers v = Just v+        t _                             = Nothing++    filterLastMajor = map maximum . groupBy ((==) `on` ghcMajVer)++genTravisFromConfigs+    :: Monad m+    => [String]+    -> Options+    -> Maybe FilePath+    -> Config+    -> Project Package+    -> Set Version+    -> YamlWriter m ()+genTravisFromConfigs argv opts isCabalProject config prj@Project { prjPackages = pkgs } versions' = do+    let folds = cfgFolds config++    putStrLnInfo $+        "Generating Travis-CI config for testing for GHC versions: " ++ ghcVersions++    unless (null $ cfgOsx config) $  do+        putStrLnInfo $ "Also OSX jobs for: " ++ ghcOsxVersions+        unless (S.null omittedOsxVersions) $+            putStrLnWarn $ "Not all GHC versions specified with --osx are generated: " ++ ghcOmittedOsxVersions++    ---------------------------------------------------------------------------+    -- travis.yml generation starts here++    tellStrLns+        [ "# This Travis job script has been generated by a script via"+        , "#"+        , rawRow $ "#   haskell-ci " ++ unwords [ "'" ++ a ++ "'" | a <- argv ]+        , "#"+        , "# For more information, see https://github.com/haskell-CI/haskell-ci"+        , "#"+        , rawRow $ "# version: " ++ CURRENT_PACKAGE_VERSION+        , "#"+        , "language: c"+        , "dist: xenial"+        , ""+        , "git:"+        , "  submodules: false  # whether to recursively clone submodules"+        , ""+        ]++    let projectName = fromMaybe (pkgName $ head pkgs) (cfgProjectName config)+    unless (null $ cfgIrcChannels config) $ tellStrLnsRaw $+        [ "notifications:"+        , "  irc:"+        , "    channels:"+        ] +++        [ "      - \"" ++ chan ++ "\"" | chan <- cfgIrcChannels config ] +++        [ "    skip_join: true"+        , "    template:"+        , "      - \"\\x0313" ++ projectName ++ "\\x03/\\x0306%{branch}\\x03 \\x0314%{commit}\\x03 %{build_url} %{message}\""+        , ""+        ]++    unless (null $ cfgOnlyBranches config) $ tellStrLnsRaw $+        [ "branches:"+        , "  only:"+        ] +++        [ "    - " ++ branch+        | branch <- cfgOnlyBranches config+        ] +++        [ ""+        ]++    -- cache directories+    when (cfgCache config) $ tellStrLns+        [ "cache:"+        , "  directories:"+        , "    - $HOME/.cabal/packages"+        , "    - $HOME/.cabal/store"+        ]+++    -- on OSX ghc is installed in $HOME so we can cache it+    -- independently of linux+    when (cfgCache config && not (null (cfgOsx config))) $ tellStrLns+        [ "    - $HOME/.ghc-install"+        ]++    tellStrLn ""++    -- postgresql+    when (cfgPostgres config) $ tellStrLns+        [ "services:"+        , "- postgresql"+        , "addons:"+        , "  postgresql: '10'"+        , ""+        ]++    -- before caching: clear some redundant stuff+    when (cfgCache config) $ tellStrLns+        [ "before_cache:"+        , "  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log"+        , "  # remove files that are regenerated by 'cabal update'"+        , "  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*" -- legacy+        , "  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json" -- TUF meta-data+        , "  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache"+        , "  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar"+        , "  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx"+        , ""+        , "  - rm -rfv $CABALHOME/packages/head.hackage" -- if we cache, it will break builds.+        , ""+        ]++    tellStrLn "matrix:"+    tellStrLn "  include:"++    let colls = [ (collToGhcVer cid,cid) | cid <- reverse $ optCollections opts ]++    let tellJob :: Monad m => Bool -> Maybe Version -> YamlWriter m ()+        tellJob osx gv = do+            let cvs = dispGhcVersion $ gv >> cfgCabalInstallVersion config+                gvs = dispGhcVersion gv++                xpkgs' = concatMap (',':) (S.toList $ cfgApt config)++                colls' = [ cid | (v,cid) <- colls, Just v == gv ]++            tellStrLnsRaw $ catMaybes+                [ Just $ "    - compiler: \"ghc-" <> gvs <> "\""+                , if | Just e <- gv >>= \v -> M.lookup v (cfgEnv config)+                                     -> Just $ "      env: " ++ e+                     | previewGHC gv -> Just $ "      env: GHCHEAD=true"+                     | null colls'   -> Nothing+                     | otherwise     -> Just $ "      env: 'COLLECTIONS=" ++ intercalate "," colls' ++ "'"+                , Just $ "      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-" <> cvs <> ",ghc-" <> gvs <> xpkgs' <> "], sources: [hvr-ghc]}}"+                ]++            when osx $ tellStrLnsRaw+                [ "      os: osx"+                ]++    -- newer GHC first, -head last (which is great).+    -- Alpha release would go first though.+    F.forM_ (reverse $ S.toList versions) $ tellJob False+    F.forM_ (reverse $ S.toList osxVersions) $ tellJob True . Just++    let allowFailures = headGhcVers `S.union` S.map Just (S.filter (`C.withinRange` cfgAllowFailures config) versions')+    unless (S.null allowFailures) $ do+        tellStrLn ""+        tellStrLn "  allow_failures:"++        F.forM_ allowFailures $ \gv -> do+            let gvs = dispGhcVersion gv+            tellStrLn $ concat [ "    - compiler: \"ghc-", gvs, "\"" ]++    tellStrLns+        [ ""+        , "before_install:"+        , sh "HC=/opt/ghc/bin/${CC}"+        , sh' [2034,2039] "HCPKG=${HC/ghc/ghc-pkg}" -- SC2039. In POSIX sh, string replacement is undefined.+        , sh "unset CC"+        -- cabal+        , sh "CABAL=/opt/ghc/bin/cabal"+        , sh "CABALHOME=$HOME/.cabal"+        -- PATH+        , sh "export PATH=\"$CABALHOME/bin:$PATH\""+        -- rootdir is useful for manual script additions+        , sh "ROOTDIR=$(pwd)"+        ]++    -- macOS installing+    let haskellOnMacos = "https://haskell.futurice.com/haskell-on-macos.py"+    unless (null (cfgOsx config)) $ tellStrLns+        [ sh $ "if [ \"$TRAVIS_OS_NAME\" = \"osx\" ]; then brew update; brew upgrade python@3; curl " ++ haskellOnMacos ++ " | python3 - --make-dirs --install-dir=$HOME/.ghc-install --cabal-alias=head install cabal-install-head ${TRAVIS_COMPILER}; fi"+        , sh' [2034,2039] "if [ \"$TRAVIS_OS_NAME\" = \"osx\" ]; then HC=$HOME/.ghc-install/ghc/bin/$TRAVIS_COMPILER; HCPKG=${HC/ghc/ghc-pkg}; CABAL=$HOME/.ghc-install/ghc/bin/cabal; fi"+        ]++    -- HCNUMVER, numeric HC version, e.g. ghc 7.8.4 is 70804 and 7.10.3 is 71003+    tellStrLns+        [ sh $ "HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\\.([0-9]+)\\.([0-9]+).*/\\1 * 10000 + \\2 * 100 + \\3/') ))"+        , sh "echo $HCNUMVER"+        ]++    unless (null colls) $+       tellStrLn " - IFS=', ' read -a COLLS <<< \"$COLLECTIONS\""++    tellStrLns+        [ ""+        , "install:"+        , sh "${CABAL} --version"+        , sh "echo \"$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]\""+        , sh "TEST=--enable-tests"+        , shForJob versions' (invertVersionRange $ cfgTests config) "TEST=--disable-tests"+        , sh "BENCH=--enable-benchmarks"+        , shForJob versions' (invertVersionRange $ cfgBenchmarks config) "BENCH=--disable-benchmarks"+        , sh "GHCHEAD=${GHCHEAD-false}"+        ]++    -- Update hackage index. Side-effect: ~/.cabal.config is created.+    tellStrLns+        [ sh "travis_retry ${CABAL} update -v"+        , sh "sed -i.bak 's/^jobs:/-- jobs:/' $CABALHOME/config"+        , sh "rm -fv cabal.project cabal.project.local"+        ]++    -- Cabal jobs+    case cfgJobs config >>= cabalJobs of+        Just n -> tellStrLns+            [ sh $ "sed -i.bak 's/^-- jobs:.*/jobs: " ++ show n ++ "/' $CABALHOME/config"+            ]+        _ -> return ()++    -- GHC jobs+    case cfgJobs config >>= ghcJobs of+        Just m -> tellStrLns+            [ shForJob versions' (orLaterVersion (mkVersion [7,8])) $+              "sed -i.bak 's/-- ghc-options:.*/ghc-options: -j" ++ show m ++ "/' $CABALHOME/config"+            ]+        _ -> return ()++    -- Add head.hackage repository to ~/.cabal/config+    -- (locally you want to add it to cabal.project)+    unless (S.null headGhcVers) $ tellStrLns+        [ "  # Overlay Hackage Package Index for GHC HEAD: https://github.com/hvr/head.hackage"+        , "  - |"+        , "    if $GHCHEAD; then"+        , "      sed -i 's/-- allow-newer: .*/allow-newer: *:base/' $CABALHOME/config"+        , "      for pkg in $($HCPKG list --simple-output); do pkg=$(echo $pkg | sed 's/-[^-]*$//'); sed -i \"s/allow-newer: /allow-newer: *:$pkg, /\" $CABALHOME/config; done"+        , ""+        , "      echo 'repository head.hackage'                                                        >> $CABALHOME/config"+        , "      echo '   url: http://head.hackage.haskell.org/'                                       >> $CABALHOME/config"+        , "      echo '   secure: True'                                                                >> $CABALHOME/config"+        , "      echo '   root-keys: 07c59cb65787dedfaef5bd5f987ceb5f7e5ebf88b904bbd4c5cbdeb2ff71b740' >> $CABALHOME/config"+        , "      echo '              2e8555dde16ebd8df076f1a8ef13b8f14c66bad8eafefd7d9e37d0ed711821fb' >> $CABALHOME/config"+        , "      echo '              8f79fd2389ab2967354407ec852cbe73f2e8635793ac446d09461ffb99527f6e' >> $CABALHOME/config"+        , "      echo '   key-threshold: 3'                                                            >> $CABALHOME.config"+        , ""+        , "      grep -Ev -- '^\\s*--' $CABALHOME/config | grep -Ev '^\\s*$'"+        , ""+        , "      ${CABAL} new-update head.hackage -v"+        , "    fi"+        ]++    -- Output cabal.config+    tellStrLns+        [ sh "grep -Ev -- '^\\s*--' $CABALHOME/config | grep -Ev '^\\s*$'"+        ]++    -- Install doctest+    let doctestVersionConstraint+            | isAnyVersion (cfgDoctestVersion doctestConfig) = ""+            | otherwise = " --constraint='doctest " ++ display (cfgDoctestVersion doctestConfig) ++ "'"+    when (cfgDoctestEnabled doctestConfig) $ tellStrLns+        [ shForJob versions' doctestJobVersionRange $ "${CABAL} new-install -w ${HC} -j2 doctest" ++ doctestVersionConstraint+        ]++    -- Install hlint+    let hlintVersionConstraint+            | isAnyVersion (cfgHLintVersion hlintConfig) = ""+            | otherwise = " --constraint='hlint " ++ display (cfgHLintVersion hlintConfig) ++ "'"+    when (cfgHLintEnabled hlintConfig) $ tellStrLns+        [ shForJob versions' (hlintJobVersionRange versions (cfgHLintJob hlintConfig)) $+          "${CABAL} new-install -w ${HC} -j2 hlint" ++ hlintVersionConstraint+        ]++    -- create cabal.project file+    generateCabalProject False++    let pkgFilter = intercalate " | " $ map (wrap.pkgName) pkgs+        wrap s = "grep -Fv \"" ++ s ++ " ==\""+    unless (null colls) $ tellStrLnsRaw+        [ "  - for COLL in \"${COLLS[@]}\"; do"+        , "      echo \"== collection $COLL ==\";"+        , "      ghc-travis collection ${COLL} > /dev/null || break;"+        , "      ghc-travis collection ${COLL} | " ++ pkgFilter ++ " > cabal.project.freeze;"+        , "      grep ' collection-id' cabal.project.freeze;"+        , "      rm -rf dist-newstyle/;"+        , "      $(CABAL} new-build -w ${HC} ${TEST} ${BENCH} --project-file=\"" ++ projectFile ++ "\" --dep -j2 all;"+        , "    done"+        , ""+        ]++    forM_ pkgs $ \Pkg{pkgDir} -> tellStrLns+        [ sh $ "if [ -f \"" ++ pkgDir ++ "/configure.ac\" ]; then (cd \"" ++ pkgDir ++ "\" && autoreconf -i); fi"+        ]++    let quotedRmPaths =+          ".ghc.environment.*"+          ++ " " +++          unwords (quotedPaths (\Pkg{pkgDir} -> pkgDir ++ "/dist"))++    tellStrLns+        [ sh $ "rm -f cabal.project.freeze"+        ]++    -- Install dependencies+    when (cfgInstallDeps config) $ do+        tellStrLns+            -- dump install plan+            [ sh $ "${CABAL} new-freeze -w ${HC} ${TEST} ${BENCH} --project-file=\"" ++ projectFile ++"\" --dry"+            , sh $ "cat \"" ++ projectFile ++ ".freeze\" | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"+            , sh $ "rm  \"" ++ projectFile ++ ".freeze\""++            -- install dependencies+            , sh $ "${CABAL} new-build -w ${HC} ${TEST} ${BENCH} --project-file=\"" ++ projectFile ++"\" --dep -j2 all"+            ]+        tellStrLns+            [ shForJob versions' (cfgNoTestsNoBench config) $ "${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks --project-file=\"" ++ projectFile ++ "\" --dep -j2 all"+            ]++    tellStrLns+        [ sh $ "rm -rf " ++ quotedRmPaths+        , sh $  "DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)"+        ]++    tellStrLns+        [ ""+        , "# Here starts the actual work to be performed for the package under test;"+        , "# any command which exits with a non-zero exit code causes the build to fail."+        , "script:"+        , "  # test that source-distributions can be generated"+        ]++    foldedTellStrLns FoldSDist "Packaging..." folds $ do+        tellStrLns+            [ sh $ "${CABAL} new-sdist all"+            ]++    let tarFiles = "dist-newstyle" </> "sdist" </> "*.tar.gz"+++    foldedTellStrLns FoldUnpack "Unpacking..." folds $ do+        tellStrLns+            [ sh $ "mv " ++ tarFiles ++ " ${DISTDIR}/"+            , sh $ "cd ${DISTDIR} || false" -- fail explicitly, makes SC happier+            , sh $ "find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \\;"+            ]+        generateCabalProject True++    unless (equivVersionRanges noVersion $ cfgNoTestsNoBench config) $ foldedTellStrLns FoldBuild "Building..." folds $ tellStrLns+        [ comment "this builds all libraries and executables (without tests/benchmarks)"+        , shForJob versions' (cfgNoTestsNoBench config) $ "${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks all"+        ]++    tellStrLns [""]+++    foldedTellStrLns FoldBuildEverything+        "Building with tests and benchmarks..." folds $ tellStrLns+        [ comment "build & run tests, build benchmarks"+        , sh "${CABAL} new-build -w ${HC} ${TEST} ${BENCH} all"+        ]++    -- cabal new-test fails if there are no test-suites.+    when hasTests $+        foldedTellStrLns FoldTest "Testing..." folds $ tellStrLns+            [ sh $ mconcat+                [ "if [ \"x$TEST\" = \"x--enable-tests\" ]; then "+                , if cfgNoise config+                     then "${CABAL} "+                     else "(set -o pipefail; ${CABAL} -vnormal+nowrap+markoutput "+                , "new-test -w ${HC} ${TEST} ${BENCH} all"+                , if cfgNoise config+                     then ""+                     else " 2>&1 | sed '/^-----BEGIN CABAL OUTPUT-----$/,/^-----END CABAL OUTPUT-----$/d' )"+                , "; fi"+                ]+            ]++    tellStrLns [""]++    when (cfgDoctestEnabled doctestConfig) $ do+        let doctestOptions = unwords $ cfgDoctestOptions doctestConfig+        tellStrLns [ comment "doctest" ]+        foldedTellStrLns FoldDoctest "Doctest..." folds $ do+            forM_ pkgs $ \Pkg{pkgName,pkgGpd,pkgJobs} -> do+                forM_ (doctestArgs pkgGpd) $ \args -> do+                    let args' = unwords args+                    unless (null args) $ tellStrLns+                        [ shForJob versions' (doctestJobVersionRange `intersectVersionRanges` pkgJobs) $+                          "(cd " ++ pkgName ++ "-* && doctest " ++ doctestOptions ++ " " ++ args' ++ ")"+                        ]+        tellStrLns [ "" ]++    when (cfgHLintEnabled hlintConfig) $ do+        let "" <+> ys = ys+            xs <+> "" = xs+            xs <+> ys = xs ++ " " ++ ys++            prependSpace "" = ""+            prependSpace xs = " " ++ xs++        let hlintOptions = prependSpace $ maybe "" ("-h ${ROOTDIR}/" ++) (cfgHLintYaml hlintConfig) <+> unwords (cfgHLintOptions hlintConfig)++        tellStrLns [ comment "hlint" ]+        foldedTellStrLns FoldHLint "HLint.." folds $ do+            forM_ pkgs $ \Pkg{pkgName,pkgGpd,pkgJobs} -> do+                -- note: similar arguments work so far for doctest and hlint+                forM_ (hlintArgs pkgGpd) $ \args -> do+                    let args' = unwords args+                    unless (null args) $ tellStrLns+                        [ shForJob versions' (hlintJobVersionRange versions (cfgHLintJob hlintConfig) `intersectVersionRanges` pkgJobs) $+                          "(cd " ++ pkgName ++ "-* && hlint" ++ hlintOptions ++ " " ++ args' ++ ")"+                        ]+        tellStrLns [ "" ]++    when (cfgCheck config) $+        foldedTellStrLns FoldCheck "cabal check..." folds $ do+            tellStrLns [ comment "cabal check" ]+            forM_ pkgs $ \Pkg{pkgName,pkgJobs} -> tellStrLns+                [ shForJob versions' pkgJobs $+                  "(cd " ++ pkgName ++ "-* && ${CABAL} check)"+                ]+            tellStrLns [ "" ]++    when (hasLibrary && not (equivVersionRanges noVersion $ cfgHaddock config)) $+        foldedTellStrLns FoldHaddock "Haddock..." folds $ tellStrLns+            [ comment "haddock"+            , shForJob versions' (cfgHaddock config) "${CABAL} new-haddock -w ${HC} ${TEST} ${BENCH} all"+            , ""+            ]++    unless (null colls) $+        foldedTellStrLns FoldStackage "Stackage builds..." folds $ tellStrLnsRaw+            [ "  # try building & testing for package collections"+            , "  - for COLL in \"${COLLS[@]}\"; do"+            , "      echo \"== collection $COLL ==\";"+            , "      ghc-travis collection ${COLL} > /dev/null || break;"+            , "      ghc-travis collection ${COLL} | " ++ pkgFilter ++ " > cabal.project.freeze;"+            , "      grep ' collection-id' cabal.project.freeze;"+            , "      rm -rf dist-newstyle/;"+            , "      ${CABAL} new-build -w ${HC} ${TEST} ${BENCH} all || break;"+            , "      if [ \"x$TEST\" = \"x--enable-tests\" ]; then ${CABAL} new-test -w ${HC} ${TEST} ${BENCH} all || break; fi;"+            , "    done"+            , ""+            ]++    -- Have to build last, as we remove cabal.project.local+    unless (equivVersionRanges noVersion $ cfgUnconstrainted config) $ foldedTellStrLns FoldBuildInstalled+        "Building without installed constraints for packages in global-db..." folds $ tellStrLns+        [ comment "Build without installed constraints for packages in global-db"+        , shForJob versions' (cfgUnconstrainted config) "rm -f cabal.project.local; ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks all;"+        , ""+        ]++    -- and now, as we don't have cabal.project.local;+    -- we can test with other constraint sets+    let constraintSets = cfgConstraintSets config+    unless (null constraintSets) $ do+        tellStrLns+            [ comment "Constraint sets"+            , sh "rm -rf cabal.project.local"+            , ""+            ]+        forM_ constraintSets $ \cs -> do+            let name = csName cs+            let constraintFlags = concatMap (\x ->  " --constraint='" ++ x ++ "'") (csConstraints cs)+            let cmd | csRunTests cs = "${CABAL} new-test  -w ${HC} --enable-tests  --enable-benchmarks"+                    | otherwise     = "${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks"+            tellStrLns [ comment $ "Constraint set " ++ name ]+            foldedTellStrLns' FoldConstraintSets name ("Constraint set " ++ name) folds $ tellStrLns+                [ shForJob versions' (csGhcVersions cs) $+                  cmd ++ " " ++ constraintFlags ++ " all"+                , ""+                ]+        tellStrLns [""]++    tellStrLnsRaw+        [ "# REGENDATA " ++ show argv+        , "# EOF"+        ]++    return ()+  where+    doctestConfig = cfgDoctest config+    hlintConfig   = cfgHLint config++    hasTests   = F.any (\Pkg{pkgGpd} -> not . null $ condTestSuites pkgGpd) pkgs+    hasLibrary = F.any (\Pkg{pkgGpd} -> isJust $ condLibrary pkgGpd) pkgs++    -- GHC versions which need head.hackage+    headGhcVers = S.filter previewGHC versions++    generateCabalProject dist = do+        tellStrLns+            [ sh "rm -f cabal.project"+            , sh "touch cabal.project"+            ]+        F.forM_  pkgs $ \pkg -> do+            let p | dist      = pkgName pkg ++ "-*/*.cabal"+                  | otherwise = pkgDir pkg+            tellStrLns $+                [ shForJob versions' (pkgJobs pkg) $ "printf 'packages: \"" ++ p ++ "\"\\n' >> cabal.project"+                ]++        case cfgCopyFields config of+            CopyFieldsNone -> return ()+            CopyFieldsAll  -> unless (null (prjOrigFields prj)) $ tellStrLns+                [ sh $ "echo '" ++ l ++ "' >> cabal.project"+                | l <- lines $ C.showFields' 2 $ prjOrigFields prj+                , not (null l)+                ]+            CopyFieldsSome -> do+                F.forM_ (prjConstraints prj) $ \xs -> do+                    let s = concat (lines xs)+                    tellStrLns+                        [ sh $ "echo 'constraints: " ++ s ++ "' >> cabal.project"+                        ]+                F.forM_ (prjAllowNewer prj) $ \xs -> do+                    let s = concat (lines xs)+                    tellStrLns+                        [ sh $ "echo 'allow-newer: " ++ s ++ "' >> cabal.project"+                        ]+                unless (null (cfgLocalGhcOptions config)) $ forM_ pkgs $ \Pkg{pkgName} -> do+                    let s = unwords $ map (show . PU.showToken) $ cfgLocalGhcOptions config+                    tellStrLns+                        [ sh $ "echo 'package " ++ pkgName ++ "' >> cabal.project"+                        , sh $ "echo '  ghc-options: " ++ s ++ "' >> cabal.project"+                        ]++                when (prjReorderGoals prj) $+                    tellStrLns+                        [ sh $ "echo 'reorder-goals: True' >> cabal.project"+                        ]++                F.forM_ (prjMaxBackjumps prj) $ \bj ->+                    tellStrLns+                        [ sh $ "echo 'max-backjumps: " ++ show bj ++ "' >> cabal.project"+                        ]++                case prjOptimization prj of+                    OptimizationOn      -> return ()+                    OptimizationOff     -> tellStrLns [ sh $ "echo 'optimization: False' >> cabal.project " ]+                    OptimizationLevel l -> tellStrLns [ sh $ "echo 'optimization: " ++ show l ++ "' >> cabal.project " ]++                F.forM_ (prjSourceRepos prj) $ \repo -> do+                    let repo' = PP.render $ C.prettyFieldGrammar (C.sourceRepoFieldGrammar $ C.RepoKindUnknown "unused") repo+                    tellStrLns [ sh $ "echo 'source-repository-package' >> cabal.project" ]+                    tellStrLns [ sh $ "echo '  " ++ l ++ "' >> cabal.project" | l <- lines repo' ]++        -- mandatory cabal.project setup+        tellStrLns+            [ sh $ "printf 'write-ghc-environment-files: always\\n' >> cabal.project"+            ]++        unless (null (cfgRawProject config)) $ tellStrLns+            [ sh $ "echo '" ++ l ++ "' >> cabal.project"+            | l <- lines $ C.showFields' 2 $ cfgRawProject config+            , not (null l)+            ]++        -- also write cabal.project.local file with+        -- @+        -- constraints: base installed+        -- constraints: array installed+        -- ...+        --+        -- omitting any local package names+        case normaliseInstalled (cfgInstalled config) of+            InstalledDiff pns -> tellStrLns+                [ sh $ "touch cabal.project.local"+                , sh $ unwords+                    [ "for pkg in $($HCPKG list --simple-output); do"+                    , "echo $pkg"+                    , "| sed 's/-[^-]*$//'"+                    , "| grep -vE -- " ++ re+                    , "| sed 's/^/constraints: /'"+                    , "| sed 's/$/ installed/'"+                    , ">> cabal.project.local; done"+                    ]+                ]+              where+                pns' = S.map unPackageName pns `S.union` foldMap (S.singleton . pkgName) pkgs+                re = "'^(" ++ intercalate "|" (S.toList pns') ++ ")$'"++            InstalledOnly pns | not (null pns') -> tellStrLns+                [ sh $ "touch cabal.project.local"+                , sh' [2043] $ unwords+                    [ "for pkg in " ++ unwords (S.toList pns') ++ "; do"+                    , "echo \"constraints: $pkg installed\" >> cabal.project"+                    , ">> cabal.project.local; done"+                    ]+                ]+              where+                pns' = S.map unPackageName pns `S.difference` foldMap (S.singleton . pkgName) pkgs++            -- otherwise: nothing+            _ -> pure ()++        tellStrLns+            [ sh $ "cat cabal.project || true"+            , sh $ "cat cabal.project.local || true"+            ]++    projectFile :: FilePath+    projectFile = fromMaybe "cabal.project" isCabalProject++    quotedPaths :: (Package -> FilePath) -> [String]+    quotedPaths f = map (f . quote) pkgs+      where+        quote pkg = pkg{ pkgDir = "\"" ++ pkgDir pkg ++ "\"" }++    showVersions :: Set (Maybe Version) -> String+    showVersions = unwords . map dispGhcVersion . S.toList++    -- specified ersions+    osxVersions' :: Set Version+    osxVersions' = cfgOsx config++    versions :: Set (Maybe Version)+    versions+        | cfgGhcHead config = S.insert Nothing $ S.map Just versions'+        | otherwise         = S.map Just versions'++    ghcVersions :: String+    ghcVersions = showVersions versions++    osxVersions, omittedOsxVersions :: Set Version+    (osxVersions, omittedOsxVersions) = S.partition (`S.member` versions') osxVersions'++    ghcOsxVersions :: String+    ghcOsxVersions = showVersions $ S.map Just osxVersions++    ghcOmittedOsxVersions :: String+    ghcOmittedOsxVersions = showVersions $ S.map Just omittedOsxVersions+++collToGhcVer :: String -> Version+collToGhcVer cid = case simpleParse cid of+  Nothing -> error ("invalid collection-id syntax " ++ show cid)+  Just (PackageIdentifier n (versionNumbers -> v))+    | display n /= "lts" -> error ("unknown collection " ++ show cid)+    | isPrefixOf [0] v -> mkVersion [7,8,3]+    | isPrefixOf [1] v -> mkVersion [7,8,4]+    | isPrefixOf [2] v -> mkVersion [7,8,4]+    | isPrefixOf [3] v -> mkVersion [7,10,2]+    | isPrefixOf [4] v -> mkVersion [7,10,3]+    | isPrefixOf [5] v -> mkVersion [7,10,3]+    | isPrefixOf [6] v -> mkVersion [7,10,3]+    | isPrefixOf [7] v -> mkVersion [8,0,1]+    | otherwise -> error ("unknown collection " ++ show cid)++-------------------------------------------------------------------------------+-- Doctest+-------------------------------------------------------------------------------++doctestJobVersionRange :: VersionRange+doctestJobVersionRange = orLaterVersion $ mkVersion [8,0]++-- | Modules arguments to the library+--+-- * We check the library component+--+-- * If there are hs-source-dirs, use them+--+-- * otherwise use exposed + other modules+--+-- * Also add default-extensions+--+-- /Note:/ same argument work for hlint too, but not exactly+--+doctestArgs :: GenericPackageDescription -> [[String]]+doctestArgs gpd =+    [ libraryModuleArgs c+    | c <- flattenPackageDescription gpd ^.. L.library . traverse+    ] +++    [ libraryModuleArgs c+    | c <- flattenPackageDescription gpd ^.. L.subLibraries . traverse+    ]++libraryModuleArgs :: PD.Library -> [String]+libraryModuleArgs l+    | null dirsOrMods = []+    | otherwise       = exts ++ dirsOrMods+  where+    bi = l ^. L.buildInfo++    dirsOrMods+        | null (PD.hsSourceDirs bi) = map display (PD.exposedModules l)+        | otherwise                 = PD.hsSourceDirs bi++    exts = map (("-X" ++) . display) (PD.defaultExtensions bi)++executableModuleArgs :: PD.Executable -> [String]+executableModuleArgs e+    | null dirsOrMods = []+    | otherwise       = exts ++ dirsOrMods+  where+    bi = e ^. L.buildInfo++    dirsOrMods+        -- note: we don't try to find main_is location, if hsSourceDirs is empty.+        | null (PD.hsSourceDirs bi) = map display (PD.otherModules bi)+        | otherwise                 = PD.hsSourceDirs bi++    exts = map (("-X" ++) . display) (PD.defaultExtensions bi)++-------------------------------------------------------------------------------+-- HLint+-------------------------------------------------------------------------------++hlintJobVersionRange :: Set (Maybe Version) -> HLintJob -> VersionRange+hlintJobVersionRange vs HLintJobLatest = case S.maxView vs of+    Just (Just v, _) -> thisVersion v+    _                -> thisVersion $ mkVersion [8,6,3]+hlintJobVersionRange _ (HLintJob v)   = thisVersion v++hlintArgs :: GenericPackageDescription -> [[String]]+hlintArgs gpd =+    [ libraryModuleArgs c+    | c <- flattenPackageDescription gpd ^.. L.library . traverse+    ] +++    [ libraryModuleArgs c+    | c <- flattenPackageDescription gpd ^.. L.subLibraries . traverse+    ] +++    [ executableModuleArgs c+    | c <- flattenPackageDescription gpd ^.. L.executables . traverse+    ]
+ src/HaskellCI/Cli.hs view
@@ -0,0 +1,91 @@+-- | Most of client interface.+module HaskellCI.Cli where++import           Prelude                  ()+import           Prelude.Compat++import           Control.Applicative      ((<|>))+import           System.Exit              (exitFailure)+import           System.IO                (hPutStrLn, stderr)++import qualified Options.Applicative      as O++import           HaskellCI.Config+import           HaskellCI.OptparseGrammar++-------------------------------------------------------------------------------+-- Command+-------------------------------------------------------------------------------++data Command+    = CommandTravis FilePath+    | CommandRegenerate+    | CommandListGHC+    | CommandDumpConfig+  deriving Show++-------------------------------------------------------------------------------+-- Options+-------------------------------------------------------------------------------++data Options = Options+    { optCollections    :: [String]+    , optOutput         :: Maybe FilePath+    , optConfig         :: Maybe FilePath+    , optConfigMorphism :: Config -> Config+    }++instance Semigroup Options where+    Options a b d e <> Options a' b' d' e' =+        Options (a <> a') (b <|> b') (d <|> d') (e' . e)++defaultOptions :: Options+defaultOptions = Options+    { optCollections    = []+    , optOutput         = Nothing+    , optConfig         = Nothing+    , optConfigMorphism = id+    }++-------------------------------------------------------------------------------+-- Parsers+-------------------------------------------------------------------------------++optionsP :: O.Parser Options+optionsP = Options+    <$> pure []+    <*> O.optional (O.strOption (O.long "output" <> O.short 'o' <> O.metavar "FILE" <> O.help "Optput file (stdout if omitted)"))+    <*> O.optional (O.strOption (O.long "config" <> O.metavar "CONFIGFILE" <> O.help "Configuration file"))+    <*> runOptparseGrammar configGrammar++cliParserInfo :: O.ParserInfo (Command, Options)+cliParserInfo = O.info ((,) <$> cmdP <*> optionsP O.<**> O.helper) $ mconcat+    [ O.fullDesc+    , O.header "haskell-ci - generate CI scripts for Haskell projects"+    ]+  where+    cmdP = O.subparser (mconcat+        [ O.command "regenerate"  $ O.info (pure CommandRegenerate) $ O.progDesc "Regenerate .travis.yml"+        , O.command "travis"      $ O.info travisP                  $ O.progDesc "Generate travis-ci config"+        , O.command "list-ghc"    $ O.info (pure CommandListGHC)    $ O.progDesc "List known GHC versions"+        , O.command "dump-config" $ O.info (pure CommandDumpConfig) $ O.progDesc "Dump cabal.haskell-ci config with default values" +        ]) <|> travisP++    travisP = CommandTravis+        <$> O.strArgument (O.metavar "CABAL.FILE" <> O.help "Either <pkg.cabal> or cabal.project")++-------------------------------------------------------------------------------+-- Parsing helpers+-------------------------------------------------------------------------------++parseTravis :: [String] -> IO (FilePath, Options)+parseTravis argv = case res of+    O.Success x -> return x+    O.Failure f -> case O.renderFailure f "haskell-ci" of+        (help, _) -> hPutStrLn stderr help >> exitFailure+    O.CompletionInvoked _ -> exitFailure -- unexpected+  where+    res = O.execParserPure (O.prefs mempty) (O.info ((,) <$> cmdP <*> optionsP) mempty) argv+    cmdP = O.strArgument (O.metavar "CABAL.FILE" <> O.help "Either <pkg.cabal> or cabal.project")++
+ src/HaskellCI/Config.hs view
@@ -0,0 +1,263 @@+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedLabels      #-}+{-# LANGUAGE OverloadedStrings     #-}+module HaskellCI.Config where++import           Control.Monad.IO.Class          (MonadIO (..))+import           Data.Coerce                     (coerce)+import           Data.Generics.Labels            ()+import           Distribution.Simple.Utils       (fromUTF8BS)+import           Distribution.Types.Version      (Version)+import           Distribution.Types.VersionRange (VersionRange, anyVersion,+                                                  noVersion)+import           GHC.Generics                    (Generic)+import           Lens.Micro                      (over)++import qualified Data.ByteString                 as BS+import qualified Data.Map                        as M+import qualified Data.Set                        as S+import qualified Distribution.CabalSpecVersion   as C+import qualified Distribution.Compat.CharParsing as C+import qualified Distribution.Compat.Newtype     as C+import qualified Distribution.FieldGrammar       as C+import qualified Distribution.Fields.Pretty      as C+import qualified Distribution.Parsec.Class       as C+import qualified Distribution.Parsec.Common      as C+import qualified Distribution.Parsec.Newtypes    as C+import qualified Distribution.Parsec.Parser      as C+import qualified Distribution.Parsec.ParseResult as C+import qualified Distribution.Pretty             as C+import qualified Distribution.Types.Version      as C+import qualified Text.PrettyPrint                as PP++import           HaskellCI.Config.ConstraintSet+import           HaskellCI.Config.CopyFields+import           HaskellCI.Config.Doctest+import           HaskellCI.Config.Folds+import           HaskellCI.Config.HLint+import           HaskellCI.Config.Installed+import           HaskellCI.Config.Jobs+import           HaskellCI.Newtypes+import           HaskellCI.OptionsGrammar+import           HaskellCI.ParsecUtils+import           HaskellCI.TestedWith++-- TODO: split other blocks like DoctestConfig+data Config = Config+    { cfgCabalInstallVersion :: Maybe Version+    , cfgJobs                :: Maybe Jobs+    , cfgTestedWith          :: !TestedWithJobs+    , cfgCopyFields          :: !CopyFields+    , cfgLocalGhcOptions     :: [String]+    , cfgCache               :: !Bool+    , cfgNoise               :: !Bool+    , cfgInstallDeps         :: !Bool+    , cfgInstalled           :: [Installed]+    , cfgTests               :: !VersionRange+    , cfgBenchmarks          :: !VersionRange+    , cfgHaddock             :: !VersionRange+    , cfgNoTestsNoBench      :: !VersionRange+    , cfgUnconstrainted      :: !VersionRange+    , cfgCheck               :: !Bool+    , cfgOnlyBranches        :: [String]+    , cfgIrcChannels         :: [String]+    , cfgProjectName         :: Maybe String+    , cfgFolds               :: S.Set Fold+    , cfgGhcHead             :: !Bool+    , cfgPostgres            :: !Bool+    , cfgEnv                 :: M.Map Version String+    , cfgAllowFailures       :: !VersionRange+    , cfgLastInSeries        :: !Bool+    , cfgOsx                 :: S.Set Version+    , cfgApt                 :: S.Set String+    , cfgDoctest             :: !DoctestConfig+    , cfgHLint               :: !HLintConfig+    , cfgConstraintSets      :: [ConstraintSet]+    , cfgRawProject          :: [C.PrettyField]+    }+  deriving (Show, Generic)++defaultCabalInstallVersion :: Maybe Version+defaultCabalInstallVersion = Just (C.mkVersion [2,4])++emptyConfig :: Config+emptyConfig = Config+    { cfgCabalInstallVersion = defaultCabalInstallVersion+    , cfgJobs            = Nothing+    , cfgTestedWith      = TestedWithUniform+    , cfgCopyFields      = CopyFieldsSome+    , cfgDoctest         = DoctestConfig+        { cfgDoctestEnabled = False+        , cfgDoctestOptions = []+        , cfgDoctestVersion = defaultDoctestVersion+        }+    , cfgHLint = HLintConfig+        { cfgHLintEnabled = False+        , cfgHLintJob     = HLintJobLatest+        , cfgHLintYaml    = Nothing+        , cfgHLintVersion = defaultHLintVersion+        , cfgHLintOptions = []+        }+    , cfgLocalGhcOptions = []+    , cfgConstraintSets  = []+    , cfgCache           = True+    , cfgNoise           = True+    , cfgInstalled       = []+    , cfgInstallDeps     = True+    , cfgTests           = anyVersion+    , cfgBenchmarks      = anyVersion+    , cfgHaddock         = anyVersion+    , cfgNoTestsNoBench  = anyVersion+    , cfgUnconstrainted  = anyVersion+    , cfgCheck           = True+    , cfgOnlyBranches    = []+    , cfgIrcChannels     = []+    , cfgProjectName     = Nothing+    , cfgFolds           = S.empty+    , cfgGhcHead         = False+    , cfgPostgres        = False+    , cfgEnv             = M.empty+    , cfgAllowFailures   = noVersion+    , cfgLastInSeries    = False+    , cfgOsx             = S.empty+    , cfgApt             = S.empty+    , cfgRawProject      = []+    }++-------------------------------------------------------------------------------+-- Grammar+-------------------------------------------------------------------------------++configGrammar+    :: (OptionsGrammar g, Applicative (g Config), Applicative (g DoctestConfig), Applicative (g HLintConfig))+    => g Config Config+configGrammar = Config+    <$> C.optionalFieldDefAla "cabal-install-version"     HeadVersion                         #cfgCabalInstallVersion defaultCabalInstallVersion+        ^^^ metahelp "VERSION" "cabal-install version for all jobs"+    <*> C.optionalField       "jobs"                                                          #cfgJobs+        ^^^ metahelp "JOBS" "jobs (N:M - cabal:ghc)"+    <*> C.optionalFieldDef    "jobs-selection"                                                #cfgTestedWith TestedWithUniform+        ^^^ metahelp "uniform|any" "Jobs selection across packages"+    <*> C.optionalFieldDef    "copy-fields"                                                   #cfgCopyFields CopyFieldsSome+        ^^^ metahelp "none|some|all" "Copy ? fields from cabal.project fields"+    <*> C.monoidalFieldAla    "local-ghc-options"         (C.alaList' C.NoCommaFSep C.Token') #cfgLocalGhcOptions+        ^^^ metahelp "OPTS" "--ghc-options for local packages"+    <*> C.booleanFieldDef     "cache"                                                         #cfgCache True+        ^^^ help "Disable caching"+    <*> C.booleanFieldDef     "cabal-noise"                                                   #cfgNoise True+        ^^^ help "Make cabal less noisy"+    <*> C.booleanFieldDef     "install-dependencies"                                          #cfgInstallDeps True+        ^^^ help "Skip separate dependency installation step"+    <*> C.monoidalFieldAla    "installed"                 (C.alaList C.FSep)                  #cfgInstalled+        ^^^ metahelp "+/-PKG" "Specify 'constraint: ... installed' packages"+    <*> rangeField            "tests"                                                         #cfgTests anyVersion+        ^^^ metahelp "RANGE" "Build and run tests with"+    <*> rangeField           "benchmarks"                                                     #cfgBenchmarks anyVersion+        ^^^ metahelp "RANGE" "Build benchmarks"+    <*> rangeField           "haddock"                                                        #cfgHaddock anyVersion+        ^^^ metahelp "RANGE" "Haddock step"+    <*> rangeField           "no-tests-no-benchmarks"                                         #cfgNoTestsNoBench anyVersion+        ^^^ metahelp "RANGE" "Build without tests and benchmarks"+    <*> rangeField            "unconstrained"                                                 #cfgUnconstrainted anyVersion+        ^^^ metahelp "RANGE" "Make unconstrained build"+    <*> C.booleanFieldDef "cabal-check"                                                       #cfgCheck True+        ^^^ help "Disable cabal check run"+    <*> C.monoidalFieldAla    "branches"                  (C.alaList' C.FSep C.Token')        #cfgOnlyBranches+        ^^^ metahelp "BRANCH" "Enable builds only for specific branches"+    <*> C.monoidalFieldAla    "irc-channels"              (C.alaList' C.FSep C.Token')        #cfgIrcChannels+        ^^^ metahelp "IRC" "Enable IRC notifications to given channel (e.g. 'irc.freenode.org#haskell-lens')"+    <*> C.optionalFieldAla    "project-name"              C.Token'                            #cfgProjectName+        ^^^ metahelp "NAME" "Project name (used for IRC notifications), defaults to package name or name of first package listed in cabal.project file"+    <*> C.monoidalFieldAla    "folds"                     Folds                               #cfgFolds+        ^^^ metahelp "FOLD" "Build steps to fold"+    <*> C.booleanFieldDef     "ghc-head"                                                      #cfgGhcHead False+        ^^^ help "Add ghc-head job"+    <*> C.booleanFieldDef     "postgresql"                                                    #cfgPostgres False+        ^^^ help "Add postgresql service"+    <*> C.monoidalFieldAla    "env"                       Env                                 #cfgEnv+        ^^^ metahelp "ENV" "Environment variables per job (e.g. `8.0.2:HADDOCK=false`)"+    <*> C.optionalFieldDefAla "allow-failures"            Range                               #cfgAllowFailures noVersion+        ^^^ metahelp "JOB" "Allow failures of particular GHC version"+    <*> C.booleanFieldDef     "last-in-series"                                                #cfgLastInSeries False+        ^^^ help "[Discouraged] Assume there are only GHCs last in major series: 8.2.* will match only 8.2.2"+    <*> C.monoidalFieldAla    "osx"                       (alaSet C.NoCommaFSep)              #cfgOsx+        ^^^ metahelp "JOB" "Jobs to additionally build with OSX"+    <*> C.monoidalFieldAla    "apt"                       (alaSet' C.NoCommaFSep C.Token')    #cfgApt+        ^^^ metahelp "PKG" "Additional apt packages to install"+    <*> C.blurFieldGrammar #cfgDoctest doctestConfigGrammar+    <*> C.blurFieldGrammar #cfgHLint   hlintConfigGrammar+    <*> pure [] -- constraint sets+    <*> pure [] -- raw project fields++-------------------------------------------------------------------------------+-- Reading+-------------------------------------------------------------------------------++readConfigFile :: MonadIO m => FilePath -> m Config+readConfigFile = liftIO . readAndParseFile parseConfigFile++parseConfigFile :: [C.Field C.Position] -> C.ParseResult Config+parseConfigFile fields0 = do+    config <- C.parseFieldGrammar C.cabalSpecLatest fields configGrammar+    config' <- traverse parseSection $ concat sections+    return (foldr (.) id config' config)+  where+    (fields, sections) = C.partitionFields fields0++    parseSection :: C.Section C.Position -> C.ParseResult (Config -> Config)+    parseSection (C.MkSection (C.Name pos name) args cfields)+        | name == "constraint-set" = do+            name' <- parseName pos args+            let (fs, _sections) = C.partitionFields cfields+            cs <- C.parseFieldGrammar C.cabalSpecLatest fs (constraintSetGrammar name')+            return $ over #cfgConstraintSets (cs :)+        | name == "raw-project" = do+            let fs = C.fromParsecFields cfields+            return $ over #cfgRawProject (++ fs)+        | otherwise = do+            C.parseWarning pos C.PWTUnknownSection $ "Unknown section " ++ fromUTF8BS name+            return id++-------------------------------------------------------------------------------+-- Env+-------------------------------------------------------------------------------++newtype Env = Env (M.Map Version String)++instance C.Newtype Env (M.Map Version String) where+    pack = coerce+    unpack = coerce++instance C.Parsec Env where+    parsec = Env . M.fromList <$> C.parsecLeadingCommaList p where+        p = do+            v <- C.parsec+            _ <- C.char ':'+            s <- C.munch1 $ \c -> c /= ','+            return (v, s)++instance C.Pretty Env where+    pretty (Env m) = PP.fsep . PP.punctuate PP.comma . map p . M.toList $ m where+        p (v, s) = C.pretty v PP.<> PP.colon PP.<> PP.text s++-------------------------------------------------------------------------------+-- From Cabal+-------------------------------------------------------------------------------++parseName :: C.Position -> [C.SectionArg C.Position] -> C.ParseResult String+parseName pos args = fromUTF8BS <$> parseNameBS pos args++parseNameBS :: C.Position -> [C.SectionArg C.Position] -> C.ParseResult BS.ByteString+parseNameBS pos args = case args of+    [C.SecArgName _pos secName] ->+         pure secName+    [C.SecArgStr _pos secName] ->+         pure secName+    [] -> do+         C.parseFailure pos "name required"+         pure ""+    _ -> do+         -- TODO: pretty print args+         C.parseFailure pos $ "Invalid name " ++ show args+         pure ""
+ src/HaskellCI/Config/ConstraintSet.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE OverloadedLabels  #-}+{-# LANGUAGE OverloadedStrings #-}+module HaskellCI.Config.ConstraintSet where++import           Data.Generics.Labels         ()+import           Distribution.Version+import           GHC.Generics                 (Generic)++import qualified Distribution.FieldGrammar    as C+import qualified Distribution.Parsec.Newtypes as C++import           HaskellCI.Newtypes++data ConstraintSet = ConstraintSet+    { csName        :: String+    , csGhcVersions :: VersionRange+    , csConstraints :: [String] -- we parse these simply as strings+    , csRunTests    :: Bool+    }+  deriving (Show, Generic)++emptyConstraintSet :: String -> ConstraintSet+emptyConstraintSet n = ConstraintSet n anyVersion [] False++-------------------------------------------------------------------------------+-- Grammar+-------------------------------------------------------------------------------++constraintSetGrammar+    :: (C.FieldGrammar g, Applicative (g ConstraintSet))+    => String -> g ConstraintSet ConstraintSet+constraintSetGrammar name = ConstraintSet name+    <$> C.optionalFieldDef "ghc"                                           #csGhcVersions anyVersion+    <*> C.monoidalFieldAla "constraints" (C.alaList' C.CommaVCat NoCommas) #csConstraints+    <*> C.booleanFieldDef  "run-tests"                                     #csRunTests False
+ src/HaskellCI/Config/CopyFields.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}+module HaskellCI.Config.CopyFields where++import qualified Distribution.Compat.CharParsing as C+import qualified Distribution.Parsec.Class       as C+import qualified Distribution.Pretty             as C+import qualified Text.PrettyPrint                as PP++data CopyFields+    = CopyFieldsNone+    | CopyFieldsSome+    | CopyFieldsAll+  deriving (Eq, Ord, Show, Enum, Bounded)++-------------------------------------------------------------------------------+-- Functions+-------------------------------------------------------------------------------++showCopyFields :: CopyFields -> String+showCopyFields CopyFieldsNone = "none"+showCopyFields CopyFieldsSome = "some"+showCopyFields CopyFieldsAll  = "all"++instance C.Pretty CopyFields where+    pretty = PP.text . showCopyFields++instance C.Parsec CopyFields where+    parsec = C.choice+        [ f <$ C.string (showCopyFields f)+        | f <- [ minBound .. maxBound ]+        ]
+ src/HaskellCI/Config/Doctest.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE OverloadedLabels  #-}+{-# LANGUAGE OverloadedStrings #-}+module HaskellCI.Config.Doctest where++import           Data.Generics.Labels         ()+import           Distribution.Version+import           GHC.Generics                 (Generic)++import qualified Distribution.FieldGrammar    as C+import qualified Distribution.Parsec.Newtypes as C++import HaskellCI.OptionsGrammar++data DoctestConfig = DoctestConfig+    { cfgDoctestEnabled :: !Bool+    , cfgDoctestOptions :: [String]+    , cfgDoctestVersion :: !VersionRange+    }+  deriving (Show, Generic)++defaultDoctestVersion :: VersionRange+defaultDoctestVersion = withinVersion (mkVersion [0,16])++-------------------------------------------------------------------------------+-- Grammar+-------------------------------------------------------------------------------++doctestConfigGrammar+    :: (OptionsGrammar g, Applicative (g DoctestConfig))+    => g DoctestConfig DoctestConfig+doctestConfigGrammar = DoctestConfig+    <$> C.booleanFieldDef  "doctest"                                             #cfgDoctestEnabled False+        ^^^ help "Enable Doctest job"+    <*> C.monoidalFieldAla "doctest-options" (C.alaList' C.NoCommaFSep C.Token') #cfgDoctestOptions+        ^^^ metahelp "OPTS" "Additional Doctest options"+    <*> C.optionalFieldDef "doctest-version"                                     #cfgDoctestVersion defaultDoctestVersion+        ^^^ metahelp "RANGE" "Doctest version"
+ src/HaskellCI/Config/Dump.hs view
@@ -0,0 +1,58 @@+module HaskellCI.Config.Dump where++import           Prelude                     ()+import           Prelude.Compat++import           Data.Coerce                 (coerce)+import           Distribution.Simple.Utils   (fromUTF8BS)++import qualified Distribution.Compat.Newtype as C+import qualified Distribution.FieldGrammar   as C+import qualified Distribution.Pretty         as C++import           HaskellCI.OptionsGrammar++-- TODO: with Cabal-2.6 this can be prettier, using Pretty.Field+newtype DumpGrammar s a = DG { runDG :: [String] }+  deriving Functor++instance Applicative (DumpGrammar s) where+    pure _ = DG []+    DG f <*> DG x = DG (f ++ x)++instance C.FieldGrammar DumpGrammar where+    blurFieldGrammar _ = coerce++    uniqueFieldAla _ _ _ = DG []++    booleanFieldDef fn _ def = DG+        [ fromUTF8BS fn ++ ": " ++ C.prettyShow def+        , ""+        ]++    optionalFieldAla fn _ _ = DG+        [ fromUTF8BS fn ++ ":"+        , ""+        ]++    optionalFieldDefAla fn c _ def = DG+        [ fromUTF8BS fn ++ ": " ++ C.prettyShow (C.pack' c def)+        , ""+        ]++    monoidalFieldAla fn _ _ = DG+        [ fromUTF8BS fn ++ ":"+        , ""+        ]++    prefixedFields _ _   = pure []+    knownField _         = pure ()+    deprecatedSince _  _ = id+    availableSince _ _   = id+    hiddenField          = id++instance OptionsGrammar DumpGrammar where+    metahelp _ = help++    help h (DG xs) = DG $+        ("-- " ++ h) : xs
+ src/HaskellCI/Config/Folds.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}+module HaskellCI.Config.Folds where++import           Data.Char                       (isUpper, toLower)+import           Data.Coerce                     (coerce)+import           Data.List                       (intercalate)++import qualified Data.Map.Strict                 as M+import qualified Data.Set                        as S+import qualified Distribution.Compat.CharParsing as C+import qualified Distribution.Compat.Newtype     as C+import qualified Distribution.Parsec.Class       as C+import qualified Distribution.Pretty             as C+import qualified Text.PrettyPrint                as PP++data Fold+    = FoldSDist+    | FoldUnpack+    | FoldBuild+    | FoldBuildInstalled+    | FoldBuildEverything+    | FoldTest+    | FoldHaddock+    | FoldStackage+    | FoldCheck+    | FoldDoctest+    | FoldHLint+    | FoldConstraintSets+  deriving (Eq, Ord, Show, Enum, Bounded)++-------------------------------------------------------------------------------+-- Functions+-------------------------------------------------------------------------------++showFold :: Fold -> String+showFold = dashise . drop 4 . show+  where+    dashise = intercalate "-" . map (map toLower) . split++    split [] = []+    split xs0 =+        let (ys, xs1) = span isUpper xs0+            (zs, xs2) = break isUpper xs1+        in (ys ++ zs) : split xs2++possibleFolds :: [Fold]+possibleFolds = [minBound .. maxBound]++-------------------------------------------------------------------------------+-- Folds+-------------------------------------------------------------------------------++newtype Folds = Folds { getFolds :: S.Set Fold }++instance C.Newtype Folds (S.Set Fold) where+    pack = coerce+    unpack = coerce++instance C.Parsec Folds where+    parsec = fmap (Folds . S.unions) $ manySpaces $ do+        t <- C.parsecToken'+        case t of+            "all"          -> return $ S.fromList possibleFolds+            "all-but-test" -> return $  S.delete FoldTest $ S.fromList possibleFolds+            n -> case M.lookup n ps of+                Just n' -> return $ S.singleton n'+                Nothing -> fail $ "Illegal fold name: " ++ n+      where+        ps = M.fromList $ map (\x -> (showFold x, x)) possibleFolds+        manySpaces p = C.many (p <* C.spaces)++instance C.Pretty Folds where+    pretty = PP.fsep . map (PP.text . showFold) . S.toList . getFolds
+ src/HaskellCI/Config/HLint.hs view
@@ -0,0 +1,65 @@+{-# LANGUAGE OverloadedLabels  #-}+{-# LANGUAGE OverloadedStrings #-}+module HaskellCI.Config.HLint where++import           Control.Applicative             ((<|>))+import           Data.Generics.Labels            ()+import           Distribution.Version+import           GHC.Generics                    (Generic)++import qualified Distribution.Compat.CharParsing as C+import qualified Distribution.FieldGrammar       as C+import qualified Distribution.Parsec.Class       as C+import qualified Distribution.Parsec.Newtypes    as C+import qualified Distribution.Pretty             as C+import qualified Text.PrettyPrint                as PP++import HaskellCI.OptionsGrammar++data HLintConfig = HLintConfig+    { cfgHLintEnabled :: !Bool+    , cfgHLintJob     :: !HLintJob+    , cfgHLintYaml    :: !(Maybe FilePath)+    , cfgHLintOptions :: [String]+    , cfgHLintVersion :: !VersionRange+    }+  deriving (Show, Generic)++defaultHLintVersion :: VersionRange+defaultHLintVersion = withinVersion (mkVersion [2,1])++-------------------------------------------------------------------------------+-- HLintJob+-------------------------------------------------------------------------------++data HLintJob+    = HLintJobLatest    -- ^ run with latest GHC+    | HLintJob Version  -- ^ run with specified GHC version+  deriving (Eq, Show)++instance C.Parsec HLintJob where+    parsec = HLintJobLatest <$ C.string "latest"+        <|> HLintJob <$> C.parsec++instance C.Pretty HLintJob where+    pretty HLintJobLatest = PP.text "latest"+    pretty (HLintJob v)   = C.pretty v++-------------------------------------------------------------------------------+-- Grammar+-------------------------------------------------------------------------------++hlintConfigGrammar+    :: (OptionsGrammar g, Applicative (g HLintConfig))+    => g HLintConfig HLintConfig+hlintConfigGrammar = HLintConfig+    <$> C.booleanFieldDef  "hlint"                                             #cfgHLintEnabled False+        ^^^ help "Enable HLint job"+    <*> C.optionalFieldDef "hlint-job"                                         #cfgHLintJob HLintJobLatest+        ^^^ metahelp "JOB" "Specify HLint job"+    <*> C.optionalFieldAla "hlint-yaml"    C.FilePathNT                        #cfgHLintYaml+        ^^^ metahelp "PATH" "Use specific .hlint.yaml"+    <*> C.monoidalFieldAla "hlint-options" (C.alaList' C.NoCommaFSep C.Token') #cfgHLintOptions+        ^^^ metahelp "OPTS" "Additional HLint options"+    <*> C.optionalFieldDef "hlint-version"                                     #cfgHLintVersion defaultHLintVersion+        ^^^ metahelp "RANGE" "HLint version"
+ src/HaskellCI/Config/Installed.hs view
@@ -0,0 +1,71 @@+module HaskellCI.Config.Installed where++import Control.Applicative ((<|>))+import Data.List (foldl')++import qualified Distribution.Types.PackageName as C+import qualified Distribution.Compat.CharParsing as C+import qualified Distribution.Parsec.Class       as C+import qualified Distribution.Pretty             as C+import qualified Text.PrettyPrint                as PP+import qualified Data.Set as S++-------------------------------------------------------------------------------+-- Single action+-------------------------------------------------------------------------------++data Installed+    = InstalledAll+    | InstalledNone+    | Add C.PackageName+    | Remove C.PackageName+  deriving (Eq, Show)++instance C.Pretty Installed where+    pretty InstalledAll  = PP.text "+all"+    pretty InstalledNone = PP.text "-all"+    pretty (Add pn)      = PP.char '+' PP.<> C.pretty pn+    pretty (Remove pn)   = PP.char '-' PP.<> C.pretty pn++instance C.Parsec Installed where+    parsec = do+        s <- True <$ C.char '+' <|> False <$ C.char '-'+        pn <- C.parsec+        return $ case (s, pn == C.mkPackageName "all") of+            (True,  True)  -> InstalledAll+            (True,  False) -> Add pn+            (False, True)  -> InstalledNone+            (False, False) -> Remove pn++-------------------------------------------------------------------------------+-- Normalised+-------------------------------------------------------------------------------++data InstalledNormalised+    = InstalledDiff (S.Set C.PackageName)+    | InstalledOnly (S.Set C.PackageName)+  deriving Show++-- | Normalised+--+-- >>> parseI = maybe (error "foo") id . traverse C.simpleParsec+-- >>> normaliseInstalled $ parseI ["-Cabal"]+-- InstalledDiff (fromList [PackageName "Cabal"])+--+-- >>> normaliseInstalled $ parseI ["-all"]+-- InstalledOnly (fromList [])+--+-- >>> normaliseInstalled $ parseI ["-all", "+transformers"]+-- InstalledOnly (fromList [PackageName "transformers"])+--+normaliseInstalled :: [Installed] -> InstalledNormalised+normaliseInstalled = foldl' f (InstalledDiff S.empty) where+    f :: InstalledNormalised -> Installed -> InstalledNormalised+    f _ InstalledNone = InstalledOnly S.empty+    f _ InstalledAll  = InstalledDiff S.empty++    f (InstalledDiff s) (Remove p) = InstalledDiff (S.insert p s)+    f (InstalledDiff s) (Add p)    = InstalledDiff (S.delete p s)++    f (InstalledOnly s) (Remove p) = InstalledOnly (S.delete p s)+    f (InstalledOnly s) (Add p)    = InstalledOnly (S.insert p s)
+ src/HaskellCI/Config/Jobs.hs view
@@ -0,0 +1,56 @@+module HaskellCI.Config.Jobs where++import Control.Applicative ((<|>))++import qualified Distribution.Pretty             as C+import qualified Text.PrettyPrint                as PP+import qualified Distribution.Compat.CharParsing as C+import qualified Distribution.Parsec.Class       as C++-- | Jobs+--+-- * @N:M@ - @N@ ghcs (cabal -j), @M@ threads (ghc -j)+--+-- >>> let parseJobs = C.simpleParsec :: String -> Maybe Jobs+-- >>> parseJobs "2:2"+-- Just (BothJobs 2 2)+--+-- >>> parseJobs ":2"+-- Just (GhcJobs 2)+--+-- >>> parseJobs "2"+-- Just (CabalJobs 2)+--+-- >>> parseJobs "garbage"+-- Nothing+--+data Jobs+    = CabalJobs Int+    | GhcJobs Int+    | BothJobs Int Int+  deriving (Show)++cabalJobs :: Jobs -> Maybe Int+cabalJobs (CabalJobs n)  = Just n+cabalJobs (GhcJobs _)    = Nothing+cabalJobs (BothJobs n _) = Just n++ghcJobs :: Jobs -> Maybe Int+ghcJobs (CabalJobs _)  = Nothing+ghcJobs (GhcJobs m)    = Just m+ghcJobs (BothJobs _ m) = Just m++instance C.Parsec Jobs where+    parsec = ghc <|> rest where+        ghc  = C.char ':' *> (GhcJobs <$> C.integral)+        rest = do+            n <- C.integral+            m' <- C.optional (C.char ':' *> C.integral)+            return $ case m' of+                Nothing -> CabalJobs n+                Just m  -> BothJobs n m++instance C.Pretty Jobs where+    pretty (BothJobs n m) = PP.int n PP.<> PP.colon PP.<> PP.int m+    pretty (CabalJobs n)  = PP.int n+    pretty (GhcJobs m)    = PP.colon PP.<> PP.int m
+ src/HaskellCI/Extras.hs view
@@ -0,0 +1,34 @@+-- | Various extras, are this in @base@ ?+module HaskellCI.Extras where++import           Control.Applicative ((<|>))+import           Data.List           (isPrefixOf, tails)++-- $setup+-- >>> import Text.Read (readMaybe)++-- | Return the part after the first argument+--+-- >>> afterInfix "BAR" "FOOBAR XYZZY"+-- Just " XYZZY"+--+afterInfix :: Eq a => [a] -> [a] -> Maybe [a]+afterInfix needle haystack = findMaybe (afterPrefix needle) (tails haystack)++-- |+--+-- >>> afterPrefix "FOO" "FOOBAR"+-- Just "BAR"+--+afterPrefix :: Eq a => [a] -> [a] -> Maybe [a]+afterPrefix needle haystack+    | needle `isPrefixOf` haystack = Just (drop (length needle) haystack)+    | otherwise                    = Nothing++-- |+--+-- >>> findMaybe readMaybe ["foo", "1", "bar"] :: Maybe Int+-- Just 1+--+findMaybe :: (a -> Maybe b) -> [a] -> Maybe b+findMaybe f = foldr (\a b -> f a <|> b) Nothing
+ src/HaskellCI/GHC.hs view
@@ -0,0 +1,36 @@+-- | This module encodes what we know about GHC, including existing/supported versions.+module HaskellCI.GHC where++import           Distribution.Version (Version, mkVersion, versionNumbers)++import qualified Distribution.Pretty             as C++knownGhcVersions :: [Version]+knownGhcVersions = fmap mkVersion+    [ [7,0,1],  [7,0,2], [7,0,3], [7,0,4]+    , [7,2,1],  [7,2,2]+    , [7,4,1],  [7,4,2]+    , [7,6,1],  [7,6,2], [7,6,3]+    , [7,8,1],  [7,8,2], [7,8,3], [7,8,4]+    , [7,10,1], [7,10,2], [7,10,3]+    , [8,0,1],  [8,0,2]+    , [8,2,1],  [8,2,2]+    , [8,4,1],  [8,4,2], [8,4,3], [8,4,4]+    , [8,6,1],  [8,6,2], [8,6,3]+    ]++ghcAlpha :: Maybe Version+ghcAlpha = Nothing+-- ghcAlpha = Just (mkVersion [8,8,1])+--+dispGhcVersion :: Maybe Version -> String+dispGhcVersion = maybe "head" C.prettyShow++-- | Alphas, RCs and HEAD.+previewGHC :: Maybe Version -> Bool+previewGHC = maybe True $ \v -> Just v == ghcAlpha || odd (snd (ghcMajVer v))++ghcMajVer :: Version -> (Int,Int)+ghcMajVer v+    | x:y:_ <- versionNumbers v = (x,y)+    | otherwise = error $ "panic: ghcMajVer called with " ++ show v
+ src/HaskellCI/Glob.hs view
@@ -0,0 +1,153 @@+module HaskellCI.Glob where++import Control.Applicative as App ((<$>))+import Control.Monad (void, filterM, liftM2)+import Control.Monad.IO.Class+import Data.List (stripPrefix)+import Distribution.Compat.ReadP+import System.Directory (doesDirectoryExist, getDirectoryContents)+import System.FilePath.Posix ((</>))++-------------------------------------------------------------------------------+-- Glob+-------------------------------------------------------------------------------++{-++Globbing code and grammar judiciously stolen from cabal-install:++FilePathGlob    ::= FilePathRoot FilePathGlobRel+FilePathRoot    ::= {- empty -}        # relative to cabal.project+                  | "/"                # Unix root+                  | [a-zA-Z] ":" [/\\] # Windows root+                  | "~"                # home directory++FilePathGlobRel ::= Glob "/"  FilePathGlobRel # Unix directory+                  | Glob "\\" FilePathGlobRel # Windows directory+                  | Glob         # file+                  | {- empty -}  # trailing slash++Glob      ::= GlobPiece *+GlobPiece ::= "*"            # wildcard+            | [^*{},/\\] *   # literal string+            | "\\" [*{},]    # escaped reserved character+            | "{" Glob "," ... "," Glob "}" # union (match any of these)+-}++data FilePathGlob = FilePathGlob FilePathRoot FilePathGlobRel+  deriving (Eq, Show)++data FilePathGlobRel+   = GlobDir  Glob FilePathGlobRel+   | GlobFile Glob+   | GlobDirTrailing -- trailing dir, a glob ending in '/'+  deriving (Eq, Show)++-- | A single directory or file component of a globbed path+type Glob = [GlobPiece]++-- | A piece of a globbing pattern+data GlobPiece = WildCard+               | Literal String+               | Union [Glob]+  deriving (Eq, Show)++data FilePathRoot+   = FilePathRelative+   | FilePathRoot FilePath -- e.g. '/', 'c:\' or result of 'takeDrive'+   | FilePathHomeDir+  deriving (Eq, Show)++parseFilePathGlobRel :: ReadP r FilePathGlobRel+parseFilePathGlobRel =+      parseGlob >>= \globpieces ->+          asDir globpieces+      <++ asTDir globpieces+      <++ asFile globpieces+  where+    asDir  glob = do dirSep+                     GlobDir glob <$> parseFilePathGlobRel+    asTDir glob = do dirSep+                     return (GlobDir glob GlobDirTrailing)+    asFile glob = return (GlobFile glob)++    dirSep = void (char '/')+         +++ (do _ <- char '\\'+                 -- check this isn't an escape code+                 following <- look+                 case following of+                   (c:_) | isGlobEscapedChar c -> pfail+                   _                           -> return ())++parseGlob :: ReadP r Glob+parseGlob = many1 parsePiece+  where+    parsePiece = literal +++ wildcard +++ union'++    wildcard = char '*' >> return WildCard++    union' = between (char '{') (char '}') $+              fmap Union (sepBy1 parseGlob (char ','))++    literal = Literal `fmap` litchars1++    litchar = normal +++ escape++    normal  = satisfy (\c -> not (isGlobEscapedChar c)+                                && c /= '/' && c /= '\\')+    escape  = char '\\' >> satisfy isGlobEscapedChar++    litchars1 :: ReadP r [Char]+    litchars1 = liftM2 (:) litchar litchars++    litchars :: ReadP r [Char]+    litchars = litchars1 <++ return []++isGlobEscapedChar :: Char -> Bool+isGlobEscapedChar '*'  = True+isGlobEscapedChar '{'  = True+isGlobEscapedChar '}'  = True+isGlobEscapedChar ','  = True+isGlobEscapedChar _    = False++expandRelGlob :: MonadIO m => FilePath -> FilePathGlobRel -> m [FilePath]+expandRelGlob root glob0 = liftIO $ go glob0 ""+  where+    go (GlobFile glob) dir = do+      entries <- getDirectoryContents (root </> dir)+      let files = filter (matchGlob glob) entries+      return (map (dir </>) files)++    go (GlobDir glob globPath) dir = do+      entries <- getDirectoryContents (root </> dir)+      subdirs <- filterM (\subdir -> doesDirectoryExist+                                       (root </> dir </> subdir))+               $ filter (matchGlob glob) entries+      concat App.<$> mapM (\subdir -> go globPath (dir </> subdir)) subdirs++    go GlobDirTrailing dir = return [dir]++matchGlob :: Glob -> FilePath -> Bool+matchGlob = goStart+  where+    -- From the man page, glob(7):+    --   "If a filename starts with a '.', this character must be+    --    matched explicitly."++    go, goStart :: [GlobPiece] -> String -> Bool++    goStart (WildCard:_) ('.':_)  = False+    goStart (Union globs:rest) cs = any (\glob -> goStart (glob ++ rest) cs)+                                        globs+    goStart rest               cs = go rest cs++    go []                 ""    = True+    go (Literal lit:rest) cs+      | Just cs' <- stripPrefix lit cs+                                = go rest cs'+      | otherwise               = False+    go [WildCard]         ""    = True+    go (WildCard:rest)   (c:cs) = go rest (c:cs) || go (WildCard:rest) cs+    go (Union globs:rest)   cs  = any (\glob -> go (glob ++ rest) cs) globs+    go []                (_:_)  = False+    go (_:_)              ""    = False
+ src/HaskellCI/MakeTravisOutput.hs view
@@ -0,0 +1,212 @@+{-# LANGUAGE CPP               #-}+{-# LANGUAGE OverloadedStrings #-}+module HaskellCI.MakeTravisOutput where++import           Prelude                    ()+import           Prelude.Compat++import           Control.Monad              (mzero)+import           Control.Monad.Trans.Class  (lift)+import           Control.Monad.Trans.Maybe  (MaybeT)+import           Control.Monad.Trans.Writer (WriterT, tell)+import           Data.Functor.Identity      (Identity (..))+import           Data.Maybe                 (mapMaybe)+import           Data.Set                   (Set)+import           Data.String                (IsString (..))+import           Distribution.Version++#ifdef MIN_VERSION_ShellCheck+import           ShellCheck.Checker         (checkScript)+import qualified ShellCheck.Interface       as SC+#endif++import qualified Data.Set                   as S+import qualified Data.Text                  as T+import qualified Data.Text.Encoding         as TE+import qualified Data.YAML                  as YAML++import           HaskellCI.Config.Folds+import           HaskellCI.Version++-- |  Encode shell command to be YAML safe and (optionally) ShellCheck it.+sh :: String -> Row+sh = sh'+    [ 2034 -- VAR appears unused. Verify it or export it.+    , 2086 -- SC2086: Double quote to prevent globbing and word splitting.+    , 2002 -- SC2002: Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead.+    ]++shForJob :: Set Version -> VersionRange -> String -> Row+shForJob  versions vr cmd+    | all (`withinRange` vr) versions       = sh cmd+    | not $ any (`withinRange` vr) versions = RowSkip+    | otherwise                             = sh $ unwords+        [ "if"+        , ghcVersionPredicate vr+        , "; then"+        , cmd+        , "; fi"+        ]++-- | Like 'sh' but with explicit SC exclude codes.+sh' :: [Integer] -> String -> Row+#ifndef MIN_VERSION_ShellCheck+sh' _ cmd = rawRow (shImpl cmd)+#else+sh' excl cmd =+    if null (SC.crComments res)+    then rawRow $ shImpl cmd+    else RowErr $ unlines $+        ("ShellCheck! " ++ cmd) :+        [ "SC" ++ show (SC.cCode c) ++ ": " ++ SC.cMessage c+        | pc <- SC.crComments res+        , let c = SC.pcComment pc+        ]++  where+    res = runIdentity $ checkScript iface spec+    iface = SC.SystemInterface $ \n -> return $ Left $ "cannot read file: " ++ n+    spec  = SC.emptyCheckSpec { SC.csFilename = "stdin"+                              , SC.csScript = cmd+                              , SC.csExcludedWarnings = excl+                              , SC.csShellTypeOverride = Just SC.Sh+                              }+#endif++-- Non-ShellCheck version of sh'+shImpl :: String -> String+shImpl cmd+    | needsEncoding = "  - " ++ show cmd+    | otherwise     = "  - " ++ cmd+  where+    -- we try to decode optimisticly serialised "- cmd..."+    -- if it's ok, we use it :)+    -- otherwise escape with show+    cmdT  = T.pack cmd+    cmdBS = "- " <> TE.encodeUtf8 cmdT+    needsEncoding = case YAML.decodeStrict cmdBS of+        Right [[t]] | t == cmdT -> False+        _           -> True++comment :: String -> Row+comment c = rawRow $ "  # " ++ c++blank :: Row+blank = rawRow ""++rawRow :: String -> Row+rawRow = Row++type MakeTravisOutput = Result Diagnostic [String]++data Diagnostic+    = Info String+    | Warn String+    | Error String+  deriving (Eq, Show)++formatDiagnostics :: [Diagnostic] -> String+formatDiagnostics = unlines . map formatDiagnostic++formatDiagnostic :: Diagnostic -> String+formatDiagnostic (Error s) = "*ERROR* " ++ s+formatDiagnostic (Warn  s) = "*WARNING* " ++ s+formatDiagnostic (Info  s) = "*INFO* " ++ s++-- MaybeT is used to preserve the short-circuiting semantics of 'putStrLnErr'.+type YamlWriter m a = MaybeT (WriterT MakeTravisOutput m) a++putStrLnErr :: Monad m => String -> YamlWriter m a+putStrLnErr m = do+    lift . tell $ Failure [Error m]+    mzero++putStrLnErrs :: Monad m => [String] -> YamlWriter m ()+putStrLnErrs [] = return ()+putStrLnErrs ms = do+    lift (tell (Failure (map Error ms)))+    mzero++putStrLnWarn, putStrLnInfo :: Monad m => String -> YamlWriter m ()+putStrLnWarn m = lift . tell $ Success [Warn m] []+putStrLnInfo m = lift . tell $ Success [Info m] []++tellStrLn :: Monad m => String -> YamlWriter m ()+tellStrLn str = lift . tell $ success [str]++data Row+    = Row String+    | RowErr String+    | RowSkip++instance IsString Row where+    fromString = rawRow++tellStrLns :: Monad m => [Row] -> YamlWriter m ()+tellStrLns rows = case sequenceRows rows of+    Left err    -> lift $ tell $ Failure [Error err]+    Right rows' -> lift $ tell $ success rows'++tellStrLnsRaw :: Monad m => [String] -> YamlWriter m ()+tellStrLnsRaw rows = lift $ tell $ success rows++sequenceRows :: [Row] -> Either String [String]+sequenceRows = sequenceA . mapMaybe f where+    f (Row s)      = Just (Right s)+    f (RowErr err) = Just (Left err)+    f RowSkip      = Nothing++-------------------------------------------------------------------------------+-- Folded+-------------------------------------------------------------------------------++foldedTellStrLns+    :: Monad m+    => Fold+    -> String+    -> Set Fold+    -> YamlWriter m ()+    -> YamlWriter m ()+foldedTellStrLns label = foldedTellStrLns' label ""++foldedTellStrLns'+    :: Monad m+    => Fold+    -> String+    -> String+    -> Set Fold+    -> YamlWriter m ()+    -> YamlWriter m ()+foldedTellStrLns' label pfx prettyLabel labels output+    | label `S.notMember` labels = output+    | otherwise = tellStrLns prologue >> output >> tellStrLns epilogue+  where+    prologue = [ sh' [2039] $ concat+        [ "echo ", prettyLabel+        , " && echo -en 'travis_fold:start:", showFold' label, "\\\\r'"+        ]]+    epilogue = [ sh' [2039] $ "echo -en 'travis_fold:end:" ++ showFold' label ++ "\\\\r'" ]++    showFold' l = showFold l ++ if null pfx then "" else "-" ++ pfx++-------------------------------------------------------------------------------+-- Result+-------------------------------------------------------------------------------++data Result e a+    = Success [e] a+    | Failure [e]+    deriving (Eq, Show, Functor)++success :: a -> Result e a+success = Success []++instance Monoid a => Monoid (Result e a) where+    mempty = success mempty+    mappend = (<>)++instance Monoid a => Semigroup (Result e a) where+    Failure err1   <> Failure err2   = Failure $ err1 <> err2+    Failure err1   <> Success err2 _ = Failure $ err1 <> err2+    Success err1 _ <> Failure err2   = Failure $ err1 <> err2+    Success l1 o1  <> Success l2 o2  = Success (mappend l1 l2) (mappend o1 o2)
+ src/HaskellCI/Newtypes.hs view
@@ -0,0 +1,178 @@+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables   #-}+module HaskellCI.Newtypes where++import           Control.Applicative             (liftA2, (<|>))+import           Data.Char                       (isSpace)+import           Data.Coerce                     (coerce)+import           Data.Functor.Identity           (Identity (..))+import           Data.Proxy                      (Proxy (..))++import qualified Data.Set                        as S+import qualified Distribution.Compat.CharParsing as C+import qualified Distribution.Compat.Newtype     as C+import qualified Distribution.Parsec.Class       as C+import qualified Distribution.Parsec.Newtypes    as C+import qualified Distribution.Pretty             as C+import qualified Distribution.Types.Version      as C+import qualified Distribution.Types.VersionRange as C+import qualified Text.PrettyPrint                as PP++import           HaskellCI.Version++-------------------------------------------------------------------------------+-- PackageLocation+-------------------------------------------------------------------------------++newtype PackageLocation = PackageLocation String++instance C.Newtype PackageLocation [Char] where+    pack = coerce+    unpack = coerce++-- | This is a bit tricky since it has to cover globs which have embedded @,@+-- chars. But we don't just want to parse strictly as a glob since we want to+-- allow http urls which don't parse as globs, and possibly some+-- system-dependent file paths. So we parse fairly liberally as a token, but+-- we allow @,@ inside matched @{}@ braces.+instance C.Parsec PackageLocation where+    parsec = PackageLocation <$> outerTerm+      where+        outerTerm = ($ "") <$> outerChars++        outerChars, outerChar, innerChars, innerChar :: C.CabalParsing m => m ShowS+        outerChars = foldr (.) id <$> C.some outerChar+        innerChars = foldr (.) id <$> C.many innerChar++        outerChar = do+            c <- C.satisfy $ \c -> not (isSpace c || c == '}' || c == ',')+            kont c++        innerChar = do+            c <- C.satisfy $ \c -> not (isSpace c || c == '}')+            kont c++        kont :: C.CabalParsing m => Char -> m ShowS+        kont c = case c of+           '{' -> do+               cs <- innerChars+               c' <- C.char '}'+               return (showChar c . cs . showChar c')+           _   -> return $ showChar c+++instance C.Pretty PackageLocation where+    pretty (PackageLocation p) = PP.text p++-------------------------------------------------------------------------------+-- NoCommas: something which can be comma separated+-------------------------------------------------------------------------------++newtype NoCommas = NoCommas String++instance C.Newtype NoCommas [Char] where+    pack = coerce+    unpack = coerce++instance C.Parsec NoCommas where+    parsec = NoCommas <$> liftA2 (:) (C.satisfy (not . isSpace)) (C.munch (/= ','))++instance C.Pretty NoCommas where+    pretty (NoCommas p) = PP.text p++-------------------------------------------------------------------------------+-- Head version+-------------------------------------------------------------------------------++newtype HeadVersion = HeadVersion { getHeadVersion :: Maybe C.Version }++instance C.Newtype HeadVersion (Maybe C.Version) where+    pack = coerce+    unpack = coerce++instance C.Parsec HeadVersion where+    parsec = HeadVersion Nothing <$ C.string "head" <|>+        HeadVersion . Just <$> C.parsec++instance C.Pretty HeadVersion where+    pretty (HeadVersion Nothing)  = PP.text "head"+    pretty (HeadVersion (Just v)) = C.pretty v++-------------------------------------------------------------------------------+-- Newtype+-------------------------------------------------------------------------------++newtype Int' = Int' Int++instance C.Newtype Int' Int where+    pack = coerce+    unpack = coerce++instance C.Parsec Int' where+    parsec = Int' <$> C.integral++instance C.Pretty Int' where+    pretty (Int' i) = PP.int i++-------------------------------------------------------------------------------+-- Range+-------------------------------------------------------------------------------++newtype Range = Range C.VersionRange++instance C.Newtype Range C.VersionRange where+    pack = coerce+    unpack = coerce++instance C.Parsec Range where+    parsec = fmap Range $ C.parsec <|> fromBool <$> C.parsec where+        fromBool True  = C.anyVersion+        fromBool False = C.noVersion++instance C.Pretty Range where+    pretty (Range r)+        | equivVersionRanges r C.anyVersion = C.pretty True+        | equivVersionRanges r C.noVersion  = C.pretty False+        | otherwise                         = C.pretty r++-------------------------------------------------------------------------------+-- AlaSet+-------------------------------------------------------------------------------++newtype AlaSet sep b a = AlaSet { getAlaSet :: S.Set a }++alaSet :: sep -> S.Set a -> AlaSet sep (Identity a) a+alaSet _ = AlaSet++-- | More general version of 'alaSet'.+alaSet' :: sep -> (a -> b) -> S.Set a -> AlaSet sep b a+alaSet' _ _ = AlaSet++instance C.Newtype (AlaSet sep wrapper a) (S.Set a) where+    pack = AlaSet+    unpack = getAlaSet++instance (C.Newtype b a, Ord a, Sep sep, C.Parsec b) => C.Parsec (AlaSet sep b a) where+    parsec   = C.pack . S.fromList . map (C.unpack :: b -> a) <$> parseSep (Proxy :: Proxy sep) C.parsec++instance (C.Newtype b a, Sep sep, C.Pretty b) => C.Pretty (AlaSet sep b a) where+    pretty = prettySep (Proxy :: Proxy sep) . map (C.pretty . (C.pack :: a -> b)) . S.toList . C.unpack++-------------------------------------------------------------------------------+-- From Cabal+-------------------------------------------------------------------------------++class    Sep sep  where+    prettySep :: Proxy sep -> [PP.Doc] -> PP.Doc+    parseSep :: C.CabalParsing m => Proxy sep -> m a -> m [a]++instance Sep C.CommaVCat where+    prettySep  _ = PP.vcat . PP.punctuate PP.comma+    parseSep   _ = C.parsecLeadingCommaList+instance Sep C.CommaFSep where+    prettySep _ = PP.fsep . PP.punctuate PP.comma+    parseSep   _ = C.parsecLeadingCommaList+instance Sep C.NoCommaFSep where+    prettySep _   = PP.fsep+    parseSep  _ p = C.many (p <* C.spaces)
+ src/HaskellCI/Optimization.hs view
@@ -0,0 +1,27 @@+module HaskellCI.Optimization where++import Control.Applicative ((<|>))++import qualified Distribution.Compat.CharParsing as C+import qualified Distribution.Parsec.Class       as C+import qualified Distribution.Pretty             as C+import qualified Text.PrettyPrint                as PP++data Optimization+    = OptimizationOn+    | OptimizationOff+    | OptimizationLevel Int+  deriving (Eq, Show)++instance C.Parsec Optimization where+    parsec = boolean <|> numeric where+        boolean = ite OptimizationOn OptimizationOff <$> C.parsec+        numeric = OptimizationLevel <$> C.integral++        ite t _ True  = t+        ite _ f False = f+    +instance C.Pretty Optimization where+    pretty OptimizationOn        = C.pretty True+    pretty OptimizationOff       = C.pretty False+    pretty (OptimizationLevel l) = PP.int l
+ src/HaskellCI/OptionsGrammar.hs view
@@ -0,0 +1,24 @@+module HaskellCI.OptionsGrammar (+    OptionsGrammar (..),+    (C.^^^),+    )  where++import qualified Distribution.Compat.Lens        as C+import qualified Distribution.FieldGrammar       as C+import qualified Distribution.Parsec.Field       as C+import qualified Distribution.Types.VersionRange as C++import           HaskellCI.Newtypes++class C.FieldGrammar p => OptionsGrammar p where+    metahelp :: String -> String -> p s a -> p s a+    metahelp _ _ = id++    help :: String -> p s a -> p s a+    help _ = id++    -- we treat range fields specially in options+    rangeField :: C.FieldName -> C.ALens' s C.VersionRange -> C.VersionRange -> p s C.VersionRange+    rangeField fn = C.optionalFieldDefAla fn Range++instance OptionsGrammar C.ParsecFieldGrammar
+ src/HaskellCI/OptparseGrammar.hs view
@@ -0,0 +1,124 @@+{-# LANGUAGE GADTs             #-}+{-# LANGUAGE OverloadedStrings #-}+module HaskellCI.OptparseGrammar (+    OptparseGrammar,+    runOptparseGrammar,+    ) where++import           Prelude                     ()+import           Prelude.Compat++import           Control.Applicative         (many)+import           Data.Foldable               (asum)+import           Distribution.Simple.Utils   (fromUTF8BS)++import qualified Distribution.Compat.Lens    as C+import qualified Distribution.Compat.Newtype as C+import qualified Distribution.FieldGrammar   as C+import qualified Distribution.Parsec.Class   as C+import qualified Distribution.Parsec.Field   as C+import qualified Distribution.Pretty         as C+import qualified Distribution.Version        as C+import qualified Options.Applicative         as O++import           HaskellCI.OptionsGrammar+import           HaskellCI.Version++data SomeParser s where+    SP :: (Maybe String -> Maybe String -> O.Parser (s -> s)) -> SomeParser s++newtype OptparseGrammar s a = OG [SomeParser s]+  deriving Functor++runOptparseGrammar :: OptparseGrammar s a -> O.Parser (s -> s)+runOptparseGrammar (OG ps) = fmap (foldr (flip (.)) id) $ many $ asum+    [ p Nothing Nothing+    | SP p <- ps+    ]++instance Applicative (OptparseGrammar s) where+    pure _ = OG []+    OG f <*> OG x = OG (f ++ x)++instance C.FieldGrammar OptparseGrammar where+    blurFieldGrammar l (OG ps) = OG+        [ SP $ \v h -> fmap (l C.#%~) (p v h)+        | SP p <- ps+        ]++    -- we don't support unique fields atm+    uniqueFieldAla _ _ _ = OG []++    -- the non default flag has help entry+    booleanFieldDef fn l def = OG+        [ SP $ \_m h -> setOG l $ O.flag' True  $ flagMods fn (th h)+        , SP $ \_m h -> setOG l $ O.flag' False $ flagMods ("no-" <> fn) (fh h)+        ]+      where+        th h = if def then Nothing else h+        fh h = if def then h else Nothing++    optionalFieldAla fn c l = OG+        [ SP $ \m h -> setOptionalOG l $ O.option (C.unpack' c <$> readMParsec) $ optionMods fn m h ]++    optionalFieldDefAla fn c l def = OG+        [ SP $ \m h -> setOG l $ O.option (C.unpack' c <$> readMParsec) $ optionMods fn m (fmap hdef h) ]+      where+        hdef h = h ++ " (Default: " ++ C.prettyShow (C.pack' c def) ++ ")"++    monoidalFieldAla fn c l = OG+        [ SP $ \m h -> monoidOG l $ O.option (C.unpack' c <$> readMParsec) $ optionMods fn m h ]++    prefixedFields _ _   = pure []+    knownField _         = pure ()+    deprecatedSince _  _ = id+    availableSince _ _   = id+    hiddenField          = id++instance OptionsGrammar OptparseGrammar where+    help h (OG ps) = OG+        [ SP $ \m _h -> p m (Just h)+        | SP p <- ps+        ]++    metahelp m h (OG ps) = OG+        [ SP $ \_m _h -> p (Just m) (Just h)+        | SP p <- ps+        ]++    -- example: @rangeField tests #cfgTests anyVersion@, generates options:+    --+    -- --tests+    -- --no-tests+    -- --tests-jobs RANGE+    --+    -- where the --no-tests has help, because it's not default.+    --+    rangeField fn l def = OG+        [ SP $ \_m  h -> setOG l $ O.flag' C.anyVersion $ flagMods fn (th h)+        , SP $ \_m  h -> setOG l $ O.flag' C.noVersion  $ flagMods ("no-" <> fn) (fh h)+        , SP $ \_m _h -> setOG l $ O.option readMParsec $ O.long (fromUTF8BS $ fn <> "-jobs") <> O.metavar "RANGE"+        ]+      where+        th h = if equivVersionRanges def C.anyVersion then Nothing else h+        fh h = if equivVersionRanges def C.anyVersion then h else Nothing++optionMods :: (O.HasName mods, O.HasMetavar mods) => C.FieldName -> Maybe String -> Maybe String -> O.Mod mods a+optionMods fn mmetavar mhelp = flagMods fn mhelp+    <> maybe mempty O.metavar mmetavar++flagMods :: O.HasName mods => C.FieldName -> Maybe String -> O.Mod mods a+flagMods fn mhelp = O.long (fromUTF8BS fn)+    <> maybe mempty O.help mhelp++readMParsec :: C.Parsec a => O.ReadM a+readMParsec = O.eitherReader C.eitherParsec++setOG :: C.ALens' s a -> O.Parser a -> O.Parser (s -> s)+setOG l = fmap (l C.#~)++setOptionalOG :: C.ALens' s (Maybe a) -> O.Parser a -> O.Parser (s -> s)+setOptionalOG l = fmap $ \x -> l C.#~ Just x++monoidOG :: Monoid a => C.ALens' s a -> O.Parser a -> O.Parser (s -> s)+monoidOG l = fmap $ \x -> l C.#%~ \y -> mappend y x
+ src/HaskellCI/Package.hs view
@@ -0,0 +1,12 @@+module HaskellCI.Package where++import qualified Distribution.Types.GenericPackageDescription as C+import qualified Distribution.Types.VersionRange              as C++data Package = Pkg+    { pkgName :: String+    , pkgJobs :: C.VersionRange+    , pkgDir  :: FilePath+    , pkgGpd  :: C.GenericPackageDescription+    }+  deriving (Eq, Show)
+ src/HaskellCI/ParsecError.hs view
@@ -0,0 +1,108 @@+module HaskellCI.ParsecError (+    renderParseError,+    ) where++import           Prelude                    ()+import           Prelude.Compat++import           Distribution.Parsec.Common (PError (..), PWarning (..),+                                             Position (..), showPos, zeroPos)+import           Distribution.Simple.Utils  (fromUTF8BS)+import           System.FilePath            (normalise)++import qualified Data.ByteString            as BS+import qualified Data.ByteString.Char8      as BS8++-- | Render parse error highlighting the part of the input file.+renderParseError+    :: FilePath+    -> BS.ByteString+    -> [PError]+    -> [PWarning]+    -> String+renderParseError filepath contents errors warnings+    | null errors && null warnings = ""+    | null errors = unlines $+        ("Warnings encountered when parsing  file " <> filepath <> ":")+        : renderedWarnings+    | otherwise = unlines $+        [ "Errors encountered when parsing file " <> filepath <> ":"+        ]+        ++ renderedErrors+        ++ renderedWarnings+  where+    filepath' = normalise filepath++    -- lines of the input file. 'lines' is taken, so they are called rows+    -- contents, line number, whether it's empty line+    rows :: [(String, Int, Bool)]+    rows = zipWith f (BS8.lines contents) [1..] where+        f bs i = let s = fromUTF8BS bs in (s, i, isEmptyOrComment s)++    rowsZipper = listToZipper rows++    isEmptyOrComment :: String -> Bool+    isEmptyOrComment s = case dropWhile (== ' ') s of+        ""          -> True   -- empty+        ('-':'-':_) -> True   -- comment+        _           -> False++    renderedErrors   = concatMap renderError errors+    renderedWarnings = concatMap renderWarning warnings++    renderError :: PError -> [String]+    renderError (PError pos@(Position row col) msg)+        -- if position is 0:0, then it doesn't make sense to show input+        -- looks like, Parsec errors have line-feed in them+        | pos == zeroPos = msgs+        | otherwise      = msgs ++ formatInput row col+      where+        msgs = [ "", filepath' ++ ":" ++ showPos pos ++ ": error:", trimLF msg, "" ]++    renderWarning :: PWarning -> [String]+    renderWarning (PWarning _ pos@(Position row col) msg)+        | pos == zeroPos = msgs+        | otherwise      = msgs ++ formatInput row col+      where+        msgs = [ "", filepath' ++ ":" ++ showPos pos ++ ": warning:", trimLF msg, "" ]++    -- sometimes there are (especially trailing) newlines.+    trimLF :: String -> String+    trimLF = dropWhile (== '\n') . reverse . dropWhile (== '\n') . reverse++    -- format line: prepend the given line number+    formatInput :: Int -> Int -> [String]+    formatInput row col = case advance (row - 1) rowsZipper of+        Zipper xs ys -> before ++ after where+            before = case span (\(_, _, b) -> b) xs of+                (_, [])     -> []+                (zs, z : _) -> map formatInputLine $ z : reverse zs++            after  = case ys of+                []        -> []+                (z : _zs) ->+                    [ formatInputLine z                             -- error line+                    , "      | " ++ replicate (col - 1) ' ' ++ "^"  -- pointer: ^+                    ]+                    -- do we need rows after?+                    -- ++ map formatInputLine (take 1 zs)           -- one row after++    formatInputLine :: (String, Int, Bool) -> String+    formatInputLine (str, row, _) = leftPadShow row ++ " | " ++ str++    -- hopefully we don't need to work with over 99999 lines .cabal files+    -- at that point small glitches in error messages are hopefully fine.+    leftPadShow :: Int -> String+    leftPadShow n = let s = show n in replicate (5 - length s) ' ' ++ s++data Zipper a = Zipper [a] [a]++listToZipper :: [a] -> Zipper a+listToZipper = Zipper []++advance :: Int -> Zipper a -> Zipper a+advance n z@(Zipper xs ys)+    | n <= 0 = z+    | otherwise = case ys of+        []      -> z+        (y:ys') -> advance (n - 1) $ Zipper (y:xs) ys'
+ src/HaskellCI/ParsecUtils.hs view
@@ -0,0 +1,42 @@+module HaskellCI.ParsecUtils where++import           Control.Monad                   (unless)+import           System.Directory                (doesFileExist)+import           System.Exit                     (exitFailure)+import           System.IO                       (hPutStr, stderr)++import qualified Data.ByteString                 as BS+import qualified Distribution.Parsec.Common      as C+import qualified Distribution.Parsec.LexerMonad  as C+import qualified Distribution.Parsec.Parser      as C+import qualified Distribution.Parsec.ParseResult as C+import qualified Text.Parsec                     as P++import           HaskellCI.ParsecError++readAndParseFile+    :: ([C.Field C.Position] -> C.ParseResult a)  -- ^ File fields to final value parser+    -> FilePath                                   -- ^ File to read+    -> IO a+readAndParseFile parser fpath = do+    exists <- doesFileExist fpath+    unless exists $ do+        putStrLn $ "Error Parsing: file \"" ++ fpath ++ "\" doesn't exist. Cannot continue."+        exitFailure+    bs <- BS.readFile fpath+    run bs $ case C.readFields' bs of+        Right (fs, lexWarnings) -> do+            C.parseWarnings (C.toPWarnings lexWarnings)+            parser fs+        Left perr -> C.parseFatalFailure pos (show perr) where+            ppos = P.errorPos perr+            pos  = C.Position (P.sourceLine ppos) (P.sourceColumn ppos)+  where+    run :: BS.ByteString -> C.ParseResult a -> IO a+    run bs r = case C.runParseResult r of+        (ws, Right x)      -> do+            hPutStr stderr $ renderParseError fpath bs [] ws+            return x+        (ws, Left (_, es)) -> do+            hPutStr stderr $ renderParseError fpath bs es ws+            exitFailure
+ src/HaskellCI/Project.hs view
@@ -0,0 +1,91 @@+{-# LANGUAGE OverloadedLabels  #-}+{-# LANGUAGE OverloadedStrings #-}+-- | Handling of @cabal.project@ file+module HaskellCI.Project (+    Project (..),+    emptyProject,+    parseProjectFile,+    ) where++import           Data.ByteString                              (ByteString)+import           Data.Generics.Labels                         ()+import           GHC.Generics                                 (Generic)+import           Lens.Micro                                   (over)++import qualified Data.Map.Strict                              as M+import qualified Distribution.CabalSpecVersion                as C+import qualified Distribution.FieldGrammar                    as C+import qualified Distribution.PackageDescription.FieldGrammar as C+import qualified Distribution.Parsec.Common                   as C+import qualified Distribution.Parsec.Newtypes                 as C+import qualified Distribution.Parsec.Parser                   as C+import qualified Distribution.Parsec.ParseResult              as C+import qualified Distribution.Types.SourceRepo                as C+import qualified Distribution.Fields.Pretty as C++import           HaskellCI.Newtypes+import           HaskellCI.Optimization+import           HaskellCI.ParsecError++-- $setup+-- >>> :seti -XOverloadedStrings++data Project a = Project+    { prjPackages     :: [a]+    , prjConstraints  :: [String]+    , prjAllowNewer   :: [String]+    , prjReorderGoals :: Bool+    , prjMaxBackjumps :: Maybe Int+    , prjOptimization :: Optimization+    , prjSourceRepos  :: [C.SourceRepo]+    , prjOrigFields   :: [C.PrettyField]+    }+  deriving (Show, Functor, Foldable, Traversable, Generic)++emptyProject :: Project [a]+emptyProject = Project [] [] [] False Nothing OptimizationOn [] []++-- | Parse project file. Extracts only few fields.+--+-- >>> fmap prjPackages $ parseProjectFile "cabal.project" "packages: foo bar/*.cabal"+-- Right ["foo","bar/*.cabal"]+--+parseProjectFile :: FilePath -> ByteString -> Either String (Project String)+parseProjectFile fp bs = do+    fields0 <- either (Left . show) Right $ C.readFields bs+    let (fields1, sections) = C.partitionFields fields0+    let fields2 = M.filterWithKey (\k _ -> k `elem` knownFields) fields1+    case C.runParseResult $ parse fields0 fields2 sections of+        (_, Right x)       -> return x+        (ws, Left (_, es)) -> Left $ renderParseError fp bs es ws+  where+    knownFields = C.fieldGrammarKnownFieldList $ grammar []++    parse origFields fields sections = do+        let prettyOrigFields = C.fromParsecFields $ filter notPackages origFields+        prj <- C.parseFieldGrammar C.cabalSpecLatest fields $ grammar prettyOrigFields+        foldr ($) prj <$> traverse parseSec (concat sections)++    parseSec :: C.Section C.Position -> C.ParseResult (Project String -> Project String)+    parseSec (C.MkSection (C.Name _pos name) [] fields) | name == "source-repository-package" = do+        let fields' = fst $ C.partitionFields fields+        repo <- C.parseFieldGrammar C.cabalSpecLatest fields' (C.sourceRepoFieldGrammar $ C.RepoKindUnknown "unused")+        return $ over #prjSourceRepos (repo :)++    parseSec _ = return id++notPackages :: C.Field ann -> Bool+notPackages (C.Field (C.Name _ "packages") _) = False+notPackages _                                 = True+++grammar :: [C.PrettyField] -> C.ParsecFieldGrammar (Project String) (Project String)+grammar origFields = Project+    <$> C.monoidalFieldAla "packages"      (C.alaList' C.FSep PackageLocation) #prjPackages+    <*> C.monoidalFieldAla "constraints"   (C.alaList' C.CommaVCat NoCommas)   #prjConstraints+    <*> C.monoidalFieldAla "allow-newer"   (C.alaList' C.CommaVCat NoCommas)   #prjAllowNewer+    <*> C.booleanFieldDef  "reorder-goals"                                     #prjReorderGoals False+    <*> C.optionalFieldAla "max-backjumps" Int'                                    #prjMaxBackjumps+    <*> C.optionalFieldDef "optimization"                                      #prjOptimization OptimizationOn+    <*> pure []+    <*> pure origFields
+ src/HaskellCI/TestedWith.hs view
@@ -0,0 +1,91 @@+module HaskellCI.TestedWith (+    TestedWithJobs (..),+    checkVersions,+    ) where++import           Prelude                         ()+import           Prelude.Compat++import           Control.Applicative             ((<|>))+import           Data.Generics.Labels            ()+import           Data.List                       (intercalate)++import qualified Data.Foldable                   as F+import qualified Data.Set                        as S+import qualified Distribution.Compat.CharParsing as C+import qualified Distribution.Parsec.Class       as C+import qualified Distribution.Pretty             as C+import qualified Distribution.Types.Version      as C+import qualified Distribution.Types.VersionRange as C+import qualified Text.PrettyPrint                as PP++import           HaskellCI.Package+import           HaskellCI.Project++data TestedWithJobs+    = TestedWithUniform+    | TestedWithAny+  deriving (Eq, Show)++instance C.Parsec TestedWithJobs where+    parsec = TestedWithUniform <$ C.string "uniform"+        <|> TestedWithAny <$ C.string "any"++instance C.Pretty TestedWithJobs where+    pretty TestedWithUniform = PP.text "uniform"+    pretty TestedWithAny     = PP.text "any"++-------------------------------------------------------------------------------+-- Selection+-------------------------------------------------------------------------------++checkVersions+    :: TestedWithJobs+    -> Project (Package, S.Set C.Version)+    -> Either [String] (S.Set C.Version, Project Package)+checkVersions TestedWithUniform = checkVersionsUniform+checkVersions TestedWithAny     = checkVersionsAny++checkVersionsUniform+    :: Project (Package, S.Set C.Version)+    -> Either [String] (S.Set C.Version, Project Package)+checkVersionsUniform prj | null (prjPackages prj) = Left ["Error reading cabal file(s)!"]+checkVersionsUniform prj = do+    let (errors, names) = F.foldl' collectConfig mempty prj+    if not (null errors)+    then Left errors+    else Right (allVersions, prj { prjPackages = names })+  where+    allVersions = F.foldMap snd prj++    collectConfig+        :: ([String], [Package])+        -> (Package, S.Set C.Version)+        -> ([String], [Package])+    collectConfig aggregate (pkg, testWith) =+        aggregate <> (errors, [pkg])+      where+        symDiff a b = S.union a b `S.difference` S.intersection a b+        diff = symDiff testWith allVersions+        missingVersions = map C.prettyShow $ S.toList diff+        errors | S.null diff = []+               | otherwise = pure $ mconcat+                    [ pkgName pkg+                    , " is missing tested-with annotations for: "+                    ] ++ intercalate "," missingVersions++checkVersionsAny+    :: Project (Package, S.Set C.Version)+    -> Either [String] (S.Set C.Version, Project Package)+checkVersionsAny prj | null (prjPackages prj) = Left ["Error reading cabal file(s)!"]+checkVersionsAny prj =+    Right (allVersions, uncurry f <$> prj)+  where+    allVersions = F.foldMap snd prj++    f :: Package -> S.Set C.Version -> Package+    f pkg vs = case S.toList vs of+        []      -> pkg { pkgJobs = C.noVersion }+        (v:vs') -> pkg { pkgJobs = foldr g (C.thisVersion v) vs' }++    g = C.unionVersionRanges . C.thisVersion
+ src/HaskellCI/Version.hs view
@@ -0,0 +1,42 @@+module HaskellCI.Version where++import           Data.Function                      (on)+import           Data.List                          (intercalate)++import qualified Distribution.Version as C++ghcVersionPredicate :: C.VersionRange -> String+ghcVersionPredicate = conj . C.asVersionIntervals+  where+    conj = intercalate "  ||  " . map disj++    disj :: C.VersionInterval -> String+    disj (C.LowerBound v C.InclusiveBound, C.UpperBound u C.InclusiveBound)+        | v == u                = "[ $HCNUMVER -eq " ++ f v ++ " ]"+    disj (lb, C.NoUpperBound)+        | isInclZero lb         = "true"+        | otherwise             = lower lb+    disj (lb, C.UpperBound v b)+        | isInclZero lb         = upper v b+        | otherwise             = lower lb ++ " && " ++ upper v b++    isInclZero (C.LowerBound v C.InclusiveBound) = v == C.mkVersion [0]+    isInclZero (C.LowerBound _ C.ExclusiveBound) = False++    lower (C.LowerBound v C.InclusiveBound) = "[ $HCNUMVER -ge " ++ f v ++ " ]"+    lower (C.LowerBound v C.ExclusiveBound) = "[ $HCNUMVER -gt " ++ f v ++ " ]"++    upper v C.InclusiveBound = "[ $HCNUMVER -le " ++ f v ++ " ]"+    upper v C.ExclusiveBound = "[ $HCNUMVER -lt " ++ f v ++ " ]"++    f = ghcVersionToString++ghcVersionToString :: C.Version -> String+ghcVersionToString v =  case C.versionNumbers v of+    []        -> "0"+    [x]       -> show (x * 10000)+    [x,y]     -> show (x * 10000 + y * 100)+    (x:y:z:_) -> show (x * 10000 + y * 100 + z)++equivVersionRanges :: C.VersionRange -> C.VersionRange -> Bool+equivVersionRanges = on (==) C.asVersionIntervals
− src/MakeTravisYml.hs
@@ -1,1905 +0,0 @@-{-# LANGUAGE Haskell2010 #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE ViewPatterns #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE MultiWayIf #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE DeriveFoldable #-}-{-# LANGUAGE DeriveTraversable #-}--#if !defined(MIN_VERSION_Cabal)--- As a heuristic, if the macro isn't defined, be pessimistic and--- assume an "old" Cabal version-# define MIN_VERSION_Cabal(x,y,z) 0-#endif---- | New-style @.travis.yml@ script generator using cabal 1.24's nix-style--- tech-preview facilities.------ See also <https://github.com/haskell-CI/haskell-ci>------ NB: This code deliberately avoids relying on non-standard packages and---     is expected to compile/work with at least GHC 7.0 through GHC 8.0-module MakeTravisYml (-    main,-    -- * for tests-    Result (..),-    Diagnostic (..),-    parseOptsNoCommands,-    formatDiagnostic, formatDiagnostics,-    travisFromConfigFile, MakeTravisOutput, Options (..), defOptions, options,-    ) where--import Control.Applicative as App ((<$>),(<|>), pure)-import Control.DeepSeq (force)-import Control.Exception (evaluate)-import Control.Monad (void, when, unless, filterM, liftM, liftM2, forM_, mzero, foldM, join)-import Data.Char (isSpace, isUpper, toLower)-import qualified Data.Foldable as F-import qualified Data.Traversable as T-import Data.Function-import Data.List-import Data.Maybe-import Data.Monoid as Mon (Monoid (..), Endo (..))-import Data.Either (partitionEithers)-import Data.Set (Set)-import qualified Data.Set as S-import qualified Data.Map as M-import System.Console.GetOpt-import System.Directory (doesDirectoryExist, getDirectoryContents, doesFileExist)-import System.Environment-import System.Exit-import System.FilePath.Posix ((</>), takeDirectory, takeFileName, takeExtension)-import System.IO-import Control.Monad.IO.Class-import Control.Monad.Trans.Class (lift)-import Control.Monad.Trans.Maybe-import Control.Monad.Trans.Writer-import Text.Read (readMaybe)--import Distribution.Compiler (CompilerFlavor(..))-import Distribution.Package hiding (Package, pkgName)-import qualified Distribution.Package as Pkg-import Distribution.PackageDescription (GenericPackageDescription,packageDescription, testedWith, package, condLibrary, condTestSuites)-import Distribution.PackageDescription.Configuration (flattenPackageDescription)-import qualified Distribution.PackageDescription as PD-import qualified Distribution.ParseUtils as PU-import Distribution.Text-import Distribution.Version-#if MIN_VERSION_Cabal(2,2,0)-import Distribution.PackageDescription.Parsec (readGenericPackageDescription)-#elif MIN_VERSION_Cabal(2,0,0)-import Distribution.PackageDescription.Parse (readGenericPackageDescription)-#else-import Distribution.PackageDescription.Parse (readPackageDescription)-import Distribution.Verbosity (Verbosity)-#endif-import Distribution.Compat.ReadP-    ( ReadP, (<++), (+++), between, char, many1, munch1-    , pfail, readP_to_S, readS_to_P, look-    , satisfy, sepBy, sepBy1, gather, munch, skipSpaces)--#ifdef MIN_VERSION_ShellCheck-import ShellCheck.Checker (checkScript)-import qualified ShellCheck.Interface as SC-import qualified ShellCheck.Formatter.Format as SC-import qualified ShellCheck.Formatter.TTY as SC.TTY-import System.IO.Unsafe (unsafePerformIO)-#endif--#if MIN_VERSION_base(4,9,0)-import Data.Semigroup (Semigroup (..))-#else-import Data.Monoid ((<>))-#endif--#if !(MIN_VERSION_Cabal(2,0,0))--- compat helpers for pre-2.0--readGenericPackageDescription :: Verbosity -> FilePath -> IO GenericPackageDescription-readGenericPackageDescription = readPackageDescription--mkVersion :: [Int] -> Version-mkVersion vn = Version vn []--versionNumbers :: Version -> [Int]-versionNumbers (Version vn _) = vn--#endif------------------------------------------------------------------------------------ Hardcoded values----------------------------------------------------------------------------------knownGhcVersions :: [Version]-knownGhcVersions = fmap mkVersion-    [ [7,0,1],  [7,0,2], [7,0,3], [7,0,4]-    , [7,2,1],  [7,2,2]-    , [7,4,1],  [7,4,2]-    , [7,6,1],  [7,6,2], [7,6,3]-    , [7,8,1],  [7,8,2], [7,8,3], [7,8,4]-    , [7,10,1], [7,10,2], [7,10,3]-    , [8,0,1],  [8,0,2]-    , [8,2,1],  [8,2,2]-    , [8,4,1],  [8,4,2], [8,4,3]-    , [8,6,1]-    ]--ghcAlpha :: Maybe Version--- ghcAlpha = Nothing-ghcAlpha = Just (mkVersion [8,6,1])--cabalVerMap :: [((Int, Int), Maybe Version)]-cabalVerMap = fmap (fmap (fmap mkVersion))-    [ ((7, 0), Just [2,2]) -- Use 2.2 for everything.-    , ((7, 2), Just [2,2])-    , ((7, 4), Just [2,2])-    , ((7, 6), Just [2,2])-    , ((7, 8), Just [2,2])-    , ((7,10), Just [2,2])-    , ((8, 0), Just [2,2])-    , ((8, 2), Just [2,2])-    , ((8, 4), Just [2,2])-    ]--defaultHLintVersion :: VersionRange-defaultHLintVersion = withinVersion (mkVersion [2,1])--defaultDoctestVersion :: VersionRange-defaultDoctestVersion = withinVersion (mkVersion [0,16])------------------------------------------------------------------------------------ Script------------------------------------------------------------------------------------ |  Encode shell command to be YAML safe and (optionally) ShellCheck it.-sh :: String -> String-sh = sh'-    [ 2034 -- VAR appears unused. Verify it or export it.-    , 2086 -- SC2086: Double quote to prevent globbing and word splitting.-    ]---- | Like 'sh' but with explicit SC exclude codes.-sh' :: [Integer] -> String -> String-#ifndef MIN_VERSION_ShellCheck-sh' _ = shImpl-#else-sh' excl cmd = unsafePerformIO $ do-  res <- checkScript iface spec-  case res of-    (SC.CheckResult _ []) -> return (shImpl cmd)-    _                     -> SC.onResult scFormatter res iface >> fail "ShellCheck!"-  where-    iface = SC.SystemInterface $ \n -> return $ Left $ "cannot read file: " ++ n-    spec  = SC.emptyCheckSpec { SC.csFilename = "stdin"-                              , SC.csScript = cmd-                              , SC.csExcludedWarnings = excl-                              , SC.csShellTypeOverride = Just SC.Sh-                              }--scFormatter :: SC.Formatter-scFormatter = unsafePerformIO (SC.TTY.format (SC.FormatterOptions SC.ColorAlways))-#endif---- Non-ShellCheck version of sh'-shImpl :: String -> String-shImpl cmd-    | ':' `elem` cmd = "  - " ++ show cmd-    | otherwise      = "  - " ++ cmd--comment :: String -> String-comment = ("  # " ++)--type MakeTravisOutput = Result Diagnostic [String]--data Diagnostic-    = Info String-    | Warn String-    | Error String-  deriving (Eq, Show)--formatDiagnostics :: [Diagnostic] -> String-formatDiagnostics = unlines . map formatDiagnostic--formatDiagnostic :: Diagnostic -> String-formatDiagnostic (Error s) = "*ERROR* " ++ s-formatDiagnostic (Warn  s) = "*WARNING* " ++ s-formatDiagnostic (Info  s) = "*INFO* " ++ s---- MaybeT is used to preserve the short-circuiting semantics of 'putStrLnErr'.-type YamlWriter m a = MaybeT (WriterT MakeTravisOutput m) a--putStrLnErr :: Monad m => String -> YamlWriter m a-putStrLnErr m = do-    lift . tell $ Failure [Error m]-    mzero--putStrLnErrs :: Monad m => [String] -> YamlWriter m ()-putStrLnErrs [] = return ()-putStrLnErrs ms = do-    lift (tell (Failure (map Error ms)))-    mzero--putStrLnWarn, putStrLnInfo :: Monad m => String -> YamlWriter m ()-putStrLnWarn m = lift . tell $ Success [Warn m] []-putStrLnInfo m = lift . tell $ Success [Info m] []--tellStrLn :: Monad m => String -> YamlWriter m ()-tellStrLn str = lift . tell $ success [str]--tellStrLns :: Monad m => [String] -> YamlWriter m ()-tellStrLns = lift . tell . success--foldedTellStrLns-    :: Monad m-    => Fold-    -> String-    -> Set Fold-    -> YamlWriter m ()-    -> YamlWriter m ()-foldedTellStrLns label = foldedTellStrLns' label ""--foldedTellStrLns'-    :: Monad m-    => Fold-    -> String-    -> String-    -> Set Fold-    -> YamlWriter m ()-    -> YamlWriter m ()-foldedTellStrLns' label pfx prettyLabel labels output-    | label `S.notMember` labels = output-    | otherwise = tellStrLns [prologue] >> output >> tellStrLns epilogue-  where-    prologue = mconcat-        [ "  - echo ", prettyLabel-        , " && echo -en 'travis_fold:start:", showFold' label, "\\\\r'" ]-    epilogue = ["  - echo -en 'travis_fold:end:" ++ showFold' label ++ "\\\\r'" ]--    showFold' l = showFold l ++ if null pfx then "" else "-" ++ pfx---- | Return the part after the first argument------ >>> afterInfix "BAR" "FOOBAR XYZZY"--- Just " XYZZY"----afterInfix :: Eq a => [a] -> [a] -> Maybe [a]-afterInfix needle haystack = findMaybe (afterPrefix needle) (tails haystack)---- |------ >>> afterPrefix "FOO" "FOOBAR"--- Just "BAR"----afterPrefix :: Eq a => [a] -> [a] -> Maybe [a]-afterPrefix needle haystack-    | needle `isPrefixOf` haystack = Just (drop (length needle) haystack)-    | otherwise                    = Nothing---- |------ >>> findMaybe readMaybe ["foo", "1", "bar"] :: Maybe Int--- Just 1----findMaybe :: (a -> Maybe b) -> [a] -> Maybe b-findMaybe f = foldr (\a b -> f a App.<|> b) Nothing---- | >>> maybeReadP PU.parseTokenQ' "foo"--- Just "foo"-maybeReadP :: ReadP a a -> String -> Maybe a-maybeReadP p s = listToMaybe $-    [ x-    | (x, rest) <- readP_to_S p s-    , all isSpace rest-    ]--main :: IO ()-main = do-    argv <- getArgs-    (opts,argv',configFile,xpkgs) <- parseOpts argv-    genTravisFromConfigFile (argv',opts) configFile xpkgs--parseOpts :: [String] -> IO (Options, [String], FilePath, [String])-parseOpts argv = case argv of-    (cmd : argv') | cmd `isPrefixOf` "regenerate" -> do-        let fp = fromMaybe  ".travis.yml" $ listToMaybe argv'-        ls <- fmap lines (readFile fp >>= evaluate . force) -- strict IO-        case findArgv ls of-            Nothing     -> dieCli [Error $ "expected REGENDATA line in " ++ fp ++ "\n"]-            Just argv'' -> parseOpts argv''-    [cmd] | cmd `isPrefixOf` "list-ghc" -> do-        putStrLn $ "Supported GHC versions:"-        forM_ groupedVersions $ \(v, vs) -> do-            putStr $ prettyMajVersion v ++ ": "-            putStrLn $ intercalate ", " (map display vs)-        exitSuccess-    _ -> parseOptsNoCommands argv-  where-    groupedVersions :: [(Version, [Version])]-    groupedVersions = map ((\vs -> (head vs, vs)) . sortBy (flip compare))-                    . groupBy ((==) `on` ghcMajVer)-                    $ sort knownGhcVersions--    prettyMajVersion :: Version -> String-    prettyMajVersion v-        | Just v == ghcAlpha = "alpha"-        | otherwise = case ghcMajVer v of (x,y) -> show x ++ "." ++ show y--    findArgv :: [String] -> Maybe [String]-    findArgv ls = do-        l <- findMaybe (afterInfix "REGENDATA") ls-        readMaybe l---- Returns options, used argv, cabal file, xpkgs-parseOptsNoCommands :: [String] -> IO (Options, [String], FilePath, [String])-parseOptsNoCommands argv = case getOpt Permute options argv of-    (opts',configFile:xpkgs,[]) -> do-        opts <- foldOptions defOptions opts'-        return (opts,argv,configFile,xpkgs)-    (_,_,[]) -> dieCli [Error "expected .cabal or cabal.project file as first non-option argument\n"]-    (_,_,errs) -> dieCli (map Error errs)-  where-    foldOptions :: Options -> [Result Diagnostic (Options -> Options)] -> IO Options-    foldOptions def opts = case foldOptions' def opts of-        Success ws x -> do-            hPutStr stderr (formatDiagnostics ws)-            return x-        Failure errs -> dieCli errs--    foldOptions' :: Options -> [Result e (Options -> Options)] -> Result e Options-    foldOptions' opts = fmap (`appEndo` opts) . F.foldMap (fmap Endo)--dieCli ::  [Diagnostic] -> IO a-dieCli errs = hPutStrLn stderr (usageMsg errs) >> exitFailure- where-    usageMsg errs' = formatDiagnostics errs' ++ usageInfo h options ++ ex--    h = intercalate "\n"-        [ "Usage: runghc make_travis_yml_2.hs [OPTIONS] <cabal-file | cabal.project> <extra-apt-packages...>"-        , ""-        , "Available commands:"-        , "    regenerate [TRAVIS.YAML]  Regenerate the file using the magic command in it. Default .travis.yml"-        , "    list-ghc                  List GHC versions supported by this version of make-travis-yml"-        , ""-        , "Available options:"-        ]--    ex = unlines-        [ ""-        , "Example:"-        , "    runghc make_travis_yml_2.hs -o .travis.yml someProject.cabal liblzma-dev"-        ]--runYamlWriter :: Maybe FilePath -> YamlWriter IO () -> IO ()-runYamlWriter mfp m = do-    result <- execWriterT (runMaybeT m)-    case result of-        Failure (formatDiagnostics -> errors) -> hPutStr stderr errors >> exitFailure-        Success (formatDiagnostics -> warnings) (unlines -> contents) -> do-            contents' <- evaluate (force contents)-            hPutStr stderr warnings-            case mfp of-                Nothing -> putStr contents'-                Just fp -> writeFile fp contents'--ghcMajVer :: Version -> (Int,Int)-ghcMajVer v-    | x:y:_ <- versionNumbers v = (x,y)-    | otherwise = error $ "panic: ghcMajVer called with " ++ show v---- | Alphas, RCs and HEAD.-previewGHC :: Maybe Version -> Bool-previewGHC = maybe True $ \v -> Just v == ghcAlpha || odd (snd (ghcMajVer v))--dispGhcVersion :: Maybe Version -> String-dispGhcVersion = maybe "head" display--data Package = Pkg-    { pkgName :: String-    , pkgDir :: FilePath-    , pkgGpd :: GenericPackageDescription-    } deriving (Eq, Show)--genTravisFromConfigFile :: ([String],Options) -> FilePath -> [String] -> IO ()-genTravisFromConfigFile args@(_, opts) path xpkgs =-    runYamlWriter (optOutput opts) $ travisFromConfigFile args path xpkgs--travisFromConfigFile-    :: MonadIO m-    => ([String],Options)-    -> FilePath-    -> [String]-    -> YamlWriter m ()-travisFromConfigFile args@(_, opts) path xpkgs = do-    cabalFiles <- getCabalFiles-    config' <- maybe (return emptyConfig) readConfigFile (optConfig opts)-    let config = optConfigMorphism opts config'-    pkgs <- T.mapM (configFromCabalFile config opts) cabalFiles-    (ghcs, prj) <- checkVersions pkgs-    genTravisFromConfigs args xpkgs isCabalProject config prj ghcs-  where-    checkVersions-        :: MonadIO m-        => Project (Package, Set Version)-        -> YamlWriter m (Set Version, Project Package)-    checkVersions prj | null (prjPackages prj) = putStrLnErr "Error reading cabal file(s)!"-    checkVersions prj = do-        let (errors, names) = F.foldl' collectConfig mempty prj-        putStrLnErrs errors-        return (allVersions, prj { prjPackages = names })-      where-        allVersions = F.foldMap snd prj--        collectConfig-            :: ([String], [Package])-            -> (Package, Set Version)-            -> ([String], [Package])-        collectConfig aggregate (pkg, testWith) =-            aggregate <> (errors, [pkg])-          where-            symDiff a b = S.union a b `S.difference` S.intersection a b-            diff = symDiff testWith allVersions-            missingVersions = map display $ S.toList diff-            errors | S.null diff = []-                   | otherwise = App.pure $ mconcat-                        [ pkgName pkg-                        , " is missing tested-with annotations for: "-                        ] ++ intercalate "," missingVersions--    isCabalProject :: Maybe FilePath-    isCabalProject-        | "cabal.project" `isPrefixOf` takeFileName path = Just path-        | otherwise = Nothing--    getCabalFiles :: MonadIO m => YamlWriter m (Project FilePath)-    getCabalFiles-        | isNothing isCabalProject = return (Project [path] Nothing Nothing)-        | otherwise = do-            contents <- liftIO $ readFile path-            pkgs <- either putStrLnErr return $ parseProjectFile path contents-            overPrjPackages concat `liftM` T.mapM findProjectPackage pkgs--    rootdir = takeDirectory path--    -- See findProjectPackages in cabal-install codebase-    -- this is simple variant.-    findProjectPackage :: MonadIO m => String -> YamlWriter m [FilePath]-    findProjectPackage pkglocstr = do-        mfp <- checkisFileGlobPackage pkglocstr `mplusMaybeT`-               checkIsSingleFilePackage pkglocstr-        maybe (putStrLnErr $ "bad package location: " ++ pkglocstr) return mfp--    checkIsSingleFilePackage pkglocstr = do-        let abspath = rootdir </> pkglocstr-        isFile <- liftIO $ doesFileExist abspath-        isDir  <- liftIO $ doesDirectoryExist abspath-        if | isFile && takeExtension pkglocstr == ".cabal" -> return (Just [abspath])-           | isDir -> checkisFileGlobPackage (pkglocstr </> "*.cabal")-           | otherwise -> return Nothing--    -- if it looks like glob, glob-    checkisFileGlobPackage pkglocstr =-        case filter (null . snd) $ readP_to_S parseFilePathGlobRel pkglocstr of-            [(g, "")] -> do-                files <- liftIO $ expandRelGlob rootdir g-                let files' = filter ((== ".cabal") . takeExtension) files-                -- if nothing is matched, skip.-                if null files' then return Nothing else return (Just files')-            _         -> return Nothing--    mplusMaybeT :: Monad m => m (Maybe a) -> m (Maybe a) -> m (Maybe a)-    mplusMaybeT ma mb = do-        mx <- ma-        case mx of-            Nothing -> mb-            Just x  -> return (Just x)--configFromCabalFile-    :: MonadIO m => Config ->  Options -> FilePath -> YamlWriter m (Package, Set Version)-configFromCabalFile cfg opts cabalFile = do-    gpd <- liftIO $ readGenericPackageDescription maxBound cabalFile--    let compilers = testedWith $ packageDescription gpd-        pkgNameStr = display $ Pkg.pkgName $ package $ packageDescription gpd--    let unknownComps = nub [ c | (c,_) <- compilers, c /= GHC ]-        ghcVerConstrs = [ vc | (GHC,vc) <- compilers ]-        ghcVerConstrs' = simplifyVersionRange $ foldr unionVersionRanges noVersion ghcVerConstrs-        twoDigitGhcVerConstrs = mapMaybe isTwoDigitGhcVersion ghcVerConstrs :: [Version]-        specificGhcVers = nub $ mapMaybe isSpecificVersion ghcVerConstrs--    unless (null twoDigitGhcVerConstrs) $ do-        putStrLnWarn $ "'tested-with:' uses two digit GHC versions (which don't match any existing GHC version): " ++ intercalate ", " (map display twoDigitGhcVerConstrs)-        putStrLnInfo $ "Either use wild-card format, for example 'tested-with: GHC ==7.10.*' or a specific existing version 'tested-with: GHC ==7.10.3'"--    when (null compilers) $ do-        putStrLnErr (unlines $-                     [ "empty or missing top-level 'tested-with:' definition in " ++ cabalFile ++ " file; example definition:"-                     , ""-                     , "tested-with: " ++ intercalate ", " [ "GHC==" ++ display v | v <- lastStableGhcVers ]-                     ])--    unless (null unknownComps) $ do-        putStrLnWarn $ "ignoring unsupported compilers mentioned in tested-with: " ++ show unknownComps--    when (null ghcVerConstrs) $ do-        putStrLnErr "'tested-with:' doesn't mention any 'GHC' version"--    when (isNoVersion ghcVerConstrs') $ do-        putStrLnErr "'tested-with:' describes an empty version range for 'GHC'"--    when (isAnyVersion ghcVerConstrs') $ do-        putStrLnErr "'tested-with:' allows /any/ 'GHC' version"--    let unknownGhcVers = sort $ specificGhcVers \\ knownGhcVersions--    unless (null unknownGhcVers) $ do-        putStrLnErr ("'tested-with:' specifically refers to unknown 'GHC' versions: "-                     ++ intercalate ", " (map display unknownGhcVers) ++ "\n"-                     ++ "Known GHC versions: " ++ intercalate ", " (map display knownGhcVersions))--    let knownGhcVersions'-            | cfgLastInSeries cfg = filterLastMajor knownGhcVersions-            | otherwise           = knownGhcVersions--    let testedGhcVersions = filter (`withinRange` ghcVerConstrs') knownGhcVersions'--    when (null testedGhcVersions) $ do-        putStrLnErr "no known GHC version is allowed by the 'tested-with' specification"--    forM_ (optCollections opts) $ \c -> do-        let v = collToGhcVer c-        unless (v `elem` testedGhcVersions) $-            putStrLnErr $ unlines-               [ "collection " ++ c ++ " requires GHC " ++ display v-               , "add 'tested-width: GHC == " ++ display v ++ "' to your .cabal file"-               ]--    let pkg = Pkg pkgNameStr (takeDirectory cabalFile) gpd--    return (pkg, S.fromList testedGhcVersions)-  where-    lastStableGhcVers-        = nubBy ((==) `on` ghcMajVer)-        $ sortBy (flip compare)-        $ filter (not . previewGHC . Just)-        $ knownGhcVersions--    isTwoDigitGhcVersion :: VersionRange -> Maybe Version-    isTwoDigitGhcVersion vr = isSpecificVersion vr >>= t-      where-        t v | [_,_] <- versionNumbers v = Just v-        t _                             = Nothing--    filterLastMajor = map maximum . groupBy ((==) `on` ghcMajVer)--genTravisFromConfigs-    :: Monad m-    => ([String], Options)-    -> [String]-    -> Maybe FilePath-    -> Config-    -> Project Package-    -> Set Version-    -> YamlWriter m ()-genTravisFromConfigs (argv,opts) xpkgs isCabalProject config prj@Project { prjPackages = pkgs } versions' = do-    let folds = cfgFolds config--    putStrLnInfo $-        "Generating Travis-CI config for testing for GHC versions: " ++ ghcVersions--    unless (null $ optOsx opts) $  do-        putStrLnInfo $ "Also OSX jobs for: " ++ ghcOsxVersions-        unless (S.null omittedOsxVersions) $-            putStrLnWarn $ "Not all GHC versions specified with --osx are generated: " ++ ghcOmittedOsxVersions--    ----------------------------------------------------------------------------    -- travis.yml generation starts here--    tellStrLns-        [ "# This Travis job script has been generated by a script via"-        , "#"-        , "#   runghc make_travis_yml_2.hs " ++ unwords [ "'" ++ a ++ "'" | a <- argv ]-        , "#"-        , "# For more information, see https://github.com/haskell-CI/haskell-ci"-        , "#"-        , "language: c"-        , "sudo: false"-        , ""-        , "git:"-        , "  submodules: false  # whether to recursively clone submodules"-        , ""-        ]--    let projectName = fromMaybe (pkgName $ head pkgs) (cfgProjectName config)-    unless (null $ cfgIrcChannels config) $ tellStrLns $-        [ "notifications:"-        , "  irc:"-        , "    channels:"-        ] ++-        [ "      - \"" ++ chan ++ "\"" | chan <- cfgIrcChannels config ] ++-        [ "    skip_join: true"-        , "    template:"-        , "      - \"\\x0313" ++ projectName ++ "\\x03/\\x0306%{branch}\\x03 \\x0314%{commit}\\x03 %{build_url} %{message}\""-        , ""-        ]--    unless (null $ cfgOnlyBranches config) $ tellStrLns $-        [ "branches:"-        , "  only:"-        ] ++-        [ "    - " ++ branch-        | branch <- cfgOnlyBranches config-        ] ++-        [ ""-        ]--    when (cfgCache config) $ tellStrLns-        [ "cache:"-        , "  directories:"-        , "    - $HOME/.cabal/packages"-        , "    - $HOME/.cabal/store"-        ]--    -- on OSX ghc is installed in $HOME so we can cache it-    -- independently of linux-    when (cfgCache config && not (null (optOsx opts))) $ tellStrLns-        [ "    - $HOME/.ghc-install"-        ]--    when (cfgCache config) $ tellStrLns-        [ ""-        , "before_cache:"-        , "  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log"-        , "  # remove files that are regenerated by 'cabal update'"-        , "  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.*" -- legacy-        , "  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/*.json" -- TUF meta-data-        , "  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.cache"-        , "  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar"-        , "  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar.idx"-        , ""-        , "  - rm -rfv $HOME/.cabal/packages/head.hackage" -- if we cache, it will break builds.-        , ""-        ]--    tellStrLn "matrix:"-    tellStrLn "  include:"--    let colls = [ (collToGhcVer cid,cid) | cid <- reverse $ optCollections opts ]--    let tellJob :: Monad m => Bool -> Maybe Version -> YamlWriter m ()-        tellJob osx gv = do-            let cvs = dispGhcVersion $ cfgCabalInstallVersion config <|> (lookupCabVer =<< gv)-                gvs = dispGhcVersion gv--                xpkgs' = concatMap (',':) xpkgs--                colls' = [ cid | (v,cid) <- colls, Just v == gv ]--            tellStrLns-                [ "    - compiler: \"ghc-" <> gvs <> "\""-                , if | Just e <- gv >>= \v -> M.lookup v (cfgEnv config)-                                     -> "      env: " ++ e-                     | previewGHC gv -> "      env: GHCHEAD=true"-                     | null colls'   -> "    # env: TEST=--disable-tests BENCH=--disable-benchmarks"-                     | otherwise     -> "      env: 'COLLECTIONS=" ++ intercalate "," colls' ++ "'"-                , "      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-" <> cvs <> ",ghc-" <> gvs <> xpkgs' <> "], sources: [hvr-ghc]}}"-                ]--            when osx $ tellStrLns-                [ "      os: osx"-                ]--    -- newer GHC first, -head last (which is great).-    -- Alpha release would go first though.-    F.forM_ (reverse $ S.toList versions) $ tellJob False-    F.forM_ (reverse $ S.toList osxVersions) $ tellJob True . Just--    let allowFailures = headGhcVers `S.union` S.map Just (cfgAllowFailures config)-    unless (S.null allowFailures) $ do-        tellStrLn ""-        tellStrLn "  allow_failures:"--        F.forM_ allowFailures $ \gv -> do-            let gvs = dispGhcVersion gv-            tellStrLn $ concat [ "    - compiler: \"ghc-", gvs, "\"" ]--    tellStrLns-        [ ""-        , "before_install:"-        , sh "HC=${CC}"-        , sh' [2034,2039] "HCPKG=${HC/ghc/ghc-pkg}" -- SC2039. In POSIX sh, string replacement is undefined.-        , sh "unset CC"-        -- rootdir is useful for manual script additions-        , sh "ROOTDIR=$(pwd)"-        , sh "mkdir -p $HOME/.local/bin"-        ]--    let haskellOnMacos = "https://haskell.futurice.com/haskell-on-macos.py"--    if null (optOsx opts)-    then tellStrLns-        [ sh "PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$HOME/local/bin:$PATH"-        ]-    else tellStrLns-        [ sh $ "if [ \"$(uname)\" = \"Darwin\" ]; then brew update; brew upgrade python@3; curl " ++ haskellOnMacos ++ " | python3 - --make-dirs --install-dir=$HOME/.ghc-install --cabal-alias=head install cabal-install-head ${HC}; fi"-        , sh $ "if [ \"$(uname)\" = \"Darwin\" ]; then PATH=$HOME/.ghc-install/ghc/bin:$HOME/local/bin:$PATH; else PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$HOME/local/bin:$PATH; fi"-        ]--    -- HCNUMVER, numeric HC version, e.g. ghc 7.8.4 is 70804 and 7.10.3 is 71003-    tellStrLns-        [ sh $ "HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\\.([0-9]+)\\.([0-9]+).*/\\1 * 10000 + \\2 * 100 + \\3/') ))"-        , sh "echo $HCNUMVER"-        ]--    unless (null colls) $-       tellStrLn " - IFS=', ' read -a COLLS <<< \"$COLLECTIONS\""--    tellStrLns-        [ ""-        , "install:"-        , sh "cabal --version"-        , sh "echo \"$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]\""-        , sh "BENCH=${BENCH---enable-benchmarks}"-        , sh "TEST=${TEST---enable-tests}"-        , sh "HADDOCK=${HADDOCK-true}"-        , sh "UNCONSTRAINED=${UNCONSTRAINED-true}"-        , sh "NOINSTALLEDCONSTRAINTS=${NOINSTALLEDCONSTRAINTS-false}"-        , sh "GHCHEAD=${GHCHEAD-false}"-        ]--    -- Update hackage index. Side-effect: ~/.cabal.config is created.-    tellStrLns-        [ sh "travis_retry cabal update -v"-        , sh "sed -i.bak 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config"-        , sh "rm -fv cabal.project cabal.project.local"-        ]--    -- Cabal jobs-    case cfgJobs config of-        (Just n, _) -> tellStrLns-            [ sh $ "sed -i.bak 's/^-- jobs:.*/jobs: " ++ show n ++ "/' ${HOME}/.cabal/config"-            ]-        _ -> return ()--    -- GHC jobs-    case cfgJobs config of-        (_, Just m) -> tellStrLns-            [ sh $ "if [ $HCNUMVER -ge 70800 ]; then sed -i.bak 's/-- ghc-options:.*/ghc-options: -j" ++ show m ++ "/' ${HOME}/.cabal/config; fi"-            ]-        _ -> return ()--    -- Add head.hackage repository to ~/.cabal/config-    -- (locally you want to add it to cabal.project)-    unless (S.null headGhcVers) $ tellStrLns-        [ "  # Overlay Hackage Package Index for GHC HEAD: https://github.com/hvr/head.hackage"-        , "  - |"-        , "    if $GHCHEAD; then"-        , "      sed -i 's/-- allow-newer: .*/allow-newer: *:base/' ${HOME}/.cabal/config"-        , "      for pkg in $($HCPKG list --simple-output); do pkg=$(echo $pkg | sed 's/-[^-]*$//'); sed -i \"s/allow-newer: /allow-newer: *:$pkg, /\" ${HOME}/.cabal/config; done"-        , ""-        , "      echo 'repository head.hackage'                                                        >> ${HOME}/.cabal/config"-        , "      echo '   url: http://head.hackage.haskell.org/'                                       >> ${HOME}/.cabal/config"-        , "      echo '   secure: True'                                                                >> ${HOME}/.cabal/config"-        , "      echo '   root-keys: 07c59cb65787dedfaef5bd5f987ceb5f7e5ebf88b904bbd4c5cbdeb2ff71b740' >> ${HOME}/.cabal/config"-        , "      echo '              2e8555dde16ebd8df076f1a8ef13b8f14c66bad8eafefd7d9e37d0ed711821fb' >> ${HOME}/.cabal/config"-        , "      echo '              8f79fd2389ab2967354407ec852cbe73f2e8635793ac446d09461ffb99527f6e' >> ${HOME}/.cabal/config"-        , "      echo '   key-threshold: 3'                                                            >> ${HOME}/.cabal.config"-        , ""-        , "      grep -Ev -- '^\\s*--' ${HOME}/.cabal/config | grep -Ev '^\\s*$'"-        , ""-        , "      cabal new-update head.hackage -v"-        , "    fi"-        ]--    -- Output cabal.config-    tellStrLns-        [ sh "grep -Ev -- '^\\s*--' ${HOME}/.cabal/config | grep -Ev '^\\s*$'"-        ]--    -- Install doctest-    let doctestVersionConstraint-            | isAnyVersion (cfgDoctestVersion config) = ""-            | otherwise = " --constraint='doctest " ++ display (cfgDoctestVersion config) ++ "'"-    when (cfgDoctest config) $ tellStrLns-        [ sh $ "if [ $HCNUMVER -ge 80000 ]; then cabal new-install -w ${HC} -j2 --symlink-bindir=$HOME/.local/bin doctest" ++ doctestVersionConstraint ++ "; fi"-        ]--    -- Install hlint-    let hlintVersionConstraint-            | isAnyVersion (cfgHLintVersion config) = ""-            | otherwise = " --constraint='hlint " ++ display (cfgHLintVersion config) ++ "'"-    when (cfgHLint config) $ tellStrLns-        [ sh $ "if [ $HCNUMVER -eq 80403 ]; then cabal new-install -w ${HC} -j2 --symlink-bindir=$HOME/.local/bin hlint" ++ hlintVersionConstraint ++ "; fi"-        ]--    -- create cabal.project file-    generateCabalProject False--    let pkgFilter = intercalate " | " $ map (wrap.pkgName) pkgs-        wrap s = "grep -Fv \"" ++ s ++ " ==\""-    unless (null colls) $ tellStrLns-        [ "  - for COLL in \"${COLLS[@]}\"; do"-        , "      echo \"== collection $COLL ==\";"-        , "      ghc-travis collection ${COLL} > /dev/null || break;"-        , "      ghc-travis collection ${COLL} | " ++ pkgFilter ++ " > cabal.project.freeze;"-        , "      grep ' collection-id' cabal.project.freeze;"-        , "      rm -rf dist-newstyle/;"-        , "      cabal new-build -w ${HC} ${TEST} ${BENCH} --project-file=\"" ++ projectFile ++ "\" --dep -j2 all;"-        , "    done"-        , ""-        ]--    forM_ pkgs $ \Pkg{pkgDir} -> tellStrLns-        [ "  - if [ -f \"" ++ pkgDir ++ "/configure.ac\" ]; then"-        , "      (cd \"" ++ pkgDir ++ "\" && autoreconf -i);"-        , "    fi"-        ]--    let quotedRmPaths =-          ".ghc.environment.*"-          ++ " " ++-          quotedPaths (\Pkg{pkgDir} -> pkgDir ++ "/dist")--    tellStrLns-        [ sh $ "rm -f cabal.project.freeze"-        ]--    -- Install dependencies-    when (cfgInstallDeps config) $ do-        tellStrLns-            [ sh $ "cabal new-build -w ${HC} ${TEST} ${BENCH} --project-file=\"" ++ projectFile ++"\" --dep -j2 all"-            ]-        when (cfgNoTestsNoBench config) $ tellStrLns-            [ sh $ "cabal new-build -w ${HC} --disable-tests --disable-benchmarks --project-file=\"" ++ projectFile ++ "\" --dep -j2 all"-            ]--    tellStrLns-        [ sh $ "rm -rf " ++ quotedRmPaths-        , sh $  "DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)"-        ]--    tellStrLns-        [ ""-        , "# Here starts the actual work to be performed for the package under test;"-        , "# any command which exits with a non-zero exit code causes the build to fail."-        , "script:"-        , "  # test that source-distributions can be generated"-        ]--    foldedTellStrLns FoldSDist "Packaging..." folds $ do-        forM_ pkgs $ \Pkg{pkgDir} -> tellStrLns-            [ sh $ "(cd \"" ++ pkgDir ++ "\" && cabal sdist)"-            ]--    let tarFiles = quotedPaths $ \Pkg{pkgDir,pkgName} ->-                pkgDir </> "dist" </> pkgName ++ "-*.tar.gz"---    foldedTellStrLns FoldUnpack "Unpacking..." folds $ do-        tellStrLns-            [ sh $ "mv " ++ tarFiles ++ " ${DISTDIR}/"-            , sh $ "cd ${DISTDIR} || false" -- fail explicitly, makes SC happier-            , sh $ "find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \\;"-            ]-        generateCabalProject True--    when (cfgNoTestsNoBench config) $ foldedTellStrLns FoldBuild "Building..." folds $ tellStrLns-        [ comment "this builds all libraries and executables (without tests/benchmarks)"-        , sh "cabal new-build -w ${HC} --disable-tests --disable-benchmarks all"-        ]--    tellStrLns [""]---    foldedTellStrLns FoldBuildEverything-        "Building with tests and benchmarks..." folds $ tellStrLns-        [ comment "build & run tests, build benchmarks"-        , sh "cabal new-build -w ${HC} ${TEST} ${BENCH} all"-        ]--    -- cabal new-test fails if there are no test-suites.-    when hasTests $-        foldedTellStrLns FoldTest "Testing..." folds $ tellStrLns-            [ sh $ mconcat-                [ "if [ \"x$TEST\" = \"x--enable-tests\" ]; then "-                , if cfgNoise config-                     then "cabal "-                     else "(set -o pipefail; cabal -vnormal+nowrap+markoutput "-                , "new-test -w ${HC} ${TEST} ${BENCH} all"-                , if cfgNoise config-                     then ""-                     else " 2>&1 | sed '/^-----BEGIN CABAL OUTPUT-----$/,/^-----END CABAL OUTPUT-----$/d' )"-                , "; fi"-                ]-            ]--    tellStrLns [""]--    when (cfgDoctest config) $ do-        let doctestOptions = unwords $ cfgDoctestOptions config-        tellStrLns [ comment "doctest" ]-        foldedTellStrLns FoldDoctest "Doctest..." folds $ do-            forM_ pkgs $ \Pkg{pkgName,pkgGpd} -> do-                let args = doctestArgs pkgGpd-                    args' = unwords args-                unless (null args) $ tellStrLns-                    [ sh $ "if [ $HCNUMVER -ge 80000 ]; then (cd " ++ pkgName ++ "-* && doctest " ++ doctestOptions ++ " " ++ args' ++ "); fi"-                    ]-        tellStrLns [ "" ]--    when (cfgHLint config) $ do-        let "" <+> ys = ys-            xs <+> "" = xs-            xs <+> ys = xs ++ " " ++ ys--            prependSpace "" = ""-            prependSpace xs = " " ++ xs--        let hlintOptions = prependSpace $ maybe "" ("-h ${ROOTDIR}/" ++) (cfgHLintYaml config) <+> unwords (cfgHLintOptions config)--        tellStrLns [ comment "hlint" ]-        foldedTellStrLns FoldHLint "HLint.." folds $ do-            forM_ pkgs $ \Pkg{pkgName,pkgGpd} -> do-                -- note: same arguments work so far for doctest and hlint-                let args = doctestArgs pkgGpd-                    args' = unwords args-                unless (null args) $ tellStrLns-                    [ sh $ "if [ $HCNUMVER -eq 80403 ]; then (cd " ++ pkgName ++ "-* && hlint" ++ hlintOptions ++ " " ++ args' ++ "); fi"-                    ]-        tellStrLns [ "" ]--    when (cfgCheck config) $-        foldedTellStrLns FoldCheck "cabal check..." folds $ do-            tellStrLns [ comment "cabal check" ]-            forM_ pkgs $ \Pkg{pkgName} -> tellStrLns-                [ sh $ "(cd " ++ pkgName ++ "-* && cabal check)"--                ]-            tellStrLns [ "" ]--    when hasLibrary $-        foldedTellStrLns FoldHaddock "Haddock..." folds $ tellStrLns-            [ comment "haddock"-            , sh "rm -rf ./dist-newstyle"-            , sh "if $HADDOCK; then cabal new-haddock -w ${HC} ${TEST} ${BENCH} all; else echo \"Skipping haddock generation\";fi"-            , ""-            ]--    unless (null colls) $-        foldedTellStrLns FoldStackage "Stackage builds..." folds $ tellStrLns-            [ "  # try building & testing for package collections"-            , "  - for COLL in \"${COLLS[@]}\"; do"-            , "      echo \"== collection $COLL ==\";"-            , "      ghc-travis collection ${COLL} > /dev/null || break;"-            , "      ghc-travis collection ${COLL} | " ++ pkgFilter ++ " > cabal.project.freeze;"-            , "      grep ' collection-id' cabal.project.freeze;"-            , "      rm -rf dist-newstyle/;"-            , "      cabal new-build -w ${HC} ${TEST} ${BENCH} all || break;"-            , "      if [ \"x$TEST\" = \"x--enable-tests\" ]; then cabal new-test -w ${HC} ${TEST} ${BENCH} all || break; fi;"-            , "    done"-            , ""-            ]--    -- Have to build last, as we remove cabal.project.local-    when (cfgUnconstrainted config) $ foldedTellStrLns FoldBuildInstalled-        "Building without installed constraints for packages in global-db..." folds $ tellStrLns-        [ comment "Build without installed constraints for packages in global-db"-        -- SC2046: Quote this to prevent word splitting.-        -- here we split on purpose!-        , sh' [2046, 2086] $ unwords-            [ "if $UNCONSTRAINED;"-            , "then rm -f cabal.project.local; echo cabal new-build -w ${HC} --disable-tests --disable-benchmarks all;"-            , "else echo \"Not building without installed constraints\"; fi"-            ]-        , ""-        ]--    -- and now, as we don't have cabal.project.local;-    -- we can test with other constraint sets-    let constraintSets = cfgConstraintSets config-    unless (null constraintSets) $ do-        tellStrLns-            [ comment "Constraint sets"-            , sh "rm -rf cabal.project.local"-            , ""-            ]-        forM_ constraintSets $ \cs -> do-            let name = csName cs-            let constraintFlags = concatMap (\x ->  " --constraint='" ++ x ++ "'") (csConstraints cs)-            tellStrLns [ comment  "Constraint set " ++ name ]-            foldedTellStrLns' FoldConstraintSets name ("Constraint set " ++ name) folds $ tellStrLns-                [ sh' [2086] $ "if " ++ ghcVersionPredicate (csGhcVersions cs) ++ "; then cabal new-build -w ${HC} --disable-tests --disable-benchmarks" ++ constraintFlags ++ " all; else echo skipping...; fi"-                , ""-                ]-        tellStrLns [""]--    tellStrLns-        [ "# REGENDATA " ++ show argv-        , "# EOF"-        ]--    return ()-  where-    hasTests   = F.any (\Pkg{pkgGpd} -> not . null $ condTestSuites pkgGpd) pkgs-    hasLibrary = F.any (\Pkg{pkgGpd} -> isJust $ condLibrary pkgGpd) pkgs--    -- GHC versions which need head.hackage-    headGhcVers = S.filter previewGHC versions--    generateCabalProject dist = do-        tellStrLns-            [ sh $ "printf 'packages: " ++ cabalPaths ++ "\\n' > cabal.project"-            ]-        F.forM_ (prjConstraints prj) $ \xs -> do-            let s = concat (lines xs)-            tellStrLns-                [ sh $ "echo 'constraints: " ++ s ++ "' >> cabal.project"-                ]-        F.forM_ (prjAllowNewer prj) $ \xs -> do-            let s = concat (lines xs)-            tellStrLns-                [ sh $ "echo 'allow-newer: " ++ s ++ "' >> cabal.project"-                ]-        unless (null (cfgLocalGhcOptions config)) $ forM_ pkgs $ \Pkg{pkgName} -> do-            let s = unwords $ map (show . PU.showToken) $ cfgLocalGhcOptions config-            tellStrLns-                [ sh $ "echo 'package " ++ pkgName ++ "' >> cabal.project"-                , sh $ "echo '  ghc-options: " ++ s ++ "' >> cabal.project"-                ]--        -- also write cabal.project.local file with-        -- @-        -- constraints: base installed-        -- constraints: array installed-        -- ...-        ---        -- omitting any local package names-        tellStrLns-            [ sh $ "touch cabal.project.local"-            , sh $ unwords-                [ "if ! $NOINSTALLEDCONSTRAINTS; then"-                , "for pkg in $($HCPKG list --simple-output); do"-                , "echo $pkg"-                , concatMap (\Pkg{pkgName} -> " | grep -vw -- " ++ pkgName) pkgs-                , "| sed 's/^/constraints: /'"-                , "| sed 's/-[^-]*$/ installed/'"-                , ">> cabal.project.local; done; fi"-                ]-            ]--        tellStrLns-            [ sh $ "cat cabal.project || true"-            , sh $ "cat cabal.project.local || true"-            ]-      where-        cabalPaths-            | dist      = quotedPaths $ \Pkg{pkgName} -> pkgName ++ "-*/*.cabal"-            | otherwise = quotedPaths $ \Pkg{pkgDir}  -> pkgDir--    projectFile :: FilePath-    projectFile = fromMaybe "cabal.project" isCabalProject--    quotedPaths :: (Package -> FilePath) -> String-    quotedPaths f = unwords $ map (f . quote) pkgs-      where-        quote pkg = pkg{ pkgDir = "\"" ++ pkgDir pkg ++ "\"" }--    showVersions :: Set (Maybe Version) -> String-    showVersions = unwords . map dispGhcVersion . S.toList--    -- specified ersions-    osxVersions' :: Set Version-    osxVersions' = S.fromList $ mapMaybe simpleParse $ optOsx opts--    versions :: Set (Maybe Version)-    versions-        | cfgGhcHead config = S.insert Nothing $ S.map Just versions'-        | otherwise         = S.map Just versions'--    ghcVersions :: String-    ghcVersions = showVersions versions--    osxVersions, omittedOsxVersions :: Set Version-    (osxVersions, omittedOsxVersions) = S.partition (`S.member` versions') osxVersions'--    ghcOsxVersions :: String-    ghcOsxVersions = showVersions $ S.map Just osxVersions--    ghcOmittedOsxVersions :: String-    ghcOmittedOsxVersions = showVersions $ S.map Just omittedOsxVersions--    lookupCabVer :: Version -> Maybe Version-    lookupCabVer v = join $ lookup (ghcMajVer v) cabalVerMap---- | Modules arguments to the library------ * We check the library component------ * If there are hs-source-dirs, use them------ * otherwise use exposed + other modules------ * Also add default-extensions------ /Note:/ same argument work for hlint too!----doctestArgs :: GenericPackageDescription -> [String]-doctestArgs gpd = case PD.library $ flattenPackageDescription gpd of-    Nothing -> []-    Just l  -> exts ++ dirsOrMods-      where-        bi = PD.libBuildInfo l--        dirsOrMods-            | null (PD.hsSourceDirs bi) = map display (PD.exposedModules l)-            | otherwise = PD.hsSourceDirs bi--        exts = map (("-X" ++) . display) (PD.defaultExtensions bi)--collToGhcVer :: String -> Version-collToGhcVer cid = case simpleParse cid of-  Nothing -> error ("invalid collection-id syntax " ++ show cid)-  Just (PackageIdentifier n (versionNumbers -> v))-    | display n /= "lts" -> error ("unknown collection " ++ show cid)-    | isPrefixOf [0] v -> mkVersion [7,8,3]-    | isPrefixOf [1] v -> mkVersion [7,8,4]-    | isPrefixOf [2] v -> mkVersion [7,8,4]-    | isPrefixOf [3] v -> mkVersion [7,10,2]-    | isPrefixOf [4] v -> mkVersion [7,10,3]-    | isPrefixOf [5] v -> mkVersion [7,10,3]-    | isPrefixOf [6] v -> mkVersion [7,10,3]-    | isPrefixOf [7] v -> mkVersion [8,0,1]-    | otherwise -> error ("unknown collection " ++ show cid)------------------------------------------------------------------------------------ Jobs------------------------------------------------------------------------------------ | parse jobs defintion------ * N:M - N ghcs (cabal -j), M threads (ghc -j)------ >>> let parseJobs = maybeReadP parseJobsQ--- >>> parseJobs "2:2"--- Just (Just 2,Just 2)------ >>> parseJobs ":2"--- Just (Nothing,Just 2)------ >>> parseJobs "2"--- Just (Just 2,Nothing)------ >>> parseJobs "garbage"--- Nothing----parseJobsQ :: ReadP r (Maybe Int, Maybe Int)-parseJobsQ = nm <++ m <++ n <++ return (Nothing, Nothing)-  where-    nm = do-      x <- parseInt-      _ <- char ':'-      y <- parseInt-      return (Just x, Just y)--    m = do-      _ <- char ':'-      y <- parseInt-      return (Nothing, Just y)--    n = do-      x <- parseInt-      return (Just x, Nothing)------------------------------------------------------------------------------------ Project file----------------------------------------------------------------------------------data Project a = Project-    { prjPackages    :: [a]-    , prjConstraints :: Maybe String-    , prjAllowNewer  :: Maybe String-    }-  deriving (Show, Functor, F.Foldable, T.Traversable)--overPrjPackages :: ([a] -> [b]) -> Project a -> Project b-overPrjPackages f prj = prj { prjPackages = f (prjPackages prj) }--emptyProject :: Project [a]-emptyProject = Project [] Nothing Nothing---- | Parse project file. Extracts only @packages@ field.------ >>> fmap prjPackages $ parseProjectFile "cabal.project" "packages: foo bar/*.cabal"--- Right ["foo","bar/*.cabal"]----parseProjectFile :: FilePath -> String -> Either String (Project String)-parseProjectFile path contents =-    case PU.parseFields legacyProjectConfigFieldDescrs emptyProject contents of-        PU.ParseOk _ x -> Right x-        PU.ParseFailed err -> Left $ case PU.locatedErrorMsg err of-            (l, msg) -> "ERROR " ++ path ++ ":" ++ show l ++ ": " ++ msg--legacyProjectConfigFieldDescrs :: [PU.FieldDescr (Project String)]-legacyProjectConfigFieldDescrs =-    [ PU.listField "packages"-        (error "we don't pretty print") -- pretty-        parsePackageLocationTokenQ -- parse-        prjPackages-        (\x prj -> prj { prjPackages = x })-    , PU.simpleField "constraints"-        (error "we don't pretty print") -- pretty-        (fmap Just PU.parseFreeText)-        prjConstraints-        (\x prj -> prj { prjConstraints = maybeAlt2 commaConcat (prjConstraints prj) x })-    , PU.simpleField "allow-newer"-        (error "we don't pretty print") -- pretty-        (fmap Just PU.parseFreeText)-        prjAllowNewer-        (\x prj -> prj { prjAllowNewer = maybeAlt2 commaConcat (prjAllowNewer prj) x })-    ]-  where-    maybeAlt2 _ Nothing  x        = x-    maybeAlt2 _ x        Nothing  = x-    maybeAlt2 f (Just x) (Just y) = Just (f x y)--    commaConcat x y-        | all isSpace x = y-        | all isSpace y = x-        | otherwise     = x ++ ", " ++ y------------------------------------------------------------------------------------ Options----------------------------------------------------------------------------------data Options = Options-    { optCollections :: [String]-    , optOutput :: Maybe FilePath-    , optOsx :: [String]-    , optConfig :: Maybe FilePath-    , optConfigMorphism :: Config -> Config-    }--defOptions :: Options-defOptions = Options-    { optCollections = []-    , optOutput = Nothing-    , optOsx = []-    , optConfig = Nothing-    , optConfigMorphism = id-    }--options :: [OptDescr (Result Diagnostic (Options -> Options))]-options =-    [ Option [] ["no-cache"]-      (NoArg $ successCM $ \cfg -> cfg { cfgCache = False })-      "disable Travis caching"-    , Option [] ["no-cabal-noise"]-      (NoArg $ successCM $ \cfg -> cfg { cfgNoise = False })-      "remove cabal noise from test output"-    , Option [] ["no-cabal-check"]-      (NoArg $ successCM $ \cfg -> cfg { cfgCheck = False })-      "Disable cabal check"-    , Option [] ["no-install-dependencies"]-      (NoArg $ successCM $ \cfg -> cfg { cfgInstallDeps = False })-      "Disable installing dependencies in a seperate step"-    , Option [] ["no-no-tests-no-bench"]-      (NoArg $ successCM $ \cfg -> cfg { cfgNoTestsNoBench = False })-      "Don't build with --no-tests --no-benchmarks"-    , Option [] ["no-unconstrained"]-      (NoArg $ successCM $ \cfg -> cfg { cfgUnconstrainted = False })-      "Build also without 'installed' constraints"-    , Option [] ["ghc-head"]-      (NoArg $ successCM $ \cfg -> cfg { cfgGhcHead = True })-      "Build also with ghc-head"-    , Option ['c'] ["collection"]-      (ReqArg (success' $ \arg opts -> opts { optCollections = arg : optCollections opts }) "CID")-      "enable package collection(s) (e.g. 'lts-7'), use multiple times for multiple collections"-    , Option ['f'] ["fold"]-      (flip OptArg "FOLDS" $ \arg -> case arg of-        Nothing   -> successCM $ \cfg -> cfg { cfgFolds = S.fromList possibleFolds }-        Just arg' -> case maybeReadP parseFoldQ arg' of-            Nothing -> Failure [Error $ "cannot parse --fold argument: " ++ arg' ++ "\n"]-            Just f  -> successCM $ \cfg -> cfg { cfgFolds = f (cfgFolds cfg) })-      ("build output(s) to fold, use multiple times for multiple folds. No argument defaults to 'all'. Possible values: all, all-but-test, " ++ intercalate ", " (map showFold possibleFolds))-    , Option [] ["irc-channel"]-      (ReqArg (successCM' $ \arg cfg -> cfg { cfgIrcChannels = arg : cfgIrcChannels cfg }) "HOST#CHANNEL")-      "enable IRC notifcations to given channel (e.g. 'irc.freenode.org#haskell-lens'), use multiple times for multiple channels"-    , Option ['n'] ["name"]-      (ReqArg (successCM' $ \arg cfg -> cfg { cfgProjectName = Just arg }) "NAME")-      "project name (used for IRC notifications), defaults to package name or name of first package listed in cabal.project file"-    , Option ['b'] ["branch"]-      (ReqArg (successCM' $ \arg cfg -> cfg { cfgOnlyBranches = arg : cfgOnlyBranches cfg }) "BRANCH")-      "enable builds only for specific brances, use multiple times for multiple branches"-    , Option ['o'] ["output"]-      (ReqArg (success' $ \arg opts -> opts { optOutput = Just arg }) "OUTPUT")-      "output file (stdout if omitted)"-    , Option [] ["config"]-      (OptArg (success' $ \arg opts -> opts { optConfig = Just $ fromMaybe "cabal.make-travis-yml" arg }) "CONFIG")-      "config file, currently used only to specify constraint sets"-    , Option [] ["osx"]-      (ReqArg (success' $ \arg opts -> opts { optOsx = arg : optOsx opts }) "GHC")-      "generate osx build job with ghc version"-    , Option ['j'] ["jobs"]-      (reqArgReadP parseJobsQ (\jobs cfg -> cfg { cfgJobs = jobs }) "JOBS")-      "jobs (N:M - cabal:ghc)"-    , Option [] ["local-ghc-options"]-      (reqArgReadP parseOptsQ (\xs cfg -> cfg { cfgLocalGhcOptions = xs }) "OPTIONS")-      "--ghc-options for local packages"-    , Option ['d'] ["doctest"]-      (NoArg $ successCM $ \cfg -> cfg { cfgDoctest = True })-      "Run doctest using .ghc.environment files."-    , Option [] ["doctest-options"]-      (reqArgReadP parseOptsQ (\xs cfg -> cfg { cfgDoctestOptions = xs }) "OPTIONS")-      "Additional doctest options."-    , Option [] ["doctest-version"]-      (reqArgReadP parse (\arg cfg -> cfg { cfgDoctestVersion = arg }) "VERSION")-      "Doctest version range"-    , Option ['l'] ["hlint"]-      (NoArg $ successCM $ \cfg -> cfg { cfgHLint = True })-      "Run hlint (only on GHC-8.4.3 target)"-    , Option [] ["hlint-yaml"]-      (ReqArg (successCM' $ \arg cfg -> cfg { cfgHLintYaml = Just arg }) "HLINT.YAML")-      "Relative path to .hlint.yaml."-    , Option [] ["hlint-options"]-      (reqArgReadP parseOptsQ (\xs cfg -> cfg { cfgHLintOptions = xs }) "OPTIONS")-      "Additional hlint options."-    , Option [] ["hlint-version"]-      (reqArgReadP parse (\arg cfg -> cfg { cfgHLintVersion = arg }) "VERSION")-      "HLint version range"-    , Option [] ["cabal-install-version"]-      (reqArgReadP parse (\arg cfg -> cfg { cfgCabalInstallVersion = Just arg }) "VERSION")-      "cabal-install version for all jobs, overrides default"-    , Option [] ["cabal-install-head"]-      (NoArg $ successCM $ \cfg -> cfg { cfgCabalInstallVersion = Nothing })-      "Use cabal-install-head for all jobs, overrides default"-    , Option [] ["env"]-      (reqArgReadP envP (\(k, v) cfg -> cfg { cfgEnv = M.insert k v (cfgEnv cfg) }) "ENVDECL")-      "Environment (e.g. `8.0.2:HADDOCK=false`)"-    , Option [] ["allow-failure"]-      (reqArgReadP parse (\arg cfg -> cfg { cfgAllowFailures = S.insert arg (cfgAllowFailures cfg) }) "GHCVERSION")-      "Allow failures of particular GHC version"-    , Option [] ["last-in-series"]-      (NoArg $ successCM $ \cfg -> cfg { cfgLastInSeries = True })-      "[Discouraged] Assume there are only GHCs last in major series: 8.0.* will match only 8.2.2"-    ]-  where-    overCM f opts = opts-        { optConfigMorphism = f . optConfigMorphism opts-        }--    success' f arg = success (f arg)--    successCM = success . overCM-    successCM' f arg = successCM (f arg)--    reqArgReadP :: ReadP a a -> (a -> Config -> Config) -> String -> ArgDescr (Result Diagnostic (Options -> Options))-    reqArgReadP p f n = flip ReqArg n $ \arg -> case maybeReadP  p arg of-        Nothing -> Failure [Error $  "cannot parse: " ++ arg ]-        Just x  -> successCM' f x--    envP :: ReadP r (Version, String)-    envP = do-        ghc <- parse-        skipSpaces-        _ <- char ':'-        skipSpaces-        v <- munch (const True)-        return (ghc, v)------------------------------------------------------------------------------------ Result----------------------------------------------------------------------------------data Result e a-    = Success [e] a-    | Failure [e]-    deriving (Eq, Show, Functor)--success :: a -> Result e a-success = Success []--instance Monoid a => Mon.Monoid (Result e a) where-    mempty = success mempty-#if MIN_VERSION_base(4,9,0)-    mappend = (<>)--instance Monoid a => Semigroup (Result e a) where-    Failure err1   <> Failure err2   = Failure $ err1 <> err2-    Failure err1   <> Success err2 _ = Failure $ err1 <> err2-    Success err1 _ <> Failure err2   = Failure $ err1 <> err2-    Success l1 o1  <> Success l2 o2  = Success (mappend l1 l2) (mappend o1 o2)-#else-    Failure err1   `mappend` Failure err2   = Failure $ err1 `mappend` err2-    Failure err1   `mappend` Success err2 _ = Failure $ err1 `mappend` err2-    Success err1 _ `mappend` Failure err2   = Failure $ err1 `mappend` err2-    Success l1 o1  `mappend` Success l2 o2  = Success (mappend l1 l2) (mappend o1 o2)-#endif------------------------------------------------------------------------------------ Fold----------------------------------------------------------------------------------data Fold-    = FoldSDist-    | FoldUnpack-    | FoldBuild-    | FoldBuildInstalled-    | FoldBuildEverything-    | FoldTest-    | FoldHaddock-    | FoldStackage-    | FoldCheck-    | FoldDoctest-    | FoldHLint-    | FoldConstraintSets-  deriving (Eq, Ord, Show, Enum, Bounded)--showFold :: Fold -> String-showFold = dashise . drop 4 . show-  where-    dashise = intercalate "-" . map (map toLower) . split--    split [] = []-    split xs0 =-        let (ys, xs1) = span isUpper xs0-            (zs, xs2) = break isUpper xs1-        in (ys ++ zs) : split xs2--possibleFolds :: [Fold]-possibleFolds = [minBound .. maxBound]--parseFoldQ :: ReadP r (Set Fold -> Set Fold)-parseFoldQ = do-    t <- PU.parseTokenQ-    case t of-        "all"          -> return $ const $ S.fromList possibleFolds-        "all-but-test" -> return $ const $ S.delete FoldTest $ S.fromList possibleFolds-        n -> case M.lookup n ps of-            Just n' -> return (S.insert n')-            Nothing -> fail $ "Illegal fold name: " ++ n-  where-    ps = M.fromList $ map (\x -> (showFold x, x)) possibleFolds------------------------------------------------------------------------------------ Config file----------------------------------------------------------------------------------data Config = Config-    { cfgCabalInstallVersion :: Maybe Version-    , cfgHLint           :: !Bool-    , cfgHLintYaml       :: !(Maybe FilePath)-    , cfgHLintVersion    :: !VersionRange-    , cfgHLintOptions    :: [String]-    , cfgJobs            :: (Maybe Int, Maybe Int)-    , cfgDoctest         :: !Bool-    , cfgDoctestOptions  :: [String]-    , cfgDoctestVersion  :: !VersionRange-    , cfgLocalGhcOptions :: [String]-    , cfgConstraintSets  :: [ConstraintSet]-    , cfgCache           :: !Bool-    , cfgCheck           :: !Bool-    , cfgNoise           :: !Bool-    , cfgNoTestsNoBench  :: !Bool-    , cfgUnconstrainted  :: !Bool-    , cfgInstallDeps     :: !Bool-    , cfgOnlyBranches    :: [String]-    , cfgIrcChannels     :: [String]-    , cfgProjectName     :: Maybe String-    , cfgFolds           :: Set Fold-    , cfgGhcHead         :: !Bool-    , cfgEnv             :: M.Map Version String-    , cfgAllowFailures   :: S.Set Version-    , cfgLastInSeries    :: !Bool-    }-  deriving (Show)--emptyConfig :: Config-emptyConfig = Config-    { cfgCabalInstallVersion = Nothing-    , cfgHLint           = False-    , cfgHLintYaml       = Nothing-    , cfgHLintVersion    = defaultHLintVersion-    , cfgHLintOptions    = []-    , cfgJobs            = (Nothing, Nothing)-    , cfgDoctest         = False-    , cfgDoctestOptions  = []-    , cfgDoctestVersion  = defaultDoctestVersion-    , cfgLocalGhcOptions = []-    , cfgConstraintSets  = []-    , cfgCache           = True-    , cfgCheck           = True-    , cfgNoise           = True-    , cfgNoTestsNoBench  = True-    , cfgUnconstrainted  = True-    , cfgInstallDeps     = True-    , cfgOnlyBranches    = []-    , cfgIrcChannels     = []-    , cfgProjectName     = Nothing-    , cfgFolds           = S.empty-    , cfgGhcHead         = False-    , cfgEnv             = M.empty-    , cfgAllowFailures   = S.empty-    , cfgLastInSeries    = False-    }--configFieldDescrs :: [PU.FieldDescr Config]-configFieldDescrs =-    [ PU.simpleField  "jobs"-        (error "we don't pretty print")-        parseJobsQ-        cfgJobs-        (\x cfg -> cfg { cfgJobs = x })-    , PU.boolField  "hlint"-        cfgHLint-        (\b cfg -> cfg { cfgHLint = b })-    , PU.simpleField "hlint-yaml"-        (error "we don't pretty print")-        (fmap Just PU.parseFilePathQ)-        cfgHLintYaml-        (\x cfg -> cfg { cfgHLintYaml = x })-    , PU.simpleField "hlint-version"-        (error "we don't pretty print")-        parse-        cfgHLintVersion-        (\x cfg -> cfg { cfgHLintVersion = x })-    -- TODO: hlint-options-    , PU.boolField  "doctest"-        cfgDoctest-        (\b cfg -> cfg { cfgDoctest = b })-    , PU.simpleField "doctest-options"-        (error "we don't pretty print")-        parseOptsQ-        cfgDoctestOptions-        (\x cfg -> cfg { cfgDoctestOptions = cfgDoctestOptions cfg ++ x })-    , PU.simpleField "doctest-version"-        (error "we don't pretty print")-        parse-        cfgDoctestVersion-        (\x cfg -> cfg { cfgDoctestVersion = x })-    , PU.simpleField "cabal-install-version"-        (error "we don't pretty print")-        (fmap Just parse)-        cfgCabalInstallVersion-        (\x cfg -> cfg { cfgCabalInstallVersion = x })-    , PU.simpleField "local-ghc-options"-        (error "we don't pretty print")-        parseOptsQ-        cfgLocalGhcOptions-        (\x cfg -> cfg { cfgLocalGhcOptions = cfgLocalGhcOptions cfg ++ x })-    , PU.boolField  "cache"-        cfgCache-        (\b cfg -> cfg { cfgCache = b })-    , PU.boolField  "cabal-noise"-        cfgNoise-        (\b cfg -> cfg { cfgNoise = b })-    , PU.boolField  "cabal-check"-        cfgCheck-        (\b cfg -> cfg { cfgCheck = b })-    , PU.boolField  "install-dependencies-step"-        cfgInstallDeps-        (\b cfg -> cfg { cfgInstallDeps = b })-    , PU.boolField  "no-tests-no-benchmarks"-        cfgNoTestsNoBench-        (\b cfg -> cfg { cfgNoTestsNoBench = b })-    , PU.boolField  "unconstrained-step"-        cfgUnconstrainted-        (\b cfg -> cfg { cfgUnconstrainted = b })-    , PU.listField  "irc-channels"-        (error "we don't pretty print")-        PU.parseTokenQ-        cfgIrcChannels-        (\x cfg -> cfg { cfgIrcChannels = x })-    , PU.simpleField "name"-        (error "we don't pretty print")-        (fmap Just PU.parseTokenQ)-        cfgProjectName-        (\x cfg -> cfg { cfgProjectName = x })-    , PU.listField  "branches"-        (error "we don't pretty print")-        PU.parseTokenQ-        cfgOnlyBranches-        (\x cfg -> cfg { cfgOnlyBranches = x })-    , PU.simpleField  "folds"-        (error "we don't pretty print")-        (sepBy parseFoldQ (munch1 isSpace))-        (\cfg -> [\_ -> cfgFolds cfg])-        (\x cfg -> cfg { cfgFolds = foldl' (flip id) (cfgFolds cfg) x })-    , PU.boolField "ghc-head"-        cfgGhcHead-        (\b cfg -> cfg { cfgGhcHead = b })-    -- , PU.simpleField "env" -- TODO-    ]--parseOptsQ :: ReadP r [String]-parseOptsQ = sepBy PU.parseTokenQ' (munch1 isSpace)--readConfigFile :: MonadIO m => FilePath -> YamlWriter m Config-readConfigFile path = do-    contents <- liftIO $ readFile path-    parseConfigFile path contents--parseConfigFile :: Monad m => FilePath -> String -> YamlWriter m Config-parseConfigFile path contents = toWriter $ do-    fields' <- PU.readFields contents-    let (fields, sections) = partitionEithers (map classify fields')-    config <- accumFields configFieldDescrs emptyConfig fields-    go config sections-  where-    toWriter r = case r of-        PU.ParseOk ws x -> do-            forM_ ws $ \w -> putStrLnWarn (PU.showPWarning path w)-            return x-        PU.ParseFailed err -> case PU.locatedErrorMsg err of-            (l, msg) -> putStrLnErr $ path ++ ":" ++ show l ++ ": " ++ msg--    classify x@PU.IfBlock {} = Right x-    classify x@PU.Section {} = Right x-    classify x@PU.F {}       = Left x--    go :: Config -> [PU.Field] -> PU.ParseResult Config-    go  cfg [] = return cfg-    go _cfg (PU.IfBlock {} : _fields) = fail "if conditional found"-    go  cfg (PU.F {} : fields)        = go cfg fields-    go  cfg (PU.Section line name arg subfields : fields)-        | name == "constraint-set" = do-            cs <- accumFields constraintSetFieldDescrs (emptyConstraintSet arg) subfields-            let cfg' = cfg { cfgConstraintSets = cfgConstraintSets cfg ++ [cs] }-            go cfg' fields-        | otherwise = do-            PU.warning $ "Unknown section " ++ name ++ " on line " ++ show line-            go cfg fields------------------------------------------------------------------------------------ ConstraintSet----------------------------------------------------------------------------------data ConstraintSet = ConstraintSet-    { csName        :: String-    , csGhcVersions :: VersionRange-    , csConstraints :: [String] -- we parse these simply as strings-    }-  deriving (Show)--emptyConstraintSet :: String -> ConstraintSet-emptyConstraintSet n = ConstraintSet n anyVersion []--constraintSetFieldDescrs :: [PU.FieldDescr ConstraintSet]-constraintSetFieldDescrs =-    [ PU.listField "constraints"-        (error "we don't pretty print") -- pretty-        (parseHaskellString <++ munch1 (`notElem` [',', '"']))-        csConstraints-        (\c cs -> cs { csConstraints = csConstraints cs ++ c })-    , PU.simpleField "ghc"-        (error "we don't pretty print") -- pretty-        Distribution.Text.parse-        csGhcVersions-        (\c cs -> cs { csGhcVersions = c })-    ]--ghcVersionPredicate :: VersionRange -> String-ghcVersionPredicate = conj . asVersionIntervals-  where-    conj = intercalate "  ||  " . map disj--    disj :: VersionInterval -> String-    disj (LowerBound v InclusiveBound, UpperBound u InclusiveBound)-        | v == u              = "[ $HCNUMVER -eq " ++ f v ++ " ]"-    disj (lb, NoUpperBound)   = lower lb-    disj (lb, UpperBound v b) = lower lb ++ " && " ++ upper v b--    lower (LowerBound v InclusiveBound) = "[ $HCNUMVER -ge " ++ f v ++ " ]"-    lower (LowerBound v ExclusiveBound) = "[ $HCNUMVER -gt " ++ f v ++ " ]"--    upper v InclusiveBound = "[ $HCNUMVER -le " ++ f v ++ " ]"-    upper v ExclusiveBound = "[ $HCNUMVER -lt " ++ f v ++ " ]"--    f v =  case versionNumbers v of-        []        -> "0"-        [x]       -> show (x * 10000)-        [x,y]     -> show (x * 10000 + y * 100)-        (x:y:z:_) -> show (x * 10000 + y * 100 + z)------------------------------------------------------------------------------------ From Cabal----------------------------------------------------------------------------------accumFields :: [PU.FieldDescr a] -> a -> [PU.Field] -> PU.ParseResult a-accumFields fields = foldM setField-  where-    fieldMap = M.fromList-        [ (name, f) | f@(PU.FieldDescr name _ _) <- fields ]-    setField accum (PU.F line name value) = case M.lookup name fieldMap of-      Just (PU.FieldDescr _ _ set) -> set line value accum-      Nothing -> do-          PU.warning $ "Unrecognized field " ++ name ++ " on line " ++ show line-          return accum-    setField accum f = do-        PU.warning ("Unrecognized stanza on line " ++ show (PU.lineNo f))-        return accum------------------------------------------------------------------------------------ From cabal-install------------------------------------------------------------------------------------ | This is a bit tricky since it has to cover globs which have embedded @,@--- chars. But we don't just want to parse strictly as a glob since we want to--- allow http urls which don't parse as globs, and possibly some--- system-dependent file paths. So we parse fairly liberally as a token, but--- we allow @,@ inside matched @{}@ braces.----parsePackageLocationTokenQ :: ReadP r String-parsePackageLocationTokenQ = parseHaskellString <++ parsePackageLocationToken-  where-    parsePackageLocationToken :: ReadP r String-    parsePackageLocationToken = fmap fst (gather outerTerm)-      where-        outerTerm   = alternateEither1 outerToken (braces innerTerm)-        innerTerm   = alternateEither  innerToken (braces innerTerm)-        outerToken  = void $ munch1 outerChar-        innerToken  = void $ munch1 innerChar-        outerChar c = not (isSpace c || c == '{' || c == '}' || c == ',')-        innerChar c = not (isSpace c || c == '{' || c == '}')-        braces      = between (char '{') (char '}')--    alternateEither, alternateEither1,-      alternatePQs, alternate1PQs, alternateQsP, alternate1QsP-      :: ReadP r () -> ReadP r () -> ReadP r ()--    alternateEither1 p q = alternate1PQs p q +++ alternate1QsP q p-    alternateEither  p q = alternateEither1 p q +++ return ()-    alternate1PQs    p q = p >> alternateQsP q p-    alternatePQs     p q = alternate1PQs p q +++ return ()-    alternate1QsP    q p = many1 q >> alternatePQs p q-    alternateQsP     q p = alternate1QsP q p +++ return ()--parseHaskellString :: ReadP r String-parseHaskellString = readS_to_P reads--parseInt :: ReadP r Int-parseInt = readS_to_P reads------------------------------------------------------------------------------------ Glob----------------------------------------------------------------------------------{---Globbing code and grammar judiciously stolen from cabal-install:--FilePathGlob    ::= FilePathRoot FilePathGlobRel-FilePathRoot    ::= {- empty -}        # relative to cabal.project-                  | "/"                # Unix root-                  | [a-zA-Z] ":" [/\\] # Windows root-                  | "~"                # home directory--FilePathGlobRel ::= Glob "/"  FilePathGlobRel # Unix directory-                  | Glob "\\" FilePathGlobRel # Windows directory-                  | Glob         # file-                  | {- empty -}  # trailing slash--Glob      ::= GlobPiece *-GlobPiece ::= "*"            # wildcard-            | [^*{},/\\] *   # literal string-            | "\\" [*{},]    # escaped reserved character-            | "{" Glob "," ... "," Glob "}" # union (match any of these)--}--data FilePathGlob = FilePathGlob FilePathRoot FilePathGlobRel-  deriving (Eq, Show)--data FilePathGlobRel-   = GlobDir  Glob FilePathGlobRel-   | GlobFile Glob-   | GlobDirTrailing -- trailing dir, a glob ending in '/'-  deriving (Eq, Show)---- | A single directory or file component of a globbed path-type Glob = [GlobPiece]---- | A piece of a globbing pattern-data GlobPiece = WildCard-               | Literal String-               | Union [Glob]-  deriving (Eq, Show)--data FilePathRoot-   = FilePathRelative-   | FilePathRoot FilePath -- e.g. '/', 'c:\' or result of 'takeDrive'-   | FilePathHomeDir-  deriving (Eq, Show)--parseFilePathGlobRel :: ReadP r FilePathGlobRel-parseFilePathGlobRel =-      parseGlob >>= \globpieces ->-          asDir globpieces-      <++ asTDir globpieces-      <++ asFile globpieces-  where-    asDir  glob = do dirSep-                     GlobDir glob <$> parseFilePathGlobRel-    asTDir glob = do dirSep-                     return (GlobDir glob GlobDirTrailing)-    asFile glob = return (GlobFile glob)--    dirSep = void (char '/')-         +++ (do _ <- char '\\'-                 -- check this isn't an escape code-                 following <- look-                 case following of-                   (c:_) | isGlobEscapedChar c -> pfail-                   _                           -> return ())--parseGlob :: ReadP r Glob-parseGlob = many1 parsePiece-  where-    parsePiece = literal +++ wildcard +++ union'--    wildcard = char '*' >> return WildCard--    union' = between (char '{') (char '}') $-              fmap Union (sepBy1 parseGlob (char ','))--    literal = Literal `fmap` litchars1--    litchar = normal +++ escape--    normal  = satisfy (\c -> not (isGlobEscapedChar c)-                                && c /= '/' && c /= '\\')-    escape  = char '\\' >> satisfy isGlobEscapedChar--    litchars1 :: ReadP r [Char]-    litchars1 = liftM2 (:) litchar litchars--    litchars :: ReadP r [Char]-    litchars = litchars1 <++ return []--isGlobEscapedChar :: Char -> Bool-isGlobEscapedChar '*'  = True-isGlobEscapedChar '{'  = True-isGlobEscapedChar '}'  = True-isGlobEscapedChar ','  = True-isGlobEscapedChar _    = False--expandRelGlob :: MonadIO m => FilePath -> FilePathGlobRel -> m [FilePath]-expandRelGlob root glob0 = liftIO $ go glob0 ""-  where-    go (GlobFile glob) dir = do-      entries <- getDirectoryContents (root </> dir)-      let files = filter (matchGlob glob) entries-      return (map (dir </>) files)--    go (GlobDir glob globPath) dir = do-      entries <- getDirectoryContents (root </> dir)-      subdirs <- filterM (\subdir -> doesDirectoryExist-                                       (root </> dir </> subdir))-               $ filter (matchGlob glob) entries-      concat App.<$> mapM (\subdir -> go globPath (dir </> subdir)) subdirs--    go GlobDirTrailing dir = return [dir]--matchGlob :: Glob -> FilePath -> Bool-matchGlob = goStart-  where-    -- From the man page, glob(7):-    --   "If a filename starts with a '.', this character must be-    --    matched explicitly."--    go, goStart :: [GlobPiece] -> String -> Bool--    goStart (WildCard:_) ('.':_)  = False-    goStart (Union globs:rest) cs = any (\glob -> goStart (glob ++ rest) cs)-                                        globs-    goStart rest               cs = go rest cs--    go []                 ""    = True-    go (Literal lit:rest) cs-      | Just cs' <- stripPrefix lit cs-                                = go rest cs'-      | otherwise               = False-    go [WildCard]         ""    = True-    go (WildCard:rest)   (c:cs) = go rest (c:cs) || go (WildCard:rest) cs-    go (Union globs:rest)   cs  = any (\glob -> go (glob ++ rest) cs) globs-    go []                (_:_)  = False-    go (_:_)              ""    = False
test/Tests.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE ViewPatterns #-} module Main (main) where -import MakeTravisYml hiding (main)+import HaskellCI hiding (main)  import Control.Applicative ((<$>), (<*>)) import Control.Exception (ErrorCall(..), throwIO, try)@@ -12,7 +12,6 @@ import Data.List (isPrefixOf, stripPrefix) import Data.Maybe (mapMaybe) import Data.Monoid (mconcat)-import System.Console.GetOpt (getOpt, ArgOrder(Permute)) import System.Directory (doesFileExist, removeFile, setCurrentDirectory) import System.Exit (ExitCode(..), exitFailure) import System.FilePath (addExtension, (</>))@@ -33,6 +32,11 @@         , fixtureGoldenTest "cabal.project.empty-line"         , fixtureGoldenTest "cabal.project.fail-versions"         , fixtureGoldenTest "cabal.project.messy"+        , testGroup "copy-fields"+            [ fixtureGoldenTest "cabal.project.copy-fields.all"+            , fixtureGoldenTest "cabal.project.copy-fields.some"+            , fixtureGoldenTest "cabal.project.copy-fields.none"+            ]         ]  linesToArgv :: String -> Maybe [String]@@ -51,8 +55,8 @@ -- @ fixtureGoldenTest :: FilePath -> TestTree fixtureGoldenTest fp = cabalGoldenTest fp outputRef errorRef $ do-    (argv, opts, xpkgs) <- makeTravisFlags-    let genConfig = travisFromConfigFile (argv, opts) fp xpkgs+    (argv, opts) <- makeTravisFlags+    let genConfig = travisFromConfigFile argv opts fp     execWriterT (runMaybeT genConfig)   where     outputRef = addExtension fp "travis.yml"@@ -63,17 +67,19 @@         | refExists = (linesToArgv . BS8.unpack) `fmap` BS.readFile outputRef         | otherwise = return $ Just [fp] -    makeTravisFlags :: IO ([String], Options, [String])+    makeTravisFlags :: IO ([String], Options)     makeTravisFlags = do         result <- doesFileExist outputRef >>= referenceArgv         case result of             Nothing -> throwIO (ErrorCall "No REGENDATA in result file.")             Just argv -> do-                (opts, _argv, _fp, xpkgs) <- parseOpts argv-                return (argv, opts, xpkgs)+                (opts, _fp) <- parseOpts argv+                return (argv, opts) -parseOpts :: [String] -> IO (Options, [String], FilePath, [String])-parseOpts = parseOptsNoCommands+parseOpts :: [String] -> IO (Options, FilePath)+parseOpts argv = do+    (path, opts) <- parseTravis argv+    return (opts, path)  cabalGoldenTest     :: TestName