Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Revision history for configurator-pg

# Unreleased

* Fix loading `utf-8` file when locale encoding is set to `ASCII`

## 0.2.10 -- 2024-03-06

* Allow megaparsec-9.6
Expand Down
1 change: 1 addition & 0 deletions configurator-pg.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ library
Data.Configurator.Syntax
Data.Configurator.Types
build-depends: base >= 4.9 && < 4.22
, bytestring >= 0.10.8 && < 0.13
, megaparsec >= 7.0.0 && < 9.8
, containers >= 0.5.6.2 && < 0.8
, protolude >= 0.1.10 && < 0.4
Expand Down
4 changes: 3 additions & 1 deletion src/Data/Configurator/Load.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import Protolude

import Control.Exception (throw)
import Text.Megaparsec (parse, errorBundlePretty)
import qualified Data.ByteString as BS
import qualified Data.Map.Strict as M
import Data.Scientific (toBoundedInteger,
toRealFloat)
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import qualified Data.Text.Lazy as TL
import Data.Text.Lazy.Builder (fromString,
fromText,
Expand All @@ -31,7 +33,7 @@ load path = applyDirective "" "" M.empty (Import $ T.pack path)

loadOne :: Path -> IO [Directive]
loadOne path = do
s <- readFile (T.unpack path)
s <- T.decodeUtf8 <$> BS.readFile (T.unpack path)
case parse topLevel (T.unpack path) s of
Left err -> throw $ ParseError $ T.pack $ errorBundlePretty err
Right directives -> return directives
Expand Down
15 changes: 15 additions & 0 deletions tests/Test.hs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE CPP #-}

module Main where

import Protolude hiding (bool, list, optional)

import Data.Configurator
import qualified Data.Text as T
import qualified GHC.IO.Encoding as E
import qualified GHC.IO.Encoding.Latin1 as E
import System.Environment
import System.FilePath
import Test.Framework
Expand All @@ -20,6 +23,7 @@ tests :: [Test]
tests =
[ testCase "read-simple" $ readTest "simple.cfg"
, testCase "read-pathological" $ readTest "pathological.cfg"
, testCase "read-utf-8-with-ascii-locale" $ readTestWithLocale "utf-8.cfg" E.ascii

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: Prior to the change, did this one fail with:

hGetContents: invalid argument (cannot decode byte sequence starting from ..

Same as PostgREST/postgrest#4379 (comment)?

@taimoorzaeem taimoorzaeem Oct 9, 2025

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly! If I remove this change and re-run tests, I get:

read-utf-8-with-ascii-locale: [Failed]
ERROR: tests/resources/utf-8.cfg: hGetContents: invalid argument (cannot decode byte sequence starting from 195)

EDIT: A couple other tests slightly change in output, so I modified accordingly.

, testCase "load" loadTest
, testCase "load" loadTest
, testCase "types" typesTest
Expand Down Expand Up @@ -51,6 +55,9 @@ testFile name = "tests" </> "resources" </> name
errorFile :: FilePath -> FilePath
errorFile name = testFile name <> ".err"

errorFileGHC8 :: FilePath -> FilePath
errorFileGHC8 name = testFile name <> ".err.ghc8"

parse :: Config -> Parser Value a -> Key -> Either Text a
parse cfg p key = runParser (required key p) cfg

Expand All @@ -63,6 +70,10 @@ parseSub cfg p prefix = runParser (subassocs prefix p) cfg
readTest :: FilePath -> Assertion
readTest file = load (testFile file) >> return ()

readTestWithLocale :: FilePath -> E.TextEncoding -> Assertion
readTestWithLocale file locale =
E.setLocaleEncoding locale >> load (testFile file) >> return ()

loadTest :: Assertion
loadTest =
withLoad "pathological.cfg" $ \cfg -> do
Expand Down Expand Up @@ -233,7 +244,11 @@ parseErrorTest file = do

ioErrorTest :: FilePath -> Assertion
ioErrorTest file = do
#if __GLASGOW_HASKELL__ >= 900
err <- readFile $ errorFile file
#else
err <- readFile $ errorFileGHC8 file
#endif
(load (testFile file) >> assertFailure "expected an IO error")
`catch` \ (ex :: IOException) -> do
assertEqual "" err (show ex)
2 changes: 1 addition & 1 deletion tests/resources/err-import.cfg.err
Original file line number Diff line number Diff line change
@@ -1 +1 @@
tests/resources/not-exist.cfg: openFile: does not exist (No such file or directory)
tests/resources/not-exist.cfg: withBinaryFile: does not exist (No such file or directory)
Comment thread
steve-chavez marked this conversation as resolved.
1 change: 1 addition & 0 deletions tests/resources/err-import.cfg.err.ghc8
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tests/resources/not-exist.cfg: openBinaryFile: does not exist (No such file or directory)
2 changes: 2 additions & 0 deletions tests/resources/utf-8.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Commènt utf-8 chàrs
utf-kèy = "utf-8-vàlue"