@@ -0,0 +1,347 @@
1+module Effectful.FileSystem
2+ ( FileSystem
3+ , runFileSystem
4+
5+ -- * Actions on directories
6+ , createDirectory
7+ , createDirectoryIfMissing
8+ , removeDirectory
9+ , removeDirectoryRecursive
10+ , removePathForcibly
11+ , renameDirectory
12+ , listDirectory
13+ , getDirectoryContents
14+
15+ -- ** Current working directory
16+ , getCurrentDirectory
17+ , setCurrentDirectory
18+ , withCurrentDirectory
19+
20+ -- * Pre-defined directories
21+ , getHomeDirectory
22+ , getXdgDirectory
23+ , getXdgDirectoryList
24+ , getAppUserDataDirectory
25+ , getUserDocumentsDirectory
26+ , getTemporaryDirectory
27+
28+ -- * Actions on files
29+ , removeFile
30+ , renameFile
31+ , renamePath
32+ , copyFile
33+ , copyFileWithMetadata
34+ , getFileSize
35+ , canonicalizePath
36+ , makeAbsolute
37+ , makeRelativeToCurrentDirectory
38+
39+ -- * Existence tests
40+ , doesPathExist
41+ , doesFileExist
42+ , doesDirectoryExist
43+ , findExecutable
44+ , findExecutables
45+ , findExecutablesInDirectories
46+ , findFile
47+ , findFiles
48+ , findFileWith
49+ , findFilesWith
50+
51+ -- * Symbolic links
52+ , createFileLink
53+ , createDirectoryLink
54+ , removeDirectoryLink
55+ , pathIsSymbolicLink
56+ , getSymbolicLinkTarget
57+
58+ -- * Permissions
59+ , getPermissions
60+ , setPermissions
61+ , copyPermissions
62+
63+ -- * Timestamps
64+ , getAccessTime
65+ , getModificationTime
66+ , setAccessTime
67+ , setModificationTime
68+
69+ -- * Re-exports
70+
71+ -- ** Pre-defined directories
72+ , D.XdgDirectory(..)
73+ , D.XdgDirectoryList(..)
74+
75+ -- ** Existence tests
76+ , D.exeExtension
77+
78+ -- ** Permissions
79+ , D.Permissions
80+ , D.emptyPermissions
81+ , D.readable
82+ , D.writable
83+ , D.executable
84+ , D.searchable
85+ , D.setOwnerReadable
86+ , D.setOwnerWritable
87+ , D.setOwnerExecutable
88+ , D.setOwnerSearchable
89+ ) where
90+
91+import Data.Time (UTCTime)
92+import qualified System.Directory as D
93+
94+import Effectful.Internal.Effect
95+import Effectful.Internal.Monad
96+
97+-- | An effect for interacting with the filesystem.
98+data FileSystem :: Effect where
99+ FileSystem :: FileSystem m r
100+
101+-- | Run the 'FileSystem' effect.
102+runFileSystem :: IOE :> es => Eff (FileSystem : es) a -> Eff es a
103+runFileSystem = evalEffect (IdE FileSystem)
104+
105+----------------------------------------
106+-- Actions on directories
107+
108+-- | Lifted 'D.createDirectory'.
109+createDirectory :: FileSystem :> es => FilePath -> Eff es ()
110+createDirectory = unsafeEff_ . D.createDirectory
111+
112+-- | Lifted 'D.createDirectoryIfMissing'.
113+createDirectoryIfMissing :: FileSystem :> es => Bool -> FilePath -> Eff es ()
114+createDirectoryIfMissing doCreateParents =
115+ unsafeEff_ . D.createDirectoryIfMissing doCreateParents
116+
117+-- | Lifted 'D.removeDirectory'.
118+removeDirectory :: FileSystem :> es => FilePath -> Eff es ()
119+removeDirectory = unsafeEff_ . D.removeDirectory
120+
121+-- | Lifted 'D.removeDirectoryRecursive'.
122+removeDirectoryRecursive :: FileSystem :> es => FilePath -> Eff es ()
123+removeDirectoryRecursive = unsafeEff_ . D.removeDirectoryRecursive
124+
125+-- | Lifted 'D.removePathForcibly'.
126+removePathForcibly :: FileSystem :> es => FilePath -> Eff es ()
127+removePathForcibly = unsafeEff_ . D.removePathForcibly
128+
129+-- | Lifted 'D.renameDirectory'.
130+renameDirectory :: FileSystem :> es => FilePath -> FilePath -> Eff es ()
131+renameDirectory old = unsafeEff_ . D.renameDirectory old
132+
133+-- | Lifted 'D.listDirectory'.
134+listDirectory :: FileSystem :> es => FilePath -> Eff es [FilePath]
135+listDirectory = unsafeEff_ . D.listDirectory
136+
137+-- | Lifted 'D.getDirectoryContents'.
138+getDirectoryContents :: FileSystem :> es => FilePath -> Eff es [FilePath]
139+getDirectoryContents = unsafeEff_ . D.getDirectoryContents
140+
141+----------------------------------------
142+-- Current working directory
143+
144+-- | Lifted 'D.getCurrentDirectory'.
145+getCurrentDirectory :: FileSystem :> es => Eff es FilePath
146+getCurrentDirectory = unsafeEff_ D.getCurrentDirectory
147+
148+-- | Lifted 'D.setCurrentDirectory'.
149+setCurrentDirectory :: FileSystem :> es => FilePath -> Eff es ()
150+setCurrentDirectory = unsafeEff_ . D.setCurrentDirectory
151+
152+-- | Lifted 'D.withCurrentDirectory'.
153+withCurrentDirectory :: FileSystem :> es => FilePath -> Eff es a -> Eff es a
154+withCurrentDirectory path = unsafeLiftMapIO (D.withCurrentDirectory path)
155+
156+----------------------------------------
157+-- Pre-defined directories
158+
159+-- | Lifted 'D.getHomeDirectory'.
160+getHomeDirectory :: FileSystem :> es => Eff es FilePath
161+getHomeDirectory = unsafeEff_ D.getHomeDirectory
162+
163+-- | Lifted 'D.getXdgDirectory'.
164+getXdgDirectory
165+ :: FileSystem :> es
166+ => D.XdgDirectory
167+ -> FilePath
168+ -> Eff es FilePath
169+getXdgDirectory xdgDir = unsafeEff_ . D.getXdgDirectory xdgDir
170+
171+-- | Lifted 'D.getXdgDirectoryList'.
172+getXdgDirectoryList
173+ :: FileSystem :> es
174+ => D.XdgDirectoryList
175+ -> Eff es [FilePath]
176+getXdgDirectoryList = unsafeEff_ . D.getXdgDirectoryList
177+
178+-- | Lifted 'D.getAppUserDataDirectory'.
179+getAppUserDataDirectory :: FileSystem :> es => FilePath -> Eff es FilePath
180+getAppUserDataDirectory = unsafeEff_ . D.getAppUserDataDirectory
181+
182+-- | Lifted 'D.getUserDocumentsDirectory'.
183+getUserDocumentsDirectory :: FileSystem :> es => Eff es FilePath
184+getUserDocumentsDirectory = unsafeEff_ D.getUserDocumentsDirectory
185+
186+-- | Lifted 'D.getTemporaryDirectory'.
187+getTemporaryDirectory :: FileSystem :> es => Eff es FilePath
188+getTemporaryDirectory = unsafeEff_ D.getTemporaryDirectory
189+
190+----------------------------------------
191+-- Actions on files
192+
193+-- | Lifted 'D.removeFile'.
194+removeFile :: FileSystem :> es => FilePath -> Eff es ()
195+removeFile = unsafeEff_ . D.removeFile
196+
197+-- | Lifted 'D.renameFile'.
198+renameFile :: FileSystem :> es => FilePath -> FilePath -> Eff es ()
199+renameFile old = unsafeEff_ . D.renameFile old
200+
201+-- | Lifted 'D.renamePath'.
202+renamePath :: FileSystem :> es => FilePath -> FilePath -> Eff es ()
203+renamePath old = unsafeEff_ . D.renamePath old
204+
205+-- | Lifted 'D.copyFile'.
206+copyFile :: FileSystem :> es => FilePath -> FilePath -> Eff es ()
207+copyFile src = unsafeEff_ . D.copyFile src
208+
209+-- | Lifted 'D.copyFileWithMetadata'.
210+copyFileWithMetadata :: FileSystem :> es => FilePath -> FilePath -> Eff es ()
211+copyFileWithMetadata src = unsafeEff_ . D.copyFileWithMetadata src
212+
213+-- | Lifted 'D.getFileSize'.
214+getFileSize :: FileSystem :> es => FilePath -> Eff es Integer
215+getFileSize = unsafeEff_ . D.getFileSize
216+
217+-- | Lifted 'D.canonicalizePath'.
218+canonicalizePath :: FileSystem :> es => FilePath -> Eff es FilePath
219+canonicalizePath = unsafeEff_ . D.canonicalizePath
220+
221+-- | Lifted 'D.makeAbsolute'.
222+makeAbsolute :: FileSystem :> es => FilePath -> Eff es FilePath
223+makeAbsolute = unsafeEff_ . D.makeAbsolute
224+
225+-- | Lifted 'D.makeRelativeToCurrentDirectory'.
226+makeRelativeToCurrentDirectory
227+ :: FileSystem :> es
228+ => FilePath
229+ -> Eff es FilePath
230+makeRelativeToCurrentDirectory = unsafeEff_ . D.makeRelativeToCurrentDirectory
231+
232+----------------------------------------
233+-- Existence tests
234+
235+-- | Lifted 'D.doesPathExist'.
236+doesPathExist :: FileSystem :> es => FilePath -> Eff es Bool
237+doesPathExist = unsafeEff_ . D.doesPathExist
238+
239+-- | Lifted 'D.doesFileExist'.
240+doesFileExist :: FileSystem :> es => FilePath -> Eff es Bool
241+doesFileExist = unsafeEff_ . D.doesFileExist
242+
243+-- | Lifted 'D.doesDirectoryExist'.
244+doesDirectoryExist :: FileSystem :> es => FilePath -> Eff es Bool
245+doesDirectoryExist = unsafeEff_ . D.doesDirectoryExist
246+
247+-- | Lifted 'D.findExecutable'.
248+findExecutable :: FileSystem :> es => String -> Eff es (Maybe FilePath)
249+findExecutable = unsafeEff_ . D.findExecutable
250+
251+-- | Lifted 'D.findExecutables'.
252+findExecutables :: FileSystem :> es => String -> Eff es [FilePath]
253+findExecutables = unsafeEff_ . D.findExecutables
254+
255+-- | Lifted 'D.findExecutablesInDirectories'.
256+findExecutablesInDirectories
257+ :: FileSystem :> es
258+ => [FilePath]
259+ -> String
260+ -> Eff es [FilePath]
261+findExecutablesInDirectories dirs =
262+ unsafeEff_ . D.findExecutablesInDirectories dirs
263+
264+-- | Lifted 'D.findFile'.
265+findFile :: FileSystem :> es => [FilePath] -> String -> Eff es (Maybe FilePath)
266+findFile dirs = unsafeEff_ . D.findFile dirs
267+
268+-- | Lifted 'D.findFiles'.
269+findFiles :: FileSystem :> es => [FilePath] -> String -> Eff es [FilePath]
270+findFiles dirs = unsafeEff_ . D.findFiles dirs
271+
272+-- | Lifted 'D.findFileWith'.
273+findFileWith
274+ :: FileSystem :> es
275+ => (FilePath -> Eff es Bool)
276+ -> [FilePath]
277+ -> String
278+ -> Eff es (Maybe FilePath)
279+findFileWith p dirs n = unsafeEff $ \es -> do
280+ D.findFileWith ((`unEff` es) . p) dirs n
281+
282+-- | Lifted 'D.findFilesWith'.
283+findFilesWith
284+ :: FileSystem :> es
285+ => (FilePath -> Eff es Bool)
286+ -> [FilePath]
287+ -> String
288+ -> Eff es [FilePath]
289+findFilesWith p dirs ns = unsafeEff $ \es -> do
290+ D.findFilesWith ((`unEff` es) . p) dirs ns
291+
292+----------------------------------------
293+-- Symbolic links
294+
295+-- | Lifted 'D.createFileLink'.
296+createFileLink :: FileSystem :> es => FilePath -> FilePath -> Eff es ()
297+createFileLink target = unsafeEff_ . D.createFileLink target
298+
299+-- | Lifted 'D.createDirectoryLink'.
300+createDirectoryLink :: FileSystem :> es => FilePath -> FilePath -> Eff es ()
301+createDirectoryLink target = unsafeEff_ . D.createDirectoryLink target
302+
303+-- | Lifted 'D.removeDirectoryLink'.
304+removeDirectoryLink :: FileSystem :> es => FilePath -> Eff es ()
305+removeDirectoryLink = unsafeEff_ . D.removeDirectoryLink
306+
307+-- | Lifted 'D.pathIsSymbolicLink'.
308+pathIsSymbolicLink :: FileSystem :> es => FilePath -> Eff es Bool
309+pathIsSymbolicLink = unsafeEff_ . D.pathIsSymbolicLink
310+
311+-- | Lifted 'D.getSymbolicLinkTarget'.
312+getSymbolicLinkTarget :: FileSystem :> es => FilePath -> Eff es FilePath
313+getSymbolicLinkTarget = unsafeEff_ . D.getSymbolicLinkTarget
314+
315+----------------------------------------
316+-- Permissions
317+
318+-- | Lifted 'D.getPermissions'.
319+getPermissions :: FileSystem :> es => FilePath -> Eff es D.Permissions
320+getPermissions = unsafeEff_ . D.getPermissions
321+
322+-- | Lifted 'D.setPermissions'.
323+setPermissions :: FileSystem :> es => FilePath -> D.Permissions -> Eff es ()
324+setPermissions path = unsafeEff_ . D.setPermissions path
325+
326+-- | Lifted 'D.copyPermissions'.
327+copyPermissions :: FileSystem :> es => FilePath -> FilePath -> Eff es ()
328+copyPermissions src = unsafeEff_ . D.copyPermissions src
329+
330+----------------------------------------
331+-- Timestamps
332+
333+-- | Lifted 'D.getAccessTime'.
334+getAccessTime :: FileSystem :> es => FilePath -> Eff es UTCTime
335+getAccessTime = unsafeEff_ . D.getAccessTime
336+
337+-- | Lifted 'D.getModificationTime'.
338+getModificationTime :: FileSystem :> es => FilePath -> Eff es UTCTime
339+getModificationTime = unsafeEff_ . D.getModificationTime
340+
341+-- | Lifted 'D.setAccessTime'.
342+setAccessTime :: FileSystem :> es => FilePath -> UTCTime -> Eff es ()
343+setAccessTime path = unsafeEff_ . D.setAccessTime path
344+
345+-- | Lifted 'D.setModificationTime'.
346+setModificationTime :: FileSystem :> es => FilePath -> UTCTime -> Eff es ()
347+setModificationTime path = unsafeEff_ . D.setModificationTime path