|
| 1 | +-- This is an example on how to build a directory tree using the so-called |
| 2 | +-- fixpointed method. See the documenatation of the `Dhall.DirectoryTree` module |
| 3 | +-- for further information on it. |
| 4 | + |
| 5 | +-- First, define some types recognized by the `dhall to-directory-tree` command. |
| 6 | + |
| 7 | +-- A user, either identified by its numeric user id or its name. |
| 8 | +let User = < UserId : Natural | UserName : Text > |
| 9 | + |
| 10 | +-- Similarly, a group. |
| 11 | +let Group = < GroupId : Natural | GroupName : Text > |
| 12 | + |
| 13 | +-- The following two type aliases are a well-typed represenation of the bitmask |
| 14 | +-- for permissions used by the DAC access control found on Unix systems. See for |
| 15 | +-- example the chmod(5) manual entry. |
| 16 | + |
| 17 | +-- How much access we do grant... |
| 18 | +let Access = |
| 19 | + { execute : Optional Bool, read : Optional Bool, write : Optional Bool } |
| 20 | + |
| 21 | +-- ... for whom. |
| 22 | +let Mode = |
| 23 | + { user : Optional Access |
| 24 | + , group : Optional Access |
| 25 | + , other : Optional Access |
| 26 | + } |
| 27 | + |
| 28 | +-- A generic file system entry. It consists of a name, an abstract content and |
| 29 | +-- some metadata which might be set (Some) or not (None). |
| 30 | +let Entry = |
| 31 | + \(content : Type) -> |
| 32 | + { name : Text |
| 33 | + , content : content |
| 34 | + , user : Optional User |
| 35 | + , group : Optional Group |
| 36 | + , mode : Optional Mode |
| 37 | + } |
| 38 | + |
| 39 | +-- This is the main program constructing our directory tree. It is a fixpoint |
| 40 | +-- definition similar to how we deal with recursive types in arbitrary Dhall |
| 41 | +-- programs but specialised to our use case. The first argument is the type of a |
| 42 | +-- directory tree and the second one is a record where each field is a |
| 43 | +-- constructor for a specific filesystem entry. |
| 44 | +in \(tree : Type) -> |
| 45 | + \ ( make |
| 46 | + : { directory : Entry (List tree) -> tree, file : Entry Text -> tree } |
| 47 | + ) -> |
| 48 | + |
| 49 | + -- Before we define the actual directory tree we define some Dhall schemas |
| 50 | + -- and shortcuts for convenience. |
| 51 | + |
| 52 | + -- A schema suitable for a directory... |
| 53 | + let Directory = |
| 54 | + { Type = |
| 55 | + { name : Text |
| 56 | + , content : List tree |
| 57 | + , user : Optional User |
| 58 | + , group : Optional Group |
| 59 | + , mode : Optional Mode |
| 60 | + } |
| 61 | + , default = |
| 62 | + { content = [] : List tree |
| 63 | + , user = None User |
| 64 | + , group = None Group |
| 65 | + , mode = None Mode |
| 66 | + } |
| 67 | + } |
| 68 | + |
| 69 | + -- ... and one for a file. |
| 70 | + let File = |
| 71 | + { Type = |
| 72 | + { name : Text |
| 73 | + , content : Text |
| 74 | + , user : Optional User |
| 75 | + , group : Optional Group |
| 76 | + , mode : Optional Mode |
| 77 | + } |
| 78 | + , default = |
| 79 | + { content = "" |
| 80 | + , user = None User |
| 81 | + , group = None Group |
| 82 | + , mode = None Mode |
| 83 | + } |
| 84 | + } |
| 85 | + |
| 86 | + -- Give someone full access to an filesystem entry. |
| 87 | + let full_access |
| 88 | + : Access |
| 89 | + = { execute = Some True, read = Some True, write = Some True } |
| 90 | + |
| 91 | + -- Give someone no access at all to an filesystem entry. |
| 92 | + let no_access |
| 93 | + : Access |
| 94 | + = { execute = Some False, read = Some False, write = Some False } |
| 95 | + |
| 96 | + -- These permissions |
| 97 | + -- * grant full access to the user. |
| 98 | + -- * retain the permissions of the primary group of the user. |
| 99 | + -- * deny access to everyone else. |
| 100 | + let semi_private |
| 101 | + : Mode |
| 102 | + = { user = Some full_access, group = None Access, other = Some no_access } |
| 103 | + |
| 104 | + -- Now let's start with the directory tree ... |
| 105 | + in [ -- Some file with a gentle greeting. No metadata is set explicitly. |
| 106 | + make.file File::{ name = "some file", content = "Hello world!" } |
| 107 | + -- A directory with some metadata set explicitely. |
| 108 | + , make.directory |
| 109 | + Directory::{ |
| 110 | + , name = "my private directory" |
| 111 | + -- How owns the new directory: just_me |
| 112 | + , user = Some (User.UserName "just_me") |
| 113 | + -- We stick with the user's default group here. |
| 114 | + , group = None Group |
| 115 | + , mode = Some semi_private |
| 116 | + , content = [] : List tree |
| 117 | + } |
| 118 | + ] |
| 119 | + : List tree |
0 commit comments