Cabal-syntax-3.12.1.0: A library for working with .cabal files

Copyright | Isaac Jones Simon Marlow 2003-2004
License | BSD3 portions Copyright (c) 2007, Galois Inc.
Maintainer | cabal-devel@haskell.org
Portability | portable
Safe Haskell | None
Language | Haskell2010

Distribution.Utils.Generic

Contents

- reading and writing files safely
- Unicode
  - Conversions
  - File I/O
  - BOM
  - Misc
- generic utils
- Triples
- FilePath stuff

Description

A large and somewhat miscellaneous collection of utility functions used throughout the rest of the Cabal lib and in other tools that use the Cabal lib like `cabal-install`. It has a very simple set of logging actions. It has low level functions for running programs, a bunch of wrappers for various directory and file functions that do extra logging.

Synopsis

- withFileContents :: FilePath -> (String -> IO a) -> IO a
- writeFileAtomic :: FilePath -> ByteString -> IO ()
- fromUTF8BS :: ByteString -> String
- fromUTF8LBS :: ByteString -> String
- toUTF8BS :: String -> ByteString
- toUTF8LBS :: String -> ByteString
- validateUTF8 :: ByteString -> Maybe Int
- readUTF8File :: FilePath -> IO String
- withUTF8FileContents :: FilePath -> (String -> IO a) -> IO a
- writeUTF8File :: FilePath -> String -> IO ()
- ignoreBOM :: String -> String
- normaliseLineEndings :: String -> String
- dropWhileEndLE :: (a -> Bool) -> [a] -> [a]
- takeWhileEndLE :: (a -> Bool) -> [a] -> [a]
- equating :: Eq a => (b -> a) -> b -> b -> Bool
- comparing :: Ord a => (b -> a) -> b -> b -> Ordering
- isInfixOf :: Eq a => [a] -> [a] -> Bool
- intercalate :: [a] -> [[a]] -> [a]
- lowercase :: String -> String
- isAscii :: Char -> Bool
- isAsciiAlpha :: Char -> Bool
- isAsciiAlphaNum :: Char -> Bool
- listUnion :: Ord a => [a] -> [a] -> [a]
- listUnionRight :: Ord a => [a] -> [a] -> [a]
- ordNub :: Ord a => [a] -> [a]
- ordNubBy :: Ord b => (a -> b) -> [a] -> [a]
- ordNubRight :: Ord a => [a] -> [a]
- safeHead :: [a] -> Maybe a
- safeTail :: [a] -> [a]
- safeLast :: [a] -> Maybe a
- safeInit :: [a] -> [a]
- unintersperse :: Char -> String -> [String]
- wrapText :: String -> String
- wrapLine :: Int -> [String] -> [[String]]
- unfoldrM :: Monad m => (b -> m (Maybe (a, b))) -> b -> m [a]
- spanMaybe :: (a -> Maybe b) -> [a] -> ([b], [a])
- breakMaybe :: (a -> Maybe b) -> [a] -> ([a], Maybe (b, [a]))
- unsnoc :: [a] -> Maybe ([a], a)
- unsnocNE :: NonEmpty a -> ([a], a)
- fstOf3 :: (a, b, c) -> a
- sndOf3 :: (a, b, c) -> b
- trdOf3 :: (a, b, c) -> c
- isAbsoluteOnAnyPlatform :: FilePath -> Bool
- isRelativeOnAnyPlatform :: FilePath -> Bool

# reading and writing files safely

withFileContents :: FilePath -> (String -> IO a) -> IO a Source #

Gets the contents of a file, but guarantee that it gets closed.

The file is read lazily but if it is not fully consumed by the action then the remaining input is truncated and the file is closed.

writeFileAtomic :: FilePath -> ByteString -> IO () Source #

Writes a file atomically.

The file is either written successfully or an IO exception is raised and the original file is left unchanged.

On windows it is not possible to delete a file that is open by a process. This case will give an IO exception but the atomic property is not affected.

# Unicode

## Conversions

fromUTF8BS :: ByteString -> String Source #

Decode `String` from UTF8-encoded `ByteString`

Invalid data in the UTF8 stream (this includes code-points `U+D800` through `U+DFFF`) will be decoded as the replacement character (`U+FFFD`).

fromUTF8LBS :: ByteString -> String Source #

Variant of `fromUTF8BS` for lazy `ByteString`s

toUTF8BS :: String -> ByteString Source #

Encode `String` to UTF8-encoded `ByteString`

Code-points in the `U+D800`-`U+DFFF` range will be encoded as the replacement character (i.e. `U+FFFD`).

toUTF8LBS :: String -> ByteString Source #

Variant of `toUTF8BS` for lazy `ByteString`s

validateUTF8 :: ByteString -> Maybe Int Source #

Check that strict `ByteString` is valid UTF8. Returns 'Just offset' if it's not.

## File I/O

readUTF8File :: FilePath -> IO String Source #

Reads a UTF8 encoded text file as a Unicode String

Reads lazily using ordinary `readFile`.

withUTF8FileContents :: FilePath -> (String -> IO a) -> IO a Source #

Reads a UTF8 encoded text file as a Unicode String

Same behaviour as `withFileContents`.

writeUTF8File :: FilePath -> String -> IO () Source #

Writes a Unicode String as a UTF8 encoded text file.

Uses `writeFileAtomic`, so provides the same guarantees.

## BOM

ignoreBOM :: String -> String Source #

Ignore a Unicode byte order mark (BOM) at the beginning of the input

## Misc

normaliseLineEndings :: String -> String Source #

Fix different systems silly line ending conventions

# generic utils

dropWhileEndLE :: (a -> Bool) -> [a] -> [a] Source #

`dropWhileEndLE p` is equivalent to `reverse . dropWhile p . reverse`, but quite a bit faster. The difference between "Data.List.dropWhileEnd" and this version is that the one in Data.List is strict in elements, but spine-lazy, while this one is spine-strict but lazy in elements. That's what `LE` stands for - "lazy in elements".

Example:

    >>> safeTail $ Data.List.dropWhileEnd (<3) [undefined, 5, 4, 3, 2, 1]
    *** Exception: Prelude.undefined
    ...

    >>> safeTail $ dropWhileEndLE (<3) [undefined, 5, 4, 3, 2, 1]
    [5,4,3]

    >>> take 3 $ Data.List.dropWhileEnd (<3) [5, 4, 3, 2, 1, undefined]
    [5,4,3]

    >>> take 3 $ dropWhileEndLE (<3) [5, 4, 3, 2, 1, undefined]
    *** Exception: Prelude.undefined
    ...

takeWhileEndLE :: (a -> Bool) -> [a] -> [a] Source #

`takeWhileEndLE p` is equivalent to `reverse . takeWhile p . reverse`, but is usually faster (as well as being easier to read).

equating :: Eq a => (b -> a) -> b -> b -> Bool Source #

comparing :: Ord a => (b -> a) -> b -> b -> Ordering #

isInfixOf :: Eq a => [a] -> [a] -> Bool #

intercalate :: [a] -> [[a]] -> [a] #

lowercase :: String -> String Source #

Lower case string

    >>> lowercase "Foobar"
    "foobar"

isAscii :: Char -> Bool Source #

Ascii characters

isAsciiAlpha :: Char -> Bool Source #

Ascii letters.

isAsciiAlphaNum :: Char -> Bool Source #

Ascii letters and digits.

    >>> isAsciiAlphaNum 'a'
    True

    >>> isAsciiAlphaNum 'ä'
    False

listUnion :: Ord a => [a] -> [a] -> [a] Source #

Like "Data.List.union", but has `O(n log n)` complexity instead of `O(n^2)`.

listUnionRight :: Ord a => [a] -> [a] -> [a] Source #

A right-biased version of `listUnion`.

Example:

    >>> listUnion [1,2,3,4,3] [2,1,1]
    [1,2,3,4,3]

    >>> listUnionRight [1,2,3,4,3] [2,1,1]
    [4,3,2,1,1]

ordNub :: Ord a => [a] -> [a] Source #

Like `nub`, but has `O(n log n)` complexity instead of `O(n^2)`. Code for `ordNub` and `listUnion` taken from Niklas Hambüchen's ordnub package.

ordNubBy :: Ord b => (a -> b) -> [a] -> [a] Source #

Like `ordNub` and `nubBy`. Selects a key for each element and takes the nub based on that key.

ordNubRight :: Ord a => [a] -> [a] Source #

A right-biased version of `ordNub`.

Example:

    >>> ordNub [1,2,1] :: [Int]
    [1,2]

    >>> ordNubRight [1,2,1] :: [Int]
    [2,1]

safeHead :: [a] -> Maybe a Source #

A total variant of `head`.

Since: Cabal-syntax-3.2.0.0

safeTail :: [a] -> [a] Source #

A total variant of `tail`.

Since: Cabal-syntax-3.2.0.0

safeLast :: [a] -> Maybe a Source #

A total variant of `last`.

Since: Cabal-syntax-3.2.0.0

safeInit :: [a] -> [a] Source #

A total variant of `init`.

Since: Cabal-syntax-3.2.0.0

unintersperse :: Char -> String -> [String] Source #

wrapText :: String -> String Source #

Wraps text to the default line width. Existing newlines are preserved.

wrapLine :: Int -> [String] -> [[String]] Source #

Wraps a list of words to a list of lines of words of a particular width.

unfoldrM :: Monad m => (b -> m (Maybe (a, b))) -> b -> m [a] Source #

`unfoldr` with monadic action.

    >>> take 5 $ unfoldrM (\b r -> Just (r + b, b + 1)) (1 :: Int) 2
    [3,4,5,6,7]

Since: Cabal-syntax-2.2

spanMaybe :: (a -> Maybe b) -> [a] -> ([b], [a]) Source #

Like `span` but with `Maybe` predicate

    >>> spanMaybe listToMaybe [[1,2],[3],[],[4,5],[6,7]]
    ([1,3],[[],[4,5],[6,7]])

    >>> spanMaybe (readMaybe :: String -> Maybe Int) ["1", "2", "foo"]
    ([1,2],["foo"])

Since: Cabal-syntax-2.2

breakMaybe :: (a -> Maybe b) -> [a] -> ([a], Maybe (b, [a])) Source #

Like `break`, but with `Maybe` predicate

    >>> breakMaybe (readMaybe :: String -> Maybe Int) ["foo", "bar", "1", "2", "quu"]
    (["foo","bar"],Just (1,["2","quu"]))

    >>> breakMaybe (readMaybe :: String -> Maybe Int) ["foo", "bar"]
    (["foo","bar"],Nothing)

Since: Cabal-syntax-2.2

unsnoc :: [a] -> Maybe ([a], a) Source #

The opposite of `snoc`, which is the reverse of `cons`

Example:

    >>> unsnoc [1, 2, 3]
    Just ([1,2],3)

    >>> unsnoc []
    Nothing

Since: Cabal-syntax-3.2.0.0

unsnocNE :: NonEmpty a -> ([a], a) Source #

Like `unsnoc`, but for `NonEmpty` so without the `Maybe`

Example:

    >>> unsnocNE (1 :| [2, 3])
    ([1,2],3)

    >>> unsnocNE (1 :| [])
    ([],1)

Since: Cabal-syntax-3.2.0.0

# Triples

fstOf3 :: (a, b, c) -> a Source #

Since: Cabal-syntax-3.4.0.0

sndOf3 :: (a, b, c) -> b Source #

Since: Cabal-syntax-3.4.0.0

trdOf3 :: (a, b, c) -> c Source #

Since: Cabal-syntax-3.4.0.0

# FilePath stuff

isAbsoluteOnAnyPlatform :: FilePath -> Bool Source #

`isAbsoluteOnAnyPlatform` and `isRelativeOnAnyPlatform` are like `isAbsolute` and `isRelative` but have platform independent heuristics. The System.FilePath exists in two versions, Windows and Posix. The two versions don't agree on what is a relative path and we don't know if we're given Windows or Posix paths. This results in false positives when running on Posix and inspecting Windows paths, like the hackage server does. System.FilePath.Posix.isAbsolute "C:\hello" == False System.FilePath.Windows.isAbsolute "/hello" == False This means that we would treat paths that start with "/" to be absolute. On Posix they are indeed absolute, while on Windows they are not.

The portable versions should be used when we might deal with paths that are from another OS than the host OS. For example, the Hackage Server deals with both Windows and Posix paths while performing the PackageDescription checks. In contrast, when we run 'cabal configure' we do expect the paths to be correct for our OS and we should not have to use the platform independent heuristics.

isRelativeOnAnyPlatform :: FilePath -> Bool Source #

    isRelativeOnAnyPlatform = not . isAbsoluteOnAnyPlatform