@@ -190,7 +190,8 @@ toDirectoryTree allowSeparators path expression = case expression of
190190
191191 Lam _ _ (Lam _ (functionBindingVariable -> make) body)
192192 | isFixpointedDirectoryTree expression
193- -> applyFilesystemEntryList allowSeparators path $ extractFilesystemEntryList make body
193+ -> processFilesystemEntryList allowSeparators path $
194+ extractFilesystemEntryList make body
194195
195196 _ ->
196197 die
@@ -217,6 +218,7 @@ toDirectoryTree allowSeparators path expression = case expression of
217218 where
218219 unexpectedExpression = expression
219220
221+ -- | Check if an expression is a valid fixpoint directory-tree.
220222isFixpointedDirectoryTree :: Expr Void Void -> Bool
221223isFixpointedDirectoryTree expr = isRight $ TypeCheck. typeOf $ Annot expr $
222224 [TH. dhall |
@@ -254,11 +256,13 @@ isFixpointedDirectoryTree expr = isRight $ TypeCheck.typeOf $ Annot expr $
254256 List r
255257 |]
256258
259+ -- | A filesystem entry.
257260data FilesystemEntry
258261 = DirectoryEntry (Entry (Seq FilesystemEntry ))
259262 | FileEntry (Entry Text )
260263 deriving Show
261264
265+ -- | Extract a `FilesystemEntry` from an expression.
262266extractFilesystemEntry :: Text -> Expr Void Void -> FilesystemEntry
263267extractFilesystemEntry make (App (Field (Var (V make' 0 )) (fieldSelectionLabel -> label)) entry)
264268 | make' == make
@@ -267,9 +271,11 @@ extractFilesystemEntry make (App (Field (Var (V make' 0)) (fieldSelectionLabel -
267271 , label == " file" = FileEntry $ extractEntry extractText entry
268272extractFilesystemEntry _ expr = Exception. throw (FilesystemError expr)
269273
274+ -- | Extract a list of `FilesystemEntry`s from an expression.
270275extractFilesystemEntryList :: Text -> Expr Void Void -> Seq FilesystemEntry
271276extractFilesystemEntryList make = extractList (extractFilesystemEntry make)
272277
278+ -- | A generic filesystem entry parameterized over the content.
273279data Entry a = Entry
274280 { entryName :: String
275281 , entryContent :: a
@@ -279,6 +285,7 @@ data Entry a = Entry
279285 }
280286 deriving Show
281287
288+ -- | Extract an `Entry` from an expression.
282289extractEntry :: (Expr Void Void -> a ) -> Expr Void Void -> Entry a
283290extractEntry extractContent (RecordLit (Map. toList ->
284291 [ (" content" , recordFieldValue -> contentExpr)
@@ -295,6 +302,7 @@ extractEntry extractContent (RecordLit (Map.toList ->
295302 }
296303extractEntry _ expr = Exception. throw (FilesystemError expr)
297304
305+ -- | A user identified either by id or name.
298306data User
299307 = UserId UserID
300308 | UserName String
@@ -307,15 +315,18 @@ pattern UserP label v <- App (Field (Union (Map.toList ->
307315 (fieldSelectionLabel -> label))
308316 v
309317
318+ -- | Extract a `User` from an expression.
310319extractUser :: Expr Void Void -> User
311320extractUser (UserP " UserId" (NaturalLit n)) = UserId $ Posix. CUid (fromIntegral n)
312321extractUser (UserP " UserName" (TextLit (Chunks [] text))) = UserName $ Text. unpack text
313322extractUser expr = Exception. throw (FilesystemError expr)
314323
324+ -- | Resolve a `User` to a numerical id.
315325getUser :: User -> IO UserID
316326getUser (UserId uid) = return uid
317327getUser (UserName name) = Posix. userID <$> Posix. getUserEntryForName name
318328
329+ -- | A group identified either by id or name.
319330data Group
320331 = GroupId GroupID
321332 | GroupName String
@@ -328,15 +339,20 @@ pattern GroupP label v <- App (Field (Union (Map.toList ->
328339 (fieldSelectionLabel -> label))
329340 v
330341
342+ -- | Extract a `Group` from an expression.
331343extractGroup :: Expr Void Void -> Group
332344extractGroup (GroupP " GroupId" (NaturalLit n)) = GroupId $ Posix. CGid (fromIntegral n)
333345extractGroup (GroupP " GroupName" (TextLit (Chunks [] text))) = GroupName $ Text. unpack text
334346extractGroup expr = Exception. throw (FilesystemError expr)
335347
348+ -- | Resolve a `Group` to a numerical id.
336349getGroup :: Group -> IO GroupID
337350getGroup (GroupId gid) = return gid
338351getGroup (GroupName name) = Posix. groupID <$> Posix. getGroupEntryForName name
339352
353+ -- | A filesystem mode. See chmod(1).
354+ -- The parameter is meant to be instantiated by either `Identity` or `Maybe`
355+ -- depending on the completeness of the information.
340356data Mode f = Mode
341357 { modeUser :: f (Access f )
342358 , modeGroup :: f (Access f )
@@ -348,6 +364,7 @@ deriving instance Eq (Mode Maybe)
348364deriving instance Show (Mode Identity )
349365deriving instance Show (Mode Maybe )
350366
367+ -- | Extract a `Mode` from an expression.
351368extractMode :: Expr Void Void -> Mode Maybe
352369extractMode (RecordLit (Map. toList ->
353370 [ (" group" , recordFieldValue -> groupExpr)
@@ -360,6 +377,7 @@ extractMode (RecordLit (Map.toList ->
360377 }
361378extractMode expr = Exception. throw (FilesystemError expr)
362379
380+ -- | The permissions for a subject (user/group/other).
363381data Access f = Access
364382 { accessExecute :: f Bool
365383 , accessRead :: f Bool
@@ -371,6 +389,7 @@ deriving instance Eq (Access Maybe)
371389deriving instance Show (Access Identity )
372390deriving instance Show (Access Maybe )
373391
392+ -- | Extract a `Access` from an expression.
374393extractAccess :: Expr Void Void -> Access Maybe
375394extractAccess (RecordLit (Map. toList ->
376395 [ (" execute" , recordFieldValue -> executeExpr)
@@ -383,49 +402,61 @@ extractAccess (RecordLit (Map.toList ->
383402 }
384403extractAccess expr = Exception. throw (FilesystemError expr)
385404
405+ -- | Helper function to extract a `Bool` value.
386406extractBool :: Expr Void Void -> Bool
387407extractBool (BoolLit b) = b
388408extractBool expr = Exception. throw (FilesystemError expr)
389409
410+ -- | Helper function to extract a list of some values.
411+ -- The first argument is used to extract the items.
390412extractList :: (Expr Void Void -> a ) -> Expr Void Void -> Seq a
391413extractList _ (ListLit (Just _) _) = mempty
392414extractList f (ListLit _ xs) = fmap f xs
393415extractList _ expr = Exception. throw (FilesystemError expr)
394416
417+ -- | Helper function to extract optional values.
418+ -- The first argument is used to extract the items.
395419extractMaybe :: (Expr Void Void -> a ) -> Expr Void Void -> Maybe a
396420extractMaybe _ (App None _) = Nothing
397421extractMaybe f (Some expr) = Just (f expr)
398422extractMaybe _ expr = Exception. throw (FilesystemError expr)
399423
424+ -- | Helper function to extract a `String` value.
400425extractString :: Expr Void Void -> String
401426extractString = Text. unpack . extractText
402427
428+ -- | Helper function to extract a `Text` value.
403429extractText :: Expr Void Void -> Text
404430extractText (TextLit (Chunks [] text)) = text
405431extractText expr = Exception. throw (FilesystemError expr)
406432
407- applyFilesystemEntry :: Bool -> FilePath -> FilesystemEntry -> IO ()
408- applyFilesystemEntry allowSeparators path (DirectoryEntry entry) = do
433+ -- | Process a `FilesystemEntry`. Writes the content to disk and apply the
434+ -- metadata to the newly created item.
435+ processFilesystemEntry :: Bool -> FilePath -> FilesystemEntry -> IO ()
436+ processFilesystemEntry allowSeparators path (DirectoryEntry entry) = do
409437 let path' = path </> entryName entry
410438 Directory. createDirectoryIfMissing allowSeparators path'
411- applyFilesystemEntryList allowSeparators path' $ entryContent entry
439+ processFilesystemEntryList allowSeparators path' $ entryContent entry
412440 -- It is important that we write the metadata after we wrote the content of
413441 -- the directories/files below this directory as we might lock ourself out
414442 -- by changing ownership or permissions.
415- unsafeApplyMetadata entry path'
416- applyFilesystemEntry _ path (FileEntry entry) = do
443+ applyMetadata entry path'
444+ processFilesystemEntry _ path (FileEntry entry) = do
417445 let path' = path </> entryName entry
418446 Text.IO. writeFile path' $ entryContent entry
419447 -- It is important that we write the metadata after we wrote the content of
420448 -- the file as we might lock ourself out by changing ownership or
421449 -- permissions.
422- unsafeApplyMetadata entry path'
450+ applyMetadata entry path'
423451
424- applyFilesystemEntryList :: Bool -> FilePath -> Seq FilesystemEntry -> IO ()
425- applyFilesystemEntryList allowSeparators path = Foldable. traverse_ (applyFilesystemEntry allowSeparators path)
452+ -- | Process a list of `FilesystemEntry`s.
453+ processFilesystemEntryList :: Bool -> FilePath -> Seq FilesystemEntry -> IO ()
454+ processFilesystemEntryList allowSeparators path = Foldable. traverse_
455+ (processFilesystemEntry allowSeparators path)
426456
427- unsafeApplyMetadata :: Entry a -> FilePath -> IO ()
428- unsafeApplyMetadata entry fp = do
457+ -- | Set the metadata of an object referenced by a path.
458+ applyMetadata :: Entry a -> FilePath -> IO ()
459+ applyMetadata entry fp = do
429460 s <- Posix. getFileStatus fp
430461 let user = Posix. fileOwner s
431462 group = Posix. fileGroup s
@@ -440,6 +471,7 @@ unsafeApplyMetadata entry fp = do
440471 unless (mode' == mode) $
441472 Posix. setFileMode fp $ modeToFileMode mode'
442473
474+ -- | Calculate the new `Mode` from the current mode and the changes specified by the user.
443475updateModeWith :: Mode Identity -> Mode Maybe -> Mode Identity
444476updateModeWith x y = Mode
445477 { modeUser = combine modeUser modeUser
@@ -449,6 +481,7 @@ updateModeWith x y = Mode
449481 where
450482 combine f g = maybe (f x) (Identity . updateAccessWith (runIdentity $ f x)) (g y)
451483
484+ -- | Calculate the new `Access` from the current permissions and the changes specified by the user.
452485updateAccessWith :: Access Identity -> Access Maybe -> Access Identity
453486updateAccessWith x y = Access
454487 { accessExecute = combine accessExecute accessExecute
@@ -458,6 +491,7 @@ updateAccessWith x y = Access
458491 where
459492 combine f g = maybe (f x) Identity (g y)
460493
494+ -- | Convert a filesystem mode given as a bitmask (`FileMode`) to an ADT (`Mode`).
461495fileModeToMode :: FileMode -> Mode Identity
462496fileModeToMode mode = Mode
463497 { modeUser = Identity $ Access
@@ -477,6 +511,7 @@ fileModeToMode mode = Mode
477511 }
478512 }
479513
514+ -- | Convert a filesystem mode given as an ADT (`Mode`) to a bitmask (`FileMode`).
480515modeToFileMode :: Mode Identity -> FileMode
481516modeToFileMode mode = foldr Posix. unionFileModes Posix. nullFileMode $
482517 [ Posix. ownerExecuteMode | runIdentity $ accessExecute (runIdentity $ modeUser mode) ] <>
@@ -489,8 +524,9 @@ modeToFileMode mode = foldr Posix.unionFileModes Posix.nullFileMode $
489524 [ Posix. otherReadMode | runIdentity $ accessRead (runIdentity $ modeOther mode) ] <>
490525 [ Posix. otherWriteMode | runIdentity $ accessWrite (runIdentity $ modeOther mode) ]
491526
527+ -- | Check whether the second `FileMode` is contained in the first one.
492528hasFileMode :: FileMode -> FileMode -> Bool
493- hasFileMode mode x = (mode `Posix.intersectFileModes` x) == Posix. nullFileMode
529+ hasFileMode mode x = (mode `Posix.intersectFileModes` x) == x
494530
495531{- | This error indicates that you supplied an invalid Dhall expression to the
496532 `toDirectoryTree` function. The Dhall expression could not be translated
0 commit comments