diff --git a/src/Stack/Build/ConstructPlan.hs b/src/Stack/Build/ConstructPlan.hs index e5818352c6..e982e2e1c7 100644 --- a/src/Stack/Build/ConstructPlan.hs +++ b/src/Stack/Build/ConstructPlan.hs @@ -19,7 +19,6 @@ import Control.Monad.IO.Class import Control.Monad.Logger (MonadLogger, logWarn) import Control.Monad.RWS.Strict import Control.Monad.Trans.Resource -import qualified Data.ByteString.Char8 as S8 import Data.Either import Data.Function import Data.List @@ -180,7 +179,7 @@ constructPlan mbp0 baseConfigOpts0 locals extraToBuild0 localDumpPkgs loadPackag , combinedMap = combineMap sourceMap installedMap , toolToPackages = \ (Dependency name _) -> maybe Map.empty (Map.fromSet (const anyVersion)) $ - Map.lookup (S8.pack . packageNameString . fromCabalPackageName $ name) toolMap + Map.lookup (T.pack . packageNameString . fromCabalPackageName $ name) toolMap , ctxEnvConfig = econfig , callStack = [] , extraToBuild = extraToBuild0 diff --git a/src/Stack/Build/Execute.hs b/src/Stack/Build/Execute.hs index e32e88de8f..d8ca91e678 100644 --- a/src/Stack/Build/Execute.hs +++ b/src/Stack/Build/Execute.hs @@ -24,19 +24,20 @@ import Control.Concurrent.MVar.Lifted import Control.Concurrent.STM import Control.Exception.Enclosed (catchIO, tryIO) import Control.Exception.Lifted -import Control.Monad (liftM, when, unless, void, join, guard, filterM, (<=<)) +import Control.Monad (liftM, when, unless, void, join, filterM, (<=<)) import Control.Monad.Catch (MonadCatch, MonadMask) import Control.Monad.IO.Class import Control.Monad.Logger import Control.Monad.Reader (MonadReader, asks) import Control.Monad.Trans.Control (liftBaseWith) import Control.Monad.Trans.Resource -import Data.ByteString (ByteString) +import Data.Attoparsec.Text import qualified Data.ByteString as S -import qualified Data.ByteString.Char8 as S8 import Data.Conduit import qualified Data.Conduit.Binary as CB import qualified Data.Conduit.List as CL +import qualified Data.Conduit.Text as CT +import Data.Either (isRight) import Data.Foldable (forM_, any) import Data.Function import Data.IORef.RunOnce (runOnce) @@ -55,7 +56,6 @@ import qualified Data.Text as T import Data.Text.Encoding (decodeUtf8) import Data.Time.Clock (getCurrentTime) import Data.Traversable (forM) -import Data.Word8 (_colon) import qualified Distribution.PackageDescription as C import Distribution.System (OS (Windows), Platform (Platform)) @@ -828,6 +828,7 @@ withSingleContext runInBase ActionContext {..} ExecuteEnv {..} task@Task {..} md liftIO $ hClose h runResourceT $ CB.sourceFile (toFilePath logFile) + =$= CT.decodeUtf8 $$ mungeBuildOutput stripTHLoading makeAbsolute pkgDir =$ CL.consume throwM $ CabalExitedUnsuccessfully @@ -1297,7 +1298,8 @@ singleBench runInBase beopts benchesToRun ac ee task installedMap = do -- | Grab all output from the given @Handle@ and log it, stripping -- Template Haskell "Loading package" lines and making paths absolute. -- thread. -printBuildOutput :: (MonadIO m, MonadBaseControl IO m, MonadLogger m) +printBuildOutput :: (MonadIO m, MonadBaseControl IO m, MonadLogger m, + MonadThrow m) => Bool -- ^ exclude TH loading? -> Bool -- ^ convert paths to absolute? -> Path Abs Dir -- ^ package's root directory @@ -1306,7 +1308,8 @@ printBuildOutput :: (MonadIO m, MonadBaseControl IO m, MonadLogger m) -> m () printBuildOutput excludeTHLoading makeAbsolute pkgDir level outH = void $ CB.sourceHandle outH - $$ mungeBuildOutput excludeTHLoading makeAbsolute pkgDir + $$ CT.decodeUtf8 + =$ mungeBuildOutput excludeTHLoading makeAbsolute pkgDir =$ CL.mapM_ (monadLoggerLog $(TH.location >>= liftLoc) "" level) -- | Strip Template Haskell "Loading package" lines and making paths absolute. @@ -1314,52 +1317,47 @@ mungeBuildOutput :: MonadIO m => Bool -- ^ exclude TH loading? -> Bool -- ^ convert paths to absolute? -> Path Abs Dir -- ^ package's root directory - -> ConduitM ByteString ByteString m () + -> ConduitM Text Text m () mungeBuildOutput excludeTHLoading makeAbsolute pkgDir = void $ - CB.lines + CT.lines =$ CL.map stripCarriageReturn =$ CL.filter (not . isTHLoading) =$ CL.mapM toAbsolutePath where -- | Is this line a Template Haskell "Loading package" line -- ByteString - isTHLoading :: S8.ByteString -> Bool + isTHLoading :: Text -> Bool isTHLoading _ | not excludeTHLoading = False isTHLoading bs = - "Loading package " `S8.isPrefixOf` bs && - ("done." `S8.isSuffixOf` bs || "done.\r" `S8.isSuffixOf` bs) + "Loading package " `T.isPrefixOf` bs && + ("done." `T.isSuffixOf` bs || "done.\r" `T.isSuffixOf` bs) -- | Convert GHC error lines with file paths to have absolute file paths toAbsolutePath bs | not makeAbsolute = return bs toAbsolutePath bs = do - let (x, y) = S.break (== _colon) bs + let (x, y) = T.break (== ':') bs mabs <- if isValidSuffix y then do - efp <- liftIO $ tryIO $ resolveFile pkgDir (S8.unpack x) + efp <- liftIO $ tryIO $ resolveFile pkgDir (T.unpack x) case efp of Left _ -> return Nothing - Right fp -> return $ Just $ S8.pack (toFilePath fp) + Right fp -> return $ Just $ T.pack (toFilePath fp) else return Nothing case mabs of Nothing -> return bs - Just fp -> return $ fp `S.append` y + Just fp -> return $ fp `T.append` y -- | Match the line:column format at the end of lines - isValidSuffix bs0 = maybe False (const True) $ do - guard $ not $ S.null bs0 - guard $ S.head bs0 == _colon - (_, bs1) <- S8.readInt $ S.drop 1 bs0 - - guard $ not $ S.null bs1 - guard $ S.head bs1 == _colon - (_, bs2) <- S8.readInt $ S.drop 1 bs1 - - guard $ (bs2 == ":" || bs2 == ": Warning:") + isValidSuffix = isRight . parseOnly (lineCol <* endOfInput) + lineCol = char ':' >> (decimal :: Parser Int) + >> char ':' >> (decimal :: Parser Int) + >> (string ":" <|> string ": Warning:") + >> return () -- | Strip @\r@ characters from the byte vector. Used because Windows. - stripCarriageReturn :: ByteString -> ByteString - stripCarriageReturn = S8.filter (not . (=='\r')) + stripCarriageReturn :: Text -> Text + stripCarriageReturn = T.filter (/= '\r') -- | Find the Setup.hs or Setup.lhs in the given directory. If none exists, -- throw an exception. diff --git a/src/Stack/BuildPlan.hs b/src/Stack/BuildPlan.hs index 11997cfd0b..1b9e5ef1ef 100644 --- a/src/Stack/BuildPlan.hs +++ b/src/Stack/BuildPlan.hs @@ -53,6 +53,7 @@ import Data.Maybe (fromMaybe, mapMaybe) import Data.Monoid import Data.Set (Set) import qualified Data.Set as Set +import Data.Text (Text) import qualified Data.Text as T import Data.Text.Encoding (encodeUtf8) import Data.Time (Day) @@ -283,7 +284,7 @@ addDeps allowMissing compilerVersion toCalc = do } name = packageIdentifierName ident pd = resolvePackageDescription packageConfig gpd - exes = Set.fromList $ map (ExeName . S8.pack . exeName) $ executables pd + exes = Set.fromList $ map (ExeName . T.pack . exeName) $ executables pd notMe = Set.filter (/= name) . Map.keysSet return (name, MiniPackageInfo { mpiVersion = packageIdentifierVersion ident @@ -368,7 +369,7 @@ getDeps mbp isShadowed packages = type ToolMap = Map ByteString (Set PackageName) -- | Map from tool name to package providing it -getToolMap :: MiniBuildPlan -> Map ByteString (Set PackageName) +getToolMap :: MiniBuildPlan -> Map Text (Set PackageName) getToolMap mbp = Map.unionsWith Set.union diff --git a/src/Stack/GhcPkg.hs b/src/Stack/GhcPkg.hs index 95d158bdc7..26d604a848 100644 --- a/src/Stack/GhcPkg.hs +++ b/src/Stack/GhcPkg.hs @@ -134,7 +134,7 @@ findGhcPkgVersion :: (MonadIO m, MonadLogger m, MonadBaseControl IO m, MonadCatc findGhcPkgVersion menv wc pkgDbs name = do mv <- findGhcPkgField menv wc pkgDbs (packageNameString name) "version" case mv of - Just !v -> return (parseVersion (T.encodeUtf8 v)) + Just !v -> return (parseVersion v) _ -> return Nothing unregisterGhcPkgId :: (MonadIO m, MonadLogger m, MonadThrow m, MonadCatch m, MonadBaseControl IO m) diff --git a/src/Stack/Package.hs b/src/Stack/Package.hs index 216ce4b5ae..0a9e764bca 100644 --- a/src/Stack/Package.hs +++ b/src/Stack/Package.hs @@ -445,10 +445,10 @@ packageDependencies = allBuildInfo' -- | Get all build tool dependencies of the package (buildable targets only). -packageToolDependencies :: PackageDescription -> Map BS.ByteString VersionRange +packageToolDependencies :: PackageDescription -> Map Text VersionRange packageToolDependencies = M.fromList . - concatMap (fmap (packageNameByteString . depName &&& depRange) . + concatMap (fmap (packageNameText . depName &&& depRange) . buildTools) . allBuildInfo' diff --git a/src/Stack/PackageDump.hs b/src/Stack/PackageDump.hs index f353bd53de..343e010463 100644 --- a/src/Stack/PackageDump.hs +++ b/src/Stack/PackageDump.hs @@ -35,12 +35,9 @@ import Control.Monad.Trans.Control import Data.Attoparsec.Args import Data.Attoparsec.Text as P import Data.Binary.VersionTagged -import Data.ByteString (ByteString) -import qualified Data.ByteString as S -import qualified Data.ByteString.Char8 as S8 import Data.Conduit -import qualified Data.Conduit.Binary as CB import qualified Data.Conduit.List as CL +import qualified Data.Conduit.Text as CT import Data.Either (partitionEithers) import Data.IORef import Data.Map (Map) @@ -48,7 +45,8 @@ import qualified Data.Map as Map import Data.Maybe (catMaybes, listToMaybe) import Data.Maybe.Extra (mapMaybeM) import qualified Data.Set as Set -import qualified Data.Text.Encoding as T +import qualified Data.Text as T +import Data.Text (Text) import Data.Typeable (Typeable) import GHC.Generics (Generic) import Path @@ -83,7 +81,7 @@ ghcPkgDump => EnvOverride -> WhichCompiler -> [Path Abs Dir] -- ^ if empty, use global - -> Sink ByteString IO a + -> Sink Text IO a -> m a ghcPkgDump = ghcPkgCmdArgs ["dump"] @@ -94,7 +92,7 @@ ghcPkgDescribe -> EnvOverride -> WhichCompiler -> [Path Abs Dir] -- ^ if empty, use global - -> Sink ByteString IO a + -> Sink Text IO a -> m a ghcPkgDescribe pkgName = ghcPkgCmdArgs ["describe", "--simple-output", packageNameString pkgName] @@ -105,13 +103,13 @@ ghcPkgCmdArgs -> EnvOverride -> WhichCompiler -> [Path Abs Dir] -- ^ if empty, use global - -> Sink ByteString IO a + -> Sink Text IO a -> m a ghcPkgCmdArgs cmd menv wc mpkgDbs sink = do case reverse mpkgDbs of (pkgDb:_) -> createDatabase menv wc pkgDb -- TODO maybe use some retry logic instead? _ -> return () - sinkProcessStdout Nothing menv (ghcPkgExeName wc) args sink + sinkProcessStdout Nothing menv (ghcPkgExeName wc) args sink' where args = concat [ case mpkgDbs of @@ -121,6 +119,7 @@ ghcPkgCmdArgs cmd menv wc mpkgDbs sink = do , cmd , ["--expand-pkgroot"] ] + sink' = CT.decodeUtf8 =$= sink -- | Create a new, empty @InstalledCache@ newInstalledCache :: MonadIO m => m InstalledCache @@ -233,12 +232,12 @@ addProfiling (InstalledCache ref) = return dp { dpProfiling = p } isProfiling :: FilePath -- ^ entry in directory - -> ByteString -- ^ name of library + -> Text -- ^ name of library -> Bool isProfiling content lib = - prefix `S.isPrefixOf` S8.pack content + prefix `T.isPrefixOf` T.pack content where - prefix = S.concat ["lib", lib, "_p"] + prefix = T.concat ["lib", lib, "_p"] -- | Add haddock information to the stream of @DumpPackage@s addHaddock :: MonadIO m @@ -268,7 +267,7 @@ data DumpPackage profiling haddock = DumpPackage { dpGhcPkgId :: !GhcPkgId , dpPackageIdent :: !PackageIdentifier , dpLibDirs :: ![FilePath] - , dpLibraries :: ![ByteString] + , dpLibraries :: ![Text] , dpHasExposedModules :: !Bool , dpDepends :: ![GhcPkgId] , dpHaddockInterfaces :: ![FilePath] @@ -280,8 +279,8 @@ data DumpPackage profiling haddock = DumpPackage deriving (Show, Eq, Ord) data PackageDumpException - = MissingSingleField ByteString (Map ByteString [Line]) - | Couldn'tParseField ByteString [Line] + = MissingSingleField Text (Map Text [Line]) + | Couldn'tParseField Text [Line] deriving Typeable instance Exception PackageDumpException instance Show PackageDumpException where @@ -298,7 +297,7 @@ instance Show PackageDumpException where -- | Convert a stream of bytes into a stream of @DumpPackage@s conduitDumpPackage :: MonadThrow m - => Conduit ByteString m (DumpPackage () ()) + => Conduit Text m (DumpPackage () ()) conduitDumpPackage = (=$= CL.catMaybes) $ eachSection $ do pairs <- eachPair (\k -> (k, ) <$> CL.consume) =$= CL.consume let m = Map.fromList pairs @@ -310,15 +309,15 @@ conduitDumpPackage = (=$= CL.catMaybes) $ eachSection $ do -- https://github.com/fpco/stack/issues/182 parseM k = Map.findWithDefault [] k m - parseDepend :: MonadThrow m => ByteString -> m (Maybe GhcPkgId) + parseDepend :: MonadThrow m => Text -> m (Maybe GhcPkgId) parseDepend "builtin_rts" = return Nothing parseDepend bs = liftM Just $ parseGhcPkgId bs' where (bs', _builtinRts) = - case stripSuffixBS " builtin_rts" bs of + case stripSuffixText " builtin_rts" bs of Nothing -> - case stripPrefixBS "builtin_rts " bs of + case stripPrefixText "builtin_rts " bs of Nothing -> (bs, False) Just x -> (x, True) Just x -> (x, True) @@ -337,7 +336,7 @@ conduitDumpPackage = (=$= CL.catMaybes) $ eachSection $ do depends <- mapMaybeM parseDepend $ parseM "depends" let parseQuoted key = - case mapM (P.parseOnly (argsParser NoEscaping) . T.decodeUtf8) val of + case mapM (P.parseOnly (argsParser NoEscaping)) val of Left{} -> throwM (Couldn'tParseField key val) Right dirs -> return (concat dirs) where @@ -350,7 +349,7 @@ conduitDumpPackage = (=$= CL.catMaybes) $ eachSection $ do { dpGhcPkgId = ghcPkgId , dpPackageIdent = PackageIdentifier name version , dpLibDirs = libDirPaths - , dpLibraries = S8.words $ S8.unwords libraries + , dpLibraries = T.words $ T.unwords libraries , dpHasExposedModules = not (null libraries || null exposedModules) , dpDepends = depends , dpHaddockInterfaces = haddockInterfaces @@ -360,34 +359,33 @@ conduitDumpPackage = (=$= CL.catMaybes) $ eachSection $ do , dpIsExposed = exposed == ["True"] } -stripPrefixBS :: ByteString -> ByteString -> Maybe ByteString -stripPrefixBS x y - | x `S.isPrefixOf` y = Just $ S.drop (S.length x) y +stripPrefixText :: Text -> Text -> Maybe Text +stripPrefixText x y + | x `T.isPrefixOf` y = Just $ T.drop (T.length x) y | otherwise = Nothing -stripSuffixBS :: ByteString -> ByteString -> Maybe ByteString -stripSuffixBS x y - | x `S.isSuffixOf` y = Just $ S.take (S.length y - S.length x) y +stripSuffixText :: Text -> Text -> Maybe Text +stripSuffixText x y + | x `T.isSuffixOf` y = Just $ T.take (T.length y - T.length x) y | otherwise = Nothing -- | A single line of input, not including line endings -type Line = ByteString +type Line = Text -- | Apply the given Sink to each section of output, broken by a single line containing --- eachSection :: Monad m => Sink Line m a - -> Conduit ByteString m a + -> Conduit Text m a eachSection inner = - CL.map (S.filter (/= _cr)) =$= CB.lines =$= start + CL.map (T.filter (/= '\r')) =$= CT.lines =$= start where - _cr = 13 - peekBS = await >>= maybe (return Nothing) (\bs -> - if S.null bs - then peekBS + peekText = await >>= maybe (return Nothing) (\bs -> + if T.null bs + then peekText else leftover bs >> return (Just bs)) - start = peekBS >>= maybe (return ()) (const go) + start = peekText >>= maybe (return ()) (const go) go = do x <- toConsumer $ takeWhileC (/= "---") =$= inner @@ -397,25 +395,22 @@ eachSection inner = -- | Grab each key/value pair eachPair :: Monad m - => (ByteString -> Sink Line m a) + => (Text -> Sink Line m a) -> Conduit Line m a eachPair inner = start where start = await >>= maybe (return ()) start' - _colon = 58 - _space = 32 - start' bs1 = toConsumer (valSrc =$= inner key) >>= yield >> start where - (key, bs2) = S.break (== _colon) bs1 - (spaces, bs3) = S.span (== _space) $ S.drop 1 bs2 - indent = S.length key + 1 + S.length spaces + (key, bs2) = T.break (== ':') bs1 + (spaces, bs3) = T.span (== ' ') $ T.drop 1 bs2 + indent = T.length key + 1 + T.length spaces valSrc - | S.null bs3 = noIndent + | T.null bs3 = noIndent | otherwise = yield bs3 >> loopIndent indent noIndent = do @@ -423,12 +418,12 @@ eachPair inner = case mx of Nothing -> return () Just bs -> do - let (spaces, val) = S.span (== _space) bs - if S.length spaces == 0 + let (spaces, val) = T.span (== ' ') bs + if T.length spaces == 0 then leftover val else do yield val - loopIndent (S.length spaces) + loopIndent (T.length spaces) loopIndent i = loop @@ -436,11 +431,11 @@ eachPair inner = loop = await >>= maybe (return ()) go go bs - | S.length spaces == i && S.all (== _space) spaces = + | T.length spaces == i && T.all (== ' ') spaces = yield val >> loop | otherwise = leftover bs where - (spaces, val) = S.splitAt i bs + (spaces, val) = T.splitAt i bs -- | General purpose utility takeWhileC :: Monad m => (a -> Bool) -> Conduit a m a diff --git a/src/Stack/PackageIndex.hs b/src/Stack/PackageIndex.hs index 02bc8caad3..92fcfdfb4e 100644 --- a/src/Stack/PackageIndex.hs +++ b/src/Stack/PackageIndex.hs @@ -34,10 +34,6 @@ import Control.Monad.Trans.Control import Data.Aeson.Extended import Data.Binary.VersionTagged -import qualified Data.Word8 as Word8 -import qualified Data.ByteString as S -import qualified Data.ByteString.Unsafe as SU -import qualified Data.ByteString.Char8 as S8 import qualified Data.ByteString.Lazy as L import Data.Conduit (($$), (=$)) import Data.Conduit.Binary (sinkHandle, @@ -50,6 +46,7 @@ import qualified Data.Map.Strict as Map import Data.Monoid import Data.Text (Text) import qualified Data.Text as T +import Data.Text.Unsafe (unsafeTail) import Data.Traversable (forM) @@ -139,19 +136,19 @@ populateCache menv index = do m breakSlash x - | S.null z = Nothing - | otherwise = Just (y, SU.unsafeTail z) + | T.null z = Nothing + | otherwise = Just (y, unsafeTail z) where - (y, z) = S.break (== Word8._slash) x + (y, z) = T.break (== '/') x parseNameVersion t1 = do (p', t3) <- breakSlash - $ S.map (\c -> if c == Word8._backslash then Word8._slash else c) - $ S8.pack t1 + $ T.map (\c -> if c == '\\' then '/' else c) + $ T.pack t1 p <- parsePackageName p' (v', t5) <- breakSlash t3 v <- parseVersion v' - let (t6, suffix) = S.break (== Word8._period) t5 + let (t6, suffix) = T.break (== '.') t5 if t6 == p' then return (PackageIdentifier p v, suffix) else Nothing diff --git a/src/Stack/Setup.hs b/src/Stack/Setup.hs index b4e4505cfb..0980a55e2f 100644 --- a/src/Stack/Setup.hs +++ b/src/Stack/Setup.hs @@ -998,7 +998,7 @@ getCabalInstallVersion menv = do ebs <- tryProcessStdout Nothing menv "cabal" ["--numeric-version"] case ebs of Left _ -> return Nothing - Right bs -> Just <$> parseVersion (T.encodeUtf8 (T.dropWhileEnd isSpace (T.decodeUtf8 bs))) + Right bs -> Just <$> parseVersion (T.dropWhileEnd isSpace (T.decodeUtf8 bs)) -- | Check if given processes appear to be present, throwing an exception if -- missing. diff --git a/src/Stack/Setup/Installed.hs b/src/Stack/Setup/Installed.hs index 1b1afec8d9..2ba12b2f95 100644 --- a/src/Stack/Setup/Installed.hs +++ b/src/Stack/Setup/Installed.hs @@ -28,6 +28,7 @@ import Data.Maybe import Data.Monoid import Data.Text (Text) import qualified Data.Text as T +import qualified Data.Text.Encoding as T import Distribution.System (Platform (..)) import qualified Distribution.System as Cabal import Path @@ -89,14 +90,14 @@ getCompilerVersion menv wc = Ghc -> do bs <- readProcessStdout Nothing menv "ghc" ["--numeric-version"] let (_, ghcVersion) = versionFromEnd bs - GhcVersion <$> parseVersion ghcVersion + GhcVersion <$> parseVersion (T.decodeUtf8 ghcVersion) Ghcjs -> do -- Output looks like -- -- The Glorious Glasgow Haskell Compilation System for JavaScript, version 0.1.0 (GHC 7.10.2) bs <- readProcessStdout Nothing menv "ghcjs" ["--version"] - let (rest, ghcVersion) = versionFromEnd bs - (_, ghcjsVersion) = versionFromEnd rest + let (rest, ghcVersion) = T.decodeUtf8 <$> versionFromEnd bs + (_, ghcjsVersion) = T.decodeUtf8 <$> versionFromEnd rest GhcjsVersion <$> parseVersion ghcjsVersion <*> parseVersion ghcVersion where versionFromEnd = S8.spanEnd isValid . fst . S8.breakEnd isValid diff --git a/src/Stack/Types/Build.hs b/src/Stack/Types/Build.hs index 718116bd4d..b0c4756fcc 100644 --- a/src/Stack/Types/Build.hs +++ b/src/Stack/Types/Build.hs @@ -110,7 +110,7 @@ data StackBuildException (Path Abs File) -- cabal Executable [String] -- cabal arguments (Maybe (Path Abs File)) -- logfiles location - [S.ByteString] -- log contents + [Text] -- log contents | ExecutionFailure [SomeException] | LocalPackageDoesn'tMatchTarget PackageName @@ -256,7 +256,7 @@ instance Show StackBuildException where logLocations ++ (if null bss then "" - else "\n\n" ++ doubleIndent (map (T.unpack . decodeUtf8With lenientDecode) bss)) + else "\n\n" ++ doubleIndent (map T.unpack bss)) where doubleIndent = dropWhileEnd isSpace . unlines . fmap (\line -> " " ++ line) dropQuotes = filter ('\"' /=) diff --git a/src/Stack/Types/BuildPlan.hs b/src/Stack/Types/BuildPlan.hs index 2701f53d77..85cc1782b4 100644 --- a/src/Stack/Types/BuildPlan.hs +++ b/src/Stack/Types/BuildPlan.hs @@ -32,8 +32,6 @@ import Data.Aeson (FromJSON (..), ToJSON (..), object, withObject, withText, (.!=), (.:), (.:?), (.=)) import Data.Binary.VersionTagged -import Data.ByteString (ByteString) -import qualified Data.ByteString.Char8 as S8 import Data.Hashable (Hashable) import qualified Data.HashMap.Strict as HashMap import Data.Map (Map) @@ -44,7 +42,6 @@ import Data.Set (Set) import Data.String (IsString, fromString) import Data.Text (Text, pack, unpack) import qualified Data.Text as T -import Data.Text.Encoding (encodeUtf8) import Data.Text.Read (decimal) import Data.Time (Day) import qualified Data.Traversable as T @@ -248,13 +245,13 @@ newtype Maintainer = Maintainer { unMaintainer :: Text } deriving (Show, Eq, Ord, Hashable, ToJSON, FromJSON, IsString) -- | Name of an executable. -newtype ExeName = ExeName { unExeName :: ByteString } +newtype ExeName = ExeName { unExeName :: Text } deriving (Show, Eq, Ord, Hashable, IsString, Generic, Binary, NFData) instance HasStructuralInfo ExeName instance ToJSON ExeName where - toJSON = toJSON . S8.unpack . unExeName + toJSON = toJSON . unExeName instance FromJSON ExeName where - parseJSON = withText "ExeName" $ return . ExeName . encodeUtf8 + parseJSON = withText "ExeName" $ return . ExeName -- | A simplified package description that tracks: -- @@ -363,9 +360,9 @@ parseSnapName t0 = Nightly <$> readMay (T.unpack t1) instance ToJSON a => ToJSON (Map ExeName a) where - toJSON = toJSON . Map.mapKeysWith const (S8.unpack . unExeName) + toJSON = toJSON . Map.mapKeysWith const unExeName instance FromJSON a => FromJSON (Map ExeName a) where - parseJSON = fmap (Map.mapKeysWith const (ExeName . encodeUtf8)) . parseJSON + parseJSON = fmap (Map.mapKeysWith const ExeName) . parseJSON -- | A simplified version of the 'BuildPlan' + cabal file. data MiniBuildPlan = MiniBuildPlan @@ -383,11 +380,11 @@ data MiniPackageInfo = MiniPackageInfo { mpiVersion :: !Version , mpiFlags :: !(Map FlagName Bool) , mpiPackageDeps :: !(Set PackageName) - , mpiToolDeps :: !(Set ByteString) + , mpiToolDeps :: !(Set Text) -- ^ Due to ambiguity in Cabal, it is unclear whether this refers to the -- executable name, the package name, or something else. We have to guess -- based on what's available, which is why we store this is an unwrapped - -- 'ByteString'. + -- 'Text'. , mpiExes :: !(Set ExeName) -- ^ Executables provided by this package , mpiHasLibrary :: !Bool diff --git a/src/Stack/Types/FlagName.hs b/src/Stack/Types/FlagName.hs index 481d98208c..dce9daa869 100644 --- a/src/Stack/Types/FlagName.hs +++ b/src/Stack/Types/FlagName.hs @@ -24,20 +24,17 @@ module Stack.Types.FlagName import Control.Applicative import Control.Monad.Catch import Data.Aeson.Extended -import Data.Attoparsec.ByteString.Char8 +import Data.Attoparsec.Text import Data.Attoparsec.Combinators import Data.Binary.VersionTagged -import qualified Data.ByteString as S -import Data.ByteString.Char8 (ByteString) -import qualified Data.ByteString.Char8 as S8 -import Data.Char (isLetter) +import Data.Char (isLetter, isDigit, toLower) import Data.Data import Data.Hashable import Data.Map (Map) import qualified Data.Map as Map import Data.Text (Text) -import qualified Data.Text.Encoding as T -import qualified Data.Word8 as Word8 +import qualified Data.Text as T +import Data.Text.Binary () import qualified Distribution.PackageDescription as Cabal import GHC.Generics import Language.Haskell.TH @@ -45,7 +42,7 @@ import Language.Haskell.TH.Syntax -- | A parse fail. data FlagNameParseFail - = FlagNameParseFail ByteString + = FlagNameParseFail Text deriving (Typeable) instance Exception FlagNameParseFail instance Show FlagNameParseFail where @@ -53,22 +50,22 @@ instance Show FlagNameParseFail where -- | A flag name. newtype FlagName = - FlagName ByteString + FlagName Text deriving (Typeable,Data,Generic,Hashable,Binary,NFData) instance HasStructuralInfo FlagName instance Eq FlagName where x == y = compare x y == EQ instance Ord FlagName where compare (FlagName x) (FlagName y) = - compare (S.map Word8.toLower x) (S.map Word8.toLower y) + compare (T.map toLower x) (T.map toLower y) instance Lift FlagName where lift (FlagName n) = appE (conE 'FlagName) - (stringE (S8.unpack n)) + (stringE (T.unpack n)) instance Show FlagName where - show (FlagName n) = S8.unpack n + show (FlagName n) = T.unpack n instance FromJSON FlagName where parseJSON j = @@ -78,10 +75,10 @@ instance FromJSON FlagName where fail ("Couldn't parse flag name: " ++ s) Just ver -> return ver --- | Attoparsec parser for a flag name from bytestring. +-- | Attoparsec parser for a flag name flagNameParser :: Parser FlagName flagNameParser = - fmap (FlagName . S8.pack) + fmap (FlagName . T.pack) (appending (many1 (satisfy isLetter)) (concating (many (alternating (pured (satisfy isAlphaNum)) @@ -97,36 +94,36 @@ mkFlagName s = Nothing -> error ("Invalid flag name: " ++ show s) Just pn -> [|pn|] --- | Convenient way to parse a flag name from a bytestring. -parseFlagName :: MonadThrow m => ByteString -> m FlagName +-- | Convenient way to parse a flag name from a 'Text'. +parseFlagName :: MonadThrow m => Text -> m FlagName parseFlagName x = go x where go = either (const (throwM (FlagNameParseFail x))) return . parseOnly (flagNameParser <* endOfInput) --- | Migration function. +-- | Convenience function for parsing from a 'String' parseFlagNameFromString :: MonadThrow m => String -> m FlagName parseFlagNameFromString = - parseFlagName . S8.pack + parseFlagName . T.pack -- | Produce a string representation of a flag name. flagNameString :: FlagName -> String -flagNameString (FlagName n) = S8.unpack n +flagNameString (FlagName n) = T.unpack n -- | Produce a string representation of a flag name. flagNameText :: FlagName -> Text -flagNameText (FlagName n) = T.decodeUtf8 n +flagNameText (FlagName n) = n -- | Convert from a Cabal flag name. fromCabalFlagName :: Cabal.FlagName -> FlagName fromCabalFlagName (Cabal.FlagName name) = - let !x = S8.pack name + let !x = T.pack name in FlagName x -- | Convert to a Cabal flag name. toCabalFlagName :: FlagName -> Cabal.FlagName toCabalFlagName (FlagName name) = - let !x = S8.unpack name + let !x = T.unpack name in Cabal.FlagName x instance ToJSON a => ToJSON (Map FlagName a) where diff --git a/src/Stack/Types/GhcPkgId.hs b/src/Stack/Types/GhcPkgId.hs index e6a923e15e..ce52455860 100644 --- a/src/Stack/Types/GhcPkgId.hs +++ b/src/Stack/Types/GhcPkgId.hs @@ -13,27 +13,26 @@ module Stack.Types.GhcPkgId import Control.Applicative import Control.Monad.Catch import Data.Aeson.Extended -import Data.Attoparsec.ByteString.Char8 as A8 +import Data.Attoparsec.Text import Data.Binary (getWord8, putWord8) import Data.Binary.VersionTagged -import Data.ByteString.Char8 (ByteString) -import qualified Data.ByteString.Char8 as S8 import Data.Data import Data.Hashable -import Data.Text.Encoding (encodeUtf8) +import Data.Text (Text) +import qualified Data.Text as T import GHC.Generics import Prelude -- Fix AMP warning -- | A parse fail. data GhcPkgIdParseFail - = GhcPkgIdParseFail ByteString + = GhcPkgIdParseFail Text deriving Typeable instance Show GhcPkgIdParseFail where show (GhcPkgIdParseFail bs) = "Invalid package ID: " ++ show bs instance Exception GhcPkgIdParseFail -- | A ghc-pkg package identifier. -newtype GhcPkgId = GhcPkgId ByteString +newtype GhcPkgId = GhcPkgId Text deriving (Eq,Ord,Data,Typeable,Generic) instance Hashable GhcPkgId @@ -59,7 +58,7 @@ instance Show GhcPkgId where instance FromJSON GhcPkgId where parseJSON = withText "GhcPkgId" $ \t -> - case parseGhcPkgId $ encodeUtf8 t of + case parseGhcPkgId t of Left e -> fail $ show (e, t) Right x -> return x @@ -67,8 +66,8 @@ instance ToJSON GhcPkgId where toJSON g = toJSON (ghcPkgIdString g) --- | Convenient way to parse a package name from a bytestring. -parseGhcPkgId :: MonadThrow m => ByteString -> m GhcPkgId +-- | Convenient way to parse a package name from a 'Text'. +parseGhcPkgId :: MonadThrow m => Text -> m GhcPkgId parseGhcPkgId x = go x where go = either (const (throwM (GhcPkgIdParseFail x))) return . @@ -77,16 +76,8 @@ parseGhcPkgId x = go x -- | A parser for a package-version-hash pair. ghcPkgIdParser :: Parser GhcPkgId ghcPkgIdParser = - fmap GhcPkgId (A8.takeWhile isValid) - where - isValid c = - ('A' <= c && c <= 'Z') || - ('a' <= c && c <= 'z') || - ('0' <= c && c <= '9') || - c == '.' || - c == '-' || - c == '_' + GhcPkgId . T.pack <$> many1 (choice [digit, letter, satisfy (`elem` "_.-")]) -- | Get a string representation of GHC package id. ghcPkgIdString :: GhcPkgId -> String -ghcPkgIdString (GhcPkgId x) = S8.unpack x +ghcPkgIdString (GhcPkgId x) = T.unpack x diff --git a/src/Stack/Types/PackageIdentifier.hs b/src/Stack/Types/PackageIdentifier.hs index 22059e3054..6e5b6420cf 100644 --- a/src/Stack/Types/PackageIdentifier.hs +++ b/src/Stack/Types/PackageIdentifier.hs @@ -21,15 +21,12 @@ import Control.DeepSeq import Control.Exception (Exception) import Control.Monad.Catch (MonadThrow, throwM) import Data.Aeson.Extended -import Data.Attoparsec.ByteString.Char8 +import Data.Attoparsec.Text import Data.Binary.VersionTagged (Binary, HasStructuralInfo) -import Data.ByteString (ByteString) -import qualified Data.ByteString.Char8 as S8 import Data.Data import Data.Hashable import Data.Text (Text) import qualified Data.Text as T -import Data.Text.Encoding (encodeUtf8) import GHC.Generics import Prelude hiding (FilePath) import Stack.Types.PackageName @@ -37,7 +34,7 @@ import Stack.Types.Version -- | A parse fail. data PackageIdentifierParseFail - = PackageIdentifierParseFail ByteString + = PackageIdentifierParseFail Text deriving (Typeable) instance Show PackageIdentifierParseFail where show (PackageIdentifierParseFail bs) = "Invalid package identifier: " ++ show bs @@ -66,7 +63,7 @@ instance ToJSON PackageIdentifier where toJSON = toJSON . packageIdentifierString instance FromJSON PackageIdentifier where parseJSON = withText "PackageIdentifier" $ \t -> - case parsePackageIdentifier $ encodeUtf8 t of + case parsePackageIdentifier t of Left e -> fail $ show (e, t) Right x -> return x @@ -82,21 +79,21 @@ fromTuple (n,v) = PackageIdentifier n v packageIdentifierParser :: Parser PackageIdentifier packageIdentifierParser = do name <- packageNameParser - char8 '-' + char '-' version <- versionParser return (PackageIdentifier name version) --- | Convenient way to parse a package identifier from a bytestring. -parsePackageIdentifier :: MonadThrow m => ByteString -> m PackageIdentifier +-- | Convenient way to parse a package identifier from a 'Text'. +parsePackageIdentifier :: MonadThrow m => Text -> m PackageIdentifier parsePackageIdentifier x = go x where go = either (const (throwM (PackageIdentifierParseFail x))) return . parseOnly (packageIdentifierParser <* endOfInput) --- | Migration function. +-- | Convenience function for parsing from a 'String'. parsePackageIdentifierFromString :: MonadThrow m => String -> m PackageIdentifier parsePackageIdentifierFromString = - parsePackageIdentifier . S8.pack + parsePackageIdentifier . T.pack -- | Get a string representation of the package identifier; name-ver. packageIdentifierString :: PackageIdentifier -> String diff --git a/src/Stack/Types/PackageName.hs b/src/Stack/Types/PackageName.hs index b87798e9f4..e862624ba8 100644 --- a/src/Stack/Types/PackageName.hs +++ b/src/Stack/Types/PackageName.hs @@ -14,7 +14,6 @@ module Stack.Types.PackageName ,packageNameParser ,parsePackageName ,parsePackageNameFromString - ,packageNameByteString ,packageNameString ,packageNameText ,fromCabalPackageName @@ -29,19 +28,17 @@ import Control.DeepSeq import Control.Monad import Control.Monad.Catch import Data.Aeson.Extended -import Data.Attoparsec.ByteString.Char8 +import Data.Attoparsec.Text import Data.Attoparsec.Combinators import Data.Binary.VersionTagged (Binary, HasStructuralInfo) -import Data.ByteString.Char8 (ByteString) -import qualified Data.ByteString.Char8 as S8 -import Data.Char (isLetter) import Data.Data import Data.Hashable import Data.List (intercalate) import Data.Map (Map) import qualified Data.Map as Map import Data.Text (Text) -import qualified Data.Text.Encoding as T +import qualified Data.Text as T +import Data.Text.Binary () import qualified Distribution.Package as Cabal import GHC.Generics import Language.Haskell.TH @@ -51,7 +48,7 @@ import qualified Options.Applicative as O -- | A parse fail. data PackageNameParseFail - = PackageNameParseFail ByteString + = PackageNameParseFail Text | CabalFileNameParseFail FilePath | CabalFileNameInvalidPackageName FilePath deriving (Typeable) @@ -63,16 +60,16 @@ instance Show PackageNameParseFail where -- | A package name. newtype PackageName = - PackageName ByteString + PackageName Text deriving (Eq,Ord,Typeable,Data,Generic,Hashable,Binary,NFData) instance Lift PackageName where lift (PackageName n) = appE (conE 'PackageName) - (stringE (S8.unpack n)) + (stringE (T.unpack n)) instance Show PackageName where - show (PackageName n) = S8.unpack n + show (PackageName n) = T.unpack n instance HasStructuralInfo PackageName @@ -86,16 +83,15 @@ instance FromJSON PackageName where fail ("Couldn't parse package name: " ++ s) Just ver -> return ver --- | Attoparsec parser for a package name from bytestring. +-- | Attoparsec parser for a package name packageNameParser :: Parser PackageName packageNameParser = - fmap (PackageName . S8.pack . intercalate "-") + fmap (PackageName . T.pack . intercalate "-") (sepBy1 word (char '-')) where word = concat <$> sequence [many digit, pured letter, many (alternating letter digit)] - letter = satisfy isLetter -- | Make a package name. mkPackageName :: String -> Q Exp @@ -104,40 +100,36 @@ mkPackageName s = Nothing -> error ("Invalid package name: " ++ show s) Just pn -> [|pn|] --- | Convenient way to parse a package name from a bytestring. -parsePackageName :: MonadThrow m => ByteString -> m PackageName +-- | Parse a package name from a 'Text'. +parsePackageName :: MonadThrow m => Text -> m PackageName parsePackageName x = go x where go = either (const (throwM (PackageNameParseFail x))) return . parseOnly (packageNameParser <* endOfInput) --- | Migration function. +-- | Parse a package name from a 'String'. parsePackageNameFromString :: MonadThrow m => String -> m PackageName parsePackageNameFromString = - parsePackageName . S8.pack - --- | Produce a bytestring representation of a package name. -packageNameByteString :: PackageName -> ByteString -packageNameByteString (PackageName n) = n + parsePackageName . T.pack -- | Produce a string representation of a package name. packageNameString :: PackageName -> String -packageNameString (PackageName n) = S8.unpack n +packageNameString (PackageName n) = T.unpack n -- | Produce a string representation of a package name. packageNameText :: PackageName -> Text -packageNameText (PackageName n) = T.decodeUtf8 n +packageNameText (PackageName n) = n -- | Convert from a Cabal package name. fromCabalPackageName :: Cabal.PackageName -> PackageName fromCabalPackageName (Cabal.PackageName name) = - let !x = S8.pack name + let !x = T.pack name in PackageName x -- | Convert to a Cabal package name. toCabalPackageName :: PackageName -> Cabal.PackageName toCabalPackageName (PackageName name) = - let !x = S8.unpack name + let !x = T.unpack name in Cabal.PackageName x -- | Parse a package name from a file path. diff --git a/src/Stack/Types/Sig.hs b/src/Stack/Types/Sig.hs index 9dee12c994..09527eb8a3 100644 --- a/src/Stack/Types/Sig.hs +++ b/src/Stack/Types/Sig.hs @@ -26,7 +26,6 @@ import Data.Monoid ((<>)) import Data.String (IsString(..)) import Data.Text (Text) import qualified Data.Text as T -import qualified Data.Text.Encoding as T import Data.Typeable (Typeable) import Stack.Types.PackageName @@ -68,7 +67,7 @@ instance IsString Fingerprint where instance FromJSON (Aeson PackageName) where parseJSON j = do s <- parseJSON j - case (parsePackageName . T.encodeUtf8) s of + case parsePackageName s of Just name -> return (Aeson name) Nothing -> fail ("Invalid package name: " <> T.unpack s) diff --git a/src/Stack/Types/Version.hs b/src/Stack/Types/Version.hs index 1b94eccc33..e3f3fb3ed2 100644 --- a/src/Stack/Types/Version.hs +++ b/src/Stack/Types/Version.hs @@ -33,10 +33,8 @@ import Control.Applicative import Control.DeepSeq import Control.Monad.Catch import Data.Aeson.Extended -import Data.Attoparsec.ByteString.Char8 +import Data.Attoparsec.Text import Data.Binary.VersionTagged (Binary, HasStructuralInfo) -import Data.ByteString (ByteString) -import qualified Data.ByteString.Char8 as S8 import Data.Data import Data.Hashable import Data.List @@ -47,6 +45,7 @@ import Data.Set (Set) import qualified Data.Set as Set import Data.Text (Text) import qualified Data.Text as T +import Data.Text.Binary () import Data.Vector.Binary () import Data.Vector.Unboxed (Vector) import qualified Data.Vector.Unboxed as V @@ -61,7 +60,7 @@ import Text.PrettyPrint (render) -- | A parse fail. data VersionParseFail = - VersionParseFail ByteString + VersionParseFail Text deriving (Typeable) instance Exception VersionParseFail instance Show VersionParseFail where @@ -106,7 +105,7 @@ instance FromJSON a => FromJSON (Map Version a) where k' <- either (fail . show) return $ parseVersionFromString k return (k', v) --- | Attoparsec parser for a package version from bytestring. +-- | Attoparsec parser for a package version. versionParser :: Parser Version versionParser = do ls <- ((:) <$> num <*> many num') @@ -116,8 +115,8 @@ versionParser = num' = point *> num point = satisfy (== '.') --- | Convenient way to parse a package version from a bytestring. -parseVersion :: MonadThrow m => ByteString -> m Version +-- | Convenient way to parse a package version from a 'Text'. +parseVersion :: MonadThrow m => Text -> m Version parseVersion x = go x where go = either (const (throwM (VersionParseFail x))) return . @@ -126,7 +125,7 @@ parseVersion x = go x -- | Migration function. parseVersionFromString :: MonadThrow m => String -> m Version parseVersionFromString = - parseVersion . S8.pack + parseVersion . T.pack -- | Get a string representation of a package version. versionString :: Version -> String diff --git a/src/test/Stack/DotSpec.hs b/src/test/Stack/DotSpec.hs index a4c0add4c9..b029d44660 100644 --- a/src/test/Stack/DotSpec.hs +++ b/src/test/Stack/DotSpec.hs @@ -5,7 +5,6 @@ module Stack.DotSpec where import Control.Monad (filterM) -import Data.ByteString.Char8 (ByteString) import Data.Foldable as F import Data.Functor.Identity import Data.List ((\\)) @@ -13,6 +12,7 @@ import qualified Data.Map as Map import Data.Maybe (fromMaybe) import Data.Set (Set) import qualified Data.Set as Set +import Data.Text (Text) import Stack.Types import Test.Hspec import Test.Hspec.QuickCheck (prop) @@ -74,7 +74,7 @@ sublistOf :: [a] -> Gen [a] sublistOf = filterM (\_ -> choose (False, True)) -- Unsafe internal helper to create a package name -pkgName :: ByteString -> PackageName +pkgName :: Text -> PackageName pkgName = fromMaybe failure . parsePackageName where failure = error "Internal error during package name creation in DotSpec.pkgName" diff --git a/src/test/Stack/PackageDumpSpec.hs b/src/test/Stack/PackageDumpSpec.hs index 07640ef982..8593f4f486 100644 --- a/src/test/Stack/PackageDumpSpec.hs +++ b/src/test/Stack/PackageDumpSpec.hs @@ -6,6 +6,7 @@ module Stack.PackageDumpSpec where import Data.Conduit import qualified Data.Conduit.List as CL import qualified Data.Conduit.Binary as CB +import Data.Conduit.Text (decodeUtf8) import Control.Monad.Trans.Resource (runResourceT) import Stack.PackageDump import Stack.Types @@ -63,6 +64,7 @@ spec = do it "ghc 7.8" $ do haskell2010:_ <- runResourceT $ CB.sourceFile "test/package-dump/ghc-7.8.txt" + =$= decodeUtf8 $$ conduitDumpPackage =$ CL.consume ghcPkgId <- parseGhcPkgId "haskell2010-1.1.2.0-05c8dd51009e08c6371c82972d40f55a" @@ -89,6 +91,7 @@ spec = do it "ghc 7.10" $ do haskell2010:_ <- runResourceT $ CB.sourceFile "test/package-dump/ghc-7.10.txt" + =$= decodeUtf8 $$ conduitDumpPackage =$ CL.consume ghcPkgId <- parseGhcPkgId "ghc-7.10.1-325809317787a897b7a97d646ceaa3a3" @@ -125,6 +128,7 @@ spec = do it "ghc 7.8.4 (osx)" $ do hmatrix:_ <- runResourceT $ CB.sourceFile "test/package-dump/ghc-7.8.4-osx.txt" + =$= decodeUtf8 $$ conduitDumpPackage =$ CL.consume ghcPkgId <- parseGhcPkgId "hmatrix-0.16.1.5-12d5d21f26aa98774cdd8edbc343fbfe" diff --git a/stack.cabal b/stack.cabal index 93e4f15409..d5c036c271 100644 --- a/stack.cabal +++ b/stack.cabal @@ -187,6 +187,7 @@ library , template-haskell >= 2.9.0.0 , temporary >= 1.2.0.3 , text >= 1.2.0.4 + , text-binary , time >= 1.4.2 , transformers >= 0.3.0.0 , transformers-base >= 0.4.4