module Main (main) where
import Version ( version, targetOS, targetARCH )
-import Distribution.InstalledPackageInfo.Binary
+import Distribution.InstalledPackageInfo.Binary()
import qualified Distribution.Simple.PackageIndex as PackageIndex
import Distribution.ModuleName hiding (main)
import Distribution.InstalledPackageInfo
import qualified Data.Binary as Bin
import qualified Data.Binary.Get as Bin
+#if __GLASGOW_HASKELL__ < 612 || defined(mingw32_HOST_OS)
+-- mingw32 needs these for getExecDir, GHC <6.12 needs them for openNewFile
import Foreign
import Foreign.C
-#ifdef mingw32_HOST_OS
-import GHC.ConsoleHandler
-#else
-import System.Posix hiding (fdToHandle)
#endif
-import IO ( isPermissionError )
+#if __GLASGOW_HASKELL__ < 612
import System.Posix.Internals
#if __GLASGOW_HASKELL__ >= 611
import GHC.IO.Handle.FD (fdToHandle)
#else
import GHC.Handle (fdToHandle)
#endif
+#endif
+
+#ifdef mingw32_HOST_OS
+import GHC.ConsoleHandler
+#else
+import System.Posix hiding (fdToHandle)
+#endif
+
+import IO ( isPermissionError )
#if defined(GLOB)
import System.Process(runInteractiveCommand)
import qualified System.Info(os)
#endif
-#if !defined(mingw32_HOST_OS) && __GLASGOW_HASKELL__ >= 611
+#if !defined(mingw32_HOST_OS) && __GLASGOW_HASKELL__ >= 611 && !defined(BOOTSTRAPPING)
import System.Console.Terminfo as Terminfo
#endif
" $p register {filename | -}\n" ++
" Register the package using the specified installed package\n" ++
" description. The syntax for the latter is given in the $p\n" ++
- " documentation.\n" ++
+ " documentation. The input file should be encoded in UTF-8.\n" ++
"\n" ++
" $p update {filename | -}\n" ++
" Register the package, overwriting any other package with the\n" ++
- " same name.\n" ++
+ " same name. The input file should be encoded in UTF-8.\n" ++
"\n" ++
" $p unregister {pkg-id}\n" ++
" Unregister the specified package.\n" ++
" $p dump\n" ++
" Dump the registered description for every package. This is like\n" ++
" \"ghc-pkg describe '*'\", except that it is intended to be used\n" ++
- " by tools that parse the results, rather than humans.\n" ++
+ " by tools that parse the results, rather than humans. The output is\n" ++
+ " always encoded in UTF-8, regardless of the current locale.\n" ++
+ "\n" ++
+ " $p recache\n" ++
+ " Regenerate the package database cache. This command should only be\n" ++
+ " necessary if you added a package to the database by dropping a file\n" ++
+ " into the database directory manually. By default, the global DB\n" ++
+ " is recached; to recache a different DB use --user or --package-conf\n" ++
+ " as appropriate.\n" ++
"\n" ++
" Substring matching is supported for {module} in find-module and\n" ++
" for {pkg} in list, describe, and field, where a '*' indicates\n" ++
parseMultiPackageConf :: Verbosity -> FilePath -> IO [InstalledPackageInfo]
parseMultiPackageConf verbosity file = do
when (verbosity > Normal) $ putStrLn ("reading package database: " ++ file)
- str <- readFile file
+ str <- readUTF8File file
let pkgs = map convertPackageInfoIn $ read str
Exception.evaluate pkgs
`catchError` \e->
parseSingletonPackageConf :: Verbosity -> FilePath -> IO InstalledPackageInfo
parseSingletonPackageConf verbosity file = do
when (verbosity > Normal) $ putStrLn ("reading package config: " ++ file)
- readFile file >>= parsePackageInfo
+ readUTF8File file >>= parsePackageInfo
cachefilename :: FilePath
cachefilename = "package.cache"
"-" -> do
when (verbosity >= Normal) $
putStr "Reading package info from stdin ... "
+#if __GLASGOW_HASKELL__ >= 612
+ -- fix the encoding to UTF-8, since this is an interchange format
+ hSetEncoding stdin utf8
+#endif
getContents
f -> do
when (verbosity >= Normal) $
putStr ("Reading package info from " ++ show f ++ " ... ")
- readFile f
+ readUTF8File f
expanded <- expandEnvVars s force
do_cmd (AddPackage p) = do
let file = location db </> display (installedPackageId p) <.> "conf"
when (verbosity > Normal) $ putStrLn ("writing " ++ file)
- writeFileAtomic file (showInstalledPackageInfo p)
+ writeFileUtf8Atomic file (showInstalledPackageInfo p)
do_cmd (ModifyPackage p) =
do_cmd (AddPackage p)
let filename = location db </> cachefilename
when (verbosity > Normal) $
putStrLn ("writing cache " ++ filename)
- writeBinPackageDB filename (map convertPackageInfoOut (packages db))
+ writeBinaryFileAtomic filename (map convertPackageInfoOut (packages db))
`catch` \e ->
if isPermissionError e
then die (filename ++ ": you don't have permission to modify this file")
if simple_output then show_simple stack else do
-#if defined(mingw32_HOST_OS) || __GLASGOW_HASKELL__ < 611
+#if defined(mingw32_HOST_OS) || __GLASGOW_HASKELL__ < 611 || defined(BOOTSTRAPPING)
mapM_ show_normal stack
#else
let
getPkgDatabases verbosity False True{-use cache-} myflags
let all_pkgs = allPackagesInStack flag_db_stack
- ipix = PackageIndex.listToInstalledPackageIndex all_pkgs
+ ipix = PackageIndex.fromList all_pkgs
putStrLn "digraph {"
let quote s = '"':s ++ "\""
| p <- all_pkgs,
let from = display (sourcePackageId p),
depid <- depends p,
- Just dep <- [PackageIndex.lookupInstalledPackage ipix depid],
+ Just dep <- [PackageIndex.lookupInstalledPackageId ipix depid],
let to = display (sourcePackageId dep)
]
putStrLn "}"
doDump (allPackagesInStack flag_db_stack)
doDump :: [InstalledPackageInfo] -> IO ()
-doDump = mapM_ putStrLn . intersperse "---" . map showInstalledPackageInfo
+doDump pkgs = do
+#if __GLASGOW_HASKELL__ >= 612
+ -- fix the encoding to UTF-8, since this is an interchange format
+ hSetEncoding stdout utf8
+#endif
+ mapM_ putStrLn . intersperse "---" . map showInstalledPackageInfo $ pkgs
-- PackageId is can have globVersion for the version
findPackages :: PackageDBStack -> PackageArg -> IO [InstalledPackageInfo]
let shown = concat $ intersperse ",\n "
$ map (show . convertPackageInfoOut) ipis
fileContents = "[" ++ shown ++ "\n]"
- writeFileAtomic filename fileContents
+ writeFileUtf8Atomic filename fileContents
`catch` \e ->
if isPermissionError e
then die (filename ++ ": you don't have permission to modify this file")
where handler' (Exception.ErrorCall err) = handler err
+writeBinaryFileAtomic :: Bin.Binary a => FilePath -> a -> IO ()
+writeBinaryFileAtomic targetFile obj =
+ withFileAtomic targetFile $ \h -> do
+ hSetBinaryMode h True
+ B.hPutStr h (Bin.encode obj)
+
+writeFileUtf8Atomic :: FilePath -> String -> IO ()
+writeFileUtf8Atomic targetFile content =
+ withFileAtomic targetFile $ \h -> do
+#if __GLASGOW_HASKELL__ >= 612
+ hSetEncoding h utf8
+#endif
+ hPutStr h content
+
-- copied from Cabal's Distribution.Simple.Utils, except that we want
-- to use text files here, rather than binary files.
-writeFileAtomic :: FilePath -> String -> IO ()
-writeFileAtomic targetFile content = do
+withFileAtomic :: FilePath -> (Handle -> IO ()) -> IO ()
+withFileAtomic targetFile write_content = do
(newFile, newHandle) <- openNewFile targetDir template
- do hPutStr newHandle content
+ do write_content newHandle
hClose newHandle
#if mingw32_HOST_OS || mingw32_TARGET_OS
renameFile newFile targetFile
-- to always return a valid dir
(targetDir_,targetName) = splitFileName targetFile
--- Ugh, this is a copy/paste of code from the base library, but
--- if uses 666 rather than 600 for the permissions.
openNewFile :: FilePath -> String -> IO (FilePath, Handle)
openNewFile dir template = do
+#if __GLASGOW_HASKELL__ >= 612
+ -- this was added to System.IO in 6.12.1
+ -- we must use this version because the version below opens the file
+ -- in binary mode.
+ openTempFileWithDefaultPermissions dir template
+#else
+ -- Ugh, this is a copy/paste of code from the base library, but
+ -- if uses 666 rather than 600 for the permissions.
pid <- c_getpid
findTempName pid
where
std_flags = o_NONBLOCK .|. o_NOCTTY
output_flags = std_flags .|. o_CREAT
rw_flags = output_flags .|. o_RDWR
+#endif /* GLASGOW_HASKELL < 612 */
-- | The function splits the given string to substrings
-- using 'isSearchPathSeparator'.
_ -> chunk'
(chunk', rest') = break isSearchPathSeparator s
+
+readUTF8File :: FilePath -> IO String
+readUTF8File file = do
+ h <- openFile file ReadMode
+#if __GLASGOW_HASKELL__ >= 612
+ -- fix the encoding to UTF-8
+ hSetEncoding h utf8
+#endif
+ hGetContents h