Compare commits
No commits in common. "master" and "gh-pages" have entirely different histories.
14
.gitignore
vendored
14
.gitignore
vendored
@ -1,14 +0,0 @@
|
|||||||
*.o
|
|
||||||
*.hi
|
|
||||||
*~
|
|
||||||
dist/
|
|
||||||
cabal-dev/
|
|
||||||
.hsenv
|
|
||||||
TAGS
|
|
||||||
tags
|
|
||||||
*.tag
|
|
||||||
.stack-work/
|
|
||||||
dist/
|
|
||||||
dist-newstyle/
|
|
||||||
.cabal-sandbox/
|
|
||||||
cabal.sandbox.config
|
|
84
.travis.yml
84
.travis.yml
@ -1,84 +0,0 @@
|
|||||||
# See https://github.com/hvr/multi-ghc-travis for more information
|
|
||||||
|
|
||||||
language: c
|
|
||||||
|
|
||||||
sudo: required
|
|
||||||
dist: trusty
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- env: CABALVER=3.0 GHCVER=7.10.3 SKIP_DOCTESTS=yes
|
|
||||||
addons: {apt: {packages: [cabal-install-3.0,ghc-7.10.3], sources: [hvr-ghc]}}
|
|
||||||
before_install:
|
|
||||||
- sudo apt-get install -y hscolour
|
|
||||||
- export PATH=~/.cabal/bin:/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH
|
|
||||||
- env: CABALVER=3.0 GHCVER=8.0.2 SKIP_DOCTESTS=yes
|
|
||||||
addons: {apt: {packages: [cabal-install-3.0,ghc-8.0.2], sources: [hvr-ghc]}}
|
|
||||||
before_install:
|
|
||||||
- sudo apt-get install -y hscolour
|
|
||||||
- export PATH=~/.cabal/bin:/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH
|
|
||||||
- env: CABALVER=3.0 GHCVER=8.2.2
|
|
||||||
addons: {apt: {packages: [cabal-install-3.0,ghc-8.2.2], sources: [hvr-ghc]}}
|
|
||||||
before_install:
|
|
||||||
- sudo apt-get install -y hscolour
|
|
||||||
- export PATH=~/.cabal/bin:/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH
|
|
||||||
- env: CABALVER=3.0 GHCVER=8.4.4
|
|
||||||
addons: {apt: {packages: [cabal-install-3.0,ghc-8.4.4], sources: [hvr-ghc]}}
|
|
||||||
before_install:
|
|
||||||
- sudo apt-get install -y hscolour
|
|
||||||
- export PATH=~/.cabal/bin:/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH
|
|
||||||
- env: CABALVER=3.0 GHCVER=8.6.5
|
|
||||||
addons: {apt: {packages: [cabal-install-3.0,ghc-8.6.5], sources: [hvr-ghc]}}
|
|
||||||
before_install:
|
|
||||||
- sudo apt-get install -y hscolour
|
|
||||||
- export PATH=~/.cabal/bin:/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH
|
|
||||||
- env: CABALVER=3.0 GHCVER=8.8.3
|
|
||||||
addons: {apt: {packages: [cabal-install-3.0,ghc-8.8.3], sources: [hvr-ghc]}}
|
|
||||||
before_install:
|
|
||||||
- sudo apt-get install -y hscolour
|
|
||||||
- export PATH=~/.cabal/bin:/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH
|
|
||||||
- env: CABALVER=head GHCVER=head
|
|
||||||
addons: {apt: {packages: [cabal-install-head,ghc-head], sources: [hvr-ghc]}}
|
|
||||||
before_install:
|
|
||||||
- sudo apt-get install -y hscolour
|
|
||||||
- export PATH=~/.cabal/bin:/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH
|
|
||||||
- os: osx
|
|
||||||
osx_image: xcode11.3
|
|
||||||
language: generic
|
|
||||||
before_install:
|
|
||||||
- mkdir -p ~/.ghcup/bin
|
|
||||||
- curl https://gitlab.haskell.org/haskell/ghcup/raw/master/ghcup > ~/.ghcup/bin/ghcup
|
|
||||||
- chmod +x ~/.ghcup/bin/ghcup
|
|
||||||
- export PATH=~/.cabal/bin:~/.ghcup/bin:$PATH
|
|
||||||
- ghcup install 8.6.5
|
|
||||||
- ghcup set 8.6.5
|
|
||||||
- ghcup install-cabal 3.2.0.0
|
|
||||||
|
|
||||||
allow_failures:
|
|
||||||
- env: CABALVER=head GHCVER=head
|
|
||||||
|
|
||||||
env:
|
|
||||||
global:
|
|
||||||
- secure: HPBARvNM85ea2U0Ynq5MMe6BRlnuwqXWuSn20VY3EYCAT2njkVPYnR3O7+bGE6aq0KHAV87zz5iUfGJontd86tE0sDVjcSuRY0hqjOeJTkQq5M8WXJZOpVqlBTwDP1Q3x/fwoRa0dt9Z0tZZdKMlrf2XdcKPDdhcP1QYP4aV/jO4ZCfAQr7zVCvTae+Lp/KmwFYcBbFo/pj0duF1M4Oqx/D388b/W4jVE3lgd/TK7Ja1xWP6g+Oyvo6iQK8yJVYGdm6E+cVsNueiisnTJ/rRA53lsaC9dmWtZaFGl41wPviSU5zPq03vOuZMiyE2WtCHoo46ONXrXJ9N2soqdQVfEkr9Nw5LQl+6C5lCPEejZ575YUkuO05H3wvHMk3YY4zWXNFA9eZ47PEH8tpoUk9LPBacCKQFtp5lfRk63crba5CiFtcMyFq++0mLpNthNvtto7ffHMZrt6fvK9axI+r21VPftf/3FiFY4mnCp/Bln+ijklfZSN71VqiT20EWuqxQHw8aCpT00KA/PKGl9iJfoN4OO3XzNRTtmM+L9Im4bc1ni9YQ6N3UYg3z0nEnCLwFcTmTH/tDMHRremE0dM6B++YfcnyIhen8w+hG4bcXk7jbMUizRhUhStN7TZQuC9S4wE5whhp9c03rJZMmH5E2rlXY3lwVgeyWm1TuMp1RYWI=
|
|
||||||
|
|
||||||
install:
|
|
||||||
- cabal --version
|
|
||||||
- travis_retry cabal update
|
|
||||||
- cabal install --installdir=$HOME/.cabal/bin hspec-discover
|
|
||||||
- cabal install --installdir=$HOME/.cabal/bin doctest
|
|
||||||
|
|
||||||
script:
|
|
||||||
- cabal build --enable-tests all
|
|
||||||
- cabal test all
|
|
||||||
- ./hpath/run-doctests.sh
|
|
||||||
- ./hpath-filepath/run-doctests.sh
|
|
||||||
- (cd hpath && cabal check)
|
|
||||||
- (cd hpath-filepath && cabal check)
|
|
||||||
- (cd hpath-io && cabal check)
|
|
||||||
- cabal sdist all
|
|
||||||
- cabal install --lib all
|
|
||||||
|
|
||||||
notifications:
|
|
||||||
email:
|
|
||||||
- hasufell@posteo.de
|
|
||||||
|
|
25
HPath-IO-Errors.html
Normal file
25
HPath-IO-Errors.html
Normal file
File diff suppressed because one or more lines are too long
81
HPath-IO.html
Normal file
81
HPath-IO.html
Normal file
File diff suppressed because one or more lines are too long
107
HPath.html
Normal file
107
HPath.html
Normal file
File diff suppressed because one or more lines are too long
19
README.md
19
README.md
@ -1,19 +0,0 @@
|
|||||||
# HPath libraries
|
|
||||||
|
|
||||||
[![Gitter chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hasufell/hpath?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://api.travis-ci.org/hasufell/hpath.png?branch=master)](http://travis-ci.org/hasufell/hpath)
|
|
||||||
|
|
||||||
Set of libraries to deal with filepaths and files.
|
|
||||||
|
|
||||||
## Motivation
|
|
||||||
|
|
||||||
* filepaths should be type-safe (absolute, relative, ...)
|
|
||||||
* filepaths should be ByteString under the hood, see [Abstract FilePath Proposal (AFPP)](https://gitlab.haskell.org/ghc/ghc/wikis/proposal/abstract-file-path)
|
|
||||||
* file high-level operations should be platform-specific, exception-stable, safe and as atomic as possible
|
|
||||||
|
|
||||||
## Projects
|
|
||||||
|
|
||||||
* [![Hackage version](https://img.shields.io/hackage/v/hpath.svg?label=Hackage)](https://hackage.haskell.org/package/hpath) [hpath](./hpath): Support for well-typed paths
|
|
||||||
* [![Hackage version](https://img.shields.io/hackage/v/hpath-filepath.svg?label=Hackage)](https://hackage.haskell.org/package/hpath-filepath) [hpath-filepath](./hpath-filepath): ByteString based filepath manipulation (can be used without hpath)
|
|
||||||
* [![Hackage version](https://img.shields.io/hackage/v/hpath-directory.svg?label=Hackage)](https://hackage.haskell.org/package/hpath-directory) [hpath-directory](./hpath-directory): High-level IO operations for files/directories on raw ByteString filepaths (use hpath-io for the type-safe path version)
|
|
||||||
* [![Hackage version](https://img.shields.io/hackage/v/hpath-io.svg?label=Hackage)](https://hackage.haskell.org/package/hpath-io) [hpath-io](./hpath-io): High-level IO operations for files/directories utilizing type-safe Path
|
|
||||||
* [![Hackage version](https://img.shields.io/hackage/v/hpath-posix.svg?label=Hackage)](https://hackage.haskell.org/package/hpath-posix) [hpath-posix](./hpath-posix): Some low-level POSIX glue code that is not in 'unix'
|
|
9
System-Posix-Directory-Foreign.html
Normal file
9
System-Posix-Directory-Foreign.html
Normal file
File diff suppressed because one or more lines are too long
11
System-Posix-Directory-Traversals.html
Normal file
11
System-Posix-Directory-Traversals.html
Normal file
File diff suppressed because one or more lines are too long
9
System-Posix-FD.html
Normal file
9
System-Posix-FD.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>System.Posix.FD</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();setSynopsis("mini_System-Posix-FD.html");};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="src/System-Posix-FD.html">Source</a></li><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="module-header"><table class="info"><tr><th>Copyright</th><td>© 2016 Julian Ospald</td></tr><tr><th>License</th><td>BSD3</td></tr><tr><th>Maintainer</th><td>Julian Ospald <hasufell@posteo.de></td></tr><tr><th>Stability</th><td>experimental</td></tr><tr><th>Portability</th><td>portable</td></tr><tr><th>Safe Haskell</th><td>Safe</td></tr><tr><th>Language</th><td>Haskell2010</td></tr></table><p class="caption">System.Posix.FD</p></div><div id="description"><p class="caption">Description</p><div class="doc"><p>Provides an alternative for <code><a href="https://hackage.haskell.org/package/unix-2.7.1.0/docs/System-Posix-IO-ByteString.html#v:openFd">openFd</a></code>
|
||||||
|
which gives us more control on what status flags to pass to the
|
||||||
|
low-level <code>open(2)</code> call, in contrast to the unix package.</p></div></div><div id="synopsis"><p id="control.syn" class="caption expander" onclick="toggleSection('syn')">Synopsis</p><ul id="section.syn" class="hide" onclick="toggleSection('syn')"><li class="src short"><a href="#v:openFd">openFd</a> :: <a href="https://hackage.haskell.org/package/unix-2.7.1.0/docs/System-Posix-ByteString-FilePath.html#t:RawFilePath">RawFilePath</a> -> <a href="https://hackage.haskell.org/package/unix-2.7.1.0/docs/System-Posix-IO-ByteString.html#t:OpenMode">OpenMode</a> -> [<a href="System-Posix-Directory-Foreign.html#t:Flags">Flags</a>] -> <a href="https://hackage.haskell.org/package/base-4.8.1.0/docs/Data-Maybe.html#t:Maybe">Maybe</a> <a href="https://hackage.haskell.org/package/base-4.8.1.0/docs/System-Posix-Types.html#t:FileMode">FileMode</a> -> <a href="https://hackage.haskell.org/package/base-4.8.1.0/docs/System-IO.html#t:IO">IO</a> <a href="https://hackage.haskell.org/package/base-4.8.1.0/docs/System-Posix-Types.html#t:Fd">Fd</a></li></ul></div><div id="interface"><h1>Documentation</h1><div class="top"><p class="src"><a name="v:openFd" class="def">openFd</a> <a href="src/System-Posix-FD.html#openFd" class="link">Source</a></p><div class="subs arguments"><p class="caption">Arguments</p><table><tr><td class="src">:: <a href="https://hackage.haskell.org/package/unix-2.7.1.0/docs/System-Posix-ByteString-FilePath.html#t:RawFilePath">RawFilePath</a></td><td class="doc empty"> </td></tr><tr><td class="src">-> <a href="https://hackage.haskell.org/package/unix-2.7.1.0/docs/System-Posix-IO-ByteString.html#t:OpenMode">OpenMode</a></td><td class="doc empty"> </td></tr><tr><td class="src">-> [<a href="System-Posix-Directory-Foreign.html#t:Flags">Flags</a>]</td><td class="doc"><p>status flags of <code>open(2)</code></p></td></tr><tr><td class="src">-> <a href="https://hackage.haskell.org/package/base-4.8.1.0/docs/Data-Maybe.html#t:Maybe">Maybe</a> <a href="https://hackage.haskell.org/package/base-4.8.1.0/docs/System-Posix-Types.html#t:FileMode">FileMode</a></td><td class="doc"><p><code>Just x</code> => creates the file with the given modes, Nothing => the file must exist.</p></td></tr><tr><td class="src">-> <a href="https://hackage.haskell.org/package/base-4.8.1.0/docs/System-IO.html#t:IO">IO</a> <a href="https://hackage.haskell.org/package/base-4.8.1.0/docs/System-Posix-Types.html#t:Fd">Fd</a></td><td class="doc empty"> </td></tr></table></div><div class="doc"><p>Open and optionally create this file. See <code><a href="https://hackage.haskell.org/package/unix-2.7.1.0/docs/System-Posix.html#v:Files">Files</a></code>
|
||||||
|
for information on how to use the <code>FileMode</code> type.</p><p>Note that passing <code>Just x</code> as the 4th argument triggers the
|
||||||
|
<code><a href="System-Posix-Directory-Foreign.html#v:oCreat">oCreat</a></code> status flag, which must be set when you pass in <code><a href="System-Posix-Directory-Foreign.html#v:oExcl">oExcl</a></code>
|
||||||
|
to the status flags. Also see the manpage for <code>open(2)</code>.</p></div></div></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
243
System-Posix-FilePath.html
Normal file
243
System-Posix-FilePath.html
Normal file
File diff suppressed because one or more lines are too long
@ -1,12 +0,0 @@
|
|||||||
packages: ./hpath
|
|
||||||
./hpath-directory
|
|
||||||
./hpath-filepath
|
|
||||||
./hpath-io
|
|
||||||
./hpath-posix
|
|
||||||
|
|
||||||
package hpath-io
|
|
||||||
ghc-options: -O2 -fspec-constr-recursive=16 -fmax-worker-args=16
|
|
||||||
|
|
||||||
-- https://github.com/composewell/streamly/blob/master/docs/Build.md
|
|
||||||
package streamly
|
|
||||||
ghc-options: -O2 -fspec-constr-recursive=16 -fmax-worker-args=16
|
|
4
doc-index-60.html
Normal file
4
doc-index-60.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>hpath-0.8.0: Support for well-typed paths (Index - <)</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="alphabet"><ul><li><a href="doc-index-A.html">A</a></li><li><a href="doc-index-B.html">B</a></li><li><a href="doc-index-C.html">C</a></li><li><a href="doc-index-D.html">D</a></li><li><a href="doc-index-E.html">E</a></li><li><a href="doc-index-F.html">F</a></li><li><a href="doc-index-G.html">G</a></li><li><a href="doc-index-H.html">H</a></li><li><a href="doc-index-I.html">I</a></li><li><a href="doc-index-J.html">J</a></li><li><a href="doc-index-M.html">M</a></li><li><a href="doc-index-N.html">N</a></li><li><a href="doc-index-O.html">O</a></li><li><a href="doc-index-P.html">P</a></li><li><a href="doc-index-R.html">R</a></li><li><a href="doc-index-S.html">S</a></li><li><a href="doc-index-T.html">T</a></li><li><a href="doc-index-U.html">U</a></li><li><a href="doc-index-W.html">W</a></li><li><a href="doc-index-60.html"><</a></li><li><a href="doc-index-All.html">All</a></li></ul></div><div id="index"><p class="caption">Index - <</p><table><tr><td class="src"><.></td><td class="module"><a href="System-Posix-FilePath.html#v:-60-.-62-">System.Posix.FilePath</a></td></tr><tr><td class="src"></></td><td> </td></tr><tr><td class="alt">1 (Function)</td><td class="module"><a href="System-Posix-FilePath.html#v:-60--47--62-">System.Posix.FilePath</a></td></tr><tr><td class="alt">2 (Function)</td><td class="module"><a href="HPath.html#v:-60--47--62-">HPath</a></td></tr></table></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
4
doc-index-A.html
Normal file
4
doc-index-A.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>hpath-0.8.0: Support for well-typed paths (Index - A)</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="alphabet"><ul><li><a href="doc-index-A.html">A</a></li><li><a href="doc-index-B.html">B</a></li><li><a href="doc-index-C.html">C</a></li><li><a href="doc-index-D.html">D</a></li><li><a href="doc-index-E.html">E</a></li><li><a href="doc-index-F.html">F</a></li><li><a href="doc-index-G.html">G</a></li><li><a href="doc-index-H.html">H</a></li><li><a href="doc-index-I.html">I</a></li><li><a href="doc-index-J.html">J</a></li><li><a href="doc-index-M.html">M</a></li><li><a href="doc-index-N.html">N</a></li><li><a href="doc-index-O.html">O</a></li><li><a href="doc-index-P.html">P</a></li><li><a href="doc-index-R.html">R</a></li><li><a href="doc-index-S.html">S</a></li><li><a href="doc-index-T.html">T</a></li><li><a href="doc-index-U.html">U</a></li><li><a href="doc-index-W.html">W</a></li><li><a href="doc-index-60.html"><</a></li><li><a href="doc-index-All.html">All</a></li></ul></div><div id="index"><p class="caption">Index - A</p><table><tr><td class="src">Abs</td><td class="module"><a href="HPath.html#t:Abs">HPath</a></td></tr><tr><td class="src">addExtension</td><td class="module"><a href="System-Posix-FilePath.html#v:addExtension">System.Posix.FilePath</a></td></tr><tr><td class="src">addTrailingPathSeparator</td><td class="module"><a href="System-Posix-FilePath.html#v:addTrailingPathSeparator">System.Posix.FilePath</a></td></tr><tr><td class="src">allDirectoryContents</td><td class="module"><a href="System-Posix-Directory-Traversals.html#v:allDirectoryContents">System.Posix.Directory.Traversals</a></td></tr><tr><td class="src">allDirectoryContents'</td><td class="module"><a href="System-Posix-Directory-Traversals.html#v:allDirectoryContents-39-">System.Posix.Directory.Traversals</a></td></tr></table></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
4
doc-index-All.html
Normal file
4
doc-index-All.html
Normal file
File diff suppressed because one or more lines are too long
4
doc-index-B.html
Normal file
4
doc-index-B.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>hpath-0.8.0: Support for well-typed paths (Index - B)</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="alphabet"><ul><li><a href="doc-index-A.html">A</a></li><li><a href="doc-index-B.html">B</a></li><li><a href="doc-index-C.html">C</a></li><li><a href="doc-index-D.html">D</a></li><li><a href="doc-index-E.html">E</a></li><li><a href="doc-index-F.html">F</a></li><li><a href="doc-index-G.html">G</a></li><li><a href="doc-index-H.html">H</a></li><li><a href="doc-index-I.html">I</a></li><li><a href="doc-index-J.html">J</a></li><li><a href="doc-index-M.html">M</a></li><li><a href="doc-index-N.html">N</a></li><li><a href="doc-index-O.html">O</a></li><li><a href="doc-index-P.html">P</a></li><li><a href="doc-index-R.html">R</a></li><li><a href="doc-index-S.html">S</a></li><li><a href="doc-index-T.html">T</a></li><li><a href="doc-index-U.html">U</a></li><li><a href="doc-index-W.html">W</a></li><li><a href="doc-index-60.html"><</a></li><li><a href="doc-index-All.html">All</a></li></ul></div><div id="index"><p class="caption">Index - B</p><table><tr><td class="src">basename</td><td class="module"><a href="HPath.html#v:basename">HPath</a></td></tr><tr><td class="src">BlockDevice</td><td class="module"><a href="HPath-IO.html#v:BlockDevice">HPath.IO</a></td></tr><tr><td class="src">bracketeer</td><td class="module"><a href="HPath-IO-Errors.html#v:bracketeer">HPath.IO.Errors</a></td></tr></table></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
4
doc-index-C.html
Normal file
4
doc-index-C.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>hpath-0.8.0: Support for well-typed paths (Index - C)</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="alphabet"><ul><li><a href="doc-index-A.html">A</a></li><li><a href="doc-index-B.html">B</a></li><li><a href="doc-index-C.html">C</a></li><li><a href="doc-index-D.html">D</a></li><li><a href="doc-index-E.html">E</a></li><li><a href="doc-index-F.html">F</a></li><li><a href="doc-index-G.html">G</a></li><li><a href="doc-index-H.html">H</a></li><li><a href="doc-index-I.html">I</a></li><li><a href="doc-index-J.html">J</a></li><li><a href="doc-index-M.html">M</a></li><li><a href="doc-index-N.html">N</a></li><li><a href="doc-index-O.html">O</a></li><li><a href="doc-index-P.html">P</a></li><li><a href="doc-index-R.html">R</a></li><li><a href="doc-index-S.html">S</a></li><li><a href="doc-index-T.html">T</a></li><li><a href="doc-index-U.html">U</a></li><li><a href="doc-index-W.html">W</a></li><li><a href="doc-index-60.html"><</a></li><li><a href="doc-index-All.html">All</a></li></ul></div><div id="index"><p class="caption">Index - C</p><table><tr><td class="src">canonicalizePath</td><td class="module"><a href="HPath-IO.html#v:canonicalizePath">HPath.IO</a></td></tr><tr><td class="src">canOpenDirectory</td><td class="module"><a href="HPath-IO-Errors.html#v:canOpenDirectory">HPath.IO.Errors</a></td></tr><tr><td class="src">catchErrno</td><td class="module"><a href="HPath-IO-Errors.html#v:catchErrno">HPath.IO.Errors</a></td></tr><tr><td class="src">CharacterDevice</td><td class="module"><a href="HPath-IO.html#v:CharacterDevice">HPath.IO</a></td></tr><tr><td class="src">CollectFailures</td><td class="module"><a href="HPath-IO.html#v:CollectFailures">HPath.IO</a></td></tr><tr><td class="src">combine</td><td class="module"><a href="System-Posix-FilePath.html#v:combine">System.Posix.FilePath</a></td></tr><tr><td class="src">copyDirRecursive</td><td class="module"><a href="HPath-IO.html#v:copyDirRecursive">HPath.IO</a></td></tr><tr><td class="src">copyFile</td><td class="module"><a href="HPath-IO.html#v:copyFile">HPath.IO</a></td></tr><tr><td class="src">CopyFileFailed</td><td class="module"><a href="HPath-IO-Errors.html#v:CopyFileFailed">HPath.IO.Errors</a></td></tr><tr><td class="src">CopyMode</td><td class="module"><a href="HPath-IO.html#t:CopyMode">HPath.IO</a></td></tr><tr><td class="src">createDir</td><td class="module"><a href="HPath-IO.html#v:createDir">HPath.IO</a></td></tr><tr><td class="src">CreateDirFailed</td><td class="module"><a href="HPath-IO-Errors.html#v:CreateDirFailed">HPath.IO.Errors</a></td></tr><tr><td class="src">createDirRecursive</td><td class="module"><a href="HPath-IO.html#v:createDirRecursive">HPath.IO</a></td></tr><tr><td class="src">createRegularFile</td><td class="module"><a href="HPath-IO.html#v:createRegularFile">HPath.IO</a></td></tr><tr><td class="src">createSymlink</td><td class="module"><a href="HPath-IO.html#v:createSymlink">HPath.IO</a></td></tr></table></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
4
doc-index-D.html
Normal file
4
doc-index-D.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>hpath-0.8.0: Support for well-typed paths (Index - D)</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="alphabet"><ul><li><a href="doc-index-A.html">A</a></li><li><a href="doc-index-B.html">B</a></li><li><a href="doc-index-C.html">C</a></li><li><a href="doc-index-D.html">D</a></li><li><a href="doc-index-E.html">E</a></li><li><a href="doc-index-F.html">F</a></li><li><a href="doc-index-G.html">G</a></li><li><a href="doc-index-H.html">H</a></li><li><a href="doc-index-I.html">I</a></li><li><a href="doc-index-J.html">J</a></li><li><a href="doc-index-M.html">M</a></li><li><a href="doc-index-N.html">N</a></li><li><a href="doc-index-O.html">O</a></li><li><a href="doc-index-P.html">P</a></li><li><a href="doc-index-R.html">R</a></li><li><a href="doc-index-S.html">S</a></li><li><a href="doc-index-T.html">T</a></li><li><a href="doc-index-U.html">U</a></li><li><a href="doc-index-W.html">W</a></li><li><a href="doc-index-60.html"><</a></li><li><a href="doc-index-All.html">All</a></li></ul></div><div id="index"><p class="caption">Index - D</p><table><tr><td class="src">deleteDir</td><td class="module"><a href="HPath-IO.html#v:deleteDir">HPath.IO</a></td></tr><tr><td class="src">deleteDirRecursive</td><td class="module"><a href="HPath-IO.html#v:deleteDirRecursive">HPath.IO</a></td></tr><tr><td class="src">deleteFile</td><td class="module"><a href="HPath-IO.html#v:deleteFile">HPath.IO</a></td></tr><tr><td class="src">DestinationInSource</td><td class="module"><a href="HPath-IO-Errors.html#v:DestinationInSource">HPath.IO.Errors</a></td></tr><tr><td class="src">Directory</td><td class="module"><a href="HPath-IO.html#v:Directory">HPath.IO</a></td></tr><tr><td class="src">dirname</td><td class="module"><a href="HPath.html#v:dirname">HPath</a></td></tr><tr><td class="src">DirType</td><td> </td></tr><tr><td class="alt">1 (Type/Class)</td><td class="module"><a href="System-Posix-Directory-Foreign.html#t:DirType">System.Posix.Directory.Foreign</a></td></tr><tr><td class="alt">2 (Data Constructor)</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:DirType">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">doesDirectoryExist</td><td class="module"><a href="HPath-IO-Errors.html#v:doesDirectoryExist">HPath.IO.Errors</a></td></tr><tr><td class="src">doesFileExist</td><td class="module"><a href="HPath-IO-Errors.html#v:doesFileExist">HPath.IO.Errors</a></td></tr><tr><td class="src">dropExtension</td><td class="module"><a href="System-Posix-FilePath.html#v:dropExtension">System.Posix.FilePath</a></td></tr><tr><td class="src">dropExtensions</td><td class="module"><a href="System-Posix-FilePath.html#v:dropExtensions">System.Posix.FilePath</a></td></tr><tr><td class="src">dropFileName</td><td class="module"><a href="System-Posix-FilePath.html#v:dropFileName">System.Posix.FilePath</a></td></tr><tr><td class="src">dropTrailingPathSeparator</td><td class="module"><a href="System-Posix-FilePath.html#v:dropTrailingPathSeparator">System.Posix.FilePath</a></td></tr><tr><td class="src">dtBlk</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:dtBlk">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">dtChr</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:dtChr">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">dtDir</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:dtDir">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">dtFifo</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:dtFifo">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">dtLnk</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:dtLnk">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">dtReg</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:dtReg">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">dtSock</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:dtSock">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">dtUnknown</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:dtUnknown">System.Posix.Directory.Foreign</a></td></tr></table></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
4
doc-index-E.html
Normal file
4
doc-index-E.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>hpath-0.8.0: Support for well-typed paths (Index - E)</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="alphabet"><ul><li><a href="doc-index-A.html">A</a></li><li><a href="doc-index-B.html">B</a></li><li><a href="doc-index-C.html">C</a></li><li><a href="doc-index-D.html">D</a></li><li><a href="doc-index-E.html">E</a></li><li><a href="doc-index-F.html">F</a></li><li><a href="doc-index-G.html">G</a></li><li><a href="doc-index-H.html">H</a></li><li><a href="doc-index-I.html">I</a></li><li><a href="doc-index-J.html">J</a></li><li><a href="doc-index-M.html">M</a></li><li><a href="doc-index-N.html">N</a></li><li><a href="doc-index-O.html">O</a></li><li><a href="doc-index-P.html">P</a></li><li><a href="doc-index-R.html">R</a></li><li><a href="doc-index-S.html">S</a></li><li><a href="doc-index-T.html">T</a></li><li><a href="doc-index-U.html">U</a></li><li><a href="doc-index-W.html">W</a></li><li><a href="doc-index-60.html"><</a></li><li><a href="doc-index-All.html">All</a></li></ul></div><div id="index"><p class="caption">Index - E</p><table><tr><td class="src">easyCopy</td><td class="module"><a href="HPath-IO.html#v:easyCopy">HPath.IO</a></td></tr><tr><td class="src">easyDelete</td><td class="module"><a href="HPath-IO.html#v:easyDelete">HPath.IO</a></td></tr><tr><td class="src">equalFilePath</td><td class="module"><a href="System-Posix-FilePath.html#v:equalFilePath">System.Posix.FilePath</a></td></tr><tr><td class="src">executeFile</td><td class="module"><a href="HPath-IO.html#v:executeFile">HPath.IO</a></td></tr><tr><td class="src">extSeparator</td><td class="module"><a href="System-Posix-FilePath.html#v:extSeparator">System.Posix.FilePath</a></td></tr></table></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
4
doc-index-F.html
Normal file
4
doc-index-F.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>hpath-0.8.0: Support for well-typed paths (Index - F)</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="alphabet"><ul><li><a href="doc-index-A.html">A</a></li><li><a href="doc-index-B.html">B</a></li><li><a href="doc-index-C.html">C</a></li><li><a href="doc-index-D.html">D</a></li><li><a href="doc-index-E.html">E</a></li><li><a href="doc-index-F.html">F</a></li><li><a href="doc-index-G.html">G</a></li><li><a href="doc-index-H.html">H</a></li><li><a href="doc-index-I.html">I</a></li><li><a href="doc-index-J.html">J</a></li><li><a href="doc-index-M.html">M</a></li><li><a href="doc-index-N.html">N</a></li><li><a href="doc-index-O.html">O</a></li><li><a href="doc-index-P.html">P</a></li><li><a href="doc-index-R.html">R</a></li><li><a href="doc-index-S.html">S</a></li><li><a href="doc-index-T.html">T</a></li><li><a href="doc-index-U.html">U</a></li><li><a href="doc-index-W.html">W</a></li><li><a href="doc-index-60.html"><</a></li><li><a href="doc-index-All.html">All</a></li></ul></div><div id="index"><p class="caption">Index - F</p><table><tr><td class="src">FailEarly</td><td class="module"><a href="HPath-IO.html#v:FailEarly">HPath.IO</a></td></tr><tr><td class="src">fdOpendir</td><td class="module"><a href="System-Posix-Directory-Traversals.html#v:fdOpendir">System.Posix.Directory.Traversals</a></td></tr><tr><td class="src">FileType</td><td class="module"><a href="HPath-IO.html#t:FileType">HPath.IO</a></td></tr><tr><td class="src">Flags</td><td> </td></tr><tr><td class="alt">1 (Type/Class)</td><td class="module"><a href="System-Posix-Directory-Foreign.html#t:Flags">System.Posix.Directory.Foreign</a></td></tr><tr><td class="alt">2 (Data Constructor)</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:Flags">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">Fn</td><td class="module"><a href="HPath.html#t:Fn">HPath</a></td></tr><tr><td class="src">fromAbs</td><td class="module"><a href="HPath.html#v:fromAbs">HPath</a></td></tr><tr><td class="src">fromRel</td><td class="module"><a href="HPath.html#v:fromRel">HPath</a></td></tr></table></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
4
doc-index-G.html
Normal file
4
doc-index-G.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>hpath-0.8.0: Support for well-typed paths (Index - G)</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="alphabet"><ul><li><a href="doc-index-A.html">A</a></li><li><a href="doc-index-B.html">B</a></li><li><a href="doc-index-C.html">C</a></li><li><a href="doc-index-D.html">D</a></li><li><a href="doc-index-E.html">E</a></li><li><a href="doc-index-F.html">F</a></li><li><a href="doc-index-G.html">G</a></li><li><a href="doc-index-H.html">H</a></li><li><a href="doc-index-I.html">I</a></li><li><a href="doc-index-J.html">J</a></li><li><a href="doc-index-M.html">M</a></li><li><a href="doc-index-N.html">N</a></li><li><a href="doc-index-O.html">O</a></li><li><a href="doc-index-P.html">P</a></li><li><a href="doc-index-R.html">R</a></li><li><a href="doc-index-S.html">S</a></li><li><a href="doc-index-T.html">T</a></li><li><a href="doc-index-U.html">U</a></li><li><a href="doc-index-W.html">W</a></li><li><a href="doc-index-60.html"><</a></li><li><a href="doc-index-All.html">All</a></li></ul></div><div id="index"><p class="caption">Index - G</p><table><tr><td class="src">getAllParents</td><td class="module"><a href="HPath.html#v:getAllParents">HPath</a></td></tr><tr><td class="src">getDirectoryContents</td><td class="module"><a href="System-Posix-Directory-Traversals.html#v:getDirectoryContents">System.Posix.Directory.Traversals</a></td></tr><tr><td class="src">getDirectoryContents'</td><td class="module"><a href="System-Posix-Directory-Traversals.html#v:getDirectoryContents-39-">System.Posix.Directory.Traversals</a></td></tr><tr><td class="src">getDirsFiles</td><td class="module"><a href="HPath-IO.html#v:getDirsFiles">HPath.IO</a></td></tr><tr><td class="src">getFileType</td><td class="module"><a href="HPath-IO.html#v:getFileType">HPath.IO</a></td></tr><tr><td class="src">getSearchPath</td><td class="module"><a href="System-Posix-FilePath.html#v:getSearchPath">System.Posix.FilePath</a></td></tr></table></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
4
doc-index-H.html
Normal file
4
doc-index-H.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>hpath-0.8.0: Support for well-typed paths (Index - H)</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="alphabet"><ul><li><a href="doc-index-A.html">A</a></li><li><a href="doc-index-B.html">B</a></li><li><a href="doc-index-C.html">C</a></li><li><a href="doc-index-D.html">D</a></li><li><a href="doc-index-E.html">E</a></li><li><a href="doc-index-F.html">F</a></li><li><a href="doc-index-G.html">G</a></li><li><a href="doc-index-H.html">H</a></li><li><a href="doc-index-I.html">I</a></li><li><a href="doc-index-J.html">J</a></li><li><a href="doc-index-M.html">M</a></li><li><a href="doc-index-N.html">N</a></li><li><a href="doc-index-O.html">O</a></li><li><a href="doc-index-P.html">P</a></li><li><a href="doc-index-R.html">R</a></li><li><a href="doc-index-S.html">S</a></li><li><a href="doc-index-T.html">T</a></li><li><a href="doc-index-U.html">U</a></li><li><a href="doc-index-W.html">W</a></li><li><a href="doc-index-60.html"><</a></li><li><a href="doc-index-All.html">All</a></li></ul></div><div id="index"><p class="caption">Index - H</p><table><tr><td class="src">handleIOError</td><td class="module"><a href="HPath-IO-Errors.html#v:handleIOError">HPath.IO.Errors</a></td></tr><tr><td class="src">hasExtension</td><td class="module"><a href="System-Posix-FilePath.html#v:hasExtension">System.Posix.FilePath</a></td></tr><tr><td class="src">hasParentDir</td><td class="module"><a href="System-Posix-FilePath.html#v:hasParentDir">System.Posix.FilePath</a></td></tr><tr><td class="src">hasTrailingPathSeparator</td><td class="module"><a href="System-Posix-FilePath.html#v:hasTrailingPathSeparator">System.Posix.FilePath</a></td></tr><tr><td class="src">hiddenFile</td><td class="module"><a href="System-Posix-FilePath.html#v:hiddenFile">System.Posix.FilePath</a></td></tr><tr><td class="src">HPathIOException</td><td class="module"><a href="HPath-IO-Errors.html#t:HPathIOException">HPath.IO.Errors</a></td></tr></table></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
4
doc-index-I.html
Normal file
4
doc-index-I.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>hpath-0.8.0: Support for well-typed paths (Index - I)</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="alphabet"><ul><li><a href="doc-index-A.html">A</a></li><li><a href="doc-index-B.html">B</a></li><li><a href="doc-index-C.html">C</a></li><li><a href="doc-index-D.html">D</a></li><li><a href="doc-index-E.html">E</a></li><li><a href="doc-index-F.html">F</a></li><li><a href="doc-index-G.html">G</a></li><li><a href="doc-index-H.html">H</a></li><li><a href="doc-index-I.html">I</a></li><li><a href="doc-index-J.html">J</a></li><li><a href="doc-index-M.html">M</a></li><li><a href="doc-index-N.html">N</a></li><li><a href="doc-index-O.html">O</a></li><li><a href="doc-index-P.html">P</a></li><li><a href="doc-index-R.html">R</a></li><li><a href="doc-index-S.html">S</a></li><li><a href="doc-index-T.html">T</a></li><li><a href="doc-index-U.html">U</a></li><li><a href="doc-index-W.html">W</a></li><li><a href="doc-index-60.html"><</a></li><li><a href="doc-index-All.html">All</a></li></ul></div><div id="index"><p class="caption">Index - I</p><table><tr><td class="src">isAbsolute</td><td class="module"><a href="System-Posix-FilePath.html#v:isAbsolute">System.Posix.FilePath</a></td></tr><tr><td class="src">isCopyFileFailed</td><td class="module"><a href="HPath-IO-Errors.html#v:isCopyFileFailed">HPath.IO.Errors</a></td></tr><tr><td class="src">isCreateDirFailed</td><td class="module"><a href="HPath-IO-Errors.html#v:isCreateDirFailed">HPath.IO.Errors</a></td></tr><tr><td class="src">isDestinationInSource</td><td class="module"><a href="HPath-IO-Errors.html#v:isDestinationInSource">HPath.IO.Errors</a></td></tr><tr><td class="src">isExtSeparator</td><td class="module"><a href="System-Posix-FilePath.html#v:isExtSeparator">System.Posix.FilePath</a></td></tr><tr><td class="src">isFileName</td><td class="module"><a href="System-Posix-FilePath.html#v:isFileName">System.Posix.FilePath</a></td></tr><tr><td class="src">isParentOf</td><td class="module"><a href="HPath.html#v:isParentOf">HPath</a></td></tr><tr><td class="src">isPathSeparator</td><td class="module"><a href="System-Posix-FilePath.html#v:isPathSeparator">System.Posix.FilePath</a></td></tr><tr><td class="src">isReadContentsFailed</td><td class="module"><a href="HPath-IO-Errors.html#v:isReadContentsFailed">HPath.IO.Errors</a></td></tr><tr><td class="src">isRecreateSymlinkFailed</td><td class="module"><a href="HPath-IO-Errors.html#v:isRecreateSymlinkFailed">HPath.IO.Errors</a></td></tr><tr><td class="src">isRecursiveFailure</td><td class="module"><a href="HPath-IO-Errors.html#v:isRecursiveFailure">HPath.IO.Errors</a></td></tr><tr><td class="src">isRelative</td><td class="module"><a href="System-Posix-FilePath.html#v:isRelative">System.Posix.FilePath</a></td></tr><tr><td class="src">isSameFile</td><td class="module"><a href="HPath-IO-Errors.html#v:isSameFile">HPath.IO.Errors</a></td></tr><tr><td class="src">isSearchPathSeparator</td><td class="module"><a href="System-Posix-FilePath.html#v:isSearchPathSeparator">System.Posix.FilePath</a></td></tr><tr><td class="src">isSupported</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:isSupported">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">isValid</td><td class="module"><a href="System-Posix-FilePath.html#v:isValid">System.Posix.FilePath</a></td></tr><tr><td class="src">isWritable</td><td class="module"><a href="HPath-IO-Errors.html#v:isWritable">HPath.IO.Errors</a></td></tr></table></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
4
doc-index-J.html
Normal file
4
doc-index-J.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>hpath-0.8.0: Support for well-typed paths (Index - J)</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="alphabet"><ul><li><a href="doc-index-A.html">A</a></li><li><a href="doc-index-B.html">B</a></li><li><a href="doc-index-C.html">C</a></li><li><a href="doc-index-D.html">D</a></li><li><a href="doc-index-E.html">E</a></li><li><a href="doc-index-F.html">F</a></li><li><a href="doc-index-G.html">G</a></li><li><a href="doc-index-H.html">H</a></li><li><a href="doc-index-I.html">I</a></li><li><a href="doc-index-J.html">J</a></li><li><a href="doc-index-M.html">M</a></li><li><a href="doc-index-N.html">N</a></li><li><a href="doc-index-O.html">O</a></li><li><a href="doc-index-P.html">P</a></li><li><a href="doc-index-R.html">R</a></li><li><a href="doc-index-S.html">S</a></li><li><a href="doc-index-T.html">T</a></li><li><a href="doc-index-U.html">U</a></li><li><a href="doc-index-W.html">W</a></li><li><a href="doc-index-60.html"><</a></li><li><a href="doc-index-All.html">All</a></li></ul></div><div id="index"><p class="caption">Index - J</p><table><tr><td class="src">joinPath</td><td class="module"><a href="System-Posix-FilePath.html#v:joinPath">System.Posix.FilePath</a></td></tr></table></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
4
doc-index-M.html
Normal file
4
doc-index-M.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>hpath-0.8.0: Support for well-typed paths (Index - M)</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="alphabet"><ul><li><a href="doc-index-A.html">A</a></li><li><a href="doc-index-B.html">B</a></li><li><a href="doc-index-C.html">C</a></li><li><a href="doc-index-D.html">D</a></li><li><a href="doc-index-E.html">E</a></li><li><a href="doc-index-F.html">F</a></li><li><a href="doc-index-G.html">G</a></li><li><a href="doc-index-H.html">H</a></li><li><a href="doc-index-I.html">I</a></li><li><a href="doc-index-J.html">J</a></li><li><a href="doc-index-M.html">M</a></li><li><a href="doc-index-N.html">N</a></li><li><a href="doc-index-O.html">O</a></li><li><a href="doc-index-P.html">P</a></li><li><a href="doc-index-R.html">R</a></li><li><a href="doc-index-S.html">S</a></li><li><a href="doc-index-T.html">T</a></li><li><a href="doc-index-U.html">U</a></li><li><a href="doc-index-W.html">W</a></li><li><a href="doc-index-60.html"><</a></li><li><a href="doc-index-All.html">All</a></li></ul></div><div id="index"><p class="caption">Index - M</p><table><tr><td class="src">makeRelative</td><td class="module"><a href="System-Posix-FilePath.html#v:makeRelative">System.Posix.FilePath</a></td></tr><tr><td class="src">makeValid</td><td class="module"><a href="System-Posix-FilePath.html#v:makeValid">System.Posix.FilePath</a></td></tr><tr><td class="src">moveFile</td><td class="module"><a href="HPath-IO.html#v:moveFile">HPath.IO</a></td></tr></table></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
4
doc-index-N.html
Normal file
4
doc-index-N.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>hpath-0.8.0: Support for well-typed paths (Index - N)</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="alphabet"><ul><li><a href="doc-index-A.html">A</a></li><li><a href="doc-index-B.html">B</a></li><li><a href="doc-index-C.html">C</a></li><li><a href="doc-index-D.html">D</a></li><li><a href="doc-index-E.html">E</a></li><li><a href="doc-index-F.html">F</a></li><li><a href="doc-index-G.html">G</a></li><li><a href="doc-index-H.html">H</a></li><li><a href="doc-index-I.html">I</a></li><li><a href="doc-index-J.html">J</a></li><li><a href="doc-index-M.html">M</a></li><li><a href="doc-index-N.html">N</a></li><li><a href="doc-index-O.html">O</a></li><li><a href="doc-index-P.html">P</a></li><li><a href="doc-index-R.html">R</a></li><li><a href="doc-index-S.html">S</a></li><li><a href="doc-index-T.html">T</a></li><li><a href="doc-index-U.html">U</a></li><li><a href="doc-index-W.html">W</a></li><li><a href="doc-index-60.html"><</a></li><li><a href="doc-index-All.html">All</a></li></ul></div><div id="index"><p class="caption">Index - N</p><table><tr><td class="src">NamedPipe</td><td class="module"><a href="HPath-IO.html#v:NamedPipe">HPath.IO</a></td></tr><tr><td class="src">newDirPerms</td><td class="module"><a href="HPath-IO.html#v:newDirPerms">HPath.IO</a></td></tr><tr><td class="src">newFilePerms</td><td class="module"><a href="HPath-IO.html#v:newFilePerms">HPath.IO</a></td></tr><tr><td class="src">normalise</td><td class="module"><a href="System-Posix-FilePath.html#v:normalise">System.Posix.FilePath</a></td></tr></table></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
4
doc-index-O.html
Normal file
4
doc-index-O.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>hpath-0.8.0: Support for well-typed paths (Index - O)</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="alphabet"><ul><li><a href="doc-index-A.html">A</a></li><li><a href="doc-index-B.html">B</a></li><li><a href="doc-index-C.html">C</a></li><li><a href="doc-index-D.html">D</a></li><li><a href="doc-index-E.html">E</a></li><li><a href="doc-index-F.html">F</a></li><li><a href="doc-index-G.html">G</a></li><li><a href="doc-index-H.html">H</a></li><li><a href="doc-index-I.html">I</a></li><li><a href="doc-index-J.html">J</a></li><li><a href="doc-index-M.html">M</a></li><li><a href="doc-index-N.html">N</a></li><li><a href="doc-index-O.html">O</a></li><li><a href="doc-index-P.html">P</a></li><li><a href="doc-index-R.html">R</a></li><li><a href="doc-index-S.html">S</a></li><li><a href="doc-index-T.html">T</a></li><li><a href="doc-index-U.html">U</a></li><li><a href="doc-index-W.html">W</a></li><li><a href="doc-index-60.html"><</a></li><li><a href="doc-index-All.html">All</a></li></ul></div><div id="index"><p class="caption">Index - O</p><table><tr><td class="src">oAppend</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:oAppend">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">oAsync</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:oAsync">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">oCloexec</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:oCloexec">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">oCreat</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:oCreat">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">oDirectory</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:oDirectory">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">oExcl</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:oExcl">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">oNoctty</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:oNoctty">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">oNofollow</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:oNofollow">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">oNonblock</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:oNonblock">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">openFd</td><td class="module"><a href="System-Posix-FD.html#v:openFd">System.Posix.FD</a></td></tr><tr><td class="src">openFile</td><td class="module"><a href="HPath-IO.html#v:openFile">HPath.IO</a></td></tr><tr><td class="src">oRdonly</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:oRdonly">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">oRdwr</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:oRdwr">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">oSync</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:oSync">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">oTrunc</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:oTrunc">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">Overwrite</td><td class="module"><a href="HPath-IO.html#v:Overwrite">HPath.IO</a></td></tr><tr><td class="src">oWronly</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:oWronly">System.Posix.Directory.Foreign</a></td></tr></table></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
4
doc-index-P.html
Normal file
4
doc-index-P.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>hpath-0.8.0: Support for well-typed paths (Index - P)</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="alphabet"><ul><li><a href="doc-index-A.html">A</a></li><li><a href="doc-index-B.html">B</a></li><li><a href="doc-index-C.html">C</a></li><li><a href="doc-index-D.html">D</a></li><li><a href="doc-index-E.html">E</a></li><li><a href="doc-index-F.html">F</a></li><li><a href="doc-index-G.html">G</a></li><li><a href="doc-index-H.html">H</a></li><li><a href="doc-index-I.html">I</a></li><li><a href="doc-index-J.html">J</a></li><li><a href="doc-index-M.html">M</a></li><li><a href="doc-index-N.html">N</a></li><li><a href="doc-index-O.html">O</a></li><li><a href="doc-index-P.html">P</a></li><li><a href="doc-index-R.html">R</a></li><li><a href="doc-index-S.html">S</a></li><li><a href="doc-index-T.html">T</a></li><li><a href="doc-index-U.html">U</a></li><li><a href="doc-index-W.html">W</a></li><li><a href="doc-index-60.html"><</a></li><li><a href="doc-index-All.html">All</a></li></ul></div><div id="index"><p class="caption">Index - P</p><table><tr><td class="src">packDirStream</td><td class="module"><a href="System-Posix-Directory-Traversals.html#v:packDirStream">System.Posix.Directory.Traversals</a></td></tr><tr><td class="src">parseAbs</td><td class="module"><a href="HPath.html#v:parseAbs">HPath</a></td></tr><tr><td class="src">parseFn</td><td class="module"><a href="HPath.html#v:parseFn">HPath</a></td></tr><tr><td class="src">parseRel</td><td class="module"><a href="HPath.html#v:parseRel">HPath</a></td></tr><tr><td class="src">Path</td><td> </td></tr><tr><td class="alt">1 (Type/Class)</td><td class="module"><a href="HPath.html#t:Path">HPath</a></td></tr><tr><td class="alt">2 (Data Constructor)</td><td class="module"><a href="HPath.html#v:Path">HPath</a></td></tr><tr><td class="src">PathException</td><td class="module"><a href="HPath.html#t:PathException">HPath</a></td></tr><tr><td class="src">pathMax</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:pathMax">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">PathParseException</td><td class="module"><a href="HPath.html#t:PathParseException">HPath</a></td></tr><tr><td class="src">pathSeparator</td><td class="module"><a href="System-Posix-FilePath.html#v:pathSeparator">System.Posix.FilePath</a></td></tr><tr><td class="src">peekFilePath</td><td class="module">System.Posix.FilePath</td></tr><tr><td class="src">peekFilePathLen</td><td class="module">System.Posix.FilePath</td></tr></table></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
4
doc-index-R.html
Normal file
4
doc-index-R.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>hpath-0.8.0: Support for well-typed paths (Index - R)</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="alphabet"><ul><li><a href="doc-index-A.html">A</a></li><li><a href="doc-index-B.html">B</a></li><li><a href="doc-index-C.html">C</a></li><li><a href="doc-index-D.html">D</a></li><li><a href="doc-index-E.html">E</a></li><li><a href="doc-index-F.html">F</a></li><li><a href="doc-index-G.html">G</a></li><li><a href="doc-index-H.html">H</a></li><li><a href="doc-index-I.html">I</a></li><li><a href="doc-index-J.html">J</a></li><li><a href="doc-index-M.html">M</a></li><li><a href="doc-index-N.html">N</a></li><li><a href="doc-index-O.html">O</a></li><li><a href="doc-index-P.html">P</a></li><li><a href="doc-index-R.html">R</a></li><li><a href="doc-index-S.html">S</a></li><li><a href="doc-index-T.html">T</a></li><li><a href="doc-index-U.html">U</a></li><li><a href="doc-index-W.html">W</a></li><li><a href="doc-index-60.html"><</a></li><li><a href="doc-index-All.html">All</a></li></ul></div><div id="index"><p class="caption">Index - R</p><table><tr><td class="src">RawFilePath</td><td class="module">System.Posix.FilePath</td></tr><tr><td class="src">reactOnError</td><td class="module"><a href="HPath-IO-Errors.html#v:reactOnError">HPath.IO.Errors</a></td></tr><tr><td class="src">ReadContentsFailed</td><td class="module"><a href="HPath-IO-Errors.html#v:ReadContentsFailed">HPath.IO.Errors</a></td></tr><tr><td class="src">readDirEnt</td><td class="module"><a href="System-Posix-Directory-Traversals.html#v:readDirEnt">System.Posix.Directory.Traversals</a></td></tr><tr><td class="src">realpath</td><td class="module"><a href="System-Posix-Directory-Traversals.html#v:realpath">System.Posix.Directory.Traversals</a></td></tr><tr><td class="src">recreateSymlink</td><td class="module"><a href="HPath-IO.html#v:recreateSymlink">HPath.IO</a></td></tr><tr><td class="src">RecreateSymlinkFailed</td><td class="module"><a href="HPath-IO-Errors.html#v:RecreateSymlinkFailed">HPath.IO.Errors</a></td></tr><tr><td class="src">RecursiveErrorMode</td><td class="module"><a href="HPath-IO.html#t:RecursiveErrorMode">HPath.IO</a></td></tr><tr><td class="src">RecursiveFailure</td><td class="module"><a href="HPath-IO-Errors.html#v:RecursiveFailure">HPath.IO.Errors</a></td></tr><tr><td class="src">RecursiveFailureHint</td><td class="module"><a href="HPath-IO-Errors.html#t:RecursiveFailureHint">HPath.IO.Errors</a></td></tr><tr><td class="src">RegularFile</td><td class="module"><a href="HPath-IO.html#v:RegularFile">HPath.IO</a></td></tr><tr><td class="src">Rel</td><td class="module"><a href="HPath.html#t:Rel">HPath</a></td></tr><tr><td class="src">RelC</td><td class="module"><a href="HPath.html#t:RelC">HPath</a></td></tr><tr><td class="src">renameFile</td><td class="module"><a href="HPath-IO.html#v:renameFile">HPath.IO</a></td></tr><tr><td class="src">replaceBaseName</td><td class="module"><a href="System-Posix-FilePath.html#v:replaceBaseName">System.Posix.FilePath</a></td></tr><tr><td class="src">replaceDirectory</td><td class="module"><a href="System-Posix-FilePath.html#v:replaceDirectory">System.Posix.FilePath</a></td></tr><tr><td class="src">replaceExtension</td><td class="module"><a href="System-Posix-FilePath.html#v:replaceExtension">System.Posix.FilePath</a></td></tr><tr><td class="src">replaceFileName</td><td class="module"><a href="System-Posix-FilePath.html#v:replaceFileName">System.Posix.FilePath</a></td></tr><tr><td class="src">rethrowErrnoAs</td><td class="module"><a href="HPath-IO-Errors.html#v:rethrowErrnoAs">HPath.IO.Errors</a></td></tr></table></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
4
doc-index-S.html
Normal file
4
doc-index-S.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>hpath-0.8.0: Support for well-typed paths (Index - S)</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="alphabet"><ul><li><a href="doc-index-A.html">A</a></li><li><a href="doc-index-B.html">B</a></li><li><a href="doc-index-C.html">C</a></li><li><a href="doc-index-D.html">D</a></li><li><a href="doc-index-E.html">E</a></li><li><a href="doc-index-F.html">F</a></li><li><a href="doc-index-G.html">G</a></li><li><a href="doc-index-H.html">H</a></li><li><a href="doc-index-I.html">I</a></li><li><a href="doc-index-J.html">J</a></li><li><a href="doc-index-M.html">M</a></li><li><a href="doc-index-N.html">N</a></li><li><a href="doc-index-O.html">O</a></li><li><a href="doc-index-P.html">P</a></li><li><a href="doc-index-R.html">R</a></li><li><a href="doc-index-S.html">S</a></li><li><a href="doc-index-T.html">T</a></li><li><a href="doc-index-U.html">U</a></li><li><a href="doc-index-W.html">W</a></li><li><a href="doc-index-60.html"><</a></li><li><a href="doc-index-All.html">All</a></li></ul></div><div id="index"><p class="caption">Index - S</p><table><tr><td class="src">SameFile</td><td class="module"><a href="HPath-IO-Errors.html#v:SameFile">HPath.IO.Errors</a></td></tr><tr><td class="src">sameFile</td><td class="module"><a href="HPath-IO-Errors.html#v:sameFile">HPath.IO.Errors</a></td></tr><tr><td class="src">searchPathSeparator</td><td class="module"><a href="System-Posix-FilePath.html#v:searchPathSeparator">System.Posix.FilePath</a></td></tr><tr><td class="src">Socket</td><td class="module"><a href="HPath-IO.html#v:Socket">HPath.IO</a></td></tr><tr><td class="src">splitDirectories</td><td class="module"><a href="System-Posix-FilePath.html#v:splitDirectories">System.Posix.FilePath</a></td></tr><tr><td class="src">splitExtension</td><td class="module"><a href="System-Posix-FilePath.html#v:splitExtension">System.Posix.FilePath</a></td></tr><tr><td class="src">splitExtensions</td><td class="module"><a href="System-Posix-FilePath.html#v:splitExtensions">System.Posix.FilePath</a></td></tr><tr><td class="src">splitFileName</td><td class="module"><a href="System-Posix-FilePath.html#v:splitFileName">System.Posix.FilePath</a></td></tr><tr><td class="src">splitPath</td><td class="module"><a href="System-Posix-FilePath.html#v:splitPath">System.Posix.FilePath</a></td></tr><tr><td class="src">splitSearchPath</td><td class="module"><a href="System-Posix-FilePath.html#v:splitSearchPath">System.Posix.FilePath</a></td></tr><tr><td class="src">Strict</td><td class="module"><a href="HPath-IO.html#v:Strict">HPath.IO</a></td></tr><tr><td class="src">stripDir</td><td class="module"><a href="HPath.html#v:stripDir">HPath</a></td></tr><tr><td class="src">stripExtension</td><td class="module"><a href="System-Posix-FilePath.html#v:stripExtension">System.Posix.FilePath</a></td></tr><tr><td class="src">SymbolicLink</td><td class="module"><a href="HPath-IO.html#v:SymbolicLink">HPath.IO</a></td></tr></table></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
4
doc-index-T.html
Normal file
4
doc-index-T.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>hpath-0.8.0: Support for well-typed paths (Index - T)</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="alphabet"><ul><li><a href="doc-index-A.html">A</a></li><li><a href="doc-index-B.html">B</a></li><li><a href="doc-index-C.html">C</a></li><li><a href="doc-index-D.html">D</a></li><li><a href="doc-index-E.html">E</a></li><li><a href="doc-index-F.html">F</a></li><li><a href="doc-index-G.html">G</a></li><li><a href="doc-index-H.html">H</a></li><li><a href="doc-index-I.html">I</a></li><li><a href="doc-index-J.html">J</a></li><li><a href="doc-index-M.html">M</a></li><li><a href="doc-index-N.html">N</a></li><li><a href="doc-index-O.html">O</a></li><li><a href="doc-index-P.html">P</a></li><li><a href="doc-index-R.html">R</a></li><li><a href="doc-index-S.html">S</a></li><li><a href="doc-index-T.html">T</a></li><li><a href="doc-index-U.html">U</a></li><li><a href="doc-index-W.html">W</a></li><li><a href="doc-index-60.html"><</a></li><li><a href="doc-index-All.html">All</a></li></ul></div><div id="index"><p class="caption">Index - T</p><table><tr><td class="src">takeBaseName</td><td class="module"><a href="System-Posix-FilePath.html#v:takeBaseName">System.Posix.FilePath</a></td></tr><tr><td class="src">takeDirectory</td><td class="module"><a href="System-Posix-FilePath.html#v:takeDirectory">System.Posix.FilePath</a></td></tr><tr><td class="src">takeExtension</td><td class="module"><a href="System-Posix-FilePath.html#v:takeExtension">System.Posix.FilePath</a></td></tr><tr><td class="src">takeExtensions</td><td class="module"><a href="System-Posix-FilePath.html#v:takeExtensions">System.Posix.FilePath</a></td></tr><tr><td class="src">takeFileName</td><td class="module"><a href="System-Posix-FilePath.html#v:takeFileName">System.Posix.FilePath</a></td></tr><tr><td class="src">throwDestinationInSource</td><td class="module"><a href="HPath-IO-Errors.html#v:throwDestinationInSource">HPath.IO.Errors</a></td></tr><tr><td class="src">throwDirDoesExist</td><td class="module"><a href="HPath-IO-Errors.html#v:throwDirDoesExist">HPath.IO.Errors</a></td></tr><tr><td class="src">throwErrnoPath</td><td class="module">System.Posix.FilePath</td></tr><tr><td class="src">throwErrnoPathIf</td><td class="module">System.Posix.FilePath</td></tr><tr><td class="src">throwErrnoPathIfMinus1</td><td class="module">System.Posix.FilePath</td></tr><tr><td class="src">throwErrnoPathIfMinus1Retry</td><td class="module">System.Posix.FilePath</td></tr><tr><td class="src">throwErrnoPathIfMinus1Retry_</td><td class="module">System.Posix.FilePath</td></tr><tr><td class="src">throwErrnoPathIfMinus1_</td><td class="module">System.Posix.FilePath</td></tr><tr><td class="src">throwErrnoPathIfNull</td><td class="module">System.Posix.FilePath</td></tr><tr><td class="src">throwErrnoPathIfNullRetry</td><td class="module">System.Posix.FilePath</td></tr><tr><td class="src">throwErrnoPathIfRetry</td><td class="module">System.Posix.FilePath</td></tr><tr><td class="src">throwErrnoPathIf_</td><td class="module">System.Posix.FilePath</td></tr><tr><td class="src">throwFileDoesExist</td><td class="module"><a href="HPath-IO-Errors.html#v:throwFileDoesExist">HPath.IO.Errors</a></td></tr><tr><td class="src">throwSameFile</td><td class="module"><a href="HPath-IO-Errors.html#v:throwSameFile">HPath.IO.Errors</a></td></tr><tr><td class="src">toFilePath</td><td class="module"><a href="HPath.html#v:toFilePath">HPath</a></td></tr><tr><td class="src">traverseDirectory</td><td class="module"><a href="System-Posix-Directory-Traversals.html#v:traverseDirectory">System.Posix.Directory.Traversals</a></td></tr></table></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
4
doc-index-U.html
Normal file
4
doc-index-U.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>hpath-0.8.0: Support for well-typed paths (Index - U)</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="alphabet"><ul><li><a href="doc-index-A.html">A</a></li><li><a href="doc-index-B.html">B</a></li><li><a href="doc-index-C.html">C</a></li><li><a href="doc-index-D.html">D</a></li><li><a href="doc-index-E.html">E</a></li><li><a href="doc-index-F.html">F</a></li><li><a href="doc-index-G.html">G</a></li><li><a href="doc-index-H.html">H</a></li><li><a href="doc-index-I.html">I</a></li><li><a href="doc-index-J.html">J</a></li><li><a href="doc-index-M.html">M</a></li><li><a href="doc-index-N.html">N</a></li><li><a href="doc-index-O.html">O</a></li><li><a href="doc-index-P.html">P</a></li><li><a href="doc-index-R.html">R</a></li><li><a href="doc-index-S.html">S</a></li><li><a href="doc-index-T.html">T</a></li><li><a href="doc-index-U.html">U</a></li><li><a href="doc-index-W.html">W</a></li><li><a href="doc-index-60.html"><</a></li><li><a href="doc-index-All.html">All</a></li></ul></div><div id="index"><p class="caption">Index - U</p><table><tr><td class="src">unFlags</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:unFlags">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">unionFlags</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:unionFlags">System.Posix.Directory.Foreign</a></td></tr><tr><td class="src">unpackDirStream</td><td class="module"><a href="System-Posix-Directory-Traversals.html#v:unpackDirStream">System.Posix.Directory.Traversals</a></td></tr><tr><td class="src">UnsupportedFlag</td><td class="module"><a href="System-Posix-Directory-Foreign.html#v:UnsupportedFlag">System.Posix.Directory.Foreign</a></td></tr></table></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
4
doc-index-W.html
Normal file
4
doc-index-W.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>hpath-0.8.0: Support for well-typed paths (Index - W)</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="alphabet"><ul><li><a href="doc-index-A.html">A</a></li><li><a href="doc-index-B.html">B</a></li><li><a href="doc-index-C.html">C</a></li><li><a href="doc-index-D.html">D</a></li><li><a href="doc-index-E.html">E</a></li><li><a href="doc-index-F.html">F</a></li><li><a href="doc-index-G.html">G</a></li><li><a href="doc-index-H.html">H</a></li><li><a href="doc-index-I.html">I</a></li><li><a href="doc-index-J.html">J</a></li><li><a href="doc-index-M.html">M</a></li><li><a href="doc-index-N.html">N</a></li><li><a href="doc-index-O.html">O</a></li><li><a href="doc-index-P.html">P</a></li><li><a href="doc-index-R.html">R</a></li><li><a href="doc-index-S.html">S</a></li><li><a href="doc-index-T.html">T</a></li><li><a href="doc-index-U.html">U</a></li><li><a href="doc-index-W.html">W</a></li><li><a href="doc-index-60.html"><</a></li><li><a href="doc-index-All.html">All</a></li></ul></div><div id="index"><p class="caption">Index - W</p><table><tr><td class="src">withAbsPath</td><td class="module"><a href="HPath.html#v:withAbsPath">HPath</a></td></tr><tr><td class="src">withFilePath</td><td class="module">System.Posix.FilePath</td></tr><tr><td class="src">withFnPath</td><td class="module"><a href="HPath.html#v:withFnPath">HPath</a></td></tr><tr><td class="src">withRelPath</td><td class="module"><a href="HPath.html#v:withRelPath">HPath</a></td></tr></table></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
4
doc-index.html
Normal file
4
doc-index.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>hpath-0.8.0: Support for well-typed paths (Index)</title><link href="ocean.css" rel="stylesheet" type="text/css" title="Ocean" /><script src="haddock-util.js" type="text/javascript"></script><script type="text/javascript">//<![CDATA[
|
||||||
|
window.onload = function () {pageLoad();};
|
||||||
|
//]]>
|
||||||
|
</script></head><body><div id="package-header"><ul class="links" id="page-menu"><li><a href="index.html">Contents</a></li><li><a href="doc-index.html">Index</a></li></ul><p class="caption">hpath-0.8.0: Support for well-typed paths</p></div><div id="content"><div id="alphabet"><ul><li><a href="doc-index-A.html">A</a></li><li><a href="doc-index-B.html">B</a></li><li><a href="doc-index-C.html">C</a></li><li><a href="doc-index-D.html">D</a></li><li><a href="doc-index-E.html">E</a></li><li><a href="doc-index-F.html">F</a></li><li><a href="doc-index-G.html">G</a></li><li><a href="doc-index-H.html">H</a></li><li><a href="doc-index-I.html">I</a></li><li><a href="doc-index-J.html">J</a></li><li><a href="doc-index-M.html">M</a></li><li><a href="doc-index-N.html">N</a></li><li><a href="doc-index-O.html">O</a></li><li><a href="doc-index-P.html">P</a></li><li><a href="doc-index-R.html">R</a></li><li><a href="doc-index-S.html">S</a></li><li><a href="doc-index-T.html">T</a></li><li><a href="doc-index-U.html">U</a></li><li><a href="doc-index-W.html">W</a></li><li><a href="doc-index-60.html"><</a></li><li><a href="doc-index-All.html">All</a></li></ul></div></div><div id="footer"><p>Produced by <a href="http://www.haskell.org/haddock/">Haddock</a> version 2.16.1</p></div></body></html>
|
30
frames.html
Normal file
30
frames.html
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<!DOCTYPE html
|
||||||
|
PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<title></title>
|
||||||
|
<script src="haddock-util.js" type="text/javascript"></script>
|
||||||
|
<script type="text/javascript"><!--
|
||||||
|
/*
|
||||||
|
|
||||||
|
The synopsis frame needs to be updated using javascript, so we hide
|
||||||
|
it by default and only show it if javascript is enabled.
|
||||||
|
|
||||||
|
TODO: provide some means to disable it.
|
||||||
|
*/
|
||||||
|
function load() {
|
||||||
|
var d = document.getElementById("inner-fs");
|
||||||
|
d.rows = "50%,50%";
|
||||||
|
postReframe();
|
||||||
|
}
|
||||||
|
--></script>
|
||||||
|
</head>
|
||||||
|
<frameset id="outer-fs" cols="25%,75%" onload="load()">
|
||||||
|
<frameset id="inner-fs" rows="100%,0%">
|
||||||
|
<frame src="index-frames.html" name="modules" />
|
||||||
|
<frame src="" name="synopsis" />
|
||||||
|
</frameset>
|
||||||
|
<frame src="index.html" name="main" />
|
||||||
|
</frameset>
|
||||||
|
</html>
|
344
haddock-util.js
Normal file
344
haddock-util.js
Normal file
@ -0,0 +1,344 @@
|
|||||||
|
// Haddock JavaScript utilities
|
||||||
|
|
||||||
|
var rspace = /\s\s+/g,
|
||||||
|
rtrim = /^\s+|\s+$/g;
|
||||||
|
|
||||||
|
function spaced(s) { return (" " + s + " ").replace(rspace, " "); }
|
||||||
|
function trim(s) { return s.replace(rtrim, ""); }
|
||||||
|
|
||||||
|
function hasClass(elem, value) {
|
||||||
|
var className = spaced(elem.className || "");
|
||||||
|
return className.indexOf( " " + value + " " ) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addClass(elem, value) {
|
||||||
|
var className = spaced(elem.className || "");
|
||||||
|
if ( className.indexOf( " " + value + " " ) < 0 ) {
|
||||||
|
elem.className = trim(className + " " + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeClass(elem, value) {
|
||||||
|
var className = spaced(elem.className || "");
|
||||||
|
className = className.replace(" " + value + " ", " ");
|
||||||
|
elem.className = trim(className);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleClass(elem, valueOn, valueOff, bool) {
|
||||||
|
if (bool == null) { bool = ! hasClass(elem, valueOn); }
|
||||||
|
if (bool) {
|
||||||
|
removeClass(elem, valueOff);
|
||||||
|
addClass(elem, valueOn);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
removeClass(elem, valueOn);
|
||||||
|
addClass(elem, valueOff);
|
||||||
|
}
|
||||||
|
return bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function makeClassToggle(valueOn, valueOff)
|
||||||
|
{
|
||||||
|
return function(elem, bool) {
|
||||||
|
return toggleClass(elem, valueOn, valueOff, bool);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleShow = makeClassToggle("show", "hide");
|
||||||
|
toggleCollapser = makeClassToggle("collapser", "expander");
|
||||||
|
|
||||||
|
function toggleSection(id)
|
||||||
|
{
|
||||||
|
var b = toggleShow(document.getElementById("section." + id));
|
||||||
|
toggleCollapser(document.getElementById("control." + id), b);
|
||||||
|
rememberCollapsed(id, b);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
var collapsed = {};
|
||||||
|
function rememberCollapsed(id, b)
|
||||||
|
{
|
||||||
|
if(b)
|
||||||
|
delete collapsed[id]
|
||||||
|
else
|
||||||
|
collapsed[id] = null;
|
||||||
|
|
||||||
|
var sections = [];
|
||||||
|
for(var i in collapsed)
|
||||||
|
{
|
||||||
|
if(collapsed.hasOwnProperty(i))
|
||||||
|
sections.push(i);
|
||||||
|
}
|
||||||
|
// cookie specific to this page; don't use setCookie which sets path=/
|
||||||
|
document.cookie = "collapsed=" + escape(sections.join('+'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreCollapsed()
|
||||||
|
{
|
||||||
|
var cookie = getCookie("collapsed");
|
||||||
|
if(!cookie)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var ids = cookie.split('+');
|
||||||
|
for(var i in ids)
|
||||||
|
{
|
||||||
|
if(document.getElementById("section." + ids[i]))
|
||||||
|
toggleSection(ids[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setCookie(name, value) {
|
||||||
|
document.cookie = name + "=" + escape(value) + ";path=/;";
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearCookie(name) {
|
||||||
|
document.cookie = name + "=;path=/;expires=Thu, 01-Jan-1970 00:00:01 GMT;";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCookie(name) {
|
||||||
|
var nameEQ = name + "=";
|
||||||
|
var ca = document.cookie.split(';');
|
||||||
|
for(var i=0;i < ca.length;i++) {
|
||||||
|
var c = ca[i];
|
||||||
|
while (c.charAt(0)==' ') c = c.substring(1,c.length);
|
||||||
|
if (c.indexOf(nameEQ) == 0) {
|
||||||
|
return unescape(c.substring(nameEQ.length,c.length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var max_results = 75; // 50 is not enough to search for map in the base libraries
|
||||||
|
var shown_range = null;
|
||||||
|
var last_search = null;
|
||||||
|
|
||||||
|
function quick_search()
|
||||||
|
{
|
||||||
|
perform_search(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function full_search()
|
||||||
|
{
|
||||||
|
perform_search(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function perform_search(full)
|
||||||
|
{
|
||||||
|
var text = document.getElementById("searchbox").value.toLowerCase();
|
||||||
|
if (text == last_search && !full) return;
|
||||||
|
last_search = text;
|
||||||
|
|
||||||
|
var table = document.getElementById("indexlist");
|
||||||
|
var status = document.getElementById("searchmsg");
|
||||||
|
var children = table.firstChild.childNodes;
|
||||||
|
|
||||||
|
// first figure out the first node with the prefix
|
||||||
|
var first = bisect(-1);
|
||||||
|
var last = (first == -1 ? -1 : bisect(1));
|
||||||
|
|
||||||
|
if (first == -1)
|
||||||
|
{
|
||||||
|
table.className = "";
|
||||||
|
status.innerHTML = "No results found, displaying all";
|
||||||
|
}
|
||||||
|
else if (first == 0 && last == children.length - 1)
|
||||||
|
{
|
||||||
|
table.className = "";
|
||||||
|
status.innerHTML = "";
|
||||||
|
}
|
||||||
|
else if (last - first >= max_results && !full)
|
||||||
|
{
|
||||||
|
table.className = "";
|
||||||
|
status.innerHTML = "More than " + max_results + ", press Search to display";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// decide what you need to clear/show
|
||||||
|
if (shown_range)
|
||||||
|
setclass(shown_range[0], shown_range[1], "indexrow");
|
||||||
|
setclass(first, last, "indexshow");
|
||||||
|
shown_range = [first, last];
|
||||||
|
table.className = "indexsearch";
|
||||||
|
status.innerHTML = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function setclass(first, last, status)
|
||||||
|
{
|
||||||
|
for (var i = first; i <= last; i++)
|
||||||
|
{
|
||||||
|
children[i].className = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// do a binary search, treating 0 as ...
|
||||||
|
// return either -1 (no 0's found) or location of most far match
|
||||||
|
function bisect(dir)
|
||||||
|
{
|
||||||
|
var first = 0, finish = children.length - 1;
|
||||||
|
var mid, success = false;
|
||||||
|
|
||||||
|
while (finish - first > 3)
|
||||||
|
{
|
||||||
|
mid = Math.floor((finish + first) / 2);
|
||||||
|
|
||||||
|
var i = checkitem(mid);
|
||||||
|
if (i == 0) i = dir;
|
||||||
|
if (i == -1)
|
||||||
|
finish = mid;
|
||||||
|
else
|
||||||
|
first = mid;
|
||||||
|
}
|
||||||
|
var a = (dir == 1 ? first : finish);
|
||||||
|
var b = (dir == 1 ? finish : first);
|
||||||
|
for (var i = b; i != a - dir; i -= dir)
|
||||||
|
{
|
||||||
|
if (checkitem(i) == 0) return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// from an index, decide what the result is
|
||||||
|
// 0 = match, -1 is lower, 1 is higher
|
||||||
|
function checkitem(i)
|
||||||
|
{
|
||||||
|
var s = getitem(i).toLowerCase().substr(0, text.length);
|
||||||
|
if (s == text) return 0;
|
||||||
|
else return (s > text ? -1 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// from an index, get its string
|
||||||
|
// this abstracts over alternates
|
||||||
|
function getitem(i)
|
||||||
|
{
|
||||||
|
for ( ; i >= 0; i--)
|
||||||
|
{
|
||||||
|
var s = children[i].firstChild.firstChild.data;
|
||||||
|
if (s.indexOf(' ') == -1)
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
return ""; // should never be reached
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSynopsis(filename) {
|
||||||
|
if (parent.window.synopsis) {
|
||||||
|
if (parent.window.synopsis.location.replace) {
|
||||||
|
// In Firefox this avoids adding the change to the history.
|
||||||
|
parent.window.synopsis.location.replace(filename);
|
||||||
|
} else {
|
||||||
|
parent.window.synopsis.location = filename;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addMenuItem(html) {
|
||||||
|
var menu = document.getElementById("page-menu");
|
||||||
|
if (menu) {
|
||||||
|
var btn = menu.firstChild.cloneNode(false);
|
||||||
|
btn.innerHTML = html;
|
||||||
|
menu.appendChild(btn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function adjustForFrames() {
|
||||||
|
var bodyCls;
|
||||||
|
|
||||||
|
if (parent.location.href == window.location.href) {
|
||||||
|
// not in frames, so add Frames button
|
||||||
|
addMenuItem("<a href='#' onclick='reframe();return true;'>Frames</a>");
|
||||||
|
bodyCls = "no-frame";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bodyCls = "in-frame";
|
||||||
|
}
|
||||||
|
addClass(document.body, bodyCls);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reframe() {
|
||||||
|
setCookie("haddock-reframe", document.URL);
|
||||||
|
window.location = "frames.html";
|
||||||
|
}
|
||||||
|
|
||||||
|
function postReframe() {
|
||||||
|
var s = getCookie("haddock-reframe");
|
||||||
|
if (s) {
|
||||||
|
parent.window.main.location = s;
|
||||||
|
clearCookie("haddock-reframe");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function styles() {
|
||||||
|
var i, a, es = document.getElementsByTagName("link"), rs = [];
|
||||||
|
for (i = 0; a = es[i]; i++) {
|
||||||
|
if(a.rel.indexOf("style") != -1 && a.title) {
|
||||||
|
rs.push(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rs;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addStyleMenu() {
|
||||||
|
var as = styles();
|
||||||
|
var i, a, btns = "";
|
||||||
|
for(i=0; a = as[i]; i++) {
|
||||||
|
btns += "<li><a href='#' onclick=\"setActiveStyleSheet('"
|
||||||
|
+ a.title + "'); return false;\">"
|
||||||
|
+ a.title + "</a></li>"
|
||||||
|
}
|
||||||
|
if (as.length > 1) {
|
||||||
|
var h = "<div id='style-menu-holder'>"
|
||||||
|
+ "<a href='#' onclick='styleMenu(); return false;'>Style ▾</a>"
|
||||||
|
+ "<ul id='style-menu' class='hide'>" + btns + "</ul>"
|
||||||
|
+ "</div>";
|
||||||
|
addMenuItem(h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setActiveStyleSheet(title) {
|
||||||
|
var as = styles();
|
||||||
|
var i, a, found;
|
||||||
|
for(i=0; a = as[i]; i++) {
|
||||||
|
a.disabled = true;
|
||||||
|
// need to do this always, some browsers are edge triggered
|
||||||
|
if(a.title == title) {
|
||||||
|
found = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
found.disabled = false;
|
||||||
|
setCookie("haddock-style", title);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
as[0].disabled = false;
|
||||||
|
clearCookie("haddock-style");
|
||||||
|
}
|
||||||
|
styleMenu(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetStyle() {
|
||||||
|
var s = getCookie("haddock-style");
|
||||||
|
if (s) setActiveStyleSheet(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function styleMenu(show) {
|
||||||
|
var m = document.getElementById('style-menu');
|
||||||
|
if (m) toggleShow(m, show);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function pageLoad() {
|
||||||
|
addStyleMenu();
|
||||||
|
adjustForFrames();
|
||||||
|
resetStyle();
|
||||||
|
restoreCollapsed();
|
||||||
|
}
|
||||||
|
|
@ -1,21 +0,0 @@
|
|||||||
# Revision history for hpath-directory
|
|
||||||
|
|
||||||
## 0.13.4 -- 2020-05-08
|
|
||||||
|
|
||||||
* Add getDirsFilesStream and use streamly-posix for dircontents (#34)
|
|
||||||
|
|
||||||
## 0.13.3 -- 2020-04-14
|
|
||||||
|
|
||||||
* Fix tests on mac
|
|
||||||
|
|
||||||
## 0.13.2 -- 2020-02-17
|
|
||||||
|
|
||||||
* Fix bug in `createDirRecursive` with trailing path separators
|
|
||||||
|
|
||||||
## 0.13.1 -- 2020-01-29
|
|
||||||
|
|
||||||
* Split some functionality out into 'hpath-posix'
|
|
||||||
|
|
||||||
## 0.1.0.0 -- 2020-01-26
|
|
||||||
|
|
||||||
* First version. Released on an unsuspecting world.
|
|
@ -1,30 +0,0 @@
|
|||||||
Copyright (c) 2020, Julian Ospald
|
|
||||||
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following
|
|
||||||
disclaimer in the documentation and/or other materials provided
|
|
||||||
with the distribution.
|
|
||||||
|
|
||||||
* Neither the name of Julian Ospald nor the names of other
|
|
||||||
contributors may be used to endorse or promote products derived
|
|
||||||
from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,21 +0,0 @@
|
|||||||
# HPath-filepath
|
|
||||||
|
|
||||||
[![Gitter chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hasufell/hpath?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Hackage version](https://img.shields.io/hackage/v/hpath-directory.svg?label=Hackage)](https://hackage.haskell.org/package/hpath-directory) [![Build Status](https://api.travis-ci.org/hasufell/hpath.png?branch=master)](http://travis-ci.org/hasufell/hpath) [![Hackage-Deps](https://img.shields.io/hackage-deps/v/hpath-directory.svg)](http://packdeps.haskellers.com/feed?needle=hpath-directory)
|
|
||||||
|
|
||||||
Support high-level IO operations on files/directories, utilizing ByteString
|
|
||||||
as FilePaths.
|
|
||||||
|
|
||||||
This package is part of the HPath suite, also check out:
|
|
||||||
|
|
||||||
* [hpath](https://hackage.haskell.org/package/hpath)
|
|
||||||
* [hpath-filepath](https://hackage.haskell.org/package/hpath-filepath)
|
|
||||||
* [hpath-io](https://hackage.haskell.org/package/hpath-io)
|
|
||||||
|
|
||||||
## Motivation
|
|
||||||
|
|
||||||
This is basically a fork of [directory](https://hackage.haskell.org/package/directory), but is a complete rewrite and the API doesn't follow the directory package.
|
|
||||||
|
|
||||||
## Differences to 'posix-paths'
|
|
||||||
|
|
||||||
* has a custom versions of `openFd` which allows more control over the flags than its unix package counterpart
|
|
||||||
* adds a `getDirectoryContents'` version that works on Fd
|
|
@ -1,2 +0,0 @@
|
|||||||
import Distribution.Simple
|
|
||||||
main = defaultMain
|
|
@ -1,116 +0,0 @@
|
|||||||
cabal-version: >=1.10
|
|
||||||
|
|
||||||
name: hpath-directory
|
|
||||||
version: 0.13.4
|
|
||||||
synopsis: Alternative to 'directory' package with ByteString based filepaths
|
|
||||||
description: This provides a safer alternative to the 'directory'
|
|
||||||
package. FilePaths are ByteString based, so this
|
|
||||||
package only works on POSIX systems.
|
|
||||||
|
|
||||||
For a more high-level version of this with
|
|
||||||
proper Path type, use 'hpath-io', which makes
|
|
||||||
use of this package.
|
|
||||||
homepage: https://github.com/hasufell/hpath
|
|
||||||
bug-reports: https://github.com/hasufell/hpath/issues
|
|
||||||
license: BSD3
|
|
||||||
license-file: LICENSE
|
|
||||||
author: Julian Ospald <hasufell@posteo.de>
|
|
||||||
maintainer: Julian Ospald <hasufell@posteo.de>
|
|
||||||
copyright: Julian Ospald <hasufell@posteo.de> 2020
|
|
||||||
category: Filesystem
|
|
||||||
build-type: Simple
|
|
||||||
extra-source-files: CHANGELOG.md
|
|
||||||
tested-with: GHC==7.10.3
|
|
||||||
, GHC==8.0.2
|
|
||||||
, GHC==8.2.2
|
|
||||||
, GHC==8.4.4
|
|
||||||
, GHC==8.6.5
|
|
||||||
, GHC==8.8.1
|
|
||||||
|
|
||||||
library
|
|
||||||
if os(windows)
|
|
||||||
build-depends: unbuildable<0
|
|
||||||
buildable: False
|
|
||||||
exposed-modules: System.Posix.RawFilePath.Directory
|
|
||||||
System.Posix.RawFilePath.Directory.Errors
|
|
||||||
-- other-modules:
|
|
||||||
-- other-extensions:
|
|
||||||
build-depends: base >= 4.8 && <5
|
|
||||||
, IfElse
|
|
||||||
, bytestring >= 0.10
|
|
||||||
, exceptions >= 0.10
|
|
||||||
, hpath-filepath >= 0.10.3
|
|
||||||
, hpath-posix >= 0.13
|
|
||||||
, safe-exceptions >= 0.1
|
|
||||||
, streamly >= 0.7
|
|
||||||
, streamly-bytestring >= 0.1.2
|
|
||||||
, streamly-posix >= 0.1.0.1
|
|
||||||
, time >= 1.8
|
|
||||||
, transformers
|
|
||||||
, unix >= 2.5
|
|
||||||
, unix-bytestring >= 0.3
|
|
||||||
, utf8-string
|
|
||||||
if impl(ghc < 8.0)
|
|
||||||
build-depends:
|
|
||||||
fail >= 4.9
|
|
||||||
|
|
||||||
hs-source-dirs: src
|
|
||||||
default-language: Haskell2010
|
|
||||||
default-extensions: PackageImports
|
|
||||||
|
|
||||||
test-suite spec
|
|
||||||
if os(windows)
|
|
||||||
build-depends: unbuildable<0
|
|
||||||
buildable: False
|
|
||||||
Type: exitcode-stdio-1.0
|
|
||||||
Default-Language: Haskell2010
|
|
||||||
Hs-Source-Dirs: test
|
|
||||||
Main-Is: Main.hs
|
|
||||||
other-modules:
|
|
||||||
System.Posix.RawFilePath.Directory.AppendFileSpec
|
|
||||||
System.Posix.RawFilePath.Directory.CanonicalizePathSpec
|
|
||||||
System.Posix.RawFilePath.Directory.CopyDirRecursiveCollectFailuresSpec
|
|
||||||
System.Posix.RawFilePath.Directory.CopyDirRecursiveOverwriteSpec
|
|
||||||
System.Posix.RawFilePath.Directory.CopyDirRecursiveSpec
|
|
||||||
System.Posix.RawFilePath.Directory.CopyFileOverwriteSpec
|
|
||||||
System.Posix.RawFilePath.Directory.CopyFileSpec
|
|
||||||
System.Posix.RawFilePath.Directory.CreateDirIfMissingSpec
|
|
||||||
System.Posix.RawFilePath.Directory.CreateDirRecursiveSpec
|
|
||||||
System.Posix.RawFilePath.Directory.CreateDirSpec
|
|
||||||
System.Posix.RawFilePath.Directory.CreateRegularFileSpec
|
|
||||||
System.Posix.RawFilePath.Directory.CreateSymlinkSpec
|
|
||||||
System.Posix.RawFilePath.Directory.DeleteDirRecursiveSpec
|
|
||||||
System.Posix.RawFilePath.Directory.DeleteDirSpec
|
|
||||||
System.Posix.RawFilePath.Directory.DeleteFileSpec
|
|
||||||
System.Posix.RawFilePath.Directory.GetDirsFilesSpec
|
|
||||||
System.Posix.RawFilePath.Directory.GetFileTypeSpec
|
|
||||||
System.Posix.RawFilePath.Directory.MoveFileOverwriteSpec
|
|
||||||
System.Posix.RawFilePath.Directory.MoveFileSpec
|
|
||||||
System.Posix.RawFilePath.Directory.ReadFileSpec
|
|
||||||
System.Posix.RawFilePath.Directory.RecreateSymlinkOverwriteSpec
|
|
||||||
System.Posix.RawFilePath.Directory.RecreateSymlinkSpec
|
|
||||||
System.Posix.RawFilePath.Directory.RenameFileSpec
|
|
||||||
System.Posix.RawFilePath.Directory.ToAbsSpec
|
|
||||||
System.Posix.RawFilePath.Directory.WriteFileLSpec
|
|
||||||
System.Posix.RawFilePath.Directory.WriteFileSpec
|
|
||||||
Spec
|
|
||||||
Utils
|
|
||||||
GHC-Options: -Wall
|
|
||||||
Build-Depends: base
|
|
||||||
, HUnit
|
|
||||||
, IfElse
|
|
||||||
, bytestring >= 0.10.0.0
|
|
||||||
, hpath-directory
|
|
||||||
, hpath-filepath >= 0.10
|
|
||||||
, hpath-posix >= 0.13
|
|
||||||
, hspec >= 1.3
|
|
||||||
, process
|
|
||||||
, time >= 1.8
|
|
||||||
, unix
|
|
||||||
, unix-bytestring
|
|
||||||
, utf8-string
|
|
||||||
default-extensions: PackageImports
|
|
||||||
|
|
||||||
source-repository head
|
|
||||||
type: git
|
|
||||||
location: https://github.com/hasufell/hpath
|
|
File diff suppressed because it is too large
Load Diff
@ -1,15 +0,0 @@
|
|||||||
module System.Posix.RawFilePath.Directory where
|
|
||||||
|
|
||||||
import System.Posix.ByteString.FilePath (RawFilePath)
|
|
||||||
|
|
||||||
canonicalizePath :: RawFilePath -> IO RawFilePath
|
|
||||||
|
|
||||||
toAbs :: RawFilePath -> IO RawFilePath
|
|
||||||
|
|
||||||
doesFileExist :: RawFilePath -> IO Bool
|
|
||||||
|
|
||||||
doesDirectoryExist :: RawFilePath -> IO Bool
|
|
||||||
|
|
||||||
isWritable :: RawFilePath -> IO Bool
|
|
||||||
|
|
||||||
canOpenDirectory :: RawFilePath -> IO Bool
|
|
@ -1,327 +0,0 @@
|
|||||||
-- |
|
|
||||||
-- Module : System.Posix.RawFilePath.Directory.Errors
|
|
||||||
-- Copyright : © 2016 Julian Ospald
|
|
||||||
-- License : BSD3
|
|
||||||
--
|
|
||||||
-- Maintainer : Julian Ospald <hasufell@posteo.de>
|
|
||||||
-- Stability : experimental
|
|
||||||
-- Portability : portable
|
|
||||||
--
|
|
||||||
-- Provides error handling.
|
|
||||||
|
|
||||||
{-# LANGUAGE DeriveDataTypeable #-}
|
|
||||||
{-# LANGUAGE ScopedTypeVariables #-}
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.Errors
|
|
||||||
(
|
|
||||||
-- * Types
|
|
||||||
HPathIOException(..)
|
|
||||||
, RecursiveFailureHint(..)
|
|
||||||
|
|
||||||
-- * Exception identifiers
|
|
||||||
, isSameFile
|
|
||||||
, isDestinationInSource
|
|
||||||
, isRecursiveFailure
|
|
||||||
, isReadContentsFailed
|
|
||||||
, isCreateDirFailed
|
|
||||||
, isCopyFileFailed
|
|
||||||
, isRecreateSymlinkFailed
|
|
||||||
|
|
||||||
-- * Path based functions
|
|
||||||
, throwFileDoesExist
|
|
||||||
, throwDirDoesExist
|
|
||||||
, throwSameFile
|
|
||||||
, sameFile
|
|
||||||
, throwDestinationInSource
|
|
||||||
|
|
||||||
-- * Error handling functions
|
|
||||||
, catchErrno
|
|
||||||
, rethrowErrnoAs
|
|
||||||
, handleIOError
|
|
||||||
, hideError
|
|
||||||
, bracketeer
|
|
||||||
, reactOnError
|
|
||||||
)
|
|
||||||
where
|
|
||||||
|
|
||||||
|
|
||||||
import Control.Applicative
|
|
||||||
(
|
|
||||||
(<$>)
|
|
||||||
)
|
|
||||||
import Control.Exception.Safe hiding (handleIOError)
|
|
||||||
import Control.Monad
|
|
||||||
(
|
|
||||||
forM
|
|
||||||
, when
|
|
||||||
)
|
|
||||||
import Control.Monad.IfElse
|
|
||||||
(
|
|
||||||
whenM
|
|
||||||
)
|
|
||||||
import Data.ByteString
|
|
||||||
(
|
|
||||||
ByteString
|
|
||||||
)
|
|
||||||
import qualified Data.ByteString as BS
|
|
||||||
import Data.ByteString.UTF8
|
|
||||||
(
|
|
||||||
toString
|
|
||||||
)
|
|
||||||
import Data.Typeable
|
|
||||||
(
|
|
||||||
Typeable
|
|
||||||
)
|
|
||||||
import Foreign.C.Error
|
|
||||||
(
|
|
||||||
getErrno
|
|
||||||
, Errno
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType
|
|
||||||
)
|
|
||||||
import {-# SOURCE #-} System.Posix.RawFilePath.Directory
|
|
||||||
(
|
|
||||||
canonicalizePath
|
|
||||||
, toAbs
|
|
||||||
, doesFileExist
|
|
||||||
, doesDirectoryExist
|
|
||||||
, isWritable
|
|
||||||
, canOpenDirectory
|
|
||||||
)
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
alreadyExistsErrorType
|
|
||||||
, ioeGetErrorType
|
|
||||||
, mkIOError
|
|
||||||
)
|
|
||||||
import System.Posix.FilePath
|
|
||||||
import qualified System.Posix.Directory.ByteString as PFD
|
|
||||||
import System.Posix.Files.ByteString
|
|
||||||
(
|
|
||||||
fileAccess
|
|
||||||
, getFileStatus
|
|
||||||
)
|
|
||||||
import qualified System.Posix.Files.ByteString as PF
|
|
||||||
|
|
||||||
|
|
||||||
-- |Additional generic IO exceptions that the posix functions
|
|
||||||
-- do not provide.
|
|
||||||
data HPathIOException = SameFile ByteString ByteString
|
|
||||||
| DestinationInSource ByteString ByteString
|
|
||||||
| RecursiveFailure [(RecursiveFailureHint, IOException)]
|
|
||||||
deriving (Eq, Show, Typeable)
|
|
||||||
|
|
||||||
|
|
||||||
-- |A type for giving failure hints on recursive failure, which allows
|
|
||||||
-- to programmatically make choices without examining
|
|
||||||
-- the weakly typed I/O error attributes (like `ioeGetFileName`).
|
|
||||||
--
|
|
||||||
-- The first argument to the data constructor is always the
|
|
||||||
-- source and the second the destination.
|
|
||||||
data RecursiveFailureHint = ReadContentsFailed ByteString ByteString
|
|
||||||
| CreateDirFailed ByteString ByteString
|
|
||||||
| CopyFileFailed ByteString ByteString
|
|
||||||
| RecreateSymlinkFailed ByteString ByteString
|
|
||||||
deriving (Eq, Show)
|
|
||||||
|
|
||||||
|
|
||||||
instance Exception HPathIOException
|
|
||||||
|
|
||||||
|
|
||||||
toConstr :: HPathIOException -> String
|
|
||||||
toConstr SameFile {} = "SameFile"
|
|
||||||
toConstr DestinationInSource {} = "DestinationInSource"
|
|
||||||
toConstr RecursiveFailure {} = "RecursiveFailure"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------------
|
|
||||||
--[ Exception identifiers ]--
|
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
|
|
||||||
isSameFile, isDestinationInSource, isRecursiveFailure :: HPathIOException -> Bool
|
|
||||||
isSameFile ex = toConstr (ex :: HPathIOException) == toConstr (SameFile mempty mempty)
|
|
||||||
isDestinationInSource ex = toConstr (ex :: HPathIOException) == (toConstr $ DestinationInSource mempty mempty)
|
|
||||||
isRecursiveFailure ex = toConstr (ex :: HPathIOException) == (toConstr $ RecursiveFailure mempty)
|
|
||||||
|
|
||||||
|
|
||||||
isReadContentsFailed, isCreateDirFailed, isCopyFileFailed, isRecreateSymlinkFailed ::RecursiveFailureHint -> Bool
|
|
||||||
isReadContentsFailed ReadContentsFailed{} = True
|
|
||||||
isReadContentsFailed _ = False
|
|
||||||
isCreateDirFailed CreateDirFailed{} = True
|
|
||||||
isCreateDirFailed _ = False
|
|
||||||
isCopyFileFailed CopyFileFailed{} = True
|
|
||||||
isCopyFileFailed _ = False
|
|
||||||
isRecreateSymlinkFailed RecreateSymlinkFailed{} = True
|
|
||||||
isRecreateSymlinkFailed _ = False
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----------------------------
|
|
||||||
--[ Path based functions ]--
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
|
|
||||||
-- |Throws `AlreadyExists` `IOError` if file exists.
|
|
||||||
throwFileDoesExist :: RawFilePath -> IO ()
|
|
||||||
throwFileDoesExist bs =
|
|
||||||
whenM (doesFileExist bs)
|
|
||||||
(ioError . mkIOError
|
|
||||||
alreadyExistsErrorType
|
|
||||||
"File already exists"
|
|
||||||
Nothing
|
|
||||||
$ (Just (toString $ bs))
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
-- |Throws `AlreadyExists` `IOError` if directory exists.
|
|
||||||
throwDirDoesExist :: RawFilePath -> IO ()
|
|
||||||
throwDirDoesExist bs =
|
|
||||||
whenM (doesDirectoryExist bs)
|
|
||||||
(ioError . mkIOError
|
|
||||||
alreadyExistsErrorType
|
|
||||||
"Directory already exists"
|
|
||||||
Nothing
|
|
||||||
$ (Just (toString $ bs))
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
-- |Uses `isSameFile` and throws `SameFile` if it returns True.
|
|
||||||
throwSameFile :: RawFilePath
|
|
||||||
-> RawFilePath
|
|
||||||
-> IO ()
|
|
||||||
throwSameFile bs1 bs2 =
|
|
||||||
whenM (sameFile bs1 bs2)
|
|
||||||
(throwIO $ SameFile bs1 bs2)
|
|
||||||
|
|
||||||
|
|
||||||
-- |Check if the files are the same by examining device and file id.
|
|
||||||
-- This follows symbolic links.
|
|
||||||
sameFile :: RawFilePath -> RawFilePath -> IO Bool
|
|
||||||
sameFile fp1 fp2 =
|
|
||||||
handleIOError (\_ -> return False) $ do
|
|
||||||
fs1 <- getFileStatus fp1
|
|
||||||
fs2 <- getFileStatus fp2
|
|
||||||
|
|
||||||
if ((PF.deviceID fs1, PF.fileID fs1) ==
|
|
||||||
(PF.deviceID fs2, PF.fileID fs2))
|
|
||||||
then return True
|
|
||||||
else return False
|
|
||||||
|
|
||||||
|
|
||||||
-- TODO: make this more robust when destination does not exist
|
|
||||||
-- |Checks whether the destination directory is contained
|
|
||||||
-- within the source directory by comparing the device+file ID of the
|
|
||||||
-- source directory with all device+file IDs of the parent directories
|
|
||||||
-- of the destination.
|
|
||||||
throwDestinationInSource :: RawFilePath -- ^ source dir
|
|
||||||
-> RawFilePath -- ^ full destination, @dirname dest@
|
|
||||||
-- must exist
|
|
||||||
-> IO ()
|
|
||||||
throwDestinationInSource sbs dbs = do
|
|
||||||
destAbs <- toAbs dbs
|
|
||||||
dest' <- (\x -> maybe x (\y -> x </> y) $ basename dbs)
|
|
||||||
<$> (canonicalizePath $ takeDirectory destAbs)
|
|
||||||
dids <- forM (takeAllParents dest') $ \p -> do
|
|
||||||
fs <- PF.getSymbolicLinkStatus p
|
|
||||||
return (PF.deviceID fs, PF.fileID fs)
|
|
||||||
sid <- fmap (\x -> (PF.deviceID x, PF.fileID x))
|
|
||||||
$ PF.getFileStatus sbs
|
|
||||||
when (elem sid dids)
|
|
||||||
(throwIO $ DestinationInSource dbs sbs)
|
|
||||||
where
|
|
||||||
basename x = let b = takeBaseName x
|
|
||||||
in if BS.null b then Nothing else Just b
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--------------------------------
|
|
||||||
--[ Error handling functions ]--
|
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
-- |Carries out an action, then checks if there is an IOException and
|
|
||||||
-- a specific errno. If so, then it carries out another action, otherwise
|
|
||||||
-- it rethrows the error.
|
|
||||||
catchErrno :: [Errno] -- ^ errno to catch
|
|
||||||
-> IO a -- ^ action to try, which can raise an IOException
|
|
||||||
-> IO a -- ^ action to carry out in case of an IOException and
|
|
||||||
-- if errno matches
|
|
||||||
-> IO a
|
|
||||||
catchErrno en a1 a2 =
|
|
||||||
catchIOError a1 $ \e -> do
|
|
||||||
errno <- getErrno
|
|
||||||
if errno `elem` en
|
|
||||||
then a2
|
|
||||||
else ioError e
|
|
||||||
|
|
||||||
|
|
||||||
-- |Execute the given action and retrow IO exceptions as a new Exception
|
|
||||||
-- that have the given errno. If errno does not match the exception is rethrown
|
|
||||||
-- as is.
|
|
||||||
rethrowErrnoAs :: Exception e
|
|
||||||
=> [Errno] -- ^ errno to catch
|
|
||||||
-> e -- ^ rethrow as if errno matches
|
|
||||||
-> IO a -- ^ action to try
|
|
||||||
-> IO a
|
|
||||||
rethrowErrnoAs en fmex action = catchErrno en action (throwIO fmex)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- |Like `catchIOError`, with arguments swapped.
|
|
||||||
handleIOError :: (IOError -> IO a) -> IO a -> IO a
|
|
||||||
handleIOError = flip catchIOError
|
|
||||||
|
|
||||||
|
|
||||||
hideError :: IOErrorType -> IO () -> IO ()
|
|
||||||
hideError err = handleIO (\e -> if err == ioeGetErrorType e then pure () else ioError e)
|
|
||||||
|
|
||||||
|
|
||||||
-- |Like `bracket`, but allows to have different clean-up
|
|
||||||
-- actions depending on whether the in-between computation
|
|
||||||
-- has raised an exception or not.
|
|
||||||
bracketeer :: IO a -- ^ computation to run first
|
|
||||||
-> (a -> IO b) -- ^ computation to run last, when
|
|
||||||
-- no exception was raised
|
|
||||||
-> (a -> IO b) -- ^ computation to run last,
|
|
||||||
-- when an exception was raised
|
|
||||||
-> (a -> IO c) -- ^ computation to run in-between
|
|
||||||
-> IO c
|
|
||||||
bracketeer before after afterEx thing =
|
|
||||||
mask $ \restore -> do
|
|
||||||
a <- before
|
|
||||||
r <- restore (thing a) `onException` afterEx a
|
|
||||||
_ <- after a
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
reactOnError :: IO a
|
|
||||||
-> [(IOErrorType, IO a)] -- ^ reaction on IO errors
|
|
||||||
-> [(HPathIOException, IO a)] -- ^ reaction on HPathIOException
|
|
||||||
-> IO a
|
|
||||||
reactOnError a ios fmios =
|
|
||||||
a `catches` [iohandler, fmiohandler]
|
|
||||||
where
|
|
||||||
iohandler = Handler $
|
|
||||||
\(ex :: IOException) ->
|
|
||||||
foldr (\(t, a') y -> if ioeGetErrorType ex == t
|
|
||||||
then a'
|
|
||||||
else y)
|
|
||||||
(throwIO ex)
|
|
||||||
ios
|
|
||||||
fmiohandler = Handler $
|
|
||||||
\(ex :: HPathIOException) ->
|
|
||||||
foldr (\(t, a') y -> if toConstr ex == toConstr t
|
|
||||||
then a'
|
|
||||||
else y)
|
|
||||||
(throwIO ex)
|
|
||||||
fmios
|
|
||||||
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
import qualified Data.ByteString as BS
|
|
||||||
import Data.IORef
|
|
||||||
import Test.Hspec
|
|
||||||
import Test.Hspec.Runner
|
|
||||||
import Test.Hspec.Formatters
|
|
||||||
import qualified Spec
|
|
||||||
import Utils
|
|
||||||
import System.Posix.Temp.ByteString (mkdtemp)
|
|
||||||
import System.Posix.Env.ByteString (getEnvDefault)
|
|
||||||
import System.Posix.FilePath ((</>))
|
|
||||||
import "hpath-directory" System.Posix.RawFilePath.Directory
|
|
||||||
|
|
||||||
|
|
||||||
-- TODO: chardev, blockdev, namedpipe, socket
|
|
||||||
|
|
||||||
|
|
||||||
main :: IO ()
|
|
||||||
main = do
|
|
||||||
tmpdir <- getEnvDefault "TMPDIR" "/tmp" >>= canonicalizePath
|
|
||||||
tmpBase <- mkdtemp (tmpdir </> "hpath-directory")
|
|
||||||
writeIORef baseTmpDir (Just (tmpBase `BS.append` "/"))
|
|
||||||
putStrLn $ ("Temporary test directory at: " ++ show tmpBase)
|
|
||||||
hspecWith
|
|
||||||
defaultConfig { configFormatter = Just progress }
|
|
||||||
$ afterAll_ deleteBaseTmpDir
|
|
||||||
$ Spec.spec
|
|
@ -1,2 +0,0 @@
|
|||||||
-- file test/Spec.hs
|
|
||||||
{-# OPTIONS_GHC -F -pgmF hspec-discover -optF --module-name=Spec #-}
|
|
@ -1,108 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.AppendFileSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import Utils
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "AppendFileSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "fileWithContent"
|
|
||||||
createRegularFile' "fileWithoutContent"
|
|
||||||
createSymlink' "inputFileSymL" "fileWithContent"
|
|
||||||
createDir' "alreadyExistsD"
|
|
||||||
createRegularFile' "noPerms"
|
|
||||||
noPerms "noPerms"
|
|
||||||
createDir' "noPermsD"
|
|
||||||
createRegularFile' "noPermsD/inputFile"
|
|
||||||
noPerms "noPermsD"
|
|
||||||
writeFile' "fileWithContent" "BLKASL"
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
deleteFile' "fileWithContent"
|
|
||||||
deleteFile' "fileWithoutContent"
|
|
||||||
deleteFile' "inputFileSymL"
|
|
||||||
deleteDir' "alreadyExistsD"
|
|
||||||
normalFilePerms "noPerms"
|
|
||||||
deleteFile' "noPerms"
|
|
||||||
normalDirPerms "noPermsD"
|
|
||||||
deleteFile' "noPermsD/inputFile"
|
|
||||||
deleteDir' "noPermsD"
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.appendFile" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "appendFile file with content, everything clear" $ do
|
|
||||||
appendFile' "fileWithContent" "blahfaselllll"
|
|
||||||
out <- readFile' "fileWithContent"
|
|
||||||
out `shouldBe` "BLKASLblahfaselllll"
|
|
||||||
|
|
||||||
it "appendFile file with content, everything clear" $ do
|
|
||||||
appendFile' "fileWithContent" "gagagaga"
|
|
||||||
out <- readFile' "fileWithContent"
|
|
||||||
out `shouldBe` "BLKASLblahfaselllllgagagaga"
|
|
||||||
|
|
||||||
it "appendFile file with content, everything clear" $ do
|
|
||||||
appendFile' "fileWithContent" ""
|
|
||||||
out <- readFile' "fileWithContent"
|
|
||||||
out `shouldBe` "BLKASLblahfaselllllgagagaga"
|
|
||||||
|
|
||||||
it "appendFile file without content, everything clear" $ do
|
|
||||||
appendFile' "fileWithoutContent" "blahfaselllll"
|
|
||||||
out <- readFile' "fileWithoutContent"
|
|
||||||
out `shouldBe` "blahfaselllll"
|
|
||||||
|
|
||||||
it "appendFile, everything clear" $ do
|
|
||||||
appendFile' "fileWithoutContent" "gagagaga"
|
|
||||||
out <- readFile' "fileWithoutContent"
|
|
||||||
out `shouldBe` "blahfaselllllgagagaga"
|
|
||||||
|
|
||||||
it "appendFile symlink, everything clear" $ do
|
|
||||||
appendFile' "inputFileSymL" "blahfaselllll"
|
|
||||||
out <- readFile' "inputFileSymL"
|
|
||||||
out `shouldBe` "BLKASLblahfaselllllgagagagablahfaselllll"
|
|
||||||
|
|
||||||
it "appendFile symlink, everything clear" $ do
|
|
||||||
appendFile' "inputFileSymL" "gagagaga"
|
|
||||||
out <- readFile' "inputFileSymL"
|
|
||||||
out `shouldBe` "BLKASLblahfaselllllgagagagablahfaselllllgagagaga"
|
|
||||||
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "appendFile to dir, inappropriate type" $ do
|
|
||||||
appendFile' "alreadyExistsD" ""
|
|
||||||
`shouldThrow` (\e -> ioeGetErrorType e == InappropriateType)
|
|
||||||
|
|
||||||
it "appendFile, no permissions to file" $ do
|
|
||||||
appendFile' "noPerms" ""
|
|
||||||
`shouldThrow` (\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "appendFile, no permissions to file" $ do
|
|
||||||
appendFile' "noPermsD/inputFile" ""
|
|
||||||
`shouldThrow` (\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "appendFile, file does not exist" $ do
|
|
||||||
appendFile' "gaga" ""
|
|
||||||
`shouldThrow` (\e -> ioeGetErrorType e == NoSuchThing)
|
|
@ -1,78 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.CanonicalizePathSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import Utils
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "CanonicalizePathSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "file"
|
|
||||||
createDir' "dir"
|
|
||||||
createSymlink' "dirSym" "dir/"
|
|
||||||
createSymlink' "brokenSym" "nothing"
|
|
||||||
createSymlink' "fileSym" "file"
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
deleteFile' "file"
|
|
||||||
deleteDir' "dir"
|
|
||||||
deleteFile' "dirSym"
|
|
||||||
deleteFile' "brokenSym"
|
|
||||||
deleteFile' "fileSym"
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.canonicalizePath" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "canonicalizePath, all fine" $ do
|
|
||||||
path <- withTmpDir "file" return
|
|
||||||
canonicalizePath' "file"
|
|
||||||
`shouldReturn` path
|
|
||||||
|
|
||||||
it "canonicalizePath, all fine" $ do
|
|
||||||
path <- withTmpDir "dir" return
|
|
||||||
canonicalizePath' "dir"
|
|
||||||
`shouldReturn` path
|
|
||||||
|
|
||||||
it "canonicalizePath, all fine" $ do
|
|
||||||
path <- withTmpDir "file" return
|
|
||||||
canonicalizePath' "fileSym"
|
|
||||||
`shouldReturn` path
|
|
||||||
|
|
||||||
it "canonicalizePath, all fine" $ do
|
|
||||||
path <- withTmpDir "dir" return
|
|
||||||
canonicalizePath' "dirSym"
|
|
||||||
`shouldReturn` path
|
|
||||||
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "canonicalizePath, broken symlink" $
|
|
||||||
canonicalizePath' "brokenSym"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
it "canonicalizePath, file does not exist" $
|
|
||||||
canonicalizePath' "nothingBlah"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
@ -1,248 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.CopyDirRecursiveCollectFailuresSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import Data.List (sort)
|
|
||||||
import "hpath-directory" System.Posix.RawFilePath.Directory
|
|
||||||
import System.Posix.RawFilePath.Directory.Errors
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import System.Exit
|
|
||||||
import System.Process
|
|
||||||
import Utils
|
|
||||||
import qualified Data.ByteString as BS
|
|
||||||
import Data.ByteString.UTF8 (toString)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "CopyDirRecursiveCollectFailuresSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "alreadyExists"
|
|
||||||
createRegularFile' "wrongInput"
|
|
||||||
createSymlink' "wrongInputSymL" "inputDir/"
|
|
||||||
createDir' "alreadyExistsD"
|
|
||||||
createDir' "noPerms"
|
|
||||||
createDir' "noWritePerm"
|
|
||||||
|
|
||||||
createDir' "inputDir"
|
|
||||||
createDir' "inputDir/bar"
|
|
||||||
createDir' "inputDir/foo"
|
|
||||||
createRegularFile' "inputDir/foo/inputFile1"
|
|
||||||
createRegularFile' "inputDir/inputFile2"
|
|
||||||
createRegularFile' "inputDir/bar/inputFile3"
|
|
||||||
writeFile' "inputDir/foo/inputFile1" "SDAADSdsada"
|
|
||||||
writeFile' "inputDir/inputFile2" "Blahfaselgagaga"
|
|
||||||
writeFile' "inputDir/bar/inputFile3"
|
|
||||||
"fdfdssdffsd3223sasdasdasdadasasddasdasdasasd4"
|
|
||||||
|
|
||||||
createDir' "inputDir1"
|
|
||||||
createDir' "inputDir1/foo2"
|
|
||||||
createDir' "inputDir1/foo2/foo3"
|
|
||||||
createDir' "inputDir1/foo2/foo4"
|
|
||||||
createRegularFile' "inputDir1/foo2/inputFile1"
|
|
||||||
createRegularFile' "inputDir1/foo2/inputFile2"
|
|
||||||
createRegularFile' "inputDir1/foo2/inputFile3"
|
|
||||||
createRegularFile' "inputDir1/foo2/foo4/inputFile4"
|
|
||||||
createRegularFile' "inputDir1/foo2/foo4/inputFile6"
|
|
||||||
createRegularFile' "inputDir1/foo2/foo3/inputFile5"
|
|
||||||
noPerms "inputDir1/foo2/foo3"
|
|
||||||
|
|
||||||
createDir' "outputDir1"
|
|
||||||
createDir' "outputDir1/foo2"
|
|
||||||
createDir' "outputDir1/foo2/foo4"
|
|
||||||
createDir' "outputDir1/foo2/foo4/inputFile4"
|
|
||||||
createRegularFile' "outputDir1/foo2/foo4/inputFile6"
|
|
||||||
noPerms "outputDir1/foo2/foo4/inputFile4"
|
|
||||||
noPerms "outputDir1/foo2/foo4"
|
|
||||||
|
|
||||||
noPerms "noPerms"
|
|
||||||
noWritableDirPerms "noWritePerm"
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
normalDirPerms "noPerms"
|
|
||||||
normalDirPerms "noWritePerm"
|
|
||||||
|
|
||||||
normalDirPerms "inputDir1/foo2/foo3"
|
|
||||||
deleteFile' "inputDir1/foo2/foo4/inputFile4"
|
|
||||||
deleteFile' "inputDir1/foo2/foo4/inputFile6"
|
|
||||||
deleteFile' "inputDir1/foo2/inputFile1"
|
|
||||||
deleteFile' "inputDir1/foo2/inputFile2"
|
|
||||||
deleteFile' "inputDir1/foo2/inputFile3"
|
|
||||||
deleteFile' "inputDir1/foo2/foo3/inputFile5"
|
|
||||||
deleteDir' "inputDir1/foo2/foo3"
|
|
||||||
deleteDir' "inputDir1/foo2/foo4"
|
|
||||||
deleteDir' "inputDir1/foo2"
|
|
||||||
deleteDir' "inputDir1"
|
|
||||||
|
|
||||||
normalDirPerms "outputDir1/foo2/foo4"
|
|
||||||
normalDirPerms "outputDir1/foo2/foo4/inputFile4"
|
|
||||||
deleteFile' "outputDir1/foo2/foo4/inputFile6"
|
|
||||||
deleteDir' "outputDir1/foo2/foo4/inputFile4"
|
|
||||||
deleteDir' "outputDir1/foo2/foo4"
|
|
||||||
deleteDir' "outputDir1/foo2"
|
|
||||||
deleteDir' "outputDir1"
|
|
||||||
|
|
||||||
deleteFile' "alreadyExists"
|
|
||||||
deleteFile' "wrongInput"
|
|
||||||
deleteFile' "wrongInputSymL"
|
|
||||||
deleteDir' "alreadyExistsD"
|
|
||||||
deleteDir' "noPerms"
|
|
||||||
deleteDir' "noWritePerm"
|
|
||||||
deleteFile' "inputDir/foo/inputFile1"
|
|
||||||
deleteFile' "inputDir/inputFile2"
|
|
||||||
deleteFile' "inputDir/bar/inputFile3"
|
|
||||||
deleteDir' "inputDir/foo"
|
|
||||||
deleteDir' "inputDir/bar"
|
|
||||||
deleteDir' "inputDir"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.copyDirRecursive" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "copyDirRecursive (Strict, CollectFailures), all fine and compare" $ do
|
|
||||||
tmpDir' <- getRawTmpDir
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"outputDir"
|
|
||||||
Strict
|
|
||||||
CollectFailures
|
|
||||||
(system $ "diff -r "
|
|
||||||
++ toString tmpDir' ++ "inputDir" ++ " "
|
|
||||||
++ toString tmpDir' ++ "outputDir"
|
|
||||||
++ " >/dev/null")
|
|
||||||
`shouldReturn` ExitSuccess
|
|
||||||
removeDirIfExists "outputDir"
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "copyDirRecursive (Strict, CollectFailures), source directory does not exist" $
|
|
||||||
copyDirRecursive' "doesNotExist"
|
|
||||||
"outputDir"
|
|
||||||
Strict
|
|
||||||
CollectFailures
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
it "copyDirRecursive (Strict, CollectFailures), cannot open source dir" $
|
|
||||||
copyDirRecursive' "noPerms/inputDir"
|
|
||||||
"foo"
|
|
||||||
Strict
|
|
||||||
CollectFailures
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
|
|
||||||
-- custom failures
|
|
||||||
it "copyDirRecursive (Overwrite, CollectFailures), various failures" $ do
|
|
||||||
copyDirRecursive' "inputDir1/foo2"
|
|
||||||
"outputDir1/foo2"
|
|
||||||
Overwrite
|
|
||||||
CollectFailures
|
|
||||||
`shouldThrow`
|
|
||||||
(\(RecursiveFailure ex@[_, _]) ->
|
|
||||||
any (\(h, e) -> ioeGetErrorType e == InappropriateType
|
|
||||||
&& isCopyFileFailed h) ex &&
|
|
||||||
any (\(h, e) -> ioeGetErrorType e == PermissionDenied
|
|
||||||
&& isReadContentsFailed h) ex)
|
|
||||||
normalDirPerms "outputDir1/foo2/foo4"
|
|
||||||
normalDirPerms "outputDir1/foo2/foo4/inputFile4"
|
|
||||||
c <- allDirectoryContents' "outputDir1"
|
|
||||||
tmpDir' <- getRawTmpDir
|
|
||||||
let shouldC = (fmap (\x -> tmpDir' `BS.append` x)
|
|
||||||
["outputDir1"
|
|
||||||
,"outputDir1/foo2"
|
|
||||||
,"outputDir1/foo2/inputFile1"
|
|
||||||
,"outputDir1/foo2/inputFile2"
|
|
||||||
,"outputDir1/foo2/inputFile3"
|
|
||||||
,"outputDir1/foo2/foo4"
|
|
||||||
,"outputDir1/foo2/foo4/inputFile6"
|
|
||||||
,"outputDir1/foo2/foo4/inputFile4"])
|
|
||||||
deleteFile' "outputDir1/foo2/inputFile1"
|
|
||||||
deleteFile' "outputDir1/foo2/inputFile2"
|
|
||||||
deleteFile' "outputDir1/foo2/inputFile3"
|
|
||||||
sort c `shouldBe` sort shouldC
|
|
||||||
|
|
||||||
|
|
||||||
it "copyDirRecursive (Strict, CollectFailures), no write permission on output dir" $
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"noWritePerm/foo"
|
|
||||||
Strict
|
|
||||||
CollectFailures
|
|
||||||
`shouldThrow`
|
|
||||||
(\(RecursiveFailure [(CreateDirFailed{}, e)]) -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "copyDirRecursive (Strict, CollectFailures), cannot open output dir" $
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"noPerms/foo"
|
|
||||||
Strict
|
|
||||||
CollectFailures
|
|
||||||
`shouldThrow`
|
|
||||||
isRecursiveFailure
|
|
||||||
|
|
||||||
it "copyDirRecursive (Strict, CollectFailures), destination dir already exists" $
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"alreadyExistsD"
|
|
||||||
Strict
|
|
||||||
CollectFailures
|
|
||||||
`shouldThrow`
|
|
||||||
(\(RecursiveFailure [(CreateDirFailed{}, e)]) -> ioeGetErrorType e == AlreadyExists)
|
|
||||||
|
|
||||||
it "copyDirRecursive (Strict, CollectFailures), destination already exists and is a file" $
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"alreadyExists"
|
|
||||||
Strict
|
|
||||||
CollectFailures
|
|
||||||
`shouldThrow`
|
|
||||||
isRecursiveFailure
|
|
||||||
|
|
||||||
it "copyDirRecursive (Strict, CollectFailures), wrong input (regular file)" $
|
|
||||||
copyDirRecursive' "wrongInput"
|
|
||||||
"outputDir"
|
|
||||||
Strict
|
|
||||||
CollectFailures
|
|
||||||
`shouldThrow`
|
|
||||||
(\(RecursiveFailure [(ReadContentsFailed{}, e)]) -> ioeGetErrorType e == InappropriateType)
|
|
||||||
|
|
||||||
it "copyDirRecursive (Strict, CollectFailures), wrong input (symlink to directory)" $
|
|
||||||
copyDirRecursive' "wrongInputSymL"
|
|
||||||
"outputDir"
|
|
||||||
Strict
|
|
||||||
CollectFailures
|
|
||||||
`shouldThrow`
|
|
||||||
(\(RecursiveFailure [(ReadContentsFailed{}, e)]) -> ioeGetErrorType e == InvalidArgument)
|
|
||||||
|
|
||||||
it "copyDirRecursive (Strict, CollectFailures), destination in source" $
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"inputDir/foo"
|
|
||||||
Strict
|
|
||||||
CollectFailures
|
|
||||||
`shouldThrow`
|
|
||||||
isDestinationInSource
|
|
||||||
|
|
||||||
it "copyDirRecursive (Strict, CollectFailures), destination and source same directory" $
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"inputDir"
|
|
||||||
Strict
|
|
||||||
CollectFailures
|
|
||||||
`shouldThrow`
|
|
||||||
isSameFile
|
|
||||||
|
|
||||||
|
|
@ -1,205 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.CopyDirRecursiveOverwriteSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import "hpath-directory" System.Posix.RawFilePath.Directory
|
|
||||||
import System.Posix.RawFilePath.Directory.Errors
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import System.Exit
|
|
||||||
import System.Process
|
|
||||||
import Utils
|
|
||||||
import Data.ByteString.UTF8 (toString)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "CopyDirRecursiveOverwriteSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "alreadyExists"
|
|
||||||
createRegularFile' "wrongInput"
|
|
||||||
createSymlink' "wrongInputSymL" "inputDir/"
|
|
||||||
createDir' "noPerms"
|
|
||||||
createDir' "noWritePerm"
|
|
||||||
|
|
||||||
createDir' "inputDir"
|
|
||||||
createDir' "inputDir/bar"
|
|
||||||
createDir' "inputDir/foo"
|
|
||||||
createRegularFile' "inputDir/foo/inputFile1"
|
|
||||||
createRegularFile' "inputDir/inputFile2"
|
|
||||||
createRegularFile' "inputDir/bar/inputFile3"
|
|
||||||
writeFile' "inputDir/foo/inputFile1" "SDAADSdsada"
|
|
||||||
writeFile' "inputDir/inputFile2" "Blahfaselgagaga"
|
|
||||||
writeFile' "inputDir/bar/inputFile3"
|
|
||||||
"fdfdssdffsd3223sasdasdasdadasasddasdasdasasd4"
|
|
||||||
|
|
||||||
createDir' "alreadyExistsD"
|
|
||||||
createDir' "alreadyExistsD/bar"
|
|
||||||
createDir' "alreadyExistsD/foo"
|
|
||||||
createRegularFile' "alreadyExistsD/foo/inputFile1"
|
|
||||||
createRegularFile' "alreadyExistsD/inputFile2"
|
|
||||||
createRegularFile' "alreadyExistsD/bar/inputFile3"
|
|
||||||
writeFile' "alreadyExistsD/foo/inputFile1" "DAAsada"
|
|
||||||
writeFile' "alreadyExistsD/inputFile2" "ahfaagaga"
|
|
||||||
writeFile' "alreadyExistsD/bar/inputFile3"
|
|
||||||
"f3223sasdasdaasdasdasasd4"
|
|
||||||
|
|
||||||
noPerms "noPerms"
|
|
||||||
noWritableDirPerms "noWritePerm"
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
normalDirPerms "noPerms"
|
|
||||||
normalDirPerms "noWritePerm"
|
|
||||||
deleteFile' "alreadyExists"
|
|
||||||
deleteFile' "wrongInput"
|
|
||||||
deleteFile' "wrongInputSymL"
|
|
||||||
deleteDir' "noPerms"
|
|
||||||
deleteDir' "noWritePerm"
|
|
||||||
deleteFile' "inputDir/foo/inputFile1"
|
|
||||||
deleteFile' "inputDir/inputFile2"
|
|
||||||
deleteFile' "inputDir/bar/inputFile3"
|
|
||||||
deleteDir' "inputDir/foo"
|
|
||||||
deleteDir' "inputDir/bar"
|
|
||||||
deleteDir' "inputDir"
|
|
||||||
deleteFile' "alreadyExistsD/foo/inputFile1"
|
|
||||||
deleteFile' "alreadyExistsD/inputFile2"
|
|
||||||
deleteFile' "alreadyExistsD/bar/inputFile3"
|
|
||||||
deleteDir' "alreadyExistsD/foo"
|
|
||||||
deleteDir' "alreadyExistsD/bar"
|
|
||||||
deleteDir' "alreadyExistsD"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.copyDirRecursive" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "copyDirRecursive (Overwrite, FailEarly), all fine" $ do
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"outputDir"
|
|
||||||
Overwrite
|
|
||||||
FailEarly
|
|
||||||
removeDirIfExists "outputDir"
|
|
||||||
|
|
||||||
it "copyDirRecursive (Overwrite, FailEarly), all fine and compare" $ do
|
|
||||||
tmpDir' <- getRawTmpDir
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"outputDir"
|
|
||||||
Overwrite
|
|
||||||
FailEarly
|
|
||||||
(system $ "diff -r "
|
|
||||||
++ toString tmpDir' ++ "inputDir" ++ " "
|
|
||||||
++ toString tmpDir' ++ "outputDir"
|
|
||||||
++ " >/dev/null")
|
|
||||||
`shouldReturn` ExitSuccess
|
|
||||||
removeDirIfExists "outputDir"
|
|
||||||
|
|
||||||
it "copyDirRecursive (Overwrite, FailEarly), destination dir already exists" $ do
|
|
||||||
tmpDir' <- getRawTmpDir
|
|
||||||
(system $ "diff -r "
|
|
||||||
++ toString tmpDir' ++ "inputDir" ++ " "
|
|
||||||
++ toString tmpDir' ++ "alreadyExistsD"
|
|
||||||
++ " >/dev/null")
|
|
||||||
`shouldReturn` (ExitFailure 1)
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"alreadyExistsD"
|
|
||||||
Overwrite
|
|
||||||
FailEarly
|
|
||||||
(system $ "diff -r "
|
|
||||||
++ toString tmpDir' ++ "inputDir" ++ " "
|
|
||||||
++ toString tmpDir' ++ "alreadyExistsD"
|
|
||||||
++ " >/dev/null")
|
|
||||||
`shouldReturn` ExitSuccess
|
|
||||||
removeDirIfExists "outputDir"
|
|
||||||
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "copyDirRecursive, source directory does not exist" $
|
|
||||||
copyDirRecursive' "doesNotExist"
|
|
||||||
"outputDir"
|
|
||||||
Overwrite
|
|
||||||
FailEarly
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
it "copyDirRecursive, no write permission on output dir" $
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"noWritePerm/foo"
|
|
||||||
Overwrite
|
|
||||||
FailEarly
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "copyDirRecursive, cannot open output dir" $
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"noPerms/foo"
|
|
||||||
Overwrite
|
|
||||||
FailEarly
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "copyDirRecursive, cannot open source dir" $
|
|
||||||
copyDirRecursive' "noPerms/inputDir"
|
|
||||||
"foo"
|
|
||||||
Overwrite
|
|
||||||
FailEarly
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "copyDirRecursive, destination already exists and is a file" $
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"alreadyExists"
|
|
||||||
Overwrite
|
|
||||||
FailEarly
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InappropriateType)
|
|
||||||
|
|
||||||
it "copyDirRecursive, wrong input (regular file)" $
|
|
||||||
copyDirRecursive' "wrongInput"
|
|
||||||
"outputDir"
|
|
||||||
Overwrite
|
|
||||||
FailEarly
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InappropriateType)
|
|
||||||
|
|
||||||
it "copyDirRecursive, wrong input (symlink to directory)" $
|
|
||||||
copyDirRecursive' "wrongInputSymL"
|
|
||||||
"outputDir"
|
|
||||||
Overwrite
|
|
||||||
FailEarly
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InvalidArgument)
|
|
||||||
|
|
||||||
-- custom failures
|
|
||||||
it "copyDirRecursive (Overwrite, FailEarly), destination in source" $
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"inputDir/foo"
|
|
||||||
Overwrite
|
|
||||||
FailEarly
|
|
||||||
`shouldThrow`
|
|
||||||
isDestinationInSource
|
|
||||||
|
|
||||||
it "copyDirRecursive (Overwrite, FailEarly), destination and source same directory" $
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"inputDir"
|
|
||||||
Overwrite
|
|
||||||
FailEarly
|
|
||||||
`shouldThrow`
|
|
||||||
isSameFile
|
|
@ -1,181 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.CopyDirRecursiveSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import "hpath-directory" System.Posix.RawFilePath.Directory
|
|
||||||
import System.Posix.RawFilePath.Directory.Errors
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import System.Exit
|
|
||||||
import System.Process
|
|
||||||
import Utils
|
|
||||||
import Data.ByteString.UTF8 (toString)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "CopyDirRecursiveSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "alreadyExists"
|
|
||||||
createRegularFile' "wrongInput"
|
|
||||||
createSymlink' "wrongInputSymL" "inputDir/"
|
|
||||||
createDir' "alreadyExistsD"
|
|
||||||
createDir' "noPerms"
|
|
||||||
createDir' "noWritePerm"
|
|
||||||
|
|
||||||
createDir' "inputDir"
|
|
||||||
createDir' "inputDir/bar"
|
|
||||||
createDir' "inputDir/foo"
|
|
||||||
createRegularFile' "inputDir/foo/inputFile1"
|
|
||||||
createRegularFile' "inputDir/inputFile2"
|
|
||||||
createRegularFile' "inputDir/bar/inputFile3"
|
|
||||||
writeFile' "inputDir/foo/inputFile1" "SDAADSdsada"
|
|
||||||
writeFile' "inputDir/inputFile2" "Blahfaselgagaga"
|
|
||||||
writeFile' "inputDir/bar/inputFile3"
|
|
||||||
"fdfdssdffsd3223sasdasdasdadasasddasdasdasasd4"
|
|
||||||
|
|
||||||
noPerms "noPerms"
|
|
||||||
noWritableDirPerms "noWritePerm"
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
normalDirPerms "noPerms"
|
|
||||||
normalDirPerms "noWritePerm"
|
|
||||||
deleteFile' "alreadyExists"
|
|
||||||
deleteFile' "wrongInput"
|
|
||||||
deleteFile' "wrongInputSymL"
|
|
||||||
deleteDir' "alreadyExistsD"
|
|
||||||
deleteDir' "noPerms"
|
|
||||||
deleteDir' "noWritePerm"
|
|
||||||
deleteFile' "inputDir/foo/inputFile1"
|
|
||||||
deleteFile' "inputDir/inputFile2"
|
|
||||||
deleteFile' "inputDir/bar/inputFile3"
|
|
||||||
deleteDir' "inputDir/foo"
|
|
||||||
deleteDir' "inputDir/bar"
|
|
||||||
deleteDir' "inputDir"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.copyDirRecursive" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "copyDirRecursive (Strict, FailEarly), all fine" $ do
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"outputDir"
|
|
||||||
Strict
|
|
||||||
FailEarly
|
|
||||||
removeDirIfExists "outputDir"
|
|
||||||
|
|
||||||
it "copyDirRecursive (Strict, FailEarly), all fine and compare" $ do
|
|
||||||
tmpDir' <- getRawTmpDir
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"outputDir"
|
|
||||||
Strict
|
|
||||||
FailEarly
|
|
||||||
(system $ "diff -r "
|
|
||||||
++ toString tmpDir' ++ "inputDir" ++ " "
|
|
||||||
++ toString tmpDir' ++ "outputDir"
|
|
||||||
++ " >/dev/null")
|
|
||||||
`shouldReturn` ExitSuccess
|
|
||||||
removeDirIfExists "outputDir"
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "copyDirRecursive (Strict, FailEarly), source directory does not exist" $
|
|
||||||
copyDirRecursive' "doesNotExist"
|
|
||||||
"outputDir"
|
|
||||||
Strict
|
|
||||||
FailEarly
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
it "copyDirRecursive (Strict, FailEarly), no write permission on output dir" $
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"noWritePerm/foo"
|
|
||||||
Strict
|
|
||||||
FailEarly
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "copyDirRecursive (Strict, FailEarly), cannot open output dir" $
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"noPerms/foo"
|
|
||||||
Strict
|
|
||||||
FailEarly
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "copyDirRecursive (Strict, FailEarly), cannot open source dir" $
|
|
||||||
copyDirRecursive' "noPerms/inputDir"
|
|
||||||
"foo"
|
|
||||||
Strict
|
|
||||||
FailEarly
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "copyDirRecursive (Strict, FailEarly), destination dir already exists" $
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"alreadyExistsD"
|
|
||||||
Strict
|
|
||||||
FailEarly
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == AlreadyExists)
|
|
||||||
|
|
||||||
it "copyDirRecursive (Strict, FailEarly), destination already exists and is a file" $
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"alreadyExists"
|
|
||||||
Strict
|
|
||||||
FailEarly
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == AlreadyExists)
|
|
||||||
|
|
||||||
it "copyDirRecursive (Strict, FailEarly), wrong input (regular file)" $
|
|
||||||
copyDirRecursive' "wrongInput"
|
|
||||||
"outputDir"
|
|
||||||
Strict
|
|
||||||
FailEarly
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InappropriateType)
|
|
||||||
|
|
||||||
it "copyDirRecursive (Strict, FailEarly), wrong input (symlink to directory)" $
|
|
||||||
copyDirRecursive' "wrongInputSymL"
|
|
||||||
"outputDir"
|
|
||||||
Strict
|
|
||||||
FailEarly
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InvalidArgument)
|
|
||||||
|
|
||||||
-- custom failures
|
|
||||||
it "copyDirRecursive (Strict, FailEarly), destination in source" $
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"inputDir/foo"
|
|
||||||
Strict
|
|
||||||
FailEarly
|
|
||||||
`shouldThrow`
|
|
||||||
isDestinationInSource
|
|
||||||
|
|
||||||
it "copyDirRecursive (Strict, FailEarly), destination and source same directory" $
|
|
||||||
copyDirRecursive' "inputDir"
|
|
||||||
"inputDir"
|
|
||||||
Strict
|
|
||||||
FailEarly
|
|
||||||
`shouldThrow`
|
|
||||||
isSameFile
|
|
||||||
|
|
||||||
|
|
@ -1,148 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.CopyFileOverwriteSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import "hpath-directory" System.Posix.RawFilePath.Directory
|
|
||||||
import System.Posix.RawFilePath.Directory.Errors
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import System.Exit
|
|
||||||
import System.Process
|
|
||||||
import Utils
|
|
||||||
import Data.ByteString.UTF8 (toString)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "CopyFileOverwriteSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "inputFile"
|
|
||||||
createRegularFile' "alreadyExists"
|
|
||||||
createSymlink' "inputFileSymL" "inputFile"
|
|
||||||
createDir' "alreadyExistsD"
|
|
||||||
createDir' "noPerms"
|
|
||||||
createRegularFile' "noPerms/inputFile"
|
|
||||||
createDir' "outputDirNoWrite"
|
|
||||||
createDir' "wrongInput"
|
|
||||||
noPerms "noPerms"
|
|
||||||
noWritableDirPerms "outputDirNoWrite"
|
|
||||||
writeFile' "inputFile" "Blahfaselgagaga"
|
|
||||||
writeFile' "alreadyExists" "dsaldsalkaklsdlkasksdadasl"
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
normalDirPerms "noPerms"
|
|
||||||
normalDirPerms "outputDirNoWrite"
|
|
||||||
deleteFile' "noPerms/inputFile"
|
|
||||||
deleteFile' "inputFile"
|
|
||||||
deleteFile' "alreadyExists"
|
|
||||||
deleteFile' "inputFileSymL"
|
|
||||||
deleteDir' "alreadyExistsD"
|
|
||||||
deleteDir' "noPerms"
|
|
||||||
deleteDir' "outputDirNoWrite"
|
|
||||||
deleteDir' "wrongInput"
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.copyFile" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "copyFile (Overwrite), everything clear" $ do
|
|
||||||
copyFile' "inputFile"
|
|
||||||
"outputFile"
|
|
||||||
Overwrite
|
|
||||||
removeFileIfExists "outputFile"
|
|
||||||
|
|
||||||
it "copyFile (Overwrite), output file already exists, all clear" $ do
|
|
||||||
tmpDir' <- getRawTmpDir
|
|
||||||
copyFile' "alreadyExists" "alreadyExists.bak" Strict
|
|
||||||
copyFile' "inputFile" "alreadyExists" Overwrite
|
|
||||||
(system $ "cmp -s " ++ toString tmpDir' ++ "inputFile" ++ " "
|
|
||||||
++ toString tmpDir' ++ "alreadyExists")
|
|
||||||
`shouldReturn` ExitSuccess
|
|
||||||
removeFileIfExists "alreadyExists"
|
|
||||||
copyFile' "alreadyExists.bak" "alreadyExists" Strict
|
|
||||||
removeFileIfExists "alreadyExists.bak"
|
|
||||||
|
|
||||||
it "copyFile (Overwrite), and compare" $ do
|
|
||||||
tmpDir' <- getRawTmpDir
|
|
||||||
copyFile' "inputFile"
|
|
||||||
"outputFile"
|
|
||||||
Overwrite
|
|
||||||
(system $ "cmp -s " ++ toString tmpDir' ++ "inputFile" ++ " "
|
|
||||||
++ toString tmpDir' ++ "outputFile")
|
|
||||||
`shouldReturn` ExitSuccess
|
|
||||||
removeFileIfExists "outputFile"
|
|
||||||
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "copyFile (Overwrite), input file does not exist" $
|
|
||||||
copyFile' "noSuchFile"
|
|
||||||
"outputFile"
|
|
||||||
Overwrite
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
it "copyFile (Overwrite), no permission to write to output directory" $
|
|
||||||
copyFile' "inputFile"
|
|
||||||
"outputDirNoWrite/outputFile"
|
|
||||||
Overwrite
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "copyFile (Overwrite), cannot open output directory" $
|
|
||||||
copyFile' "inputFile"
|
|
||||||
"noPerms/outputFile"
|
|
||||||
Overwrite
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "copyFile (Overwrite), cannot open source directory" $
|
|
||||||
copyFile' "noPerms/inputFile"
|
|
||||||
"outputFile"
|
|
||||||
Overwrite
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "copyFile (Overwrite), wrong input type (symlink)" $
|
|
||||||
copyFile' "inputFileSymL"
|
|
||||||
"outputFile"
|
|
||||||
Overwrite
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InvalidArgument)
|
|
||||||
|
|
||||||
it "copyFile (Overwrite), wrong input type (directory)" $
|
|
||||||
copyFile' "wrongInput"
|
|
||||||
"outputFile"
|
|
||||||
Overwrite
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InappropriateType)
|
|
||||||
|
|
||||||
it "copyFile (Overwrite), output file already exists and is a dir" $
|
|
||||||
copyFile' "inputFile"
|
|
||||||
"alreadyExistsD"
|
|
||||||
Overwrite
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InappropriateType)
|
|
||||||
|
|
||||||
-- custom failures --
|
|
||||||
it "copyFile (Overwrite), output and input are same file" $
|
|
||||||
copyFile' "inputFile"
|
|
||||||
"inputFile"
|
|
||||||
Overwrite
|
|
||||||
`shouldThrow` isSameFile
|
|
@ -1,143 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.CopyFileSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import "hpath-directory" System.Posix.RawFilePath.Directory
|
|
||||||
import System.Posix.RawFilePath.Directory.Errors
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import System.Exit
|
|
||||||
import System.Process
|
|
||||||
import Utils
|
|
||||||
import Data.ByteString.UTF8 (toString)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "CopyFileSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "inputFile"
|
|
||||||
createRegularFile' "alreadyExists"
|
|
||||||
createSymlink' "inputFileSymL" "inputFile"
|
|
||||||
createDir' "alreadyExistsD"
|
|
||||||
createDir' "noPerms"
|
|
||||||
createRegularFile' "noPerms/inputFile"
|
|
||||||
createDir' "outputDirNoWrite"
|
|
||||||
createDir' "wrongInput"
|
|
||||||
noPerms "noPerms"
|
|
||||||
noWritableDirPerms "outputDirNoWrite"
|
|
||||||
writeFile' "inputFile" "Blahfaselgagaga"
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
normalDirPerms "noPerms"
|
|
||||||
normalDirPerms "outputDirNoWrite"
|
|
||||||
deleteFile' "noPerms/inputFile"
|
|
||||||
deleteFile' "inputFile"
|
|
||||||
deleteFile' "alreadyExists"
|
|
||||||
deleteFile' "inputFileSymL"
|
|
||||||
deleteDir' "alreadyExistsD"
|
|
||||||
deleteDir' "noPerms"
|
|
||||||
deleteDir' "outputDirNoWrite"
|
|
||||||
deleteDir' "wrongInput"
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.copyFile" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "copyFile (Strict), everything clear" $ do
|
|
||||||
copyFile' "inputFile"
|
|
||||||
"outputFile"
|
|
||||||
Strict
|
|
||||||
removeFileIfExists "outputFile"
|
|
||||||
|
|
||||||
it "copyFile (Strict), and compare" $ do
|
|
||||||
tmpDir' <- getRawTmpDir
|
|
||||||
copyFile' "inputFile"
|
|
||||||
"outputFile"
|
|
||||||
Strict
|
|
||||||
(system $ "cmp -s " ++ toString tmpDir' ++ "inputFile" ++ " "
|
|
||||||
++ toString tmpDir' ++ "outputFile")
|
|
||||||
`shouldReturn` ExitSuccess
|
|
||||||
removeFileIfExists "outputFile"
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "copyFile (Strict), input file does not exist" $
|
|
||||||
copyFile' "noSuchFile"
|
|
||||||
"outputFile"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
it "copyFile (Strict), no permission to write to output directory" $
|
|
||||||
copyFile' "inputFile"
|
|
||||||
"outputDirNoWrite/outputFile"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "copyFile (Strict), cannot open output directory" $
|
|
||||||
copyFile' "inputFile"
|
|
||||||
"noPerms/outputFile"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "copyFile (Strict), cannot open source directory" $
|
|
||||||
copyFile' "noPerms/inputFile"
|
|
||||||
"outputFile"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "copyFile (Strict), wrong input type (symlink)" $
|
|
||||||
copyFile' "inputFileSymL"
|
|
||||||
"outputFile"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InvalidArgument)
|
|
||||||
|
|
||||||
it "copyFile (Strict), wrong input type (directory)" $
|
|
||||||
copyFile' "wrongInput"
|
|
||||||
"outputFile"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InappropriateType)
|
|
||||||
|
|
||||||
it "copyFile (Strict), output file already exists" $
|
|
||||||
copyFile' "inputFile"
|
|
||||||
"alreadyExists"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == AlreadyExists)
|
|
||||||
|
|
||||||
it "copyFile (Strict), output file already exists and is a dir" $
|
|
||||||
copyFile' "inputFile"
|
|
||||||
"alreadyExistsD"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == AlreadyExists)
|
|
||||||
|
|
||||||
-- custom failures --
|
|
||||||
it "copyFile (Strict), output and input are same file" $
|
|
||||||
copyFile' "inputFile"
|
|
||||||
"inputFile"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
isSameFile
|
|
@ -1,69 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.CreateDirIfMissingSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import Utils
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "CreateDirIfMissingSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createDir' "alreadyExists"
|
|
||||||
createDir' "noPerms"
|
|
||||||
createDir' "noWritePerms"
|
|
||||||
noPerms "noPerms"
|
|
||||||
noWritableDirPerms "noWritePerms"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
normalDirPerms "noPerms"
|
|
||||||
normalDirPerms "noWritePerms"
|
|
||||||
deleteDir' "alreadyExists"
|
|
||||||
deleteDir' "noPerms"
|
|
||||||
deleteDir' "noWritePerms"
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.CreateDirIfMissing" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "createDirIfMissing, all fine" $ do
|
|
||||||
createDirIfMissing' "newDir"
|
|
||||||
removeDirIfExists "newDir"
|
|
||||||
|
|
||||||
it "createDirIfMissing, destination directory already exists" $
|
|
||||||
createDirIfMissing' "alreadyExists"
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "createDirIfMissing, parent directories do not exist" $
|
|
||||||
createDirIfMissing' "some/thing/dada"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
it "createDirIfMissing, can't write to output directory" $
|
|
||||||
createDirIfMissing' "noWritePerms/newDir"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "createDirIfMissing, can't open output directory" $
|
|
||||||
createDirIfMissing' "noPerms/newDir"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
@ -1,83 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.CreateDirRecursiveSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import Utils
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "CreateDirRecursiveSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createDir' "alreadyExists"
|
|
||||||
createRegularFile' "alreadyExistsF"
|
|
||||||
createDir' "noPerms"
|
|
||||||
createDir' "noWritePerms"
|
|
||||||
noPerms "noPerms"
|
|
||||||
noWritableDirPerms "noWritePerms"
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
normalDirPerms "noPerms"
|
|
||||||
normalDirPerms "noWritePerms"
|
|
||||||
deleteDir' "alreadyExists"
|
|
||||||
deleteDir' "noPerms"
|
|
||||||
deleteDir' "noWritePerms"
|
|
||||||
deleteFile' "alreadyExistsF"
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.createDirRecursive" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "createDirRecursive, all fine" $ do
|
|
||||||
createDirRecursive' "newDir"
|
|
||||||
deleteDir' "newDir"
|
|
||||||
|
|
||||||
it "createDirRecursive with trailing path separator, all fine" $ do
|
|
||||||
createDirRecursive' "newDir/foo/"
|
|
||||||
deleteDir' "newDir/foo"
|
|
||||||
deleteDir' "newDir"
|
|
||||||
|
|
||||||
it "createDirRecursive, parent directories do not exist" $ do
|
|
||||||
createDirRecursive' "some/thing/dada"
|
|
||||||
deleteDir' "some/thing/dada"
|
|
||||||
deleteDir' "some/thing"
|
|
||||||
deleteDir' "some"
|
|
||||||
|
|
||||||
it "createDirRecursive, destination directory already exists" $
|
|
||||||
createDirRecursive' "alreadyExists"
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "createDirRecursive, destination already exists and is a file" $
|
|
||||||
createDirRecursive' "alreadyExistsF"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == AlreadyExists)
|
|
||||||
|
|
||||||
it "createDirRecursive, can't write to output directory" $
|
|
||||||
createDirRecursive' "noWritePerms/newDir"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "createDirRecursive, can't open output directory" $
|
|
||||||
createDirRecursive' "noPerms/newDir"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.CreateDirSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import Utils
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "CreateDirSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createDir' "alreadyExists"
|
|
||||||
createDir' "noPerms"
|
|
||||||
createDir' "noWritePerms"
|
|
||||||
noPerms "noPerms"
|
|
||||||
noWritableDirPerms "noWritePerms"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
normalDirPerms "noPerms"
|
|
||||||
normalDirPerms "noWritePerms"
|
|
||||||
deleteDir' "alreadyExists"
|
|
||||||
deleteDir' "noPerms"
|
|
||||||
deleteDir' "noWritePerms"
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.createDir" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "createDir, all fine" $ do
|
|
||||||
createDir' "newDir"
|
|
||||||
removeDirIfExists "newDir"
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "createDir, parent directories do not exist" $
|
|
||||||
createDir' "some/thing/dada"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
it "createDir, can't write to output directory" $
|
|
||||||
createDir' "noWritePerms/newDir"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "createDir, can't open output directory" $
|
|
||||||
createDir' "noPerms/newDir"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "createDir, destination directory already exists" $
|
|
||||||
createDir' "alreadyExists"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == AlreadyExists)
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.CreateRegularFileSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import Utils
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "CreateRegularFileSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "alreadyExists"
|
|
||||||
createDir' "noPerms"
|
|
||||||
createDir' "noWritePerms"
|
|
||||||
noPerms "noPerms"
|
|
||||||
noWritableDirPerms "noWritePerms"
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
normalDirPerms "noPerms"
|
|
||||||
normalDirPerms "noWritePerms"
|
|
||||||
deleteFile' "alreadyExists"
|
|
||||||
deleteDir' "noPerms"
|
|
||||||
deleteDir' "noWritePerms"
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.createRegularFile" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "createRegularFile, all fine" $ do
|
|
||||||
createRegularFile' "newDir"
|
|
||||||
removeFileIfExists "newDir"
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "createRegularFile, parent directories do not exist" $
|
|
||||||
createRegularFile' "some/thing/dada"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
it "createRegularFile, can't write to destination directory" $
|
|
||||||
createRegularFile' "noWritePerms/newDir"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "createRegularFile, can't write to destination directory" $
|
|
||||||
createRegularFile' "noPerms/newDir"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "createRegularFile, destination file already exists" $
|
|
||||||
createRegularFile' "alreadyExists"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == AlreadyExists)
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.CreateSymlinkSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import Utils
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "CreateSymlinkSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "alreadyExists"
|
|
||||||
createDir' "noPerms"
|
|
||||||
createDir' "noWritePerms"
|
|
||||||
noPerms "noPerms"
|
|
||||||
noWritableDirPerms "noWritePerms"
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
normalDirPerms "noPerms"
|
|
||||||
normalDirPerms "noWritePerms"
|
|
||||||
deleteFile' "alreadyExists"
|
|
||||||
deleteDir' "noPerms"
|
|
||||||
deleteDir' "noWritePerms"
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.createSymlink" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "createSymlink, all fine" $ do
|
|
||||||
createSymlink' "newSymL" "alreadyExists/"
|
|
||||||
removeFileIfExists "newSymL"
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "createSymlink, parent directories do not exist" $
|
|
||||||
createSymlink' "some/thing/dada" "lala"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
it "createSymlink, can't write to destination directory" $
|
|
||||||
createSymlink' "noWritePerms/newDir" "lala"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "createSymlink, can't write to destination directory" $
|
|
||||||
createSymlink' "noPerms/newDir" "lala"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "createSymlink, destination file already exists" $
|
|
||||||
createSymlink' "alreadyExists" "lala"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == AlreadyExists)
|
|
||||||
|
|
@ -1,116 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.DeleteDirRecursiveSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import System.Posix.Files.ByteString
|
|
||||||
(
|
|
||||||
getSymbolicLinkStatus
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import Utils
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "DeleteDirRecursiveSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "file"
|
|
||||||
createDir' "dir"
|
|
||||||
createRegularFile' "dir/.keep"
|
|
||||||
createSymlink' "dirSym" "dir/"
|
|
||||||
createDir' "noPerms"
|
|
||||||
createRegularFile' "noPerms/.keep"
|
|
||||||
createDir' "noWritable"
|
|
||||||
createRegularFile' "noWritable/.keep"
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
deleteFile' "file"
|
|
||||||
deleteFile' "dir/.keep"
|
|
||||||
deleteDir' "dir"
|
|
||||||
deleteFile' "dirSym"
|
|
||||||
deleteFile' "noPerms/.keep"
|
|
||||||
deleteDir' "noPerms"
|
|
||||||
deleteFile' "noWritable/.keep"
|
|
||||||
deleteDir' "noWritable"
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.deleteDirRecursive" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "deleteDirRecursive, empty directory, all fine" $ do
|
|
||||||
createDir' "testDir"
|
|
||||||
deleteDirRecursive' "testDir"
|
|
||||||
getSymbolicLinkStatus "testDir"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
it "deleteDirRecursive, empty directory with null permissions, all fine" $ do
|
|
||||||
createDir' "noPerms/testDir"
|
|
||||||
noPerms "noPerms/testDir"
|
|
||||||
deleteDirRecursive' "noPerms/testDir"
|
|
||||||
|
|
||||||
it "deleteDirRecursive, non-empty directory, all fine" $ do
|
|
||||||
createDir' "nonEmpty"
|
|
||||||
createDir' "nonEmpty/dir1"
|
|
||||||
createDir' "nonEmpty/dir2"
|
|
||||||
createDir' "nonEmpty/dir2/dir3"
|
|
||||||
createRegularFile' "nonEmpty/file1"
|
|
||||||
createRegularFile' "nonEmpty/dir1/file2"
|
|
||||||
deleteDirRecursive' "nonEmpty"
|
|
||||||
getSymbolicLinkStatus "nonEmpty"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "deleteDirRecursive, can't open parent directory" $ do
|
|
||||||
createDir' "noPerms/foo"
|
|
||||||
noPerms "noPerms"
|
|
||||||
(deleteDirRecursive' "noPerms/foo")
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
normalDirPerms "noPerms"
|
|
||||||
deleteDir' "noPerms/foo"
|
|
||||||
|
|
||||||
it "deleteDirRecursive, can't write to parent directory" $ do
|
|
||||||
createDir' "noWritable/foo"
|
|
||||||
noWritableDirPerms "noWritable"
|
|
||||||
(deleteDirRecursive' "noWritable/foo")
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
normalDirPerms "noWritable"
|
|
||||||
deleteDir' "noWritable/foo"
|
|
||||||
|
|
||||||
it "deleteDirRecursive, wrong file type (symlink to directory)" $
|
|
||||||
deleteDirRecursive' "dirSym"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InappropriateType)
|
|
||||||
|
|
||||||
it "deleteDirRecursive, wrong file type (regular file)" $
|
|
||||||
deleteDirRecursive' "file"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InappropriateType)
|
|
||||||
|
|
||||||
it "deleteDirRecursive, directory does not exist" $
|
|
||||||
deleteDirRecursive' "doesNotExist"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
|
|
@ -1,114 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.DeleteDirSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import System.Posix.Files.ByteString
|
|
||||||
(
|
|
||||||
getSymbolicLinkStatus
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import Utils
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "DeleteDirSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "file"
|
|
||||||
createDir' "dir"
|
|
||||||
createRegularFile' "dir/.keep"
|
|
||||||
createSymlink' "dirSym" "dir/"
|
|
||||||
createDir' "noPerms"
|
|
||||||
createRegularFile' "noPerms/.keep"
|
|
||||||
createDir' "noWritable"
|
|
||||||
createRegularFile' "noWritable/.keep"
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
deleteFile' "file"
|
|
||||||
deleteFile' "dir/.keep"
|
|
||||||
deleteDir' "dir"
|
|
||||||
deleteFile' "dirSym"
|
|
||||||
deleteFile' "noPerms/.keep"
|
|
||||||
deleteDir' "noPerms"
|
|
||||||
deleteFile' "noWritable/.keep"
|
|
||||||
deleteDir' "noWritable"
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.deleteDir" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "deleteDir, empty directory, all fine" $ do
|
|
||||||
createDir' "testDir"
|
|
||||||
deleteDir' "testDir"
|
|
||||||
getSymbolicLinkStatus "testDir"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
it "deleteDir, directory with null permissions, all fine" $ do
|
|
||||||
createDir' "noPerms/testDir"
|
|
||||||
noPerms "noPerms/testDir"
|
|
||||||
deleteDir' "noPerms/testDir"
|
|
||||||
getSymbolicLinkStatus "testDir"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "deleteDir, wrong file type (symlink to directory)" $
|
|
||||||
deleteDir' "dirSym"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InappropriateType)
|
|
||||||
|
|
||||||
it "deleteDir, wrong file type (regular file)" $
|
|
||||||
deleteDir' "file"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InappropriateType)
|
|
||||||
|
|
||||||
it "deleteDir, directory does not exist" $
|
|
||||||
deleteDir' "doesNotExist"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
it "deleteDir, directory not empty" $
|
|
||||||
deleteDir' "dir"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == UnsatisfiedConstraints)
|
|
||||||
|
|
||||||
it "deleteDir, can't open parent directory" $ do
|
|
||||||
createDir' "noPerms/foo"
|
|
||||||
noPerms "noPerms"
|
|
||||||
(deleteDir' "noPerms/foo")
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
normalDirPerms "noPerms"
|
|
||||||
deleteDir' "noPerms/foo"
|
|
||||||
|
|
||||||
it "deleteDir, can't write to parent directory, still fine" $ do
|
|
||||||
createDir' "noWritable/foo"
|
|
||||||
noWritableDirPerms "noWritable"
|
|
||||||
(deleteDir' "noWritable/foo")
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
normalDirPerms "noWritable"
|
|
||||||
deleteDir' "noWritable/foo"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,84 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.DeleteFileSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import "hpath-directory" System.Posix.RawFilePath.Directory
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import System.Posix.Files.ByteString
|
|
||||||
(
|
|
||||||
getSymbolicLinkStatus
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import Utils
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "DeleteFileSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "foo"
|
|
||||||
createSymlink' "syml" "foo"
|
|
||||||
createDir' "dir"
|
|
||||||
createDir' "noPerms"
|
|
||||||
noPerms "noPerms"
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
normalDirPerms "noPerms"
|
|
||||||
deleteFile' "foo"
|
|
||||||
deleteFile' "syml"
|
|
||||||
deleteDir' "dir"
|
|
||||||
deleteDir' "noPerms"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.deleteFile" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "deleteFile, regular file, all fine" $ do
|
|
||||||
createRegularFile' "testFile"
|
|
||||||
deleteFile' "testFile"
|
|
||||||
getSymbolicLinkStatus "testFile"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
it "deleteFile, symlink, all fine" $ do
|
|
||||||
recreateSymlink' "syml"
|
|
||||||
"testFile"
|
|
||||||
Strict
|
|
||||||
deleteFile' "testFile"
|
|
||||||
getSymbolicLinkStatus "testFile"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "deleteFile, wrong file type (directory)" $
|
|
||||||
deleteFile' "dir"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InappropriateType || ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "deleteFile, file does not exist" $
|
|
||||||
deleteFile' "doesNotExist"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
it "deleteFile, can't read directory" $
|
|
||||||
deleteFile' "noPerms/blah"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.GetDirsFilesSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Data.List
|
|
||||||
(
|
|
||||||
sort
|
|
||||||
)
|
|
||||||
import "hpath-directory" System.Posix.RawFilePath.Directory hiding (getDirsFiles')
|
|
||||||
import System.Posix.FilePath
|
|
||||||
import Test.Hspec
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import Utils
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "GetDirsFilesSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "file"
|
|
||||||
createRegularFile' "Lala"
|
|
||||||
createRegularFile' ".hidden"
|
|
||||||
createSymlink' "syml" "Lala"
|
|
||||||
createDir' "dir"
|
|
||||||
createSymlink' "dirsym" "dir"
|
|
||||||
createDir' "noPerms"
|
|
||||||
noPerms "noPerms"
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
normalDirPerms "noPerms"
|
|
||||||
deleteFile' "file"
|
|
||||||
deleteFile' "Lala"
|
|
||||||
deleteFile' ".hidden"
|
|
||||||
deleteFile' "syml"
|
|
||||||
deleteDir' "dir"
|
|
||||||
deleteFile' "dirsym"
|
|
||||||
deleteDir' "noPerms"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.getDirsFiles" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "getDirsFiles, all fine" $
|
|
||||||
withRawTmpDir $ \p -> do
|
|
||||||
let expectedFiles = [".hidden"
|
|
||||||
,"Lala"
|
|
||||||
,"dir"
|
|
||||||
,"dirsym"
|
|
||||||
,"file"
|
|
||||||
,"noPerms"
|
|
||||||
,"syml"]
|
|
||||||
(fmap sort $ getDirsFiles p)
|
|
||||||
`shouldReturn` fmap (p </>) expectedFiles
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "getDirsFiles, nonexistent directory" $
|
|
||||||
getDirsFiles' "nothingHere"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
it "getDirsFiles, wrong file type (file)" $
|
|
||||||
getDirsFiles' "file"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InappropriateType)
|
|
||||||
|
|
||||||
it "getDirsFiles, wrong file type (symlink to file)" $
|
|
||||||
getDirsFiles' "syml"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InvalidArgument)
|
|
||||||
|
|
||||||
it "getDirsFiles, wrong file type (symlink to dir)" $
|
|
||||||
getDirsFiles' "dirsym"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InvalidArgument)
|
|
||||||
|
|
||||||
it "getDirsFiles, can't open directory" $
|
|
||||||
getDirsFiles' "noPerms"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.GetFileTypeSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import "hpath-directory" System.Posix.RawFilePath.Directory
|
|
||||||
import Test.Hspec
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import Utils
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "GetFileTypeSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "regularfile"
|
|
||||||
createSymlink' "symlink" "regularfile"
|
|
||||||
createSymlink' "brokenSymlink" "broken"
|
|
||||||
createDir' "directory"
|
|
||||||
createSymlink' "symlinkD" "directory"
|
|
||||||
createDir' "noPerms"
|
|
||||||
noPerms "noPerms"
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
normalDirPerms "noPerms"
|
|
||||||
deleteFile' "regularfile"
|
|
||||||
deleteFile' "symlink"
|
|
||||||
deleteFile' "brokenSymlink"
|
|
||||||
deleteDir' "directory"
|
|
||||||
deleteFile' "symlinkD"
|
|
||||||
deleteDir' "noPerms"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.getFileType" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "getFileType, regular file" $
|
|
||||||
getFileType' "regularfile"
|
|
||||||
`shouldReturn` RegularFile
|
|
||||||
|
|
||||||
it "getFileType, directory" $
|
|
||||||
getFileType' "directory"
|
|
||||||
`shouldReturn` Directory
|
|
||||||
|
|
||||||
it "getFileType, directory with null permissions" $
|
|
||||||
getFileType' "noPerms"
|
|
||||||
`shouldReturn` Directory
|
|
||||||
|
|
||||||
it "getFileType, symlink to file" $
|
|
||||||
getFileType' "symlink"
|
|
||||||
`shouldReturn` SymbolicLink
|
|
||||||
|
|
||||||
it "getFileType, symlink to directory" $
|
|
||||||
getFileType' "symlinkD"
|
|
||||||
`shouldReturn` SymbolicLink
|
|
||||||
|
|
||||||
it "getFileType, broken symlink" $
|
|
||||||
getFileType' "brokenSymlink"
|
|
||||||
`shouldReturn` SymbolicLink
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "getFileType, file does not exist" $
|
|
||||||
getFileType' "nothingHere"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
it "getFileType, can't open directory" $
|
|
||||||
getFileType' "noPerms/forz"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
@ -1,126 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.MoveFileOverwriteSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import "hpath-directory" System.Posix.RawFilePath.Directory
|
|
||||||
import System.Posix.RawFilePath.Directory.Errors
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import Utils
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "MoveFileOverwriteSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "myFile"
|
|
||||||
createSymlink' "myFileL" "myFile"
|
|
||||||
createDir' "alreadyExistsD"
|
|
||||||
createDir' "dir"
|
|
||||||
createDir' "noPerms"
|
|
||||||
createDir' "noWritePerm"
|
|
||||||
noPerms "noPerms"
|
|
||||||
noWritableDirPerms "noWritePerm"
|
|
||||||
writeFile' "myFile" "Blahfaselgagaga"
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
normalDirPerms "noPerms"
|
|
||||||
normalDirPerms "noWritePerm"
|
|
||||||
deleteFile' "myFile"
|
|
||||||
deleteFile' "myFileL"
|
|
||||||
deleteDir' "alreadyExistsD"
|
|
||||||
deleteDir' "dir"
|
|
||||||
deleteDir' "noPerms"
|
|
||||||
deleteDir' "noWritePerm"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.moveFile" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "moveFile (Overwrite), all fine" $
|
|
||||||
moveFile' "myFile"
|
|
||||||
"movedFile"
|
|
||||||
Overwrite
|
|
||||||
|
|
||||||
it "moveFile (Overwrite), all fine" $
|
|
||||||
moveFile' "myFile"
|
|
||||||
"dir/movedFile"
|
|
||||||
Overwrite
|
|
||||||
|
|
||||||
it "moveFile (Overwrite), all fine on symlink" $
|
|
||||||
moveFile' "myFileL"
|
|
||||||
"movedFile"
|
|
||||||
Overwrite
|
|
||||||
|
|
||||||
it "moveFile (Overwrite), all fine on directory" $
|
|
||||||
moveFile' "dir"
|
|
||||||
"movedFile"
|
|
||||||
Overwrite
|
|
||||||
|
|
||||||
it "moveFile (Overwrite), destination file already exists" $
|
|
||||||
moveFile' "myFile"
|
|
||||||
"alreadyExists"
|
|
||||||
Overwrite
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "moveFile (Overwrite), source file does not exist" $
|
|
||||||
moveFile' "fileDoesNotExist"
|
|
||||||
"movedFile"
|
|
||||||
Overwrite
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
it "moveFile (Overwrite), can't write to destination directory" $
|
|
||||||
moveFile' "myFile"
|
|
||||||
"noWritePerm/movedFile"
|
|
||||||
Overwrite
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "moveFile (Overwrite), can't open destination directory" $
|
|
||||||
moveFile' "myFile"
|
|
||||||
"noPerms/movedFile"
|
|
||||||
Overwrite
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "moveFile (Overwrite), can't open source directory" $
|
|
||||||
moveFile' "noPerms/myFile"
|
|
||||||
"movedFile"
|
|
||||||
Overwrite
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
-- custom failures --
|
|
||||||
|
|
||||||
it "moveFile (Overwrite), move from file to dir" $
|
|
||||||
moveFile' "myFile"
|
|
||||||
"alreadyExistsD"
|
|
||||||
Overwrite
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == AlreadyExists)
|
|
||||||
|
|
||||||
it "moveFile (Overwrite), source and dest are same file" $
|
|
||||||
moveFile' "myFile"
|
|
||||||
"myFile"
|
|
||||||
Overwrite
|
|
||||||
`shouldThrow`
|
|
||||||
isSameFile
|
|
@ -1,129 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.MoveFileSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import "hpath-directory" System.Posix.RawFilePath.Directory
|
|
||||||
import System.Posix.RawFilePath.Directory.Errors
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import Utils
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "MoveFileSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "myFile"
|
|
||||||
createSymlink' "myFileL" "myFile"
|
|
||||||
createRegularFile' "alreadyExists"
|
|
||||||
createDir' "alreadyExistsD"
|
|
||||||
createDir' "dir"
|
|
||||||
createDir' "noPerms"
|
|
||||||
createDir' "noWritePerm"
|
|
||||||
noPerms "noPerms"
|
|
||||||
noWritableDirPerms "noWritePerm"
|
|
||||||
writeFile' "myFile" "Blahfaselgagaga"
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
normalDirPerms "noPerms"
|
|
||||||
normalDirPerms "noWritePerm"
|
|
||||||
deleteFile' "myFile"
|
|
||||||
deleteFile' "myFileL"
|
|
||||||
deleteFile' "alreadyExists"
|
|
||||||
deleteDir' "alreadyExistsD"
|
|
||||||
deleteDir' "dir"
|
|
||||||
deleteDir' "noPerms"
|
|
||||||
deleteDir' "noWritePerm"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.moveFile" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "moveFile (Strict), all fine" $
|
|
||||||
moveFile' "myFile"
|
|
||||||
"movedFile"
|
|
||||||
Strict
|
|
||||||
|
|
||||||
it "moveFile (Strict), all fine" $
|
|
||||||
moveFile' "myFile"
|
|
||||||
"dir/movedFile"
|
|
||||||
Strict
|
|
||||||
|
|
||||||
it "moveFile (Strict), all fine on symlink" $
|
|
||||||
moveFile' "myFileL"
|
|
||||||
"movedFile"
|
|
||||||
Strict
|
|
||||||
|
|
||||||
it "moveFile (Strict), all fine on directory" $
|
|
||||||
moveFile' "dir"
|
|
||||||
"movedFile"
|
|
||||||
Strict
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "moveFile (Strict), source file does not exist" $
|
|
||||||
moveFile' "fileDoesNotExist"
|
|
||||||
"movedFile"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
it "moveFile (Strict), can't write to destination directory" $
|
|
||||||
moveFile' "myFile"
|
|
||||||
"noWritePerm/movedFile"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "moveFile (Strict), can't open destination directory" $
|
|
||||||
moveFile' "myFile"
|
|
||||||
"noPerms/movedFile"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "moveFile (Strict), can't open source directory" $
|
|
||||||
moveFile' "noPerms/myFile"
|
|
||||||
"movedFile"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
-- custom failures --
|
|
||||||
it "moveFile (Strict), destination file already exists" $
|
|
||||||
moveFile' "myFile"
|
|
||||||
"alreadyExists"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == AlreadyExists)
|
|
||||||
|
|
||||||
it "moveFile (Strict), move from file to dir" $
|
|
||||||
moveFile' "myFile"
|
|
||||||
"alreadyExistsD"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == AlreadyExists)
|
|
||||||
|
|
||||||
it "moveFile (Strict), source and dest are same file" $
|
|
||||||
moveFile' "myFile"
|
|
||||||
"myFile"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
isSameFile
|
|
@ -1,85 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.ReadFileSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import Utils
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "ReadFileSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "fileWithContent"
|
|
||||||
createRegularFile' "fileWithoutContent"
|
|
||||||
createSymlink' "inputFileSymL" "fileWithContent"
|
|
||||||
createDir' "alreadyExistsD"
|
|
||||||
createRegularFile' "noPerms"
|
|
||||||
noPerms "noPerms"
|
|
||||||
createDir' "noPermsD"
|
|
||||||
createRegularFile' "noPermsD/inputFile"
|
|
||||||
noPerms "noPermsD"
|
|
||||||
writeFile' "fileWithContent" "Blahfaselgagaga"
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
deleteFile' "fileWithContent"
|
|
||||||
deleteFile' "fileWithoutContent"
|
|
||||||
deleteFile' "inputFileSymL"
|
|
||||||
deleteDir' "alreadyExistsD"
|
|
||||||
normalFilePerms "noPerms"
|
|
||||||
deleteFile' "noPerms"
|
|
||||||
normalDirPerms "noPermsD"
|
|
||||||
deleteFile' "noPermsD/inputFile"
|
|
||||||
deleteDir' "noPermsD"
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.readFile" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "readFile (Strict) file with content, everything clear" $ do
|
|
||||||
out <- readFile' "fileWithContent"
|
|
||||||
out `shouldBe` "Blahfaselgagaga"
|
|
||||||
|
|
||||||
it "readFile (Strict) symlink, everything clear" $ do
|
|
||||||
out <- readFile' "inputFileSymL"
|
|
||||||
out `shouldBe` "Blahfaselgagaga"
|
|
||||||
|
|
||||||
it "readFile (Strict) empty file, everything clear" $ do
|
|
||||||
out <- readFile' "fileWithoutContent"
|
|
||||||
out `shouldBe` ""
|
|
||||||
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "readFile (Strict) directory, wrong file type" $ do
|
|
||||||
readFile' "alreadyExistsD"
|
|
||||||
`shouldThrow` (\e -> ioeGetErrorType e == InappropriateType)
|
|
||||||
|
|
||||||
it "readFile (Strict) file, no permissions" $ do
|
|
||||||
readFile' "noPerms"
|
|
||||||
`shouldThrow` (\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "readFile (Strict) file, no permissions on dir" $ do
|
|
||||||
readFile' "noPermsD/inputFile"
|
|
||||||
`shouldThrow` (\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "readFile (Strict) file, no such file" $ do
|
|
||||||
readFile' "lalala"
|
|
||||||
`shouldThrow` (\e -> ioeGetErrorType e == NoSuchThing)
|
|
@ -1,139 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.RecreateSymlinkOverwriteSpec where
|
|
||||||
|
|
||||||
|
|
||||||
-- TODO: exception if destination exists but is not a file + `OverWrite` CopyMode
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import "hpath-directory" System.Posix.RawFilePath.Directory
|
|
||||||
import System.Posix.RawFilePath.Directory.Errors
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import Utils
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "RecreateSymlinkOverwriteSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "myFile"
|
|
||||||
createSymlink' "myFileL" "myFile"
|
|
||||||
createRegularFile' "alreadyExists"
|
|
||||||
createDir' "alreadyExistsD"
|
|
||||||
createDir' "dir"
|
|
||||||
createDir' "noPerms"
|
|
||||||
createDir' "noWritePerm"
|
|
||||||
createDir' "alreadyExistsD2"
|
|
||||||
createRegularFile' "alreadyExistsD2/lala"
|
|
||||||
noPerms "noPerms"
|
|
||||||
noWritableDirPerms "noWritePerm"
|
|
||||||
writeFile' "myFile" "Blahfaselgagaga"
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
normalDirPerms "noPerms"
|
|
||||||
normalDirPerms "noWritePerm"
|
|
||||||
deleteFile' "myFile"
|
|
||||||
deleteFile' "myFileL"
|
|
||||||
deleteFile' "alreadyExists"
|
|
||||||
deleteFile' "alreadyExistsD2/lala"
|
|
||||||
deleteDir' "alreadyExistsD"
|
|
||||||
deleteDir' "alreadyExistsD2"
|
|
||||||
deleteDir' "dir"
|
|
||||||
deleteDir' "noPerms"
|
|
||||||
deleteDir' "noWritePerm"
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.recreateSymlink" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "recreateSymLink (Overwrite), all fine" $ do
|
|
||||||
recreateSymlink' "myFileL"
|
|
||||||
"movedFile"
|
|
||||||
Overwrite
|
|
||||||
removeFileIfExists "movedFile"
|
|
||||||
|
|
||||||
it "recreateSymLink (Overwrite), all fine" $ do
|
|
||||||
recreateSymlink' "myFileL"
|
|
||||||
"dir/movedFile"
|
|
||||||
Overwrite
|
|
||||||
removeFileIfExists "dir/movedFile"
|
|
||||||
|
|
||||||
it "recreateSymLink (Overwrite), destination file already exists" $
|
|
||||||
recreateSymlink' "myFileL"
|
|
||||||
"alreadyExists"
|
|
||||||
Overwrite
|
|
||||||
|
|
||||||
it "recreateSymLink (Overwrite), destination already exists and is an empty dir" $ do
|
|
||||||
recreateSymlink' "myFileL"
|
|
||||||
"alreadyExistsD"
|
|
||||||
Overwrite
|
|
||||||
deleteFile' "alreadyExistsD"
|
|
||||||
createDir' "alreadyExistsD"
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "recreateSymLink (Overwrite), destination already exists and is a non-empty dir" $
|
|
||||||
recreateSymlink' "myFileL"
|
|
||||||
"alreadyExistsD2"
|
|
||||||
Overwrite
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == UnsatisfiedConstraints)
|
|
||||||
|
|
||||||
it "recreateSymLink (Overwrite), wrong input type (file)" $
|
|
||||||
recreateSymlink' "myFile"
|
|
||||||
"movedFile"
|
|
||||||
Overwrite
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InvalidArgument)
|
|
||||||
|
|
||||||
it "recreateSymLink (Overwrite), wrong input type (directory)" $
|
|
||||||
recreateSymlink' "dir"
|
|
||||||
"movedFile"
|
|
||||||
Overwrite
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InvalidArgument)
|
|
||||||
|
|
||||||
it "recreateSymLink (Overwrite), can't write to destination directory" $
|
|
||||||
recreateSymlink' "myFileL"
|
|
||||||
"noWritePerm/movedFile"
|
|
||||||
Overwrite
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "recreateSymLink (Overwrite), can't open destination directory" $
|
|
||||||
recreateSymlink' "myFileL"
|
|
||||||
"noPerms/movedFile"
|
|
||||||
Overwrite
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "recreateSymLink (Overwrite), can't open source directory" $
|
|
||||||
recreateSymlink' "noPerms/myFileL"
|
|
||||||
"movedFile"
|
|
||||||
Overwrite
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
-- custom failures --
|
|
||||||
it "recreateSymLink (Overwrite), source and destination are the same file" $
|
|
||||||
recreateSymlink' "myFileL"
|
|
||||||
"myFileL"
|
|
||||||
Overwrite
|
|
||||||
`shouldThrow`
|
|
||||||
isSameFile
|
|
||||||
|
|
@ -1,130 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.RecreateSymlinkSpec where
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import "hpath-directory" System.Posix.RawFilePath.Directory
|
|
||||||
import System.Posix.RawFilePath.Directory.Errors
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import Utils
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "RecreateSymlinkSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "myFile"
|
|
||||||
createSymlink' "myFileL" "myFile"
|
|
||||||
createRegularFile' "alreadyExists"
|
|
||||||
createDir' "alreadyExistsD"
|
|
||||||
createDir' "dir"
|
|
||||||
createDir' "noPerms"
|
|
||||||
createDir' "noWritePerm"
|
|
||||||
noPerms "noPerms"
|
|
||||||
noWritableDirPerms "noWritePerm"
|
|
||||||
writeFile' "myFile" "Blahfaselgagaga"
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
normalDirPerms "noPerms"
|
|
||||||
normalDirPerms "noWritePerm"
|
|
||||||
deleteFile' "myFile"
|
|
||||||
deleteFile' "myFileL"
|
|
||||||
deleteFile' "alreadyExists"
|
|
||||||
deleteDir' "alreadyExistsD"
|
|
||||||
deleteDir' "dir"
|
|
||||||
deleteDir' "noPerms"
|
|
||||||
deleteDir' "noWritePerm"
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.recreateSymlink" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "recreateSymLink (Strict), all fine" $ do
|
|
||||||
recreateSymlink' "myFileL"
|
|
||||||
"movedFile"
|
|
||||||
Strict
|
|
||||||
removeFileIfExists "movedFile"
|
|
||||||
|
|
||||||
it "recreateSymLink (Strict), all fine" $ do
|
|
||||||
recreateSymlink' "myFileL"
|
|
||||||
"dir/movedFile"
|
|
||||||
Strict
|
|
||||||
removeFileIfExists "dir/movedFile"
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "recreateSymLink (Strict), wrong input type (file)" $
|
|
||||||
recreateSymlink' "myFile"
|
|
||||||
"movedFile"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InvalidArgument)
|
|
||||||
|
|
||||||
it "recreateSymLink (Strict), wrong input type (directory)" $
|
|
||||||
recreateSymlink' "dir"
|
|
||||||
"movedFile"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == InvalidArgument)
|
|
||||||
|
|
||||||
it "recreateSymLink (Strict), can't write to destination directory" $
|
|
||||||
recreateSymlink' "myFileL"
|
|
||||||
"noWritePerm/movedFile"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "recreateSymLink (Strict), can't open destination directory" $
|
|
||||||
recreateSymlink' "myFileL"
|
|
||||||
"noPerms/movedFile"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "recreateSymLink (Strict), can't open source directory" $
|
|
||||||
recreateSymlink' "noPerms/myFileL"
|
|
||||||
"movedFile"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "recreateSymLink (Strict), destination file already exists" $
|
|
||||||
recreateSymlink' "myFileL"
|
|
||||||
"alreadyExists"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == AlreadyExists)
|
|
||||||
|
|
||||||
it "recreateSymLink (Strict), destination already exists and is a dir" $
|
|
||||||
recreateSymlink' "myFileL"
|
|
||||||
"alreadyExistsD"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == AlreadyExists)
|
|
||||||
|
|
||||||
-- custom failures --
|
|
||||||
it "recreateSymLink (Strict), source and destination are the same file" $
|
|
||||||
recreateSymlink' "myFileL"
|
|
||||||
"myFileL"
|
|
||||||
Strict
|
|
||||||
`shouldThrow`
|
|
||||||
isSameFile
|
|
||||||
|
|
@ -1,117 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.RenameFileSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import System.Posix.RawFilePath.Directory.Errors
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import Utils
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "RenameFileSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "myFile"
|
|
||||||
createSymlink' "myFileL" "myFile"
|
|
||||||
createRegularFile' "alreadyExists"
|
|
||||||
createDir' "alreadyExistsD"
|
|
||||||
createDir' "dir"
|
|
||||||
createDir' "noPerms"
|
|
||||||
createDir' "noWritePerm"
|
|
||||||
noPerms "noPerms"
|
|
||||||
noWritableDirPerms "noWritePerm"
|
|
||||||
writeFile' "myFile" "Blahfaselgagaga"
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
normalDirPerms "noPerms"
|
|
||||||
normalDirPerms "noWritePerm"
|
|
||||||
deleteFile' "myFile"
|
|
||||||
deleteFile' "myFileL"
|
|
||||||
deleteFile' "alreadyExists"
|
|
||||||
deleteDir' "alreadyExistsD"
|
|
||||||
deleteDir' "dir"
|
|
||||||
deleteDir' "noPerms"
|
|
||||||
deleteDir' "noWritePerm"
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.renameFile" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "renameFile, all fine" $
|
|
||||||
renameFile' "myFile"
|
|
||||||
"renamedFile"
|
|
||||||
|
|
||||||
it "renameFile, all fine" $
|
|
||||||
renameFile' "myFile"
|
|
||||||
"dir/renamedFile"
|
|
||||||
|
|
||||||
it "renameFile, all fine on symlink" $
|
|
||||||
renameFile' "myFileL"
|
|
||||||
"renamedFile"
|
|
||||||
|
|
||||||
it "renameFile, all fine on directory" $
|
|
||||||
renameFile' "dir"
|
|
||||||
"renamedFile"
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "renameFile, source file does not exist" $
|
|
||||||
renameFile' "fileDoesNotExist"
|
|
||||||
"renamedFile"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == NoSuchThing)
|
|
||||||
|
|
||||||
it "renameFile, can't write to output directory" $
|
|
||||||
renameFile' "myFile"
|
|
||||||
"noWritePerm/renamedFile"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "renameFile, can't open output directory" $
|
|
||||||
renameFile' "myFile"
|
|
||||||
"noPerms/renamedFile"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "renameFile, can't open source directory" $
|
|
||||||
renameFile' "noPerms/myFile"
|
|
||||||
"renamedFile"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
-- custom failures --
|
|
||||||
it "renameFile, destination file already exists" $
|
|
||||||
renameFile' "myFile"
|
|
||||||
"alreadyExists"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == AlreadyExists)
|
|
||||||
|
|
||||||
it "renameFile, move from file to dir" $
|
|
||||||
renameFile' "myFile"
|
|
||||||
"alreadyExistsD"
|
|
||||||
`shouldThrow`
|
|
||||||
(\e -> ioeGetErrorType e == AlreadyExists)
|
|
||||||
|
|
||||||
it "renameFile, source and dest are same file" $
|
|
||||||
renameFile' "myFile"
|
|
||||||
"myFile"
|
|
||||||
`shouldThrow`
|
|
||||||
isSameFile
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.ToAbsSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import "hpath-directory" System.Posix.RawFilePath.Directory
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = describe "System.Posix.RawFilePath.Directory.toAbs" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "toAbs returns absolute paths unchanged" $ do
|
|
||||||
let p1 = "/a/b/c/d"
|
|
||||||
to <- toAbs p1
|
|
||||||
p1 `shouldBe` to
|
|
||||||
|
|
||||||
it "toAbs returns even existing absolute paths unchanged" $ do
|
|
||||||
let p1 = "/home"
|
|
||||||
to <- toAbs p1
|
|
||||||
p1 `shouldBe` to
|
|
||||||
|
|
||||||
|
|
@ -1,108 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.WriteFileLSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import Utils
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "WriteFileLSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "fileWithContent"
|
|
||||||
createRegularFile' "fileWithoutContent"
|
|
||||||
createSymlink' "inputFileSymL" "fileWithContent"
|
|
||||||
createDir' "alreadyExistsD"
|
|
||||||
createRegularFile' "noPerms"
|
|
||||||
noPerms "noPerms"
|
|
||||||
createDir' "noPermsD"
|
|
||||||
createRegularFile' "noPermsD/inputFile"
|
|
||||||
noPerms "noPermsD"
|
|
||||||
writeFile' "fileWithContent" "BLKASL"
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
deleteFile' "fileWithContent"
|
|
||||||
deleteFile' "fileWithoutContent"
|
|
||||||
deleteFile' "inputFileSymL"
|
|
||||||
deleteDir' "alreadyExistsD"
|
|
||||||
normalFilePerms "noPerms"
|
|
||||||
deleteFile' "noPerms"
|
|
||||||
normalDirPerms "noPermsD"
|
|
||||||
deleteFile' "noPermsD/inputFile"
|
|
||||||
deleteDir' "noPermsD"
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.WriteFileL" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "WriteFileL file with content, everything clear" $ do
|
|
||||||
writeFileL' "fileWithContent" "blahfaselllll"
|
|
||||||
out <- readFile' "fileWithContent"
|
|
||||||
out `shouldBe` "blahfaselllll"
|
|
||||||
|
|
||||||
it "WriteFileL file with content, everything clear" $ do
|
|
||||||
writeFileL' "fileWithContent" "gagagaga"
|
|
||||||
out <- readFile' "fileWithContent"
|
|
||||||
out `shouldBe` "gagagaga"
|
|
||||||
|
|
||||||
it "WriteFileL file with content, everything clear" $ do
|
|
||||||
writeFileL' "fileWithContent" ""
|
|
||||||
out <- readFile' "fileWithContent"
|
|
||||||
out `shouldBe` ""
|
|
||||||
|
|
||||||
it "WriteFileL file without content, everything clear" $ do
|
|
||||||
writeFileL' "fileWithoutContent" "blahfaselllll"
|
|
||||||
out <- readFile' "fileWithoutContent"
|
|
||||||
out `shouldBe` "blahfaselllll"
|
|
||||||
|
|
||||||
it "WriteFileL, everything clear" $ do
|
|
||||||
writeFileL' "fileWithoutContent" "gagagaga"
|
|
||||||
out <- readFile' "fileWithoutContent"
|
|
||||||
out `shouldBe` "gagagaga"
|
|
||||||
|
|
||||||
it "WriteFileL symlink, everything clear" $ do
|
|
||||||
writeFileL' "inputFileSymL" "blahfaselllll"
|
|
||||||
out <- readFile' "inputFileSymL"
|
|
||||||
out `shouldBe` "blahfaselllll"
|
|
||||||
|
|
||||||
it "WriteFileL symlink, everything clear" $ do
|
|
||||||
writeFileL' "inputFileSymL" "gagagaga"
|
|
||||||
out <- readFile' "inputFileSymL"
|
|
||||||
out `shouldBe` "gagagaga"
|
|
||||||
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "WriteFileL to dir, inappropriate type" $ do
|
|
||||||
writeFileL' "alreadyExistsD" ""
|
|
||||||
`shouldThrow` (\e -> ioeGetErrorType e == InappropriateType)
|
|
||||||
|
|
||||||
it "WriteFileL, no permissions to file" $ do
|
|
||||||
writeFileL' "noPerms" ""
|
|
||||||
`shouldThrow` (\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "WriteFileL, no permissions to file" $ do
|
|
||||||
writeFileL' "noPermsD/inputFile" ""
|
|
||||||
`shouldThrow` (\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "WriteFileL, file does not exist" $ do
|
|
||||||
writeFileL' "gaga" ""
|
|
||||||
`shouldThrow` (\e -> ioeGetErrorType e == NoSuchThing)
|
|
@ -1,108 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.WriteFileSpec where
|
|
||||||
|
|
||||||
|
|
||||||
import Test.Hspec
|
|
||||||
import System.IO.Error
|
|
||||||
(
|
|
||||||
ioeGetErrorType
|
|
||||||
)
|
|
||||||
import GHC.IO.Exception
|
|
||||||
(
|
|
||||||
IOErrorType(..)
|
|
||||||
)
|
|
||||||
import Utils
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
upTmpDir :: IO ()
|
|
||||||
upTmpDir = do
|
|
||||||
setTmpDir "WriteFileSpec"
|
|
||||||
createTmpDir
|
|
||||||
|
|
||||||
setupFiles :: IO ()
|
|
||||||
setupFiles = do
|
|
||||||
createRegularFile' "fileWithContent"
|
|
||||||
createRegularFile' "fileWithoutContent"
|
|
||||||
createSymlink' "inputFileSymL" "fileWithContent"
|
|
||||||
createDir' "alreadyExistsD"
|
|
||||||
createRegularFile' "noPerms"
|
|
||||||
noPerms "noPerms"
|
|
||||||
createDir' "noPermsD"
|
|
||||||
createRegularFile' "noPermsD/inputFile"
|
|
||||||
noPerms "noPermsD"
|
|
||||||
writeFile' "fileWithContent" "BLKASL"
|
|
||||||
|
|
||||||
|
|
||||||
cleanupFiles :: IO ()
|
|
||||||
cleanupFiles = do
|
|
||||||
deleteFile' "fileWithContent"
|
|
||||||
deleteFile' "fileWithoutContent"
|
|
||||||
deleteFile' "inputFileSymL"
|
|
||||||
deleteDir' "alreadyExistsD"
|
|
||||||
normalFilePerms "noPerms"
|
|
||||||
deleteFile' "noPerms"
|
|
||||||
normalDirPerms "noPermsD"
|
|
||||||
deleteFile' "noPermsD/inputFile"
|
|
||||||
deleteDir' "noPermsD"
|
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = beforeAll_ (upTmpDir >> setupFiles) $ afterAll_ cleanupFiles $
|
|
||||||
describe "System.Posix.RawFilePath.Directory.writeFile" $ do
|
|
||||||
|
|
||||||
-- successes --
|
|
||||||
it "writeFile file with content, everything clear" $ do
|
|
||||||
writeFile' "fileWithContent" "blahfaselllll"
|
|
||||||
out <- readFile' "fileWithContent"
|
|
||||||
out `shouldBe` "blahfaselllll"
|
|
||||||
|
|
||||||
it "writeFile file with content, everything clear" $ do
|
|
||||||
writeFile' "fileWithContent" "gagagaga"
|
|
||||||
out <- readFile' "fileWithContent"
|
|
||||||
out `shouldBe` "gagagaga"
|
|
||||||
|
|
||||||
it "writeFile file with content, everything clear" $ do
|
|
||||||
writeFile' "fileWithContent" ""
|
|
||||||
out <- readFile' "fileWithContent"
|
|
||||||
out `shouldBe` ""
|
|
||||||
|
|
||||||
it "writeFile file without content, everything clear" $ do
|
|
||||||
writeFile' "fileWithoutContent" "blahfaselllll"
|
|
||||||
out <- readFile' "fileWithoutContent"
|
|
||||||
out `shouldBe` "blahfaselllll"
|
|
||||||
|
|
||||||
it "writeFile, everything clear" $ do
|
|
||||||
writeFile' "fileWithoutContent" "gagagaga"
|
|
||||||
out <- readFile' "fileWithoutContent"
|
|
||||||
out `shouldBe` "gagagaga"
|
|
||||||
|
|
||||||
it "writeFile symlink, everything clear" $ do
|
|
||||||
writeFile' "inputFileSymL" "blahfaselllll"
|
|
||||||
out <- readFile' "inputFileSymL"
|
|
||||||
out `shouldBe` "blahfaselllll"
|
|
||||||
|
|
||||||
it "writeFile symlink, everything clear" $ do
|
|
||||||
writeFile' "inputFileSymL" "gagagaga"
|
|
||||||
out <- readFile' "inputFileSymL"
|
|
||||||
out `shouldBe` "gagagaga"
|
|
||||||
|
|
||||||
|
|
||||||
-- posix failures --
|
|
||||||
it "writeFile to dir, inappropriate type" $ do
|
|
||||||
writeFile' "alreadyExistsD" ""
|
|
||||||
`shouldThrow` (\e -> ioeGetErrorType e == InappropriateType)
|
|
||||||
|
|
||||||
it "writeFile, no permissions to file" $ do
|
|
||||||
writeFile' "noPerms" ""
|
|
||||||
`shouldThrow` (\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "writeFile, no permissions to file" $ do
|
|
||||||
writeFile' "noPermsD/inputFile" ""
|
|
||||||
`shouldThrow` (\e -> ioeGetErrorType e == PermissionDenied)
|
|
||||||
|
|
||||||
it "writeFile, file does not exist" $ do
|
|
||||||
writeFile' "gaga" ""
|
|
||||||
`shouldThrow` (\e -> ioeGetErrorType e == NoSuchThing)
|
|
@ -1,293 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
|
|
||||||
module Utils where
|
|
||||||
|
|
||||||
|
|
||||||
import Control.Applicative
|
|
||||||
(
|
|
||||||
(<$>)
|
|
||||||
)
|
|
||||||
import Control.Monad
|
|
||||||
(
|
|
||||||
forM_
|
|
||||||
, void
|
|
||||||
)
|
|
||||||
import Control.Monad.IfElse
|
|
||||||
(
|
|
||||||
whenM
|
|
||||||
)
|
|
||||||
import qualified Data.ByteString as BS
|
|
||||||
import qualified Data.ByteString.Lazy as BSL
|
|
||||||
import Data.IORef
|
|
||||||
(
|
|
||||||
newIORef
|
|
||||||
, readIORef
|
|
||||||
, writeIORef
|
|
||||||
, IORef
|
|
||||||
)
|
|
||||||
import "hpath-directory" System.Posix.RawFilePath.Directory
|
|
||||||
import Prelude hiding (appendFile, readFile, writeFile)
|
|
||||||
import Data.Maybe
|
|
||||||
(
|
|
||||||
fromJust
|
|
||||||
)
|
|
||||||
import System.IO.Unsafe
|
|
||||||
(
|
|
||||||
unsafePerformIO
|
|
||||||
)
|
|
||||||
import qualified System.Posix.RawFilePath.Directory.Traversals as DT
|
|
||||||
import Data.ByteString
|
|
||||||
(
|
|
||||||
ByteString
|
|
||||||
)
|
|
||||||
import qualified Data.ByteString.Lazy as L
|
|
||||||
import System.Posix.FilePath
|
|
||||||
import System.Posix.Files.ByteString
|
|
||||||
(
|
|
||||||
groupExecuteMode
|
|
||||||
, groupReadMode
|
|
||||||
, nullFileMode
|
|
||||||
, otherExecuteMode
|
|
||||||
, otherReadMode
|
|
||||||
, ownerExecuteMode
|
|
||||||
, ownerReadMode
|
|
||||||
, setFileMode
|
|
||||||
, unionFileModes
|
|
||||||
)
|
|
||||||
|
|
||||||
baseTmpDir :: IORef (Maybe ByteString)
|
|
||||||
{-# NOINLINE baseTmpDir #-}
|
|
||||||
baseTmpDir = unsafePerformIO (newIORef Nothing)
|
|
||||||
|
|
||||||
|
|
||||||
tmpDir :: IORef (Maybe ByteString)
|
|
||||||
{-# NOINLINE tmpDir #-}
|
|
||||||
tmpDir = unsafePerformIO (newIORef Nothing)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------
|
|
||||||
--[ Utilities ]--
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
|
|
||||||
setTmpDir :: ByteString -> IO ()
|
|
||||||
{-# NOINLINE setTmpDir #-}
|
|
||||||
setTmpDir bs = do
|
|
||||||
tmp <- fromJust <$> readIORef baseTmpDir
|
|
||||||
writeIORef tmpDir (Just (tmp `BS.append` bs))
|
|
||||||
|
|
||||||
|
|
||||||
createTmpDir :: IO ()
|
|
||||||
{-# NOINLINE createTmpDir #-}
|
|
||||||
createTmpDir = do
|
|
||||||
tmp <- fromJust <$> readIORef tmpDir
|
|
||||||
void $ createDir newDirPerms tmp
|
|
||||||
|
|
||||||
|
|
||||||
deleteTmpDir :: IO ()
|
|
||||||
{-# NOINLINE deleteTmpDir #-}
|
|
||||||
deleteTmpDir = do
|
|
||||||
tmp <- fromJust <$> readIORef tmpDir
|
|
||||||
void $ deleteDir tmp
|
|
||||||
|
|
||||||
|
|
||||||
deleteBaseTmpDir :: IO ()
|
|
||||||
{-# NOINLINE deleteBaseTmpDir #-}
|
|
||||||
deleteBaseTmpDir = do
|
|
||||||
tmp <- fromJust <$> readIORef baseTmpDir
|
|
||||||
contents <- getDirsFiles tmp
|
|
||||||
forM_ contents deleteDir
|
|
||||||
void $ deleteDir tmp
|
|
||||||
|
|
||||||
|
|
||||||
withRawTmpDir :: (ByteString -> IO a) -> IO a
|
|
||||||
{-# NOINLINE withRawTmpDir #-}
|
|
||||||
withRawTmpDir f = do
|
|
||||||
tmp <- fromJust <$> readIORef tmpDir
|
|
||||||
f tmp
|
|
||||||
|
|
||||||
|
|
||||||
getRawTmpDir :: IO ByteString
|
|
||||||
{-# NOINLINE getRawTmpDir #-}
|
|
||||||
getRawTmpDir = withRawTmpDir (return . flip BS.append "/")
|
|
||||||
|
|
||||||
|
|
||||||
withTmpDir :: ByteString -> (ByteString -> IO a) -> IO a
|
|
||||||
{-# NOINLINE withTmpDir #-}
|
|
||||||
withTmpDir ip f = do
|
|
||||||
tmp <- fromJust <$> readIORef tmpDir
|
|
||||||
let p = tmp </> ip
|
|
||||||
f p
|
|
||||||
|
|
||||||
|
|
||||||
withTmpDir' :: ByteString
|
|
||||||
-> ByteString
|
|
||||||
-> (ByteString -> ByteString -> IO a)
|
|
||||||
-> IO a
|
|
||||||
{-# NOINLINE withTmpDir' #-}
|
|
||||||
withTmpDir' ip1 ip2 f = do
|
|
||||||
tmp <- fromJust <$> readIORef tmpDir
|
|
||||||
let p1 = tmp </> ip1
|
|
||||||
let p2 = tmp </> ip2
|
|
||||||
f p1 p2
|
|
||||||
|
|
||||||
|
|
||||||
removeFileIfExists :: ByteString -> IO ()
|
|
||||||
{-# NOINLINE removeFileIfExists #-}
|
|
||||||
removeFileIfExists bs =
|
|
||||||
withTmpDir bs $ \p -> whenM (doesFileExist p) (deleteFile p)
|
|
||||||
|
|
||||||
|
|
||||||
removeDirIfExists :: ByteString -> IO ()
|
|
||||||
{-# NOINLINE removeDirIfExists #-}
|
|
||||||
removeDirIfExists bs =
|
|
||||||
withTmpDir bs $ \p -> whenM (doesDirectoryExist p) (deleteDirRecursive p)
|
|
||||||
|
|
||||||
|
|
||||||
copyFile' :: ByteString -> ByteString -> CopyMode -> IO ()
|
|
||||||
{-# NOINLINE copyFile' #-}
|
|
||||||
copyFile' inputFileP outputFileP cm =
|
|
||||||
withTmpDir' inputFileP outputFileP (\p1 p2 -> copyFile p1 p2 cm)
|
|
||||||
|
|
||||||
|
|
||||||
copyDirRecursive' :: ByteString -> ByteString
|
|
||||||
-> CopyMode -> RecursiveErrorMode -> IO ()
|
|
||||||
{-# NOINLINE copyDirRecursive' #-}
|
|
||||||
copyDirRecursive' inputDirP outputDirP cm rm =
|
|
||||||
withTmpDir' inputDirP outputDirP (\p1 p2 -> copyDirRecursive p1 p2 cm rm)
|
|
||||||
|
|
||||||
|
|
||||||
createDir' :: ByteString -> IO ()
|
|
||||||
{-# NOINLINE createDir' #-}
|
|
||||||
createDir' dest = withTmpDir dest (createDir newDirPerms)
|
|
||||||
|
|
||||||
createDirIfMissing' :: ByteString -> IO ()
|
|
||||||
{-# NOINLINE createDirIfMissing' #-}
|
|
||||||
createDirIfMissing' dest = withTmpDir dest (createDirIfMissing newDirPerms)
|
|
||||||
|
|
||||||
createDirRecursive' :: ByteString -> IO ()
|
|
||||||
{-# NOINLINE createDirRecursive' #-}
|
|
||||||
createDirRecursive' dest = withTmpDir dest (createDirRecursive newDirPerms)
|
|
||||||
|
|
||||||
createRegularFile' :: ByteString -> IO ()
|
|
||||||
{-# NOINLINE createRegularFile' #-}
|
|
||||||
createRegularFile' dest = withTmpDir dest (createRegularFile newFilePerms)
|
|
||||||
|
|
||||||
|
|
||||||
createSymlink' :: ByteString -> ByteString -> IO ()
|
|
||||||
{-# NOINLINE createSymlink' #-}
|
|
||||||
createSymlink' dest sympoint = withTmpDir dest
|
|
||||||
(\x -> createSymlink x sympoint)
|
|
||||||
|
|
||||||
|
|
||||||
renameFile' :: ByteString -> ByteString -> IO ()
|
|
||||||
{-# NOINLINE renameFile' #-}
|
|
||||||
renameFile' inputFileP outputFileP =
|
|
||||||
withTmpDir' inputFileP outputFileP $ \i o -> do
|
|
||||||
renameFile i o
|
|
||||||
renameFile o i
|
|
||||||
|
|
||||||
|
|
||||||
moveFile' :: ByteString -> ByteString -> CopyMode -> IO ()
|
|
||||||
{-# NOINLINE moveFile' #-}
|
|
||||||
moveFile' inputFileP outputFileP cm =
|
|
||||||
withTmpDir' inputFileP outputFileP $ \i o -> do
|
|
||||||
moveFile i o cm
|
|
||||||
moveFile o i Strict
|
|
||||||
|
|
||||||
|
|
||||||
recreateSymlink' :: ByteString -> ByteString -> CopyMode -> IO ()
|
|
||||||
{-# NOINLINE recreateSymlink' #-}
|
|
||||||
recreateSymlink' inputFileP outputFileP cm =
|
|
||||||
withTmpDir' inputFileP outputFileP (\p1 p2 -> recreateSymlink p1 p2 cm)
|
|
||||||
|
|
||||||
|
|
||||||
noWritableDirPerms :: ByteString -> IO ()
|
|
||||||
{-# NOINLINE noWritableDirPerms #-}
|
|
||||||
noWritableDirPerms path = withTmpDir path $ \p ->
|
|
||||||
setFileMode p perms
|
|
||||||
where
|
|
||||||
perms = ownerReadMode
|
|
||||||
`unionFileModes` ownerExecuteMode
|
|
||||||
`unionFileModes` groupReadMode
|
|
||||||
`unionFileModes` groupExecuteMode
|
|
||||||
`unionFileModes` otherReadMode
|
|
||||||
`unionFileModes` otherExecuteMode
|
|
||||||
|
|
||||||
|
|
||||||
noPerms :: ByteString -> IO ()
|
|
||||||
{-# NOINLINE noPerms #-}
|
|
||||||
noPerms path = withTmpDir path $ \p -> setFileMode p nullFileMode
|
|
||||||
|
|
||||||
|
|
||||||
normalDirPerms :: ByteString -> IO ()
|
|
||||||
{-# NOINLINE normalDirPerms #-}
|
|
||||||
normalDirPerms path =
|
|
||||||
withTmpDir path $ \p -> setFileMode p newDirPerms
|
|
||||||
|
|
||||||
|
|
||||||
normalFilePerms :: ByteString -> IO ()
|
|
||||||
{-# NOINLINE normalFilePerms #-}
|
|
||||||
normalFilePerms path =
|
|
||||||
withTmpDir path $ \p -> setFileMode p newFilePerms
|
|
||||||
|
|
||||||
|
|
||||||
getFileType' :: ByteString -> IO FileType
|
|
||||||
{-# NOINLINE getFileType' #-}
|
|
||||||
getFileType' path = withTmpDir path getFileType
|
|
||||||
|
|
||||||
|
|
||||||
getDirsFiles' :: ByteString -> IO [ByteString]
|
|
||||||
{-# NOINLINE getDirsFiles' #-}
|
|
||||||
getDirsFiles' path = withTmpDir path getDirsFiles
|
|
||||||
|
|
||||||
|
|
||||||
deleteFile' :: ByteString -> IO ()
|
|
||||||
{-# NOINLINE deleteFile' #-}
|
|
||||||
deleteFile' p = withTmpDir p deleteFile
|
|
||||||
|
|
||||||
|
|
||||||
deleteDir' :: ByteString -> IO ()
|
|
||||||
{-# NOINLINE deleteDir' #-}
|
|
||||||
deleteDir' p = withTmpDir p deleteDir
|
|
||||||
|
|
||||||
|
|
||||||
deleteDirRecursive' :: ByteString -> IO ()
|
|
||||||
{-# NOINLINE deleteDirRecursive' #-}
|
|
||||||
deleteDirRecursive' p = withTmpDir p deleteDirRecursive
|
|
||||||
|
|
||||||
|
|
||||||
canonicalizePath' :: ByteString -> IO ByteString
|
|
||||||
{-# NOINLINE canonicalizePath' #-}
|
|
||||||
canonicalizePath' p = withTmpDir p canonicalizePath
|
|
||||||
|
|
||||||
|
|
||||||
writeFile' :: ByteString -> ByteString -> IO ()
|
|
||||||
{-# NOINLINE writeFile' #-}
|
|
||||||
writeFile' ip bs =
|
|
||||||
withTmpDir ip $ \p -> writeFile p Nothing bs
|
|
||||||
|
|
||||||
writeFileL' :: ByteString -> BSL.ByteString -> IO ()
|
|
||||||
{-# NOINLINE writeFileL' #-}
|
|
||||||
writeFileL' ip bs =
|
|
||||||
withTmpDir ip $ \p -> writeFileL p Nothing bs
|
|
||||||
|
|
||||||
|
|
||||||
appendFile' :: ByteString -> ByteString -> IO ()
|
|
||||||
{-# NOINLINE appendFile' #-}
|
|
||||||
appendFile' ip bs =
|
|
||||||
withTmpDir ip $ \p -> appendFile p bs
|
|
||||||
|
|
||||||
|
|
||||||
allDirectoryContents' :: ByteString -> IO [ByteString]
|
|
||||||
{-# NOINLINE allDirectoryContents' #-}
|
|
||||||
allDirectoryContents' ip =
|
|
||||||
withTmpDir ip $ \p -> DT.allDirectoryContents' p
|
|
||||||
|
|
||||||
|
|
||||||
readFile' :: ByteString -> IO ByteString
|
|
||||||
{-# NOINLINE readFile' #-}
|
|
||||||
readFile' p = withTmpDir p (fmap L.toStrict . readFile)
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
|||||||
# Revision history for hpath-filepath
|
|
||||||
|
|
||||||
## 0.10.4 -- 2020-01-26
|
|
||||||
|
|
||||||
* Add `takeAllParents`
|
|
||||||
|
|
||||||
|
|
||||||
## 0.10.2 -- 2020-01-18
|
|
||||||
|
|
||||||
* Add `isSpecialDirectoryEntry`
|
|
||||||
|
|
||||||
## 0.10.0 -- 2020-01-04
|
|
||||||
|
|
||||||
* First version. Split from 'hpath', contains only the filepath ByteString manipulation parts.
|
|
@ -1,30 +0,0 @@
|
|||||||
Copyright (c) 2020, Julian Ospald
|
|
||||||
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following
|
|
||||||
disclaimer in the documentation and/or other materials provided
|
|
||||||
with the distribution.
|
|
||||||
|
|
||||||
* Neither the name of Julian Ospald nor the names of other
|
|
||||||
contributors may be used to endorse or promote products derived
|
|
||||||
from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,29 +0,0 @@
|
|||||||
# HPath-filepath
|
|
||||||
|
|
||||||
[![Gitter chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hasufell/hpath?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Hackage version](https://img.shields.io/hackage/v/hpath-filepath.svg?label=Hackage)](https://hackage.haskell.org/package/hpath-filepath) [![Build Status](https://api.travis-ci.org/hasufell/hpath.png?branch=master)](http://travis-ci.org/hasufell/hpath) [![Hackage-Deps](https://img.shields.io/hackage-deps/v/hpath-filepath.svg)](http://packdeps.haskellers.com/feed?needle=hpath-filepath)
|
|
||||||
|
|
||||||
Support for bytestring based filepath manipulation, similar to 'filepath'.
|
|
||||||
|
|
||||||
This package is part of the HPath suite, also check out:
|
|
||||||
|
|
||||||
* [hpath](https://hackage.haskell.org/package/hpath)
|
|
||||||
* [hpath-directory](https://hackage.haskell.org/package/hpath-directory)
|
|
||||||
* [hpath-io](https://hackage.haskell.org/package/hpath-io)
|
|
||||||
|
|
||||||
## Motivation
|
|
||||||
|
|
||||||
This is basically a fork of [posix-paths](https://github.com/JohnLato/posix-paths), which seemed to have stalled development.
|
|
||||||
|
|
||||||
There is also a similar library [filepath-bytestring](https://hackage.haskell.org/package/filepath-bytestring), but it doesn't follow an open development model and is cross-platform, which this library is not interested in.
|
|
||||||
|
|
||||||
## Differences to 'posix-paths'
|
|
||||||
|
|
||||||
* uses the `word8` package for save word8 literals instead of `OverloadedStrings`
|
|
||||||
* `hasTrailingPathSeparator` and `dropTrailingPathSeparator` behave in the same way as their `System.FilePath` counterpart
|
|
||||||
* has some additional functions
|
|
||||||
|
|
||||||
## Differences to 'filepath-bytestring'
|
|
||||||
|
|
||||||
* uses the `word8` package for save word8 literals instead of `OverloadedStrings`
|
|
||||||
* is not cross-platform (less odd code to maintain)
|
|
||||||
* has some additional functions
|
|
@ -1,2 +0,0 @@
|
|||||||
import Distribution.Simple
|
|
||||||
main = defaultMain
|
|
@ -1,39 +0,0 @@
|
|||||||
name: hpath-filepath
|
|
||||||
version: 0.10.4
|
|
||||||
synopsis: ByteString based filepath manipulation
|
|
||||||
description: ByteString based filepath manipulation, similar to 'filepath' package. This is POSIX only.
|
|
||||||
-- bug-reports:
|
|
||||||
license: BSD3
|
|
||||||
license-file: LICENSE
|
|
||||||
author: Julian Ospald <hasufell@posteo.de>
|
|
||||||
maintainer: Julian Ospald <hasufell@posteo.de>
|
|
||||||
copyright: Julian Ospald 2016
|
|
||||||
category: Filesystem
|
|
||||||
build-type: Simple
|
|
||||||
cabal-version: 1.14
|
|
||||||
tested-with: GHC==7.10.3
|
|
||||||
, GHC==8.0.2
|
|
||||||
, GHC==8.2.2
|
|
||||||
, GHC==8.4.4
|
|
||||||
, GHC==8.6.5
|
|
||||||
, GHC==8.8.1
|
|
||||||
extra-source-files: README.md
|
|
||||||
CHANGELOG.md
|
|
||||||
|
|
||||||
library
|
|
||||||
if os(windows)
|
|
||||||
build-depends: unbuildable<0
|
|
||||||
buildable: False
|
|
||||||
exposed-modules: System.Posix.FilePath
|
|
||||||
-- other-modules:
|
|
||||||
-- other-extensions:
|
|
||||||
build-depends: base >=4.8 && <5
|
|
||||||
, bytestring >= 0.10.0.0
|
|
||||||
, unix >= 2.5
|
|
||||||
, word8
|
|
||||||
hs-source-dirs: src
|
|
||||||
default-language: Haskell2010
|
|
||||||
|
|
||||||
source-repository head
|
|
||||||
type: git
|
|
||||||
location: https://github.com/hasufell/hpath
|
|
@ -1,23 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if [ -n "${SKIP_DOCTESTS}" ] ; then
|
|
||||||
echo "Skipping doctests"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! command -v doctest >/dev/null ; then
|
|
||||||
tempdir="$(mktemp -d)"
|
|
||||||
(
|
|
||||||
cd "${tempdir}"
|
|
||||||
cabal install --installdir="${tempdir}" doctest
|
|
||||||
)
|
|
||||||
export PATH="${tempdir}:$PATH"
|
|
||||||
fi
|
|
||||||
|
|
||||||
set -x
|
|
||||||
|
|
||||||
cd "$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P)"
|
|
||||||
|
|
||||||
cabal exec doctest -- -isrc -XOverloadedStrings System.Posix.FilePath
|
|
@ -1,859 +0,0 @@
|
|||||||
-- |
|
|
||||||
-- Module : System.Posix.FilePath
|
|
||||||
-- Copyright : © 2016 Julian Ospald
|
|
||||||
-- License : BSD3
|
|
||||||
--
|
|
||||||
-- Maintainer : Julian Ospald <hasufell@posteo.de>
|
|
||||||
-- Stability : experimental
|
|
||||||
-- Portability : portable
|
|
||||||
--
|
|
||||||
-- The equivalent of "System.FilePath" on raw (byte string) file paths.
|
|
||||||
--
|
|
||||||
-- Not all functions of "System.FilePath" are implemented yet. Feel free to contribute!
|
|
||||||
|
|
||||||
|
|
||||||
{-# LANGUAGE CPP #-}
|
|
||||||
{-# LANGUAGE TupleSections #-}
|
|
||||||
|
|
||||||
{-# OPTIONS_GHC -Wall #-}
|
|
||||||
|
|
||||||
|
|
||||||
module System.Posix.FilePath (
|
|
||||||
|
|
||||||
-- * Separator predicates
|
|
||||||
pathSeparator
|
|
||||||
, isPathSeparator
|
|
||||||
, searchPathSeparator
|
|
||||||
, isSearchPathSeparator
|
|
||||||
, extSeparator
|
|
||||||
, isExtSeparator
|
|
||||||
|
|
||||||
-- * $PATH methods
|
|
||||||
, splitSearchPath
|
|
||||||
, getSearchPath
|
|
||||||
|
|
||||||
-- * Extension functions
|
|
||||||
, splitExtension
|
|
||||||
, takeExtension
|
|
||||||
, replaceExtension
|
|
||||||
, dropExtension
|
|
||||||
, addExtension
|
|
||||||
, hasExtension
|
|
||||||
, (<.>)
|
|
||||||
, splitExtensions
|
|
||||||
, dropExtensions
|
|
||||||
, takeExtensions
|
|
||||||
, stripExtension
|
|
||||||
|
|
||||||
-- * Filename\/directory functions
|
|
||||||
, splitFileName
|
|
||||||
, takeFileName
|
|
||||||
, replaceFileName
|
|
||||||
, dropFileName
|
|
||||||
, takeBaseName
|
|
||||||
, replaceBaseName
|
|
||||||
, takeDirectory
|
|
||||||
, replaceDirectory
|
|
||||||
, combine
|
|
||||||
, (</>)
|
|
||||||
, splitPath
|
|
||||||
, joinPath
|
|
||||||
, splitDirectories
|
|
||||||
, takeAllParents
|
|
||||||
|
|
||||||
-- * Trailing slash functions
|
|
||||||
, hasTrailingPathSeparator
|
|
||||||
, addTrailingPathSeparator
|
|
||||||
, dropTrailingPathSeparator
|
|
||||||
|
|
||||||
-- * File name manipulations
|
|
||||||
, normalise
|
|
||||||
, makeRelative
|
|
||||||
, equalFilePath
|
|
||||||
, isRelative
|
|
||||||
, isAbsolute
|
|
||||||
, isValid
|
|
||||||
, makeValid
|
|
||||||
, isSpecialDirectoryEntry
|
|
||||||
, isFileName
|
|
||||||
, hasParentDir
|
|
||||||
, hiddenFile
|
|
||||||
|
|
||||||
, module System.Posix.ByteString.FilePath
|
|
||||||
) where
|
|
||||||
|
|
||||||
import Data.ByteString (ByteString)
|
|
||||||
import qualified Data.ByteString as BS
|
|
||||||
import Data.String (fromString)
|
|
||||||
import System.Posix.ByteString.FilePath
|
|
||||||
import qualified System.Posix.Env.ByteString as PE
|
|
||||||
|
|
||||||
import Data.Maybe (isJust)
|
|
||||||
import Data.Word8
|
|
||||||
#if !MIN_VERSION_bytestring(0,10,8)
|
|
||||||
import qualified Data.List as L
|
|
||||||
#endif
|
|
||||||
import Control.Arrow (second)
|
|
||||||
|
|
||||||
-- $setup
|
|
||||||
-- >>> import Data.Char
|
|
||||||
-- >>> import Data.Maybe
|
|
||||||
-- >>> import Data.Word8
|
|
||||||
-- >>> import Test.QuickCheck
|
|
||||||
-- >>> import Control.Applicative
|
|
||||||
-- >>> import qualified Data.ByteString as BS
|
|
||||||
-- >>> instance Arbitrary ByteString where arbitrary = BS.pack <$> arbitrary
|
|
||||||
-- >>> instance CoArbitrary ByteString where coarbitrary = coarbitrary . BS.unpack
|
|
||||||
--
|
|
||||||
-- >>> let _chr :: Word8 -> Char; _chr = chr . fromIntegral
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
------------------------
|
|
||||||
-- Separator predicates
|
|
||||||
|
|
||||||
|
|
||||||
-- | Path separator character
|
|
||||||
pathSeparator :: Word8
|
|
||||||
pathSeparator = _slash
|
|
||||||
|
|
||||||
|
|
||||||
-- | Check if a character is the path separator
|
|
||||||
--
|
|
||||||
-- prop> \n -> (_chr n == '/') == isPathSeparator n
|
|
||||||
isPathSeparator :: Word8 -> Bool
|
|
||||||
isPathSeparator = (== pathSeparator)
|
|
||||||
|
|
||||||
|
|
||||||
-- | Search path separator
|
|
||||||
searchPathSeparator :: Word8
|
|
||||||
searchPathSeparator = _colon
|
|
||||||
|
|
||||||
|
|
||||||
-- | Check if a character is the search path separator
|
|
||||||
--
|
|
||||||
-- prop> \n -> (_chr n == ':') == isSearchPathSeparator n
|
|
||||||
isSearchPathSeparator :: Word8 -> Bool
|
|
||||||
isSearchPathSeparator = (== searchPathSeparator)
|
|
||||||
|
|
||||||
|
|
||||||
-- | File extension separator
|
|
||||||
extSeparator :: Word8
|
|
||||||
extSeparator = _period
|
|
||||||
|
|
||||||
|
|
||||||
-- | Check if a character is the file extension separator
|
|
||||||
--
|
|
||||||
-- prop> \n -> (_chr n == '.') == isExtSeparator n
|
|
||||||
isExtSeparator :: Word8 -> Bool
|
|
||||||
isExtSeparator = (== extSeparator)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
------------------------
|
|
||||||
-- $PATH methods
|
|
||||||
|
|
||||||
|
|
||||||
-- | Take a ByteString, split it on the 'searchPathSeparator'.
|
|
||||||
-- Blank items are converted to @.@.
|
|
||||||
--
|
|
||||||
-- Follows the recommendations in
|
|
||||||
-- <http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html>
|
|
||||||
--
|
|
||||||
-- >>> splitSearchPath "File1:File2:File3"
|
|
||||||
-- ["File1","File2","File3"]
|
|
||||||
-- >>> splitSearchPath "File1::File2:File3"
|
|
||||||
-- ["File1",".","File2","File3"]
|
|
||||||
-- >>> splitSearchPath ""
|
|
||||||
-- ["."]
|
|
||||||
splitSearchPath :: ByteString -> [RawFilePath]
|
|
||||||
splitSearchPath = f
|
|
||||||
where
|
|
||||||
f bs = let (pre, post) = BS.break isSearchPathSeparator bs
|
|
||||||
in if BS.null post
|
|
||||||
then g pre
|
|
||||||
else g pre ++ f (BS.tail post)
|
|
||||||
g x
|
|
||||||
| BS.null x = [BS.singleton _period]
|
|
||||||
| otherwise = [x]
|
|
||||||
|
|
||||||
|
|
||||||
-- | Get a list of 'RawFilePath's in the $PATH variable.
|
|
||||||
getSearchPath :: IO [RawFilePath]
|
|
||||||
getSearchPath = fmap (maybe [] splitSearchPath) (PE.getEnv $ fromString "PATH")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
------------------------
|
|
||||||
-- Extension functions
|
|
||||||
|
|
||||||
-- | Split a 'RawFilePath' into a path+filename and extension
|
|
||||||
--
|
|
||||||
-- >>> splitExtension "file.exe"
|
|
||||||
-- ("file",".exe")
|
|
||||||
-- >>> splitExtension "file"
|
|
||||||
-- ("file","")
|
|
||||||
-- >>> splitExtension "/path/file.tar.gz"
|
|
||||||
-- ("/path/file.tar",".gz")
|
|
||||||
--
|
|
||||||
-- prop> \path -> uncurry (BS.append) (splitExtension path) == path
|
|
||||||
splitExtension :: RawFilePath -> (RawFilePath, ByteString)
|
|
||||||
splitExtension x = if BS.null basename
|
|
||||||
then (x,BS.empty)
|
|
||||||
else (BS.append path (BS.init basename),BS.cons extSeparator fileExt)
|
|
||||||
where
|
|
||||||
(path,file) = splitFileNameRaw x
|
|
||||||
(basename,fileExt) = BS.breakEnd isExtSeparator file
|
|
||||||
|
|
||||||
|
|
||||||
-- | Get the final extension from a 'RawFilePath'
|
|
||||||
--
|
|
||||||
-- >>> takeExtension "file.exe"
|
|
||||||
-- ".exe"
|
|
||||||
-- >>> takeExtension "file"
|
|
||||||
-- ""
|
|
||||||
-- >>> takeExtension "/path/file.tar.gz"
|
|
||||||
-- ".gz"
|
|
||||||
takeExtension :: RawFilePath -> ByteString
|
|
||||||
takeExtension = snd . splitExtension
|
|
||||||
|
|
||||||
|
|
||||||
-- | Change a file's extension
|
|
||||||
--
|
|
||||||
-- prop> \path -> let ext = takeExtension path in replaceExtension path ext == path
|
|
||||||
replaceExtension :: RawFilePath -> ByteString -> RawFilePath
|
|
||||||
replaceExtension path ext = dropExtension path <.> ext
|
|
||||||
|
|
||||||
|
|
||||||
-- | Drop the final extension from a 'RawFilePath'
|
|
||||||
--
|
|
||||||
-- >>> dropExtension "file.exe"
|
|
||||||
-- "file"
|
|
||||||
-- >>> dropExtension "file"
|
|
||||||
-- "file"
|
|
||||||
-- >>> dropExtension "/path/file.tar.gz"
|
|
||||||
-- "/path/file.tar"
|
|
||||||
dropExtension :: RawFilePath -> RawFilePath
|
|
||||||
dropExtension = fst . splitExtension
|
|
||||||
|
|
||||||
|
|
||||||
-- | Add an extension to a 'RawFilePath'
|
|
||||||
--
|
|
||||||
-- >>> addExtension "file" ".exe"
|
|
||||||
-- "file.exe"
|
|
||||||
-- >>> addExtension "file.tar" ".gz"
|
|
||||||
-- "file.tar.gz"
|
|
||||||
-- >>> addExtension "/path/" ".ext"
|
|
||||||
-- "/path/.ext"
|
|
||||||
addExtension :: RawFilePath -> ByteString -> RawFilePath
|
|
||||||
addExtension file ext
|
|
||||||
| BS.null ext = file
|
|
||||||
| isExtSeparator (BS.head ext) = BS.append file ext
|
|
||||||
| otherwise = BS.intercalate (BS.singleton extSeparator) [file, ext]
|
|
||||||
|
|
||||||
|
|
||||||
-- | Check if a 'RawFilePath' has an extension
|
|
||||||
--
|
|
||||||
-- >>> hasExtension "file"
|
|
||||||
-- False
|
|
||||||
-- >>> hasExtension "file.tar"
|
|
||||||
-- True
|
|
||||||
-- >>> hasExtension "/path.part1/"
|
|
||||||
-- False
|
|
||||||
hasExtension :: RawFilePath -> Bool
|
|
||||||
hasExtension = isJust . BS.elemIndex extSeparator . takeFileName
|
|
||||||
|
|
||||||
|
|
||||||
-- | Operator version of 'addExtension'
|
|
||||||
(<.>) :: RawFilePath -> ByteString -> RawFilePath
|
|
||||||
(<.>) = addExtension
|
|
||||||
|
|
||||||
|
|
||||||
-- | Split a 'RawFilePath' on the first extension.
|
|
||||||
--
|
|
||||||
-- >>> splitExtensions "/path/file.tar.gz"
|
|
||||||
-- ("/path/file",".tar.gz")
|
|
||||||
--
|
|
||||||
-- prop> \path -> uncurry addExtension (splitExtensions path) == path
|
|
||||||
splitExtensions :: RawFilePath -> (RawFilePath, ByteString)
|
|
||||||
splitExtensions x = if BS.null basename
|
|
||||||
then (path,fileExt)
|
|
||||||
else (BS.append path basename,fileExt)
|
|
||||||
where
|
|
||||||
(path,file) = splitFileNameRaw x
|
|
||||||
(basename,fileExt) = BS.break isExtSeparator file
|
|
||||||
|
|
||||||
|
|
||||||
-- | Remove all extensions from a 'RawFilePath'
|
|
||||||
--
|
|
||||||
-- >>> dropExtensions "/path/file.tar.gz"
|
|
||||||
-- "/path/file"
|
|
||||||
dropExtensions :: RawFilePath -> RawFilePath
|
|
||||||
dropExtensions = fst . splitExtensions
|
|
||||||
|
|
||||||
|
|
||||||
-- | Take all extensions from a 'RawFilePath'
|
|
||||||
--
|
|
||||||
-- >>> takeExtensions "/path/file.tar.gz"
|
|
||||||
-- ".tar.gz"
|
|
||||||
takeExtensions :: RawFilePath -> ByteString
|
|
||||||
takeExtensions = snd . splitExtensions
|
|
||||||
|
|
||||||
|
|
||||||
-- | Drop the given extension from a FilePath, and the @\".\"@ preceding it.
|
|
||||||
-- Returns 'Nothing' if the FilePath does not have the given extension, or
|
|
||||||
-- 'Just' and the part before the extension if it does.
|
|
||||||
--
|
|
||||||
-- This function can be more predictable than 'dropExtensions',
|
|
||||||
-- especially if the filename might itself contain @.@ characters.
|
|
||||||
--
|
|
||||||
-- >>> stripExtension "hs.o" "foo.x.hs.o"
|
|
||||||
-- Just "foo.x"
|
|
||||||
-- >>> stripExtension "hi.o" "foo.x.hs.o"
|
|
||||||
-- Nothing
|
|
||||||
-- >>> stripExtension ".c.d" "a.b.c.d"
|
|
||||||
-- Just "a.b"
|
|
||||||
-- >>> stripExtension ".c.d" "a.b..c.d"
|
|
||||||
-- Just "a.b."
|
|
||||||
-- >>> stripExtension "baz" "foo.bar"
|
|
||||||
-- Nothing
|
|
||||||
-- >>> stripExtension "bar" "foobar"
|
|
||||||
-- Nothing
|
|
||||||
--
|
|
||||||
-- prop> \path -> stripExtension "" path == Just path
|
|
||||||
-- prop> \path -> dropExtension path == fromJust (stripExtension (takeExtension path) path)
|
|
||||||
-- prop> \path -> dropExtensions path == fromJust (stripExtension (takeExtensions path) path)
|
|
||||||
stripExtension :: ByteString -> RawFilePath -> Maybe RawFilePath
|
|
||||||
stripExtension bs path
|
|
||||||
| BS.null bs = Just path
|
|
||||||
| otherwise = stripSuffix' dotExt path
|
|
||||||
where
|
|
||||||
dotExt = if isExtSeparator $ BS.head bs
|
|
||||||
then bs
|
|
||||||
else extSeparator `BS.cons` bs
|
|
||||||
#if MIN_VERSION_bytestring(0,10,8)
|
|
||||||
stripSuffix' = BS.stripSuffix
|
|
||||||
#else
|
|
||||||
stripSuffix' xs ys = fmap (BS.pack . reverse) $ L.stripPrefix (reverse $ BS.unpack xs) (reverse $ BS.unpack ys)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
------------------------
|
|
||||||
-- Filename/directory functions
|
|
||||||
|
|
||||||
|
|
||||||
-- | Split a 'RawFilePath' into (path,file). 'combine' is the inverse
|
|
||||||
--
|
|
||||||
-- >>> splitFileName "path/file.txt"
|
|
||||||
-- ("path/","file.txt")
|
|
||||||
-- >>> splitFileName "path/"
|
|
||||||
-- ("path/","")
|
|
||||||
-- >>> splitFileName "file.txt"
|
|
||||||
-- ("./","file.txt")
|
|
||||||
--
|
|
||||||
-- prop> \path -> uncurry combine (splitFileName path) == path || fst (splitFileName path) == "./"
|
|
||||||
splitFileName :: RawFilePath -> (RawFilePath, RawFilePath)
|
|
||||||
splitFileName x = if BS.null path
|
|
||||||
then (dotSlash, file)
|
|
||||||
else (path,file)
|
|
||||||
where
|
|
||||||
(path,file) = splitFileNameRaw x
|
|
||||||
dotSlash = _period `BS.cons` (BS.singleton pathSeparator)
|
|
||||||
|
|
||||||
|
|
||||||
-- | Get the file name
|
|
||||||
--
|
|
||||||
-- >>> takeFileName "path/file.txt"
|
|
||||||
-- "file.txt"
|
|
||||||
-- >>> takeFileName "path/"
|
|
||||||
-- ""
|
|
||||||
takeFileName :: RawFilePath -> RawFilePath
|
|
||||||
takeFileName = snd . splitFileName
|
|
||||||
|
|
||||||
|
|
||||||
-- | Change the file name
|
|
||||||
--
|
|
||||||
-- prop> \path -> replaceFileName path (takeFileName path) == path
|
|
||||||
replaceFileName :: RawFilePath -> ByteString -> RawFilePath
|
|
||||||
replaceFileName x y = fst (splitFileNameRaw x) </> y
|
|
||||||
|
|
||||||
|
|
||||||
-- | Drop the file name
|
|
||||||
--
|
|
||||||
-- >>> dropFileName "path/file.txt"
|
|
||||||
-- "path/"
|
|
||||||
-- >>> dropFileName "file.txt"
|
|
||||||
-- "./"
|
|
||||||
dropFileName :: RawFilePath -> RawFilePath
|
|
||||||
dropFileName = fst . splitFileName
|
|
||||||
|
|
||||||
|
|
||||||
-- | Get the file name, without a trailing extension
|
|
||||||
--
|
|
||||||
-- >>> takeBaseName "path/file.tar.gz"
|
|
||||||
-- "file.tar"
|
|
||||||
-- >>> takeBaseName ""
|
|
||||||
-- ""
|
|
||||||
takeBaseName :: RawFilePath -> ByteString
|
|
||||||
takeBaseName = dropExtension . takeFileName
|
|
||||||
|
|
||||||
|
|
||||||
-- | Change the base name
|
|
||||||
--
|
|
||||||
-- >>> replaceBaseName "path/file.tar.gz" "bob"
|
|
||||||
-- "path/bob.gz"
|
|
||||||
--
|
|
||||||
-- prop> \path -> replaceBaseName path (takeBaseName path) == path
|
|
||||||
replaceBaseName :: RawFilePath -> ByteString -> RawFilePath
|
|
||||||
replaceBaseName path name = combineRaw dir (name <.> ext)
|
|
||||||
where
|
|
||||||
(dir,file) = splitFileNameRaw path
|
|
||||||
ext = takeExtension file
|
|
||||||
|
|
||||||
|
|
||||||
-- | Get the directory, moving up one level if it's already a directory
|
|
||||||
--
|
|
||||||
-- >>> takeDirectory "path/file.txt"
|
|
||||||
-- "path"
|
|
||||||
-- >>> takeDirectory "file"
|
|
||||||
-- "."
|
|
||||||
-- >>> takeDirectory "/path/to/"
|
|
||||||
-- "/path/to"
|
|
||||||
-- >>> takeDirectory "/path/to"
|
|
||||||
-- "/path"
|
|
||||||
takeDirectory :: RawFilePath -> RawFilePath
|
|
||||||
takeDirectory x = case () of
|
|
||||||
() | x == BS.singleton pathSeparator -> x
|
|
||||||
| BS.null res && not (BS.null file) -> file
|
|
||||||
| otherwise -> res
|
|
||||||
where
|
|
||||||
res = fst $ BS.spanEnd isPathSeparator file
|
|
||||||
file = dropFileName x
|
|
||||||
|
|
||||||
|
|
||||||
-- | Change the directory component of a 'RawFilePath'
|
|
||||||
--
|
|
||||||
-- prop> \path -> replaceDirectory path (takeDirectory path) `equalFilePath` path || takeDirectory path == "."
|
|
||||||
replaceDirectory :: RawFilePath -> ByteString -> RawFilePath
|
|
||||||
replaceDirectory file dir = combineRaw dir (takeFileName file)
|
|
||||||
|
|
||||||
|
|
||||||
-- | Join two paths together
|
|
||||||
--
|
|
||||||
-- >>> combine "/" "file"
|
|
||||||
-- "/file"
|
|
||||||
-- >>> combine "/path/to" "file"
|
|
||||||
-- "/path/to/file"
|
|
||||||
-- >>> combine "file" "/absolute/path"
|
|
||||||
-- "/absolute/path"
|
|
||||||
combine :: RawFilePath -> RawFilePath -> RawFilePath
|
|
||||||
combine a b | not (BS.null b) && isPathSeparator (BS.head b) = b
|
|
||||||
| otherwise = combineRaw a b
|
|
||||||
|
|
||||||
|
|
||||||
-- | Operator version of combine
|
|
||||||
(</>) :: RawFilePath -> RawFilePath -> RawFilePath
|
|
||||||
(</>) = combine
|
|
||||||
|
|
||||||
-- | Split a path into a list of components:
|
|
||||||
--
|
|
||||||
-- >>> splitPath "/path/to/file.txt"
|
|
||||||
-- ["/","path/","to/","file.txt"]
|
|
||||||
--
|
|
||||||
-- prop> \path -> BS.concat (splitPath path) == path
|
|
||||||
splitPath :: RawFilePath -> [RawFilePath]
|
|
||||||
splitPath = splitter
|
|
||||||
where
|
|
||||||
splitter x
|
|
||||||
| BS.null x = []
|
|
||||||
| otherwise = case BS.elemIndex pathSeparator x of
|
|
||||||
Nothing -> [x]
|
|
||||||
Just ix -> case BS.findIndex (not . isPathSeparator) $ BS.drop (ix+1) x of
|
|
||||||
Nothing -> [x]
|
|
||||||
Just runlen -> uncurry (:) . second splitter $ BS.splitAt (ix+1+runlen) x
|
|
||||||
|
|
||||||
|
|
||||||
-- | Join a split path back together
|
|
||||||
--
|
|
||||||
-- prop> \path -> joinPath (splitPath path) == path
|
|
||||||
--
|
|
||||||
-- >>> joinPath ["path","to","file.txt"]
|
|
||||||
-- "path/to/file.txt"
|
|
||||||
joinPath :: [RawFilePath] -> RawFilePath
|
|
||||||
joinPath = foldr (</>) BS.empty
|
|
||||||
|
|
||||||
|
|
||||||
-- | Like 'splitPath', but without trailing slashes
|
|
||||||
--
|
|
||||||
-- >>> splitDirectories "/path/to/file.txt"
|
|
||||||
-- ["/","path","to","file.txt"]
|
|
||||||
-- >>> splitDirectories "path/to/file.txt"
|
|
||||||
-- ["path","to","file.txt"]
|
|
||||||
-- >>> splitDirectories ""
|
|
||||||
-- []
|
|
||||||
splitDirectories :: RawFilePath -> [RawFilePath]
|
|
||||||
splitDirectories x
|
|
||||||
| BS.null x = []
|
|
||||||
| isPathSeparator (BS.head x) = let (root,rest) = BS.splitAt 1 x
|
|
||||||
in root : splitter rest
|
|
||||||
| otherwise = splitter x
|
|
||||||
where
|
|
||||||
splitter = filter (not . BS.null) . BS.split pathSeparator
|
|
||||||
|
|
||||||
|
|
||||||
-- |Get all parents of a path.
|
|
||||||
--
|
|
||||||
-- >>> takeAllParents "/abs/def/dod"
|
|
||||||
-- ["/abs/def","/abs","/"]
|
|
||||||
-- >>> takeAllParents "/foo"
|
|
||||||
-- ["/"]
|
|
||||||
-- >>> takeAllParents "/"
|
|
||||||
-- []
|
|
||||||
takeAllParents :: RawFilePath -> [RawFilePath]
|
|
||||||
takeAllParents p
|
|
||||||
| np == BS.singleton pathSeparator = []
|
|
||||||
| otherwise = takeDirectory np : takeAllParents (takeDirectory np)
|
|
||||||
where
|
|
||||||
np = normalise p
|
|
||||||
|
|
||||||
|
|
||||||
------------------------
|
|
||||||
-- Trailing slash functions
|
|
||||||
|
|
||||||
-- | Check if the last character of a 'RawFilePath' is '/'.
|
|
||||||
--
|
|
||||||
-- >>> hasTrailingPathSeparator "/path/"
|
|
||||||
-- True
|
|
||||||
-- >>> hasTrailingPathSeparator "/"
|
|
||||||
-- True
|
|
||||||
-- >>> hasTrailingPathSeparator "/path"
|
|
||||||
-- False
|
|
||||||
hasTrailingPathSeparator :: RawFilePath -> Bool
|
|
||||||
hasTrailingPathSeparator x
|
|
||||||
| BS.null x = False
|
|
||||||
| otherwise = isPathSeparator $ BS.last x
|
|
||||||
|
|
||||||
|
|
||||||
-- | Add a trailing path separator.
|
|
||||||
--
|
|
||||||
-- >>> addTrailingPathSeparator "/path"
|
|
||||||
-- "/path/"
|
|
||||||
-- >>> addTrailingPathSeparator "/path/"
|
|
||||||
-- "/path/"
|
|
||||||
-- >>> addTrailingPathSeparator "/"
|
|
||||||
-- "/"
|
|
||||||
addTrailingPathSeparator :: RawFilePath -> RawFilePath
|
|
||||||
addTrailingPathSeparator x = if hasTrailingPathSeparator x
|
|
||||||
then x
|
|
||||||
else x `BS.snoc` pathSeparator
|
|
||||||
|
|
||||||
|
|
||||||
-- | Remove a trailing path separator
|
|
||||||
--
|
|
||||||
-- >>> dropTrailingPathSeparator "/path/"
|
|
||||||
-- "/path"
|
|
||||||
-- >>> dropTrailingPathSeparator "/path////"
|
|
||||||
-- "/path"
|
|
||||||
-- >>> dropTrailingPathSeparator "/"
|
|
||||||
-- "/"
|
|
||||||
-- >>> dropTrailingPathSeparator "//"
|
|
||||||
-- "/"
|
|
||||||
dropTrailingPathSeparator :: RawFilePath -> RawFilePath
|
|
||||||
dropTrailingPathSeparator x
|
|
||||||
| x == BS.singleton pathSeparator = x
|
|
||||||
| otherwise = if hasTrailingPathSeparator x
|
|
||||||
then dropTrailingPathSeparator $ BS.init x
|
|
||||||
else x
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
------------------------
|
|
||||||
-- File name manipulations
|
|
||||||
|
|
||||||
|
|
||||||
-- |Normalise a file.
|
|
||||||
--
|
|
||||||
-- >>> normalise "/file/\\test////"
|
|
||||||
-- "/file/\\test/"
|
|
||||||
-- >>> normalise "/file/./test"
|
|
||||||
-- "/file/test"
|
|
||||||
-- >>> normalise "/test/file/../bob/fred/"
|
|
||||||
-- "/test/file/../bob/fred/"
|
|
||||||
-- >>> normalise "../bob/fred/"
|
|
||||||
-- "../bob/fred/"
|
|
||||||
-- >>> normalise "./bob/fred/"
|
|
||||||
-- "bob/fred/"
|
|
||||||
-- >>> normalise "./bob////.fred/./...///./..///#."
|
|
||||||
-- "bob/.fred/.../../#."
|
|
||||||
-- >>> normalise "."
|
|
||||||
-- "."
|
|
||||||
-- >>> normalise "./"
|
|
||||||
-- "./"
|
|
||||||
-- >>> normalise "./."
|
|
||||||
-- "./"
|
|
||||||
-- >>> normalise "/./"
|
|
||||||
-- "/"
|
|
||||||
-- >>> normalise "/"
|
|
||||||
-- "/"
|
|
||||||
-- >>> normalise "bob/fred/."
|
|
||||||
-- "bob/fred/"
|
|
||||||
-- >>> normalise "//home"
|
|
||||||
-- "/home"
|
|
||||||
normalise :: RawFilePath -> RawFilePath
|
|
||||||
normalise filepath =
|
|
||||||
result `BS.append`
|
|
||||||
(if addPathSeparator
|
|
||||||
then BS.singleton pathSeparator
|
|
||||||
else BS.empty)
|
|
||||||
where
|
|
||||||
result = let n = f filepath
|
|
||||||
in if BS.null n
|
|
||||||
then BS.singleton _period
|
|
||||||
else n
|
|
||||||
addPathSeparator = isDirPath filepath &&
|
|
||||||
not (hasTrailingPathSeparator result)
|
|
||||||
isDirPath xs = hasTrailingPathSeparator xs
|
|
||||||
|| not (BS.null xs) && BS.last xs == _period
|
|
||||||
&& hasTrailingPathSeparator (BS.init xs)
|
|
||||||
f = joinPath . dropDots . propSep . splitDirectories
|
|
||||||
propSep :: [ByteString] -> [ByteString]
|
|
||||||
propSep (x:xs)
|
|
||||||
| BS.all (== pathSeparator) x = BS.singleton pathSeparator : xs
|
|
||||||
| otherwise = x : xs
|
|
||||||
propSep [] = []
|
|
||||||
dropDots :: [ByteString] -> [ByteString]
|
|
||||||
dropDots = filter (BS.singleton _period /=)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- | Contract a filename, based on a relative path. Note that the resulting
|
|
||||||
-- path will never introduce @..@ paths, as the presence of symlinks
|
|
||||||
-- means @..\/b@ may not reach @a\/b@ if it starts from @a\/c@. For a
|
|
||||||
-- worked example see
|
|
||||||
-- <http://neilmitchell.blogspot.co.uk/2015/10/filepaths-are-subtle-symlinks-are-hard.html this blog post>.
|
|
||||||
--
|
|
||||||
-- >>> makeRelative "/directory" "/directory/file.ext"
|
|
||||||
-- "file.ext"
|
|
||||||
-- >>> makeRelative "/Home" "/home/bob"
|
|
||||||
-- "/home/bob"
|
|
||||||
-- >>> makeRelative "/home/" "/home/bob/foo/bar"
|
|
||||||
-- "bob/foo/bar"
|
|
||||||
-- >>> makeRelative "/fred" "bob"
|
|
||||||
-- "bob"
|
|
||||||
-- >>> makeRelative "/file/test" "/file/test/fred"
|
|
||||||
-- "fred"
|
|
||||||
-- >>> makeRelative "/file/test" "/file/test/fred/"
|
|
||||||
-- "fred/"
|
|
||||||
-- >>> makeRelative "some/path" "some/path/a/b/c"
|
|
||||||
-- "a/b/c"
|
|
||||||
--
|
|
||||||
-- prop> \p -> makeRelative p p == "."
|
|
||||||
-- prop> \p -> makeRelative (takeDirectory p) p `equalFilePath` takeFileName p
|
|
||||||
-- prop \x y -> equalFilePath x y || (isRelative x && makeRelative y x == x) || equalFilePath (y </> makeRelative y x) x
|
|
||||||
makeRelative :: RawFilePath -> RawFilePath -> RawFilePath
|
|
||||||
makeRelative root path
|
|
||||||
| equalFilePath root path = BS.singleton _period
|
|
||||||
| takeAbs root /= takeAbs path = path
|
|
||||||
| otherwise = f (dropAbs root) (dropAbs path)
|
|
||||||
where
|
|
||||||
f x y
|
|
||||||
| BS.null x = BS.dropWhile isPathSeparator y
|
|
||||||
| otherwise = let (x1,x2) = g x
|
|
||||||
(y1,y2) = g y
|
|
||||||
in if equalFilePath x1 y1 then f x2 y2 else path
|
|
||||||
g x = (BS.dropWhile isPathSeparator a, BS.dropWhile isPathSeparator b)
|
|
||||||
where (a, b) = BS.break isPathSeparator $ BS.dropWhile isPathSeparator x
|
|
||||||
dropAbs x = snd $ BS.span (== _slash) x
|
|
||||||
takeAbs x = fst $ BS.span (== _slash) x
|
|
||||||
|
|
||||||
|
|
||||||
-- |Equality of two filepaths. The filepaths are normalised
|
|
||||||
-- and trailing path separators are dropped.
|
|
||||||
--
|
|
||||||
-- >>> equalFilePath "foo" "foo"
|
|
||||||
-- True
|
|
||||||
-- >>> equalFilePath "foo" "foo/"
|
|
||||||
-- True
|
|
||||||
-- >>> equalFilePath "foo" "./foo"
|
|
||||||
-- True
|
|
||||||
-- >>> equalFilePath "" ""
|
|
||||||
-- True
|
|
||||||
-- >>> equalFilePath "foo" "/foo"
|
|
||||||
-- False
|
|
||||||
-- >>> equalFilePath "foo" "FOO"
|
|
||||||
-- False
|
|
||||||
-- >>> equalFilePath "foo" "../foo"
|
|
||||||
-- False
|
|
||||||
--
|
|
||||||
-- prop> \p -> equalFilePath p p
|
|
||||||
equalFilePath :: RawFilePath -> RawFilePath -> Bool
|
|
||||||
equalFilePath p1 p2 = f p1 == f p2
|
|
||||||
where
|
|
||||||
f x = dropTrailingPathSeparator $ normalise x
|
|
||||||
|
|
||||||
|
|
||||||
-- | Check if a path is relative
|
|
||||||
--
|
|
||||||
-- prop> \path -> isRelative path /= isAbsolute path
|
|
||||||
isRelative :: RawFilePath -> Bool
|
|
||||||
isRelative = not . isAbsolute
|
|
||||||
|
|
||||||
|
|
||||||
-- | Check if a path is absolute
|
|
||||||
--
|
|
||||||
-- >>> isAbsolute "/path"
|
|
||||||
-- True
|
|
||||||
-- >>> isAbsolute "path"
|
|
||||||
-- False
|
|
||||||
-- >>> isAbsolute ""
|
|
||||||
-- False
|
|
||||||
isAbsolute :: RawFilePath -> Bool
|
|
||||||
isAbsolute x
|
|
||||||
| BS.length x > 0 = isPathSeparator (BS.head x)
|
|
||||||
| otherwise = False
|
|
||||||
|
|
||||||
|
|
||||||
-- | Is a FilePath valid, i.e. could you create a file like it?
|
|
||||||
--
|
|
||||||
-- >>> isValid ""
|
|
||||||
-- False
|
|
||||||
-- >>> isValid "\0"
|
|
||||||
-- False
|
|
||||||
-- >>> isValid "/random_ path:*"
|
|
||||||
-- True
|
|
||||||
isValid :: RawFilePath -> Bool
|
|
||||||
isValid filepath
|
|
||||||
| BS.null filepath = False
|
|
||||||
| _nul `BS.elem` filepath = False
|
|
||||||
| otherwise = True
|
|
||||||
|
|
||||||
|
|
||||||
-- | Take a FilePath and make it valid; does not change already valid FilePaths.
|
|
||||||
--
|
|
||||||
-- >>> makeValid ""
|
|
||||||
-- "_"
|
|
||||||
-- >>> makeValid "file\0name"
|
|
||||||
-- "file_name"
|
|
||||||
--
|
|
||||||
-- prop> \p -> if isValid p then makeValid p == p else makeValid p /= p
|
|
||||||
-- prop> \p -> isValid (makeValid p)
|
|
||||||
makeValid :: RawFilePath -> RawFilePath
|
|
||||||
makeValid path
|
|
||||||
| BS.null path = BS.singleton _underscore
|
|
||||||
| otherwise = BS.map (\x -> if x == _nul then _underscore else x) path
|
|
||||||
|
|
||||||
|
|
||||||
-- | Whether the filename is a special directory entry
|
|
||||||
-- (. and ..). Does not normalise filepaths.
|
|
||||||
--
|
|
||||||
-- >>> isSpecialDirectoryEntry "."
|
|
||||||
-- True
|
|
||||||
-- >>> isSpecialDirectoryEntry ".."
|
|
||||||
-- True
|
|
||||||
-- >>> isSpecialDirectoryEntry "/random_ path:*"
|
|
||||||
-- False
|
|
||||||
isSpecialDirectoryEntry :: RawFilePath -> Bool
|
|
||||||
isSpecialDirectoryEntry filepath
|
|
||||||
| BS.pack [_period, _period] == filepath = True
|
|
||||||
| BS.pack [_period] == filepath = True
|
|
||||||
| otherwise = False
|
|
||||||
|
|
||||||
|
|
||||||
-- | Is the given path a valid filename? This includes
|
|
||||||
-- "." and "..".
|
|
||||||
--
|
|
||||||
-- >>> isFileName "lal"
|
|
||||||
-- True
|
|
||||||
-- >>> isFileName "."
|
|
||||||
-- True
|
|
||||||
-- >>> isFileName ".."
|
|
||||||
-- True
|
|
||||||
-- >>> isFileName ""
|
|
||||||
-- False
|
|
||||||
-- >>> isFileName "\0"
|
|
||||||
-- False
|
|
||||||
-- >>> isFileName "/random_ path:*"
|
|
||||||
-- False
|
|
||||||
isFileName :: RawFilePath -> Bool
|
|
||||||
isFileName filepath =
|
|
||||||
not (BS.singleton pathSeparator `BS.isInfixOf` filepath) &&
|
|
||||||
not (BS.null filepath) &&
|
|
||||||
not (_nul `BS.elem` filepath)
|
|
||||||
|
|
||||||
|
|
||||||
-- | Check if the filepath has any parent directories in it.
|
|
||||||
--
|
|
||||||
-- >>> hasParentDir "/.."
|
|
||||||
-- True
|
|
||||||
-- >>> hasParentDir "foo/bar/.."
|
|
||||||
-- True
|
|
||||||
-- >>> hasParentDir "foo/../bar/."
|
|
||||||
-- True
|
|
||||||
-- >>> hasParentDir "foo/bar"
|
|
||||||
-- False
|
|
||||||
-- >>> hasParentDir "foo"
|
|
||||||
-- False
|
|
||||||
-- >>> hasParentDir ""
|
|
||||||
-- False
|
|
||||||
-- >>> hasParentDir ".."
|
|
||||||
-- False
|
|
||||||
hasParentDir :: RawFilePath -> Bool
|
|
||||||
hasParentDir filepath =
|
|
||||||
(pathSeparator `BS.cons` pathDoubleDot)
|
|
||||||
`BS.isSuffixOf` filepath
|
|
||||||
||
|
|
||||||
(BS.singleton pathSeparator
|
|
||||||
`BS.append` pathDoubleDot
|
|
||||||
`BS.append` BS.singleton pathSeparator)
|
|
||||||
`BS.isInfixOf` filepath
|
|
||||||
||
|
|
||||||
(pathDoubleDot `BS.append` BS.singleton pathSeparator)
|
|
||||||
`BS.isPrefixOf` filepath
|
|
||||||
where
|
|
||||||
pathDoubleDot = BS.pack [_period, _period]
|
|
||||||
|
|
||||||
|
|
||||||
-- | Whether the file is a hidden file.
|
|
||||||
--
|
|
||||||
-- >>> hiddenFile ".foo"
|
|
||||||
-- True
|
|
||||||
-- >>> hiddenFile "..foo.bar"
|
|
||||||
-- True
|
|
||||||
-- >>> hiddenFile "some/path/.bar"
|
|
||||||
-- True
|
|
||||||
-- >>> hiddenFile "..."
|
|
||||||
-- True
|
|
||||||
-- >>> hiddenFile "dod.bar"
|
|
||||||
-- False
|
|
||||||
-- >>> hiddenFile "."
|
|
||||||
-- False
|
|
||||||
-- >>> hiddenFile ".."
|
|
||||||
-- False
|
|
||||||
-- >>> hiddenFile ""
|
|
||||||
-- False
|
|
||||||
hiddenFile :: RawFilePath -> Bool
|
|
||||||
hiddenFile fp
|
|
||||||
| fn == BS.pack [_period, _period] = False
|
|
||||||
| fn == BS.pack [_period] = False
|
|
||||||
| otherwise = BS.pack [extSeparator]
|
|
||||||
`BS.isPrefixOf` fn
|
|
||||||
where
|
|
||||||
fn = takeFileName fp
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
------------------------
|
|
||||||
-- internal stuff
|
|
||||||
|
|
||||||
-- Just split the input FileName without adding/normalizing or changing
|
|
||||||
-- anything.
|
|
||||||
splitFileNameRaw :: RawFilePath -> (RawFilePath, RawFilePath)
|
|
||||||
splitFileNameRaw = BS.breakEnd isPathSeparator
|
|
||||||
|
|
||||||
-- | Combine two paths, assuming rhs is NOT absolute.
|
|
||||||
combineRaw :: RawFilePath -> RawFilePath -> RawFilePath
|
|
||||||
combineRaw a b | BS.null a = b
|
|
||||||
| BS.null b = a
|
|
||||||
| isPathSeparator (BS.last a) = BS.append a b
|
|
||||||
| otherwise = BS.intercalate (BS.singleton pathSeparator) [a, b]
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
|||||||
# Revision history for hpath-io
|
|
||||||
|
|
||||||
## 0.13.2 -- 2020-05-08
|
|
||||||
|
|
||||||
* Add getDirsFilesStream and use streamly-posix for dircontents (#34)
|
|
||||||
|
|
||||||
## 0.13.0 -- 2020-01-26
|
|
||||||
|
|
||||||
* switch to using 'hpath-bytestring' for the implementation (this is now just a wrapper module, mostly)
|
|
||||||
|
|
||||||
## 0.12.0 -- 2020-01-20
|
|
||||||
|
|
||||||
* breaking API changes
|
|
||||||
* RelC and Fn were removed from `hpath`
|
|
||||||
* further changes to `parseAny`
|
|
||||||
|
|
||||||
|
|
||||||
## 0.11.0 -- 2020-01-18
|
|
||||||
|
|
||||||
* `writeFile` not allows to set file mode and create file if it does not exist (this broke API)
|
|
||||||
* added various new functions:
|
|
||||||
* createDirIfMissing
|
|
||||||
* writeFileL (for lazy bytestring)
|
|
||||||
* isReadable
|
|
||||||
* isExecutable
|
|
||||||
* getModificationTime
|
|
||||||
* setModificationTime
|
|
||||||
* setModificationTimeHiRes
|
|
||||||
* getDirsFiles' (returns filenames instead of paths)
|
|
||||||
* withRawFilePath
|
|
||||||
* withHandle
|
|
||||||
|
|
||||||
## 0.10.1 -- 2020-01-13
|
|
||||||
|
|
||||||
* Move file check functions to HPath.IO
|
|
||||||
* Add 'doesExist'
|
|
||||||
* Exception handling of `doesExist`, `doesFileExist`, `doesDirectoryExist` has changed: only eNOENT is catched
|
|
||||||
* Exception handling of `isWritable` has changed: just a wrapper around `access` now
|
|
||||||
* switch exception handling to `safe-exceptions`
|
|
||||||
* Redo file reading API (readFileEOF dropped and now using streamly under the hood, added `readFileStream`)
|
|
||||||
|
|
||||||
|
|
||||||
## 0.10.0 -- 2020-01-04
|
|
||||||
|
|
||||||
* First version. Split from 'hpath', contains only the IO parts.
|
|
||||||
* Now uses streamly for 'copyFile'
|
|
||||||
* Fixed tmpdir in hspec
|
|
@ -1,30 +0,0 @@
|
|||||||
Copyright (c) 2020, Julian Ospald
|
|
||||||
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following
|
|
||||||
disclaimer in the documentation and/or other materials provided
|
|
||||||
with the distribution.
|
|
||||||
|
|
||||||
* Neither the name of Julian Ospald nor the names of other
|
|
||||||
contributors may be used to endorse or promote products derived
|
|
||||||
from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,27 +0,0 @@
|
|||||||
# HPath-IO
|
|
||||||
|
|
||||||
[![Gitter chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hasufell/hpath?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Hackage version](https://img.shields.io/hackage/v/hpath-io.svg?label=Hackage)](https://hackage.haskell.org/package/hpath-io) [![Build Status](https://api.travis-ci.org/hasufell/hpath.png?branch=master)](http://travis-ci.org/hasufell/hpath) [![Hackage-Deps](https://img.shields.io/hackage-deps/v/hpath-io.svg)](http://packdeps.haskellers.com/feed?needle=hpath-io)
|
|
||||||
|
|
||||||
High-level IO operations on files/directories, utilizing type-safe Paths. This uses [hpath-directory](https://hackage.haskell.org/package/hpath-directory) under the hood.
|
|
||||||
|
|
||||||
This package is part of the HPath suite, also check out:
|
|
||||||
|
|
||||||
* [hpath](https://hackage.haskell.org/package/hpath)
|
|
||||||
* [hpath-directory](https://hackage.haskell.org/package/hpath-directory)
|
|
||||||
* [hpath-filepath](https://hackage.haskell.org/package/hpath-filepath)
|
|
||||||
|
|
||||||
## Motivation
|
|
||||||
|
|
||||||
The motivation came during development of
|
|
||||||
[hsfm](https://github.com/hasufell/hsfm)
|
|
||||||
in order to have a proper high-level API of file related operations,
|
|
||||||
while utilizing type-safe Paths.
|
|
||||||
|
|
||||||
## Goals
|
|
||||||
|
|
||||||
* high-level API to file operations like recursive directory copy
|
|
||||||
* still allowing sufficient control to interact with the underlying low-level calls
|
|
||||||
* unit-testing exceptions (because yes, people may rely on them)
|
|
||||||
|
|
||||||
Note: this library was written for __posix__ systems and it will probably not support other systems.
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
|||||||
import Distribution.Simple
|
|
||||||
main = defaultMain
|
|
@ -1,6 +0,0 @@
|
|||||||
# TODO
|
|
||||||
|
|
||||||
## Tests
|
|
||||||
|
|
||||||
* `doesExist` not tested
|
|
||||||
* `readFileStream` only implicitly tested by `readFile`
|
|
@ -1,46 +0,0 @@
|
|||||||
name: hpath-io
|
|
||||||
version: 0.13.2
|
|
||||||
synopsis: High-level IO operations on files/directories
|
|
||||||
description: High-level IO operations on files/directories, utilizing type-safe Paths
|
|
||||||
-- bug-reports:
|
|
||||||
license: BSD3
|
|
||||||
license-file: LICENSE
|
|
||||||
author: Julian Ospald <hasufell@posteo.de>
|
|
||||||
maintainer: Julian Ospald <hasufell@posteo.de>
|
|
||||||
copyright: Julian Ospald 2016
|
|
||||||
category: Filesystem
|
|
||||||
build-type: Simple
|
|
||||||
cabal-version: 1.14
|
|
||||||
tested-with: GHC==7.10.3
|
|
||||||
, GHC==8.0.2
|
|
||||||
, GHC==8.2.2
|
|
||||||
, GHC==8.4.4
|
|
||||||
, GHC==8.6.5
|
|
||||||
, GHC==8.8.1
|
|
||||||
extra-source-files: README.md
|
|
||||||
CHANGELOG.md
|
|
||||||
|
|
||||||
library
|
|
||||||
if os(windows)
|
|
||||||
build-depends: unbuildable<0
|
|
||||||
buildable: False
|
|
||||||
exposed-modules: HPath.IO
|
|
||||||
build-depends: base >= 4.8 && <5
|
|
||||||
, bytestring >= 0.10.0.0
|
|
||||||
, exceptions
|
|
||||||
, hpath >= 0.11 && < 0.12
|
|
||||||
, hpath-directory >= 0.13 && < 0.14
|
|
||||||
, hpath-posix >= 0.13 && < 0.14
|
|
||||||
, safe-exceptions >= 0.1
|
|
||||||
, streamly >= 0.7
|
|
||||||
, time >= 1.8
|
|
||||||
, unix >= 2.5
|
|
||||||
if !impl(ghc>=7.11)
|
|
||||||
build-depends: transformers
|
|
||||||
hs-source-dirs: src
|
|
||||||
default-language: Haskell2010
|
|
||||||
|
|
||||||
|
|
||||||
source-repository head
|
|
||||||
type: git
|
|
||||||
location: https://github.com/hasufell/hpath
|
|
@ -1,865 +0,0 @@
|
|||||||
-- |
|
|
||||||
-- Module : HPath.IO
|
|
||||||
-- Copyright : © 2016 Julian Ospald
|
|
||||||
-- License : BSD3
|
|
||||||
--
|
|
||||||
-- Maintainer : Julian Ospald <hasufell@posteo.de>
|
|
||||||
-- Stability : experimental
|
|
||||||
-- Portability : portable
|
|
||||||
--
|
|
||||||
-- This module provides high-level IO related file operations like
|
|
||||||
-- copy, delete, move and so on. It only operates on /Path x/ which
|
|
||||||
-- guarantees us well-typed paths. This is a thin wrapper over
|
|
||||||
-- System.Posix.RawFilePath.Directory in 'hpath-directory'. It's
|
|
||||||
-- encouraged to use this module.
|
|
||||||
--
|
|
||||||
-- Some of these operations are due to their nature __not atomic__, which
|
|
||||||
-- means they may do multiple syscalls which form one context. Some
|
|
||||||
-- of them also have to examine the filetypes explicitly before the
|
|
||||||
-- syscalls, so a reasonable decision can be made. That means
|
|
||||||
-- the result is undefined if another process changes that context
|
|
||||||
-- while the non-atomic operation is still happening. However, where
|
|
||||||
-- possible, as few syscalls as possible are used and the underlying
|
|
||||||
-- exception handling is kept.
|
|
||||||
--
|
|
||||||
-- Note: `BlockDevice`, `CharacterDevice`, `NamedPipe` and `Socket`
|
|
||||||
-- are ignored by some of the more high-level functions (like `easyCopy`).
|
|
||||||
-- For other functions (like `copyFile`), the behavior on these file types is
|
|
||||||
-- unreliable/unsafe. Check the documentation of those functions for details.
|
|
||||||
|
|
||||||
{-# LANGUAGE FlexibleContexts #-} -- streamly
|
|
||||||
{-# LANGUAGE PackageImports #-}
|
|
||||||
|
|
||||||
module HPath.IO
|
|
||||||
(
|
|
||||||
-- * Types
|
|
||||||
FileType(..)
|
|
||||||
, RecursiveErrorMode(..)
|
|
||||||
, CopyMode(..)
|
|
||||||
-- * File copying
|
|
||||||
, copyDirRecursive
|
|
||||||
, recreateSymlink
|
|
||||||
, copyFile
|
|
||||||
, easyCopy
|
|
||||||
-- * File deletion
|
|
||||||
, deleteFile
|
|
||||||
, deleteDir
|
|
||||||
, deleteDirRecursive
|
|
||||||
, easyDelete
|
|
||||||
-- * File opening
|
|
||||||
, openFile
|
|
||||||
, executeFile
|
|
||||||
-- * File creation
|
|
||||||
, createRegularFile
|
|
||||||
, createDir
|
|
||||||
, createDirIfMissing
|
|
||||||
, createDirRecursive
|
|
||||||
, createSymlink
|
|
||||||
-- * File renaming/moving
|
|
||||||
, renameFile
|
|
||||||
, moveFile
|
|
||||||
-- * File reading
|
|
||||||
, readFile
|
|
||||||
, readFileStream
|
|
||||||
-- * File writing
|
|
||||||
, writeFile
|
|
||||||
, writeFileL
|
|
||||||
, appendFile
|
|
||||||
-- * File permissions
|
|
||||||
, RD.newFilePerms
|
|
||||||
, RD.newDirPerms
|
|
||||||
-- * File checks
|
|
||||||
, doesExist
|
|
||||||
, doesFileExist
|
|
||||||
, doesDirectoryExist
|
|
||||||
, isReadable
|
|
||||||
, isWritable
|
|
||||||
, isExecutable
|
|
||||||
, canOpenDirectory
|
|
||||||
-- * File times
|
|
||||||
, getModificationTime
|
|
||||||
, setModificationTime
|
|
||||||
, setModificationTimeHiRes
|
|
||||||
-- * Directory reading
|
|
||||||
, getDirsFiles
|
|
||||||
, getDirsFiles'
|
|
||||||
, getDirsFilesStream
|
|
||||||
-- * Filetype operations
|
|
||||||
, getFileType
|
|
||||||
-- * Others
|
|
||||||
, canonicalizePath
|
|
||||||
, toAbs
|
|
||||||
, withRawFilePath
|
|
||||||
, withHandle
|
|
||||||
, module System.Posix.RawFilePath.Directory.Errors
|
|
||||||
)
|
|
||||||
where
|
|
||||||
|
|
||||||
|
|
||||||
import Control.Exception.Safe ( MonadMask
|
|
||||||
, MonadCatch
|
|
||||||
, bracketOnError
|
|
||||||
, finally
|
|
||||||
)
|
|
||||||
import Control.Monad.Catch ( MonadThrow(..) )
|
|
||||||
|
|
||||||
import Data.ByteString ( ByteString )
|
|
||||||
import Data.Traversable ( for )
|
|
||||||
import qualified Data.ByteString.Lazy as L
|
|
||||||
import Data.Time.Clock
|
|
||||||
import Data.Time.Clock.POSIX ( POSIXTime )
|
|
||||||
import HPath
|
|
||||||
import Prelude hiding ( appendFile
|
|
||||||
, readFile
|
|
||||||
, writeFile
|
|
||||||
)
|
|
||||||
import Streamly
|
|
||||||
import qualified System.IO as SIO
|
|
||||||
import System.Posix.Directory.ByteString
|
|
||||||
( getWorkingDirectory )
|
|
||||||
import qualified "unix" System.Posix.IO.ByteString
|
|
||||||
as SPI
|
|
||||||
import System.Posix.FD ( openFd )
|
|
||||||
import System.Posix.RawFilePath.Directory.Errors
|
|
||||||
import System.Posix.Types ( FileMode
|
|
||||||
, ProcessID
|
|
||||||
, EpochTime
|
|
||||||
)
|
|
||||||
import qualified System.Posix.RawFilePath.Directory
|
|
||||||
as RD
|
|
||||||
import System.Posix.RawFilePath.Directory
|
|
||||||
( FileType
|
|
||||||
, RecursiveErrorMode
|
|
||||||
, CopyMode
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--------------------
|
|
||||||
--[ File Copying ]--
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- |Copies the contents of a directory recursively to the given destination, while preserving permissions.
|
|
||||||
-- Does not follow symbolic links. This behaves more or less like
|
|
||||||
-- the following, without descending into the destination if it
|
|
||||||
-- already exists:
|
|
||||||
--
|
|
||||||
-- @
|
|
||||||
-- cp -a \/source\/dir \/destination\/somedir
|
|
||||||
-- @
|
|
||||||
--
|
|
||||||
-- For directory contents, this will ignore any file type that is not
|
|
||||||
-- `RegularFile`, `SymbolicLink` or `Directory`.
|
|
||||||
--
|
|
||||||
-- For `Overwrite` copy mode this does not prune destination directory
|
|
||||||
-- contents, so the destination might contain more files than the source after
|
|
||||||
-- the operation has completed. Permissions of existing directories are
|
|
||||||
-- fixed.
|
|
||||||
--
|
|
||||||
-- Safety/reliability concerns:
|
|
||||||
--
|
|
||||||
-- * not atomic
|
|
||||||
-- * examines filetypes explicitly
|
|
||||||
-- * an explicit check `throwDestinationInSource` is carried out for the
|
|
||||||
-- top directory for basic sanity, because otherwise we might end up
|
|
||||||
-- with an infinite copy loop... however, this operation is not
|
|
||||||
-- carried out recursively (because it's slow)
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `NoSuchThing` if source directory does not exist
|
|
||||||
-- - `PermissionDenied` if source directory can't be opened
|
|
||||||
-- - `SameFile` if source and destination are the same file
|
|
||||||
-- (`HPathIOException`)
|
|
||||||
-- - `DestinationInSource` if destination is contained in source
|
|
||||||
-- (`HPathIOException`)
|
|
||||||
--
|
|
||||||
-- Throws in `FailEarly` RecursiveErrorMode only:
|
|
||||||
--
|
|
||||||
-- - `PermissionDenied` if output directory is not writable
|
|
||||||
-- - `InvalidArgument` if source directory is wrong type (symlink)
|
|
||||||
-- - `InappropriateType` if source directory is wrong type (regular file)
|
|
||||||
--
|
|
||||||
-- Throws in `CollectFailures` RecursiveErrorMode only:
|
|
||||||
--
|
|
||||||
-- - `RecursiveFailure` if any of the recursive operations that are not
|
|
||||||
-- part of the top-directory sanity-checks fail (`HPathIOException`)
|
|
||||||
--
|
|
||||||
-- Throws in `Strict` CopyMode only:
|
|
||||||
--
|
|
||||||
-- - `AlreadyExists` if destination already exists
|
|
||||||
--
|
|
||||||
-- Note: may call `getcwd` (only if destination is a relative path)
|
|
||||||
copyDirRecursive :: Path b1 -- ^ source dir
|
|
||||||
-> Path b2 -- ^ destination (parent dirs
|
|
||||||
-- are not automatically created)
|
|
||||||
-> CopyMode
|
|
||||||
-> RecursiveErrorMode
|
|
||||||
-> IO ()
|
|
||||||
copyDirRecursive (Path fromp) (Path destdirp) cm rm =
|
|
||||||
RD.copyDirRecursive fromp destdirp cm rm
|
|
||||||
|
|
||||||
|
|
||||||
-- |Recreate a symlink.
|
|
||||||
--
|
|
||||||
-- In `Overwrite` copy mode only files and empty directories are deleted.
|
|
||||||
--
|
|
||||||
-- Safety/reliability concerns:
|
|
||||||
--
|
|
||||||
-- * `Overwrite` mode is inherently non-atomic
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `InvalidArgument` if source file is wrong type (not a symlink)
|
|
||||||
-- - `PermissionDenied` if output directory cannot be written to
|
|
||||||
-- - `PermissionDenied` if source directory cannot be opened
|
|
||||||
-- - `SameFile` if source and destination are the same file
|
|
||||||
-- (`HPathIOException`)
|
|
||||||
--
|
|
||||||
--
|
|
||||||
-- Throws in `Strict` mode only:
|
|
||||||
--
|
|
||||||
-- - `AlreadyExists` if destination already exists
|
|
||||||
--
|
|
||||||
-- Throws in `Overwrite` mode only:
|
|
||||||
--
|
|
||||||
-- - `UnsatisfiedConstraints` if destination file is non-empty directory
|
|
||||||
--
|
|
||||||
-- Notes:
|
|
||||||
--
|
|
||||||
-- - calls `symlink`
|
|
||||||
-- - calls `getcwd` in Overwrite mode (if destination is a relative path)
|
|
||||||
recreateSymlink :: Path b1 -- ^ the old symlink file
|
|
||||||
-> Path b2 -- ^ destination file
|
|
||||||
-> CopyMode
|
|
||||||
-> IO ()
|
|
||||||
recreateSymlink (Path symsourceBS) (Path newsymBS) cm =
|
|
||||||
RD.recreateSymlink symsourceBS newsymBS cm
|
|
||||||
|
|
||||||
|
|
||||||
-- |Copies the given regular file to the given destination.
|
|
||||||
-- Neither follows symbolic links, nor accepts them.
|
|
||||||
-- For "copying" symbolic links, use `recreateSymlink` instead.
|
|
||||||
--
|
|
||||||
-- Note that this is still sort of a low-level function and doesn't
|
|
||||||
-- examine file types. For a more high-level version, use `easyCopy`
|
|
||||||
-- instead.
|
|
||||||
--
|
|
||||||
-- In `Overwrite` copy mode only overwrites actual files, not directories.
|
|
||||||
-- In `Strict` mode the destination file must not exist.
|
|
||||||
--
|
|
||||||
-- Safety/reliability concerns:
|
|
||||||
--
|
|
||||||
-- * `Overwrite` mode is not atomic
|
|
||||||
-- * when used on `CharacterDevice`, reads the "contents" and copies
|
|
||||||
-- them to a regular file, which might take indefinitely
|
|
||||||
-- * when used on `BlockDevice`, may either read the "contents"
|
|
||||||
-- and copy them to a regular file (potentially hanging indefinitely)
|
|
||||||
-- or may create a regular empty destination file
|
|
||||||
-- * when used on `NamedPipe`, will hang indefinitely
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `NoSuchThing` if source file does not exist
|
|
||||||
-- - `NoSuchThing` if source file is a a `Socket`
|
|
||||||
-- - `PermissionDenied` if output directory is not writable
|
|
||||||
-- - `PermissionDenied` if source directory can't be opened
|
|
||||||
-- - `InvalidArgument` if source file is wrong type (symlink or directory)
|
|
||||||
-- - `SameFile` if source and destination are the same file
|
|
||||||
-- (`HPathIOException`)
|
|
||||||
--
|
|
||||||
-- Throws in `Strict` mode only:
|
|
||||||
--
|
|
||||||
-- - `AlreadyExists` if destination already exists
|
|
||||||
--
|
|
||||||
-- Notes:
|
|
||||||
--
|
|
||||||
-- - may call `getcwd` in Overwrite mode (if destination is a relative path)
|
|
||||||
copyFile :: Path b1 -- ^ source file
|
|
||||||
-> Path b2 -- ^ destination file
|
|
||||||
-> CopyMode
|
|
||||||
-> IO ()
|
|
||||||
copyFile (Path from) (Path to) cm = RD.copyFile from to cm
|
|
||||||
|
|
||||||
-- |Copies a regular file, directory or symbolic link. In case of a
|
|
||||||
-- symbolic link it is just recreated, even if it points to a directory.
|
|
||||||
-- Any other file type is ignored.
|
|
||||||
--
|
|
||||||
-- Safety/reliability concerns:
|
|
||||||
--
|
|
||||||
-- * examines filetypes explicitly
|
|
||||||
-- * calls `copyDirRecursive` for directories
|
|
||||||
--
|
|
||||||
-- Note: may call `getcwd` in Overwrite mode (if destination is a relative path)
|
|
||||||
easyCopy :: Path b1 -> Path b2 -> CopyMode -> RecursiveErrorMode -> IO ()
|
|
||||||
easyCopy (Path from) (Path to) cm rm = RD.easyCopy from to cm rm
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
---------------------
|
|
||||||
--[ File Deletion ]--
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
|
|
||||||
-- |Deletes the given file. Raises `eISDIR`
|
|
||||||
-- if run on a directory. Does not follow symbolic links.
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `InappropriateType` for wrong file type (directory)
|
|
||||||
-- - `NoSuchThing` if the file does not exist
|
|
||||||
-- - `PermissionDenied` if the directory cannot be read
|
|
||||||
deleteFile :: Path b -> IO ()
|
|
||||||
deleteFile (Path p) = RD.deleteFile p
|
|
||||||
|
|
||||||
|
|
||||||
-- |Deletes the given directory, which must be empty, never symlinks.
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `InappropriateType` for wrong file type (symlink to directory)
|
|
||||||
-- - `InappropriateType` for wrong file type (regular file)
|
|
||||||
-- - `NoSuchThing` if directory does not exist
|
|
||||||
-- - `UnsatisfiedConstraints` if directory is not empty
|
|
||||||
-- - `PermissionDenied` if we can't open or write to parent directory
|
|
||||||
--
|
|
||||||
-- Notes: calls `rmdir`
|
|
||||||
deleteDir :: Path b -> IO ()
|
|
||||||
deleteDir (Path p) = RD.deleteDir p
|
|
||||||
|
|
||||||
|
|
||||||
-- |Deletes the given directory recursively. Does not follow symbolic
|
|
||||||
-- links. Tries `deleteDir` first before attemtping a recursive
|
|
||||||
-- deletion.
|
|
||||||
--
|
|
||||||
-- On directory contents this behaves like `easyDelete`
|
|
||||||
-- and thus will ignore any file type that is not `RegularFile`,
|
|
||||||
-- `SymbolicLink` or `Directory`.
|
|
||||||
--
|
|
||||||
-- Safety/reliability concerns:
|
|
||||||
--
|
|
||||||
-- * not atomic
|
|
||||||
-- * examines filetypes explicitly
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `InappropriateType` for wrong file type (symlink to directory)
|
|
||||||
-- - `InappropriateType` for wrong file type (regular file)
|
|
||||||
-- - `NoSuchThing` if directory does not exist
|
|
||||||
-- - `PermissionDenied` if we can't open or write to parent directory
|
|
||||||
deleteDirRecursive :: Path b -> IO ()
|
|
||||||
deleteDirRecursive (Path p) = RD.deleteDirRecursive p
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- |Deletes a file, directory or symlink.
|
|
||||||
-- In case of directory, performs recursive deletion. In case of
|
|
||||||
-- a symlink, the symlink file is deleted.
|
|
||||||
-- Any other file type is ignored.
|
|
||||||
--
|
|
||||||
-- Safety/reliability concerns:
|
|
||||||
--
|
|
||||||
-- * examines filetypes explicitly
|
|
||||||
-- * calls `deleteDirRecursive` for directories
|
|
||||||
easyDelete :: Path b -> IO ()
|
|
||||||
easyDelete (Path p) = RD.easyDelete p
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--------------------
|
|
||||||
--[ File Opening ]--
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
|
|
||||||
-- |Opens a file appropriately by invoking xdg-open. The file type
|
|
||||||
-- is not checked. This forks a process.
|
|
||||||
openFile :: Path b -> IO ProcessID
|
|
||||||
openFile (Path fp) = RD.openFile fp
|
|
||||||
|
|
||||||
|
|
||||||
-- |Executes a program with the given arguments. This forks a process.
|
|
||||||
executeFile :: Path b -- ^ program
|
|
||||||
-> [ByteString] -- ^ arguments
|
|
||||||
-> IO ProcessID
|
|
||||||
executeFile (Path fp) args = RD.executeFile fp args
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
---------------------
|
|
||||||
--[ File Creation ]--
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
|
|
||||||
-- |Create an empty regular file at the given directory with the given
|
|
||||||
-- filename.
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `PermissionDenied` if output directory cannot be written to
|
|
||||||
-- - `AlreadyExists` if destination already exists
|
|
||||||
-- - `NoSuchThing` if any of the parent components of the path
|
|
||||||
-- do not exist
|
|
||||||
createRegularFile :: FileMode -> Path b -> IO ()
|
|
||||||
createRegularFile fm (Path destBS) = RD.createRegularFile fm destBS
|
|
||||||
|
|
||||||
|
|
||||||
-- |Create an empty directory at the given directory with the given filename.
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `PermissionDenied` if output directory cannot be written to
|
|
||||||
-- - `AlreadyExists` if destination already exists
|
|
||||||
-- - `NoSuchThing` if any of the parent components of the path
|
|
||||||
-- do not exist
|
|
||||||
createDir :: FileMode -> Path b -> IO ()
|
|
||||||
createDir fm (Path destBS) = RD.createDir fm destBS
|
|
||||||
|
|
||||||
-- |Create an empty directory at the given directory with the given filename.
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `PermissionDenied` if output directory cannot be written to
|
|
||||||
-- - `NoSuchThing` if any of the parent components of the path
|
|
||||||
-- do not exist
|
|
||||||
createDirIfMissing :: FileMode -> Path b -> IO ()
|
|
||||||
createDirIfMissing fm (Path destBS) = RD.createDirIfMissing fm destBS
|
|
||||||
|
|
||||||
|
|
||||||
-- |Create an empty directory at the given directory with the given filename.
|
|
||||||
-- All parent directories are created with the same filemode. This
|
|
||||||
-- basically behaves like:
|
|
||||||
--
|
|
||||||
-- @
|
|
||||||
-- mkdir -p \/some\/dir
|
|
||||||
-- @
|
|
||||||
--
|
|
||||||
-- Safety/reliability concerns:
|
|
||||||
--
|
|
||||||
-- * not atomic
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `PermissionDenied` if any part of the path components do not
|
|
||||||
-- exist and cannot be written to
|
|
||||||
-- - `AlreadyExists` if destination already exists and
|
|
||||||
-- is *not* a directory
|
|
||||||
--
|
|
||||||
-- Note: calls `getcwd` if the input path is a relative path
|
|
||||||
createDirRecursive :: FileMode -> Path b -> IO ()
|
|
||||||
createDirRecursive fm (Path p) = RD.createDirRecursive fm p
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- |Create a symlink.
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `PermissionDenied` if output directory cannot be written to
|
|
||||||
-- - `AlreadyExists` if destination file already exists
|
|
||||||
-- - `NoSuchThing` if any of the parent components of the path
|
|
||||||
-- do not exist
|
|
||||||
--
|
|
||||||
-- Note: calls `symlink`
|
|
||||||
createSymlink :: Path b -- ^ destination file
|
|
||||||
-> ByteString -- ^ path the symlink points to
|
|
||||||
-> IO ()
|
|
||||||
createSymlink (Path destBS) sympoint = RD.createSymlink destBS sympoint
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----------------------------
|
|
||||||
--[ File Renaming/Moving ]--
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
|
|
||||||
-- |Rename a given file with the provided filename. Destination and source
|
|
||||||
-- must be on the same device, otherwise `eXDEV` will be raised.
|
|
||||||
--
|
|
||||||
-- Does not follow symbolic links, but renames the symbolic link file.
|
|
||||||
--
|
|
||||||
-- Safety/reliability concerns:
|
|
||||||
--
|
|
||||||
-- * has a separate set of exception handling, apart from the syscall
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `NoSuchThing` if source file does not exist
|
|
||||||
-- - `PermissionDenied` if output directory cannot be written to
|
|
||||||
-- - `PermissionDenied` if source directory cannot be opened
|
|
||||||
-- - `UnsupportedOperation` if source and destination are on different
|
|
||||||
-- devices
|
|
||||||
-- - `AlreadyExists` if destination already exists
|
|
||||||
-- - `SameFile` if destination and source are the same file
|
|
||||||
-- (`HPathIOException`)
|
|
||||||
--
|
|
||||||
-- Note: calls `rename` (but does not allow to rename over existing files)
|
|
||||||
renameFile :: Path b1 -> Path b2 -> IO ()
|
|
||||||
renameFile (Path from) (Path to) = RD.renameFile from to
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- |Move a file. This also works across devices by copy-delete fallback.
|
|
||||||
-- And also works on directories.
|
|
||||||
--
|
|
||||||
-- Does not follow symbolic links, but renames the symbolic link file.
|
|
||||||
--
|
|
||||||
--
|
|
||||||
-- Safety/reliability concerns:
|
|
||||||
--
|
|
||||||
-- * `Overwrite` mode is not atomic
|
|
||||||
-- * copy-delete fallback is inherently non-atomic
|
|
||||||
-- * since this function calls `easyCopy` and `easyDelete` as a fallback
|
|
||||||
-- to `renameFile`, file types that are not `RegularFile`, `SymbolicLink`
|
|
||||||
-- or `Directory` may be ignored
|
|
||||||
-- * for `Overwrite` mode, the destination will be deleted (not recursively)
|
|
||||||
-- before moving
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `NoSuchThing` if source file does not exist
|
|
||||||
-- - `PermissionDenied` if output directory cannot be written to
|
|
||||||
-- - `PermissionDenied` if source directory cannot be opened
|
|
||||||
-- - `SameFile` if destination and source are the same file
|
|
||||||
-- (`HPathIOException`)
|
|
||||||
--
|
|
||||||
-- Throws in `Strict` mode only:
|
|
||||||
--
|
|
||||||
-- - `AlreadyExists` if destination already exists
|
|
||||||
--
|
|
||||||
-- Notes:
|
|
||||||
--
|
|
||||||
-- - calls `rename` (but does not allow to rename over existing files)
|
|
||||||
-- - calls `getcwd` in Overwrite mode if destination is a relative path
|
|
||||||
moveFile :: Path b1 -- ^ file to move
|
|
||||||
-> Path b2 -- ^ destination
|
|
||||||
-> CopyMode
|
|
||||||
-> IO ()
|
|
||||||
moveFile (Path from) (Path to) cm = RD.moveFile from to cm
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--------------------
|
|
||||||
--[ File Reading ]--
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
|
|
||||||
-- |Read the given file *at once* into memory as a lazy ByteString.
|
|
||||||
-- Symbolic links are followed, no sanity checks on file size
|
|
||||||
-- or file type. File must exist. Uses Builders under the hood
|
|
||||||
-- (hence lazy ByteString).
|
|
||||||
--
|
|
||||||
-- Safety/reliability concerns:
|
|
||||||
--
|
|
||||||
-- * the whole file is read into memory, this doesn't read lazily
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `InappropriateType` if file is not a regular file or a symlink
|
|
||||||
-- - `PermissionDenied` if we cannot read the file or the directory
|
|
||||||
-- containting it
|
|
||||||
-- - `NoSuchThing` if the file does not exist
|
|
||||||
readFile :: Path b -> IO L.ByteString
|
|
||||||
readFile (Path path) = RD.readFile path
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- | Open the given file as a filestream. Once the filestream is
|
|
||||||
-- exits, the filehandle is cleaned up.
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `InappropriateType` if file is not a regular file or a symlink
|
|
||||||
-- - `PermissionDenied` if we cannot read the file or the directory
|
|
||||||
-- containting it
|
|
||||||
-- - `NoSuchThing` if the file does not exist
|
|
||||||
readFileStream :: Path b -> IO (SerialT IO ByteString)
|
|
||||||
readFileStream (Path fp) = RD.readFileStream fp
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--------------------
|
|
||||||
--[ File Writing ]--
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
|
|
||||||
-- |Write a given ByteString to a file, truncating the file beforehand.
|
|
||||||
-- Follows symlinks.
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `InappropriateType` if file is not a regular file or a symlink
|
|
||||||
-- - `PermissionDenied` if we cannot read the file or the directory
|
|
||||||
-- containting it
|
|
||||||
-- - `NoSuchThing` if the file does not exist
|
|
||||||
writeFile :: Path b
|
|
||||||
-> Maybe FileMode -- ^ if Nothing, file must exist
|
|
||||||
-> ByteString
|
|
||||||
-> IO ()
|
|
||||||
writeFile (Path fp) fmode bs = RD.writeFile fp fmode bs
|
|
||||||
|
|
||||||
|
|
||||||
-- |Write a given lazy ByteString to a file, truncating the file beforehand.
|
|
||||||
-- Follows symlinks.
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `InappropriateType` if file is not a regular file or a symlink
|
|
||||||
-- - `PermissionDenied` if we cannot read the file or the directory
|
|
||||||
-- containting it
|
|
||||||
-- - `NoSuchThing` if the file does not exist
|
|
||||||
--
|
|
||||||
-- Note: uses streamly under the hood
|
|
||||||
writeFileL :: Path b
|
|
||||||
-> Maybe FileMode -- ^ if Nothing, file must exist
|
|
||||||
-> L.ByteString
|
|
||||||
-> IO ()
|
|
||||||
writeFileL (Path fp) fmode lbs = RD.writeFileL fp fmode lbs
|
|
||||||
|
|
||||||
|
|
||||||
-- |Append a given ByteString to a file.
|
|
||||||
-- The file must exist. Follows symlinks.
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `InappropriateType` if file is not a regular file or a symlink
|
|
||||||
-- - `PermissionDenied` if we cannot read the file or the directory
|
|
||||||
-- containting it
|
|
||||||
-- - `NoSuchThing` if the file does not exist
|
|
||||||
appendFile :: Path b -> ByteString -> IO ()
|
|
||||||
appendFile (Path fp) bs = RD.appendFile fp bs
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-------------------
|
|
||||||
--[ File checks ]--
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
|
|
||||||
-- |Checks if the given file exists.
|
|
||||||
-- Does not follow symlinks.
|
|
||||||
--
|
|
||||||
-- Only eNOENT is catched (and returns False).
|
|
||||||
doesExist :: Path b -> IO Bool
|
|
||||||
doesExist (Path bs) = RD.doesExist bs
|
|
||||||
|
|
||||||
|
|
||||||
-- |Checks if the given file exists and is not a directory.
|
|
||||||
-- Does not follow symlinks.
|
|
||||||
--
|
|
||||||
-- Only eNOENT is catched (and returns False).
|
|
||||||
doesFileExist :: Path b -> IO Bool
|
|
||||||
doesFileExist (Path bs) = RD.doesFileExist bs
|
|
||||||
|
|
||||||
|
|
||||||
-- |Checks if the given file exists and is a directory.
|
|
||||||
-- Does not follow symlinks.
|
|
||||||
--
|
|
||||||
-- Only eNOENT is catched (and returns False).
|
|
||||||
doesDirectoryExist :: Path b -> IO Bool
|
|
||||||
doesDirectoryExist (Path bs) = RD.doesDirectoryExist bs
|
|
||||||
|
|
||||||
|
|
||||||
-- |Checks whether a file or folder is readable.
|
|
||||||
--
|
|
||||||
-- Only eACCES, eROFS, eTXTBSY, ePERM are catched (and return False).
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `NoSuchThing` if the file does not exist
|
|
||||||
isReadable :: Path b -> IO Bool
|
|
||||||
isReadable (Path bs) = RD.isReadable bs
|
|
||||||
|
|
||||||
-- |Checks whether a file or folder is writable.
|
|
||||||
--
|
|
||||||
-- Only eACCES, eROFS, eTXTBSY, ePERM are catched (and return False).
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `NoSuchThing` if the file does not exist
|
|
||||||
isWritable :: Path b -> IO Bool
|
|
||||||
isWritable (Path bs) = RD.isWritable bs
|
|
||||||
|
|
||||||
|
|
||||||
-- |Checks whether a file or folder is executable.
|
|
||||||
--
|
|
||||||
-- Only eACCES, eROFS, eTXTBSY, ePERM are catched (and return False).
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `NoSuchThing` if the file does not exist
|
|
||||||
isExecutable :: Path b -> IO Bool
|
|
||||||
isExecutable (Path bs) = RD.isExecutable bs
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- |Checks whether the directory at the given path exists and can be
|
|
||||||
-- opened. This invokes `openDirStream` which follows symlinks.
|
|
||||||
canOpenDirectory :: Path b -> IO Bool
|
|
||||||
canOpenDirectory (Path bs) = RD.canOpenDirectory bs
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
------------------
|
|
||||||
--[ File times ]--
|
|
||||||
------------------
|
|
||||||
|
|
||||||
|
|
||||||
getModificationTime :: Path b -> IO UTCTime
|
|
||||||
getModificationTime (Path bs) = RD.getModificationTime bs
|
|
||||||
|
|
||||||
setModificationTime :: Path b -> EpochTime -> IO ()
|
|
||||||
setModificationTime (Path bs) t = RD.setModificationTime bs t
|
|
||||||
|
|
||||||
setModificationTimeHiRes :: Path b -> POSIXTime -> IO ()
|
|
||||||
setModificationTimeHiRes (Path bs) t = RD.setModificationTimeHiRes bs t
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-------------------------
|
|
||||||
--[ Directory reading ]--
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
|
|
||||||
-- |Gets all filenames of the given directory. This excludes "." and "..".
|
|
||||||
-- This version does not follow symbolic links.
|
|
||||||
--
|
|
||||||
-- The contents are not sorted and there is no guarantee on the ordering.
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `NoSuchThing` if directory does not exist
|
|
||||||
-- - `InappropriateType` if file type is wrong (file)
|
|
||||||
-- - `InappropriateType` if file type is wrong (symlink to file)
|
|
||||||
-- - `InappropriateType` if file type is wrong (symlink to dir)
|
|
||||||
-- - `PermissionDenied` if directory cannot be opened
|
|
||||||
-- - `PathParseException` if a filename could not be parsed (should never happen)
|
|
||||||
getDirsFiles :: Path b -- ^ dir to read
|
|
||||||
-> IO [Path b]
|
|
||||||
getDirsFiles p = do
|
|
||||||
contents <- getDirsFiles' p
|
|
||||||
pure $ fmap (p </>) contents
|
|
||||||
|
|
||||||
|
|
||||||
-- | Like 'getDirsFiles', but returns the filename only, instead
|
|
||||||
-- of prepending the base path.
|
|
||||||
getDirsFiles' :: Path b -- ^ dir to read
|
|
||||||
-> IO [Path Rel]
|
|
||||||
getDirsFiles' (Path fp) = do
|
|
||||||
rawContents <- RD.getDirsFiles' fp
|
|
||||||
for rawContents $ \r -> parseRel r
|
|
||||||
|
|
||||||
|
|
||||||
-- | Like 'getDirsFiles'', except returning a Stream.
|
|
||||||
getDirsFilesStream :: (MonadCatch m, MonadAsync m, MonadMask m)
|
|
||||||
=> Path b
|
|
||||||
-> IO (SerialT m (Path Rel))
|
|
||||||
getDirsFilesStream (Path fp) = do
|
|
||||||
s <- RD.getDirsFilesStream fp
|
|
||||||
pure (s >>= parseRel)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
---------------------------
|
|
||||||
--[ FileType operations ]--
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
|
|
||||||
-- |Get the file type of the file located at the given path. Does
|
|
||||||
-- not follow symbolic links.
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `NoSuchThing` if the file does not exist
|
|
||||||
-- - `PermissionDenied` if any part of the path is not accessible
|
|
||||||
getFileType :: Path b -> IO FileType
|
|
||||||
getFileType (Path fp) = RD.getFileType fp
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--------------
|
|
||||||
--[ Others ]--
|
|
||||||
--------------
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- |Applies `realpath` on the given path.
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `NoSuchThing` if the file at the given path does not exist
|
|
||||||
-- - `NoSuchThing` if the symlink is broken
|
|
||||||
-- - `PathParseException` if realpath does not return an absolute path
|
|
||||||
canonicalizePath :: Path b -> IO (Path Abs)
|
|
||||||
canonicalizePath (Path l) = do
|
|
||||||
nl <- RD.canonicalizePath l
|
|
||||||
parseAbs nl
|
|
||||||
|
|
||||||
|
|
||||||
-- |Converts any path to an absolute path.
|
|
||||||
-- This is done in the following way:
|
|
||||||
--
|
|
||||||
-- - if the path is already an absolute one, just return it
|
|
||||||
-- - if it's a relative path, prepend the current directory to it
|
|
||||||
toAbs :: Path b -> IO (Path Abs)
|
|
||||||
toAbs (Path bs) = do
|
|
||||||
let mabs = parseAbs bs :: Maybe (Path Abs)
|
|
||||||
case mabs of
|
|
||||||
Just a -> return a
|
|
||||||
Nothing -> do
|
|
||||||
cwd <- getWorkingDirectory >>= parseAbs
|
|
||||||
r <- parseRel bs -- we know it must be relative now
|
|
||||||
return $ cwd </> r
|
|
||||||
|
|
||||||
|
|
||||||
-- | Helper function to use the Path library without
|
|
||||||
-- buying into the Path type too much. This uses 'parseAny'
|
|
||||||
-- under the hood and may throw `PathParseException`.
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `PathParseException` if the bytestring could neither be parsed as
|
|
||||||
-- relative or absolute Path
|
|
||||||
withRawFilePath :: MonadThrow m
|
|
||||||
=> ByteString
|
|
||||||
-> (Either (Path Abs) (Path Rel) -> m b)
|
|
||||||
-> m b
|
|
||||||
withRawFilePath bs action = do
|
|
||||||
path <- parseAny bs
|
|
||||||
action path
|
|
||||||
|
|
||||||
|
|
||||||
-- | Convenience function to open the path as a handle.
|
|
||||||
--
|
|
||||||
-- If the file does not exist, it will be created with 'newFilePerms'.
|
|
||||||
--
|
|
||||||
-- Throws:
|
|
||||||
--
|
|
||||||
-- - `PathParseException` if the bytestring could neither be parsed as
|
|
||||||
-- relative or absolute Path
|
|
||||||
withHandle :: ByteString
|
|
||||||
-> SPI.OpenMode
|
|
||||||
-> ((SIO.Handle, Either (Path Abs) (Path Rel)) -> IO a)
|
|
||||||
-> IO a
|
|
||||||
withHandle bs mode action = do
|
|
||||||
path <- parseAny bs
|
|
||||||
handle <-
|
|
||||||
bracketOnError (openFd bs mode [] (Just RD.newFilePerms)) (SPI.closeFd)
|
|
||||||
$ SPI.fdToHandle
|
|
||||||
finally (action (handle, path)) (SIO.hClose handle)
|
|
@ -1,14 +0,0 @@
|
|||||||
# Revision history for hpath-posix
|
|
||||||
|
|
||||||
## 0.13.2 -- 2020-04-14
|
|
||||||
|
|
||||||
* fix macOS compatibility, especially with memory bug in `fdopendir`
|
|
||||||
|
|
||||||
## 0.13.1 -- 2020-02-08
|
|
||||||
|
|
||||||
* Remove unnecessary dependencies
|
|
||||||
|
|
||||||
|
|
||||||
## 0.13.0 -- 2020-01-29
|
|
||||||
|
|
||||||
* First version. Released on an unsuspecting world.
|
|
@ -1,30 +0,0 @@
|
|||||||
Copyright (c) 2020, Julian Ospald
|
|
||||||
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following
|
|
||||||
disclaimer in the documentation and/or other materials provided
|
|
||||||
with the distribution.
|
|
||||||
|
|
||||||
* Neither the name of Julian Ospald nor the names of other
|
|
||||||
contributors may be used to endorse or promote products derived
|
|
||||||
from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,13 +0,0 @@
|
|||||||
# HPath-filepath
|
|
||||||
|
|
||||||
[![Gitter chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hasufell/hpath?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Hackage version](https://img.shields.io/hackage/v/hpath-posix.svg?label=Hackage)](https://hackage.haskell.org/package/hpath-posix) [![Build Status](https://api.travis-ci.org/hasufell/hpath.png?branch=master)](http://travis-ci.org/hasufell/hpath) [![Hackage-Deps](https://img.shields.io/hackage-deps/v/hpath-posix.svg)](http://packdeps.haskellers.com/feed?needle=hpath-posix)
|
|
||||||
|
|
||||||
Some low-level POSIX glue code, that is not in 'unix'.
|
|
||||||
|
|
||||||
This package is part of the HPath suite, also check out:
|
|
||||||
|
|
||||||
* [hpath](https://hackage.haskell.org/package/hpath)
|
|
||||||
* [hpath-directory](https://hackage.haskell.org/package/hpath-directory)
|
|
||||||
* [hpath-filepath](https://hackage.haskell.org/package/hpath-filepath)
|
|
||||||
* [hpath-io](https://hackage.haskell.org/package/hpath-io)
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
|||||||
import Distribution.Simple
|
|
||||||
main = defaultMain
|
|
@ -1,7 +0,0 @@
|
|||||||
#include "dirutils.h"
|
|
||||||
|
|
||||||
unsigned int
|
|
||||||
__posixdir_d_type(struct dirent* d)
|
|
||||||
{
|
|
||||||
return(d -> d_type);
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
#ifndef POSIXPATHS_CBITS_DIRUTILS_H
|
|
||||||
#define POSIXPATHS_CBITS_DIRUTILS_H
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
|
|
||||||
extern unsigned int
|
|
||||||
__posixdir_d_type(struct dirent* d)
|
|
||||||
;
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,48 +0,0 @@
|
|||||||
cabal-version: >=1.10
|
|
||||||
|
|
||||||
name: hpath-posix
|
|
||||||
version: 0.13.2
|
|
||||||
synopsis: Some low-level POSIX glue code, that is not in 'unix'
|
|
||||||
homepage: https://github.com/hasufell/hpath
|
|
||||||
bug-reports: https://github.com/hasufell/hpath/issues
|
|
||||||
license: BSD3
|
|
||||||
license-file: LICENSE
|
|
||||||
author: Julian Ospald <hasufell@posteo.de>
|
|
||||||
maintainer: Julian Ospald <hasufell@posteo.de>
|
|
||||||
copyright: Julian Ospald <hasufell@posteo.de> 2020
|
|
||||||
category: Filesystem
|
|
||||||
build-type: Simple
|
|
||||||
extra-source-files: CHANGELOG.md
|
|
||||||
cbits/dirutils.h
|
|
||||||
tested-with: GHC==7.10.3
|
|
||||||
, GHC==8.0.2
|
|
||||||
, GHC==8.2.2
|
|
||||||
, GHC==8.4.4
|
|
||||||
, GHC==8.6.5
|
|
||||||
, GHC==8.8.1
|
|
||||||
|
|
||||||
library
|
|
||||||
if os(windows)
|
|
||||||
build-depends: unbuildable<0
|
|
||||||
buildable: False
|
|
||||||
exposed-modules: System.Posix.RawFilePath.Directory.Traversals
|
|
||||||
System.Posix.Foreign
|
|
||||||
System.Posix.FD
|
|
||||||
-- other-modules:
|
|
||||||
-- other-extensions:
|
|
||||||
c-sources: cbits/dirutils.c
|
|
||||||
build-depends: base >= 4.8 && <5
|
|
||||||
, bytestring >= 0.10
|
|
||||||
, hpath-filepath >= 0.10.3
|
|
||||||
, unix >= 2.5
|
|
||||||
if impl(ghc < 8.0)
|
|
||||||
build-depends:
|
|
||||||
fail >= 4.9
|
|
||||||
|
|
||||||
hs-source-dirs: src
|
|
||||||
default-language: Haskell2010
|
|
||||||
default-extensions: PackageImports
|
|
||||||
|
|
||||||
source-repository head
|
|
||||||
type: git
|
|
||||||
location: https://github.com/hasufell/hpath
|
|
@ -1,75 +0,0 @@
|
|||||||
-- |
|
|
||||||
-- Module : System.Posix.FD
|
|
||||||
-- Copyright : © 2016 Julian Ospald
|
|
||||||
-- License : BSD3
|
|
||||||
--
|
|
||||||
-- Maintainer : Julian Ospald <hasufell@posteo.de>
|
|
||||||
-- Stability : experimental
|
|
||||||
-- Portability : portable
|
|
||||||
--
|
|
||||||
-- Provides an alternative for `System.Posix.IO.ByteString.openFd`
|
|
||||||
-- which gives us more control on what status flags to pass to the
|
|
||||||
-- low-level @open(2)@ call, in contrast to the unix package.
|
|
||||||
|
|
||||||
|
|
||||||
{-# LANGUAGE ForeignFunctionInterface #-}
|
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
{-# LANGUAGE TupleSections #-}
|
|
||||||
|
|
||||||
{-# OPTIONS_GHC -Wall #-}
|
|
||||||
|
|
||||||
|
|
||||||
module System.Posix.FD (
|
|
||||||
openFd
|
|
||||||
) where
|
|
||||||
|
|
||||||
|
|
||||||
import Foreign.C.String
|
|
||||||
import Foreign.C.Types
|
|
||||||
import System.Posix.Foreign
|
|
||||||
import qualified System.Posix as Posix
|
|
||||||
import System.Posix.ByteString.FilePath
|
|
||||||
|
|
||||||
|
|
||||||
foreign import ccall unsafe "open"
|
|
||||||
c_open :: CString -> CInt -> Posix.CMode -> IO CInt
|
|
||||||
|
|
||||||
|
|
||||||
open_ :: CString
|
|
||||||
-> Posix.OpenMode
|
|
||||||
-> [Flags]
|
|
||||||
-> Maybe Posix.FileMode
|
|
||||||
-> IO Posix.Fd
|
|
||||||
open_ str how optional_flags maybe_mode = do
|
|
||||||
fd <- c_open str all_flags mode_w
|
|
||||||
return (Posix.Fd fd)
|
|
||||||
where
|
|
||||||
all_flags = unionFlags $ optional_flags ++ [open_mode] ++ creat
|
|
||||||
|
|
||||||
|
|
||||||
(creat, mode_w) = case maybe_mode of
|
|
||||||
Nothing -> ([],0)
|
|
||||||
Just x -> ([oCreat], x)
|
|
||||||
|
|
||||||
open_mode = case how of
|
|
||||||
Posix.ReadOnly -> oRdonly
|
|
||||||
Posix.WriteOnly -> oWronly
|
|
||||||
Posix.ReadWrite -> oRdwr
|
|
||||||
|
|
||||||
|
|
||||||
-- |Open and optionally create this file. See 'System.Posix.Files'
|
|
||||||
-- for information on how to use the 'FileMode' type.
|
|
||||||
--
|
|
||||||
-- Note that passing @Just x@ as the 4th argument triggers the
|
|
||||||
-- `oCreat` status flag, which must be set when you pass in `oExcl`
|
|
||||||
-- to the status flags. Also see the manpage for @open(2)@.
|
|
||||||
openFd :: RawFilePath
|
|
||||||
-> Posix.OpenMode
|
|
||||||
-> [Flags] -- ^ status flags of @open(2)@
|
|
||||||
-> Maybe Posix.FileMode -- ^ @Just x@ => creates the file with the given modes, Nothing => the file must exist.
|
|
||||||
-> IO Posix.Fd
|
|
||||||
openFd name how optional_flags maybe_mode =
|
|
||||||
withFilePath name $ \str ->
|
|
||||||
throwErrnoPathIfMinus1Retry "openFd" name $
|
|
||||||
open_ str how optional_flags maybe_mode
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
|||||||
module System.Posix.Foreign where
|
|
||||||
|
|
||||||
import Data.Bits
|
|
||||||
import Data.List (foldl')
|
|
||||||
import Foreign.C.Types
|
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
newtype DirType = DirType Int deriving (Eq, Show)
|
|
||||||
data Flags = Flags Int | UnsupportedFlag String deriving (Eq, Show)
|
|
||||||
|
|
||||||
unFlags :: Flags -> Int
|
|
||||||
unFlags (Flags i) = i
|
|
||||||
unFlags (UnsupportedFlag name) = error (name ++ " is not supported on this platform")
|
|
||||||
|
|
||||||
-- |Returns @True@ if posix-paths was compiled with support for the provided
|
|
||||||
-- flag. (As of this writing, the only flag for which this check may be
|
|
||||||
-- necessary is 'oCloexec'; all other flags will always yield @True@.)
|
|
||||||
isSupported :: Flags -> Bool
|
|
||||||
isSupported (Flags _) = True
|
|
||||||
isSupported _ = False
|
|
||||||
|
|
||||||
-- |@O_CLOEXEC@ is not supported on every POSIX platform. Use
|
|
||||||
-- @'isSupported' oCloexec@ to determine if support for @O_CLOEXEC@ was
|
|
||||||
-- compiled into your version of posix-paths. (If not, using @oCloexec@ will
|
|
||||||
-- throw an exception.)
|
|
||||||
oCloexec :: Flags
|
|
||||||
#ifdef O_CLOEXEC
|
|
||||||
oCloexec = Flags #{const O_CLOEXEC}
|
|
||||||
#else
|
|
||||||
{-# WARNING oCloexec
|
|
||||||
"This version of posix-paths was compiled without @O_CLOEXEC@ support." #-}
|
|
||||||
oCloexec = UnsupportedFlag "O_CLOEXEC"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- If these enum declarations occur earlier in the file, haddock
|
|
||||||
-- gets royally confused about the above doc comments.
|
|
||||||
-- Probably http://trac.haskell.org/haddock/ticket/138
|
|
||||||
|
|
||||||
#{enum DirType, DirType, DT_BLK, DT_CHR, DT_DIR, DT_FIFO, DT_LNK, DT_REG, DT_SOCK, DT_UNKNOWN}
|
|
||||||
|
|
||||||
#{enum Flags, Flags, O_APPEND, O_ASYNC, O_CREAT, O_DIRECTORY, O_EXCL, O_NOCTTY, O_NOFOLLOW, O_NONBLOCK, O_RDONLY, O_WRONLY, O_RDWR, O_SYNC, O_TRUNC}
|
|
||||||
|
|
||||||
pathMax :: Int
|
|
||||||
pathMax = #{const PATH_MAX}
|
|
||||||
|
|
||||||
unionFlags :: [Flags] -> CInt
|
|
||||||
unionFlags = fromIntegral . foldl' ((. unFlags) . (.|.)) 0
|
|
@ -1,268 +0,0 @@
|
|||||||
-- |
|
|
||||||
-- Module : System.Posix.RawFilePath.Directory.Traversals
|
|
||||||
-- Copyright : © 2016 Julian Ospald
|
|
||||||
-- License : BSD3
|
|
||||||
--
|
|
||||||
-- Maintainer : Julian Ospald <hasufell@posteo.de>
|
|
||||||
-- Stability : experimental
|
|
||||||
-- Portability : portable
|
|
||||||
--
|
|
||||||
-- Traversal and read operations on directories.
|
|
||||||
|
|
||||||
|
|
||||||
{-# LANGUAGE CApiFFI #-}
|
|
||||||
{-# LANGUAGE CPP #-}
|
|
||||||
{-# LANGUAGE ForeignFunctionInterface #-}
|
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
{-# LANGUAGE TupleSections #-}
|
|
||||||
{-# LANGUAGE ViewPatterns #-}
|
|
||||||
|
|
||||||
{-# OPTIONS_GHC -Wall #-}
|
|
||||||
|
|
||||||
|
|
||||||
module System.Posix.RawFilePath.Directory.Traversals (
|
|
||||||
|
|
||||||
getDirectoryContents
|
|
||||||
, getDirectoryContents'
|
|
||||||
|
|
||||||
, allDirectoryContents
|
|
||||||
, allDirectoryContents'
|
|
||||||
, traverseDirectory
|
|
||||||
|
|
||||||
-- lower-level stuff
|
|
||||||
, readDirEnt
|
|
||||||
, packDirStream
|
|
||||||
, unpackDirStream
|
|
||||||
, fdOpendir
|
|
||||||
|
|
||||||
, realpath
|
|
||||||
) where
|
|
||||||
|
|
||||||
|
|
||||||
#if __GLASGOW_HASKELL__ < 710
|
|
||||||
import Control.Applicative ((<$>))
|
|
||||||
#endif
|
|
||||||
import Control.Monad
|
|
||||||
import System.Posix.FilePath ((</>))
|
|
||||||
import System.Posix.Foreign
|
|
||||||
|
|
||||||
import qualified System.Posix as Posix
|
|
||||||
import System.IO.Error
|
|
||||||
import Control.Exception
|
|
||||||
import qualified Data.ByteString.Char8 as BS
|
|
||||||
import System.Posix.ByteString.FilePath
|
|
||||||
import System.Posix.Directory.ByteString as PosixBS
|
|
||||||
import System.Posix.Files.ByteString
|
|
||||||
|
|
||||||
import System.IO.Unsafe
|
|
||||||
import "unix" System.Posix.IO.ByteString (closeFd)
|
|
||||||
import Unsafe.Coerce (unsafeCoerce)
|
|
||||||
import Foreign.C.Error
|
|
||||||
import Foreign.C.String
|
|
||||||
import Foreign.C.Types
|
|
||||||
import Foreign.Marshal.Alloc (alloca,allocaBytes)
|
|
||||||
import Foreign.Ptr
|
|
||||||
import Foreign.Storable
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------------------
|
|
||||||
|
|
||||||
-- | Get all files from a directory and its subdirectories.
|
|
||||||
--
|
|
||||||
-- Upon entering a directory, 'allDirectoryContents' will get all entries
|
|
||||||
-- strictly. However the returned list is lazy in that directories will only
|
|
||||||
-- be accessed on demand.
|
|
||||||
--
|
|
||||||
-- Follows symbolic links for the input dir.
|
|
||||||
allDirectoryContents :: RawFilePath -> IO [RawFilePath]
|
|
||||||
allDirectoryContents topdir = do
|
|
||||||
namesAndTypes <- getDirectoryContents topdir
|
|
||||||
let properNames = filter ((`notElem` [".", ".."]) . snd) namesAndTypes
|
|
||||||
paths <- forM properNames $ \(typ,name) -> unsafeInterleaveIO $ do
|
|
||||||
let path = topdir </> name
|
|
||||||
case () of
|
|
||||||
() | typ == dtDir -> allDirectoryContents path
|
|
||||||
| typ == dtUnknown -> do
|
|
||||||
isDir <- isDirectory <$> getFileStatus path
|
|
||||||
if isDir
|
|
||||||
then allDirectoryContents path
|
|
||||||
else return [path]
|
|
||||||
| otherwise -> return [path]
|
|
||||||
return (topdir : concat paths)
|
|
||||||
|
|
||||||
-- | Get all files from a directory and its subdirectories strictly.
|
|
||||||
--
|
|
||||||
-- Follows symbolic links for the input dir.
|
|
||||||
allDirectoryContents' :: RawFilePath -> IO [RawFilePath]
|
|
||||||
allDirectoryContents' = fmap reverse . traverseDirectory (\acc fp -> return (fp:acc)) []
|
|
||||||
-- this uses traverseDirectory because it's more efficient than forcing the
|
|
||||||
-- lazy version.
|
|
||||||
|
|
||||||
-- | Recursively apply the 'action' to the parent directory and all
|
|
||||||
-- files/subdirectories.
|
|
||||||
--
|
|
||||||
-- This function allows for memory-efficient traversals.
|
|
||||||
--
|
|
||||||
-- Follows symbolic links for the input dir.
|
|
||||||
traverseDirectory :: (s -> RawFilePath -> IO s) -> s -> RawFilePath -> IO s
|
|
||||||
traverseDirectory act s0 topdir = toploop
|
|
||||||
where
|
|
||||||
toploop = do
|
|
||||||
isDir <- isDirectory <$> getFileStatus topdir
|
|
||||||
s' <- act s0 topdir
|
|
||||||
if isDir then actOnDirContents topdir s' loop
|
|
||||||
else return s'
|
|
||||||
loop typ path acc = do
|
|
||||||
isDir <- case () of
|
|
||||||
() | typ == dtDir -> return True
|
|
||||||
| typ == dtUnknown -> isDirectory <$> getFileStatus path
|
|
||||||
| otherwise -> return False
|
|
||||||
if isDir
|
|
||||||
then act acc path >>= \acc' -> actOnDirContents path acc' loop
|
|
||||||
else act acc path
|
|
||||||
|
|
||||||
actOnDirContents :: RawFilePath
|
|
||||||
-> b
|
|
||||||
-> (DirType -> RawFilePath -> b -> IO b)
|
|
||||||
-> IO b
|
|
||||||
actOnDirContents pathRelToTop b f =
|
|
||||||
modifyIOError ((`ioeSetFileName` (BS.unpack pathRelToTop)) .
|
|
||||||
(`ioeSetLocation` "findBSTypRel")) $
|
|
||||||
bracket
|
|
||||||
(openDirStream pathRelToTop)
|
|
||||||
Posix.closeDirStream
|
|
||||||
(\dirp -> loop dirp b)
|
|
||||||
where
|
|
||||||
loop dirp b' = do
|
|
||||||
(typ,e) <- readDirEnt dirp
|
|
||||||
if (e == "")
|
|
||||||
then return b'
|
|
||||||
else
|
|
||||||
if (e == "." || e == "..")
|
|
||||||
then loop dirp b'
|
|
||||||
else f typ (pathRelToTop </> e) b' >>= loop dirp
|
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------------------
|
|
||||||
-- dodgy stuff
|
|
||||||
|
|
||||||
type CDir = ()
|
|
||||||
type CDirent = ()
|
|
||||||
|
|
||||||
-- Posix doesn't export DirStream, so to re-use that type we need to use
|
|
||||||
-- unsafeCoerce. It's just a newtype, so this is a legitimate usage.
|
|
||||||
-- ugly trick.
|
|
||||||
unpackDirStream :: DirStream -> Ptr CDir
|
|
||||||
unpackDirStream = unsafeCoerce
|
|
||||||
|
|
||||||
packDirStream :: Ptr CDir -> DirStream
|
|
||||||
packDirStream = unsafeCoerce
|
|
||||||
|
|
||||||
-- the __hscore_* functions are defined in the unix package. We can import them and let
|
|
||||||
-- the linker figure it out.
|
|
||||||
foreign import ccall unsafe "__hscore_readdir"
|
|
||||||
c_readdir :: Ptr CDir -> Ptr (Ptr CDirent) -> IO CInt
|
|
||||||
|
|
||||||
foreign import ccall unsafe "__hscore_free_dirent"
|
|
||||||
c_freeDirEnt :: Ptr CDirent -> IO ()
|
|
||||||
|
|
||||||
foreign import ccall unsafe "__hscore_d_name"
|
|
||||||
c_name :: Ptr CDirent -> IO CString
|
|
||||||
|
|
||||||
foreign import ccall unsafe "__posixdir_d_type"
|
|
||||||
c_type :: Ptr CDirent -> IO DirType
|
|
||||||
|
|
||||||
foreign import capi "stdlib.h realpath"
|
|
||||||
c_realpath :: CString -> CString -> IO CString
|
|
||||||
|
|
||||||
-- Using normal 'ccall' here lead to memory bugs, crashes
|
|
||||||
-- and corrupted d_name entries. It appears there are two fdopendirs:
|
|
||||||
-- https://opensource.apple.com/source/Libc/Libc-1244.1.7/include/dirent.h.auto.html
|
|
||||||
-- The capi call picks the correct one.
|
|
||||||
foreign import capi unsafe "dirent.h fdopendir"
|
|
||||||
c_fdopendir :: Posix.Fd -> IO (Ptr CDir)
|
|
||||||
|
|
||||||
----------------------------------------------------------
|
|
||||||
-- less dodgy but still lower-level
|
|
||||||
|
|
||||||
|
|
||||||
readDirEnt :: DirStream -> IO (DirType, RawFilePath)
|
|
||||||
readDirEnt (unpackDirStream -> dirp) =
|
|
||||||
alloca $ \ptr_dEnt -> loop ptr_dEnt
|
|
||||||
where
|
|
||||||
loop ptr_dEnt = do
|
|
||||||
resetErrno
|
|
||||||
r <- c_readdir dirp ptr_dEnt
|
|
||||||
if (r == 0)
|
|
||||||
then do
|
|
||||||
dEnt <- peek ptr_dEnt
|
|
||||||
if (dEnt == nullPtr)
|
|
||||||
then return (dtUnknown,BS.empty)
|
|
||||||
else do
|
|
||||||
dName <- c_name dEnt >>= peekFilePath
|
|
||||||
dType <- c_type dEnt
|
|
||||||
c_freeDirEnt dEnt
|
|
||||||
return (dType, dName)
|
|
||||||
else do
|
|
||||||
errno <- getErrno
|
|
||||||
if (errno == eINTR)
|
|
||||||
then loop ptr_dEnt
|
|
||||||
else do
|
|
||||||
let (Errno eo) = errno
|
|
||||||
if (eo == 0)
|
|
||||||
then return (dtUnknown,BS.empty)
|
|
||||||
else throwErrno "readDirEnt"
|
|
||||||
|
|
||||||
|
|
||||||
-- |Gets all directory contents (not recursively).
|
|
||||||
getDirectoryContents :: RawFilePath -> IO [(DirType, RawFilePath)]
|
|
||||||
getDirectoryContents path =
|
|
||||||
modifyIOError ((`ioeSetFileName` (BS.unpack path)) .
|
|
||||||
(`ioeSetLocation` "System.Posix.RawFilePath.Directory.Traversals.getDirectoryContents")) $
|
|
||||||
bracket
|
|
||||||
(PosixBS.openDirStream path)
|
|
||||||
PosixBS.closeDirStream
|
|
||||||
_dirloop
|
|
||||||
|
|
||||||
|
|
||||||
-- |Binding to @fdopendir(3)@.
|
|
||||||
fdOpendir :: Posix.Fd -> IO DirStream
|
|
||||||
fdOpendir fd =
|
|
||||||
packDirStream <$> throwErrnoIfNull "fdOpendir" (c_fdopendir fd)
|
|
||||||
|
|
||||||
|
|
||||||
-- |Like `getDirectoryContents` except for a file descriptor.
|
|
||||||
--
|
|
||||||
-- To avoid complicated error checks, the file descriptor is
|
|
||||||
-- __always__ closed, even if `fdOpendir` fails. Usually, this
|
|
||||||
-- only happens on successful `fdOpendir` and after the directory
|
|
||||||
-- stream is closed. Also see the manpage of @fdopendir(3)@ for
|
|
||||||
-- more details.
|
|
||||||
getDirectoryContents' :: Posix.Fd -> IO [(DirType, RawFilePath)]
|
|
||||||
getDirectoryContents' fd = do
|
|
||||||
dirstream <- fdOpendir fd `catchIOError` \e -> do
|
|
||||||
closeFd fd
|
|
||||||
ioError e
|
|
||||||
-- closeDirStream closes the filedescriptor
|
|
||||||
finally (_dirloop dirstream) (PosixBS.closeDirStream dirstream)
|
|
||||||
|
|
||||||
|
|
||||||
_dirloop :: DirStream -> IO [(DirType, RawFilePath)]
|
|
||||||
{-# INLINE _dirloop #-}
|
|
||||||
_dirloop dirp = do
|
|
||||||
t@(_typ,e) <- readDirEnt dirp
|
|
||||||
if BS.null e then return [] else do
|
|
||||||
es <- _dirloop dirp
|
|
||||||
return (t:es)
|
|
||||||
|
|
||||||
|
|
||||||
-- | return the canonicalized absolute pathname
|
|
||||||
--
|
|
||||||
-- like canonicalizePath, but uses @realpath(3)@
|
|
||||||
realpath :: RawFilePath -> IO RawFilePath
|
|
||||||
realpath inp =
|
|
||||||
allocaBytes pathMax $ \tmp -> do
|
|
||||||
void $ BS.useAsCString inp $ \cstr -> throwErrnoIfNull "realpath" $ c_realpath cstr tmp
|
|
||||||
BS.packCString tmp
|
|
BIN
hpath.haddock
Normal file
BIN
hpath.haddock
Normal file
Binary file not shown.
@ -1,89 +0,0 @@
|
|||||||
0.11.0
|
|
||||||
* Many API breaking changes
|
|
||||||
* Remove RelC and Fn, because they complicate API/break semantics (see #29)
|
|
||||||
* Redo 'parseAny'
|
|
||||||
* Unexpose HPath.Internal
|
|
||||||
* Don't preserve trailing path separators (if you need to pass something to a C function that way, do it manually)
|
|
||||||
* Added `rooPath`, `isRootPath`, `getAllComponents`, `getAllComponentsAfterRoot`
|
|
||||||
0.10.2
|
|
||||||
* Add `parseAny` and the related QuasiQuoter
|
|
||||||
0.10.1
|
|
||||||
* Add quasi quoters for hpath
|
|
||||||
0.10.0
|
|
||||||
* split packages, this one now just contains the type-safe Path wrappers
|
|
||||||
0.9.2
|
|
||||||
* fix build with ghc-7.6
|
|
||||||
* raise required bytestring version
|
|
||||||
* Tighten base bound to prevent building before GHC 7.6 (by George Wilson)
|
|
||||||
0.9.1
|
|
||||||
* fix build with ghc-7.8 and 7.10
|
|
||||||
0.9.0
|
|
||||||
* don't force "Path Abs" anymore in IO module, abstract more over Path types
|
|
||||||
* add 'toAbs'
|
|
||||||
0.8.1
|
|
||||||
* add 'readFile', 'readFileEOF', 'writeFile' and 'appendFile'
|
|
||||||
0.8.0
|
|
||||||
* 'copyDirRecursiveOverwrite', 'copyFileOverwrite', 'easyCopyOverwrite' and 'moveFileOverwrite' have been removed, instead use the versions without the *Overwrite suffix and pass in 'Strict' (for default behavior) or 'Overwrite' as the CopyMode argument
|
|
||||||
* introduced a new 'RecursiveErrorMode' type to allow controlling recursive behavior of 'copyDirRecursive' (use 'FailEarly' for default behavior)
|
|
||||||
* 'createRegularFile' and 'createDir' now take FileMode as a parameter (also see 'newFilePerms' and 'newDirPerms')
|
|
||||||
* various documentation fixes
|
|
||||||
* improved reliability of tests
|
|
||||||
0.7.5:
|
|
||||||
* relicense to BSD3
|
|
||||||
0.7.3:
|
|
||||||
* don't expose HPath.Internal
|
|
||||||
0.7.2:
|
|
||||||
* fix tests, so they work with the sdist tarball too
|
|
||||||
* added the following function to HPath.IO: createSymlink
|
|
||||||
0.7.1:
|
|
||||||
* various cleanups and documentation improvements
|
|
||||||
* added the following functions to System.Posix.FilePath: splitSearchPath, getSearchPath, stripExtension, makeRelative, makeValid
|
|
||||||
0.7.0:
|
|
||||||
* use 'sendfile' from 'simple-sendfile' in _copyFile and do read/write as a fallback only
|
|
||||||
* add isFileName, hasParentDir, hiddenFile to System.Posix.FilePath
|
|
||||||
* add our own openFd version for more control
|
|
||||||
* small documentation improvements
|
|
||||||
* add a getDirectoryContents' version that works on Fd
|
|
||||||
* lift version constraints in benchmark
|
|
||||||
* remove fpToString and userStringToFP, use Data.ByteString.UTF8 directly instead
|
|
||||||
0.6.0:
|
|
||||||
* fixes 'throwDestinationInSource' to be more reliable.
|
|
||||||
* removes some unused HPathIOException constructors
|
|
||||||
* consistently provide exception constructor identifiers
|
|
||||||
* be less harsh when non-supported file types get passed to our functions, possibly ignoring them
|
|
||||||
* minor cleanups
|
|
||||||
0.5.9:
|
|
||||||
* Adds our posix-paths fork and a lot of IO operations.
|
|
||||||
0.5.8:
|
|
||||||
* First version of the fork.
|
|
||||||
0.5.7:
|
|
||||||
* Fix haddock problem.
|
|
||||||
0.5.6:
|
|
||||||
* Reject only .. and .
|
|
||||||
0.5.5:
|
|
||||||
* Use filepath's isValid function for additional sanity checks
|
|
||||||
0.5.4:
|
|
||||||
* Disable parsing of path consisting only of "."
|
|
||||||
* Add NFData instance for Path
|
|
||||||
* Some typo/docs improvements
|
|
||||||
* Add standard headers to modules
|
|
||||||
0.5.3:
|
|
||||||
* Added conversion functions.
|
|
||||||
|
|
||||||
0.2.0:
|
|
||||||
|
|
||||||
* Rename parentAbs to simply parent.
|
|
||||||
* Add dirname.
|
|
||||||
|
|
||||||
0.3.0:
|
|
||||||
* Removed Generic instance.
|
|
||||||
|
|
||||||
0.4.0:
|
|
||||||
* Implemented stricter parsing, disabling use of "..".
|
|
||||||
* Made stripDir generic over MonadThrow
|
|
||||||
|
|
||||||
0.5.0:
|
|
||||||
* Fix stripDir p p /= Nothing bug.
|
|
||||||
|
|
||||||
0.5.2:
|
|
||||||
* Removed unused DeriveGeneric.
|
|
@ -1,30 +0,0 @@
|
|||||||
Copyright (c) Julian Ospald
|
|
||||||
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions
|
|
||||||
are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. Neither the name of the author nor the names of his contributors
|
|
||||||
may be used to endorse or promote products derived from this software
|
|
||||||
without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
|
|
||||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
||||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
||||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,40 +0,0 @@
|
|||||||
# HPath
|
|
||||||
|
|
||||||
[![Gitter chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hasufell/hpath?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Hackage version](https://img.shields.io/hackage/v/hpath.svg?label=Hackage)](https://hackage.haskell.org/package/hpath) [![Build Status](https://api.travis-ci.org/hasufell/hpath.png?branch=master)](http://travis-ci.org/hasufell/hpath) [![Hackage-Deps](https://img.shields.io/hackage-deps/v/hpath.svg)](http://packdeps.haskellers.com/feed?needle=hpath)
|
|
||||||
|
|
||||||
Support for well-typed paths in Haskell.
|
|
||||||
|
|
||||||
This package is part of the HPath suite, also check out:
|
|
||||||
|
|
||||||
* [hpath-directory](https://hackage.haskell.org/package/hpath-directory)
|
|
||||||
* [hpath-filepath](https://hackage.haskell.org/package/hpath-filepath)
|
|
||||||
* [hpath-io](https://hackage.haskell.org/package/hpath-io)
|
|
||||||
|
|
||||||
## Motivation
|
|
||||||
|
|
||||||
The motivation came during development of
|
|
||||||
[hsfm](https://github.com/hasufell/hsfm)
|
|
||||||
which has a pretty strict File type, but lacks a strict Path type, e.g.
|
|
||||||
for user input.
|
|
||||||
|
|
||||||
The library that came closest to my needs was
|
|
||||||
[path](https://github.com/chrisdone/path),
|
|
||||||
but the API turned out to be oddly complicated for my use case, so I
|
|
||||||
decided to fork it.
|
|
||||||
|
|
||||||
## Goals
|
|
||||||
|
|
||||||
* well-typed paths
|
|
||||||
* safe filepath manipulation, never using String as filepath, but ByteString
|
|
||||||
|
|
||||||
Note: this library was written for __posix__ systems and it will probably not support other systems.
|
|
||||||
|
|
||||||
## Differences to 'path'
|
|
||||||
|
|
||||||
* doesn't attempt to fake IO-related information into the path, so whether a path points to a file or directory is up to your IO-code to decide...
|
|
||||||
* uses safe ByteString for filepaths under the hood instead of unsafe String
|
|
||||||
* fixes broken [dirname](https://github.com/chrisdone/path/issues/18)
|
|
||||||
* renames dirname/filename to basename/dirname to match the POSIX shell functions
|
|
||||||
* allows pattern matching via unidirectional PatternSynonym
|
|
||||||
* uses simple doctest for testing
|
|
||||||
* allows `~/` as relative path, because on posix level `~` is just a regular filename that does _NOT_ point to `$HOME`
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user