packages feed

system-fileio (empty) → 0.1

raw patch · 6 files changed

+559/−0 lines, 6 filesdep +Win32dep +basedep +bytestringsetup-changed

Dependencies added: Win32, base, bytestring, directory, system-filepath, text, time, unix

Files

+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ System/Directory.hs view
@@ -0,0 +1,336 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE PackageImports #-}++-- |+-- Module: System.Directory+-- Copyright: 2011 John Millikin+-- License: MIT+--+-- Maintainer: jmillikin@gmail.com+-- Portability: portable+--+-- Simple 'FilePath'&#x2010;aware wrappers around standard "System.Directory"+-- computations. See the linked documentation for each computation for+-- details on exceptions and operating system interaction.+module System.Directory+	(+	+	-- * File and directory attributes+	  isFile+	, isDirectory+	, fileSize+	, rename+	, modified+	, listDirectory+	+	-- * Creating things+	, createDirectory+	, createTree+	+	-- * Removing things+	, removeFile+	, removeDirectory+	, removeTree+	+	-- * Current working directory+	, getWorkingDirectory+	, setWorkingDirectory+	+	-- * Commonly used paths+	, getHomeDirectory+	, getDesktopDirectory+	, getDocumentsDirectory+	, getAppDataDirectory+	, getAppCacheDirectory+	, getAppConfigDirectory+	) where++import           Prelude hiding (FilePath)++import qualified Control.Exception as Exc+import qualified Data.Text as T+import qualified System.Environment as SE+import           System.FilePath (FilePath, append)+import           System.FilePath.CurrentOS (currentOS)+import qualified System.FilePath.Rules as R+import           System.IO.Error (isDoesNotExistError)++#ifdef CABAL_OS_WINDOWS++import           Data.Bits ((.|.))+import           Data.Time ( UTCTime(..)+                           , fromGregorian+                           , secondsToDiffTime+                           , picosecondsToDiffTime)+import qualified System.Win32 as Win32++#else++import           Data.Time (UTCTime)+import           Data.Time.Clock.POSIX (posixSecondsToUTCTime)+import qualified System.Posix as Posix++#endif++-- hopefully temporary+import qualified "directory" System.Directory as SD++import           System.FileIO.Internal (encode, decode)++-- | Check if a file exists at the given path.+--+-- See: 'SD.doesFileExist'+isFile :: FilePath -> IO Bool+isFile path = SD.doesFileExist (encode path)++-- | Check if a directory exists at the given path.+--+-- See: 'SD.doesDirectoryExist'+isDirectory :: FilePath -> IO Bool+isDirectory path = SD.doesDirectoryExist (encode path)++-- | Get when the object at a given path was last modified.+modified :: FilePath -> IO UTCTime+modified path = do+#ifdef CABAL_OS_WINDOWS+	info <- withHANDLE path Win32.getFileInformationByHandle+	let ftime = Win32.bhfiLastWriteTime info+	stime <- Win32.fileTimeToSystemTime ftime+	+	let date = fromGregorian+		(fromIntegral (Win32.wYear stime))+		(fromIntegral (Win32.wMonth stime))+		(fromIntegral (Win32.wDay stime))+	+	let seconds = secondsToDiffTime $+		(toInteger (Win32.wHour stime) * 3600) ++		(toInteger (Win32.wMinute stime) * 60) ++		(toInteger (Win32.wSecond stime))+	+	let msecs = picosecondsToDiffTime $+		(toInteger (Win32.wMilliseconds stime) * 1000000000)+	+	return (UTCTime date (seconds + msecs))+#else+	stat <- Posix.getFileStatus (encode path)+	let mtime = Posix.modificationTime stat+	return (posixSecondsToUTCTime (realToFrac mtime))+#endif++-- | Get the size of an object at a given path. For special objects like+-- links or directories, the size is filesystem&#x2010; and+-- platform&#x2010;dependent.+fileSize :: FilePath -> IO Integer+fileSize path = do+#ifdef CABAL_OS_WINDOWS+	info <- withHANDLE path Win32.getFileInformationByHandle+	return (toInteger (Win32.bhfiSize info))+#else+	stat <- Posix.getFileStatus (encode path)+	return (toInteger (Posix.fileSize stat))+#endif++-- | Rename a filesystem object. Some operating systems have restrictions+-- on what objects can be renamed; see linked documentation for details.+--+-- See: 'SD.renameFile' and 'SD.renameDirectory'+rename :: FilePath -> FilePath -> IO ()+rename old new =+	let old' = encode old in+	let new' = encode new in+#ifdef CABAL_OS_WINDOWS+	Win32.moveFileEx old' new' Win32.mOVEFILE_REPLACE_EXISTING+#else+	Posix.rename old' new'+#endif++-- | Create a directory at a given path. The user may choose whether it is+-- an error for a directory to already exist at that path.+--+-- See: 'SD.createDirectory'.+createDirectory :: Bool -- ^ Succeed if the directory already exists+                -> FilePath -> IO ()+createDirectory False path =+	let path' = encode path in+#ifdef CABAL_OS_WINDOWS+	Win32.createDirectory path' Nothing+#else+	Posix.createDirectory path' 0o777+#endif+createDirectory True path = SD.createDirectoryIfMissing False (encode path)++-- | Create a directory at a given path, including any parents which might+-- be missing.+--+-- See: 'SD.createDirectoryIfMissing'+createTree :: FilePath -> IO ()+createTree path = SD.createDirectoryIfMissing True (encode path)++-- | List contents of a directory, excluding @\".\"@ and @\"..\"@.+--+-- See: 'SD.getDirectoryContents'+listDirectory :: FilePath -> IO [FilePath]+listDirectory path = fmap cleanup contents where+	contents = SD.getDirectoryContents (encode path)+	cleanup = map decode . filter (`notElem` [".", ".."])++-- | Remove a file.+--+-- See: 'SD.removeFile'+removeFile :: FilePath -> IO ()+removeFile path =+	let path' = encode path in+#ifdef CABAL_OS_WINDOWS+	Win32.deleteFile path'+#else+	Posix.removeLink path'+#endif++-- | Remove an empty directory.+--+-- See: 'SD.removeDirectory'+removeDirectory :: FilePath -> IO ()+removeDirectory path =+	let path' = encode path in+#ifdef CABAL_OS_WINDOWS+	Win32.removeDirectory path'+#else+	Posix.removeDirectory path'+#endif++-- | Recursively remove a directory tree rooted at the given path.+--+-- See: 'SD.removeDirectoryRecursive'+removeTree :: FilePath -> IO ()+removeTree path = SD.removeDirectoryRecursive (encode path)++-- | Get the current working directory.+--+-- See: 'SD.getCurrentDirectory'+getWorkingDirectory :: IO FilePath+getWorkingDirectory = do+#ifdef CABAL_OS_WINDOWS+	raw <- Win32.getCurrentDirectory+#else+	raw <- Posix.getWorkingDirectory+#endif+	return (decode raw)++-- | Set the current working directory.+--+-- See: 'SD.setCurrentDirectory'+setWorkingDirectory :: FilePath -> IO ()+setWorkingDirectory path =+	let path' = encode path in+#ifdef CABAL_OS_WINDOWS+	Win32.setCurrentDirectory path'+#else+	Posix.changeWorkingDirectory path'+#endif++-- TODO: expose all known exceptions as specific types, for users to catch+-- if need be++-- | Get the user&#x2019;s home directory. This is useful for building paths+-- to more specific directories.+--+-- For directing the user to open or safe a document, use+-- 'getDocumentsDirectory'.+--+-- For data files the user does not explicitly create, such as automatic+-- saves, use 'getAppDataDirectory'.+--+-- See: 'SD.getHomeDirectory'+getHomeDirectory :: IO FilePath+getHomeDirectory = fmap decode SD.getHomeDirectory++-- | Get the user&#x2019;s home directory. This is a good starting point for+-- file dialogs and other user queries. For data files the user does not+-- explicitly create, such as automatic saves, use 'getAppDataDirectory'.+getDesktopDirectory :: IO FilePath+getDesktopDirectory = xdg "XDG_DESKTOP_DIR" Nothing+	(homeSlash "Desktop")++-- | Get the user&#x2019;s documents directory. This is a good place to save+-- user-created files. For data files the user does not explicitly create,+-- such as automatic saves, use 'getAppDataDirectory'.+--+-- See: 'SD.getUserDocumentsDirectory'+getDocumentsDirectory :: IO FilePath+getDocumentsDirectory = xdg "XDG_DOCUMENTS_DIR" Nothing+#ifdef CABAL_OS_WINDOWS+	(fmap decode SD.getUserDocumentsDirectory)+#else+	(homeSlash "Documents")+#endif++-- | Get the user&#x2019;s application data directory, given an application+-- label. This directory is where applications should store data the user did+-- not explicitly create, such as databases and automatic saves.+--+-- See: 'SD.getAppUserDataDirectory'+getAppDataDirectory :: T.Text -> IO FilePath+getAppDataDirectory label = xdg "XDG_DATA_HOME" (Just label)+#ifdef CABAL_OS_WINDOWS+	(fmap decode (SD.getAppUserDataDirectory ""))+#else+	(homeSlash ".local/share")+#endif++-- | Get the user&#x2019;s application cache directory, given an application+-- label. This directory is where applications should store caches, which+-- might be large and can be safely deleted.+getAppCacheDirectory :: T.Text -> IO FilePath+getAppCacheDirectory label = xdg "XDG_CACHE_HOME" (Just label)+#ifdef CABAL_OS_WINDOWS+	(homeSlash "Local Settings\\Cache")+#else+	(homeSlash ".cache")+#endif++-- | Get the user&#x2019;s application configuration directory, given an+-- application label. This directory is where applications should store their+-- configurations and settings.+getAppConfigDirectory :: T.Text -> IO FilePath+getAppConfigDirectory label = xdg "XDG_CONFIG_HOME" (Just label)+#ifdef CABAL_OS_WINDOWS+	(homeSlash "Local Settings")+#else+	(homeSlash ".config")+#endif++homeSlash :: String -> IO FilePath+homeSlash path = do+	home <- getHomeDirectory+	return (append home (decode path))++getenv :: String -> IO (Maybe String)+getenv key = Exc.catch+	(fmap Just (SE.getEnv key))+	(\e -> if isDoesNotExistError e+		then return Nothing+		else Exc.throwIO e)++xdg :: String -> Maybe T.Text -> IO FilePath -> IO FilePath+xdg envkey label fallback = do+	env <- getenv envkey+	dir <- case env of+		Just var -> return (decode var)+		Nothing -> fallback+	return $ case label of+		Just text -> append dir (R.fromText currentOS text)+		Nothing -> dir++#ifdef CABAL_OS_WINDOWS+withHANDLE :: FilePath -> (Win32.HANDLE -> IO a) -> IO a+withHANDLE path = Exc.bracket open close where+	open = Win32.createFile+		(encode path)+		Win32.gENERIC_READ+		(Win32.fILE_SHARE_READ .|. Win32.fILE_SHARE_WRITE)+		Nothing+		Win32.oPEN_EXISTING+		0+		Nothing+	close = Win32.closeHandle+#endif
+ System/File.hs view
@@ -0,0 +1,120 @@+-- |+-- Module: System.File+-- Copyright: 2011 John Millikin+-- License: MIT+--+-- Maintainer: jmillikin@gmail.com+-- Portability: portable+--+-- Simple 'FilePath'&#x2010;aware wrappers around standard "System.IO"+-- computations. See the linked documentation for each computation for+-- details on exceptions and operating system interaction.+module System.File+	( Handle+	, Mode+	+	-- * Binary files+	, openFile+	, withFile+	, readFile+	, writeFile+	, appendFile+	+	-- * Text files+	, openTextFile+	, withTextFile+	, readTextFile+	, writeTextFile+	, appendTextFile+	) where++import           Prelude hiding (FilePath, readFile, writeFile, appendFile)++import qualified Data.ByteString as B+import qualified Data.Text as T+import qualified Data.Text.IO as T+import qualified System.IO as IO+import           System.FilePath (FilePath)+import           System.FileIO.Internal (encode)++-- | Re&#x2010;exported for convenience.+type Handle = IO.Handle++-- | Re&#x2010;exported for convenience.+type Mode = IO.IOMode++-- | Open a file in binary mode, and return an open 'Handle'. The 'Handle'+-- should be 'IO.hClose'd when it is no longer needed.+--+-- 'withFile' is easier to use, because it will handle the 'Handle'&#x2019;s+-- lifetime automatically.+--+-- See: 'IO.openBinaryFile'+openFile :: FilePath -> Mode -> IO IO.Handle+openFile path = IO.openBinaryFile (encode path)++-- | Open a file in binary mode, and pass its 'Handle' to a provided+-- computation. The 'Handle' will be automatically closed when the+-- computation returns.+--+-- See: 'IO.withBinaryFile'+withFile :: FilePath -> Mode -> (IO.Handle -> IO a) -> IO a+withFile path = IO.withBinaryFile (encode path)++-- | Read in the entire contents of a binary file.+--+-- See: 'B.readFile'+readFile :: FilePath -> IO B.ByteString+readFile path = B.readFile (encode path)++-- | Replace the entire contents of a binary file with the provided+-- 'B.ByteString'.+--+-- See: 'B.writeFile'+writeFile :: FilePath -> B.ByteString -> IO ()+writeFile path = B.writeFile (encode path)++-- | Append a 'B.ByteString' to a file. If the file does not exist, it will+-- be created.+--+-- See: 'B.appendFile'+appendFile :: FilePath -> B.ByteString -> IO ()+appendFile path = B.appendFile (encode path)++-- | Open a file in text mode, and return an open 'Handle'. The 'Handle'+-- should be 'IO.hClose'd when it is no longer needed.+--+-- 'withTextFile' is easier to use, because it will handle the+-- 'Handle'&#x2019;s lifetime automatically.+--+-- See: 'IO.openFile'+openTextFile :: FilePath -> Mode -> IO IO.Handle+openTextFile path = IO.openFile (encode path)++-- | Open a file in text mode, and pass its 'Handle' to a provided+-- computation. The 'Handle' will be automatically closed when the+-- computation returns.+--+-- See: 'IO.withFile'+withTextFile :: FilePath -> Mode -> (IO.Handle -> IO a) -> IO a+withTextFile path = IO.withFile (encode path)++-- | Read in the entire contents of a text file.+--+-- See: 'T.readFile'+readTextFile :: FilePath -> IO T.Text+readTextFile path = T.readFile (encode path)++-- | Replace the entire contents of a text file with the provided+-- 'T.Text'.+--+-- See: 'T.writeFile'+writeTextFile :: FilePath -> T.Text -> IO ()+writeTextFile path = T.writeFile (encode path)++-- | Append 'T.Text' to a file. If the file does not exist, it will+-- be created.+--+-- See: 'T.appendFile'+appendTextFile :: FilePath -> T.Text -> IO ()+appendTextFile path = T.appendFile (encode path)
+ System/FileIO/Internal.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE CPP #-}++-- haddock header here+module System.FileIO.Internal+	( encode+	, decode+	) where++import           Prelude hiding (FilePath)++import           System.FilePath (FilePath)+import qualified System.FilePath.Rules as R++#ifdef CABAL_OS_WINDOWS+import qualified Data.Text as T+#else+import qualified Data.ByteString.Char8 as B8+#endif++decode :: String -> FilePath+#ifdef CABAL_OS_WINDOWS+decode = R.decode R.windows . T.pack+#else+decode = R.decode R.posix . B8.pack+#endif++encode :: FilePath -> String+#ifdef CABAL_OS_WINDOWS+encode = T.unpack . R.encode R.windows+#else+encode = B8.unpack . R.encode R.posix+#endif
+ license.txt view
@@ -0,0 +1,22 @@+Copyright (c) 2011 John Millikin++Permission is hereby granted, free of charge, to any person+obtaining a copy of this software and associated documentation+files (the "Software"), to deal in the Software without+restriction, including without limitation the rights to use,+copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the+Software is furnished to do so, subject to the following+conditions:++The above copyright notice and this permission notice shall be+included in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR+OTHER DEALINGS IN THE SOFTWARE.
+ system-fileio.cabal view
@@ -0,0 +1,47 @@+name: system-fileio+version: 0.1+synopsis: High-level filesystem interaction+license: MIT+license-file: license.txt+author: John Millikin <jmillikin@gmail.com>+maintainer: jmillikin@gmail.com+copyright: Copyright (c) John Millikin 2011+build-type: Simple+cabal-version: >=1.6+category: System+stability: experimental+homepage: http://john-millikin.com/software/system-fileio/+bug-reports: mailto:jmillikin@gmail.com+tested-with: GHC==6.12.1++description:+  This is a small wrapper around the \"directory\", \"unix\", and \"Win32\"+  packages for use with \"system-filepath\".++source-repository head+  type: bzr+  location: http://john-millikin.com/software/system-fileio/++library+  ghc-options: -Wall -O2++  build-depends:+      base >= 3 && < 5+    , bytestring >= 0.9 && < 0.10+    , directory >= 1.0 && < 1.2+    , system-filepath >= 0.3 && < 0.4+    , text >= 0.1 && < 0.12+    , time >= 1.0 && < 1.3++  if os(windows)+    cpp-options: -DCABAL_OS_WINDOWS+    build-depends: Win32+  else+    build-depends: unix++  exposed-modules:+    System.Directory+    System.File++  other-modules:+    System.FileIO.Internal