Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC

Commits:

9 changed files:

Changes:

  • changelog.d/ghc-pkg-long-path-support
    1
    +section: ghc-pkg
    
    2
    +synopsis: Improve ``ghc-pkg``'s support for long paths on windows.
    
    3
    +issues: #26960
    
    4
    +mrs: !15584
    
    5
    +
    
    6
    +description: {
    
    7
    +    ``ghc-pkg`` can't handle working with file paths longer than the MAX_PATH
    
    8
    +    restrictions on windows as it is not using UNC file paths by default.
    
    9
    +
    
    10
    +    By using UNC file paths whenever possible, we improve ``ghc-pkg`` on windows.
    
    11
    +    Note, this still requires the user to enable the use of long paths in order to opt-in
    
    12
    +    this behaviour on older windows machines.
    
    13
    +}
    
    14
    +
    
    15
    +

  • compiler/GHC/Unit/State.hs
    ... ... @@ -802,7 +802,7 @@ readUnitDatabase logger cfg conf_file = do
    802 802
           if cache_exists
    
    803 803
             then do
    
    804 804
               debugTraceMsg logger 2 $ text "Using binary package database:" <+> ppr filename
    
    805
    -          readPackageDbForGhc (OsPath.unsafeDecodeUtf filename)
    
    805
    +          readPackageDbForGhc filename
    
    806 806
             else do
    
    807 807
               -- If there is no package.cache file, we check if the database is not
    
    808 808
               -- empty by inspecting if the directory contains any .conf file. If it
    

  • libraries/ghc-boot/GHC/Unit/Database.hs
    ... ... @@ -68,6 +68,8 @@ module GHC.Unit.Database
    68 68
        -- * Misc
    
    69 69
        , mkMungePathUrl
    
    70 70
        , mungeUnitInfoPaths
    
    71
    +   , writeFileAtomic
    
    72
    +   , unsafeDecodeUtf
    
    71 73
        )
    
    72 74
     where
    
    73 75
     
    
    ... ... @@ -86,18 +88,23 @@ import Data.Binary.Get as Bin
    86 88
     import Data.List (intersperse)
    
    87 89
     import Control.Exception as Exception
    
    88 90
     import Control.Monad (when)
    
    89
    -import System.FilePath as FilePath
    
    91
    +import qualified System.FilePath as FilePath
    
    90 92
     #if !defined(mingw32_HOST_OS)
    
    91 93
     import Data.Bits ((.|.))
    
    92
    -import System.Posix.Files
    
    94
    +import System.Posix.Files.PosixString
    
    93 95
     import System.Posix.Types (FileMode)
    
    96
    +import System.OsString.Internal.Types (getOsString)
    
    94 97
     #endif
    
    95 98
     import System.IO
    
    96 99
     import System.IO.Error
    
    97 100
     import GHC.IO.Exception (IOErrorType(InappropriateType))
    
    98 101
     import qualified GHC.Data.ShortText as ST
    
    99 102
     import GHC.IO.Handle.Lock
    
    100
    -import System.Directory
    
    103
    +import GHC.Stack.Types (HasCallStack)
    
    104
    +import System.OsPath
    
    105
    +import qualified System.Directory.OsPath as OsPath
    
    106
    +import qualified System.Directory.Internal as OsPath.Internal
    
    107
    +import qualified System.File.OsPath as FileIO
    
    101 108
     
    
    102 109
     -- | @ghc-boot@'s UnitInfo, serialized to the database.
    
    103 110
     type DbUnitInfo      = GenericUnitInfo BS.ByteString BS.ByteString BS.ByteString BS.ByteString DbModule
    
    ... ... @@ -314,13 +321,13 @@ data DbInstUnitId
    314 321
     newtype PackageDbLock = PackageDbLock Handle
    
    315 322
     
    
    316 323
     -- | Acquire an exclusive lock related to package DB under given location.
    
    317
    -lockPackageDb :: FilePath -> IO PackageDbLock
    
    324
    +lockPackageDb :: OsPath -> IO PackageDbLock
    
    318 325
     
    
    319 326
     -- | Release the lock related to package DB.
    
    320 327
     unlockPackageDb :: PackageDbLock -> IO ()
    
    321 328
     
    
    322 329
     -- | Acquire a lock of given type related to package DB under given location.
    
    323
    -lockPackageDbWith :: LockMode -> FilePath -> IO PackageDbLock
    
    330
    +lockPackageDbWith :: LockMode -> OsPath -> IO PackageDbLock
    
    324 331
     lockPackageDbWith mode file = do
    
    325 332
       -- We are trying to open the lock file and then lock it. Thus the lock file
    
    326 333
       -- needs to either exist or we need to be able to create it. Ideally we
    
    ... ... @@ -350,10 +357,10 @@ lockPackageDbWith mode file = do
    350 357
         (lockFileOpenIn ReadWriteMode)
    
    351 358
         (const $ lockFileOpenIn ReadMode)
    
    352 359
       where
    
    353
    -    lock = file <.> "lock"
    
    360
    +    lock = file <.> OsPath.Internal.os "lock"
    
    354 361
     
    
    355 362
         lockFileOpenIn io_mode = bracketOnError
    
    356
    -      (openBinaryFile lock io_mode)
    
    363
    +      (FileIO.openBinaryFile lock io_mode)
    
    357 364
           hClose
    
    358 365
           -- If file locking support is not available, ignore the error and proceed
    
    359 366
           -- normally. Without it the only thing we lose on non-Windows platforms is
    
    ... ... @@ -387,7 +394,7 @@ isDbOpenReadMode = \case
    387 394
     
    
    388 395
     -- | Read the part of the package DB that GHC is interested in.
    
    389 396
     --
    
    390
    -readPackageDbForGhc :: FilePath -> IO [DbUnitInfo]
    
    397
    +readPackageDbForGhc :: OsPath -> IO [DbUnitInfo]
    
    391 398
     readPackageDbForGhc file =
    
    392 399
       decodeFromFile file DbOpenReadOnly getDbForGhc >>= \case
    
    393 400
         (pkgs, DbOpenReadOnly) -> return pkgs
    
    ... ... @@ -409,7 +416,7 @@ readPackageDbForGhc file =
    409 416
     -- we additionally receive a PackageDbLock that represents a lock on the
    
    410 417
     -- database, so that we can safely update it later.
    
    411 418
     --
    
    412
    -readPackageDbForGhcPkg :: Binary pkgs => FilePath -> DbOpenMode mode t ->
    
    419
    +readPackageDbForGhcPkg :: Binary pkgs => OsPath -> DbOpenMode mode t ->
    
    413 420
                               IO (pkgs, DbOpenMode mode PackageDbLock)
    
    414 421
     readPackageDbForGhcPkg file mode =
    
    415 422
         decodeFromFile file mode getDbForGhcPkg
    
    ... ... @@ -425,7 +432,7 @@ readPackageDbForGhcPkg file mode =
    425 432
     
    
    426 433
     -- | Write the whole of the package DB, both parts.
    
    427 434
     --
    
    428
    -writePackageDb :: Binary pkgs => FilePath -> [DbUnitInfo] -> pkgs -> IO ()
    
    435
    +writePackageDb :: Binary pkgs => OsPath -> [DbUnitInfo] -> pkgs -> IO ()
    
    429 436
     writePackageDb file ghcPkgs ghcPkgPart = do
    
    430 437
       writeFileAtomic file (runPut putDbForGhcPkg)
    
    431 438
     #if !defined(mingw32_HOST_OS)
    
    ... ... @@ -446,10 +453,10 @@ writePackageDb file ghcPkgs ghcPkgPart = do
    446 453
             ghcPart    = encode ghcPkgs
    
    447 454
     
    
    448 455
     #if !defined(mingw32_HOST_OS)
    
    449
    -addFileMode :: FilePath -> FileMode -> IO ()
    
    456
    +addFileMode :: OsPath -> FileMode -> IO ()
    
    450 457
     addFileMode file m = do
    
    451
    -  o <- fileMode <$> getFileStatus file
    
    452
    -  setFileMode file (m .|. o)
    
    458
    +  o <- fileMode <$> getFileStatus (getOsString file)
    
    459
    +  setFileMode (getOsString file) (m .|. o)
    
    453 460
     #endif
    
    454 461
     
    
    455 462
     getHeader :: Get (Word32, Word32)
    
    ... ... @@ -496,7 +503,7 @@ headerMagic = BS.Char8.pack "\0ghcpkg\0"
    496 503
     
    
    497 504
     -- | Feed a 'Get' decoder with data chunks from a file.
    
    498 505
     --
    
    499
    -decodeFromFile :: FilePath -> DbOpenMode mode t -> Get pkgs ->
    
    506
    +decodeFromFile :: OsPath -> DbOpenMode mode t -> Get pkgs ->
    
    500 507
                       IO (pkgs, DbOpenMode mode PackageDbLock)
    
    501 508
     decodeFromFile file mode decoder = case mode of
    
    502 509
       DbOpenReadOnly -> do
    
    ... ... @@ -517,7 +524,7 @@ decodeFromFile file mode decoder = case mode of
    517 524
         bracketOnError (lockPackageDb file) unlockPackageDb $ \lock -> do
    
    518 525
           (, DbOpenReadWrite lock) <$> decodeFileContents
    
    519 526
       where
    
    520
    -    decodeFileContents = withBinaryFile file ReadMode $ \hnd ->
    
    527
    +    decodeFileContents = FileIO.withBinaryFile file ReadMode $ \hnd ->
    
    521 528
           feed hnd (runGetIncremental decoder)
    
    522 529
     
    
    523 530
         feed hnd (Partial k)  = do chunk <- BS.hGet hnd BS.Lazy.defaultChunkSize
    
    ... ... @@ -527,21 +534,21 @@ decodeFromFile file mode decoder = case mode of
    527 534
         feed _ (Done _ _ res) = return res
    
    528 535
         feed _ (Fail _ _ msg) = ioError err
    
    529 536
           where
    
    530
    -        err = mkIOError InappropriateType loc Nothing (Just file)
    
    537
    +        err = mkIOError InappropriateType loc Nothing (Just $ unsafeDecodeUtf file)
    
    531 538
                   `ioeSetErrorString` msg
    
    532 539
             loc = "GHC.Unit.Database.readPackageDb"
    
    533 540
     
    
    534 541
     -- Copied from Cabal's Distribution.Simple.Utils.
    
    535
    -writeFileAtomic :: FilePath -> BS.Lazy.ByteString -> IO ()
    
    542
    +writeFileAtomic :: OsPath -> BS.Lazy.ByteString -> IO ()
    
    536 543
     writeFileAtomic targetPath content = do
    
    537 544
       let (targetDir, targetFile) = splitFileName targetPath
    
    538 545
       Exception.bracketOnError
    
    539
    -    (openBinaryTempFileWithDefaultPermissions targetDir $ targetFile <.> "tmp")
    
    540
    -    (\(tmpPath, handle) -> hClose handle >> removeFile tmpPath)
    
    546
    +    (FileIO.openBinaryTempFileWithDefaultPermissions targetDir $ targetFile <.> OsPath.Internal.os "tmp")
    
    547
    +    (\(tmpPath, handle) -> hClose handle >> OsPath.removeFile tmpPath)
    
    541 548
         (\(tmpPath, handle) -> do
    
    542 549
             BS.Lazy.hPut handle content
    
    543 550
             hClose handle
    
    544
    -        renameFile tmpPath targetPath)
    
    551
    +        OsPath.renameFile tmpPath targetPath)
    
    545 552
     
    
    546 553
     instance Binary DbUnitInfo where
    
    547 554
       put (GenericUnitInfo
    
    ... ... @@ -711,7 +718,7 @@ mkMungePathUrl top_dir pkgroot = (munge_path, munge_url)
    711 718
         -- rather than letting FilePath change it to use \ as the separator
    
    712 719
         stripVarPrefix var path = case ST.stripPrefix var path of
    
    713 720
                                   Just "" -> Just ""
    
    714
    -                              Just cs | isPathSeparator (ST.head cs) -> Just cs
    
    721
    +                              Just cs | FilePath.isPathSeparator (ST.head cs) -> Just cs
    
    715 722
                                   _ -> Nothing
    
    716 723
     
    
    717 724
     
    
    ... ... @@ -742,3 +749,8 @@ mungeUnitInfoPaths top_dir pkgroot pkg =
    742 749
           munge_paths = map munge_path
    
    743 750
           munge_urls  = map munge_url
    
    744 751
           (munge_path,munge_url) = mkMungePathUrl top_dir pkgroot
    
    752
    +
    
    753
    +-- | Decode an 'OsPath' to 'FilePath', throwing an 'error' if decoding failed.
    
    754
    +-- Prefer 'decodeUtf' and gracious error handling.
    
    755
    +unsafeDecodeUtf :: HasCallStack => OsPath -> FilePath
    
    756
    +unsafeDecodeUtf = OsPath.Internal.so

  • libraries/ghc-boot/ghc-boot.cabal.in
    ... ... @@ -82,6 +82,8 @@ Library
    82 82
                        containers >= 0.5 && < 0.9,
    
    83 83
                        directory  >= 1.2 && < 1.4,
    
    84 84
                        filepath   >= 1.3 && < 1.6,
    
    85
    +                   file-io    >= 0.1.6 && < 0.3,
    
    86
    +                   os-string  >= 2.0.1 && < 2.1,
    
    85 87
                        deepseq    >= 1.4 && < 1.6,
    
    86 88
                        ghc-platform  >= 0.1,
    
    87 89
                        ghc-toolchain >= 0.1
    

  • testsuite/tests/cabal/Makefile
    ... ... @@ -79,6 +79,25 @@ ghcpkg04 :
    79 79
     	@: # testpkg-1.2.3.4 and newtestpkg-2.0 are both exposed now
    
    80 80
     	'$(TEST_HC)' $(TEST_HC_OPTS) -package-db $(PKGCONF04) -c ghcpkg04.hs || true
    
    81 81
     
    
    82
    +PKGCONF20=local20.package.conf
    
    83
    +LOCAL_GHC_PKG20 = '$(GHC_PKG)' --no-user-package-db
    
    84
    +
    
    85
    +DIR1=asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf
    
    86
    +DIR2=zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv
    
    87
    +DIR3=uiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiop
    
    88
    +DIR4=qwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwer
    
    89
    +WDIR=$(DIR1)/$(DIR2)/$(DIR3)/$(DIR4)
    
    90
    +.PHONY: ghcpkg10
    
    91
    +ghcpkg10 :
    
    92
    +	@mkdir -p $(WDIR)
    
    93
    +	@rm -rf $(WDIR)/$(PKGCONF20)
    
    94
    +	$(LOCAL_GHC_PKG20) -f $(WDIR)/$(PKGCONF20) init $(WDIR)/$(PKGCONF20)
    
    95
    +	$(LOCAL_GHC_PKG20) -f $(WDIR)/$(PKGCONF20) list
    
    96
    +	$(LOCAL_GHC_PKG20) -f $(WDIR)/$(PKGCONF20) register --force test.pkg 2>/dev/null
    
    97
    +	$(LOCAL_GHC_PKG20) -f $(WDIR)/$(PKGCONF20) describe testpkg         | $(STRIP_PKGROOT)
    
    98
    +	$(LOCAL_GHC_PKG20) -f $(WDIR)/$(PKGCONF20) describe testpkg-1.2.3.4 | $(STRIP_PKGROOT)
    
    99
    +	$(LOCAL_GHC_PKG20) -f $(WDIR)/$(PKGCONF20) field testpkg-1.2.3.4 import-dirs
    
    100
    +
    
    82 101
     # Test stacking of package.confs (also #2441)
    
    83 102
     PKGCONF05a=local05a.package.conf
    
    84 103
     PKGCONF05b=local05b.package.conf
    

  • testsuite/tests/cabal/all.T
    ... ... @@ -5,6 +5,7 @@ def ignore_warnings(str):
    5 5
         return re.sub(r'Warning:.*\n', '', str)
    
    6 6
     
    
    7 7
     test('ghcpkg01', [extra_files(['test.pkg', 'test2.pkg', 'test3.pkg'])], makefile_test, [])
    
    8
    +test('ghcpkg10', [extra_files(['test.pkg', 'test2.pkg', 'test3.pkg'])], makefile_test, [])
    
    8 9
     
    
    9 10
     # Use ignore_stderr to prevent (when HADDOCK_DOCS=NO):
    
    10 11
     #  warning: haddock-interfaces .. doesn't exist or isn't a file
    

  • testsuite/tests/cabal/ghcpkg10.stdout
    1
    +asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf/zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv/uiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiop/qwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwer/local20.package.conf
    
    2
    +    (no packages)
    
    3
    +Reading package info from "test.pkg" ... done.
    
    4
    +name:            testpkg
    
    5
    +version:         1.2.3.4
    
    6
    +visibility:      public
    
    7
    +id:              testpkg-1.2.3.4-XXX
    
    8
    +key:             testpkg-1.2.3.4-XXX
    
    9
    +license:         BSD3
    
    10
    +copyright:       (c) The Univsersity of Glasgow 2004
    
    11
    +maintainer:      glasgow-haskell-users@haskell.org
    
    12
    +author:          simonmar@microsoft.com
    
    13
    +stability:       stable
    
    14
    +homepage:        http://www.haskell.org/ghc
    
    15
    +package-url:     http://www.haskell.org/ghc
    
    16
    +description:     A Test Package
    
    17
    +category:        none
    
    18
    +exposed:         True
    
    19
    +exposed-modules: A
    
    20
    +hidden-modules:  B C.D
    
    21
    +import-dirs:     /usr/local/lib/testpkg "c:/Program Files/testpkg"
    
    22
    +library-dirs:    /usr/local/lib/testpkg "c:/Program Files/testpkg"
    
    23
    +hs-libraries:    testpkg-1.2.3.4-XXX
    
    24
    +include-dirs:    /usr/local/include/testpkg "c:/Program Files/testpkg"
    
    25
    +pkgroot: 
    
    26
    +
    
    27
    +name:            testpkg
    
    28
    +version:         1.2.3.4
    
    29
    +visibility:      public
    
    30
    +id:              testpkg-1.2.3.4-XXX
    
    31
    +key:             testpkg-1.2.3.4-XXX
    
    32
    +license:         BSD3
    
    33
    +copyright:       (c) The Univsersity of Glasgow 2004
    
    34
    +maintainer:      glasgow-haskell-users@haskell.org
    
    35
    +author:          simonmar@microsoft.com
    
    36
    +stability:       stable
    
    37
    +homepage:        http://www.haskell.org/ghc
    
    38
    +package-url:     http://www.haskell.org/ghc
    
    39
    +description:     A Test Package
    
    40
    +category:        none
    
    41
    +exposed:         True
    
    42
    +exposed-modules: A
    
    43
    +hidden-modules:  B C.D
    
    44
    +import-dirs:     /usr/local/lib/testpkg "c:/Program Files/testpkg"
    
    45
    +library-dirs:    /usr/local/lib/testpkg "c:/Program Files/testpkg"
    
    46
    +hs-libraries:    testpkg-1.2.3.4-XXX
    
    47
    +include-dirs:    /usr/local/include/testpkg "c:/Program Files/testpkg"
    
    48
    +pkgroot: 
    
    49
    +
    
    50
    +import-dirs: /usr/local/lib/testpkg "c:/Program Files/testpkg"

  • utils/ghc-pkg/Main.hs
    ... ... @@ -47,12 +47,19 @@ import Distribution.Types.UnqualComponentName
    47 47
     import Distribution.Types.LibraryName
    
    48 48
     import Distribution.Types.MungedPackageName
    
    49 49
     import Distribution.Types.MungedPackageId
    
    50
    -import Distribution.Simple.Utils (toUTF8BS, writeUTF8File, readUTF8File)
    
    50
    +import Distribution.Simple.Utils (ignoreBOM, toUTF8BS, toUTF8LBS, fromUTF8LBS)
    
    51 51
     import qualified Data.Version as Version
    
    52
    -import System.FilePath as FilePath
    
    52
    +import System.OsPath as OsPath
    
    53
    +import qualified System.FilePath as FilePath
    
    53 54
     import qualified System.FilePath.Posix as FilePath.Posix
    
    54
    -import System.Directory ( getXdgDirectory, createDirectoryIfMissing, getAppUserDataDirectory,
    
    55
    -                          getModificationTime, XdgDirectory ( XdgData ) )
    
    55
    +import System.Directory.OsPath
    
    56
    +  ( getXdgDirectory, createDirectoryIfMissing, getAppUserDataDirectory,
    
    57
    +    getModificationTime, XdgDirectory ( XdgData ),
    
    58
    +    doesDirectoryExist, getDirectoryContents,
    
    59
    +    doesFileExist, removeFile,
    
    60
    +    getCurrentDirectory )
    
    61
    +import System.Directory.Internal (os)
    
    62
    +import qualified System.File.OsPath as FileIO
    
    56 63
     import Text.Printf
    
    57 64
     
    
    58 65
     import Prelude hiding (Foldable(..))
    
    ... ... @@ -65,15 +72,13 @@ import Data.Bifunctor
    65 72
     
    
    66 73
     import Data.Char ( toLower )
    
    67 74
     import Control.Monad
    
    68
    -import System.Directory ( doesDirectoryExist, getDirectoryContents,
    
    69
    -                          doesFileExist, removeFile,
    
    70
    -                          getCurrentDirectory )
    
    71 75
     import System.Exit ( exitWith, ExitCode(..) )
    
    72 76
     import System.Environment ( getArgs, getProgName, getEnv )
    
    73 77
     import System.IO
    
    74 78
     import System.IO.Error
    
    75
    -import GHC.IO           ( catchException )
    
    79
    +import GHC.IO           ( catchException, unsafePerformIO )
    
    76 80
     import GHC.IO.Exception (IOErrorType(InappropriateType))
    
    81
    +import GHC.Stack.Types (HasCallStack)
    
    77 82
     import Data.List ( group, sort, sortBy, nub, partition, find
    
    78 83
                      , intercalate, intersperse, unfoldr
    
    79 84
                      , isInfixOf, isSuffixOf, isPrefixOf, stripPrefix )
    
    ... ... @@ -429,8 +434,9 @@ runit verbosity cli nonopts = do
    429 434
             print filename
    
    430 435
             glob filename >>= print
    
    431 436
     #endif
    
    432
    -    ["init", filename] ->
    
    433
    -        initPackageDB filename verbosity cli
    
    437
    +    ["init", filename] -> do
    
    438
    +        filenameOs <- encodeFS filename
    
    439
    +        initPackageDB filenameOs verbosity cli
    
    434 440
         ["register", filename] ->
    
    435 441
             registerPackage filename verbosity cli
    
    436 442
                             multi_instance
    
    ... ... @@ -538,7 +544,7 @@ readPackageArg AsDefault str = Id <$> readGlobPkgId str
    538 544
     
    
    539 545
     data PackageDB (mode :: GhcPkg.DbMode)
    
    540 546
       = PackageDB {
    
    541
    -      location, locationAbsolute :: !FilePath,
    
    547
    +      location, locationAbsolute :: !OsPath,
    
    542 548
           -- We need both possibly-relative and definitely-absolute package
    
    543 549
           -- db locations. This is because the relative location is used as
    
    544 550
           -- an identifier for the db, so it is important we do not modify it.
    
    ... ... @@ -570,14 +576,14 @@ allPackagesInStack = concatMap packages
    570 576
     -- specified package DB can depend on, since dependencies can only extend
    
    571 577
     -- down the stack, not up (e.g. global packages cannot depend on user
    
    572 578
     -- packages).
    
    573
    -stackUpTo :: FilePath -> PackageDBStack -> PackageDBStack
    
    579
    +stackUpTo :: OsPath -> PackageDBStack -> PackageDBStack
    
    574 580
     stackUpTo to_modify = dropWhile ((/= to_modify) . location)
    
    575 581
     
    
    576
    -readFromSettingsFile :: FilePath
    
    577
    -                      -> (FilePath -> RawSettings -> Either String b)
    
    582
    +readFromSettingsFile :: OsPath
    
    583
    +                      -> (OsPath -> RawSettings -> Either String b)
    
    578 584
                           -> IO (Either String b)
    
    579 585
     readFromSettingsFile settingsFile f = do
    
    580
    -  settingsStr <- readFile settingsFile
    
    586
    +  settingsStr <- readUtf8File settingsFile
    
    581 587
       pure $ do
    
    582 588
         mySettings <- case maybeReadFuzzy settingsStr of
    
    583 589
           Just s -> pure $ Map.fromList s
    
    ... ... @@ -586,11 +592,11 @@ readFromSettingsFile settingsFile f = do
    586 592
           Nothing -> Left $ "Can't parse settings file " ++ show settingsFile
    
    587 593
         f settingsFile mySettings
    
    588 594
     
    
    589
    -readFromTargetFile :: FilePath
    
    595
    +readFromTargetFile :: OsPath
    
    590 596
                        -> (Target -> b)
    
    591 597
                        -> IO (Either String b)
    
    592 598
     readFromTargetFile targetFile f = do
    
    593
    -  targetStr <- readFile targetFile
    
    599
    +  targetStr <- readUtf8File targetFile
    
    594 600
       pure $ do
    
    595 601
         target <- case maybeReadFuzzy targetStr of
    
    596 602
           Just t -> Right t
    
    ... ... @@ -626,33 +632,35 @@ getPkgDatabases verbosity mode use_user use_cache expand_vars my_flags = do
    626 632
          case [ f | FlagGlobalConfig f <- my_flags ] of
    
    627 633
             -- See Note [Base Dir] for more information on the base dir / top dir.
    
    628 634
             [] -> do mb_dir <- getBaseDir
    
    629
    -                 case mb_dir of
    
    635
    +                 mb_dir_os <- traverse encodeFS mb_dir
    
    636
    +                 case mb_dir_os of
    
    630 637
                        Nothing  -> die err_msg
    
    631 638
                        Just dir -> do
    
    632 639
                          -- Look for where it is given in the settings file, if marked there.
    
    633 640
                          -- See Note [Settings file] about this file, and why we need GHC to share it with us.
    
    634
    -                     let settingsFile = dir </> "settings"
    
    641
    +                     let settingsFile = dir </> os "settings"
    
    635 642
                          exists_settings_file <- doesFileExist settingsFile
    
    636 643
                          erel_db <-
    
    637 644
                           if exists_settings_file
    
    638
    -                          then readFromSettingsFile settingsFile getGlobalPackageDb
    
    639
    -                          else pure (Left ("Settings file doesn't exist: " ++ settingsFile))
    
    645
    +                          then do
    
    646
    +                            readFromSettingsFile settingsFile (\ settings  -> getGlobalPackageDb (unsafeDecodeUtf settings))
    
    647
    +                          else pure (Left ("Settings file doesn't exist: " ++ showOsPath settingsFile))
    
    640 648
     
    
    641 649
                          case erel_db of
    
    642
    -                      Right rel_db -> return (dir, dir </> rel_db)
    
    650
    +                      Right rel_db -> return (dir, dir </> unsafeEncodeUtf rel_db)
    
    643 651
                           -- If the version of GHC doesn't have this field or the settings file
    
    644 652
                           -- doesn't exist for some reason, look in the libdir.
    
    645 653
                           Left err -> do
    
    646 654
                             r <- lookForPackageDBIn dir
    
    647 655
                             case r of
    
    648
    -                          Nothing -> die (unlines [err, ("Fallback: Can't find package database in " ++ dir)])
    
    656
    +                          Nothing -> die (unlines [err, ("Fallback: Can't find package database in " ++ showOsPath dir)])
    
    649 657
                               Just path -> return (dir, path)
    
    650 658
             fs -> do
    
    651 659
               -- The value of the $topdir variable used in some package descriptions
    
    652 660
               -- Note that the way we calculate this is slightly different to how it
    
    653 661
               -- is done in ghc itself. We rely on the convention that the global
    
    654 662
               -- package db lives in ghc's libdir.
    
    655
    -          let pkg_db = last fs
    
    663
    +          let pkg_db = unsafeEncodeUtf $ last fs
    
    656 664
               top_dir <- absolutePath (takeDirectory pkg_db)
    
    657 665
               return (top_dir, pkg_db)
    
    658 666
     
    
    ... ... @@ -662,10 +670,10 @@ getPkgDatabases verbosity mode use_user use_cache expand_vars my_flags = do
    662 670
       -- getXdgDirectory can fail (e.g. if $HOME isn't set)
    
    663 671
     
    
    664 672
       mb_user_conf <-
    
    665
    -    case [ f | FlagUserConfig f <- my_flags ] of
    
    673
    +    case [ unsafeEncodeUtf f | FlagUserConfig f <- my_flags ] of
    
    666 674
           _ | no_user_db -> return Nothing
    
    667 675
           [] -> do
    
    668
    -        let targetFile = top_dir </> "targets" </> "default.target"
    
    676
    +        let targetFile = top_dir </> os "targets" </> os "default.target"
    
    669 677
             exists_settings_file <- doesFileExist targetFile
    
    670 678
             targetArchOS <- case exists_settings_file of
    
    671 679
               False -> do
    
    ... ... @@ -694,15 +702,15 @@ getPkgDatabases verbosity mode use_user use_cache expand_vars my_flags = do
    694 702
             -- otherwise we use $XDG_DATA_HOME/$UNIQUE_SUBDIR
    
    695 703
             --
    
    696 704
             -- UNIQUE_SUBDIR is typically a combination of the target platform and GHC version
    
    697
    -        m_appdir <- getFirstSuccess $ map (fmap (</> subdir))
    
    698
    -          [ getAppUserDataDirectory "ghc"  -- this is ~/.ghc/
    
    699
    -          , getXdgDirectory XdgData "ghc"  -- this is $XDG_DATA_HOME/
    
    705
    +        m_appdir <- getFirstSuccess $ map (fmap (</> unsafeEncodeUtf subdir))
    
    706
    +          [ getAppUserDataDirectory $ os "ghc"  -- this is ~/.ghc/
    
    707
    +          , getXdgDirectory XdgData $ os "ghc"  -- this is $XDG_DATA_HOME/
    
    700 708
               ]
    
    701 709
             case m_appdir of
    
    702 710
               Nothing -> return Nothing
    
    703 711
               Just dir -> do
    
    704 712
                 lookForPackageDBIn dir >>= \case
    
    705
    -              Nothing -> return (Just (dir </> "package.conf.d", False))
    
    713
    +              Nothing -> return (Just (dir </> os "package.conf.d", False))
    
    706 714
                   Just f  -> return (Just (f, True))
    
    707 715
           fs -> return (Just (last fs, True))
    
    708 716
     
    
    ... ... @@ -716,11 +724,11 @@ getPkgDatabases verbosity mode use_user use_cache expand_vars my_flags = do
    716 724
     
    
    717 725
       e_pkg_path <- tryIO (System.Environment.getEnv "GHC_PACKAGE_PATH")
    
    718 726
       let env_stack =
    
    719
    -        case e_pkg_path of
    
    727
    +        case fmap unsafeEncodeUtf e_pkg_path of
    
    720 728
                     Left  _ -> sys_databases
    
    721 729
                     Right path
    
    722
    -                  | not (null path) && isSearchPathSeparator (last path)
    
    723
    -                  -> splitSearchPath (init path) ++ sys_databases
    
    730
    +                  | hasTrailingPathSeparator path
    
    731
    +                  -> splitSearchPath (dropTrailingPathSeparator path) <> sys_databases
    
    724 732
                       | otherwise
    
    725 733
                       -> splitSearchPath path
    
    726 734
     
    
    ... ... @@ -733,7 +741,7 @@ getPkgDatabases verbosity mode use_user use_cache expand_vars my_flags = do
    733 741
                           | Just (user_conf, _user_exists) <- mb_user_conf
    
    734 742
                           = Just user_conf
    
    735 743
                    is_db_flag FlagGlobal     = Just virt_global_conf
    
    736
    -               is_db_flag (FlagConfig f) = Just f
    
    744
    +               is_db_flag (FlagConfig f) = Just $ unsafeEncodeUtf f
    
    737 745
                    is_db_flag _              = Nothing
    
    738 746
     
    
    739 747
       let flag_db_names | null db_flags = env_stack
    
    ... ... @@ -748,7 +756,7 @@ getPkgDatabases verbosity mode use_user use_cache expand_vars my_flags = do
    748 756
       -- stack, unless any of them are present in the stack
    
    749 757
       -- already.
    
    750 758
       let final_stack = filter (`notElem` env_stack)
    
    751
    -                     [ f | FlagConfig f <- reverse my_flags ]
    
    759
    +                     [ unsafeEncodeUtf f | FlagConfig f <- reverse my_flags ]
    
    752 760
                          ++ env_stack
    
    753 761
     
    
    754 762
           top_db = if null db_flags
    
    ... ... @@ -764,7 +772,7 @@ getPkgDatabases verbosity mode use_user use_cache expand_vars my_flags = do
    764 772
       when (verbosity > Normal) $ do
    
    765 773
         infoLn ("db stack: " ++ show (map location db_stack))
    
    766 774
         F.forM_ db_to_operate_on $ \db ->
    
    767
    -      infoLn ("modifying: " ++ (location db))
    
    775
    +      infoLn ("modifying: " ++ showOsPath (location db))
    
    768 776
         infoLn ("flag db stack: " ++ show (map location flag_db_stack))
    
    769 777
     
    
    770 778
       return (db_stack, db_to_operate_on, flag_db_stack)
    
    ... ... @@ -843,17 +851,19 @@ getPkgDatabases verbosity mode use_user use_cache expand_vars my_flags = do
    843 851
     
    
    844 852
             return (db_stack, GhcPkg.DbOpenReadWrite to_modify)
    
    845 853
           where
    
    846
    -        couldntOpenDbForModification :: FilePath -> IOError -> IO a
    
    854
    +        couldntOpenDbForModification :: OsPath -> IOError -> IO a
    
    847 855
             couldntOpenDbForModification db_path e = die $ "Couldn't open database "
    
    848
    -          ++ db_path ++ " for modification: " ++ show e
    
    856
    +          ++ showOsPath db_path ++ " for modification: " ++ show e
    
    849 857
     
    
    850 858
             -- Parse package db in read-only mode.
    
    851
    -        readDatabase :: FilePath -> IO (PackageDB 'GhcPkg.DbReadOnly)
    
    859
    +        readDatabase :: OsPath -> IO (PackageDB 'GhcPkg.DbReadOnly)
    
    852 860
             readDatabase db_path = do
    
    853 861
               db <- readParseDatabase verbosity mb_user_conf
    
    854 862
                                       GhcPkg.DbOpenReadOnly use_cache db_path
    
    855 863
               if expand_vars
    
    856
    -            then return $ mungePackageDBPaths top_dir db
    
    864
    +            then do
    
    865
    +              top_dir_filepath <- decodeFS top_dir
    
    866
    +              return $ mungePackageDBPaths top_dir_filepath db
    
    857 867
                 else return db
    
    858 868
     
    
    859 869
         stateSequence :: Monad m => s -> [s -> m (a, s)] -> m ([a], s)
    
    ... ... @@ -863,20 +873,20 @@ getPkgDatabases verbosity mode use_user use_cache expand_vars my_flags = do
    863 873
           (as, s'') <- stateSequence s' ms
    
    864 874
           return (a : as, s'')
    
    865 875
     
    
    866
    -lookForPackageDBIn :: FilePath -> IO (Maybe FilePath)
    
    876
    +lookForPackageDBIn :: OsPath -> IO (Maybe OsPath)
    
    867 877
     lookForPackageDBIn dir = do
    
    868
    -  let path_dir = dir </> "package.conf.d"
    
    878
    +  let path_dir = dir </> os "package.conf.d"
    
    869 879
       exists_dir <- doesDirectoryExist path_dir
    
    870 880
       if exists_dir then return (Just path_dir) else do
    
    871
    -    let path_file = dir </> "package.conf"
    
    881
    +    let path_file = dir </> os "package.conf"
    
    872 882
         exists_file <- doesFileExist path_file
    
    873 883
         if exists_file then return (Just path_file) else return Nothing
    
    874 884
     
    
    875 885
     readParseDatabase :: forall mode t. Verbosity
    
    876
    -                  -> Maybe (FilePath,Bool)
    
    886
    +                  -> Maybe (OsPath,Bool)
    
    877 887
                       -> GhcPkg.DbOpenMode mode t
    
    878 888
                       -> Bool -- use cache
    
    879
    -                  -> FilePath
    
    889
    +                  -> OsPath
    
    880 890
                       -> IO (PackageDB mode)
    
    881 891
     readParseDatabase verbosity mb_user_conf mode use_cache path
    
    882 892
       -- the user database (only) is allowed to be non-existent
    
    ... ... @@ -898,7 +908,7 @@ readParseDatabase verbosity mb_user_conf mode use_cache path
    898 908
                     Just db -> return db
    
    899 909
                     Nothing ->
    
    900 910
                       die $ "ghc no longer supports single-file style package "
    
    901
    -                     ++ "databases (" ++ path ++ ") use 'ghc-pkg init'"
    
    911
    +                     ++ "databases (" ++ showOsPath path ++ ") use 'ghc-pkg init'"
    
    902 912
                          ++ "to create the database with the correct format."
    
    903 913
     
    
    904 914
                | otherwise -> ioError err
    
    ... ... @@ -914,7 +924,7 @@ readParseDatabase verbosity mb_user_conf mode use_cache path
    914 924
                             -- It's fine if the cache is not there as long as the
    
    915 925
                             -- database is empty.
    
    916 926
                             when (not $ null confs) $ do
    
    917
    -                            warn ("WARNING: cache does not exist: " ++ cache)
    
    927
    +                            warn ("WARNING: cache does not exist: " ++ showOsPath cache)
    
    918 928
                                 warn ("ghc will fail to read this package db. " ++
    
    919 929
                                       recacheAdvice)
    
    920 930
                           else do
    
    ... ... @@ -923,7 +933,7 @@ readParseDatabase verbosity mb_user_conf mode use_cache path
    923 933
                       ignore_cache (const $ return ())
    
    924 934
                     Right tcache -> do
    
    925 935
                       when (verbosity >= Verbose) $ do
    
    926
    -                      warn ("Timestamp " ++ show tcache ++ " for " ++ cache)
    
    936
    +                      warn ("Timestamp " ++ show tcache ++ " for " ++ showOsPath cache)
    
    927 937
                       -- If any of the .conf files is newer than package.cache, we
    
    928 938
                       -- assume that cache is out of date.
    
    929 939
                       cache_outdated <- (`anyM` confs) $ \conf ->
    
    ... ... @@ -931,12 +941,12 @@ readParseDatabase verbosity mb_user_conf mode use_cache path
    931 941
                       if not cache_outdated
    
    932 942
                           then do
    
    933 943
                               when (verbosity > Normal) $
    
    934
    -                             infoLn ("using cache: " ++ cache)
    
    944
    +                             infoLn ("using cache: " ++ showOsPath cache)
    
    935 945
                               GhcPkg.readPackageDbForGhcPkg cache mode
    
    936 946
                                 >>= uncurry mkPackageDB
    
    937 947
                           else do
    
    938 948
                               whenReportCacheErrors $ do
    
    939
    -                              warn ("WARNING: cache is out of date: " ++ cache)
    
    949
    +                              warn ("WARNING: cache is out of date: " ++ showOsPath cache)
    
    940 950
                                   warn ("ghc will see an old view of this " ++
    
    941 951
                                         "package db. " ++ recacheAdvice)
    
    942 952
                               ignore_cache $ \file -> do
    
    ... ... @@ -947,11 +957,11 @@ readParseDatabase verbosity mb_user_conf mode use_cache path
    947 957
                                         GT -> " (older than cache)"
    
    948 958
                                         EQ -> " (same as cache)"
    
    949 959
                                   warn ("Timestamp " ++ show tFile
    
    950
    -                                ++ " for " ++ file ++ rel)
    
    960
    +                                ++ " for " ++ showOsPath file ++ rel)
    
    951 961
                 where
    
    952
    -                 confs = map (path </>) $ filter (".conf" `isSuffixOf`) fs
    
    962
    +                 confs = map (path </>) $ filter (os ".conf" `OsPath.isExtensionOf`) fs
    
    953 963
     
    
    954
    -                 ignore_cache :: (FilePath -> IO ()) -> IO (PackageDB mode)
    
    964
    +                 ignore_cache :: (OsPath -> IO ()) -> IO (PackageDB mode)
    
    955 965
                      ignore_cache checkTime = do
    
    956 966
                          -- If we're opening for modification, we need to acquire a
    
    957 967
                          -- lock even if we don't open the cache now, because we are
    
    ... ... @@ -987,17 +997,18 @@ readParseDatabase verbosity mb_user_conf mode use_cache path
    987 997
               packages = pkgs
    
    988 998
             }
    
    989 999
     
    
    990
    -parseSingletonPackageConf :: Verbosity -> FilePath -> IO InstalledPackageInfo
    
    1000
    +parseSingletonPackageConf :: Verbosity -> OsPath -> IO InstalledPackageInfo
    
    991 1001
     parseSingletonPackageConf verbosity file = do
    
    992
    -  when (verbosity > Normal) $ infoLn ("reading package config: " ++ file)
    
    993
    -  BS.readFile file >>= fmap fst . parsePackageInfo
    
    1002
    +  when (verbosity > Normal) $ infoLn ("reading package config: " ++ showOsPath file)
    
    1003
    +  FileIO.readFile file >>= fmap fst . parsePackageInfo . BS.toStrict
    
    1004
    +
    
    994 1005
     
    
    995
    -cachefilename :: FilePath
    
    996
    -cachefilename = "package.cache"
    
    1006
    +cachefilename :: OsPath
    
    1007
    +cachefilename = os "package.cache"
    
    997 1008
     
    
    998 1009
     mungePackageDBPaths :: FilePath -> PackageDB mode -> PackageDB mode
    
    999 1010
     mungePackageDBPaths top_dir db@PackageDB { packages = pkgs } =
    
    1000
    -    db { packages = map (mungePackagePaths top_dir pkgroot) pkgs }
    
    1011
    +    db { packages = map (mungePackagePaths top_dir (unsafeDecodeUtf pkgroot)) pkgs }
    
    1001 1012
       where
    
    1002 1013
         pkgroot = takeDirectory $ dropTrailingPathSeparator (locationAbsolute db)
    
    1003 1014
         -- It so happens that for both styles of package db ("package.conf"
    
    ... ... @@ -1044,12 +1055,13 @@ mkMungePathUrl top_dir pkgroot = (munge_path, munge_url)
    1044 1055
           | Just p' <- stripVarPrefix "$httptopdir"   p = toUrlPath top_dir p'
    
    1045 1056
           | otherwise                                   = p
    
    1046 1057
     
    
    1058
    +    toUrlPath :: FilePath -> FilePath -> FilePath
    
    1047 1059
         toUrlPath r p = "file:///"
    
    1048 1060
                      -- URLs always use posix style '/' separators:
    
    1049 1061
                      ++ FilePath.Posix.joinPath
    
    1050 1062
                             (r : -- We need to drop a leading "/" or "\\"
    
    1051 1063
                                  -- if there is one:
    
    1052
    -                             dropWhile (all isPathSeparator)
    
    1064
    +                             dropWhile (all FilePath.isPathSeparator)
    
    1053 1065
                                            (FilePath.splitDirectories p))
    
    1054 1066
     
    
    1055 1067
         -- We could drop the separator here, and then use </> above. However,
    
    ... ... @@ -1057,7 +1069,7 @@ mkMungePathUrl top_dir pkgroot = (munge_path, munge_url)
    1057 1069
         -- rather than letting FilePath change it to use \ as the separator
    
    1058 1070
         stripVarPrefix var path = case stripPrefix var path of
    
    1059 1071
                                   Just [] -> Just []
    
    1060
    -                              Just cs@(c : _) | isPathSeparator c -> Just cs
    
    1072
    +                              Just cs@(c : _) | FilePath.isPathSeparator c -> Just cs
    
    1061 1073
                                   _ -> Nothing
    
    1062 1074
     
    
    1063 1075
     -- -----------------------------------------------------------------------------
    
    ... ... @@ -1074,18 +1086,18 @@ mkMungePathUrl top_dir pkgroot = (munge_path, munge_url)
    1074 1086
     
    
    1075 1087
     -- ghc itself also cooperates in this workaround
    
    1076 1088
     
    
    1077
    -tryReadParseOldFileStyleDatabase :: Verbosity -> Maybe (FilePath, Bool)
    
    1078
    -                                 -> GhcPkg.DbOpenMode mode t -> Bool -> FilePath
    
    1089
    +tryReadParseOldFileStyleDatabase :: Verbosity -> Maybe (OsPath, Bool)
    
    1090
    +                                 -> GhcPkg.DbOpenMode mode t -> Bool -> OsPath
    
    1079 1091
                                      -> IO (Maybe (PackageDB mode))
    
    1080 1092
     tryReadParseOldFileStyleDatabase verbosity mb_user_conf
    
    1081 1093
                                      mode use_cache path = do
    
    1082 1094
       -- assumes we've already established that path exists and is not a dir
    
    1083
    -  content <- readFile path `catchIO` \_ -> return ""
    
    1095
    +  content <- readUtf8File path `catchIO` \_ -> return ""
    
    1084 1096
       if take 2 content == "[]"
    
    1085 1097
         then do
    
    1086 1098
           path_abs <- absolutePath path
    
    1087 1099
           let path_dir = adjustOldDatabasePath path
    
    1088
    -      warn $ "Warning: ignoring old file-style db and trying " ++ path_dir
    
    1100
    +      warn $ "Warning: ignoring old file-style db and trying " ++ showOsPath path_dir
    
    1089 1101
           direxists <- doesDirectoryExist path_dir
    
    1090 1102
           if direxists
    
    1091 1103
             then do
    
    ... ... @@ -1112,7 +1124,7 @@ tryReadParseOldFileStyleDatabase verbosity mb_user_conf
    1112 1124
     adjustOldFileStylePackageDB :: PackageDB mode -> IO (PackageDB mode)
    
    1113 1125
     adjustOldFileStylePackageDB db = do
    
    1114 1126
       -- assumes we have not yet established if it's an old style or not
    
    1115
    -  mcontent <- liftM Just (readFile (location db)) `catchIO` \_ -> return Nothing
    
    1127
    +  mcontent <- liftM Just (readUtf8File (location db)) `catchIO` \_ -> return Nothing
    
    1116 1128
       case fmap (take 2) mcontent of
    
    1117 1129
         -- it is an old style and empty db, so look for a dir kind in location.d/
    
    1118 1130
         Just "[]" -> return db {
    
    ... ... @@ -1121,20 +1133,20 @@ adjustOldFileStylePackageDB db = do
    1121 1133
           }
    
    1122 1134
         -- it is old style but not empty, we have to bail
    
    1123 1135
         Just  _   -> die $ "ghc no longer supports single-file style package "
    
    1124
    -                    ++ "databases (" ++ location db ++ ") use 'ghc-pkg init'"
    
    1136
    +                    ++ "databases (" ++ showOsPath (location db) ++ ") use 'ghc-pkg init'"
    
    1125 1137
                         ++ "to create the database with the correct format."
    
    1126 1138
         -- probably not old style, carry on as normal
    
    1127 1139
         Nothing   -> return db
    
    1128 1140
     
    
    1129
    -adjustOldDatabasePath :: FilePath -> FilePath
    
    1130
    -adjustOldDatabasePath = (<.> "d")
    
    1141
    +adjustOldDatabasePath :: OsPath -> OsPath
    
    1142
    +adjustOldDatabasePath = (<.> os "d")
    
    1131 1143
     
    
    1132 1144
     -- -----------------------------------------------------------------------------
    
    1133 1145
     -- Creating a new package DB
    
    1134 1146
     
    
    1135
    -initPackageDB :: FilePath -> Verbosity -> [Flag] -> IO ()
    
    1147
    +initPackageDB :: OsPath -> Verbosity -> [Flag] -> IO ()
    
    1136 1148
     initPackageDB filename verbosity _flags = do
    
    1137
    -  let eexist = die ("cannot create: " ++ filename ++ " already exists")
    
    1149
    +  let eexist = die ("cannot create: " ++ showOsPath filename ++ " already exists")
    
    1138 1150
       b1 <- doesFileExist filename
    
    1139 1151
       when b1 eexist
    
    1140 1152
       b2 <- doesDirectoryExist filename
    
    ... ... @@ -1183,7 +1195,8 @@ registerPackage input verbosity my_flags multi_instance
    1183 1195
           f   -> do
    
    1184 1196
             when (verbosity >= Normal) $
    
    1185 1197
                 info ("Reading package info from " ++ show f ++ " ... ")
    
    1186
    -        readUTF8File f
    
    1198
    +        fs <- encodeFS f
    
    1199
    +        readUtf8File fs
    
    1187 1200
     
    
    1188 1201
       expanded <- if expand_env_vars then expandEnvVars s force
    
    1189 1202
                                      else return s
    
    ... ... @@ -1199,7 +1212,11 @@ registerPackage input verbosity my_flags multi_instance
    1199 1212
       -- validate the expanded pkg, but register the unexpanded
    
    1200 1213
       pkgroot <- absolutePath (takeDirectory to_modify)
    
    1201 1214
       let top_dir = takeDirectory (location (last db_stack))
    
    1202
    -      pkg_expanded = mungePackagePaths top_dir pkgroot pkg
    
    1215
    +
    
    1216
    +  top_dir_filepath <- decodeFS top_dir
    
    1217
    +  pkgroot_filepath <- decodeFS pkgroot
    
    1218
    +  let
    
    1219
    +      pkg_expanded = mungePackagePaths top_dir_filepath pkgroot_filepath pkg
    
    1203 1220
     
    
    1204 1221
       let truncated_stack = stackUpTo to_modify db_stack
    
    1205 1222
       -- truncate the stack for validation, because we don't allow
    
    ... ... @@ -1274,13 +1291,13 @@ changeDBDir verbosity cmds db db_stack = do
    1274 1291
       updateDBCache verbosity db db_stack
    
    1275 1292
      where
    
    1276 1293
       do_cmd (RemovePackage p) = do
    
    1277
    -    let file = location db </> display (installedUnitId p) <.> "conf"
    
    1278
    -    when (verbosity > Normal) $ infoLn ("removing " ++ file)
    
    1294
    +    let file = location db </> unsafeEncodeUtf (display (installedUnitId p)) <.> os "conf"
    
    1295
    +    when (verbosity > Normal) $ infoLn ("removing " ++ showOsPath file)
    
    1279 1296
         removeFileSafe file
    
    1280 1297
       do_cmd (AddPackage p) = do
    
    1281
    -    let file = location db </> display (installedUnitId p) <.> "conf"
    
    1282
    -    when (verbosity > Normal) $ infoLn ("writing " ++ file)
    
    1283
    -    writeUTF8File file (showInstalledPackageInfo p)
    
    1298
    +    let file = location db </> unsafeEncodeUtf (display (installedUnitId p)) <.> os "conf"
    
    1299
    +    when (verbosity > Normal) $ infoLn ("writing " ++ showOsPath file)
    
    1300
    +    writeUtf8File file (showInstalledPackageInfo p)
    
    1284 1301
       do_cmd (ModifyPackage p) =
    
    1285 1302
         do_cmd (AddPackage p)
    
    1286 1303
     
    
    ... ... @@ -1338,13 +1355,13 @@ updateDBCache verbosity db db_stack = do
    1338 1355
                 warn $ "    " ++ pkg
    
    1339 1356
     
    
    1340 1357
       when (verbosity > Normal) $
    
    1341
    -      infoLn ("writing cache " ++ filename)
    
    1358
    +      infoLn ("writing cache " ++ showOsPath filename)
    
    1342 1359
     
    
    1343 1360
       let d = fmap (fromPackageCacheFormat . fst) pkgsGhcCacheFormat
    
    1344 1361
       GhcPkg.writePackageDb filename d pkgsCabalFormat
    
    1345 1362
         `catchIO` \e ->
    
    1346 1363
           if isPermissionError e
    
    1347
    -      then die $ filename ++ ": you don't have permission to modify this file"
    
    1364
    +      then die $ showOsPath filename ++ ": you don't have permission to modify this file"
    
    1348 1365
           else ioError e
    
    1349 1366
     
    
    1350 1367
       case packageDbLock db of
    
    ... ... @@ -1583,7 +1600,7 @@ listPackages verbosity my_flags mPackageName mModuleName = do
    1583 1600
           broken = map installedUnitId (brokenPackages pkg_map)
    
    1584 1601
     
    
    1585 1602
           show_normal PackageDB{ location = db_name, packages = pkg_confs } =
    
    1586
    -          do hPutStrLn stdout db_name
    
    1603
    +          do hPutStrLn stdout (showOsPath db_name)
    
    1587 1604
                  if null pkg_confs
    
    1588 1605
                      then hPutStrLn stdout "    (no packages)"
    
    1589 1606
                      else hPutStrLn stdout $ unlines (map ("    " ++) (map pp_pkg pkg_confs))
    
    ... ... @@ -1610,7 +1627,7 @@ listPackages verbosity my_flags mPackageName mModuleName = do
    1610 1627
     #else
    
    1611 1628
         let
    
    1612 1629
           show_colour PackageDB{ location = db_name, packages = pkg_confs } =
    
    1613
    -          do hPutStrLn stdout db_name
    
    1630
    +          do hPutStrLn stdout (showOsPath db_name)
    
    1614 1631
                  if null pkg_confs
    
    1615 1632
                      then hPutStrLn stdout "    (no packages)"
    
    1616 1633
                      else hPutStrLn stdout $ unlines (map ("    " ++) (map pp_pkg pkg_confs))
    
    ... ... @@ -1698,7 +1715,7 @@ dumpUnits verbosity my_flags expand_pkgroot = do
    1698 1715
       doDump expand_pkgroot [ (pkg, locationAbsolute db)
    
    1699 1716
                             | db <- flag_db_stack, pkg <- packages db ]
    
    1700 1717
     
    
    1701
    -doDump :: Bool -> [(InstalledPackageInfo, FilePath)] -> IO ()
    
    1718
    +doDump :: Bool -> [(InstalledPackageInfo, OsPath)] -> IO ()
    
    1702 1719
     doDump expand_pkgroot pkgs = do
    
    1703 1720
       -- fix the encoding to UTF-8, since this is an interchange format
    
    1704 1721
       hSetEncoding stdout utf8
    
    ... ... @@ -1731,7 +1748,7 @@ findPackagesByDB db_stack pkgarg
    1731 1748
     
    
    1732 1749
     cannotFindPackage :: PackageArg -> Maybe (PackageDB mode) -> IO a
    
    1733 1750
     cannotFindPackage pkgarg mdb = die $ "cannot find package " ++ pkg_msg pkgarg
    
    1734
    -  ++ maybe "" (\db -> " in " ++ location db) mdb
    
    1751
    +  ++ maybe "" (\db -> " in " ++ showOsPath (location db)) mdb
    
    1735 1752
       where
    
    1736 1753
         pkg_msg (Id pkgid)           = displayGlobPkgId pkgid
    
    1737 1754
         pkg_msg (IUId ipid)          = display ipid
    
    ... ... @@ -1944,7 +1961,7 @@ checkPackageConfig pkg verbosity db_stack
    1944 1961
       checkExposedModules db_stack pkg
    
    1945 1962
       checkOtherModules pkg
    
    1946 1963
       let has_code = Set.null (openModuleSubstFreeHoles (Map.fromList (instantiatedWith pkg)))
    
    1947
    -  when has_code $ mapM_ (checkHSLib verbosity (libraryDirs pkg ++ libraryDynDirs pkg)) (hsLibraries pkg)
    
    1964
    +  when has_code $ mapM_ (checkHSLib verbosity (fmap unsafeEncodeUtf $ libraryDirs pkg ++ libraryDynDirs pkg)) (hsLibraries pkg)
    
    1948 1965
       -- ToDo: check these somehow?
    
    1949 1966
       --    extra_libraries :: [String],
    
    1950 1967
       --    c_includes      :: [String],
    
    ... ... @@ -2011,20 +2028,20 @@ checkPath url_ok is_dir warn_only thisfield d
    2011 2028
                || "https://" `isPrefixOf` d) = return ()
    
    2012 2029
     
    
    2013 2030
      | url_ok
    
    2014
    - , Just d' <- stripPrefix "file://" d
    
    2015
    - = checkPath False is_dir warn_only thisfield d'
    
    2031
    + , Just f <- stripPrefix "file://" d
    
    2032
    + = checkPath False is_dir warn_only thisfield f
    
    2016 2033
     
    
    2017 2034
        -- Note: we don't check for $topdir/${pkgroot} here. We rely on these
    
    2018 2035
        -- variables having been expanded already, see mungePackagePaths.
    
    2019 2036
     
    
    2020
    - | isRelative d = verror ForceFiles $
    
    2037
    + | isRelative d' = verror ForceFiles $
    
    2021 2038
                          thisfield ++ ": " ++ d ++ " is a relative path which "
    
    2022 2039
                       ++ "makes no sense (as there is nothing for it to be "
    
    2023 2040
                       ++ "relative to). You can make paths relative to the "
    
    2024 2041
                       ++ "package database itself by using ${pkgroot}."
    
    2025 2042
             -- relative paths don't make any sense; #4134
    
    2026 2043
      | otherwise = do
    
    2027
    -   there <- liftIO $ if is_dir then doesDirectoryExist d else doesFileExist d
    
    2044
    +   there <- liftIO $ if is_dir then doesDirectoryExist d' else doesFileExist d'
    
    2028 2045
        when (not there) $
    
    2029 2046
            let msg = thisfield ++ ": " ++ d ++ " doesn't exist or isn't a "
    
    2030 2047
                                             ++ if is_dir then "directory" else "file"
    
    ... ... @@ -2032,6 +2049,8 @@ checkPath url_ok is_dir warn_only thisfield d
    2032 2049
            if warn_only
    
    2033 2050
               then vwarn msg
    
    2034 2051
               else verror ForceFiles msg
    
    2052
    +  where
    
    2053
    +   d' = unsafeEncodeUtf d
    
    2035 2054
     
    
    2036 2055
     checkDep :: PackageDBStack -> UnitId -> Validate ()
    
    2037 2056
     checkDep db_stack pkgid
    
    ... ... @@ -2050,24 +2069,25 @@ checkDuplicateDepends deps
    2050 2069
       where
    
    2051 2070
            dups = [ p | (p:_:_) <- group (sort deps) ]
    
    2052 2071
     
    
    2053
    -checkHSLib :: Verbosity -> [String] -> String -> Validate ()
    
    2072
    +checkHSLib :: Verbosity -> [OsPath] -> String -> Validate ()
    
    2054 2073
     checkHSLib _verbosity dirs lib = do
    
    2055
    -  let filenames = ["lib" ++ lib ++ ".a",
    
    2056
    -                   "lib" ++ lib ++ "_p.a",
    
    2057
    -                   "lib" ++ lib ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".so",
    
    2058
    -                   "lib" ++ lib ++ "_p" ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".so",
    
    2059
    -                   "lib" ++ lib ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".dylib",
    
    2060
    -                   "lib" ++ lib ++ "_p" ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".dylib",
    
    2061
    -                   lib ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".dll",
    
    2062
    -                   lib ++ "_p" ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".dll",
    
    2063
    -                   lib ++ ".bytecodelib"
    
    2064
    -                  ]
    
    2074
    +  let filenames = fmap OsPath.unsafeEncodeUtf
    
    2075
    +        [ "lib" ++ lib ++ ".a"
    
    2076
    +        , "lib" ++ lib ++ "_p.a"
    
    2077
    +        , "lib" ++ lib ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".so"
    
    2078
    +        , "lib" ++ lib ++ "_p" ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".so"
    
    2079
    +        , "lib" ++ lib ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".dylib"
    
    2080
    +        , "lib" ++ lib ++ "_p" ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".dylib"
    
    2081
    +        , lib ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".dll"
    
    2082
    +        , lib ++ "_p" ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".dll"
    
    2083
    +        , lib ++ ".bytecodelib"
    
    2084
    +        ]
    
    2065 2085
       b <- liftIO $ doesFileExistOnPath filenames dirs
    
    2066 2086
       when (not b) $
    
    2067 2087
         verror ForceFiles ("cannot find any of " ++ show filenames ++
    
    2068 2088
                            " on library path")
    
    2069 2089
     
    
    2070
    -doesFileExistOnPath :: [FilePath] -> [FilePath] -> IO Bool
    
    2090
    +doesFileExistOnPath :: [OsPath] -> [OsPath] -> IO Bool
    
    2071 2091
     doesFileExistOnPath filenames paths = anyM doesFileExist fullFilenames
    
    2072 2092
       where fullFilenames = [ path </> filename
    
    2073 2093
                             | filename <- filenames
    
    ... ... @@ -2096,9 +2116,9 @@ checkModuleFile :: InstalledPackageInfo -> ModuleName -> Validate ()
    2096 2116
     checkModuleFile pkg modl =
    
    2097 2117
           -- there's no interface file for GHC.Prim
    
    2098 2118
           unless (modl == ModuleName.fromString "GHC.Prim") $ do
    
    2099
    -      let files = [ ModuleName.toFilePath modl <.> extension
    
    2100
    -                  | extension <- ["hi", "p_hi", "dyn_hi", "p_dyn_hi"] ]
    
    2101
    -      b <- liftIO $ doesFileExistOnPath files (importDirs pkg)
    
    2119
    +      let files = [ unsafeEncodeUtf (ModuleName.toFilePath modl) <.> extension
    
    2120
    +                  | extension <- fmap os ["hi", "p_hi", "dyn_hi", "p_dyn_hi"] ]
    
    2121
    +      b <- liftIO $ doesFileExistOnPath files (fmap unsafeEncodeUtf $ importDirs pkg)
    
    2102 2122
           when (not b) $
    
    2103 2123
              verror ForceFiles ("cannot find any of " ++ show files)
    
    2104 2124
     
    
    ... ... @@ -2273,19 +2293,45 @@ installSignalHandlers = do
    2273 2293
       return ()
    
    2274 2294
     #endif
    
    2275 2295
     
    
    2296
    +-- ------------------------------------------------
    
    2297
    +-- OsPath Utils
    
    2298
    +
    
    2299
    +-- | Show an 'OsPath', throwing an exception if we fail to decode it.
    
    2300
    +showOsPath :: HasCallStack => OsPath -> FilePath
    
    2301
    +showOsPath = unsafePerformIO . decodeFS
    
    2302
    +
    
    2303
    +-- | Turn a path relative to the current directory into a (normalised)
    
    2304
    +-- absolute path.
    
    2305
    +absolutePath :: OsPath -> IO OsPath
    
    2306
    +absolutePath path = return . normalise . (</> path) =<< getCurrentDirectory
    
    2307
    +
    
    2308
    +-- ------------------------------------------------
    
    2309
    +
    
    2276 2310
     catchIO :: IO a -> (Exception.IOException -> IO a) -> IO a
    
    2277 2311
     catchIO = catchException
    
    2278 2312
     
    
    2279 2313
     tryIO :: IO a -> IO (Either Exception.IOException a)
    
    2280 2314
     tryIO = Exception.try
    
    2281 2315
     
    
    2282
    --- removeFileSave doesn't throw an exceptions, if the file is already deleted
    
    2283
    -removeFileSafe :: FilePath -> IO ()
    
    2316
    +-----------------------------------------
    
    2317
    +-- Adapted from ghc/compiler/utils/Panic
    
    2318
    +
    
    2319
    +-- | 'removeFileSave' doesn't throw an exceptions, if the file is already deleted
    
    2320
    +removeFileSafe :: OsPath -> IO ()
    
    2284 2321
     removeFileSafe fn =
    
    2285 2322
       removeFile fn `catchIO` \ e ->
    
    2286 2323
         when (not $ isDoesNotExistError e) $ ioError e
    
    2287 2324
     
    
    2288
    --- | Turn a path relative to the current directory into a (normalised)
    
    2289
    --- absolute path.
    
    2290
    -absolutePath :: FilePath -> IO FilePath
    
    2291
    -absolutePath path = return . normalise . (</> path) =<< getCurrentDirectory
    2325
    +-- | Read a file using UTF-8 encoding
    
    2326
    +--
    
    2327
    +-- Taken from https://github.com/haskell/cabal/blob/cea1d8ff1a80df3c3b3148d1556bd3edf656da93/Cabal-syntax/src/Distribution/Utils/Generic.hs#L326
    
    2328
    +-- and adapted to 'OsPath'.
    
    2329
    +writeUtf8File :: OsPath -> String -> IO ()
    
    2330
    +writeUtf8File file contents = writeFileAtomic file (toUTF8LBS contents)
    
    2331
    +
    
    2332
    +-- | Read a file and interpret its content to be UTF-8 encoded.
    
    2333
    +--
    
    2334
    +-- Taken from https://github.com/haskell/cabal/blob/cea1d8ff1a80df3c3b3148d1556bd3edf656da93/Cabal-syntax/src/Distribution/Utils/Generic.hs#L309
    
    2335
    +-- and adapted to 'OsPath'.
    
    2336
    +readUtf8File :: OsPath -> IO String
    
    2337
    +readUtf8File file = (ignoreBOM . fromUTF8LBS) <$> FileIO.readFile file

  • utils/ghc-pkg/ghc-pkg.cabal.in
    ... ... @@ -25,6 +25,7 @@ Executable ghc-pkg
    25 25
                        process    >= 1   && < 1.7,
    
    26 26
                        containers,
    
    27 27
                        filepath,
    
    28
    +                   file-io,
    
    28 29
                        Cabal,
    
    29 30
                        Cabal-syntax,
    
    30 31
                        binary,